summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/IO/IsolatedStorage/IsolatedStorageFileSmall.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/IO/IsolatedStorage/IsolatedStorageFileSmall.cs')
-rw-r--r--src/mscorlib/src/System/IO/IsolatedStorage/IsolatedStorageFileSmall.cs2082
1 files changed, 2082 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/IO/IsolatedStorage/IsolatedStorageFileSmall.cs b/src/mscorlib/src/System/IO/IsolatedStorage/IsolatedStorageFileSmall.cs
new file mode 100644
index 0000000000..766037fad9
--- /dev/null
+++ b/src/mscorlib/src/System/IO/IsolatedStorage/IsolatedStorageFileSmall.cs
@@ -0,0 +1,2082 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*============================================================
+ *
+//
+//
+ *
+ *
+ * Purpose: Provides access to Application files and folders
+ *
+ *
+ ===========================================================*/
+namespace System.IO.IsolatedStorage {
+ using System;
+ using System.Text;
+ using System.IO;
+ using Microsoft.Win32;
+ using Microsoft.Win32.SafeHandles;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Security;
+ using System.Threading;
+ using System.Security.Policy;
+ using System.Security.Permissions;
+ using System.Runtime.InteropServices;
+ using System.Runtime.CompilerServices;
+#if FEATURE_CORRUPTING_EXCEPTIONS
+ using System.Runtime.ExceptionServices;
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ using System.Runtime.ConstrainedExecution;
+ using System.Runtime.Versioning;
+ using System.Globalization;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics.Contracts;
+ using System.Security.AccessControl;
+ using System.Security.Principal;
+ using System.Security.Util;
+
+ public sealed class IsolatedStorageFile : IDisposable {
+ private const int s_BlockSize = 1024;
+ private const int s_DirSize = s_BlockSize;
+#if !FEATURE_LEGACYNETCF
+ internal const string s_GroupPathPrefix = "g";
+ internal const string s_StorePathPrefix = "s";
+ internal const string s_FilesPathPrefix = "f";
+ internal const string s_LockPathPrefix = "l";
+ internal const string s_GroupFileName = "group.dat";
+ internal const string s_IdFileName = "id.dat";
+ internal const string s_CleanupFileName = "pendingcleanup.dat";
+ internal const string c_VersionPrefix = "1";
+#endif // !FEATURE_LEGACYNETCF
+ internal const string c_DisabledFileName = "disabled.dat";
+
+#if !FEATURE_LEGACYNETCF
+ private string m_GroupPath;
+ private string m_StorePath;
+#endif
+ private string m_AppFilesPath;
+ private string m_GroupName;
+
+ private FileIOAccess m_AppFilesPathAccess;
+
+ private bool m_bDisposed;
+ private bool m_closed;
+
+ private object m_internalLock = new object();
+
+ private static string s_RootFromHost;
+ private static string s_IsolatedStorageRoot;
+
+#if FEATURE_LEGACYNETCF
+ private static Lazy<IsolatedStorageFileIOHelperBase> s_IsoStoreFileIOHelper;
+
+ [SecuritySafeCritical]
+ static IsolatedStorageFile() {
+ // IsolatedStorageFile is on the dangerous list, so we can't construct a delegate to GetIsolatedStorageFileIOHelper in partial trust
+ // unless we have ReflectionPermission.
+ (new ReflectionPermission(PermissionState.Unrestricted)).Assert();
+ s_IsoStoreFileIOHelper = new Lazy<IsolatedStorageFileIOHelperBase>(GetIsolatedStorageFileIOHelper);
+ }
+#endif
+
+#if !FEATURE_LEGACYNETCF
+ private IsolatedStorageAccountingInfo m_accountingInfo;
+#endif // !FEATURE_LEGACYNETCF
+
+ /*
+ * Constructors
+ */
+ internal IsolatedStorageFile() { }
+
+#if !FEATURE_LEGACYNETCF
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private FileLock GetGroupFileLock() {
+ return FileLock.GetFileLock(Path.Combine(IsolatedStorageRoot, s_LockPathPrefix), s_GroupPathPrefix + "-" + DirectoryInfo.UnsafeCreateDirectoryInfo(m_GroupPath).Name);
+ }
+#endif
+
+ /*
+ * Public Static Properties
+ */
+ public static Int64 DefaultQuota {
+ get {
+#if FEATURE_LEGACYNETCF
+ return Int64.MaxValue;
+#else
+ return 1024 * 1024;
+#endif // FEATURE_LEGACYNETCF
+ }
+ }
+
+ public static Boolean IsEnabled {
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ get {
+ return IsolatedStorageGroup.Enabled;
+ }
+ }
+
+ /*
+ * Public Instance Properties
+ */
+ public Int64 UsedSize {
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ get {
+#if !FEATURE_LEGACYNETCF
+ lock (m_internalLock) {
+
+ EnsureStoreIsValid();
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+ return m_accountingInfo.UsedSize;
+ } catch (IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } finally {
+ groupLock.Unlock();
+ }
+ }
+#else // !FEATURE_LEGACYNETCF
+ return 0;
+#endif // !FEATURE_LEGACYNETCF
+ }
+ }
+
+ public Int64 Quota {
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ get
+ {
+#if !FEATURE_LEGACYNETCF
+ lock(m_internalLock) {
+
+ EnsureStoreIsValid();
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+ return m_accountingInfo.Quota;
+ } catch(IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } finally {
+ groupLock.Unlock();
+ }
+ }
+#else // !FEATURE_LEGACYNETCF
+ EnsureStoreIsValid();
+
+ return Int64.MaxValue;
+#endif
+ }
+ }
+
+ public Int64 AvailableFreeSpace {
+#if FEATURE_LEGACYNETCF
+ [SecuritySafeCritical]
+#endif
+ get {
+#if FEATURE_LEGACYNETCF
+ IsolatedStorageSecurityState s = IsolatedStorageSecurityState.CreateStateToGetAvailableFreeSpace();
+ if(s.IsStateAvailable())
+ {
+ if (s.AvailableFreeSpaceComputed) {
+ return s.AvailableFreeSpace;
+ } else {
+ return Quota - UsedSize;
+ }
+ } else {
+ return Quota - UsedSize;
+ }
+#else // FEATURE_LEGACYNETCF
+ return Quota - UsedSize;
+#endif // FEATURE_LEGACYNETCF
+ }
+ }
+
+ /*
+ * Private Properties
+ */
+ internal string RootDirectory {
+ get {
+ return m_AppFilesPath;
+ }
+ }
+
+ internal bool Disposed {
+ get {
+ return m_bDisposed;
+ }
+ }
+
+#if FEATURE_LEGACYNETCF
+ internal string GroupName {
+ get {
+ return m_GroupName;
+ }
+ }
+#endif
+
+ internal static string IsolatedStorageRoot {
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ get {
+ if (s_IsolatedStorageRoot == null) {
+ // No need to lock here, FetchOrCreateRoot is idempotent.
+ s_IsolatedStorageRoot = FetchOrCreateRoot();
+ }
+
+ return s_IsolatedStorageRoot;
+ }
+
+ private set {
+ s_IsolatedStorageRoot = value;
+ }
+ }
+
+ internal bool IsDeleted {
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ get {
+ try {
+#if !FEATURE_LEGACYNETCF
+ return !(Directory.UnsafeExists(m_StorePath) && !File.UnsafeExists(Path.Combine(m_StorePath, s_CleanupFileName)) &&
+ !File.UnsafeExists(Path.Combine(m_GroupPath, s_CleanupFileName)));
+#else // !FEATURE_LEGACYNETCF
+ return !Directory.UnsafeExists(IsolatedStorageRoot);
+#endif // !FEATURE_LEGACYNETCF
+ } catch(IOException) {
+ // It's better to assume the IsoStore is gone if we can't prove it is there.
+ return true;
+ } catch(UnauthorizedAccessException) {
+ // It's better to assume the IsoStore is gone if we can't prove it is there.
+ return true;
+ }
+ }
+ }
+
+ /*
+ * Public Instance Methods
+ */
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void Remove() {
+#if !FEATURE_LEGACYNETCF
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+ EnsureStoreIsValid();
+ TryRemove();
+ } finally {
+ groupLock.Unlock();
+ }
+#else
+ CleanDirectoryNoUnreserve(m_AppFilesPath);
+#endif
+ }
+
+#if !FEATURE_LEGACYNETCF
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal bool TryRemove() {
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+
+ bool removedAll = false;
+
+ try {
+ TouchFile(Path.Combine(m_StorePath, s_CleanupFileName));
+ removedAll = CleanDirectory(Path.Combine(m_StorePath, s_FilesPathPrefix));
+
+ if (removedAll) {
+ Directory.UnsafeDelete(Path.Combine(m_StorePath, s_FilesPathPrefix), false);
+ File.UnsafeDelete(Path.Combine(m_StorePath, s_GroupFileName));
+ File.UnsafeDelete(Path.Combine(m_StorePath, s_IdFileName));
+ File.UnsafeDelete(Path.Combine(m_StorePath, s_CleanupFileName));
+ Directory.UnsafeDelete(m_StorePath, false);
+ Unreserve(s_DirSize);
+ }
+
+ } catch (IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+
+ Close();
+
+ return removedAll;
+ } finally {
+ groupLock.Unlock();
+ }
+ }
+#endif // !FEATURE_LEGACYNETCF
+
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static bool CleanDirectoryNoUnreserve(string targetDirectory) {
+ bool noErrors = true;
+
+ foreach (string f in Directory.UnsafeGetFiles(targetDirectory, "*", SearchOption.TopDirectoryOnly)) {
+ try {
+ File.UnsafeDelete(Path.Combine(targetDirectory, f));
+ } catch (IOException) {
+ noErrors = false;
+ } catch (UnauthorizedAccessException) {
+ noErrors = false;
+ }
+ }
+
+ foreach (string d in Directory.UnsafeGetDirectories(targetDirectory, "*", SearchOption.TopDirectoryOnly)) {
+ if (CleanDirectoryNoUnreserve(d)) {
+ try {
+ Directory.UnsafeDelete(d, false);
+ } catch (IOException) {
+ noErrors = false;
+ } catch (UnauthorizedAccessException) {
+ noErrors = false;
+ }
+ } else {
+ noErrors = false;
+ }
+ }
+ return noErrors;
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private bool CleanDirectory(string targetDirectory) {
+ bool noErrors = true;
+
+ foreach (string f in Directory.UnsafeGetFiles(targetDirectory, "*", SearchOption.TopDirectoryOnly)) {
+ try {
+ long fileLength = FileInfo.UnsafeCreateFileInfo(f).Length;
+ File.UnsafeDelete(Path.Combine(targetDirectory, f));
+ Unreserve(RoundToBlockSize((ulong)fileLength));
+ } catch (IOException) {
+ noErrors = false;
+ } catch (UnauthorizedAccessException) {
+ noErrors = false;
+ }
+ }
+
+ foreach (string d in Directory.UnsafeGetDirectories(targetDirectory, "*", SearchOption.TopDirectoryOnly)) {
+ if (CleanDirectory(d)) {
+ try {
+ Directory.UnsafeDelete(d, false);
+ Unreserve(s_DirSize);
+ } catch (IOException) {
+ noErrors = false;
+ } catch (UnauthorizedAccessException) {
+ noErrors = false;
+ }
+ } else {
+ noErrors = false;
+ }
+ }
+ return noErrors;
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ public void Close() {
+ lock(m_internalLock) {
+
+ if(!m_closed) {
+ m_closed = true;
+#if !FEATURE_LEGACYNETCF
+ m_accountingInfo.Dispose();
+#endif
+ GC.SuppressFinalize(this);
+ }
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public bool IncreaseQuotaTo(Int64 newQuotaSize) {
+ if(newQuotaSize <= Quota) {
+ throw new ArgumentException(Environment.GetResourceString("IsolatedStorage_OldQuotaLarger"));
+ }
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ IsolatedStorageSecurityState s = IsolatedStorageSecurityState.CreateStateToIncreaseQuotaForGroup(m_GroupName, newQuotaSize, UsedSize);
+ if(!s.IsStateAvailable())
+ {
+ return false;
+ }
+
+#if !FEATURE_LEGACYNETCF
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+ m_accountingInfo.Quota = s.Quota;
+ return true;
+ } catch(IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } finally {
+ groupLock.Unlock();
+ }
+#else // !FEATURE_LEGACYNETCF
+ return true;
+#endif
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void DeleteFile(String file) {
+ if(file == null)
+ throw new ArgumentNullException("file");
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ long oldLen = 0;
+
+ bool locked = false;
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try {
+ Lock(ref locked); // protect oldLen
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ try {
+
+ String fullPath = GetFullPath(file);
+
+ Demand(fullPath);
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ FileInfo f = FileInfo.UnsafeCreateFileInfo(fullPath);
+ oldLen = f.Length;
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ File.UnsafeDelete(fullPath);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_DeleteFile", e);
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ Unreserve(RoundToBlockSize((ulong)oldLen));
+ } finally {
+ if(locked)
+ Unlock();
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public bool FileExists(string path) {
+
+ if(path == null) {
+ if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
+ return false;
+ }
+
+ throw new ArgumentNullException("path");
+ }
+
+ EnsureStoreIsValid();
+
+ String isPath = GetFullPath(path); // Prepend IS root
+ String fullPath = Path.GetFullPathInternal(isPath);
+
+ // Make sure that we have permission to check the file so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(fullPath);
+ } catch {
+ // File.UnsafeExists returns false if the demand fails as well.
+ return false;
+ }
+
+ bool ret = File.UnsafeExists(fullPath);
+
+ return ret;
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public bool DirectoryExists(string path) {
+ if (path == null)
+ throw new ArgumentNullException("path");
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String isPath = GetFullPath(path); // Prepend IS root
+ String fullPath = Path.GetFullPathInternal(isPath);
+
+ if (isPath.EndsWith(Path.DirectorySeparatorChar + ".", StringComparison.Ordinal)) {
+ if (fullPath.EndsWith(Path.DirectorySeparatorChar)) {
+ fullPath += ".";
+ } else {
+ fullPath += Path.DirectorySeparatorChar + ".";
+ }
+ }
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(fullPath);
+ } catch {
+ // Directory.UnsafeExists returns false if the demand fails as well.
+ return false;
+ }
+
+ bool ret = Directory.UnsafeExists(fullPath);
+
+ return ret;
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void CreateDirectory(String dir) {
+ if(dir == null)
+ throw new ArgumentNullException("dir");
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String isPath = GetFullPath(dir); // Prepend IS root
+ String fullPath = Path.GetFullPathInternal(isPath);
+
+
+ // Make sure that we have permission to create the directory, so that we don't try to process
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(fullPath);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_CreateDirectory", e);
+ }
+
+ // We can save a bunch of work if the directory we want to create already exists. This also
+ // saves us in the case where sub paths are inaccessible (due to ERROR_ACCESS_DENIED) but the
+ // final path is accessable and the directory already exists. For example, consider trying
+ // to create c:\Foo\Bar\Baz, where everything already exists but ACLS prevent access to c:\Foo
+ // and c:\Foo\Bar. In that case, this code will think it needs to create c:\Foo, and c:\Foo\Bar
+ // and fail to due so, causing an exception to be thrown. This is not what we want.
+ if(Directory.InternalExists(fullPath)) {
+ return;
+ }
+
+ String[] dirList = DirectoriesToCreate(fullPath);
+
+ // Nothing to create, return.
+ if(dirList == null) {
+ return;
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ Reserve(s_DirSize * ((ulong)dirList.Length));
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ try {
+ Directory.UnsafeCreateDirectory(dirList[dirList.Length - 1]);
+ } catch (Exception e) {
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ Unreserve(s_DirSize * ((ulong)dirList.Length));
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ // force delete any new directories we created
+ try {
+ Directory.UnsafeDelete(dirList[0], true);
+ } catch {
+ // If the above failed (on index 0) then this could fail as well.
+ }
+ throw GetIsolatedStorageException("IsolatedStorage_CreateDirectory", e);
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void DeleteDirectory(String dir) {
+ if(dir == null)
+ throw new ArgumentNullException("dir");
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ bool locked = false;
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try {
+ Lock(ref locked); // Delete *.*, will beat quota enforcement without this lock
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ try {
+ string fullPath = GetFullPath(dir);
+ Demand(fullPath);
+ Directory.UnsafeDelete(fullPath, false);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_DeleteDirectory", e);
+ }
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ Unreserve(s_DirSize);
+ } finally {
+ if(locked)
+ Unlock();
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ }
+
+ public String[] GetFileNames() {
+ return GetFileNames("*");
+ }
+
+ /*
+ * foo\abc*.txt will give all abc*.txt files in foo directory
+ */
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public String[] GetFileNames(String searchPattern) {
+ if(searchPattern == null)
+ throw new ArgumentNullException("searchPattern");
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String[] retVal = GetFileDirectoryNames(GetFullPath(searchPattern), searchPattern, true, this);
+ return retVal;
+ }
+
+ public String[] GetDirectoryNames() {
+ return GetDirectoryNames("*");
+ }
+
+ /*
+ * foo\data* will give all directory names in foo directory that
+ * starts with data
+ */
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public String[] GetDirectoryNames(String searchPattern) {
+ if(searchPattern == null)
+ throw new ArgumentNullException("searchPattern");
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String[] retVal = GetFileDirectoryNames(GetFullPath(searchPattern), searchPattern, false, this);
+ return retVal;
+ }
+
+ public IsolatedStorageFileStream OpenFile(string path, FileMode mode) {
+
+ EnsureStoreIsValid();
+ return new IsolatedStorageFileStream(path, mode, this);
+
+ }
+
+ public IsolatedStorageFileStream OpenFile(string path, FileMode mode, FileAccess access) {
+
+ EnsureStoreIsValid();
+ return new IsolatedStorageFileStream(path, mode, access, this);
+ }
+
+ public IsolatedStorageFileStream OpenFile(string path, FileMode mode, FileAccess access, FileShare share) {
+
+ EnsureStoreIsValid();
+ return new IsolatedStorageFileStream(path, mode, access, share, this);
+ }
+
+ public IsolatedStorageFileStream CreateFile(string path) {
+
+ EnsureStoreIsValid();
+ return new IsolatedStorageFileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, this);
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public DateTimeOffset GetCreationTime(string path) {
+
+ if (path == null)
+ throw new ArgumentNullException("path");
+
+ if (path == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "path");
+ }
+
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String isPath = GetFullPath(path); // Prepend IS root
+ String fullPath = Path.GetFullPathInternal(isPath);
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(fullPath);
+ } catch {
+ return new DateTimeOffset(1601, 1, 1, 0, 0, 0, TimeSpan.Zero).ToLocalTime();
+ }
+
+ DateTimeOffset ret = new DateTimeOffset(File.GetCreationTimeUtc(fullPath)).ToLocalTime();
+
+ return ret;
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public DateTimeOffset GetLastAccessTime(string path) {
+
+ if (path == null)
+ throw new ArgumentNullException("path");
+
+ if (path == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "path");
+ }
+
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String isPath = GetFullPath(path); // Prepend IS root
+ String fullPath = Path.GetFullPathInternal(isPath);
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(fullPath);
+ } catch {
+ return new DateTimeOffset(1601, 1, 1, 0, 0, 0, TimeSpan.Zero).ToLocalTime();
+ }
+
+ DateTimeOffset ret = new DateTimeOffset(File.GetLastAccessTimeUtc(fullPath)).ToLocalTime();
+
+ return ret;
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public DateTimeOffset GetLastWriteTime(string path) {
+
+ if (path == null)
+ throw new ArgumentNullException("path");
+
+ if (path == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "path");
+ }
+
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String isPath = GetFullPath(path); // Prepend IS root
+ String fullPath = Path.GetFullPathInternal(isPath);
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(fullPath);
+ } catch {
+ return new DateTimeOffset(1601, 1, 1, 0, 0, 0, TimeSpan.Zero).ToLocalTime();
+ }
+
+ DateTimeOffset ret = new DateTimeOffset(File.GetLastWriteTimeUtc(fullPath)).ToLocalTime();
+
+ return ret;
+ }
+
+
+ public void CopyFile(string sourceFileName, string destinationFileName) {
+
+ if (sourceFileName == null)
+ throw new ArgumentNullException("sourceFileName");
+
+ if (destinationFileName == null)
+ throw new ArgumentNullException("destinationFileName");
+
+ if (sourceFileName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "sourceFileName");
+ }
+
+ if (destinationFileName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "destinationFileName");
+ }
+
+ Contract.EndContractBlock();
+
+ CopyFile(sourceFileName, destinationFileName, false);
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void CopyFile(string sourceFileName, string destinationFileName, bool overwrite) {
+
+ if (sourceFileName == null)
+ throw new ArgumentNullException("sourceFileName");
+
+ if (destinationFileName == null)
+ throw new ArgumentNullException("destinationFileName");
+
+ if (sourceFileName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "sourceFileName");
+ }
+
+ if (destinationFileName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "destinationFileName");
+ }
+
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String sourceFileNameFullPath = Path.GetFullPathInternal(GetFullPath(sourceFileName));
+ String destinationFileNameFullPath = Path.GetFullPathInternal(GetFullPath(destinationFileName));
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(sourceFileNameFullPath);
+ Demand(destinationFileNameFullPath);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ bool isLocked = false;
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try {
+ Lock(ref isLocked);
+
+ FileInfo sourceInfo = FileInfo.UnsafeCreateFileInfo(sourceFileNameFullPath);
+ FileInfo destInfo = FileInfo.UnsafeCreateFileInfo(destinationFileNameFullPath);
+
+ long fileLen = sourceInfo.Length;
+ long destLen = destInfo.Exists ? destInfo.Length : 0;
+
+ if (destLen < fileLen) {
+ Reserve(RoundToBlockSize((ulong)(fileLen - destLen)));
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ try {
+ File.UnsafeCopy(sourceFileNameFullPath, destinationFileNameFullPath, overwrite);
+ } catch (FileNotFoundException) {
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ // Copying the file failed, undo our reserve.
+ if (destLen < fileLen) {
+ Unreserve(RoundToBlockSize((ulong)(fileLen - destLen)));
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ throw new FileNotFoundException(Environment.GetResourceString("IO.PathNotFound_Path", sourceFileName));
+ } catch (Exception e) {
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ // Copying the file failed, undo our reserve.
+ if (destLen < fileLen) {
+ Unreserve(RoundToBlockSize((ulong)(fileLen - destLen)));
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ // If the file we we overwrote was larger than the source file, then we can free some used blocks.
+ if (destLen > fileLen && overwrite) {
+ Unreserve(RoundToBlockSizeFloor((ulong)(destLen - fileLen)));
+ }
+
+ } finally {
+ if (isLocked) {
+ Unlock();
+ }
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void MoveFile(string sourceFileName, string destinationFileName) {
+
+ if (sourceFileName == null)
+ throw new ArgumentNullException("sourceFileName");
+
+ if (destinationFileName == null)
+ throw new ArgumentNullException("destinationFileName");
+
+ if (sourceFileName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "sourceFileName");
+ }
+
+ if (destinationFileName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "destinationFileName");
+ }
+
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String sourceFileNameFullPath = Path.GetFullPathInternal(GetFullPath(sourceFileName));
+ String destinationFileNameFullPath = Path.GetFullPathInternal(GetFullPath(destinationFileName));
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(sourceFileNameFullPath);
+ Demand(destinationFileNameFullPath);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+
+ try {
+#if !FEATURE_LEGACYNETCF
+ File.UnsafeMove(sourceFileNameFullPath, destinationFileNameFullPath);
+#else
+ // We use the WinRT methods instead of Win32 APIs as this will fix up ACLs when you move the file
+ // which matches what phone did.
+ s_IsoStoreFileIOHelper.Value.UnsafeMoveFile(sourceFileNameFullPath, destinationFileNameFullPath);
+#endif
+ } catch (FileNotFoundException) {
+ throw new FileNotFoundException(Environment.GetResourceString("IO.PathNotFound_Path", sourceFileName));
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public void MoveDirectory(string sourceDirectoryName, string destinationDirectoryName) {
+
+ if (sourceDirectoryName == null)
+ throw new ArgumentNullException("sourceDirectoryName");
+
+ if (destinationDirectoryName == null)
+ throw new ArgumentNullException("destinationDirectoryName");
+
+ if (sourceDirectoryName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "sourceDirectoryName");
+ }
+
+ if (destinationDirectoryName == String.Empty) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "destinationDirectoryName");
+ }
+
+ Contract.EndContractBlock();
+
+ EnsureStoreIsValid();
+
+ String sourceDirectoryNameFullPath = Path.GetFullPathInternal(GetFullPath(sourceDirectoryName));
+ String destinationDirectoryNameFullPath = Path.GetFullPathInternal(GetFullPath(destinationDirectoryName));
+
+ // Make sure that we have permission to check the directory so we don't
+ // paths like ..\..\..\..\Windows
+ try {
+ Demand(sourceDirectoryNameFullPath);
+ Demand(destinationDirectoryNameFullPath);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+
+ try {
+ Directory.UnsafeMove(sourceDirectoryNameFullPath, destinationDirectoryNameFullPath);
+ } catch (DirectoryNotFoundException) {
+ throw new DirectoryNotFoundException(Environment.GetResourceString("IO.PathNotFound_Path", sourceDirectoryName));
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+ }
+
+
+ /*
+ * Public Static Methods
+ */
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public static IsolatedStorageFile GetUserStoreForApplication() {
+ IsolatedStorageSecurityState s = IsolatedStorageSecurityState.CreateStateToGetGroupAndIdForApplication();
+ s.EnsureState();
+ return GetUserStore(s.Group, s.Id);
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal static IsolatedStorageFile GetUserStore(string group, string id) {
+
+ // This forces the random directories under the root directory given to us by the host to be recreated if they have been
+ // deleted. Pre v4.0 we did this anytime the IsolatedStorageRoot property was accessed, but this was expensive.
+ IsolatedStorageRoot = FetchOrCreateRoot();
+
+ if (!IsolatedStorageGroup.Enabled) {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+
+#if !FEATURE_LEGACYNETCF
+ IsolatedStorageFile isf = new IsolatedStorageFile();
+ isf.m_GroupPath = FetchOrCreateGroup(group, out isf.m_accountingInfo);
+ isf.m_GroupName = group;
+ isf.m_StorePath = FetchOrCreateStore(group, id, isf);
+ isf.m_AppFilesPath = Path.Combine(isf.m_StorePath, s_FilesPathPrefix);
+#else
+ IsolatedStorageFile isf = new IsolatedStorageFile();
+ isf.m_GroupName = group;
+ isf.m_AppFilesPath = IsolatedStorageRoot;
+#endif
+
+ isf.m_AppFilesPathAccess = FileIOAccessFromPath(isf.m_AppFilesPath);
+
+ return isf;
+ }
+
+#if !FEATURE_LEGACYNETCF
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal static IsolatedStorageFile GetUserStoreFromGroupAndStorePath(string group, string storePath) {
+ IsolatedStorageFile isf = new IsolatedStorageFile();
+ isf.m_GroupPath = GetGroupPathFromName(group);
+ isf.m_GroupName = group;
+ isf.m_accountingInfo = new IsolatedStorageAccountingInfo(isf.m_GroupPath);
+ isf.m_StorePath = storePath;
+ isf.m_AppFilesPath = Path.Combine(isf.m_StorePath, s_FilesPathPrefix);
+ isf.m_AppFilesPathAccess = FileIOAccessFromPath(isf.m_AppFilesPath);
+
+ return isf;
+ }
+#endif
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ public static IsolatedStorageFile GetUserStoreForSite() {
+
+#if !FEATURE_LEGACYNETCF
+ IsolatedStorageSecurityState s = IsolatedStorageSecurityState.CreateStateToGetGroupAndIdForSite();
+ s.EnsureState();
+ return GetUserStore(s.Group, s.Id);
+#else // !FEATURE_LEGACYNETCF
+ // Legacy NetCF didn't make a distinction between Apps and Sites, they both used the Application identity.
+ return GetUserStoreForApplication();
+#endif // !FEATURE_LEGACYNETCF
+
+ }
+
+
+ /*
+ * Private Instance Methods
+ */
+ internal string GetFullPath(string partialPath) {
+
+ Contract.Assert(partialPath != null, "partialPath should be non null");
+
+ int i;
+
+ // Chop off directory separator characters at the start of the string because they counfuse Path.Combine.
+ for(i = 0; i < partialPath.Length; i++) {
+ if(partialPath[i] != Path.DirectorySeparatorChar && partialPath[i] != Path.AltDirectorySeparatorChar) {
+ break;
+ }
+ }
+
+ partialPath = partialPath.Substring(i);
+
+ return Path.Combine(m_AppFilesPath, partialPath);
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void Reserve(ulong lReserve) {
+
+ lock(m_internalLock) {
+
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+ long oldUsed = m_accountingInfo.UsedSize;
+ long quota = m_accountingInfo.Quota;
+ if(oldUsed + (long) lReserve > quota) {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_UsageWillExceedQuota"));
+ }
+ long newUsed = oldUsed + (long) lReserve;
+ m_accountingInfo.UsedSize = newUsed;
+ } catch(IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } finally {
+ groupLock.Unlock();
+ }
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void Unreserve(ulong lFree) {
+
+ lock(m_internalLock) {
+
+ FileLock groupLock = GetGroupFileLock();
+
+ try {
+ groupLock.Lock();
+ long oldUsed = m_accountingInfo.UsedSize;
+ long newUsed = oldUsed - (long) lFree;
+ Contract.Assert(newUsed >= 0, "Unreserve is making quota negative!");
+ m_accountingInfo.UsedSize = newUsed;
+ } catch(IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } finally {
+ groupLock.Unlock();
+ }
+ }
+ }
+
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void Lock(ref bool locked)
+ {
+ locked = false;
+
+ FileLock groupLock = GetGroupFileLock();
+
+ lock (m_internalLock) {
+ groupLock.Lock();
+ locked = true;
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void Unlock() {
+
+ FileLock groupLock = GetGroupFileLock();
+
+ lock(m_internalLock) {
+ groupLock.Unlock();
+ }
+ }
+
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ /*
+ * Private Static Methods
+ */
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static void CreatePathPrefixIfNeeded(string path) {
+
+ string root = Path.GetPathRoot(path);
+
+ Contract.Assert(!String.IsNullOrEmpty(root), "Path.GetPathRoot returned null or empty for: " + path);
+
+ try {
+
+ if (!Directory.UnsafeExists(path)) {
+ Directory.UnsafeCreateDirectory(path);
+ }
+
+ } catch (IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal static string FetchOrCreateRoot() {
+
+ string rootFromHost = s_RootFromHost;
+
+ if (s_RootFromHost == null) {
+ IsolatedStorageSecurityState s = IsolatedStorageSecurityState.CreateStateToGetRootUserDirectory();
+ s.EnsureState();
+ string root = s.RootUserDirectory;
+
+#if FEATURE_LEGACYNETCF
+ IsolatedStorageSecurityState s2 = IsolatedStorageSecurityState.CreateStateForIsolatedStorageFolderName();
+ if(s2.IsStateAvailable()) {
+ if(s2.IsolatedStorageFolderName != null) {
+ root = Path.Combine(root , s2.IsolatedStorageFolderName);
+ } else {
+ root = Path.Combine(root , "IsolatedStore");
+ }
+ } else {
+ root = Path.Combine(root, "IsolatedStore");
+ }
+#endif
+ s_RootFromHost = root;
+ }
+
+ CreatePathPrefixIfNeeded(s_RootFromHost);
+
+#if !FEATURE_LEGACYNETCF
+ FileLock rootLock = null;
+ try {
+ rootLock = FileLock.GetFileLock(s_RootFromHost);
+ rootLock.Lock();
+
+ string obfuscatedRootDir = GetRandomDirectory(s_RootFromHost);
+
+ if (obfuscatedRootDir == null) {
+ obfuscatedRootDir = CreateRandomDirectory(s_RootFromHost);
+ }
+
+ obfuscatedRootDir = Path.Combine(obfuscatedRootDir, c_VersionPrefix);
+
+ if (!Directory.UnsafeExists(Path.Combine(Path.Combine(s_RootFromHost, obfuscatedRootDir), s_LockPathPrefix))) {
+ Directory.UnsafeCreateDirectory(Path.Combine(Path.Combine(s_RootFromHost, obfuscatedRootDir), s_LockPathPrefix));
+ }
+
+ return Path.Combine(s_RootFromHost, obfuscatedRootDir);
+
+ } catch (IOException e) {
+ // We don't want to leak any information here
+ // Throw a store initialization exception instead
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ } catch (UnauthorizedAccessException e) {
+ // We don't want to leak any information here
+ // Throw a store initialization exception instead
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ } finally {
+ if (rootLock != null) {
+ rootLock.Unlock();
+ }
+ }
+#else // !FEATURE_LEGACYNETCF
+ return s_RootFromHost;
+#endif // !FEATURE_LEGACYNETCF
+
+ }
+
+ // creates and returns the relative path to the random directory string without the path separator
+#if FEATURE_CORRUPTING_EXCEPTIONS
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #else
+ [System.Security.SecuritySafeCritical]
+ #endif
+
+ [HandleProcessCorruptedStateExceptions]
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ internal static string CreateRandomDirectory(String rootDir) {
+ string rndName;
+ string dirToCreate;
+ do {
+ rndName = Path.Combine(Path.GetRandomFileName(), Path.GetRandomFileName());
+ dirToCreate = Path.Combine(rootDir, rndName);
+ } while(Directory.UnsafeExists(dirToCreate));
+ // Note that there is still a small window (between where we check for .Exists and execute the .CreateDirectory)
+ // when another process can come up with the same random name and create that directory.
+ // That's potentially a security hole, but the odds of that are low enough that the risk is acceptable.
+ try {
+ Directory.UnsafeCreateDirectory(dirToCreate);
+ } catch (Exception e) {
+ // We don't want to leak any information here
+ // Throw a store initialization exception instead
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ }
+ return rndName;
+ }
+
+ // returns the relative path to the current random directory string if one is there without the path separator
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal static string GetRandomDirectory(String rootDir) {
+ String[] nodes1 = GetFileDirectoryNames(Path.Combine(rootDir, "*"), "*", false, null);
+ // First see if there is a new store
+ for(int i = 0; i < nodes1.Length; ++i) {
+ if(nodes1[i].Length == 12) {
+ String[] nodes2 = GetFileDirectoryNames(Path.Combine(Path.Combine(rootDir, nodes1[i]), "*"), "*", false, null);
+ for(int j = 0; j < nodes2.Length; ++j) {
+ if(nodes2[j].Length == 12) {
+ return (Path.Combine(nodes1[i], nodes2[j])); // Get the first directory
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+#if !FEATURE_LEGACYNETCF
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static string FetchOrCreateGroup(string groupName, out IsolatedStorageAccountingInfo accountInfo) {
+ return FetchOrCreateGroup(groupName, out accountInfo, true);
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static string GetGroupPathFromName(string groupName) {
+ string obfuscatedGroupName = GetHash(groupName);
+ string groupRootPath = Path.Combine(IsolatedStorageRoot, Path.Combine(s_GroupPathPrefix, obfuscatedGroupName));
+
+ return groupRootPath;
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static bool DeleteStoresForGroup(string obfuscatedGroupName) {
+ if (Directory.UnsafeExists(Path.Combine(IsolatedStorageRoot, s_StorePathPrefix))) {
+ foreach (string storePath in Directory.UnsafeGetDirectories(Path.Combine(IsolatedStorageRoot, s_StorePathPrefix), "*", SearchOption.TopDirectoryOnly)) {
+ if (File.UnsafeExists(Path.Combine(storePath, s_GroupFileName)) && (File.UnsafeReadAllText(Path.Combine(storePath, s_GroupFileName))) == obfuscatedGroupName) {
+ if (!CleanDirectoryNoUnreserve(storePath)) {
+ // We couldn't clean an existing store that belongs to this group. So we will fail to create the group, doing
+ // so would mess up our bookkeeping information.
+ return false;
+ }
+
+ Directory.UnsafeDelete(storePath, false);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static string FetchOrCreateGroup(string groupName, out IsolatedStorageAccountingInfo accountInfo, bool retry) {
+ string obfuscatedGroupName = GetHash(groupName);
+ string groupRootPath = GetGroupPathFromName(groupName);
+
+ FileLock rootLock = FileLock.GetFileLock(IsolatedStorageRoot);
+
+ try {
+ rootLock.Lock();
+
+ if(Directory.UnsafeExists(groupRootPath)) {
+ if(File.UnsafeExists(Path.Combine(groupRootPath, s_CleanupFileName))) {
+ if (retry) {
+ // The IsolatedStorageGroup object we construct here has dummy data for the Quota and Used Size,
+ // But it doesn't really matter, since we won't use that information for anything. We just want
+ // to use the Group's Remove method.
+ (new IsolatedStorageGroup(groupName, 0, 0, groupRootPath)).Remove();
+ return FetchOrCreateGroup(groupName, out accountInfo, false);
+ } else {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+ } else {
+
+ // We should ensure that the id.dat, quota.dat and used.dat files exist.
+ if (!File.UnsafeExists(Path.Combine(groupRootPath, s_IdFileName))) {
+ // We can simply recreate the id.dat file if it is missing
+ File.UnsafeWriteAllText(Path.Combine(groupRootPath, s_IdFileName), groupName);
+ } else {
+ // Check for colision.
+ if (!groupName.Equals(File.UnsafeReadAllText(Path.Combine(groupRootPath, s_IdFileName)))) {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+ }
+
+ if (!IsolatedStorageAccountingInfo.IsAccountingInfoValid(groupRootPath)) {
+ // We'll delete all the stuff tied to this group and recreate these files.
+
+ if (!DeleteStoresForGroup(obfuscatedGroupName)) {
+ // We couldn't clean an existing store that belongs to this group. So we will fail to create the group, doing
+ // so would mess up our bookkeeping information.
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+ }
+
+ accountInfo = new IsolatedStorageAccountingInfo(groupRootPath);
+
+ return groupRootPath;
+ }
+ } else {
+ // We might be in a weird state where the "g" directory got deleted but there are stores still in that group around
+ // This could happen if a someone deleted the "g" directory with Windows Explorer or Finder or something. We should
+ // ensure there are no stores for this group here.
+ if (!DeleteStoresForGroup(obfuscatedGroupName)) {
+ // We couldn't clean an existing store that belongs to this group. So we will fail to create the group, doing
+ // so would mess up our bookkeeping information.
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+
+ Directory.UnsafeCreateDirectory(groupRootPath);
+ TouchFile(Path.Combine(groupRootPath, s_CleanupFileName));
+
+ File.UnsafeWriteAllText(Path.Combine(groupRootPath, s_IdFileName), groupName);
+ File.UnsafeDelete(Path.Combine(groupRootPath, s_CleanupFileName));
+
+ accountInfo = new IsolatedStorageAccountingInfo(groupRootPath);
+
+ return groupRootPath;
+ }
+ } catch(IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ } finally {
+ rootLock.Unlock();
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static string FetchOrCreateStore(string groupName, string storeName, IsolatedStorageFile isf) {
+ string groupRootPath = GetGroupPathFromName(groupName);
+ string obfuscatedStoreName = GetHash(storeName);
+ string obfuscatedGroupName = GetHash(groupName);
+ string storeRootPath = Path.Combine(IsolatedStorageRoot, Path.Combine(s_StorePathPrefix, obfuscatedStoreName));
+
+ FileLock rootLock = FileLock.GetFileLock(IsolatedStorageRoot);
+
+ try {
+ rootLock.Lock();
+
+ if(Directory.UnsafeExists(storeRootPath)) {
+
+ if (!File.UnsafeExists(Path.Combine(storeRootPath, s_IdFileName))) {
+ File.UnsafeWriteAllText(Path.Combine(storeRootPath, s_IdFileName), storeName);
+ } else {
+ if (!storeName.Equals(File.UnsafeReadAllText(Path.Combine(storeRootPath, s_IdFileName)))) {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+ }
+
+ File.UnsafeWriteAllText(Path.Combine(storeRootPath, s_GroupFileName), obfuscatedGroupName);
+
+
+ if (!Directory.UnsafeExists(Path.Combine(storeRootPath, s_FilesPathPrefix))) {
+ Directory.UnsafeCreateDirectory(Path.Combine(storeRootPath, s_FilesPathPrefix));
+ }
+
+ if(File.UnsafeExists(Path.Combine(storeRootPath, s_CleanupFileName))) {
+ bool removedAll = isf.CleanDirectory(Path.Combine(storeRootPath, s_FilesPathPrefix));
+
+ if(removedAll) {
+ File.UnsafeDelete(Path.Combine(storeRootPath, s_CleanupFileName));
+ return storeRootPath;
+ } else {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Init"));
+ }
+ } else {
+ return storeRootPath;
+ }
+ } else {
+ isf.Reserve(s_DirSize);
+ Directory.UnsafeCreateDirectory(storeRootPath);
+ TouchFile(Path.Combine(storeRootPath, s_CleanupFileName));
+
+ Directory.UnsafeCreateDirectory(Path.Combine(storeRootPath, s_FilesPathPrefix));
+ File.UnsafeWriteAllText(Path.Combine(storeRootPath, s_GroupFileName), obfuscatedGroupName);
+ File.UnsafeWriteAllText(Path.Combine(storeRootPath, s_IdFileName), storeName);
+ File.UnsafeDelete(Path.Combine(storeRootPath, s_CleanupFileName));
+ return storeRootPath;
+ }
+ } catch(IOException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ } catch (UnauthorizedAccessException e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Init", e);
+ } finally {
+ if(rootLock != null) {
+ rootLock.Unlock();
+ }
+ }
+ }
+#endif // !FEATURE_LEGACYNETCF
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal static void TouchFile(string pathToFile) {
+ using (FileStream fs = new FileStream(pathToFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, FileStream.DefaultBufferSize, false)) {
+ // We just need the file to be created.
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ #endif
+ internal void EnsureStoreIsValid() {
+ if(Disposed)
+ throw new ObjectDisposedException(null, Environment.GetResourceString("IsolatedStorage_StoreNotOpen"));
+ Contract.EndContractBlock();
+
+ if(IsDeleted) {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_StoreNotOpen"));
+ }
+
+ if(m_closed)
+ throw new InvalidOperationException(Environment.GetResourceString("IsolatedStorage_StoreNotOpen"));
+
+ if (!IsolatedStorageGroup.Enabled) {
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_StoreNotOpen"));
+ }
+ }
+
+#if FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+ // Utility Functions (Common With IsolatedStorageFile):
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void UndoReserveOperation(ulong oldLen, ulong newLen) {
+ oldLen = RoundToBlockSize(oldLen);
+ if(newLen > oldLen)
+ Unreserve(RoundToBlockSize(newLen - oldLen));
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void Reserve(ulong oldLen, ulong newLen) {
+ oldLen = RoundToBlockSize(oldLen);
+ if(newLen > oldLen)
+ Reserve(RoundToBlockSize(newLen - oldLen));
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void ReserveOneBlock() {
+ Reserve(s_BlockSize);
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ internal void UnreserveOneBlock() {
+ Unreserve(s_BlockSize);
+ }
+#endif // FEATURE_ISOLATED_STORAGE_QUOTA_ENFORCEMENT
+
+ internal static ulong RoundToBlockSize(ulong num) {
+ if(num < s_BlockSize)
+ return s_BlockSize;
+
+ ulong rem = (num % s_BlockSize);
+
+ if(rem != 0)
+ num += (s_BlockSize - rem);
+
+ return num;
+ }
+
+ internal static ulong RoundToBlockSizeFloor(ulong num) {
+ if (num < s_BlockSize)
+ return 0;
+
+ ulong rem = (num % s_BlockSize);
+ num -= rem;
+
+ return num;
+ }
+
+ // Given a path to a dir to create, will return the list of directories to create and the last one in the array is the actual dir to create.
+ // for example if dir is a\\b\\c and none of them exist, the list returned will be a, a\\b, a\\b\\c.
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private String[] DirectoriesToCreate(String fullPath) {
+ Contract.Ensures(Contract.Result<string[]>() == null || Contract.Result<string[]>().Length > 0);
+
+ List<String> list = new List<String>();
+ int length = fullPath.Length;
+
+ // We need to trim the trailing slash or the code will try to create 2 directories of the same name.
+ if(length >= 2 && fullPath[length - 1] == Path.DirectorySeparatorChar)
+ length--;
+ int i = Path.GetRootLength(fullPath);
+
+ // Attempt to figure out which directories don't exist
+ while(i < length) {
+ i++;
+ while(i < length && fullPath[i] != Path.DirectorySeparatorChar)
+ i++;
+ String currDir = fullPath.Substring(0, i);
+
+ if(!Directory.InternalExists(currDir)) { // Create only the ones missing
+ list.Add(currDir);
+ }
+ }
+
+ if(list.Count != 0) {
+ return list.ToArray();
+ }
+ return null;
+ }
+
+
+ [System.Security.SecurityCritical]
+ private static FileIOAccess FileIOAccessFromPath(string fullPath) {
+ FileIOAccess access = new FileIOAccess();
+
+#if FEATURE_WINDOWSPHONE
+ // Due to an interaction between the ACLs on the phone for the directories isolated storage lives in
+ // and GetLongPathNameW (which StringExpressionSet.CreateListFromExpressions ends up calling if the
+ // path name has a ~ in it), we remove all ~'s before constructing the path to demand.
+ //
+ // The risk here is the case where there's a short file name that resolves to a path not under the root
+ // of Isolated Storage, but in that case either the Win32 ACLs will prevent access or the user could
+ // have accessed the files anyway. Since Isolated Storage is not a security boundary in Windows Phone
+ // we are not concerned about this case.
+ fullPath = fullPath.Replace("~", "");
+#endif
+
+ ArrayList expressions = StringExpressionSet.CreateListFromExpressions(new string[] { fullPath }, true);
+ access.AddExpressions(expressions, false);
+ return access;
+ }
+
+ [System.Security.SecurityCritical]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal void Demand(String pathToDemand) {
+ try {
+ FileIOAccess target = FileIOAccessFromPath(pathToDemand);
+ if(!target.IsSubsetOf(m_AppFilesPathAccess))
+ {
+ throw new SecurityException();
+ }
+ } catch (Exception) {
+ // We couldn't construct a FileIOAccess object because the path was bad.
+ throw new SecurityException();
+ }
+ }
+
+ internal static String GetHash(String s) {
+ byte[] preHash = (new System.Security.Cryptography.SHA256Managed()).ComputeHash(Encoding.Unicode.GetBytes(s));
+ if (preHash.Length % 5 != 0) {
+ byte[] b = new byte[preHash.Length + (5 - (preHash.Length % 5))];
+ for (int i = 0; i < preHash.Length; i++) {
+ b[i] = preHash[i];
+ }
+
+ preHash = b;
+ }
+ return Path.ToBase32StringSuitableForDirName(preHash);
+ }
+
+ // From IO.Directory class (make that internal if possible)
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ private static String[] GetFileDirectoryNames(String path, String msg, bool file, IsolatedStorageFile isf) {
+ int hr;
+
+ if(path == null) throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path"));
+ Contract.EndContractBlock();
+
+ bool fEndsWithDirectory = false;
+ char lastChar = path[path.Length - 1];
+ if(lastChar == Path.DirectorySeparatorChar ||
+ lastChar == Path.AltDirectorySeparatorChar ||
+ lastChar == '.')
+ fEndsWithDirectory = true;
+
+
+ // Get an absolute path and do a security check
+ String fullPath = Path.GetFullPathInternal(path);
+
+ // GetFullPath() removes '\', "\." etc from path, we will restore
+ // it here. If path ends in a trailing slash (\), append a *
+ // or we'll get a "Cannot find the file specified" exception
+ if((fEndsWithDirectory) &&
+ (fullPath[fullPath.Length - 1] != lastChar))
+ fullPath += "\\*";
+
+ // Check for read permission to the directory, not to the contents.
+ String dir = Path.GetDirectoryName(fullPath);
+
+ if(dir != null)
+ dir += "\\";
+
+ if(isf != null) {
+ try {
+ isf.Demand(dir == null ? fullPath : dir);
+ } catch (Exception e) {
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", e);
+ }
+ }
+
+ if(CompatibilitySwitches.IsAppEarlierThanWindowsPhoneMango)
+ {
+ // Pre Mango Windows Phone had very odd behavior for this function. It would take the parent directory of the search pattern and do a *
+ // in there. That means something like GetDirectories("Dir1") would be treated as GetDirectories("*") and GetDirectories("Dir2\Dir3") would be
+ // treated as GetDirectories("Dir2\*").
+
+ // This also means that GetDirectories("") returned "IsolatedStorage" since it was looking at the directory above the root of Isolated Storage.
+ fullPath = Path.Combine(Path.GetDirectoryName(fullPath), "*");
+ }
+
+ String[] list = new String[10];
+ int listSize = 0;
+ Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
+
+ // Open a Find handle
+ SafeFindHandle hnd = Win32Native.FindFirstFile(fullPath, data);
+ if(hnd.IsInvalid) {
+ // Calls to GetLastWin32Error overwrites HResult. Store HResult.
+ hr = Marshal.GetLastWin32Error();
+ if(hr == Win32Native.ERROR_FILE_NOT_FOUND)
+ return new String[0];
+
+ // Mango would throw DirectoryNotFoundException if we got ERROR_PATH_NOT_FOUND instead of IsolatedStorageException
+ if(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && hr == Win32Native.ERROR_PATH_NOT_FOUND)
+ __Error.WinIOError(hr, msg);
+
+#if FEATURE_ISOSTORE_LIGHT
+ throw GetIsolatedStorageException("IsolatedStorage_Operation", Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1)));
+#else
+ __Error.WinIOError(hr, msg);
+#endif
+ }
+
+ // Keep asking for more matching files, adding file names to list
+ int numEntries = 0; // Number of directory entities we see.
+ do {
+ bool includeThis; // Should this file/directory be included in the output?
+ if(file)
+ includeThis = (0 == (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY));
+ else {
+ includeThis = (0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY));
+ // Don't add "." nor ".."
+ if(includeThis && (data.cFileName.Equals(".") || data.cFileName.Equals("..")))
+ includeThis = false;
+ }
+
+ if(includeThis) {
+ numEntries++;
+ if(listSize == list.Length) {
+ String[] newList = new String[list.Length * 2];
+ Array.Copy(list, 0, newList, 0, listSize);
+ list = newList;
+ }
+ list[listSize++] = data.cFileName;
+ }
+
+ } while(Win32Native.FindNextFile(hnd, data));
+
+ // Make sure we quit with a sensible error.
+ hr = Marshal.GetLastWin32Error();
+ hnd.Close(); // Close Find handle in all cases.
+ if(hr != 0 && hr != Win32Native.ERROR_NO_MORE_FILES) __Error.WinIOError(hr, msg);
+
+ // Check for a string such as "C:\tmp", in which case we return
+ // just the directory name. FindNextFile fails first time, and
+ // data still contains a directory.
+ if(!file && numEntries == 1 && (0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY))) {
+ String[] sa = new String[1];
+ sa[0] = data.cFileName;
+ return sa;
+ }
+
+ // Return list of files/directories as an array of strings
+ if(listSize == list.Length)
+ return list;
+ String[] items = new String[listSize];
+ Array.Copy(list, 0, items, 0, listSize);
+ return items;
+ }
+
+ public void Dispose() {
+ Close();
+ m_bDisposed = true;
+ }
+
+ [SecurityCritical]
+ internal static Exception GetIsolatedStorageException(string exceptionKey, Exception rootCause) {
+#if DEBUG
+ IsolatedStorageException e = new IsolatedStorageException(Environment.GetResourceString(exceptionKey), rootCause);
+#else
+ Exception innerException = null;
+
+#if !FEATURE_LEGACYNETCF
+ if (IsolatedStorageSecurityState.CreateStateToCheckSetInnerException().IsStateAvailable()) {
+ innerException = rootCause;
+ }
+#endif
+
+ IsolatedStorageException e = new IsolatedStorageException(Environment.GetResourceString(exceptionKey), innerException);
+#endif
+ e.m_UnderlyingException = rootCause;
+
+ return e;
+ }
+
+#if FEATURE_LEGACYNETCF
+ [SecuritySafeCritical]
+ internal static IsolatedStorageFileIOHelperBase GetIsolatedStorageFileIOHelper()
+ {
+ Type WinRTResourceManagerType = Type.GetType("System.IO.IsolatedStorage.IsolatedStorageFileIOHelper, " + AssemblyRef.SystemRuntimeWindowsRuntime, true);
+ return (IsolatedStorageFileIOHelperBase)Activator.CreateInstance(WinRTResourceManagerType, true);
+ }
+#endif // FEATURE_LEGACYNETCF
+
+ }
+
+
+#if FEATURE_LEGACYNETCF
+ //
+ // This is implemented in System.Runtime.WindowsRuntime as function System.IO.IsolatedStorage.IsolatedStorageFileIOHelper,
+ // allowing us to use WinRT to implement MoveFile.
+ // Ideally this would be an interface, or at least an abstract class - but neither seems to play nice with FriendAccessAllowed.
+ //
+ public class IsolatedStorageFileIOHelperBase
+ {
+ [SecurityCritical]
+ public virtual void UnsafeMoveFile(string sourceFileName, string destinationFileName) { }
+ }
+#endif
+
+#if !FEATURE_LEGACYNETCF
+ internal class FileLock {
+
+ private const string s_LockFileName = "lock.dat";
+
+ private string m_FileLockName;
+ private Mutex m_Mutex;
+ private bool m_HaveLock;
+
+ private int m_LockCount = 0;
+
+ [ThreadStatic]
+ private static Dictionary<string, FileLock> cache;
+
+ private static object s_LockObject = new object();
+
+ [SecurityCritical]
+ private FileLock(string pathToLock, string lockFileName) {
+ m_FileLockName = Path.Combine(pathToLock, lockFileName);
+ m_Mutex = GetMutexWithAcl(IsolatedStorageFile.GetHash(m_FileLockName));
+ }
+
+ [SecurityCritical]
+ private static unsafe Mutex GetMutexWithAcl(string mutexName) {
+ // We need to set at a DACL on the Mutex we're going to create to allow it to be shared.
+ // The DACL here grants MUTEX_ALL_ACCESS (0x001F0001) to the current user. This allows hosts
+ // like sllaucher.exe which strip the admin sections of the current user token to access the
+ // Mutex.
+ IntPtr byteArray = IntPtr.Zero;
+ uint byteArraySize = 0;
+ try {
+ if (Win32Native.ConvertStringSdToSd(String.Format(CultureInfo.InvariantCulture, "D:(A;;0x001F0001;;;{0})", GetCurrentSIDAsString()), 1 /*SDDL_REVISION_1*/, out byteArray, ref byteArraySize) == 0) {
+ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1));
+ }
+
+ Win32Native.SECURITY_ATTRIBUTES secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
+ secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
+ // The Win32 function ConvertStringSecurityDescriptorToSecurityDescriptor allocated the buffer pointed to by byteArray
+ // it isn't tracked by the GC so we don't need to pin it.
+ secAttrs.pSecurityDescriptor = (byte*)byteArray.ToPointer();
+ bool createdNew; /* not used */
+ return new Mutex(false, mutexName, out createdNew, secAttrs);
+ } finally {
+ if (byteArray != IntPtr.Zero) {
+ Win32Native.LocalFree(byteArray);
+ }
+ }
+ }
+
+ // This code mimics the behavior of WindowsIdentity.GetCurrent().User.ToString() but doesn't take a
+ // dependency on the WindowsIdentity class because it depends on code not in Silverlight.
+ //
+ // The function works by getting the current token secruity token and getting the TOKEN_USER
+ // structure from the token. This contains the SID, which we can pass to ConvertSidToStringSid.
+ //
+ [SecurityCritical]
+ private static string GetCurrentSIDAsString() {
+ using (SafeTokenHandle hToken = GetCurrentToken(TokenAccessLevels.Query)) {
+ using (SafeLocalAllocHandle tokenUser = GetTokenUserFromToken(hToken)) {
+ IntPtr pStrSid = IntPtr.Zero;
+ try {
+ if (!Win32Native.ConvertSidToStringSid(Marshal.ReadIntPtr(tokenUser.DangerousGetHandle()), ref pStrSid)) {
+ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1));
+ }
+ return Marshal.PtrToStringUni(pStrSid);
+ } finally {
+ if (pStrSid != IntPtr.Zero) {
+ Win32Native.LocalFree(pStrSid);
+ }
+ }
+ }
+ }
+ }
+
+ [SecurityCritical] // auto-generated
+ private static SafeLocalAllocHandle GetTokenUserFromToken(SafeTokenHandle tokenHandle) {
+ SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
+ uint dwLength = (uint)Marshal.SizeOf(typeof(uint));
+ bool result = Win32Native.GetTokenInformation(tokenHandle,
+ 1 /* TokenInformationClass.TokenUser */,
+ safeLocalAllocHandle,
+ 0,
+ out dwLength);
+ int dwErrorCode = Marshal.GetLastWin32Error();
+ switch (dwErrorCode) {
+ case Win32Native.ERROR_INSUFFICIENT_BUFFER:
+ // ptrLength is an [In] param to LocalAlloc
+ UIntPtr ptrLength = new UIntPtr(dwLength);
+ safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength);
+ if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
+ throw new OutOfMemoryException();
+ safeLocalAllocHandle.Initialize(dwLength);
+
+ result = Win32Native.GetTokenInformation(tokenHandle,
+ 1 /* TokenInformationClass.TokenUser */,
+ safeLocalAllocHandle,
+ dwLength,
+ out dwLength);
+ if (!result) {
+ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1));
+ }
+ break;
+ default:
+ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1));
+ break;
+ }
+ return safeLocalAllocHandle;
+ }
+
+ [SecurityCritical] // auto-generated
+ private static SafeTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess) {
+ int lastError;
+ SafeTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out lastError);
+ if (safeTokenHandle.IsInvalid && lastError == Win32Native.ERROR_NO_TOKEN) {
+ safeTokenHandle = GetCurrentProcessToken(desiredAccess, out lastError);
+ if (safeTokenHandle.IsInvalid) {
+ Marshal.ThrowExceptionForHR(lastError);
+ }
+ }
+ return safeTokenHandle;
+ }
+
+ [SecurityCritical] // auto-generated
+ private static SafeTokenHandle GetCurrentProcessToken(TokenAccessLevels desiredAccess, out int lastError) {
+ SafeTokenHandle safeTokenHandle;
+ Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, out safeTokenHandle);
+ lastError = Marshal.GetLastWin32Error();
+ return safeTokenHandle;
+ }
+
+ [SecurityCritical] // auto-generated
+ private static SafeTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int lastError) {
+ SafeTokenHandle safeTokenHandle;
+ Win32Native.OpenThreadToken(Win32Native.GetCurrentThread(), desiredAccess, true, out safeTokenHandle);
+ lastError = Marshal.GetLastWin32Error();
+ return safeTokenHandle;
+ }
+
+ [SecurityCritical]
+ public static FileLock GetFileLock(string pathToLock) {
+ return GetFileLock(pathToLock, s_LockFileName);
+ }
+
+ [SecurityCritical]
+ public static FileLock GetFileLock(string pathToLock, string lockFileName) {
+ lock (s_LockObject) {
+ if (cache == null) {
+ cache = new Dictionary<string, FileLock>();
+ }
+
+ if (!cache.ContainsKey(pathToLock)) {
+ cache[pathToLock] = new FileLock(pathToLock, lockFileName);
+ }
+
+ return cache[pathToLock];
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ public void Lock() {
+ try {
+ lock (this) {
+ if (m_LockCount == 0) {
+ m_HaveLock = m_Mutex.WaitOne(5000);
+ if (!m_HaveLock) {
+ // Couldn't obtain lock!
+ BCLDebug.Assert(false, "Couldn't obtain Lock on: " + m_FileLockName);
+ throw new IsolatedStorageException(Environment.GetResourceString("IsolatedStorage_Operation"));
+ }
+ }
+ }
+ } finally {
+ // We increment m_LockCount even in the case where we throw for Lock because upstack code will do an Unlock call in their finally block.
+ m_LockCount++;
+ }
+ }
+
+ #if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ #endif
+ public void Unlock() {
+ lock (this) {
+ if (m_LockCount == 1) {
+ if (m_HaveLock) {
+ m_Mutex.ReleaseMutex();
+ m_HaveLock = false;
+ }
+ }
+
+ m_LockCount--;
+ }
+ }
+ }
+#endif // !FEATURE_LEGACYNETCF
+}
+