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.
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;
40 using System.Threading;
42 using Mono.Security.Cryptography;
44 namespace System.IO.IsolatedStorage {
46 // This is a terribly named class. It doesn't actually represent a file as
47 // much as a directory
51 // FIXME: Further limit the assertion when imperative Assert is implemented
52 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
53 public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable {
55 private bool _resolved;
56 private ulong _maxSize;
58 private Evidence _fullEvidences;
59 private static Mutex mutex = new Mutex ();
62 private bool disposed;
65 public static IEnumerator GetEnumerator (IsolatedStorageScope scope)
70 case IsolatedStorageScope.User:
71 case IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
72 case IsolatedStorageScope.Machine:
75 string msg = Locale.GetText ("Invalid scope, only User, User|Roaming and Machine are valid");
76 throw new ArgumentException (msg);
79 return new IsolatedStorageFileEnumerator (scope, GetIsolatedStorageRoot (scope));
82 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope,
83 Evidence domainEvidence, Type domainEvidenceType,
84 Evidence assemblyEvidence, Type assemblyEvidenceType)
88 bool domain = ((scope & IsolatedStorageScope.Domain) != 0);
89 if (domain && (domainEvidence == null))
90 throw new ArgumentNullException ("domainEvidence");
92 bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
93 if (assembly && (assemblyEvidence == null))
94 throw new ArgumentNullException ("assemblyEvidence");
96 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
99 if (domainEvidenceType == null) {
100 storageFile._domainIdentity = GetDomainIdentityFromEvidence (domainEvidence);
102 storageFile._domainIdentity = GetTypeFromEvidence (domainEvidence, domainEvidenceType);
105 if (storageFile._domainIdentity == null)
106 throw new IsolatedStorageException (Locale.GetText ("Couldn't find domain identity."));
110 if (assemblyEvidenceType == null) {
111 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (assemblyEvidence);
113 storageFile._assemblyIdentity = GetTypeFromEvidence (assemblyEvidence, assemblyEvidenceType);
116 if (storageFile._assemblyIdentity == null)
117 throw new IsolatedStorageException (Locale.GetText ("Couldn't find assembly identity."));
120 storageFile.PostInit ();
124 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object domainIdentity, object assemblyIdentity)
128 if (((scope & IsolatedStorageScope.Domain) != 0) && (domainIdentity == null))
129 throw new ArgumentNullException ("domainIdentity");
131 bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
132 if (assembly && (assemblyIdentity == null))
133 throw new ArgumentNullException ("assemblyIdentity");
135 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
138 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
140 storageFile._domainIdentity = domainIdentity;
141 storageFile._assemblyIdentity = assemblyIdentity;
142 storageFile.PostInit ();
146 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
149 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
151 if ((scope & IsolatedStorageScope.Domain) != 0) {
152 if (domainEvidenceType == null)
153 domainEvidenceType = typeof (Url);
154 storageFile._domainIdentity = GetTypeFromEvidence (AppDomain.CurrentDomain.Evidence, domainEvidenceType);
156 if ((scope & IsolatedStorageScope.Assembly) != 0) {
157 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
158 storageFile._fullEvidences = e;
159 if ((scope & IsolatedStorageScope.Domain) != 0) {
160 if (assemblyEvidenceType == null)
161 assemblyEvidenceType = typeof (Url);
162 storageFile._assemblyIdentity = GetTypeFromEvidence (e, assemblyEvidenceType);
164 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
168 storageFile.PostInit ();
171 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object applicationIdentity)
174 if (applicationIdentity == null)
175 throw new ArgumentNullException ("applicationIdentity");
177 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
178 storageFile._applicationIdentity = applicationIdentity;
180 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
182 storageFile.PostInit ();
186 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type applicationEvidenceType)
189 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
190 storageFile.InitStore (scope, applicationEvidenceType);
192 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
194 storageFile.PostInit ();
198 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByMachine)]
199 public static IsolatedStorageFile GetMachineStoreForApplication ()
201 IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Application;
202 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
203 storageFile.InitStore (scope, null);
205 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
207 storageFile.PostInit ();
211 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByMachine)]
212 public static IsolatedStorageFile GetMachineStoreForAssembly ()
214 IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Assembly;
215 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
217 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
218 storageFile._fullEvidences = e;
219 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
221 storageFile.PostInit ();
225 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByMachine)]
226 public static IsolatedStorageFile GetMachineStoreForDomain ()
228 IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
229 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
231 storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
232 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
233 storageFile._fullEvidences = e;
234 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
236 storageFile.PostInit ();
240 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByUser)]
241 public static IsolatedStorageFile GetUserStoreForApplication ()
243 IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Application;
244 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
245 storageFile.InitStore (scope, null);
247 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
249 storageFile.PostInit ();
253 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser)]
254 public static IsolatedStorageFile GetUserStoreForAssembly ()
256 IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Assembly;
257 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
259 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
260 storageFile._fullEvidences = e;
261 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
263 storageFile.PostInit ();
267 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]
268 public static IsolatedStorageFile GetUserStoreForDomain ()
270 IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
271 IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
273 storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
274 Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
275 storageFile._fullEvidences = e;
276 storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
278 storageFile.PostInit ();
282 #if NET_4_0 || MOBILE
284 public static IsolatedStorageFile GetUserStoreForSite ()
286 throw new NotSupportedException ();
290 public static void Remove (IsolatedStorageScope scope)
292 string dir = GetIsolatedStorageRoot (scope);
293 if (!Directory.Exists (dir))
297 Directory.Delete (dir, true);
298 } catch (IOException) {
299 throw new IsolatedStorageException ("Could not remove storage.");
303 // internal static stuff
305 // Security Note: We're using InternalGetFolderPath because
306 // IsolatedStorage must be able to work even if we do not have
307 // FileIOPermission's PathDiscovery permissions
308 internal static string GetIsolatedStorageRoot (IsolatedStorageScope scope)
310 // IsolatedStorageScope mixes several flags into one.
311 // This first level deals with the root directory - it
312 // is decided based on User, User+Roaming or Machine
315 if ((scope & IsolatedStorageScope.User) != 0) {
316 if ((scope & IsolatedStorageScope.Roaming) != 0) {
317 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.Create);
319 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create);
321 } else if ((scope & IsolatedStorageScope.Machine) != 0) {
322 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.CommonApplicationData, Environment.SpecialFolderOption.Create);
326 string msg = Locale.GetText ("Couldn't access storage location for '{0}'.");
327 throw new IsolatedStorageException (String.Format (msg, scope));
330 return Path.Combine (root, ".isolated-storage");
333 private static void Demand (IsolatedStorageScope scope)
336 if (SecurityManager.SecurityEnabled) {
337 IsolatedStorageFilePermission isfp = new IsolatedStorageFilePermission (PermissionState.None);
338 isfp.UsageAllowed = ScopeToContainment (scope);
344 private static IsolatedStorageContainment ScopeToContainment (IsolatedStorageScope scope)
347 case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
348 return IsolatedStorageContainment.DomainIsolationByUser;
349 case IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
350 return IsolatedStorageContainment.AssemblyIsolationByUser;
351 case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
352 return IsolatedStorageContainment.DomainIsolationByRoamingUser;
353 case IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
354 return IsolatedStorageContainment.AssemblyIsolationByRoamingUser;
355 case IsolatedStorageScope.Application | IsolatedStorageScope.User:
356 return IsolatedStorageContainment.ApplicationIsolationByUser;
357 case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
358 return IsolatedStorageContainment.DomainIsolationByMachine;
359 case IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
360 return IsolatedStorageContainment.AssemblyIsolationByMachine;
361 case IsolatedStorageScope.Application | IsolatedStorageScope.Machine:
362 return IsolatedStorageContainment.ApplicationIsolationByMachine;
363 case IsolatedStorageScope.Application | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
364 return IsolatedStorageContainment.ApplicationIsolationByRoamingUser;
366 // unknown ?!?! then ask for maximum (unrestricted)
367 return IsolatedStorageContainment.UnrestrictedIsolatedStorage;
371 internal static ulong GetDirectorySize (DirectoryInfo di)
375 foreach (FileInfo fi in di.GetFiles ())
376 size += (ulong) fi.Length;
378 foreach (DirectoryInfo d in di.GetDirectories ())
379 size += GetDirectorySize (d);
386 private DirectoryInfo directory;
388 private IsolatedStorageFile (IsolatedStorageScope scope)
390 storage_scope = scope;
393 internal IsolatedStorageFile (IsolatedStorageScope scope, string location)
395 storage_scope = scope;
396 directory = new DirectoryInfo (location);
397 if (!directory.Exists) {
398 string msg = Locale.GetText ("Invalid storage.");
399 throw new IsolatedStorageException (msg);
401 // load the identities
404 ~IsolatedStorageFile ()
408 private void PostInit ()
410 string root = GetIsolatedStorageRoot (Scope);
415 if (_applicationIdentity != null) {
416 dir = String.Format ("a{0}{1}", SeparatorInternal, GetNameFromIdentity (_applicationIdentity));
417 } else if (_domainIdentity != null) {
418 dir = String.Format ("d{0}{1}{0}{2}", SeparatorInternal,
419 GetNameFromIdentity (_domainIdentity), GetNameFromIdentity (_assemblyIdentity));
420 } else if (_assemblyIdentity != null) {
421 dir = String.Format ("d{0}none{0}{1}", SeparatorInternal, GetNameFromIdentity (_assemblyIdentity));
423 throw new IsolatedStorageException (Locale.GetText ("No code identity available."));
427 root = Path.Combine (root, dir);
429 // identities have been selected
430 directory = new DirectoryInfo (root);
431 if (!directory.Exists) {
435 SaveIdentities (root);
438 catch (IOException) {
443 [CLSCompliant(false)]
444 #if NET_4_0 || MOBILE
447 public override ulong CurrentSize {
448 get { return GetDirectorySize (directory); }
451 [CLSCompliant(false)]
452 #if NET_4_0 || MOBILE
455 public override ulong MaximumSize {
456 // return an ulong but default is signed long
459 // no security manager is active so the rest of the code is useless
460 return Int64.MaxValue;
462 if (!SecurityManager.SecurityEnabled)
463 return Int64.MaxValue;
469 if (_fullEvidences != null) {
470 // if possible use the complete evidences we had
471 // for computing the X identity
475 // otherwise use what was provided
476 if (_assemblyIdentity != null)
477 e.AddHost (_assemblyIdentity);
480 throw new InvalidOperationException (
481 Locale.GetText ("Couldn't get the quota from the available evidences."));
484 PermissionSet denied = null;
485 PermissionSet ps = SecurityManager.ResolvePolicy (e, null, null, null, out denied);
486 IsolatedStoragePermission isp = GetPermission (ps);
488 if (ps.IsUnrestricted ()) {
489 _maxSize = Int64.MaxValue; /* default value */
491 throw new InvalidOperationException (
492 Locale.GetText ("No quota from the available evidences."));
495 _maxSize = (ulong) isp.UserQuota;
503 internal string Root {
504 get { return directory.FullName; }
507 #if NET_4_0 || MOBILE
509 public override long AvailableFreeSpace {
513 // See the notes for 'Quota'
514 return Int64.MaxValue;
520 public override long Quota {
524 // Since we don't fully support CAS, we are likely
525 // going to return Int64.MaxValue always, but we return
526 // MaximumSize just in case.
527 return (long)MaximumSize;
532 public override long UsedSize {
535 return (long)GetDirectorySize (directory);
540 public static bool IsEnabled {
546 internal bool IsClosed {
552 internal bool IsDisposed {
563 #if NET_4_0 || MOBILE
568 public void CreateDirectory (string dir)
571 throw new ArgumentNullException ("dir");
573 if (dir.IndexOfAny (Path.PathSeparatorChars) < 0) {
574 if (directory.GetFiles (dir).Length > 0)
575 #if NET_4_0 || MOBILE
576 throw new IsolatedStorageException ("Unable to create directory.");
578 throw new IOException (Locale.GetText ("Directory name already exists as a file."));
580 directory.CreateSubdirectory (dir);
582 string[] dirs = dir.Split (Path.PathSeparatorChars, StringSplitOptions.RemoveEmptyEntries);
583 DirectoryInfo dinfo = directory;
585 for (int i = 0; i < dirs.Length; i++) {
586 if (dinfo.GetFiles (dirs [i]).Length > 0)
587 #if NET_4_0 || MOBILE
588 throw new IsolatedStorageException ("Unable to create directory.");
590 throw new IOException (Locale.GetText (
591 "Part of the directory name already exists as a file."));
593 dinfo = dinfo.CreateSubdirectory (dirs [i]);
598 #if NET_4_0 || MOBILE
600 public void CopyFile (string sourceFileName, string destinationFileName)
602 CopyFile (sourceFileName, destinationFileName, false);
606 public void CopyFile (string sourceFileName, string destinationFileName, bool overwrite)
608 if (sourceFileName == null)
609 throw new ArgumentNullException ("sourceFileName");
610 if (destinationFileName == null)
611 throw new ArgumentNullException ("destinationFileName");
612 if (sourceFileName.Trim ().Length == 0)
613 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
614 if (destinationFileName.Trim ().Length == 0)
615 throw new ArgumentException ("An empty file name is not valid.", "destinationFileName");
619 string source_full_path = Path.Combine (directory.FullName, sourceFileName);
620 string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
622 if (!IsPathInStorage (source_full_path) || !IsPathInStorage (dest_full_path))
623 throw new IsolatedStorageException ("Operation not allowed.");
624 // These excs can be thrown from File.Copy, but we can try to detect them from here.
625 if (!Directory.Exists (Path.GetDirectoryName (source_full_path)))
626 throw new DirectoryNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
627 if (!File.Exists (source_full_path))
628 throw new FileNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
629 if (File.Exists (dest_full_path) && !overwrite)
630 throw new IsolatedStorageException ("Operation not allowed.");
633 File.Copy (source_full_path, dest_full_path, overwrite);
634 } catch (IOException) {
635 throw new IsolatedStorageException ("Operation not allowed.");
640 public IsolatedStorageFileStream CreateFile (string path)
642 return new IsolatedStorageFileStream (path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this);
646 public void DeleteDirectory (string dir)
649 if (Path.IsPathRooted (dir))
650 dir = dir.Substring (1);
651 DirectoryInfo subdir = directory.CreateSubdirectory (dir);
655 // hide the real exception to avoid leaking the full path
656 throw new IsolatedStorageException (Locale.GetText ("Could not delete directory '{0}'", dir));
660 public void DeleteFile (string file)
663 throw new ArgumentNullException ("file");
665 string full_path = Path.Combine (directory.FullName, file);
666 if (!File.Exists (full_path))
667 throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
670 File.Delete (Path.Combine (directory.FullName, file));
672 // hide the internal exception, just as DeleteDirectory does.
673 throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
677 public void Dispose ()
679 #if NET_4_0 || MOBILE
680 // Dispose may be calling Close, but we are not sure
683 // nothing to dispose, anyway we want to please the tools
684 GC.SuppressFinalize (this);
687 #if NET_4_0 || MOBILE
689 public bool DirectoryExists (string path)
692 throw new ArgumentNullException ("path");
696 string full_path = Path.Combine (directory.FullName, path);
697 if (!IsPathInStorage (full_path))
700 return Directory.Exists (full_path);
704 public bool FileExists (string path)
707 throw new ArgumentNullException ("path");
711 string full_path = Path.Combine (directory.FullName, path);
712 if (!IsPathInStorage (full_path))
715 return File.Exists (full_path);
719 public DateTimeOffset GetCreationTime (string path)
722 throw new ArgumentNullException ("path");
723 if (path.Trim ().Length == 0)
724 throw new ArgumentException ("An empty path is not valid.");
728 string full_path = Path.Combine (directory.FullName, path);
729 if (File.Exists (full_path))
730 return File.GetCreationTime (full_path);
732 return Directory.GetCreationTime (full_path);
736 public DateTimeOffset GetLastAccessTime (string path)
739 throw new ArgumentNullException ("path");
740 if (path.Trim ().Length == 0)
741 throw new ArgumentException ("An empty path is not valid.");
745 string full_path = Path.Combine (directory.FullName, path);
746 if (File.Exists (full_path))
747 return File.GetLastAccessTime (full_path);
749 return Directory.GetLastAccessTime (full_path);
753 public DateTimeOffset GetLastWriteTime (string path)
756 throw new ArgumentNullException ("path");
757 if (path.Trim ().Length == 0)
758 throw new ArgumentException ("An empty path is not valid.");
762 string full_path = Path.Combine (directory.FullName, path);
763 if (File.Exists (full_path))
764 return File.GetLastWriteTime (full_path);
766 return Directory.GetLastWriteTime (full_path);
770 public string[] GetDirectoryNames (string searchPattern)
772 if (searchPattern == null)
773 throw new ArgumentNullException ("searchPattern");
774 #if NET_4_0 || MOBILE
775 if (searchPattern.Contains (".."))
776 throw new ArgumentException ("Search pattern cannot contain '..' to move up directories.", "searchPattern");
779 // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
780 // so we need to split them to get the right results
781 string path = Path.GetDirectoryName (searchPattern);
782 string pattern = Path.GetFileName (searchPattern);
783 DirectoryInfo[] adi = null;
784 if (path == null || path.Length == 0) {
785 adi = directory.GetDirectories (searchPattern);
787 // we're looking for a single result, identical to path (no pattern here)
788 DirectoryInfo[] subdirs = directory.GetDirectories (path);
789 DirectoryInfo di = subdirs [0];
790 // we're also looking for something under the current path (not outside isolated storage)
791 if (di.FullName.IndexOf (directory.FullName) >= 0) {
792 adi = di.GetDirectories (pattern);
793 string[] segments = path.Split (new char [] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
794 for (int i = segments.Length - 1; i >= 0; i--) {
795 if (di.Name != segments [i]) {
803 // CAS, even in FullTrust, normally enforce IsolatedStorage
805 throw new SecurityException ();
807 return GetNames (adi);
810 #if NET_4_0 || MOBILE
812 public string [] GetDirectoryNames ()
814 return GetDirectoryNames ("*");
818 private string[] GetNames (FileSystemInfo[] afsi)
820 string[] r = new string[afsi.Length];
821 for (int i = 0; i != afsi.Length; ++i)
826 public string[] GetFileNames (string searchPattern)
828 if (searchPattern == null)
829 throw new ArgumentNullException ("searchPattern");
830 #if NET_4_0 || MOBILE
831 if (searchPattern.Contains (".."))
832 throw new ArgumentException ("Search pattern cannot contain '..' to move up directories.", "searchPattern");
835 // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
836 // so we need to split them to get the right results
837 string path = Path.GetDirectoryName (searchPattern);
838 string pattern = Path.GetFileName (searchPattern);
839 FileInfo[] afi = null;
840 if (path == null || path.Length == 0) {
841 afi = directory.GetFiles (searchPattern);
843 DirectoryInfo[] subdirs = directory.GetDirectories (path);
844 // we're looking for a single result, identical to path (no pattern here)
845 // we're also looking for something under the current path (not outside isolated storage)
846 if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs [0].FullName.IndexOf (directory.FullName) >= 0)) {
847 afi = subdirs [0].GetFiles (pattern);
849 // CAS, even in FullTrust, normally enforce IsolatedStorage
850 throw new SecurityException ();
854 return GetNames (afi);
857 #if NET_4_0 || MOBILE
859 public string [] GetFileNames ()
861 return GetFileNames ("*");
865 public override bool IncreaseQuotaTo (long newQuotaSize)
867 if (newQuotaSize < Quota)
868 throw new ArgumentException ();
872 // .Net is supposed to be returning false, as mentioned in the docs.
877 public void MoveDirectory (string sourceDirectoryName, string destinationDirectoryName)
879 if (sourceDirectoryName == null)
880 throw new ArgumentNullException ("sourceDirectoryName");
881 if (destinationDirectoryName == null)
882 throw new ArgumentNullException ("sourceDirectoryName");
883 if (sourceDirectoryName.Trim ().Length == 0)
884 throw new ArgumentException ("An empty directory name is not valid.", "sourceDirectoryName");
885 if (destinationDirectoryName.Trim ().Length == 0)
886 throw new ArgumentException ("An empty directory name is not valid.", "destinationDirectoryName");
890 string src_full_path = Path.Combine (directory.FullName, sourceDirectoryName);
891 string dest_full_path = Path.Combine (directory.FullName, destinationDirectoryName);
893 if (!IsPathInStorage (src_full_path) || !IsPathInStorage (dest_full_path))
894 throw new IsolatedStorageException ("Operation not allowed.");
895 if (!Directory.Exists (src_full_path))
896 throw new DirectoryNotFoundException ("Could not find a part of path '" + sourceDirectoryName + "'.");
897 if (!Directory.Exists (Path.GetDirectoryName (dest_full_path)))
898 throw new DirectoryNotFoundException ("Could not find a part of path '" + destinationDirectoryName + "'.");
901 Directory.Move (src_full_path, dest_full_path);
902 } catch (IOException) {
903 throw new IsolatedStorageException ("Operation not allowed.");
908 public void MoveFile (string sourceFileName, string destinationFileName)
910 if (sourceFileName == null)
911 throw new ArgumentNullException ("sourceFileName");
912 if (destinationFileName == null)
913 throw new ArgumentNullException ("sourceFileName");
914 if (sourceFileName.Trim ().Length == 0)
915 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
916 if (destinationFileName.Trim ().Length == 0)
917 throw new ArgumentException ("An empty file name is not valid.", "destinationFileName");
921 string source_full_path = Path.Combine (directory.FullName, sourceFileName);
922 string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
924 if (!IsPathInStorage (source_full_path) || !IsPathInStorage (dest_full_path))
925 throw new IsolatedStorageException ("Operation not allowed.");
926 if (!File.Exists (source_full_path))
927 throw new FileNotFoundException ("Could not find a part of path '" + sourceFileName + "'.");
928 // I expected a DirectoryNotFound exception.
929 if (!Directory.Exists (Path.GetDirectoryName (dest_full_path)))
930 throw new IsolatedStorageException ("Operation not allowed.");
933 File.Move (source_full_path, dest_full_path);
934 } catch (IOException) {
935 throw new IsolatedStorageException ("Operation not allowed.");
940 public IsolatedStorageFileStream OpenFile (string path, FileMode mode)
942 return new IsolatedStorageFileStream (path, mode, this);
946 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access)
948 return new IsolatedStorageFileStream (path, mode, access, this);
952 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access, FileShare share)
954 return new IsolatedStorageFileStream (path, mode, access, share, this);
958 public override void Remove ()
960 #if NET_4_0 || MOBILE
964 directory.Delete (true);
966 throw new IsolatedStorageException ("Could not remove storage.");
969 // It seems .Net is calling Close from here.
974 protected override IsolatedStoragePermission GetPermission (PermissionSet ps)
978 return (IsolatedStoragePermission) ps.GetPermission (typeof (IsolatedStorageFilePermission));
982 #if NET_4_0 || MOBILE
988 void CheckOpen (bool checkDirExists)
991 throw new ObjectDisposedException ("IsolatedStorageFile");
993 throw new InvalidOperationException ("Storage needs to be open for this operation.");
994 if (checkDirExists && !Directory.Exists (directory.FullName))
995 throw new IsolatedStorageException ("Isolated storage has been removed or disabled.");
998 bool IsPathInStorage (string path)
1000 return Path.GetFullPath (path).StartsWith (directory.FullName);
1005 private string GetNameFromIdentity (object identity)
1007 // Note: Default evidences return an XML string with ToString
1008 byte[] id = Encoding.UTF8.GetBytes (identity.ToString ());
1009 SHA1 hash = SHA1.Create ();
1010 // this create an unique name for an identity - bad identities like Url
1011 // results in bad (i.e. changing) names.
1012 byte[] full = hash.ComputeHash (id, 0, id.Length);
1013 byte[] half = new byte [10];
1014 Buffer.BlockCopy (full, 0, half, 0, half.Length);
1015 return CryptoConvert.ToHex (half);
1018 private static object GetTypeFromEvidence (Evidence e, Type t)
1020 foreach (object o in e) {
1021 if (o.GetType () == t)
1027 internal static object GetAssemblyIdentityFromEvidence (Evidence e)
1030 // a. a Publisher evidence
1031 object identity = GetTypeFromEvidence (e, typeof (Publisher));
1032 if (identity != null)
1034 // b. a StrongName evidence
1035 identity = GetTypeFromEvidence (e, typeof (StrongName));
1036 if (identity != null)
1038 // c. a Url evidence
1039 return GetTypeFromEvidence (e, typeof (Url));
1042 internal static object GetDomainIdentityFromEvidence (Evidence e)
1045 // a. a ApplicationDirectory evidence
1046 object identity = GetTypeFromEvidence (e, typeof (ApplicationDirectory));
1047 if (identity != null)
1049 // b. a Url evidence
1050 return GetTypeFromEvidence (e, typeof (Url));
1054 private struct Identities {
1055 public object Application;
1056 public object Assembly;
1057 public object Domain;
1059 public Identities (object application, object assembly, object domain)
1061 Application = application;
1062 Assembly = assembly;
1067 [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
1068 private void LoadIdentities (string root)
1070 if (!File.Exists (root + ".storage"))
1071 throw new IsolatedStorageException (Locale.GetText ("Missing identities."));
1073 BinaryFormatter deformatter = new BinaryFormatter ();
1074 using (FileStream fs = File.OpenRead (root + ".storage")) {
1075 Identities identities = (Identities) deformatter.Deserialize (fs);
1077 _applicationIdentity = identities.Application;
1078 _assemblyIdentity = identities.Assembly;
1079 _domainIdentity = identities.Domain;
1083 [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
1084 private void SaveIdentities (string root)
1086 Identities identities = new Identities (_applicationIdentity, _assemblyIdentity, _domainIdentity);
1087 BinaryFormatter formatter = new BinaryFormatter ();
1090 using (FileStream fs = File.Create (root + ".storage")) {
1091 formatter.Serialize (fs, identities);
1095 mutex.ReleaseMutex ();