IsolatedStorageFile.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. //
  2. // System.IO.IsolatedStorage.IsolatedStorageFile
  3. //
  4. // Authors
  5. // Jonathan Pryor ([email protected])
  6. // Sebastien Pouliot <[email protected]>
  7. //
  8. // (C) 2003 Jonathan Pryor
  9. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System.Collections;
  31. using System.Reflection;
  32. using System.Runtime.Serialization.Formatters.Binary;
  33. using System.Security;
  34. using System.Security.Cryptography;
  35. using System.Security.Permissions;
  36. using System.Security.Policy;
  37. using System.Text;
  38. using Mono.Security.Cryptography;
  39. namespace System.IO.IsolatedStorage {
  40. // This is a terribly named class. It doesn't actually represent a file as
  41. // much as a directory
  42. public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable {
  43. public static IEnumerator GetEnumerator (IsolatedStorageScope scope)
  44. {
  45. Demand (scope);
  46. switch (scope) {
  47. case IsolatedStorageScope.User:
  48. case IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  49. #if NET_2_0
  50. case IsolatedStorageScope.Machine:
  51. #endif
  52. break;
  53. default:
  54. string msg = Locale.GetText ("Invalid scope, only User, User|Roaming and Machine are valid");
  55. throw new ArgumentException (msg);
  56. }
  57. return new IsolatedStorageFileEnumerator (scope, GetIsolatedStorageRoot (scope));
  58. }
  59. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope,
  60. Evidence domainEvidence, Type domainEvidenceType,
  61. Evidence assemblyEvidence, Type assemblyEvidenceType)
  62. {
  63. Demand (scope);
  64. bool domain = ((scope & IsolatedStorageScope.Domain) != 0);
  65. if (domain && (domainEvidence == null))
  66. throw new ArgumentNullException ("domainEvidence");
  67. bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
  68. if (assembly && (assemblyEvidence == null))
  69. throw new ArgumentNullException ("assemblyEvidence");
  70. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  71. if (domain) {
  72. if (domainEvidenceType == null) {
  73. storageFile._domainIdentity = GetDomainIdentityFromEvidence (domainEvidence);
  74. } else {
  75. storageFile._domainIdentity = GetTypeFromEvidence (domainEvidence, domainEvidenceType);
  76. }
  77. if (storageFile._domainIdentity == null)
  78. throw new IsolatedStorageException (Locale.GetText ("Couldn't find domain identity."));
  79. }
  80. if (assembly) {
  81. if (assemblyEvidenceType == null) {
  82. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (assemblyEvidence);
  83. } else {
  84. storageFile._assemblyIdentity = GetTypeFromEvidence (assemblyEvidence, assemblyEvidenceType);
  85. }
  86. if (storageFile._assemblyIdentity == null)
  87. throw new IsolatedStorageException (Locale.GetText ("Couldn't find assembly identity."));
  88. }
  89. storageFile.PostInit ();
  90. return storageFile;
  91. }
  92. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object domainIdentity, object assemblyIdentity)
  93. {
  94. Demand (scope);
  95. if (((scope & IsolatedStorageScope.Domain) != 0) && (domainIdentity == null))
  96. throw new ArgumentNullException ("domainIdentity");
  97. if (((scope & IsolatedStorageScope.Assembly) != 0) && (assemblyIdentity == null))
  98. throw new ArgumentNullException ("assemblyIdentity");
  99. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  100. storageFile._domainIdentity = domainIdentity;
  101. storageFile._assemblyIdentity = assemblyIdentity;
  102. storageFile.PostInit ();
  103. return storageFile;
  104. }
  105. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
  106. {
  107. Demand (scope);
  108. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  109. if ((scope & IsolatedStorageScope.Domain) != 0) {
  110. storageFile._domainIdentity = GetTypeFromEvidence (AppDomain.CurrentDomain.Evidence, domainEvidenceType);
  111. }
  112. if ((scope & IsolatedStorageScope.Assembly) != 0) {
  113. storageFile._assemblyIdentity = GetTypeFromEvidence (Assembly.GetCallingAssembly ().Evidence, assemblyEvidenceType);
  114. }
  115. storageFile.PostInit ();
  116. return storageFile;
  117. }
  118. #if NET_2_0
  119. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object applicationIdentity)
  120. {
  121. Demand (scope);
  122. if (applicationIdentity == null)
  123. throw new ArgumentNullException ("applicationIdentity");
  124. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  125. storageFile._applicationIdentity = applicationIdentity;
  126. storageFile.PostInit ();
  127. return storageFile;
  128. }
  129. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type applicationEvidenceType)
  130. {
  131. Demand (scope);
  132. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  133. storageFile.InitStore (scope, applicationEvidenceType);
  134. storageFile.PostInit ();
  135. return storageFile;
  136. }
  137. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByMachine)]
  138. public static IsolatedStorageFile GetMachineStoreForApplication ()
  139. {
  140. IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Application;
  141. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  142. storageFile.InitStore (scope, null);
  143. storageFile.PostInit ();
  144. return storageFile;
  145. }
  146. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByMachine)]
  147. public static IsolatedStorageFile GetMachineStoreForAssembly ()
  148. {
  149. IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Assembly;
  150. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  151. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (Assembly.GetCallingAssembly ().Evidence);
  152. storageFile.PostInit ();
  153. return storageFile;
  154. }
  155. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByMachine)]
  156. public static IsolatedStorageFile GetMachineStoreForDomain ()
  157. {
  158. IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
  159. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  160. storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
  161. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (Assembly.GetCallingAssembly ().Evidence);
  162. storageFile.PostInit ();
  163. return storageFile;
  164. }
  165. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByUser)]
  166. public static IsolatedStorageFile GetUserStoreForApplication ()
  167. {
  168. IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Application;
  169. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  170. storageFile.InitStore (scope, null);
  171. storageFile.PostInit ();
  172. return storageFile;
  173. }
  174. #endif
  175. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser)]
  176. public static IsolatedStorageFile GetUserStoreForAssembly ()
  177. {
  178. IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Assembly;
  179. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  180. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (Assembly.GetCallingAssembly ().Evidence);
  181. storageFile.PostInit ();
  182. return storageFile;
  183. }
  184. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]
  185. public static IsolatedStorageFile GetUserStoreForDomain ()
  186. {
  187. IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
  188. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  189. storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
  190. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (Assembly.GetCallingAssembly ().Evidence);
  191. storageFile.PostInit ();
  192. return storageFile;
  193. }
  194. public static void Remove (IsolatedStorageScope scope)
  195. {
  196. string dir = GetIsolatedStorageRoot (scope);
  197. Directory.Delete (dir, true);
  198. }
  199. // internal static stuff
  200. // Security Note: We're using InternalGetFolderPath because
  201. // IsolatedStorage must be able to work even if we do not have
  202. // FileIOPermission's PathDiscovery permissions
  203. internal static string GetIsolatedStorageRoot (IsolatedStorageScope scope)
  204. {
  205. // IsolatedStorageScope mixes several flags into one.
  206. // This first level deals with the root directory - it
  207. // is decided based on User, User+Roaming or Machine
  208. string root = null;
  209. if ((scope & IsolatedStorageScope.User) != 0) {
  210. if ((scope & IsolatedStorageScope.Roaming) != 0) {
  211. root = Environment.InternalGetFolderPath (Environment.SpecialFolder.LocalApplicationData);
  212. } else {
  213. root = Environment.InternalGetFolderPath (Environment.SpecialFolder.ApplicationData);
  214. }
  215. #if NET_2_0
  216. } else if ((scope & IsolatedStorageScope.Machine) != 0) {
  217. root = Environment.InternalGetFolderPath (Environment.SpecialFolder.CommonApplicationData);
  218. #endif
  219. }
  220. if (root == null) {
  221. string msg = Locale.GetText ("Couldn't access storage location for '{0}'.");
  222. throw new IsolatedStorageException (String.Format (msg, scope));
  223. }
  224. return Path.Combine (root, ".isolated-storage");
  225. }
  226. private static void Demand (IsolatedStorageScope scope)
  227. {
  228. if (SecurityManager.SecurityEnabled) {
  229. IsolatedStorageFilePermission isfp = new IsolatedStorageFilePermission (PermissionState.None);
  230. isfp.UsageAllowed = ScopeToContainment (scope);
  231. // TODO: quota
  232. isfp.Demand ();
  233. }
  234. }
  235. private static IsolatedStorageContainment ScopeToContainment (IsolatedStorageScope scope)
  236. {
  237. switch (scope) {
  238. case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
  239. return IsolatedStorageContainment.DomainIsolationByUser;
  240. case IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
  241. return IsolatedStorageContainment.AssemblyIsolationByUser;
  242. case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  243. return IsolatedStorageContainment.DomainIsolationByRoamingUser;
  244. case IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  245. return IsolatedStorageContainment.AssemblyIsolationByRoamingUser;
  246. #if NET_2_0
  247. case IsolatedStorageScope.Application | IsolatedStorageScope.User:
  248. return IsolatedStorageContainment.ApplicationIsolationByUser;
  249. case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
  250. return IsolatedStorageContainment.DomainIsolationByMachine;
  251. case IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
  252. return IsolatedStorageContainment.AssemblyIsolationByMachine;
  253. case IsolatedStorageScope.Application | IsolatedStorageScope.Machine:
  254. return IsolatedStorageContainment.ApplicationIsolationByMachine;
  255. case IsolatedStorageScope.Application | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  256. return IsolatedStorageContainment.ApplicationIsolationByRoamingUser;
  257. #endif
  258. default:
  259. // unknown ?!?! then ask for maximum (unrestricted)
  260. return IsolatedStorageContainment.UnrestrictedIsolatedStorage;
  261. }
  262. }
  263. internal static ulong GetDirectorySize (DirectoryInfo di)
  264. {
  265. ulong size = 0;
  266. foreach (FileInfo fi in di.GetFiles ())
  267. size += (ulong) fi.Length;
  268. foreach (DirectoryInfo d in di.GetDirectories ())
  269. size += GetDirectorySize (d);
  270. return size;
  271. }
  272. // non-static stuff
  273. private DirectoryInfo directory;
  274. private IsolatedStorageFile (IsolatedStorageScope scope)
  275. {
  276. storage_scope = scope;
  277. }
  278. internal IsolatedStorageFile (IsolatedStorageScope scope, string location)
  279. {
  280. storage_scope = scope;
  281. directory = new DirectoryInfo (location);
  282. if (!directory.Exists) {
  283. string msg = Locale.GetText ("Invalid storage.");
  284. throw new IsolatedStorageException (msg);
  285. }
  286. // load the identities
  287. }
  288. ~IsolatedStorageFile ()
  289. {
  290. }
  291. private void PostInit ()
  292. {
  293. string root = GetIsolatedStorageRoot (Scope);
  294. string dir = null;
  295. #if NET_2_0
  296. if (_applicationIdentity != null) {
  297. dir = String.Format ("a{0}{1}", SeparatorInternal, GetNameFromIdentity (_applicationIdentity));
  298. } else
  299. #endif
  300. if (_domainIdentity != null) {
  301. dir = String.Format ("d{0}{1}{0}{2}", SeparatorInternal,
  302. GetNameFromIdentity (_domainIdentity), GetNameFromIdentity (_assemblyIdentity));
  303. } else if (_assemblyIdentity != null) {
  304. dir = String.Format ("d{0}none{0}{1}", SeparatorInternal, GetNameFromIdentity (_assemblyIdentity));
  305. } else {
  306. throw new IsolatedStorageException (Locale.GetText ("No code identity available."));
  307. }
  308. root = Path.Combine (root, dir);
  309. // identities have been selected
  310. directory = new DirectoryInfo (root);
  311. if (!directory.Exists) {
  312. directory.Create ();
  313. SaveIdentities (root);
  314. }
  315. }
  316. [CLSCompliant(false)]
  317. public override ulong CurrentSize {
  318. get { return GetDirectorySize (directory); }
  319. }
  320. [CLSCompliant(false)]
  321. [MonoTODO ("Maximum size must be restricted by the security policy")]
  322. public override ulong MaximumSize {
  323. // return an ulong but default is signed long
  324. get { return Int64.MaxValue; }
  325. }
  326. internal string Root {
  327. get { return directory.FullName; }
  328. }
  329. // methods
  330. public void Close ()
  331. {
  332. }
  333. public void CreateDirectory (string dir)
  334. {
  335. directory.CreateSubdirectory (dir);
  336. }
  337. public void DeleteDirectory (string dir)
  338. {
  339. DirectoryInfo subdir = directory.CreateSubdirectory (dir);
  340. subdir.Delete ();
  341. }
  342. public void DeleteFile (string file)
  343. {
  344. File.Delete (Path.Combine (directory.FullName, file));
  345. }
  346. public void Dispose ()
  347. {
  348. }
  349. public string[] GetDirectoryNames (string searchPattern)
  350. {
  351. DirectoryInfo[] adi = directory.GetDirectories (searchPattern);
  352. return GetNames (adi);
  353. }
  354. private string[] GetNames (FileSystemInfo[] afsi)
  355. {
  356. string[] r = new string[afsi.Length];
  357. for (int i = 0; i != afsi.Length; ++i)
  358. r[i] = afsi[i].Name;
  359. return r;
  360. }
  361. public string[] GetFileNames (string searchPattern)
  362. {
  363. FileInfo[] afi = directory.GetFiles (searchPattern);
  364. return GetNames (afi);
  365. }
  366. public override void Remove ()
  367. {
  368. directory.Delete (true);
  369. }
  370. [MonoTODO ("Permissions are CAS related")]
  371. protected override IsolatedStoragePermission GetPermission (PermissionSet ps)
  372. {
  373. throw new NotImplementedException ();
  374. }
  375. // internal stuff
  376. private string GetNameFromIdentity (object identity)
  377. {
  378. // Note: Default evidences return an XML string with ToString
  379. byte[] id = Encoding.UTF8.GetBytes (identity.ToString ());
  380. SHA1 hash = SHA1.Create ();
  381. // this create an unique name for an identity - bad identities like Url
  382. // results in bad (i.e. changing) names.
  383. byte[] full = hash.ComputeHash (id, 0, id.Length);
  384. byte[] half = new byte [10];
  385. Buffer.BlockCopy (full, 0, half, 0, half.Length);
  386. return CryptoConvert.ToHex (half);
  387. }
  388. private static object GetTypeFromEvidence (Evidence e, Type t)
  389. {
  390. foreach (object o in e) {
  391. if (o.GetType () == t)
  392. return o;
  393. }
  394. return null;
  395. }
  396. internal static object GetAssemblyIdentityFromEvidence (Evidence e)
  397. {
  398. // we prefer...
  399. // a. a Publisher evidence
  400. object identity = GetTypeFromEvidence (e, typeof (Publisher));
  401. if (identity != null)
  402. return identity;
  403. // b. a StrongName evidence
  404. identity = GetTypeFromEvidence (e, typeof (StrongName));
  405. if (identity != null)
  406. return identity;
  407. // c. a Url evidence
  408. return GetTypeFromEvidence (e, typeof (Url));
  409. }
  410. internal static object GetDomainIdentityFromEvidence (Evidence e)
  411. {
  412. // we prefer...
  413. // a. a ApplicationDirectory evidence
  414. object identity = GetTypeFromEvidence (e, typeof (ApplicationDirectory));
  415. if (identity != null)
  416. return identity;
  417. // b. a Url evidence
  418. return GetTypeFromEvidence (e, typeof (Url));
  419. }
  420. [Serializable]
  421. private struct Identities {
  422. public object Application;
  423. public object Assembly;
  424. public object Domain;
  425. public Identities (object application, object assembly, object domain)
  426. {
  427. Application = application;
  428. Assembly = assembly;
  429. Domain = domain;
  430. }
  431. }
  432. private void LoadIdentities (string root)
  433. {
  434. if (!File.Exists (root + ".storage"))
  435. throw new IsolatedStorageException (Locale.GetText ("Missing identities."));
  436. using (FileStream fs = File.OpenRead (root + ".storage")) {
  437. BinaryFormatter deformatter = new BinaryFormatter ();
  438. Identities identities = (Identities) deformatter.Deserialize (fs);
  439. fs.Close ();
  440. _applicationIdentity = identities.Application;
  441. _assemblyIdentity = identities.Assembly;
  442. _domainIdentity = identities.Domain;
  443. }
  444. }
  445. private void SaveIdentities (string root)
  446. {
  447. Identities identities = new Identities (_applicationIdentity, _assemblyIdentity, _domainIdentity);
  448. using (FileStream fs = File.OpenWrite (root + ".storage")) {
  449. BinaryFormatter formatter = new BinaryFormatter ();
  450. formatter.Serialize (fs, identities);
  451. fs.Close ();
  452. }
  453. }
  454. }
  455. }