IsolatedStorageFile.cs 35 KB

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