Update mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng/RelaxngPattern.cs
[mono.git] / mcs / class / corlib / System.IO.IsolatedStorage / IsolatedStorageFile.cs
1 //
2 // System.IO.IsolatedStorage.IsolatedStorageFile
3 //
4 // Authors
5 //      Jonathan Pryor (jonpryor@vt.edu)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
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
42 using Mono.Security.Cryptography;
43
44 namespace System.IO.IsolatedStorage {
45
46         // This is a terribly named class.  It doesn't actually represent a file as
47         // much as a directory
48
49
50         [ComVisible (true)]
51         // FIXME: Further limit the assertion when imperative Assert is implemented
52         [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
53         public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable {
54 #if !MOBILE
55                 private bool _resolved;
56                 private ulong _maxSize;
57 #endif
58                 private Evidence _fullEvidences;
59                 private static Mutex mutex = new Mutex ();
60 #if NET_4_0 || MOBILE
61                 private bool closed;
62                 private bool disposed;
63 #endif
64
65                 public static IEnumerator GetEnumerator (IsolatedStorageScope scope)
66                 {
67                         Demand (scope);
68
69                         switch (scope) {
70                         case IsolatedStorageScope.User:
71                         case IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
72                         case IsolatedStorageScope.Machine:
73                                 break;
74                         default:
75                                 string msg = Locale.GetText ("Invalid scope, only User, User|Roaming and Machine are valid");
76                                 throw new ArgumentException (msg);
77                         }
78
79                         return new IsolatedStorageFileEnumerator (scope, GetIsolatedStorageRoot (scope));
80                 }
81
82                 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope,
83                         Evidence domainEvidence, Type domainEvidenceType,
84                         Evidence assemblyEvidence, Type assemblyEvidenceType)
85                 {
86                         Demand (scope);
87
88                         bool domain = ((scope & IsolatedStorageScope.Domain) != 0);
89                         if (domain && (domainEvidence == null))
90                                 throw new ArgumentNullException ("domainEvidence");
91
92                         bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
93                         if (assembly && (assemblyEvidence == null))
94                                 throw new ArgumentNullException ("assemblyEvidence");
95
96                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
97 #if !MOBILE
98                         if (domain) {
99                                 if (domainEvidenceType == null) {
100                                         storageFile._domainIdentity = GetDomainIdentityFromEvidence (domainEvidence);
101                                 } else {
102                                         storageFile._domainIdentity = GetTypeFromEvidence (domainEvidence, domainEvidenceType);
103                                 }
104
105                                 if (storageFile._domainIdentity == null)
106                                         throw new IsolatedStorageException (Locale.GetText ("Couldn't find domain identity."));
107                         }
108
109                         if (assembly) {
110                                 if (assemblyEvidenceType == null) {
111                                         storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (assemblyEvidence);
112                                 } else {
113                                         storageFile._assemblyIdentity = GetTypeFromEvidence (assemblyEvidence, assemblyEvidenceType);
114                                 }
115
116                                 if (storageFile._assemblyIdentity == null)
117                                         throw new IsolatedStorageException (Locale.GetText ("Couldn't find assembly identity."));
118                         }
119 #endif
120                         storageFile.PostInit ();
121                         return storageFile;
122                 }
123
124                 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object domainIdentity, object assemblyIdentity)
125                 {
126                         Demand (scope);
127
128                         if (((scope & IsolatedStorageScope.Domain) != 0) && (domainIdentity == null))
129                                 throw new ArgumentNullException ("domainIdentity");
130
131                         bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
132                         if (assembly && (assemblyIdentity == null))
133                                 throw new ArgumentNullException ("assemblyIdentity");
134
135                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
136 #if !MOBILE
137                         if (assembly)
138                                 storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
139 #endif
140                         storageFile._domainIdentity = domainIdentity;
141                         storageFile._assemblyIdentity = assemblyIdentity;
142                         storageFile.PostInit ();
143                         return storageFile;
144                 }
145
146                 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
147                 {
148                         Demand (scope);
149                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
150 #if !MOBILE
151                         if ((scope & IsolatedStorageScope.Domain) != 0) {
152                                 if (domainEvidenceType == null)
153                                         domainEvidenceType = typeof (Url);
154                                 storageFile._domainIdentity = GetTypeFromEvidence (AppDomain.CurrentDomain.Evidence, domainEvidenceType);
155                         }
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);
163                                 } else {
164                                         storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
165                                 }
166                         }
167 #endif
168                         storageFile.PostInit ();
169                         return storageFile;
170                 }
171                 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object applicationIdentity)
172                 {
173                         Demand (scope);
174                         if (applicationIdentity == null)
175                                 throw new ArgumentNullException ("applicationIdentity");
176
177                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
178                         storageFile._applicationIdentity = applicationIdentity;
179 #if !MOBILE
180                         storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
181 #endif
182                         storageFile.PostInit ();
183                         return storageFile;
184                 }
185
186                 public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type applicationEvidenceType)
187                 {
188                         Demand (scope);
189                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
190                         storageFile.InitStore (scope, applicationEvidenceType);
191 #if !MOBILE
192                         storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
193 #endif
194                         storageFile.PostInit ();
195                         return storageFile;
196                 }
197
198                 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByMachine)]
199                 public static IsolatedStorageFile GetMachineStoreForApplication ()
200                 {
201                         IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Application;
202                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
203                         storageFile.InitStore (scope, null);
204 #if !MOBILE
205                         storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
206 #endif
207                         storageFile.PostInit ();
208                         return storageFile;
209                 }
210
211                 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByMachine)]
212                 public static IsolatedStorageFile GetMachineStoreForAssembly ()
213                 {
214                         IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Assembly;
215                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
216 #if !MOBILE
217                         Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
218                         storageFile._fullEvidences = e;
219                         storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
220 #endif
221                         storageFile.PostInit ();
222                         return storageFile;
223                 }
224
225                 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByMachine)]
226                 public static IsolatedStorageFile GetMachineStoreForDomain ()
227                 {
228                         IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
229                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
230 #if !MOBILE
231                         storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
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
240                 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByUser)]
241                 public static IsolatedStorageFile GetUserStoreForApplication ()
242                 {
243                         IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Application;
244                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
245                         storageFile.InitStore (scope, null);
246 #if !MOBILE
247                         storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
248 #endif
249                         storageFile.PostInit ();
250                         return storageFile;
251                 }
252
253                 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser)]
254                 public static IsolatedStorageFile GetUserStoreForAssembly ()
255                 {
256                         IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Assembly;
257                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
258 #if !MOBILE
259                         Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
260                         storageFile._fullEvidences = e;
261                         storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
262 #endif
263                         storageFile.PostInit ();
264                         return storageFile;
265                 }
266
267                 [IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]
268                 public static IsolatedStorageFile GetUserStoreForDomain ()
269                 {
270                         IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
271                         IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
272 #if !MOBILE
273                         storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
274                         Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
275                         storageFile._fullEvidences = e;
276                         storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
277 #endif
278                         storageFile.PostInit ();
279                         return storageFile;
280                 }
281
282 #if NET_4_0 || MOBILE
283                 [ComVisible (false)]
284                 public static IsolatedStorageFile GetUserStoreForSite ()
285                 {
286                         throw new NotSupportedException ();
287                 }
288 #endif
289
290                 public static void Remove (IsolatedStorageScope scope)
291                 {
292                         string dir = GetIsolatedStorageRoot (scope);
293                         if (!Directory.Exists (dir))
294                                 return;
295
296                         try {
297                                 Directory.Delete (dir, true);
298                         } catch (IOException) {
299                                 throw new IsolatedStorageException ("Could not remove storage.");
300                         }
301                 }
302
303                 // internal static stuff
304
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)
309                 {
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
313                         string root = null;
314
315                         if ((scope & IsolatedStorageScope.User) != 0) {
316                                 if ((scope & IsolatedStorageScope.Roaming) != 0) {
317                                         root = Environment.UnixGetFolderPath (Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.Create);
318                                 } else {
319                                         root = Environment.UnixGetFolderPath (Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create);
320                                 }
321                         } else if ((scope & IsolatedStorageScope.Machine) != 0) {
322                                 root = Environment.UnixGetFolderPath (Environment.SpecialFolder.CommonApplicationData, Environment.SpecialFolderOption.Create);
323                         }
324
325                         if (root == null) {
326                                 string msg = Locale.GetText ("Couldn't access storage location for '{0}'.");
327                                 throw new IsolatedStorageException (String.Format (msg, scope));
328                         }
329
330                         return Path.Combine (root, ".isolated-storage");
331                 }
332
333                 private static void Demand (IsolatedStorageScope scope)
334                 {
335 #if !MOBILE
336                         if (SecurityManager.SecurityEnabled) {
337                                 IsolatedStorageFilePermission isfp = new IsolatedStorageFilePermission (PermissionState.None);
338                                 isfp.UsageAllowed = ScopeToContainment (scope);
339                                 isfp.Demand ();
340                         }
341 #endif
342                 }
343
344                 private static IsolatedStorageContainment ScopeToContainment (IsolatedStorageScope scope)
345                 {
346                         switch (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;
365                         default:
366                                 // unknown ?!?! then ask for maximum (unrestricted)
367                                 return IsolatedStorageContainment.UnrestrictedIsolatedStorage;
368                         }
369                 }
370
371                 internal static ulong GetDirectorySize (DirectoryInfo di)
372                 {
373                         ulong size = 0;
374
375                         foreach (FileInfo fi in di.GetFiles ())
376                                 size += (ulong) fi.Length;
377
378                         foreach (DirectoryInfo d in di.GetDirectories ())
379                                 size += GetDirectorySize (d);
380
381                         return size;
382                 }
383
384                 // non-static stuff
385
386                 private DirectoryInfo directory;
387
388                 private IsolatedStorageFile (IsolatedStorageScope scope)
389                 {
390                         storage_scope = scope;
391                 }
392
393                 internal IsolatedStorageFile (IsolatedStorageScope scope, string location)
394                 {
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);
400                         }
401                         // load the identities
402                 }
403
404                 ~IsolatedStorageFile ()
405                 {
406                 }
407
408                 private void PostInit ()
409                 {
410                         string root = GetIsolatedStorageRoot (Scope);
411                         string dir = null;
412 #if MOBILE
413                         dir = "";
414 #else
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));
422                         } else {
423                                 throw new IsolatedStorageException (Locale.GetText ("No code identity available."));
424                         }
425 #endif
426
427                         root = Path.Combine (root, dir);
428
429                         // identities have been selected
430                         directory = new DirectoryInfo (root);
431                         if (!directory.Exists) {
432                                 try {
433                                         directory.Create ();
434 #if !MOBILE
435                                         SaveIdentities (root);
436 #endif
437                                 }
438                                 catch (IOException) {
439                                 }
440                         }
441                 }
442
443                 [CLSCompliant(false)]
444 #if NET_4_0 || MOBILE
445                 [Obsolete]
446 #endif
447                 public override ulong CurrentSize {
448                         get { return GetDirectorySize (directory); }
449                 }
450
451                 [CLSCompliant(false)]
452 #if NET_4_0 || MOBILE
453                 [Obsolete]
454 #endif
455                 public override ulong MaximumSize {
456                         // return an ulong but default is signed long
457                         get {
458 #if MOBILE
459                                 // no security manager is active so the rest of the code is useless
460                                 return Int64.MaxValue;
461 #else
462                                 if (!SecurityManager.SecurityEnabled)
463                                         return Int64.MaxValue;
464
465                                 if (_resolved)
466                                         return _maxSize;
467
468                                 Evidence e = null;
469                                 if (_fullEvidences != null) {
470                                         // if possible use the complete evidences we had
471                                         // for computing the X identity
472                                         e = _fullEvidences;
473                                 } else {
474                                         e = new Evidence ();
475                                         // otherwise use what was provided
476                                         if (_assemblyIdentity != null)
477                                                 e.AddHost (_assemblyIdentity);
478                                 }
479                                 if (e.Count < 1) {
480                                         throw new InvalidOperationException (
481                                                 Locale.GetText ("Couldn't get the quota from the available evidences."));
482                                 }
483
484                                 PermissionSet denied = null;
485                                 PermissionSet ps = SecurityManager.ResolvePolicy (e, null, null, null, out denied);
486                                 IsolatedStoragePermission isp = GetPermission (ps);
487                                 if (isp == null) {
488                                         if (ps.IsUnrestricted ()) {
489                                                 _maxSize = Int64.MaxValue; /* default value */
490                                         } else {
491                                                 throw new InvalidOperationException (
492                                                         Locale.GetText ("No quota from the available evidences."));
493                                         }
494                                 } else {
495                                         _maxSize = (ulong) isp.UserQuota;
496                                 }
497                                 _resolved = true;
498                                 return _maxSize;
499 #endif
500                         }
501                 }
502
503                 internal string Root {
504                         get { return directory.FullName; }
505                 }
506
507 #if NET_4_0 || MOBILE
508                 [ComVisible (false)]
509                 public override long AvailableFreeSpace {
510                         get {
511                                 CheckOpen ();
512
513                                 // See the notes for 'Quota'
514                                 return Int64.MaxValue;
515
516                         }
517                 }
518
519                 [ComVisible (false)]
520                 public override long Quota {
521                         get {
522                                 CheckOpen ();
523
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;
528                         }
529                 }
530
531                 [ComVisible (false)]
532                 public override long UsedSize {
533                         get {
534                                 CheckOpen ();
535                                 return (long)GetDirectorySize (directory);
536                         }
537                 }
538
539                 [ComVisible (false)]
540                 public static bool IsEnabled {
541                         get {
542                                 return true;
543                         }
544                 }
545
546                 internal bool IsClosed {
547                         get {
548                                 return closed;
549                         }
550                 }
551
552                 internal bool IsDisposed {
553                         get {
554                                 return disposed;
555                         }
556                 }
557 #endif
558
559                 // methods
560
561                 public void Close ()
562                 {
563 #if NET_4_0 || MOBILE
564                         closed = true;
565 #endif
566                 }
567
568                 public void CreateDirectory (string dir)
569                 {
570                         if (dir == null)
571                                 throw new ArgumentNullException ("dir");
572
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.");
577 #else
578                                         throw new IOException (Locale.GetText ("Directory name already exists as a file."));
579 #endif
580                                 directory.CreateSubdirectory (dir);
581                         } else {
582                                 string[] dirs = dir.Split (Path.PathSeparatorChars, StringSplitOptions.RemoveEmptyEntries);
583                                 DirectoryInfo dinfo = directory;
584
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.");
589 #else
590                                                 throw new IOException (Locale.GetText (
591                                                         "Part of the directory name already exists as a file."));
592 #endif
593                                         dinfo = dinfo.CreateSubdirectory (dirs [i]);
594                                 }
595                         }
596                 }
597
598 #if NET_4_0 || MOBILE
599                 [ComVisible (false)]
600                 public void CopyFile (string sourceFileName, string destinationFileName)
601                 {
602                         CopyFile (sourceFileName, destinationFileName, false);
603                 }
604
605                 [ComVisible (false)]
606                 public void CopyFile (string sourceFileName, string destinationFileName, bool overwrite)
607                 {
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");
616
617                         CheckOpen ();
618
619                         string source_full_path = Path.Combine (directory.FullName, sourceFileName);
620                         string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
621
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.");
631
632                         try {
633                                 File.Copy (source_full_path, dest_full_path, overwrite);
634                         } catch (IOException) {
635                                 throw new IsolatedStorageException ("Operation not allowed.");
636                         }
637                 }
638
639                 [ComVisible (false)]
640                 public IsolatedStorageFileStream CreateFile (string path)
641                 {
642                         return new IsolatedStorageFileStream (path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this);
643                 }
644 #endif
645
646                 public void DeleteDirectory (string dir)
647                 {
648                         try {
649                                 if (Path.IsPathRooted (dir))
650                                         dir = dir.Substring (1);
651                                 DirectoryInfo subdir = directory.CreateSubdirectory (dir);
652                                 subdir.Delete ();
653                         }
654                         catch {
655                                 // hide the real exception to avoid leaking the full path
656                                 throw new IsolatedStorageException (Locale.GetText ("Could not delete directory '{0}'", dir));
657                         }
658                 }
659
660                 public void DeleteFile (string file)
661                 {
662                         if (file == null)
663                                 throw new ArgumentNullException ("file");
664
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));
668
669                         try {
670                                 File.Delete (Path.Combine (directory.FullName, file));
671                         } catch {
672                                 // hide the internal exception, just as DeleteDirectory does.
673                                 throw new IsolatedStorageException (Locale.GetText ("Could not delete file '{0}'", file));
674                         }
675                 }
676
677                 public void Dispose ()
678                 {
679 #if NET_4_0 || MOBILE
680                         // Dispose may be calling Close, but we are not sure
681                         disposed = true;
682 #endif
683                         // nothing to dispose, anyway we want to please the tools
684                         GC.SuppressFinalize (this);
685                 }
686
687 #if NET_4_0 || MOBILE
688                 [ComVisible (false)]
689                 public bool DirectoryExists (string path)
690                 {
691                         if (path == null)
692                                 throw new ArgumentNullException ("path");
693
694                         CheckOpen ();
695
696                         string full_path = Path.Combine (directory.FullName, path);
697                         if (!IsPathInStorage (full_path))
698                                 return false;
699
700                         return Directory.Exists (full_path);
701                 }
702
703                 [ComVisible (false)]
704                 public bool FileExists (string path)
705                 {
706                         if (path == null)
707                                 throw new ArgumentNullException ("path");
708
709                         CheckOpen ();
710
711                         string full_path = Path.Combine (directory.FullName, path);
712                         if (!IsPathInStorage (full_path))
713                                 return false;
714
715                         return File.Exists (full_path);
716                 }
717
718                 [ComVisible (false)]
719                 public DateTimeOffset GetCreationTime (string path)
720                 {
721                         if (path == null)
722                                 throw new ArgumentNullException ("path");
723                         if (path.Trim ().Length == 0)
724                                 throw new ArgumentException ("An empty path is not valid.");
725
726                         CheckOpen ();
727
728                         string full_path = Path.Combine (directory.FullName, path);
729                         if (File.Exists (full_path))
730                                 return File.GetCreationTime (full_path);
731
732                         return Directory.GetCreationTime (full_path);
733                 }
734
735                 [ComVisible (false)]
736                 public DateTimeOffset GetLastAccessTime (string path)
737                 {
738                         if (path == null)
739                                 throw new ArgumentNullException ("path");
740                         if (path.Trim ().Length == 0)
741                                 throw new ArgumentException ("An empty path is not valid.");
742
743                         CheckOpen ();
744
745                         string full_path = Path.Combine (directory.FullName, path);
746                         if (File.Exists (full_path))
747                                 return File.GetLastAccessTime (full_path);
748
749                         return Directory.GetLastAccessTime (full_path);
750                 }
751
752                 [ComVisible (false)]
753                 public DateTimeOffset GetLastWriteTime (string path)
754                 {
755                         if (path == null)
756                                 throw new ArgumentNullException ("path");
757                         if (path.Trim ().Length == 0)
758                                 throw new ArgumentException ("An empty path is not valid.");
759
760                         CheckOpen ();
761
762                         string full_path = Path.Combine (directory.FullName, path);
763                         if (File.Exists (full_path))
764                                 return File.GetLastWriteTime (full_path);
765
766                         return Directory.GetLastWriteTime (full_path);
767                 }
768 #endif
769                 
770                 public string[] GetDirectoryNames (string searchPattern)
771                 {
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");
777 #endif
778
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);
786                         } else {
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]) {
796                                                         adi = null;
797                                                         break;
798                                                 }
799                                                 di = di.Parent;
800                                         }
801                                 }
802                         }
803                         // CAS, even in FullTrust, normally enforce IsolatedStorage
804                         if (adi == null)
805                                 throw new SecurityException ();
806                          
807                         return GetNames (adi);
808                 }
809
810 #if NET_4_0 || MOBILE
811                 [ComVisible (false)]
812                 public string [] GetDirectoryNames ()
813                 {
814                         return GetDirectoryNames ("*");
815                 }
816 #endif
817
818                 private string[] GetNames (FileSystemInfo[] afsi)
819                 {
820                         string[] r = new string[afsi.Length];
821                         for (int i = 0; i != afsi.Length; ++i)
822                                 r[i] = afsi[i].Name;
823                         return r;
824                 }
825
826                 public string[] GetFileNames (string searchPattern)
827                 {
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");
833 #endif
834
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);
842                         } else {
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);
848                                 } else {
849                                         // CAS, even in FullTrust, normally enforce IsolatedStorage
850                                         throw new SecurityException ();
851                                 }
852                         }
853
854                         return GetNames (afi);
855                 }
856
857 #if NET_4_0 || MOBILE
858                 [ComVisible (false)]
859                 public string [] GetFileNames ()
860                 {
861                         return GetFileNames ("*");
862                 }
863
864                 [ComVisible (false)]
865                 public override bool IncreaseQuotaTo (long newQuotaSize)
866                 {
867                         if (newQuotaSize < Quota)
868                                 throw new ArgumentException ();
869
870                         CheckOpen ();
871
872                         // .Net is supposed to be returning false, as mentioned in the docs.
873                         return false;
874                 }
875
876                 [ComVisible (false)]
877                 public void MoveDirectory (string sourceDirectoryName, string destinationDirectoryName)
878                 {
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");
887
888                         CheckOpen ();
889
890                         string src_full_path = Path.Combine (directory.FullName, sourceDirectoryName);
891                         string dest_full_path = Path.Combine (directory.FullName, destinationDirectoryName);
892
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 + "'.");
899
900                         try {
901                                 Directory.Move (src_full_path, dest_full_path);
902                         } catch (IOException) {
903                                 throw new IsolatedStorageException ("Operation not allowed.");
904                         }
905                 }
906
907                 [ComVisible (false)]
908                 public void MoveFile (string sourceFileName, string destinationFileName)
909                 {
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");
918
919                         CheckOpen ();
920
921                         string source_full_path = Path.Combine (directory.FullName, sourceFileName);
922                         string dest_full_path = Path.Combine (directory.FullName, destinationFileName);
923
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.");
931
932                         try {
933                                 File.Move (source_full_path, dest_full_path);
934                         } catch (IOException) {
935                                 throw new IsolatedStorageException ("Operation not allowed.");
936                         }
937                 }
938
939                 [ComVisible (false)]
940                 public IsolatedStorageFileStream OpenFile (string path, FileMode mode)
941                 {
942                         return new IsolatedStorageFileStream (path, mode, this);
943                 }
944
945                 [ComVisible (false)]
946                 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access)
947                 {
948                         return new IsolatedStorageFileStream (path, mode, access, this);
949                 }
950
951                 [ComVisible (false)]
952                 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access, FileShare share)
953                 {
954                         return new IsolatedStorageFileStream (path, mode, access, share, this);
955                 }
956 #endif
957
958                 public override void Remove ()
959                 {
960 #if NET_4_0 || MOBILE
961                         CheckOpen (false);
962 #endif
963                         try {
964                                 directory.Delete (true);
965                         } catch {
966                                 throw new IsolatedStorageException ("Could not remove storage.");
967                         }
968
969                         // It seems .Net is calling Close from here.
970                         Close ();
971                 }
972
973
974                 protected override IsolatedStoragePermission GetPermission (PermissionSet ps)
975                 {
976                         if (ps == null)
977                                 return null;
978                         return (IsolatedStoragePermission) ps.GetPermission (typeof (IsolatedStorageFilePermission));
979                 }
980
981                 // internal stuff
982 #if NET_4_0 || MOBILE
983                 void CheckOpen ()
984                 {
985                         CheckOpen (true);
986                 }
987
988                 void CheckOpen (bool checkDirExists)
989                 {
990                         if (disposed)
991                                 throw new ObjectDisposedException ("IsolatedStorageFile");
992                         if (closed)
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.");
996                 }
997
998                 bool IsPathInStorage (string path)
999                 {
1000                         return Path.GetFullPath (path).StartsWith (directory.FullName);
1001                 }
1002 #endif
1003
1004 #if !MOBILE
1005                 private string GetNameFromIdentity (object identity)
1006                 {
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);
1016                 }
1017
1018                 private static object GetTypeFromEvidence (Evidence e, Type t)
1019                 {
1020                         foreach (object o in e) {
1021                                 if (o.GetType () == t)
1022                                         return o;
1023                         }
1024                         return null;
1025                 }
1026
1027                 internal static object GetAssemblyIdentityFromEvidence (Evidence e)
1028                 {
1029                         // we prefer...
1030                         // a. a Publisher evidence
1031                         object identity = GetTypeFromEvidence (e, typeof (Publisher));
1032                         if (identity != null)
1033                                 return identity;
1034                         // b. a StrongName evidence
1035                         identity = GetTypeFromEvidence (e, typeof (StrongName));
1036                         if (identity != null)
1037                                 return identity;
1038                         // c. a Url evidence
1039                         return GetTypeFromEvidence (e, typeof (Url));
1040                 }
1041
1042                 internal static object GetDomainIdentityFromEvidence (Evidence e)
1043                 {
1044                         // we prefer...
1045                         // a. a ApplicationDirectory evidence
1046                         object identity = GetTypeFromEvidence (e, typeof (ApplicationDirectory));
1047                         if (identity != null)
1048                                 return identity;
1049                         // b. a Url evidence
1050                         return GetTypeFromEvidence (e, typeof (Url));
1051                 }
1052
1053                 [Serializable]
1054                 private struct Identities {
1055                         public object Application;
1056                         public object Assembly;
1057                         public object Domain;
1058
1059                         public Identities (object application, object assembly, object domain)
1060                         {
1061                                 Application = application;
1062                                 Assembly = assembly;
1063                                 Domain = domain;
1064                         }
1065                 }
1066 /*
1067                 [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
1068                 private void LoadIdentities (string root)
1069                 {
1070                         if (!File.Exists (root + ".storage"))
1071                                 throw new IsolatedStorageException (Locale.GetText ("Missing identities."));
1072
1073                         BinaryFormatter deformatter = new BinaryFormatter ();
1074                         using (FileStream fs = File.OpenRead (root + ".storage")) {
1075                                 Identities identities = (Identities) deformatter.Deserialize (fs);
1076
1077                                 _applicationIdentity = identities.Application;
1078                                 _assemblyIdentity = identities.Assembly;
1079                                 _domainIdentity = identities.Domain;
1080                         }
1081                 }
1082 */
1083                 [SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
1084                 private void SaveIdentities (string root)
1085                 {
1086                         Identities identities = new Identities (_applicationIdentity, _assemblyIdentity, _domainIdentity);
1087                         BinaryFormatter formatter = new BinaryFormatter ();
1088                         mutex.WaitOne ();
1089                         try {
1090                                 using (FileStream fs = File.Create (root + ".storage")) {
1091                                         formatter.Serialize (fs, identities);
1092                                 }
1093                         }
1094                         finally {
1095                                 mutex.ReleaseMutex ();
1096                         }
1097                 }
1098 #endif
1099         }
1100 }
1101 #endif