IsolatedStorageFile.cs 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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. #if !MOONLIGHT
  31. using System.Collections;
  32. using System.Reflection;
  33. using System.Runtime.InteropServices;
  34. using System.Runtime.Serialization.Formatters.Binary;
  35. using System.Security;
  36. using System.Security.Cryptography;
  37. using System.Security.Permissions;
  38. using System.Security.Policy;
  39. using System.Text;
  40. using System.Threading;
  41. using Mono.Security.Cryptography;
  42. namespace System.IO.IsolatedStorage {
  43. // This is a terribly named class. It doesn't actually represent a file as
  44. // much as a directory
  45. [ComVisible (true)]
  46. // FIXME: Further limit the assertion when imperative Assert is implemented
  47. [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
  48. public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable {
  49. private bool _resolved;
  50. private ulong _maxSize;
  51. private Evidence _fullEvidences;
  52. private static Mutex mutex = new Mutex ();
  53. #if NET_4_0
  54. private bool closed;
  55. private bool disposed;
  56. #endif
  57. public static IEnumerator GetEnumerator (IsolatedStorageScope scope)
  58. {
  59. Demand (scope);
  60. switch (scope) {
  61. case IsolatedStorageScope.User:
  62. case IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  63. case IsolatedStorageScope.Machine:
  64. break;
  65. default:
  66. string msg = Locale.GetText ("Invalid scope, only User, User|Roaming and Machine are valid");
  67. throw new ArgumentException (msg);
  68. }
  69. return new IsolatedStorageFileEnumerator (scope, GetIsolatedStorageRoot (scope));
  70. }
  71. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope,
  72. Evidence domainEvidence, Type domainEvidenceType,
  73. Evidence assemblyEvidence, Type assemblyEvidenceType)
  74. {
  75. Demand (scope);
  76. bool domain = ((scope & IsolatedStorageScope.Domain) != 0);
  77. if (domain && (domainEvidence == null))
  78. throw new ArgumentNullException ("domainEvidence");
  79. bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
  80. if (assembly && (assemblyEvidence == null))
  81. throw new ArgumentNullException ("assemblyEvidence");
  82. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  83. if (domain) {
  84. if (domainEvidenceType == null) {
  85. storageFile._domainIdentity = GetDomainIdentityFromEvidence (domainEvidence);
  86. } else {
  87. storageFile._domainIdentity = GetTypeFromEvidence (domainEvidence, domainEvidenceType);
  88. }
  89. if (storageFile._domainIdentity == null)
  90. throw new IsolatedStorageException (Locale.GetText ("Couldn't find domain identity."));
  91. }
  92. if (assembly) {
  93. if (assemblyEvidenceType == null) {
  94. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (assemblyEvidence);
  95. } else {
  96. storageFile._assemblyIdentity = GetTypeFromEvidence (assemblyEvidence, assemblyEvidenceType);
  97. }
  98. if (storageFile._assemblyIdentity == null)
  99. throw new IsolatedStorageException (Locale.GetText ("Couldn't find assembly identity."));
  100. }
  101. storageFile.PostInit ();
  102. return storageFile;
  103. }
  104. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object domainIdentity, object assemblyIdentity)
  105. {
  106. Demand (scope);
  107. if (((scope & IsolatedStorageScope.Domain) != 0) && (domainIdentity == null))
  108. throw new ArgumentNullException ("domainIdentity");
  109. bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
  110. if (assembly && (assemblyIdentity == null))
  111. throw new ArgumentNullException ("assemblyIdentity");
  112. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  113. if (assembly)
  114. storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  115. storageFile._domainIdentity = domainIdentity;
  116. storageFile._assemblyIdentity = assemblyIdentity;
  117. storageFile.PostInit ();
  118. return storageFile;
  119. }
  120. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
  121. {
  122. Demand (scope);
  123. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  124. if ((scope & IsolatedStorageScope.Domain) != 0) {
  125. if (domainEvidenceType == null)
  126. domainEvidenceType = typeof (Url);
  127. storageFile._domainIdentity = GetTypeFromEvidence (AppDomain.CurrentDomain.Evidence, domainEvidenceType);
  128. }
  129. if ((scope & IsolatedStorageScope.Assembly) != 0) {
  130. Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  131. storageFile._fullEvidences = e;
  132. if ((scope & IsolatedStorageScope.Domain) != 0) {
  133. if (assemblyEvidenceType == null)
  134. assemblyEvidenceType = typeof (Url);
  135. storageFile._assemblyIdentity = GetTypeFromEvidence (e, assemblyEvidenceType);
  136. } else {
  137. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
  138. }
  139. }
  140. storageFile.PostInit ();
  141. return storageFile;
  142. }
  143. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object applicationIdentity)
  144. {
  145. Demand (scope);
  146. if (applicationIdentity == null)
  147. throw new ArgumentNullException ("applicationIdentity");
  148. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  149. storageFile._applicationIdentity = applicationIdentity;
  150. storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  151. storageFile.PostInit ();
  152. return storageFile;
  153. }
  154. public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type applicationEvidenceType)
  155. {
  156. Demand (scope);
  157. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  158. storageFile.InitStore (scope, applicationEvidenceType);
  159. storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  160. storageFile.PostInit ();
  161. return storageFile;
  162. }
  163. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByMachine)]
  164. public static IsolatedStorageFile GetMachineStoreForApplication ()
  165. {
  166. IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Application;
  167. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  168. storageFile.InitStore (scope, null);
  169. storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  170. storageFile.PostInit ();
  171. return storageFile;
  172. }
  173. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByMachine)]
  174. public static IsolatedStorageFile GetMachineStoreForAssembly ()
  175. {
  176. IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Assembly;
  177. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  178. Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  179. storageFile._fullEvidences = e;
  180. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
  181. storageFile.PostInit ();
  182. return storageFile;
  183. }
  184. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByMachine)]
  185. public static IsolatedStorageFile GetMachineStoreForDomain ()
  186. {
  187. IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
  188. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  189. storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
  190. Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  191. storageFile._fullEvidences = e;
  192. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
  193. storageFile.PostInit ();
  194. return storageFile;
  195. }
  196. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByUser)]
  197. public static IsolatedStorageFile GetUserStoreForApplication ()
  198. {
  199. IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Application;
  200. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  201. storageFile.InitStore (scope, null);
  202. storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  203. storageFile.PostInit ();
  204. return storageFile;
  205. }
  206. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser)]
  207. public static IsolatedStorageFile GetUserStoreForAssembly ()
  208. {
  209. IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Assembly;
  210. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  211. Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  212. storageFile._fullEvidences = e;
  213. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
  214. storageFile.PostInit ();
  215. return storageFile;
  216. }
  217. [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]
  218. public static IsolatedStorageFile GetUserStoreForDomain ()
  219. {
  220. IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
  221. IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
  222. storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
  223. Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
  224. storageFile._fullEvidences = e;
  225. storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
  226. storageFile.PostInit ();
  227. return storageFile;
  228. }
  229. #if NET_4_0
  230. [ComVisible (false)]
  231. public static IsolatedStorageFile GetUserStoreForSite ()
  232. {
  233. throw new NotSupportedException ();
  234. }
  235. #endif
  236. public static void Remove (IsolatedStorageScope scope)
  237. {
  238. string dir = GetIsolatedStorageRoot (scope);
  239. if (!Directory.Exists (dir))
  240. return;
  241. try {
  242. Directory.Delete (dir, true);
  243. } catch (IOException) {
  244. throw new IsolatedStorageException ("Could not remove storage.");
  245. }
  246. }
  247. // internal static stuff
  248. // Security Note: We're using InternalGetFolderPath because
  249. // IsolatedStorage must be able to work even if we do not have
  250. // FileIOPermission's PathDiscovery permissions
  251. internal static string GetIsolatedStorageRoot (IsolatedStorageScope scope)
  252. {
  253. // IsolatedStorageScope mixes several flags into one.
  254. // This first level deals with the root directory - it
  255. // is decided based on User, User+Roaming or Machine
  256. string root = null;
  257. if ((scope & IsolatedStorageScope.User) != 0) {
  258. if ((scope & IsolatedStorageScope.Roaming) != 0) {
  259. root = Environment.InternalGetFolderPath (Environment.SpecialFolder.LocalApplicationData);
  260. } else {
  261. root = Environment.InternalGetFolderPath (Environment.SpecialFolder.ApplicationData);
  262. }
  263. } else if ((scope & IsolatedStorageScope.Machine) != 0) {
  264. root = Environment.InternalGetFolderPath (Environment.SpecialFolder.CommonApplicationData);
  265. }
  266. if (root == null) {
  267. string msg = Locale.GetText ("Couldn't access storage location for '{0}'.");
  268. throw new IsolatedStorageException (String.Format (msg, scope));
  269. }
  270. return Path.Combine (root, ".isolated-storage");
  271. }
  272. private static void Demand (IsolatedStorageScope scope)
  273. {
  274. if (SecurityManager.SecurityEnabled) {
  275. IsolatedStorageFilePermission isfp = new IsolatedStorageFilePermission (PermissionState.None);
  276. isfp.UsageAllowed = ScopeToContainment (scope);
  277. isfp.Demand ();
  278. }
  279. }
  280. private static IsolatedStorageContainment ScopeToContainment (IsolatedStorageScope scope)
  281. {
  282. switch (scope) {
  283. case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
  284. return IsolatedStorageContainment.DomainIsolationByUser;
  285. case IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
  286. return IsolatedStorageContainment.AssemblyIsolationByUser;
  287. case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  288. return IsolatedStorageContainment.DomainIsolationByRoamingUser;
  289. case IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  290. return IsolatedStorageContainment.AssemblyIsolationByRoamingUser;
  291. case IsolatedStorageScope.Application | IsolatedStorageScope.User:
  292. return IsolatedStorageContainment.ApplicationIsolationByUser;
  293. case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
  294. return IsolatedStorageContainment.DomainIsolationByMachine;
  295. case IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
  296. return IsolatedStorageContainment.AssemblyIsolationByMachine;
  297. case IsolatedStorageScope.Application | IsolatedStorageScope.Machine:
  298. return IsolatedStorageContainment.ApplicationIsolationByMachine;
  299. case IsolatedStorageScope.Application | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
  300. return IsolatedStorageContainment.ApplicationIsolationByRoamingUser;
  301. default:
  302. // unknown ?!?! then ask for maximum (unrestricted)
  303. return IsolatedStorageContainment.UnrestrictedIsolatedStorage;
  304. }
  305. }
  306. internal static ulong GetDirectorySize (DirectoryInfo di)
  307. {
  308. ulong size = 0;
  309. foreach (FileInfo fi in di.GetFiles ())
  310. size += (ulong) fi.Length;
  311. foreach (DirectoryInfo d in di.GetDirectories ())
  312. size += GetDirectorySize (d);
  313. return size;
  314. }
  315. // non-static stuff
  316. private DirectoryInfo directory;
  317. private IsolatedStorageFile (IsolatedStorageScope scope)
  318. {
  319. storage_scope = scope;
  320. }
  321. internal IsolatedStorageFile (IsolatedStorageScope scope, string location)
  322. {
  323. storage_scope = scope;
  324. directory = new DirectoryInfo (location);
  325. if (!directory.Exists) {
  326. string msg = Locale.GetText ("Invalid storage.");
  327. throw new IsolatedStorageException (msg);
  328. }
  329. // load the identities
  330. }
  331. ~IsolatedStorageFile ()
  332. {
  333. }
  334. private void PostInit ()
  335. {
  336. string root = GetIsolatedStorageRoot (Scope);
  337. string dir = null;
  338. #if MOBILE
  339. dir = "";
  340. #else
  341. if (_applicationIdentity != null) {
  342. dir = String.Format ("a{0}{1}", SeparatorInternal, GetNameFromIdentity (_applicationIdentity));
  343. } else if (_domainIdentity != null) {
  344. dir = String.Format ("d{0}{1}{0}{2}", SeparatorInternal,
  345. GetNameFromIdentity (_domainIdentity), GetNameFromIdentity (_assemblyIdentity));
  346. } else if (_assemblyIdentity != null) {
  347. dir = String.Format ("d{0}none{0}{1}", SeparatorInternal, GetNameFromIdentity (_assemblyIdentity));
  348. } else {
  349. throw new IsolatedStorageException (Locale.GetText ("No code identity available."));
  350. }
  351. #endif
  352. root = Path.Combine (root, dir);
  353. // identities have been selected
  354. directory = new DirectoryInfo (root);
  355. if (!directory.Exists) {
  356. try {
  357. directory.Create ();
  358. SaveIdentities (root);
  359. }
  360. catch (IOException) {
  361. }
  362. }
  363. }
  364. [CLSCompliant(false)]
  365. #if NET_4_0
  366. [Obsolete]
  367. #endif
  368. public override ulong CurrentSize {
  369. get { return GetDirectorySize (directory); }
  370. }
  371. [CLSCompliant(false)]
  372. #if NET_4_0
  373. [Obsolete]
  374. #endif
  375. public override ulong MaximumSize {
  376. // return an ulong but default is signed long
  377. get {
  378. if (!SecurityManager.SecurityEnabled)
  379. return Int64.MaxValue;
  380. if (_resolved)
  381. return _maxSize;
  382. Evidence e = null;
  383. if (_fullEvidences != null) {
  384. // if possible use the complete evidences we had
  385. // for computing the X identity
  386. e = _fullEvidences;
  387. } else {
  388. e = new Evidence ();
  389. // otherwise use what was provided
  390. if (_assemblyIdentity != null)
  391. e.AddHost (_assemblyIdentity);
  392. }
  393. if (e.Count < 1) {
  394. throw new InvalidOperationException (
  395. Locale.GetText ("Couldn't get the quota from the available evidences."));
  396. }
  397. PermissionSet denied = null;
  398. PermissionSet ps = SecurityManager.ResolvePolicy (e, null, null, null, out denied);
  399. IsolatedStoragePermission isp = GetPermission (ps);
  400. if (isp == null) {
  401. if (ps.IsUnrestricted ()) {
  402. _maxSize = Int64.MaxValue; /* default value */
  403. } else {
  404. throw new InvalidOperationException (
  405. Locale.GetText ("No quota from the available evidences."));
  406. }
  407. } else {
  408. _maxSize = (ulong) isp.UserQuota;
  409. }
  410. _resolved = true;
  411. return _maxSize;
  412. }
  413. }
  414. internal string Root {
  415. get { return directory.FullName; }
  416. }
  417. #if NET_4_0
  418. [ComVisible (false)]
  419. public override long AvailableFreeSpace {
  420. get {
  421. CheckOpen ();
  422. // See the notes for 'Quota'
  423. return Int64.MaxValue;
  424. }
  425. }
  426. [ComVisible (false)]
  427. public override long Quota {
  428. get {
  429. CheckOpen ();
  430. // Since we don't fully support CAS, we are likely
  431. // going to return Int64.MaxValue always, but we return
  432. // MaximumSize just in case.
  433. return (long)MaximumSize;
  434. }
  435. }
  436. [ComVisible (false)]
  437. public override long UsedSize {
  438. get {
  439. CheckOpen ();
  440. return (long)GetDirectorySize (directory);
  441. }
  442. }
  443. [ComVisible (false)]
  444. public static bool IsEnabled {
  445. get {
  446. return true;
  447. }
  448. }
  449. internal bool IsClosed {
  450. get {
  451. return closed;
  452. }
  453. }
  454. internal bool IsDisposed {
  455. get {
  456. return disposed;
  457. }
  458. }
  459. #endif
  460. // methods
  461. public void Close ()
  462. {
  463. #if NET_4_0
  464. closed = true;
  465. #endif
  466. }
  467. public void CreateDirectory (string dir)
  468. {
  469. if (dir == null)
  470. throw new ArgumentNullException ("dir");
  471. if (dir.IndexOfAny (Path.PathSeparatorChars) < 0) {
  472. if (directory.GetFiles (dir).Length > 0)
  473. #if NET_4_0
  474. throw new IsolatedStorageException ("Unable to create directory.");
  475. #else
  476. throw new IOException (Locale.GetText ("Directory name already exists as a file."));
  477. #endif
  478. directory.CreateSubdirectory (dir);
  479. } else {
  480. string[] dirs = dir.Split (Path.PathSeparatorChars);
  481. DirectoryInfo dinfo = directory;
  482. for (int i = 0; i < dirs.Length; i++) {
  483. if (dinfo.GetFiles (dirs [i]).Length > 0)
  484. #if NET_4_0
  485. throw new IsolatedStorageException ("Unable to create directory.");
  486. #else
  487. throw new IOException (Locale.GetText (
  488. "Part of the directory name already exists as a file."));
  489. #endif
  490. dinfo = dinfo.CreateSubdirectory (dirs [i]);
  491. }
  492. }
  493. }
  494. #if NET_4_0
  495. [ComVisible (false)]
  496. public void CopyFile (string sourceFileName, string destinationFileName)
  497. {
  498. CopyFile (sourceFileName, destinationFileName, false);
  499. }
  500. [ComVisible (false)]
  501. public void CopyFile (string sourceFileName, string destinationFileName, bool overwrite)
  502. {
  503. if (sourceFileName == null)
  504. throw new ArgumentNullException ("sourceFileName");
  505. if (destinationFileName == null)
  506. throw new ArgumentNullException ("destinationFileName");
  507. if (sourceFileName.Trim ().Length == 0)
  508. throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
  509. if (destinationFileName.Trim ().Length == 0)
  510. throw new ArgumentException ("An empty file name is not valid.", "destinationFileName");
  511. CheckOpen ();
  512. string source_full_path = Path.Combine (directory.FullName, sourceFileName);
  513. string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
  514. if (!IsPathInStorage (source_full_path) || !IsPathInStorage (dest_full_path))
  515. throw new IsolatedStorageException ("Operation not allowed.");
  516. // These excs can be thrown from File.Copy, but we can try to detect them from here.
  517. if (!Directory.Exists (Path.GetDirectoryName (source_full_path)))
  518. throw new DirectoryNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
  519. if (!File.Exists (source_full_path))
  520. throw new FileNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
  521. if (File.Exists (dest_full_path) && !overwrite)
  522. throw new IsolatedStorageException ("Operation not allowed.");
  523. try {
  524. File.Copy (source_full_path, dest_full_path, overwrite);
  525. } catch (IOException) {
  526. throw new IsolatedStorageException ("Operation not allowed.");
  527. }
  528. }
  529. [ComVisible (false)]
  530. public IsolatedStorageFileStream CreateFile (string path)
  531. {
  532. return new IsolatedStorageFileStream (path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this);
  533. }
  534. #endif
  535. public void DeleteDirectory (string dir)
  536. {
  537. try {
  538. DirectoryInfo subdir = directory.CreateSubdirectory (dir);
  539. subdir.Delete ();
  540. }
  541. catch {
  542. // hide the real exception to avoid leaking the full path
  543. throw new IsolatedStorageException (Locale.GetText ("Could not delete directory '{0}'", dir));
  544. }
  545. }
  546. public void DeleteFile (string file)
  547. {
  548. if (file == null)
  549. throw new ArgumentNullException ("file");
  550. string full_path = Path.Combine (directory.FullName, file);
  551. if (!File.Exists (full_path))
  552. throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
  553. try {
  554. File.Delete (Path.Combine (directory.FullName, file));
  555. } catch {
  556. // hide the internal exception, just as DeleteDirectory does.
  557. throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
  558. }
  559. }
  560. public void Dispose ()
  561. {
  562. #if NET_4_0
  563. // Dispose may be calling Close, but we are not sure
  564. disposed = true;
  565. #endif
  566. // nothing to dispose, anyway we want to please the tools
  567. GC.SuppressFinalize (this);
  568. }
  569. #if NET_4_0
  570. [ComVisible (false)]
  571. public bool DirectoryExists (string path)
  572. {
  573. if (path == null)
  574. throw new ArgumentNullException ("path");
  575. CheckOpen ();
  576. string full_path = Path.Combine (directory.FullName, path);
  577. if (!IsPathInStorage (full_path))
  578. return false;
  579. return Directory.Exists (full_path);
  580. }
  581. [ComVisible (false)]
  582. public bool FileExists (string path)
  583. {
  584. if (path == null)
  585. throw new ArgumentNullException ("path");
  586. CheckOpen ();
  587. string full_path = Path.Combine (directory.FullName, path);
  588. if (!IsPathInStorage (full_path))
  589. return false;
  590. return File.Exists (full_path);
  591. }
  592. [ComVisible (false)]
  593. public DateTimeOffset GetCreationTime (string path)
  594. {
  595. if (path == null)
  596. throw new ArgumentNullException ("path");
  597. if (path.Trim ().Length == 0)
  598. throw new ArgumentException ("An empty path is not valid.");
  599. CheckOpen ();
  600. string full_path = Path.Combine (directory.FullName, path);
  601. if (File.Exists (full_path))
  602. return File.GetCreationTime (full_path);
  603. return Directory.GetCreationTime (full_path);
  604. }
  605. [ComVisible (false)]
  606. public DateTimeOffset GetLastAccessTime (string path)
  607. {
  608. if (path == null)
  609. throw new ArgumentNullException ("path");
  610. if (path.Trim ().Length == 0)
  611. throw new ArgumentException ("An empty path is not valid.");
  612. CheckOpen ();
  613. string full_path = Path.Combine (directory.FullName, path);
  614. if (File.Exists (full_path))
  615. return File.GetLastAccessTime (full_path);
  616. return Directory.GetLastAccessTime (full_path);
  617. }
  618. [ComVisible (false)]
  619. public DateTimeOffset GetLastWriteTime (string path)
  620. {
  621. if (path == null)
  622. throw new ArgumentNullException ("path");
  623. if (path.Trim ().Length == 0)
  624. throw new ArgumentException ("An empty path is not valid.");
  625. CheckOpen ();
  626. string full_path = Path.Combine (directory.FullName, path);
  627. if (File.Exists (full_path))
  628. return File.GetLastWriteTime (full_path);
  629. return Directory.GetLastWriteTime (full_path);
  630. }
  631. #endif
  632. public string[] GetDirectoryNames (string searchPattern)
  633. {
  634. if (searchPattern == null)
  635. throw new ArgumentNullException ("searchPattern");
  636. #if NET_4_0
  637. if (searchPattern.Contains (".."))
  638. throw new ArgumentException ("Search pattern cannot contain '..' to move up directories.", "searchPattern");
  639. #endif
  640. // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
  641. // so we need to split them to get the right results
  642. string path = Path.GetDirectoryName (searchPattern);
  643. string pattern = Path.GetFileName (searchPattern);
  644. DirectoryInfo[] adi = null;
  645. if (path == null || path.Length == 0) {
  646. adi = directory.GetDirectories (searchPattern);
  647. } else {
  648. DirectoryInfo[] subdirs = directory.GetDirectories (path);
  649. // we're looking for a single result, identical to path (no pattern here)
  650. // we're also looking for something under the current path (not outside isolated storage)
  651. if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs [0].FullName.IndexOf (directory.FullName) >= 0)) {
  652. adi = subdirs [0].GetDirectories (pattern);
  653. } else {
  654. // CAS, even in FullTrust, normally enforce IsolatedStorage
  655. throw new SecurityException ();
  656. }
  657. }
  658. return GetNames (adi);
  659. }
  660. #if NET_4_0
  661. [ComVisible (false)]
  662. public string [] GetDirectoryNames ()
  663. {
  664. return GetDirectoryNames ("*");
  665. }
  666. #endif
  667. private string[] GetNames (FileSystemInfo[] afsi)
  668. {
  669. string[] r = new string[afsi.Length];
  670. for (int i = 0; i != afsi.Length; ++i)
  671. r[i] = afsi[i].Name;
  672. return r;
  673. }
  674. public string[] GetFileNames (string searchPattern)
  675. {
  676. if (searchPattern == null)
  677. throw new ArgumentNullException ("searchPattern");
  678. #if NET_4_0
  679. if (searchPattern.Contains (".."))
  680. throw new ArgumentException ("Search pattern cannot contain '..' to move up directories.", "searchPattern");
  681. #endif
  682. // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
  683. // so we need to split them to get the right results
  684. string path = Path.GetDirectoryName (searchPattern);
  685. string pattern = Path.GetFileName (searchPattern);
  686. FileInfo[] afi = null;
  687. if (path == null || path.Length == 0) {
  688. afi = directory.GetFiles (searchPattern);
  689. } else {
  690. DirectoryInfo[] subdirs = directory.GetDirectories (path);
  691. // we're looking for a single result, identical to path (no pattern here)
  692. // we're also looking for something under the current path (not outside isolated storage)
  693. if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs [0].FullName.IndexOf (directory.FullName) >= 0)) {
  694. afi = subdirs [0].GetFiles (pattern);
  695. } else {
  696. // CAS, even in FullTrust, normally enforce IsolatedStorage
  697. throw new SecurityException ();
  698. }
  699. }
  700. return GetNames (afi);
  701. }
  702. #if NET_4_0
  703. [ComVisible (false)]
  704. public string [] GetFileNames ()
  705. {
  706. return GetFileNames ("*");
  707. }
  708. [ComVisible (false)]
  709. public override bool IncreaseQuotaTo (long newQuotaSize)
  710. {
  711. if (newQuotaSize < Quota)
  712. throw new ArgumentException ();
  713. CheckOpen ();
  714. // .Net is supposed to be returning false, as mentioned in the docs.
  715. return false;
  716. }
  717. [ComVisible (false)]
  718. public void MoveDirectory (string sourceDirectoryName, string destinationDirectoryName)
  719. {
  720. if (sourceDirectoryName == null)
  721. throw new ArgumentNullException ("sourceDirectoryName");
  722. if (destinationDirectoryName == null)
  723. throw new ArgumentNullException ("sourceDirectoryName");
  724. if (sourceDirectoryName.Trim ().Length == 0)
  725. throw new ArgumentException ("An empty directory name is not valid.", "sourceDirectoryName");
  726. if (destinationDirectoryName.Trim ().Length == 0)
  727. throw new ArgumentException ("An empty directory name is not valid.", "destinationDirectoryName");
  728. CheckOpen ();
  729. string src_full_path = Path.Combine (directory.FullName, sourceDirectoryName);
  730. string dest_full_path = Path.Combine (directory.FullName, destinationDirectoryName);
  731. if (!IsPathInStorage (src_full_path) || !IsPathInStorage (dest_full_path))
  732. throw new IsolatedStorageException ("Operation not allowed.");
  733. if (!Directory.Exists (src_full_path))
  734. throw new DirectoryNotFoundException ("Could not find a part of path '" + sourceDirectoryName + "'.");
  735. if (!Directory.Exists (Path.GetDirectoryName (dest_full_path)))
  736. throw new DirectoryNotFoundException ("Could not find a part of path '" + destinationDirectoryName + "'.");
  737. try {
  738. Directory.Move (src_full_path, dest_full_path);
  739. } catch (IOException) {
  740. throw new IsolatedStorageException ("Operation not allowed.");
  741. }
  742. }
  743. [ComVisible (false)]
  744. public void MoveFile (string sourceFileName, string destinationFileName)
  745. {
  746. if (sourceFileName == null)
  747. throw new ArgumentNullException ("sourceFileName");
  748. if (destinationFileName == null)
  749. throw new ArgumentNullException ("sourceFileName");
  750. if (sourceFileName.Trim ().Length == 0)
  751. throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
  752. if (destinationFileName.Trim ().Length == 0)
  753. throw new ArgumentException ("An empty file name is not valid.", "destinationFileName");
  754. CheckOpen ();
  755. string source_full_path = Path.Combine (directory.FullName, sourceFileName);
  756. string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
  757. if (!IsPathInStorage (source_full_path) || !IsPathInStorage (dest_full_path))
  758. throw new IsolatedStorageException ("Operation not allowed.");
  759. if (!File.Exists (source_full_path))
  760. throw new FileNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
  761. // I expected a DirectoryNotFound exception.
  762. if (!Directory.Exists (Path.GetDirectoryName (dest_full_path)))
  763. throw new IsolatedStorageException ("Operation not allowed.");
  764. try {
  765. File.Move (source_full_path, dest_full_path);
  766. } catch (IOException) {
  767. throw new IsolatedStorageException ("Operation not allowed.");
  768. }
  769. }
  770. [ComVisible (false)]
  771. public IsolatedStorageFileStream OpenFile (string path, FileMode mode)
  772. {
  773. return new IsolatedStorageFileStream (path, mode, this);
  774. }
  775. [ComVisible (false)]
  776. public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access)
  777. {
  778. return new IsolatedStorageFileStream (path, mode, access, this);
  779. }
  780. [ComVisible (false)]
  781. public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access, FileShare share)
  782. {
  783. return new IsolatedStorageFileStream (path, mode, access, share, this);
  784. }
  785. #endif
  786. public override void Remove ()
  787. {
  788. #if NET_4_0
  789. CheckOpen (false);
  790. #endif
  791. try {
  792. directory.Delete (true);
  793. } catch {
  794. throw new IsolatedStorageException ("Could not remove storage.");
  795. }
  796. // It seems .Net is calling Close from here.
  797. Close ();
  798. }
  799. protected override IsolatedStoragePermission GetPermission (PermissionSet ps)
  800. {
  801. if (ps == null)
  802. return null;
  803. return (IsolatedStoragePermission) ps.GetPermission (typeof (IsolatedStorageFilePermission));
  804. }
  805. // internal stuff
  806. #if NET_4_0
  807. void CheckOpen ()
  808. {
  809. CheckOpen (true);
  810. }
  811. void CheckOpen (bool checkDirExists)
  812. {
  813. if (disposed)
  814. throw new ObjectDisposedException ("IsolatedStorageFile");
  815. if (closed)
  816. throw new InvalidOperationException ("Storage needs to be open for this operation.");
  817. if (checkDirExists && !Directory.Exists (directory.FullName))
  818. throw new IsolatedStorageException ("Isolated storage has been removed or disabled.");
  819. }
  820. bool IsPathInStorage (string path)
  821. {
  822. return Path.GetFullPath (path).StartsWith (directory.FullName);
  823. }
  824. #endif
  825. private string GetNameFromIdentity (object identity)
  826. {
  827. // Note: Default evidences return an XML string with ToString
  828. byte[] id = Encoding.UTF8.GetBytes (identity.ToString ());
  829. SHA1 hash = SHA1.Create ();
  830. // this create an unique name for an identity - bad identities like Url
  831. // results in bad (i.e. changing) names.
  832. byte[] full = hash.ComputeHash (id, 0, id.Length);
  833. byte[] half = new byte [10];
  834. Buffer.BlockCopy (full, 0, half, 0, half.Length);
  835. return CryptoConvert.ToHex (half);
  836. }
  837. private static object GetTypeFromEvidence (Evidence e, Type t)
  838. {
  839. foreach (object o in e) {
  840. if (o.GetType () == t)
  841. return o;
  842. }
  843. return null;
  844. }
  845. internal static object GetAssemblyIdentityFromEvidence (Evidence e)
  846. {
  847. // we prefer...
  848. // a. a Publisher evidence
  849. object identity = GetTypeFromEvidence (e, typeof (Publisher));
  850. if (identity != null)
  851. return identity;
  852. // b. a StrongName evidence
  853. identity = GetTypeFromEvidence (e, typeof (StrongName));
  854. if (identity != null)
  855. return identity;
  856. // c. a Url evidence
  857. return GetTypeFromEvidence (e, typeof (Url));
  858. }
  859. internal static object GetDomainIdentityFromEvidence (Evidence e)
  860. {
  861. // we prefer...
  862. // a. a ApplicationDirectory evidence
  863. object identity = GetTypeFromEvidence (e, typeof (ApplicationDirectory));
  864. if (identity != null)
  865. return identity;
  866. // b. a Url evidence
  867. return GetTypeFromEvidence (e, typeof (Url));
  868. }
  869. [Serializable]
  870. private struct Identities {
  871. public object Application;
  872. public object Assembly;
  873. public object Domain;
  874. public Identities (object application, object assembly, object domain)
  875. {
  876. Application = application;
  877. Assembly = assembly;
  878. Domain = domain;
  879. }
  880. }
  881. /*
  882. [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
  883. private void LoadIdentities (string root)
  884. {
  885. if (!File.Exists (root + ".storage"))
  886. throw new IsolatedStorageException (Locale.GetText ("Missing identities."));
  887. BinaryFormatter deformatter = new BinaryFormatter ();
  888. using (FileStream fs = File.OpenRead (root + ".storage")) {
  889. Identities identities = (Identities) deformatter.Deserialize (fs);
  890. _applicationIdentity = identities.Application;
  891. _assemblyIdentity = identities.Assembly;
  892. _domainIdentity = identities.Domain;
  893. }
  894. }
  895. */
  896. [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
  897. private void SaveIdentities (string root)
  898. {
  899. Identities identities = new Identities (_applicationIdentity, _assemblyIdentity, _domainIdentity);
  900. BinaryFormatter formatter = new BinaryFormatter ();
  901. mutex.WaitOne ();
  902. try {
  903. using (FileStream fs = File.Create (root + ".storage")) {
  904. formatter.Serialize (fs, identities);
  905. }
  906. }
  907. finally {
  908. mutex.ReleaseMutex ();
  909. }
  910. }
  911. }
  912. }
  913. #endif