//
// System.IO.IsolatedStorage.IsolatedStorageFile
//
// Authors
// 	Jonathan Pryor (jonpryor@vt.edu)
//	Sebastien Pouliot  <sebastien@ximian.com>
//
// (C) 2003 Jonathan Pryor
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#if !NET_2_1
using System.Collections;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;

using Mono.Security.Cryptography;

namespace System.IO.IsolatedStorage {

	// This is a terribly named class.  It doesn't actually represent a file as
	// much as a directory


#if NET_2_0
	[ComVisible (true)]
#endif
	// FIXME: Further limit the assertion when imperative Assert is implemented
	[FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
	public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable {

		private bool _resolved;
		private ulong _maxSize;
		private Evidence _fullEvidences;

		public static IEnumerator GetEnumerator (IsolatedStorageScope scope)
		{
			Demand (scope);

			switch (scope) {
			case IsolatedStorageScope.User:
			case IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
#if NET_2_0
			case IsolatedStorageScope.Machine:
#endif
				break;
			default:
				string msg = Locale.GetText ("Invalid scope, only User, User|Roaming and Machine are valid");
				throw new ArgumentException (msg);
			}

			return new IsolatedStorageFileEnumerator (scope, GetIsolatedStorageRoot (scope));
		}

		public static IsolatedStorageFile GetStore (IsolatedStorageScope scope,
			Evidence domainEvidence, Type domainEvidenceType,
			Evidence assemblyEvidence, Type assemblyEvidenceType)
		{
			Demand (scope);

			bool domain = ((scope & IsolatedStorageScope.Domain) != 0);
			if (domain && (domainEvidence == null))
				throw new ArgumentNullException ("domainEvidence");

			bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
			if (assembly && (assemblyEvidence == null))
				throw new ArgumentNullException ("assemblyEvidence");

			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			if (domain) {
				if (domainEvidenceType == null) {
					storageFile._domainIdentity = GetDomainIdentityFromEvidence (domainEvidence);
				} else {
					storageFile._domainIdentity = GetTypeFromEvidence (domainEvidence, domainEvidenceType);
				}

				if (storageFile._domainIdentity == null)
					throw new IsolatedStorageException (Locale.GetText ("Couldn't find domain identity."));
			}

			if (assembly) {
				if (assemblyEvidenceType == null) {
					storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (assemblyEvidence);
				} else {
					storageFile._assemblyIdentity = GetTypeFromEvidence (assemblyEvidence, assemblyEvidenceType);
				}

				if (storageFile._assemblyIdentity == null)
					throw new IsolatedStorageException (Locale.GetText ("Couldn't find assembly identity."));
			}

			storageFile.PostInit ();
			return storageFile;
		}

		public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object domainIdentity, object assemblyIdentity)
		{
			Demand (scope);

			if (((scope & IsolatedStorageScope.Domain) != 0) && (domainIdentity == null))
				throw new ArgumentNullException ("domainIdentity");

			bool assembly = ((scope & IsolatedStorageScope.Assembly) != 0);
			if (assembly && (assemblyIdentity == null))
				throw new ArgumentNullException ("assemblyIdentity");

			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			if (assembly)
				storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile._domainIdentity = domainIdentity;
			storageFile._assemblyIdentity = assemblyIdentity;
			storageFile.PostInit ();
			return storageFile;
		}

		public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type domainEvidenceType, Type assemblyEvidenceType)
		{
			Demand (scope);
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			if ((scope & IsolatedStorageScope.Domain) != 0) {
				storageFile._domainIdentity = GetTypeFromEvidence (AppDomain.CurrentDomain.Evidence, domainEvidenceType);
			}
			if ((scope & IsolatedStorageScope.Assembly) != 0) {
				Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
				storageFile._fullEvidences = e;
				if ((scope & IsolatedStorageScope.Domain) != 0)
					storageFile._assemblyIdentity = GetTypeFromEvidence (e, assemblyEvidenceType);
				else
					storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
			}
			storageFile.PostInit ();
			return storageFile;
		}
#if NET_2_0
		public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, object applicationIdentity)
		{
			Demand (scope);
			if (applicationIdentity == null)
				throw new ArgumentNullException ("applicationIdentity");

			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			storageFile._applicationIdentity = applicationIdentity;
			storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile.PostInit ();
			return storageFile;
		}

		public static IsolatedStorageFile GetStore (IsolatedStorageScope scope, Type applicationEvidenceType)
		{
			Demand (scope);
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			storageFile.InitStore (scope, applicationEvidenceType);
			storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile.PostInit ();
			return storageFile;
		}

		[IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByMachine)]
		public static IsolatedStorageFile GetMachineStoreForApplication ()
		{
			IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Application;
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			storageFile.InitStore (scope, null);
			storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile.PostInit ();
			return storageFile;
		}

		[IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByMachine)]
		public static IsolatedStorageFile GetMachineStoreForAssembly ()
		{
			IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Assembly;
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile._fullEvidences = e;
			storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
			storageFile.PostInit ();
			return storageFile;
		}

		[IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByMachine)]
		public static IsolatedStorageFile GetMachineStoreForDomain ()
		{
			IsolatedStorageScope scope = IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
			Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile._fullEvidences = e;
			storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
			storageFile.PostInit ();
			return storageFile;
		}

		[IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.ApplicationIsolationByUser)]
		public static IsolatedStorageFile GetUserStoreForApplication ()
		{
			IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Application;
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			storageFile.InitStore (scope, null);
			storageFile._fullEvidences = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile.PostInit ();
			return storageFile;
		}
#endif
		[IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByUser)]
		public static IsolatedStorageFile GetUserStoreForAssembly ()
		{
			IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Assembly;
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile._fullEvidences = e;
			storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
			storageFile.PostInit ();
			return storageFile;
		}

		[IsolatedStorageFilePermission (SecurityAction.Demand, UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]
		public static IsolatedStorageFile GetUserStoreForDomain ()
		{
			IsolatedStorageScope scope = IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
			IsolatedStorageFile storageFile = new IsolatedStorageFile (scope);
			storageFile._domainIdentity = GetDomainIdentityFromEvidence (AppDomain.CurrentDomain.Evidence);
			Evidence e = Assembly.GetCallingAssembly ().UnprotectedGetEvidence ();
			storageFile._fullEvidences = e;
			storageFile._assemblyIdentity = GetAssemblyIdentityFromEvidence (e);
			storageFile.PostInit ();
			return storageFile;
		}

		public static void Remove (IsolatedStorageScope scope)
		{
			string dir = GetIsolatedStorageRoot (scope);
			Directory.Delete (dir, true);
		}

		// internal static stuff

		// Security Note: We're using InternalGetFolderPath because 
		// IsolatedStorage must be able to work even if we do not have
		// FileIOPermission's PathDiscovery permissions
		internal static string GetIsolatedStorageRoot (IsolatedStorageScope scope)
		{
			// IsolatedStorageScope mixes several flags into one.
			// This first level deals with the root directory - it
			// is decided based on User, User+Roaming or Machine
			string root = null;

			if ((scope & IsolatedStorageScope.User) != 0) {
				if ((scope & IsolatedStorageScope.Roaming) != 0) {
					root = Environment.InternalGetFolderPath (Environment.SpecialFolder.LocalApplicationData);
				} else {
					root = Environment.InternalGetFolderPath (Environment.SpecialFolder.ApplicationData);
				}
#if NET_2_0
			} else if ((scope & IsolatedStorageScope.Machine) != 0) {
				root = Environment.InternalGetFolderPath (Environment.SpecialFolder.CommonApplicationData);
#endif
			}

			if (root == null) {
				string msg = Locale.GetText ("Couldn't access storage location for '{0}'.");
				throw new IsolatedStorageException (String.Format (msg, scope));
			}

			return Path.Combine (root, ".isolated-storage");
		}

		private static void Demand (IsolatedStorageScope scope)
		{
			if (SecurityManager.SecurityEnabled) {
				IsolatedStorageFilePermission isfp = new IsolatedStorageFilePermission (PermissionState.None);
				isfp.UsageAllowed = ScopeToContainment (scope);
				isfp.Demand ();
			}
		}

		private static IsolatedStorageContainment ScopeToContainment (IsolatedStorageScope scope)
		{
			switch (scope) {
			case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
				return IsolatedStorageContainment.DomainIsolationByUser;
			case IsolatedStorageScope.Assembly | IsolatedStorageScope.User:
				return IsolatedStorageContainment.AssemblyIsolationByUser;
			case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
				return IsolatedStorageContainment.DomainIsolationByRoamingUser;
			case IsolatedStorageScope.Assembly | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
				return IsolatedStorageContainment.AssemblyIsolationByRoamingUser;
#if NET_2_0
			case IsolatedStorageScope.Application | IsolatedStorageScope.User:
				return IsolatedStorageContainment.ApplicationIsolationByUser;
			case IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
				return IsolatedStorageContainment.DomainIsolationByMachine;
			case IsolatedStorageScope.Assembly | IsolatedStorageScope.Machine:
				return IsolatedStorageContainment.AssemblyIsolationByMachine;
			case IsolatedStorageScope.Application | IsolatedStorageScope.Machine:
				return IsolatedStorageContainment.ApplicationIsolationByMachine;
			case IsolatedStorageScope.Application | IsolatedStorageScope.User | IsolatedStorageScope.Roaming:
				return IsolatedStorageContainment.ApplicationIsolationByRoamingUser;
#endif
			default:
				// unknown ?!?! then ask for maximum (unrestricted)
				return IsolatedStorageContainment.UnrestrictedIsolatedStorage;
			}
		}

		internal static ulong GetDirectorySize (DirectoryInfo di)
		{
			ulong size = 0;

			foreach (FileInfo fi in di.GetFiles ())
				size += (ulong) fi.Length;

			foreach (DirectoryInfo d in di.GetDirectories ())
				size += GetDirectorySize (d);

			return size;
		}

		// non-static stuff

		private DirectoryInfo directory;

		private IsolatedStorageFile (IsolatedStorageScope scope)
		{
			storage_scope = scope;
		}

		internal IsolatedStorageFile (IsolatedStorageScope scope, string location)
		{
			storage_scope = scope;
			directory = new DirectoryInfo (location);
			if (!directory.Exists) {
				string msg = Locale.GetText ("Invalid storage.");
				throw new IsolatedStorageException (msg);
			}
			// load the identities
		}

		~IsolatedStorageFile ()
		{
		}

		private void PostInit ()
		{
			string root = GetIsolatedStorageRoot (Scope);
			string dir = null;
#if NET_2_0
			if (_applicationIdentity != null) {
				dir = String.Format ("a{0}{1}", SeparatorInternal, GetNameFromIdentity (_applicationIdentity));
			} else
#endif
			if (_domainIdentity != null) {
				dir = String.Format ("d{0}{1}{0}{2}", SeparatorInternal,
					GetNameFromIdentity (_domainIdentity), GetNameFromIdentity (_assemblyIdentity));
			} else if (_assemblyIdentity != null) {
				dir = String.Format ("d{0}none{0}{1}", SeparatorInternal, GetNameFromIdentity (_assemblyIdentity));
			} else {
				throw new IsolatedStorageException (Locale.GetText ("No code identity available."));
			}

			root = Path.Combine (root, dir);

			// identities have been selected
			directory = new DirectoryInfo (root);
			if (!directory.Exists) {
				directory.Create ();
				SaveIdentities (root);
			}
		}

		[CLSCompliant(false)]
		public override ulong CurrentSize {
			get { return GetDirectorySize (directory); }
		}

		[CLSCompliant(false)]
		public override ulong MaximumSize {
			// return an ulong but default is signed long
			get {
				if (!SecurityManager.SecurityEnabled)
					return Int64.MaxValue;

				if (_resolved)
					return _maxSize;

				Evidence e = null;
				if (_fullEvidences != null) {
					// if possible use the complete evidences we had
					// for computing the X identity
					e = _fullEvidences;
				} else {
					e = new Evidence ();
					// otherwise use what was provided
					if (_assemblyIdentity != null)
						e.AddHost (_assemblyIdentity);
				}
				if (e.Count < 1) {
					throw new InvalidOperationException (
						Locale.GetText ("Couldn't get the quota from the available evidences."));
				}

				PermissionSet denied = null;
				PermissionSet ps = SecurityManager.ResolvePolicy (e, null, null, null, out denied);
				IsolatedStoragePermission isp = GetPermission (ps);
				if (isp == null) {
					if (ps.IsUnrestricted ()) {
						_maxSize = Int64.MaxValue; /* default value */
					} else {
						throw new InvalidOperationException (
							Locale.GetText ("No quota from the available evidences."));
					}
				} else {
					_maxSize = (ulong) isp.UserQuota;
				}
				_resolved = true;
				return _maxSize;
			}
		}

		internal string Root {
			get { return directory.FullName; }
		}

		// methods

		public void Close ()
		{
		}

		public void CreateDirectory (string dir)
		{
			if (dir == null)
				throw new ArgumentNullException ("dir");

			if (dir.IndexOfAny (Path.PathSeparatorChars) < 0) {
				if (directory.GetFiles (dir).Length > 0)
					throw new IOException (Locale.GetText ("Directory name already exists as a file."));
				directory.CreateSubdirectory (dir);
			} else {
				string[] dirs = dir.Split (Path.PathSeparatorChars);
				DirectoryInfo dinfo = directory;

				for (int i = 0; i < dirs.Length; i++) {
					if (dinfo.GetFiles (dirs [i]).Length > 0)
						throw new IOException (Locale.GetText (
							"Part of the directory name already exists as a file."));
					dinfo = dinfo.CreateSubdirectory (dirs [i]);
				}
			}
		}

		public void DeleteDirectory (string dir)
		{
			try {
				DirectoryInfo subdir = directory.CreateSubdirectory (dir);
				subdir.Delete ();
			}
			catch {
				// hide the real exception to avoid leaking the full path
				throw new IsolatedStorageException (Locale.GetText ("Could not delete directory '{0}'", dir));
			}
		}

		public void DeleteFile (string file)
		{
			File.Delete (Path.Combine (directory.FullName, file));
		}

		public void Dispose ()
		{
			// nothing to dispose, anyway we want to please the tools
			GC.SuppressFinalize (this);
		}

		public string[] GetDirectoryNames (string searchPattern)
		{
			if (searchPattern == null)
				throw new ArgumentNullException ("searchPattern");

			// note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
			// so we need to split them to get the right results
			string path = Path.GetDirectoryName (searchPattern);
			string pattern = Path.GetFileName (searchPattern);
			DirectoryInfo[] adi = null;
			if (path == null || path.Length == 0) {
				adi = directory.GetDirectories (searchPattern);
			} else {
				DirectoryInfo[] subdirs = directory.GetDirectories (path);
				// we're looking for a single result, identical to path (no pattern here)
				// we're also looking for something under the current path (not outside isolated storage)
				if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs [0].FullName.IndexOf (directory.FullName) >= 0)) {
					adi = subdirs [0].GetDirectories (pattern);
				} else {
					// CAS, even in FullTrust, normally enforce IsolatedStorage
					throw new SecurityException ();
				}
			}
			 
			return GetNames (adi);
		}

		private string[] GetNames (FileSystemInfo[] afsi)
		{
			string[] r = new string[afsi.Length];
			for (int i = 0; i != afsi.Length; ++i)
				r[i] = afsi[i].Name;
			return r;
		}

		public string[] GetFileNames (string searchPattern)
		{
			if (searchPattern == null)
				throw new ArgumentNullException ("searchPattern");

			// note: IsolatedStorageFile accept a "dir/file" pattern which is not allowed by DirectoryInfo
			// so we need to split them to get the right results
			string path = Path.GetDirectoryName (searchPattern);
			string pattern = Path.GetFileName (searchPattern);
			FileInfo[] afi = null;
			if (path == null || path.Length == 0) {
				afi = directory.GetFiles (searchPattern);
			} else {
				DirectoryInfo[] subdirs = directory.GetDirectories (path);
				// we're looking for a single result, identical to path (no pattern here)
				// we're also looking for something under the current path (not outside isolated storage)
				if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs [0].FullName.IndexOf (directory.FullName) >= 0)) {
					afi = subdirs [0].GetFiles (pattern);
				} else {
					// CAS, even in FullTrust, normally enforce IsolatedStorage
					throw new SecurityException ();
				}
			}

			return GetNames (afi);
		}

		public override void Remove ()
		{
			directory.Delete (true);
		}


		protected override IsolatedStoragePermission GetPermission (PermissionSet ps)
		{
			if (ps == null)
				return null;
			return (IsolatedStoragePermission) ps.GetPermission (typeof (IsolatedStorageFilePermission));
		}

		// internal stuff

		private string GetNameFromIdentity (object identity)
		{
			// Note: Default evidences return an XML string with ToString
			byte[] id = Encoding.UTF8.GetBytes (identity.ToString ());
			SHA1 hash = SHA1.Create ();
			// this create an unique name for an identity - bad identities like Url
			// results in bad (i.e. changing) names.
			byte[] full = hash.ComputeHash (id, 0, id.Length);
			byte[] half = new byte [10];
			Buffer.BlockCopy (full, 0, half, 0, half.Length);
			return CryptoConvert.ToHex (half);
		}

		private static object GetTypeFromEvidence (Evidence e, Type t)
		{
			foreach (object o in e) {
				if (o.GetType () == t)
					return o;
			}
			return null;
		}

		internal static object GetAssemblyIdentityFromEvidence (Evidence e)
		{
			// we prefer...
			// a. a Publisher evidence
			object identity = GetTypeFromEvidence (e, typeof (Publisher));
			if (identity != null)
				return identity;
			// b. a StrongName evidence
			identity = GetTypeFromEvidence (e, typeof (StrongName));
			if (identity != null)
				return identity;
			// c. a Url evidence
			return GetTypeFromEvidence (e, typeof (Url));
		}

		internal static object GetDomainIdentityFromEvidence (Evidence e)
		{
			// we prefer...
			// a. a ApplicationDirectory evidence
			object identity = GetTypeFromEvidence (e, typeof (ApplicationDirectory));
			if (identity != null)
				return identity;
			// b. a Url evidence
			return GetTypeFromEvidence (e, typeof (Url));
		}

		[Serializable]
		private struct Identities {
			public object Application;
			public object Assembly;
			public object Domain;

			public Identities (object application, object assembly, object domain)
			{
				Application = application;
				Assembly = assembly;
				Domain = domain;
			}
		}

		[SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
		private void LoadIdentities (string root)
		{
			if (!File.Exists (root + ".storage"))
				throw new IsolatedStorageException (Locale.GetText ("Missing identities."));

			using (FileStream fs = File.OpenRead (root + ".storage")) {
				BinaryFormatter deformatter = new BinaryFormatter ();
				Identities identities = (Identities) deformatter.Deserialize (fs);
				fs.Close ();

				_applicationIdentity = identities.Application;
				_assemblyIdentity = identities.Assembly;
				_domainIdentity = identities.Domain;
			}
		}

		[SecurityPermission (SecurityAction.Assert, SerializationFormatter = true)]
		private void SaveIdentities (string root)
		{
			Identities identities = new Identities (_applicationIdentity, _assemblyIdentity, _domainIdentity);
			using (FileStream fs = File.OpenWrite (root + ".storage")) {
				BinaryFormatter formatter = new BinaryFormatter ();
				formatter.Serialize (fs, identities);
				fs.Close ();
			}
		}
	}
}
#endif
