2 // System.IO.IsolatedStorage.IsolatedStorageFile
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Sebastien Pouliot <sebastien@ximian.com>
8 // (C) 2003 Jonathan Pryor
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections;
31 using System.Reflection;
32 using System.Runtime.InteropServices;
33 using System.Runtime.Serialization.Formatters.Binary;
34 using System.Security;
35 using System.Security.Cryptography;
36 using System.Security.Permissions;
37 using System.Security.Policy;
39 using System.Threading;
41 using Mono.Security.Cryptography;
43 namespace System.IO.IsolatedStorage {
45 // This is a terribly named class. It doesn't actually represent a file as
46 // much as a directory
50 // FIXME: Further limit the assertion when imperative Assert is implemented
51 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
52 public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable {
54 private bool _resolved;
55 private ulong _maxSize;
56 private Evidence _fullEvidences;
57 private static readonly Mutex mutex = new Mutex ();
61 private bool disposed;
63 public static IEnumerator GetEnumerator (IsolatedStorageScope scope)
68 case IsolatedStorageScope.User:
69 case IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
70 case IsolatedStorageScope.Machine:
73 string msg = Locale.GetText ("Invalid scope, only User, User|Roaming and Machine are valid");
74 throw new ArgumentException (msg);
77 return new IsolatedStorageFileEnumerator (scope, GetIsolatedStorageRoot (scope));
80 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope,
81 Evidence domainEvidence, Type domainEvidenceType,
82 Evidence assemblyEvidence, Type assemblyEvidenceType)
86 bool domain = ((scope & IsolatedStorageScope.Domain) != 0);
87 if (domain && (domainEvidence == null))
88 throw new ArgumentNullException ("domainEvidence");
90 bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
91 if (assembly && (assemblyEvidence == null))
92 throw new ArgumentNullException ("assemblyEvidence");
94 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
97 if (domainEvidenceType == null) {
98 storageFile._domainIdentity = GetDomainIdentityFromEvidence (domainEvidence);
100 storageFile._domainIdentity = GetTypeFromEvidence (domainEvidence, domainEvidenceType);
103 if (storageFile._domainIdentity == null)
104 throw new IsolatedStorageException (Locale.GetText ("Couldn't find domain identity."));
108 if (assemblyEvidenceType == null) {
109 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (assemblyEvidence);
111 storageFile._assemblyIdentity = GetTypeFromEvidence (assemblyEvidence, assemblyEvidenceType);
114 if (storageFile._assemblyIdentity == null)
115 throw new IsolatedStorageException (Locale.GetText ("Couldn't find assembly identity."));
118 storageFile.PostInit ();
122 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object domainIdentity, object assemblyIdentity)
126 if (((scope & IsolatedStorageScope.Domain) != 0) && (domainIdentity == null))
127 throw new ArgumentNullException ("domainIdentity");
129 bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
130 if (assembly && (assemblyIdentity == null))
131 throw new ArgumentNullException ("assemblyIdentity");
133 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
136 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
138 storageFile._domainIdentity = domainIdentity;
139 storageFile._assemblyIdentity = assemblyIdentity;
140 storageFile.PostInit ();
144 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
147 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
149 if ((scope & IsolatedStorageScope.Domain) != 0) {
150 if (domainEvidenceType == null)
151 domainEvidenceType = typeof (Url);
152 storageFile._domainIdentity = GetTypeFromEvidence (AppDomain.CurrentDomain.Evidence, domainEvidenceType);
154 if ((scope & IsolatedStorageScope.Assembly) != 0) {
155 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
156 storageFile._fullEvidences = e;
157 if ((scope & IsolatedStorageScope.Domain) != 0) {
158 if (assemblyEvidenceType == null)
159 assemblyEvidenceType = typeof (Url);
160 storageFile._assemblyIdentity = GetTypeFromEvidence (e, assemblyEvidenceType);
162 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
166 storageFile.PostInit ();
169 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object applicationIdentity)
172 if (applicationIdentity == null)
173 throw new ArgumentNullException ("applicationIdentity");
175 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
176 storageFile._applicationIdentity = applicationIdentity;
178 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
180 storageFile.PostInit ();
184 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type applicationEvidenceType)
187 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
188 storageFile.InitStore (scope, applicationEvidenceType);
190 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
192 storageFile.PostInit ();
196 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByMachine)]
197 public static IsolatedStorageFile GetMachineStoreForApplication ()
199 IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Application;
200 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
201 storageFile.InitStore (scope, null);
203 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
205 storageFile.PostInit ();
209 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByMachine)]
210 public static IsolatedStorageFile GetMachineStoreForAssembly ()
212 IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Assembly;
213 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
215 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
216 storageFile._fullEvidences = e;
217 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
219 storageFile.PostInit ();
223 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByMachine)]
224 public static IsolatedStorageFile GetMachineStoreForDomain ()
226 IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
227 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
229 storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
230 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
231 storageFile._fullEvidences = e;
232 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
234 storageFile.PostInit ();
238 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByUser)]
239 public static IsolatedStorageFile GetUserStoreForApplication ()
241 IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Application;
242 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
243 storageFile.InitStore (scope, null);
245 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
247 storageFile.PostInit ();
251 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser)]
252 public static IsolatedStorageFile GetUserStoreForAssembly ()
254 IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Assembly;
255 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
257 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
258 storageFile._fullEvidences = e;
259 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
261 storageFile.PostInit ();
265 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]
266 public static IsolatedStorageFile GetUserStoreForDomain ()
268 IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
269 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
271 storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
272 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
273 storageFile._fullEvidences = e;
274 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
276 storageFile.PostInit ();
281 public static IsolatedStorageFile GetUserStoreForSite ()
283 throw new NotSupportedException ();
286 public static void Remove (IsolatedStorageScope scope)
288 string dir = GetIsolatedStorageRoot (scope);
289 if (!Directory.Exists (dir))
293 Directory.Delete (dir, true);
294 } catch (IOException) {
295 throw new IsolatedStorageException ("Could not remove storage.");
299 // internal static stuff
301 // Security Note: We're using InternalGetFolderPath because
302 // IsolatedStorage must be able to work even if we do not have
303 // FileIOPermission's PathDiscovery permissions
304 internal static string GetIsolatedStorageRoot (IsolatedStorageScope scope)
306 // IsolatedStorageScope mixes several flags into one.
307 // This first level deals with the root directory - it
308 // is decided based on User, User+Roaming or Machine
311 if ((scope & IsolatedStorageScope.User) != 0) {
312 if ((scope & IsolatedStorageScope.Roaming) != 0) {
313 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.Create);
315 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create);
317 } else if ((scope & IsolatedStorageScope.Machine) != 0) {
318 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.CommonApplicationData, Environment.SpecialFolderOption.Create);
322 string msg = Locale.GetText ("Couldn't access storage location for '{0}'.");
323 throw new IsolatedStorageException (String.Format (msg, scope));
326 return Path.Combine (root, ".isolated-storage");
329 private static void Demand (IsolatedStorageScope scope)
332 if (SecurityManager.SecurityEnabled) {
333 IsolatedStorageFilePermission isfp = new IsolatedStorageFilePermission (PermissionState.None);
334 isfp.UsageAllowed = ScopeToContainment (scope);
340 private static IsolatedStorageContainment ScopeToContainment (IsolatedStorageScope scope)
343 case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
344 return IsolatedStorageContainment.DomainIsolationByUser;
345 case IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
346 return IsolatedStorageContainment.AssemblyIsolationByUser;
347 case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
348 return IsolatedStorageContainment.DomainIsolationByRoamingUser;
349 case IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
350 return IsolatedStorageContainment.AssemblyIsolationByRoamingUser;
351 case IsolatedStorageScope.Application | IsolatedStorageScope.User:
352 return IsolatedStorageContainment.ApplicationIsolationByUser;
353 case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
354 return IsolatedStorageContainment.DomainIsolationByMachine;
355 case IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
356 return IsolatedStorageContainment.AssemblyIsolationByMachine;
357 case IsolatedStorageScope.Application | IsolatedStorageScope.Machine:
358 return IsolatedStorageContainment.ApplicationIsolationByMachine;
359 case IsolatedStorageScope.Application | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
360 return IsolatedStorageContainment.ApplicationIsolationByRoamingUser;
362 // unknown ?!?! then ask for maximum (unrestricted)
363 return IsolatedStorageContainment.UnrestrictedIsolatedStorage;
367 internal static ulong GetDirectorySize (DirectoryInfo di)
371 foreach (FileInfo fi in di.GetFiles ())
372 size += (ulong) fi.Length;
374 foreach (DirectoryInfo d in di.GetDirectories ())
375 size += GetDirectorySize (d);
382 private DirectoryInfo directory;
384 private IsolatedStorageFile (IsolatedStorageScope scope)
386 storage_scope = scope;
389 internal IsolatedStorageFile (IsolatedStorageScope scope, string location)
391 storage_scope = scope;
392 directory = new DirectoryInfo (location);
393 if (!directory.Exists) {
394 string msg = Locale.GetText ("Invalid storage.");
395 throw new IsolatedStorageException (msg);
397 // load the identities
400 ~IsolatedStorageFile ()
404 private void PostInit ()
406 string root = GetIsolatedStorageRoot (Scope);
411 if (_applicationIdentity != null) {
412 dir = String.Format ("a{0}{1}", SeparatorInternal, GetNameFromIdentity (_applicationIdentity));
413 } else if (_domainIdentity != null) {
414 dir = String.Format ("d{0}{1}{0}{2}", SeparatorInternal,
415 GetNameFromIdentity (_domainIdentity), GetNameFromIdentity (_assemblyIdentity));
416 } else if (_assemblyIdentity != null) {
417 dir = String.Format ("d{0}none{0}{1}", SeparatorInternal, GetNameFromIdentity (_assemblyIdentity));
419 throw new IsolatedStorageException (Locale.GetText ("No code identity available."));
423 root = Path.Combine (root, dir);
425 // identities have been selected
426 directory = new DirectoryInfo (root);
427 if (!directory.Exists) {
431 SaveIdentities (root);
434 catch (IOException) {
439 [CLSCompliant(false)]
441 public override ulong CurrentSize {
442 get { return GetDirectorySize (directory); }
445 [CLSCompliant(false)]
447 public override ulong MaximumSize {
448 // return an ulong but default is signed long
451 // no security manager is active so the rest of the code is useless
452 return Int64.MaxValue;
454 if (!SecurityManager.SecurityEnabled)
455 return Int64.MaxValue;
461 if (_fullEvidences != null) {
462 // if possible use the complete evidences we had
463 // for computing the X identity
467 // otherwise use what was provided
468 if (_assemblyIdentity != null)
469 e.AddHost (_assemblyIdentity);
472 throw new InvalidOperationException (
473 Locale.GetText ("Couldn't get the quota from the available evidences."));
476 PermissionSet denied = null;
477 PermissionSet ps = SecurityManager.ResolvePolicy (e, null, null, null, out denied);
478 IsolatedStoragePermission isp = GetPermission (ps);
480 if (ps.IsUnrestricted ()) {
481 _maxSize = Int64.MaxValue; /* default value */
483 throw new InvalidOperationException (
484 Locale.GetText ("No quota from the available evidences."));
487 _maxSize = (ulong) isp.UserQuota;
495 internal string Root {
496 get { return directory.FullName; }
500 public override long AvailableFreeSpace {
504 // See the notes for 'Quota'
505 return Int64.MaxValue;
511 public override long Quota {
515 // Since we don't fully support CAS, we are likely
516 // going to return Int64.MaxValue always, but we return
517 // MaximumSize just in case.
518 return (long)MaximumSize;
523 public override long UsedSize {
526 return (long)GetDirectorySize (directory);
531 public static bool IsEnabled {
537 internal bool IsClosed {
543 internal bool IsDisposed {
556 public void CreateDirectory (string dir)
559 throw new ArgumentNullException ("dir");
561 if (dir.IndexOfAny (Path.PathSeparatorChars) < 0) {
562 if (directory.GetFiles (dir).Length > 0)
563 throw new IsolatedStorageException ("Unable to create directory.");
564 directory.CreateSubdirectory (dir);
566 string[] dirs = dir.Split (Path.PathSeparatorChars, StringSplitOptions.RemoveEmptyEntries);
567 DirectoryInfo dinfo = directory;
569 for (int i = 0; i < dirs.Length; i++) {
570 if (dinfo.GetFiles (dirs [i]).Length > 0)
571 throw new IsolatedStorageException ("Unable to create directory.");
572 dinfo = dinfo.CreateSubdirectory (dirs [i]);
578 public void CopyFile (string sourceFileName, string destinationFileName)
580 CopyFile (sourceFileName, destinationFileName, false);
584 public void CopyFile (string sourceFileName, string destinationFileName, bool overwrite)
586 if (sourceFileName == null)
587 throw new ArgumentNullException ("sourceFileName");
588 if (destinationFileName == null)
589 throw new ArgumentNullException ("destinationFileName");
590 if (sourceFileName.Trim ().Length == 0)
591 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
592 if (destinationFileName.Trim ().Length == 0)
593 throw new ArgumentException ("An empty file name is not valid.", "destinationFileName");
597 string source_full_path = Path.Combine (directory.FullName, sourceFileName);
598 string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
600 if (!IsPathInStorage (source_full_path) || !IsPathInStorage (dest_full_path))
601 throw new IsolatedStorageException ("Operation not allowed.");
602 // These excs can be thrown from File.Copy, but we can try to detect them from here.
603 if (!Directory.Exists (Path.GetDirectoryName (source_full_path)))
604 throw new DirectoryNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
605 if (!File.Exists (source_full_path))
606 throw new FileNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
607 if (File.Exists (dest_full_path) && !overwrite)
608 throw new IsolatedStorageException ("Operation not allowed.");
611 File.Copy (source_full_path, dest_full_path, overwrite);
612 } catch (IOException) {
613 throw new IsolatedStorageException ("Operation not allowed.");
618 public IsolatedStorageFileStream CreateFile (string path)
620 return new IsolatedStorageFileStream (path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this);
623 public void DeleteDirectory (string dir)
626 if (Path.IsPathRooted (dir))
627 dir = dir.Substring (1);
628 DirectoryInfo subdir = directory.CreateSubdirectory (dir);
632 // hide the real exception to avoid leaking the full path
633 throw new IsolatedStorageException (Locale.GetText ("Could not delete directory '{0}'", dir));
637 public void DeleteFile (string file)
640 throw new ArgumentNullException ("file");
642 string full_path = Path.Combine (directory.FullName, file);
643 if (!File.Exists (full_path))
644 throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
647 File.Delete (Path.Combine (directory.FullName, file));
649 // hide the internal exception, just as DeleteDirectory does.
650 throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
654 public void Dispose ()
656 // Dispose may be calling Close, but we are not sure
658 // nothing to dispose, anyway we want to please the tools
659 GC.SuppressFinalize (this);
663 public bool DirectoryExists (string path)
666 throw new ArgumentNullException ("path");
670 string full_path = Path.Combine (directory.FullName, path);
671 if (!IsPathInStorage (full_path))
674 return Directory.Exists (full_path);
678 public bool FileExists (string path)
681 throw new ArgumentNullException ("path");
685 string full_path = Path.Combine (directory.FullName, path);
686 if (!IsPathInStorage (full_path))
689 return File.Exists (full_path);
693 public DateTimeOffset GetCreationTime (string path)
696 throw new ArgumentNullException ("path");
697 if (path.Trim ().Length == 0)
698 throw new ArgumentException ("An empty path is not valid.");
702 string full_path = Path.Combine (directory.FullName, path);
703 if (File.Exists (full_path))
704 return File.GetCreationTime (full_path);
706 return Directory.GetCreationTime (full_path);
710 public DateTimeOffset GetLastAccessTime (string path)
713 throw new ArgumentNullException ("path");
714 if (path.Trim ().Length == 0)
715 throw new ArgumentException ("An empty path is not valid.");
719 string full_path = Path.Combine (directory.FullName, path);
720 if (File.Exists (full_path))
721 return File.GetLastAccessTime (full_path);
723 return Directory.GetLastAccessTime (full_path);
727 public DateTimeOffset GetLastWriteTime (string path)
730 throw new ArgumentNullException ("path");
731 if (path.Trim ().Length == 0)
732 throw new ArgumentException ("An empty path is not valid.");
736 string full_path = Path.Combine (directory.FullName, path);
737 if (File.Exists (full_path))
738 return File.GetLastWriteTime (full_path);
740 return Directory.GetLastWriteTime (full_path);
743 public string[] GetDirectoryNames (string searchPattern)
745 if (searchPattern == null)
746 throw new ArgumentNullException ("searchPattern");
747 if (searchPattern.Contains (".."))
748 throw new ArgumentException ("Search pattern cannot contain '..' to move up directories.", "searchPattern");
750 // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
751 // so we need to split them to get the right results
752 string path = Path.GetDirectoryName (searchPattern);
753 string pattern = Path.GetFileName (searchPattern);
754 DirectoryInfo[] adi = null;
755 if (path == null || path.Length == 0) {
756 adi = directory.GetDirectories (searchPattern);
758 // we're looking for a single result, identical to path (no pattern here)
759 DirectoryInfo[] subdirs = directory.GetDirectories (path);
760 DirectoryInfo di = subdirs [0];
761 // we're also looking for something under the current path (not outside isolated storage)
762 if (di.FullName.IndexOf (directory.FullName) >= 0) {
763 adi = di.GetDirectories (pattern);
764 string[] segments = path.Split (new char [] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
765 for (int i = segments.Length - 1; i >= 0; i--) {
766 if (di.Name != segments [i]) {
774 // CAS, even in FullTrust, normally enforce IsolatedStorage
776 throw new SecurityException ();
778 return GetNames (adi);
782 public string [] GetDirectoryNames ()
784 return GetDirectoryNames ("*");
787 private string[] GetNames (FileSystemInfo[] afsi)
789 string[] r = new string[afsi.Length];
790 for (int i = 0; i != afsi.Length; ++i)
795 public string[] GetFileNames (string searchPattern)
797 if (searchPattern == null)
798 throw new ArgumentNullException ("searchPattern");
799 if (searchPattern.Contains (".."))
800 throw new ArgumentException ("Search pattern cannot contain '..' to move up directories.", "searchPattern");
802 // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
803 // so we need to split them to get the right results
804 string path = Path.GetDirectoryName (searchPattern);
805 string pattern = Path.GetFileName (searchPattern);
806 FileInfo[] afi = null;
807 if (path == null || path.Length == 0) {
808 afi = directory.GetFiles (searchPattern);
810 DirectoryInfo[] subdirs = directory.GetDirectories (path);
811 // we're looking for a single result, identical to path (no pattern here)
812 // we're also looking for something under the current path (not outside isolated storage)
813 if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs [0].FullName.IndexOf (directory.FullName) >= 0)) {
814 afi = subdirs [0].GetFiles (pattern);
816 // CAS, even in FullTrust, normally enforce IsolatedStorage
817 throw new SecurityException ();
821 return GetNames (afi);
825 public string [] GetFileNames ()
827 return GetFileNames ("*");
831 public override bool IncreaseQuotaTo (long newQuotaSize)
833 if (newQuotaSize < Quota)
834 throw new ArgumentException ();
838 // .Net is supposed to be returning false, as mentioned in the docs.
843 public void MoveDirectory (string sourceDirectoryName, string destinationDirectoryName)
845 if (sourceDirectoryName == null)
846 throw new ArgumentNullException ("sourceDirectoryName");
847 if (destinationDirectoryName == null)
848 throw new ArgumentNullException ("sourceDirectoryName");
849 if (sourceDirectoryName.Trim ().Length == 0)
850 throw new ArgumentException ("An empty directory name is not valid.", "sourceDirectoryName");
851 if (destinationDirectoryName.Trim ().Length == 0)
852 throw new ArgumentException ("An empty directory name is not valid.", "destinationDirectoryName");
856 string src_full_path = Path.Combine (directory.FullName, sourceDirectoryName);
857 string dest_full_path = Path.Combine (directory.FullName, destinationDirectoryName);
859 if (!IsPathInStorage (src_full_path) || !IsPathInStorage (dest_full_path))
860 throw new IsolatedStorageException ("Operation not allowed.");
861 if (!Directory.Exists (src_full_path))
862 throw new DirectoryNotFoundException ("Could not find a part of path '" + sourceDirectoryName + "'.");
863 if (!Directory.Exists (Path.GetDirectoryName (dest_full_path)))
864 throw new DirectoryNotFoundException ("Could not find a part of path '" + destinationDirectoryName + "'.");
867 Directory.Move (src_full_path, dest_full_path);
868 } catch (IOException) {
869 throw new IsolatedStorageException ("Operation not allowed.");
874 public void MoveFile (string sourceFileName, string destinationFileName)
876 if (sourceFileName == null)
877 throw new ArgumentNullException ("sourceFileName");
878 if (destinationFileName == null)
879 throw new ArgumentNullException ("sourceFileName");
880 if (sourceFileName.Trim ().Length == 0)
881 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
882 if (destinationFileName.Trim ().Length == 0)
883 throw new ArgumentException ("An empty file name is not valid.", "destinationFileName");
887 string source_full_path = Path.Combine (directory.FullName, sourceFileName);
888 string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
890 if (!IsPathInStorage (source_full_path) || !IsPathInStorage (dest_full_path))
891 throw new IsolatedStorageException ("Operation not allowed.");
892 if (!File.Exists (source_full_path))
893 throw new FileNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
894 // I expected a DirectoryNotFound exception.
895 if (!Directory.Exists (Path.GetDirectoryName (dest_full_path)))
896 throw new IsolatedStorageException ("Operation not allowed.");
899 File.Move (source_full_path, dest_full_path);
900 } catch (IOException) {
901 throw new IsolatedStorageException ("Operation not allowed.");
906 public IsolatedStorageFileStream OpenFile (string path, FileMode mode)
908 return new IsolatedStorageFileStream (path, mode, this);
912 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access)
914 return new IsolatedStorageFileStream (path, mode, access, this);
918 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access, FileShare share)
920 return new IsolatedStorageFileStream (path, mode, access, share, this);
923 public override void Remove ()
927 directory.Delete (true);
929 throw new IsolatedStorageException ("Could not remove storage.");
932 // It seems .Net is calling Close from here.
937 protected override IsolatedStoragePermission GetPermission (PermissionSet ps)
941 return (IsolatedStoragePermission) ps.GetPermission (typeof (IsolatedStorageFilePermission));
950 void CheckOpen (bool checkDirExists)
953 throw new ObjectDisposedException ("IsolatedStorageFile");
955 throw new InvalidOperationException ("Storage needs to be open for this operation.");
956 if (checkDirExists && !Directory.Exists (directory.FullName))
957 throw new IsolatedStorageException ("Isolated storage has been removed or disabled.");
960 bool IsPathInStorage (string path)
962 return Path.GetFullPath (path).StartsWith (directory.FullName);
966 private string GetNameFromIdentity (object identity)
968 // Note: Default evidences return an XML string with ToString
969 byte[] id = Encoding.UTF8.GetBytes (identity.ToString ());
970 SHA1 hash = SHA1.Create ();
971 // this create an unique name for an identity - bad identities like Url
972 // results in bad (i.e. changing) names.
973 byte[] full = hash.ComputeHash (id, 0, id.Length);
974 byte[] half = new byte [10];
975 Buffer.BlockCopy (full, 0, half, 0, half.Length);
976 return CryptoConvert.ToHex (half);
979 private static object GetTypeFromEvidence (Evidence e, Type t)
981 foreach (object o in e) {
982 if (o.GetType () == t)
988 internal static object GetAssemblyIdentityFromEvidence (Evidence e)
991 // a. a Publisher evidence
992 object identity = GetTypeFromEvidence (e, typeof (Publisher));
993 if (identity != null)
995 // b. a StrongName evidence
996 identity = GetTypeFromEvidence (e, typeof (StrongName));
997 if (identity != null)
1000 return GetTypeFromEvidence (e, typeof (Url));
1003 internal static object GetDomainIdentityFromEvidence (Evidence e)
1006 // a. a ApplicationDirectory evidence
1007 object identity = GetTypeFromEvidence (e, typeof (ApplicationDirectory));
1008 if (identity != null)
1010 // b. a Url evidence
1011 return GetTypeFromEvidence (e, typeof (Url));
1015 private struct Identities {
1016 public object Application;
1017 public object Assembly;
1018 public object Domain;
1020 public Identities (object application, object assembly, object domain)
1022 Application = application;
1023 Assembly = assembly;
1028 [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
1029 private void LoadIdentities (string root)
1031 if (!File.Exists (root + ".storage"))
1032 throw new IsolatedStorageException (Locale.GetText ("Missing identities."));
1034 BinaryFormatter deformatter = new BinaryFormatter ();
1035 using (FileStream fs = File.OpenRead (root + ".storage")) {
1036 Identities identities = (Identities) deformatter.Deserialize (fs);
1038 _applicationIdentity = identities.Application;
1039 _assemblyIdentity = identities.Assembly;
1040 _domainIdentity = identities.Domain;
1044 [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
1045 private void SaveIdentities (string root)
1047 Identities identities = new Identities (_applicationIdentity, _assemblyIdentity, _domainIdentity);
1048 BinaryFormatter formatter = new BinaryFormatter ();
1051 using (FileStream fs = File.Create (root + ".storage")) {
1052 formatter.Serialize (fs, identities);
1056 mutex.ReleaseMutex ();