2010-05-27 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.IO.IsolatedStorage / MoonIsolatedStorage.cs
blob9ea31ee08bb3a9feedc2804596c3b63104be2f86
1 //
2 // System.IO.IsolatedStorage.IsolatedQuotaGroup
3 //
4 // Authors
5 // Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #if MOONLIGHT
31 using System;
32 using System.IO;
33 using System.Runtime.InteropServices;
34 using System.Security;
35 using System.Security.Cryptography;
36 using System.Text;
38 namespace System.IO.IsolatedStorage {
40 static class IsolatedStorage {
42 // NOTE: both the 'site' and 'application' share the same quota
43 internal const long DefaultQuota = 1024 * 1024;
44 // Since we can extend more than AvailableFreeSize we need to substract the "safety" value out of it
45 private const int SafetyZone = 1024;
48 static string site_root;
49 static string site_config;
50 static long site_quota;
52 // this is similar to Silverlight hierarchy because differing too much would cause
53 // problems with the 260 character maximum allowed for paths
55 // Considering a 10 characters user name the following platform will allow:
56 // 109 characters path, under Windows Vista (Silverlight 2)
57 // 77 characters path, under Windows XP (Silverlight 2)
58 // 100 characters path, under Mac OSX (Silverlight 2)
59 // 159 characters path, under Linux (Moonlight 2)
61 // 1234567890123456789012345678901234567890123 = 43 + 28 + 1 + 28 +1 = 101
62 // 1 2 3 4
63 // /home/1234567890/.local/share/moonlight/is/{site-hash:28}/{app-hash:28}/
65 static IsolatedStorage ()
67 string isolated_root = GetIsolatedStorageRoot ();
68 // enable/disable osilated storage - requires restart
69 Enabled = !File.Exists (Path.Combine (isolated_root, "disabled"));
71 // from System.Windows.Application we made "xap_uri" correspond to
72 // Application.Current.Host.Source.AbsoluteUri
73 string app = (AppDomain.CurrentDomain.GetData ("xap_uri") as string);
74 if (app.StartsWith ("file://")) {
75 // every path is a different site, the XAP is the application
76 Site = Path.GetDirectoryName (app.Substring (7));
77 } else {
78 // for http[s] the "Site Identity" is built using:
79 // * the protocol (so http and https are different);
80 // * the host (so beta.moonlight.com is different from www.moonlight.com); and
81 // * the port (so 8080 is different from 80) but
82 // ** 80 and none are identical for HTTP
83 // ** 443 and none are identical for HTTPS
84 Site = app.Substring (0, app.IndexOf ('/', 8));
87 // the "Site Identity"
88 string site_hash = Hash (Site);
89 site_root = TryDirectory (Path.Combine (isolated_root, site_hash));
90 SetupSite (site_root);
91 SitePath = TryDirectory (Path.Combine (site_root, site_hash));
93 // the "Application Identity"
94 string app_hash = Hash (app);
95 SetupApplication (app, app_hash, site_root);
96 ApplicationPath = TryDirectory (Path.Combine (site_root, app_hash));
99 static string GetIsolatedStorageRoot ()
101 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
102 string xdg_data_home = Environment.GetEnvironmentVariable ("XDG_DATA_HOME");
103 if (String.IsNullOrEmpty (xdg_data_home)) {
104 xdg_data_home = Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData);
107 string moonlight = TryDirectory (Path.Combine (xdg_data_home, "moonlight"));
108 return TryDirectory (Path.Combine (moonlight, "is"));
111 static void SetupSite (string dir)
113 site_quota = DefaultQuota;
114 // read configuration file (e.g. quota) if it exists, otherwise write it
115 site_config = Path.Combine (dir, "config");
116 if (File.Exists (site_config)) {
117 LoadConfiguration ();
118 } else {
119 SaveConfiguration ();
123 static void LoadConfiguration ()
125 // read quota, the rest is not useful to us
126 using (StreamReader sr = new StreamReader (site_config)) {
127 string line = sr.ReadLine ();
128 while (line != null) {
129 if (line.StartsWith ("QUOTA = ")) {
130 if (!Int64.TryParse (line.Substring (8, line.Length - 8), out site_quota))
131 Quota = DefaultQuota;
133 line = sr.ReadLine ();
138 static void SaveConfiguration ()
140 using (StreamWriter sw = new StreamWriter (site_config)) {
141 sw.WriteLine ("URI = {0}", Site);
142 sw.WriteLine ("QUOTA = {0}", Quota);
146 static void SetupApplication (string app, string app_hash, string dir)
148 // save the application information (for the management UI)
149 string config = Path.Combine (dir, app_hash + ".info");
150 if (File.Exists (config))
151 return;
153 using (StreamWriter sw = new StreamWriter (config)) {
154 sw.WriteLine ("URI = {0}", app);
158 // goal: uniform length directory name
159 // non-goal: security by obsfucation
160 static string Hash (string name)
162 string id;
163 using (SHA1Managed hash = new SHA1Managed ()) {
164 byte[] digest = hash.ComputeHash (Encoding.UTF8.GetBytes (name));
165 id = Convert.ToBase64String (digest);
167 return (id.IndexOf ('/') == -1) ? id : id.Replace ('/', '-');
170 static string TryDirectory (string path)
172 try {
173 Directory.CreateDirectory (path);
174 return path;
175 } catch {
176 return null;
180 static internal void Remove (string dir)
182 try {
183 Directory.Delete (dir, true);
185 finally {
186 TryDirectory (dir);
190 static internal bool CanExtend (long request)
192 return (request <= AvailableFreeSpace + SafetyZone);
195 static public string ApplicationPath {
196 get; private set;
199 static public string SitePath {
200 get; private set;
203 static public long AvailableFreeSpace {
204 get { return Quota - Current - SafetyZone; }
207 [DllImport ("moon")]
208 extern static long isolated_storage_get_current_usage (string root);
210 static public long Current {
211 get { return isolated_storage_get_current_usage (site_root); }
214 static public long Quota {
215 get { return site_quota; }
216 set {
217 site_quota = value;
218 SaveConfiguration ();
222 static public string Site {
223 get; private set;
226 // it is possible, from the UI, to completely disable IsolatedStorage
227 static public bool Enabled { get; private set; }
231 #endif