use MOONLIGHT symbol
[mono-project.git] / mcs / class / corlib / System.IO.IsolatedStorage / MoonIsolatedStorageFile.cs
blob0c0fe270416bd8036b89ad985dff5e382d012f1f
1 //
2 // System.IO.IsolatedStorage.MoonIsolatedStorageFile
3 //
4 // Moonlight's implementation for the IsolatedStorageFile
5 //
6 // Authors
7 // Miguel de Icaza (miguel@novell.com)
8 // Sebastien Pouliot <sebastien@ximian.com>
9 //
10 // Copyright (C) 2007, 2008, 2009 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #if MOONLIGHT
32 using System;
33 using System.IO;
34 using System.Runtime.InteropServices;
35 using System.Security;
37 namespace System.IO.IsolatedStorage {
39 // Most of the time there will only be a single instance of both
40 // * Application Store (GetUserStoreForApplication)
41 // * Site Store (GetUserStoreForSite)
42 // However both can have multiple concurrent uses, e.g.
43 // * another instance of the same application (same URL) running in another Moonlight instance
44 // * another application on the same site (i.e. host) for a site store
45 // and share the some quota, i.e. a site and all applications on the sites share the same space
47 // notes:
48 // * quota seems computed in (disk) blocks, i.e. a small file will have a (non-small) size
49 // e.g. every files and directories entries takes 1KB
51 public sealed class IsolatedStorageFile : IDisposable {
53 static object locker = new object ();
55 private string basedir;
56 private long used;
57 private bool removed = false;
58 private bool disposed = false;
60 internal IsolatedStorageFile (string root)
62 basedir = root;
65 internal void PreCheck ()
67 if (disposed)
68 throw new ObjectDisposedException ("Storage was disposed");
69 if (removed)
70 throw new IsolatedStorageException ("Storage was removed");
73 public static IsolatedStorageFile GetUserStoreForApplication ()
75 return new IsolatedStorageFile (IsolatedStorage.ApplicationPath);
78 public static IsolatedStorageFile GetUserStoreForSite ()
80 return new IsolatedStorageFile (IsolatedStorage.SitePath);
83 internal string Verify (string path)
85 // special case: 'path' would be returned (instead of combined)
86 if ((path.Length > 0) && (path [0] == '/'))
87 path = path.Substring (1, path.Length - 1);
89 // outside of try/catch since we want to get things like
90 // ArgumentException for invalid characters
91 string combined = Path.Combine (basedir, path);
92 try {
93 string full = Path.GetFullPath (combined);
94 if (full.StartsWith (basedir))
95 return full;
96 } catch {
97 // we do not supply an inner exception since it could contains details about the path
98 throw new IsolatedStorageException ();
100 throw new IsolatedStorageException ();
103 public void CreateDirectory (string dir)
105 PreCheck ();
106 if (dir == null)
107 throw new ArgumentNullException ("dir");
108 // empty dir is ignored
109 if (dir.Length > 0)
110 Directory.CreateDirectory (Verify (dir));
113 public IsolatedStorageFileStream CreateFile (string path)
115 PreCheck ();
116 try {
117 return new IsolatedStorageFileStream (path, FileMode.Create, this);
119 catch (DirectoryNotFoundException) {
120 // this can happen if the supplied path includes an unexisting directory
121 throw new IsolatedStorageException ();
125 public void DeleteDirectory (string dir)
127 PreCheck ();
128 if (dir == null)
129 throw new ArgumentNullException ("dir");
130 Directory.Delete (Verify (dir));
133 public void DeleteFile (string file)
135 PreCheck ();
136 if (file == null)
137 throw new ArgumentNullException ("file");
138 string checked_filename = Verify (file);
139 if (!File.Exists (checked_filename))
140 throw new IsolatedStorageException ("File does not exists");
141 File.Delete (checked_filename);
144 public void Dispose ()
146 disposed = true;
149 public bool DirectoryExists (string path)
151 PreCheck ();
152 return Directory.Exists (Verify (path));
155 public bool FileExists (string path)
157 PreCheck ();
158 return File.Exists (Verify (path));
161 private string HideAppDir (string path)
163 // remove the "isolated" part of the path (and the extra '/')
164 return path.Substring (basedir.Length + 1);
167 private string [] HideAppDirs (string[] paths)
169 for (int i=0; i < paths.Length; i++)
170 paths [i] = HideAppDir (paths [i]);
171 return paths;
174 private void CheckSearchPattern (string searchPattern)
176 if (searchPattern == null)
177 throw new ArgumentNullException ("searchPattern");
178 if (searchPattern.Length == 0)
179 throw new IsolatedStorageException ("searchPattern");
180 if (searchPattern.IndexOfAny (Path.GetInvalidPathChars ()) != -1)
181 throw new ArgumentException ("searchPattern");
184 public string [] GetDirectoryNames ()
186 return HideAppDirs (Directory.GetDirectories (basedir));
189 public string [] GetDirectoryNames (string searchPattern)
191 CheckSearchPattern (searchPattern);
193 // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
194 // so we need to split them to get the right results
195 string path = Path.GetDirectoryName (searchPattern);
196 string pattern = Path.GetFileName (searchPattern);
197 string [] afi = null;
199 if (path == null || path.Length == 0) {
200 return HideAppDirs (Directory.GetDirectories (basedir, searchPattern));
201 } else {
202 // we're looking for a single result, identical to path (no pattern here)
203 // we're also looking for something under the current path (not outside isolated storage)
205 string [] subdirs = Directory.GetDirectories (basedir, path);
206 if (subdirs.Length != 1 || subdirs [0].IndexOf (basedir) < 0)
207 throw new IsolatedStorageException ();
209 DirectoryInfo dir = new DirectoryInfo (subdirs [0]);
210 if (dir.Name != path)
211 throw new IsolatedStorageException ();
213 return GetNames (dir.GetDirectories (pattern));
217 public string [] GetFileNames ()
219 return HideAppDirs (Directory.GetFiles (basedir));
222 public string [] GetFileNames (string searchPattern)
224 CheckSearchPattern (searchPattern);
226 // note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
227 // so we need to split them to get the right results
228 string path = Path.GetDirectoryName (searchPattern);
229 string pattern = Path.GetFileName (searchPattern);
230 string [] afi = null;
232 if (path == null || path.Length == 0) {
233 return HideAppDirs (Directory.GetFiles (basedir, searchPattern));
234 } else {
235 // we're looking for a single result, identical to path (no pattern here)
236 // we're also looking for something under the current path (not outside isolated storage)
238 string [] subdirs = Directory.GetDirectories (basedir, path);
239 if (subdirs.Length != 1 || subdirs [0].IndexOf (basedir) < 0)
240 throw new IsolatedStorageException ();
242 DirectoryInfo dir = new DirectoryInfo (subdirs [0]);
243 if (dir.Name != path)
244 throw new IsolatedStorageException ();
246 return GetNames (dir.GetFiles (pattern));
250 // Return the file name portion of a full path
251 private string[] GetNames (FileSystemInfo[] afsi)
253 string[] r = new string[afsi.Length];
254 for (int i = 0; i != afsi.Length; ++i)
255 r[i] = afsi[i].Name;
256 return r;
259 public IsolatedStorageFileStream OpenFile (string path, FileMode mode)
261 return OpenFile (path, mode, FileAccess.ReadWrite, FileShare.None);
264 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access)
266 return OpenFile (path, mode, access, FileShare.None);
269 public IsolatedStorageFileStream OpenFile (string path, FileMode mode, FileAccess access, FileShare share)
271 PreCheck ();
272 return new IsolatedStorageFileStream (path, mode, access, share, this);
275 public void Remove ()
277 PreCheck ();
278 IsolatedStorage.Remove (basedir);
279 removed = true;
282 // note: available free space could be changed from another application (same URL, another ML instance) or
283 // another application on the same site
284 public long AvailableFreeSpace {
285 get {
286 PreCheck ();
287 return IsolatedStorage.AvailableFreeSpace;
291 // note: quota could be changed from another application (same URL, another ML instance) or
292 // another application on the same site
293 public long Quota {
294 get {
295 PreCheck ();
296 return IsolatedStorage.Quota;
300 [DllImport ("moon")]
301 [return: MarshalAs (UnmanagedType.Bool)]
302 extern static bool isolated_storage_increase_quota_to (string primary_text, string secondary_text);
304 const long mb = 1024 * 1024;
306 public bool IncreaseQuotaTo (long newQuotaSize)
308 PreCheck ();
310 if (newQuotaSize <= Quota)
311 throw new ArgumentException ("newQuotaSize", "Only increases are possible");
313 string message = String.Format ("This web site, <u>{0}</u>, is requesting an increase of its local storage capacity on your computer. It is currently using <b>{1:F1} MB</b> out of a maximum of <b>{2:F1} MB</b>.",
314 IsolatedStorage.Site, IsolatedStorage.Current / mb, IsolatedStorage.Quota / mb);
315 string question = String.Format ("Do you want to increase the web site quota to a new maximum of <b>{0:F1} MB</b> ?",
316 newQuotaSize / mb);
317 bool result = isolated_storage_increase_quota_to (message, question);
318 if (result)
319 IsolatedStorage.Quota = newQuotaSize;
320 return result;
324 #endif