<Compile Include="System\IO\IsolatedStorage\IsolatedStorage.cs" />
<Compile Include="System\IO\IsolatedStorage\IsolatedStorageScope.cs" />
<Compile Include="System\IO\IsolatedStorage\Helper.cs" />
- <Compile Include="System\IO\IsolatedStorage\Helper.Win32Unix.cs" />
<Compile Include="System\IO\IsolatedStorage\INormalizeForIsolatedStorage.cs" />
<Compile Include="$(CommonPath)System\Security\IdentityHelper.cs"
Link="Common\System\Security\IdentityHelper.cs" />
{
internal static partial class Helper
{
+ // we're using a different directory name for compatibility with legacy Xamarin
public const string IsolatedStorageDirectoryName = ".isolated-storage";
+
+ internal static string GetDataDirectory(IsolatedStorageScope scope)
+ {
+ // In legacy Xamarin for Roaming Scope we were using Environment.SpecialFolder.LocalApplicationData
+ // In .Net 7 for Roaming Scope we are using Environment.SpecialFolder.ApplicationData
+ // e.g. Android .Net 7 path = /data/user/0/{packageName}/files/.isolated-storage/{hash}/{hash}/AppFiles/
+ // e.g. Android Xamarin path = /data/user/0/{packageName}/files/.config/.isolated-storage/
+ // e.g. iOS .Net 7 path = /Users/userName/{packageName}/Documents/.isolated-storage/{hash}/{hash}/AppFiles/
+ // e.g. iOS Xamarin path = /Users/userName/{packageName}/Documents/.config/.isolated-storage/
+ //
+ // Since we shipped that behavior as part of .NET 7 we can't change this now or upgraded apps wouldn't find their files anymore.
+ // We need to look for an existing directory first before using the legacy Xamarin approach.
+
+ Environment.SpecialFolder specialFolder =
+ IsMachine(scope) ? Environment.SpecialFolder.CommonApplicationData : // e.g. /usr/share;
+ IsRoaming(scope) ? Environment.SpecialFolder.ApplicationData : // e.g. /data/user/0/{packageName}/files/.config;
+ Environment.SpecialFolder.LocalApplicationData; // e.g. /data/user/0/{packageName}/files;
+
+ string dataDirectory = Environment.GetFolderPath(specialFolder);
+ dataDirectory = Path.Combine(dataDirectory, IsolatedStorageDirectoryName);
+ if (Directory.Exists(dataDirectory))
+ {
+ return dataDirectory;
+ }
+ // Otherwise return legacy xamarin path
+ else
+ {
+ // In .Net 7 for Android SpecialFolder.LocalApplicationData returns "/data/user/0/{packageName}/files"
+ // while in Xamarin it was "/data/user/0/{packageName}/files/.local/share"
+ // For Android we need to hardcode Xamarin path for compatibility with legacy Xamarin
+ if (OperatingSystem.IsAndroid() && IsRoaming(scope))
+ {
+ dataDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + ".local/share";
+ Directory.CreateDirectory(dataDirectory);
+ }
+ else
+ {
+ specialFolder =
+ IsMachine(scope) ? Environment.SpecialFolder.CommonApplicationData :
+ IsRoaming(scope) ? Environment.SpecialFolder.LocalApplicationData :
+ Environment.SpecialFolder.ApplicationData;
+
+ dataDirectory = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.Create);
+ }
+
+ dataDirectory = Path.Combine(dataDirectory, IsolatedStorageDirectoryName);
+ }
+
+ return dataDirectory;
+ }
+
+ internal static string GetRandomDirectory(string rootDirectory, IsolatedStorageScope _)
+ {
+ // In legacy Xamarin we didn't have a random directory inside of the isolated storage root for each app,
+ // we tried to preserve that in https://github.com/dotnet/runtime/pull/75541 but the fix wasn't complete enough
+ // and we still created random directories when not using the Roaming scope.
+ //
+ // Since we shipped that behavior as part of .NET 7 we can't change this now or upgraded apps wouldn't find their files anymore.
+ // We need to look for an existing random directory first before using the plain root directory.
+ return GetExistingRandomDirectory(rootDirectory) ?? rootDirectory;
+ }
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Threading;
+using System.Security;
+
namespace System.IO.IsolatedStorage
{
internal static partial class Helper
{
public const string IsolatedStorageDirectoryName = "IsolatedStorage";
+
+ internal static string GetDataDirectory(IsolatedStorageScope scope)
+ {
+ // This is the relevant special folder for the given scope plus IsolatedStorageDirectoryName.
+ // It is meant to replicate the behavior of the VM ComIsolatedStorage::GetRootDir().
+
+ // (note that Silverlight used "CoreIsolatedStorage" for a directory name and did not support machine scope)
+
+ Environment.SpecialFolder specialFolder =
+ IsMachine(scope) ? Environment.SpecialFolder.CommonApplicationData : // e.g. C:\ProgramData
+ IsRoaming(scope) ? Environment.SpecialFolder.ApplicationData : // e.g. C:\Users\Joe\AppData\Roaming
+ Environment.SpecialFolder.LocalApplicationData; // e.g. C:\Users\Joe\AppData\Local
+
+ string dataDirectory = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.Create);
+ dataDirectory = Path.Combine(dataDirectory, IsolatedStorageDirectoryName);
+
+ return dataDirectory;
+ }
+
+ internal static string GetRandomDirectory(string rootDirectory, IsolatedStorageScope scope)
+ {
+ string? randomDirectory = GetExistingRandomDirectory(rootDirectory);
+ if (string.IsNullOrEmpty(randomDirectory))
+ {
+ using (Mutex m = CreateMutexNotOwned(rootDirectory))
+ {
+ if (!m.WaitOne())
+ {
+ throw new IsolatedStorageException(SR.IsolatedStorage_Init);
+ }
+
+ try
+ {
+ randomDirectory = GetExistingRandomDirectory(rootDirectory);
+ if (string.IsNullOrEmpty(randomDirectory))
+ {
+ // Someone else hasn't created the directory before we took the lock
+ randomDirectory = Path.Combine(rootDirectory, Path.GetRandomFileName(), Path.GetRandomFileName());
+ CreateDirectory(randomDirectory, scope);
+ }
+ }
+ finally
+ {
+ m.ReleaseMutex();
+ }
+ }
+ }
+
+ return randomDirectory;
+ }
+
+ private static Mutex CreateMutexNotOwned(string pathName)
+ {
+ return new Mutex(initiallyOwned: false, name: @"Global\" + IdentityHelper.GetStrongHashSuitableForObjectName(pathName));
+ }
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using System.Security;
-using System.Threading;
-
-namespace System.IO.IsolatedStorage
-{
- internal static partial class Helper
- {
- internal static string GetDataDirectory(IsolatedStorageScope scope)
- {
- // This is the relevant special folder for the given scope plus IsolatedStorageDirectoryName.
- // It is meant to replicate the behavior of the VM ComIsolatedStorage::GetRootDir().
-
- // (note that Silverlight used "CoreIsolatedStorage" for a directory name and did not support machine scope)
-
- Environment.SpecialFolder specialFolder =
- IsMachine(scope) ? Environment.SpecialFolder.CommonApplicationData : // e.g. C:\ProgramData
- IsRoaming(scope) ? Environment.SpecialFolder.ApplicationData : // e.g. C:\Users\Joe\AppData\Roaming
- Environment.SpecialFolder.LocalApplicationData; // e.g. C:\Users\Joe\AppData\Local
-
- string dataDirectory = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.Create);
- dataDirectory = Path.Combine(dataDirectory, IsolatedStorageDirectoryName);
-
- return dataDirectory;
- }
-
- [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file",
- Justification = "Code handles single-file deployment by using the information of the .exe file")]
- internal static void GetDefaultIdentityAndHash(out object identity, out string hash, char separator)
- {
- // In .NET Framework IsolatedStorage uses identity from System.Security.Policy.Evidence to build
- // the folder structure on disk. It would use the "best" available evidence in this order:
- //
- // 1. Publisher (Authenticode)
- // 2. StrongName
- // 3. Url (CodeBase)
- // 4. Site
- // 5. Zone
- //
- // For .NET Core StrongName and Url are the only relevant types. By default evidence for the Domain comes
- // from the Assembly which comes from the EntryAssembly(). We'll emulate the legacy default behavior
- // by pulling directly from EntryAssembly.
- //
- // Note that it is possible that there won't be an EntryAssembly, which is something the .NET Framework doesn't
- // have to deal with and isn't likely on .NET Core due to a single AppDomain. The exception is Android which
- // doesn't set an EntryAssembly.
-
- Assembly? assembly = Assembly.GetEntryAssembly();
- string? location = null;
-
- if (assembly != null)
- {
- AssemblyName assemblyName = assembly.GetName();
-
- hash = IdentityHelper.GetNormalizedStrongNameHash(assemblyName)!;
- if (hash != null)
- {
- hash = string.Concat("StrongName", new ReadOnlySpan<char>(in separator), hash);
- identity = assemblyName;
- return;
- }
- else
- {
- location = assembly.Location;
- }
- }
-
- // In case of SingleFile deployment, Assembly.Location is empty. On Android there is no entry assembly.
- if (string.IsNullOrEmpty(location))
- location = Environment.ProcessPath;
- if (string.IsNullOrEmpty(location))
- throw new IsolatedStorageException(SR.IsolatedStorage_Init);
- Uri locationUri = new Uri(location);
- hash = string.Concat("Url", new ReadOnlySpan<char>(in separator), IdentityHelper.GetNormalizedUriHash(locationUri));
- identity = locationUri;
- }
-
- internal static string GetRandomDirectory(string rootDirectory, IsolatedStorageScope scope)
- {
- string? randomDirectory = GetExistingRandomDirectory(rootDirectory);
- if (string.IsNullOrEmpty(randomDirectory))
- {
- using (Mutex m = CreateMutexNotOwned(rootDirectory))
- {
- if (!m.WaitOne())
- {
- throw new IsolatedStorageException(SR.IsolatedStorage_Init);
- }
-
- try
- {
- randomDirectory = GetExistingRandomDirectory(rootDirectory);
- if (string.IsNullOrEmpty(randomDirectory))
- {
- // Someone else hasn't created the directory before we took the lock
- randomDirectory = Path.Combine(rootDirectory, Path.GetRandomFileName(), Path.GetRandomFileName());
- CreateDirectory(randomDirectory, scope);
- }
- }
- finally
- {
- m.ReleaseMutex();
- }
- }
- }
-
- return randomDirectory;
- }
-
- internal static string? GetExistingRandomDirectory(string rootDirectory)
- {
- // Look for an existing random directory at the given root
- // (a set of nested directories that were created via Path.GetRandomFileName())
-
- // Older versions of the .NET Framework created longer (24 character) random paths and would
- // migrate them if they could not find the new style directory.
-
- if (!Directory.Exists(rootDirectory))
- return null;
-
- foreach (string directory in Directory.GetDirectories(rootDirectory))
- {
- if (Path.GetFileName(directory)?.Length == 12)
- {
- foreach (string subdirectory in Directory.GetDirectories(directory))
- {
- if (Path.GetFileName(subdirectory)?.Length == 12)
- {
- return subdirectory;
- }
- }
- }
- }
-
- return null;
- }
-
- private static Mutex CreateMutexNotOwned(string pathName)
- {
- return new Mutex(initiallyOwned: false, name: @"Global\" + IdentityHelper.GetStrongHashSuitableForObjectName(pathName));
- }
- }
-}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using System.Security;
+using System.Threading;
+
namespace System.IO.IsolatedStorage
{
internal static partial class Helper
/// <summary>
/// The full root directory is the relevant special folder from Environment.GetFolderPath() plus IsolatedStorageDirectoryName
- /// and a set of random directory names if not roaming. (The random directories aren't created for WinRT as
- /// the FolderPath locations for WinRT are app isolated already.)
+ /// and a set of random directory names if not roaming. (The random directories aren't created for Android/iOS as
+ /// the FolderPath locations for Android/iOS are app isolated already.)
///
/// Examples:
///
/// User: @"C:\Users\jerem\AppData\Local\IsolatedStorage\10v31ho4.bo2\eeolfu22.f2w\"
/// User|Roaming: @"C:\Users\jerem\AppData\Roaming\IsolatedStorage\"
/// Machine: @"C:\ProgramData\IsolatedStorage\nin03cyc.wr0\o3j0urs3.0sn\"
- /// Android path: "/data/user/0/net.dot.System.IO.IsolatedStorage.Tests/files/.config/.isolated-storage/"
- /// iOS path: "/var/mobile/Containers/Data/Application/A323CBB9-A2B3-4432-9449-48CC20C07A7D/Documents/.config/.isolated-storage/"
+ /// Android path: "/data/user/0/{packageName}/files/.config/.isolated-storage"
+ /// iOS path: "/var/mobile/Containers/Data/Application/A323CBB9-A2B3-4432-9449-48CC20C07A7D/Documents/.config/.isolated-storage"
///
/// Identity for the current store gets tacked on after this.
/// </summary>
return s_userRootDirectory;
}
+ internal static string? GetExistingRandomDirectory(string rootDirectory)
+ {
+ // Look for an existing random directory at the given root
+ // (a set of nested directories that were created via Path.GetRandomFileName())
+
+ // Older versions of the .NET Framework created longer (24 character) random paths and would
+ // migrate them if they could not find the new style directory.
+
+ if (!Directory.Exists(rootDirectory))
+ return null;
+
+ foreach (string directory in Directory.GetDirectories(rootDirectory))
+ {
+ if (Path.GetFileName(directory)?.Length == 12)
+ {
+ foreach (string subdirectory in Directory.GetDirectories(directory))
+ {
+ if (Path.GetFileName(subdirectory)?.Length == 12)
+ {
+ return subdirectory;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file",
+ Justification = "Code handles single-file deployment by using the information of the .exe file")]
+ internal static void GetDefaultIdentityAndHash(out object identity, out string hash, char separator)
+ {
+ // In .NET Framework IsolatedStorage uses identity from System.Security.Policy.Evidence to build
+ // the folder structure on disk. It would use the "best" available evidence in this order:
+ //
+ // 1. Publisher (Authenticode)
+ // 2. StrongName
+ // 3. Url (CodeBase)
+ // 4. Site
+ // 5. Zone
+ //
+ // For .NET Core StrongName and Url are the only relevant types. By default evidence for the Domain comes
+ // from the Assembly which comes from the EntryAssembly(). We'll emulate the legacy default behavior
+ // by pulling directly from EntryAssembly.
+ //
+ // Note that it is possible that there won't be an EntryAssembly, which is something the .NET Framework doesn't
+ // have to deal with and isn't likely on .NET Core due to a single AppDomain. The exception is Android which
+ // doesn't set an EntryAssembly.
+
+ Assembly? assembly = Assembly.GetEntryAssembly();
+ string? location = null;
+
+ if (assembly != null)
+ {
+ AssemblyName assemblyName = assembly.GetName();
+
+ hash = IdentityHelper.GetNormalizedStrongNameHash(assemblyName)!;
+ if (hash != null)
+ {
+ hash = string.Concat("StrongName", new ReadOnlySpan<char>(in separator), hash);
+ identity = assemblyName;
+ return;
+ }
+ else
+ {
+ location = assembly.Location;
+ }
+ }
+
+ // In case of SingleFile deployment, Assembly.Location is empty. On Android there is no entry assembly.
+ if (string.IsNullOrEmpty(location))
+ location = Environment.ProcessPath;
+ if (string.IsNullOrEmpty(location))
+ throw new IsolatedStorageException(SR.IsolatedStorage_Init);
+ Uri locationUri = new Uri(location);
+ hash = string.Concat("Url", new ReadOnlySpan<char>(in separator), IdentityHelper.GetNormalizedUriHash(locationUri));
+ identity = locationUri;
+ }
+
internal static bool IsMachine(IsolatedStorageScope scope) => ((scope & IsolatedStorageScope.Machine) != 0);
internal static bool IsAssembly(IsolatedStorageScope scope) => ((scope & IsolatedStorageScope.Assembly) != 0);
internal static bool IsApplication(IsolatedStorageScope scope) => ((scope & IsolatedStorageScope.Application) != 0);
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Text;
+
namespace System.IO.IsolatedStorage
{
public sealed partial class IsolatedStorageFile : IsolatedStorage, IDisposable
{
+ internal IsolatedStorageFile(IsolatedStorageScope scope)
+ {
+ // In legacy Xamarin root ends with "/.isolated-storage"
+ // In .Net 7 we added at the end "/AppFiles" or "/Files" or "/AssemFiles/".
+ // e.g. .Net 7 path = /data/user/0/{packageName}/files/.isolated-storage/{hash}/{hash}/AppFiles/
+ // e.g. Xamarin path = /data/user/0/{packageName}/files/.config/.isolated-storage"
+ //
+ // Since we shipped that behavior as part of .NET 7 we can't change this now or upgraded apps wouldn't find their files anymore.
+ // We need to look for an existing directory first before using the legacy Xamarin approach.
+
+ InitStore(scope, null, null);
+
+ StringBuilder sb = new StringBuilder(GetIsolatedStorageRoot());
+
+ string directoryPath = sb.ToString() + SeparatorExternal;
+ if (Helper.IsApplication(scope) && Directory.Exists(directoryPath + s_appFiles))
+ {
+ sb.Append(SeparatorExternal);
+ sb.Append(s_appFiles);
+ sb.Append(SeparatorExternal);
+ }
+ else if (Helper.IsDomain(scope) && Directory.Exists(directoryPath + s_files))
+ {
+ sb.Append(SeparatorExternal);
+ sb.Append(s_files);
+ sb.Append(SeparatorExternal);
+ }
+ else if (Directory.Exists(directoryPath + s_assemFiles))
+ {
+ sb.Append(SeparatorExternal);
+ sb.Append(s_assemFiles);
+ sb.Append(SeparatorExternal);
+ }
+
+ _rootDirectory = sb.ToString();
+ Helper.CreateDirectory(_rootDirectory, scope);
+ }
+
private string GetIsolatedStorageRoot()
{
return Helper.GetRootDirectory(Scope);
}
+
+ private bool IsMatchingScopeDirectory(string _)
+ {
+ return (Helper.IsApplication(Scope)) || (Helper.IsAssembly(Scope)) || (Helper.IsDomain(Scope));
+ }
+
+ private string? GetParentDirectory()
+ {
+ return Path.GetDirectoryName(RootDirectory);
+ }
}
}
{
public sealed partial class IsolatedStorageFile : IsolatedStorage, IDisposable
{
+ // Data file notes
+ // ===============
+
+ // "identity.dat" is the serialized identity object, such as StrongName or Url. It is used to
+ // enumerate stores, which we currently do not support.
+ //
+ // private const string IDFile = "identity.dat";
+
+ // "info.dat" is used to track disk space usage (against quota). The accounting file for Silverlight
+ // stores is "appInfo.dat". .NET Core is always in full trust so we can safely ignore these.
+ //
+ // private const string InfoFile = "info.dat";
+ // private const string AppInfoFile = "appInfo.dat";
+
+ internal IsolatedStorageFile(IsolatedStorageScope scope)
+ {
+ // Evidence isn't currently available: https://github.com/dotnet/runtime/issues/18208
+ // public static IsolatedStorageFile GetStore(IsolatedStorageScope scope, Evidence domainEvidence, Type domainEvidenceType, Evidence assemblyEvidence, Type assemblyEvidenceType) { return default(IsolatedStorageFile); }
+
+ // InitStore will set up the IdentityHash
+ InitStore(scope, null, null);
+
+ StringBuilder sb = new StringBuilder(GetIsolatedStorageRoot());
+ sb.Append(SeparatorExternal);
+
+ if (Helper.IsApplication(scope))
+ {
+ sb.Append(s_appFiles);
+ }
+ else if (Helper.IsDomain(scope))
+ {
+ sb.Append(s_files);
+ }
+ else
+ {
+ sb.Append(s_assemFiles);
+ }
+ sb.Append(SeparatorExternal);
+
+ _rootDirectory = sb.ToString();
+ Helper.CreateDirectory(_rootDirectory, scope);
+ }
+
private string GetIsolatedStorageRoot()
{
StringBuilder root = new StringBuilder(Helper.GetRootDirectory(Scope));
return root.ToString();
}
+
+ private bool IsMatchingScopeDirectory(string directory)
+ {
+ string directoryName = Path.GetFileName(directory);
+
+ return
+ (Helper.IsApplication(Scope) && string.Equals(directoryName, s_appFiles, StringComparison.Ordinal))
+ || (Helper.IsAssembly(Scope) && string.Equals(directoryName, s_assemFiles, StringComparison.Ordinal))
+ || (Helper.IsDomain(Scope) && string.Equals(directoryName, s_files, StringComparison.Ordinal));
+ }
+
+ private string? GetParentDirectory()
+ {
+ return Path.GetDirectoryName(RootDirectory.TrimEnd(Path.DirectorySeparatorChar));
+ }
}
}
private readonly object _internalLock = new object();
private readonly string _rootDirectory;
- // Data file notes
- // ===============
-
- // "identity.dat" is the serialized identity object, such as StrongName or Url. It is used to
- // enumerate stores, which we currently do not support.
- //
- // private const string IDFile = "identity.dat";
-
- // "info.dat" is used to track disk space usage (against quota). The accounting file for Silverlight
- // stores is "appInfo.dat". .NET Core is always in full trust so we can safely ignore these.
- //
- // private const string InfoFile = "info.dat";
- // private const string AppInfoFile = "appInfo.dat";
-
- internal IsolatedStorageFile(IsolatedStorageScope scope)
- {
- // Evidence isn't currently available: https://github.com/dotnet/runtime/issues/18208
- // public static IsolatedStorageFile GetStore(IsolatedStorageScope scope, Evidence domainEvidence, Type domainEvidenceType, Evidence assemblyEvidence, Type assemblyEvidenceType) { return default(IsolatedStorageFile); }
-
- // InitStore will set up the IdentityHash
- InitStore(scope, null, null);
-
- StringBuilder sb = new StringBuilder(GetIsolatedStorageRoot());
- sb.Append(SeparatorExternal);
-
- if (Helper.IsApplication(scope))
- {
- sb.Append(s_appFiles);
- }
- else if (Helper.IsDomain(scope))
- {
- sb.Append(s_files);
- }
- else
- {
- sb.Append(s_assemFiles);
- }
- sb.Append(SeparatorExternal);
-
- _rootDirectory = sb.ToString();
- Helper.CreateDirectory(_rootDirectory, scope);
- }
-
// Using this property to match .NET Framework for testing
private string RootDirectory
{
Close();
- string? parentDirectory = Path.GetDirectoryName(RootDirectory.TrimEnd(Path.DirectorySeparatorChar));
+ string? parentDirectory = GetParentDirectory();
Debug.Assert(parentDirectory != null);
if (ContainsUnknownFiles(parentDirectory))
);
}
- private bool IsMatchingScopeDirectory(string directory)
- {
- string directoryName = Path.GetFileName(directory);
-
- return
- (Helper.IsApplication(Scope) && string.Equals(directoryName, s_appFiles, StringComparison.Ordinal))
- || (Helper.IsAssembly(Scope) && string.Equals(directoryName, s_assemFiles, StringComparison.Ordinal))
- || (Helper.IsDomain(Scope) && string.Equals(directoryName, s_files, StringComparison.Ordinal));
- }
-
private static bool IsIdFile(string file) => string.Equals(Path.GetFileName(file), "identity.dat");
private static bool IsInfoFile(string file) => string.Equals(Path.GetFileName(file), "info.dat");
<Compile Include="System\IO\IsolatedStorage\IsolatedStorageFileStreamTests.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="..\src\System\IO\IsolatedStorage\Helper.Win32Unix.cs"
- Link="Internals\Helper.Win32Unix.cs" />
<Compile Include="System\IO\IsolatedStorage\HelperTests.Win32Unix.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'android' or '$(TargetPlatformIdentifier)' == 'ios' or '$(TargetPlatformIdentifier)' == 'maccatalyst' or '$(TargetPlatformIdentifier)' == 'tvos'">
<Compile Include="..\src\System\IO\IsolatedStorage\Helper.AnyMobile.cs" />
<Compile Include="System\IO\IsolatedStorage\TestHelper.AnyMobile.cs" />
+ <Compile Include="System\IO\IsolatedStorage\HelperTests.AnyMobile.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetPlatformIdentifier)' != 'android' and '$(TargetPlatformIdentifier)' != 'ios' and '$(TargetPlatformIdentifier)' != 'maccatalyst' and '$(TargetPlatformIdentifier)' != 'tvos' and '$(TargetPlatformIdentifier)' != ''">
<Compile Include="..\src\System\IO\IsolatedStorage\Helper.NonMobile.cs" />
<Compile Include="System\IO\IsolatedStorage\TestHelper.NonMobile.cs" />
+ <Compile Include="System\IO\IsolatedStorage\HelperTests.NonMobile.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(LibrariesProjectRoot)System.DirectoryServices\src\System.DirectoryServices.csproj" />
}
[Theory, MemberData(nameof(ValidStores))]
+ [SkipOnPlatform(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "For mobile platforms root ends with /.isolated-storage/")]
public void ContainsUnknownFiles_NotOkDirectory(PresetScopes scope)
{
TestHelper.WipeStores();
using (var isf = GetPresetScope(scope))
{
string root = isf.GetUserRootDirectory();
- string file = "FileExists_Existence";
+ string file = scope.ToString() + "FileExists_Existence";
isf.CreateTestFile(file);
Assert.True(File.Exists(Path.Combine(root, file)), "exists per file.io where expected");
}
[Fact]
+ [SkipOnPlatform(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "For mobile platforms root ends with /.isolated-storage")]
public void GetUserStoreForApplication()
{
var isf = IsolatedStorageFile.GetUserStoreForApplication();
}
[Fact]
+ [SkipOnPlatform(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "For mobile platforms root ends with /.isolated-storage")]
public void GetUserStoreForAssembly()
{
var isf = IsolatedStorageFile.GetUserStoreForAssembly();
}
[Fact]
+ [SkipOnPlatform(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "For mobile platforms root ends with /.isolated-storage")]
public void GetUserStoreForDomain()
{
var isf = IsolatedStorageFile.GetUserStoreForDomain();
}
[Fact]
+ [SkipOnPlatform(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "For mobile platforms root ends with /.isolated-storage")]
public void GetStore_NullParamsAllowed()
{
VerifyApplicationStore(IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Application, (Type)null));
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+using System.Reflection;
+using System.Text;
+
+namespace System.IO.IsolatedStorage
+{
+ public partial class HelperTests
+ {
+ [Theory, InlineData(IsolatedStorageScope.User)]
+ public void GetRandomDirectory(IsolatedStorageScope scope)
+ {
+ using (var temp = new TempDirectory())
+ {
+ string randomDir = Helper.GetRandomDirectory(temp.Path, scope);
+ Assert.True(Directory.Exists(randomDir.Replace(Helper.IsolatedStorageDirectoryName, "")));
+ }
+ }
+
+ [Theory,
+ InlineData(IsolatedStorageScope.Assembly),
+ InlineData(IsolatedStorageScope.Assembly | IsolatedStorageScope.Roaming),
+ InlineData(IsolatedStorageScope.User)
+ ]
+ public void GetRandomDirectoryWithExistingDir(IsolatedStorageScope scope)
+ {
+ using (var temp = new TempDirectory())
+ {
+ Assert.Null(Helper.GetExistingRandomDirectory(temp.Path));
+
+ string randomPath = Path.Combine(temp.Path, Path.GetRandomFileName(), Path.GetRandomFileName());
+ Directory.CreateDirectory(randomPath);
+ Assert.Equal(randomPath, Helper.GetExistingRandomDirectory(temp.Path));
+ Assert.Equal(Helper.GetRandomDirectory(temp.Path, scope), Helper.GetExistingRandomDirectory(temp.Path));
+ }
+ }
+
+ [Theory,
+ InlineData(IsolatedStorageScope.Assembly),
+ InlineData(IsolatedStorageScope.Assembly | IsolatedStorageScope.Roaming),
+ InlineData(IsolatedStorageScope.User)
+ ]
+ public void GetRandomDirectoryWithNotExistingDir(IsolatedStorageScope scope)
+ {
+ using (var temp = new TempDirectory())
+ {
+ Assert.Null(Helper.GetExistingRandomDirectory(temp.Path));
+ Assert.Equal(Helper.GetRandomDirectory(Helper.GetDataDirectory(scope), scope), Helper.GetDataDirectory(scope));
+ }
+ }
+
+ [Fact]
+ public void GetUserStoreForApplicationPath()
+ {
+ TestHelper.WipeStores();
+
+ using (var isf = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ string root = isf.GetUserRootDirectory();
+ Assert.EndsWith("/.config/.isolated-storage", root);
+ }
+ }
+
+ [Fact]
+ public void GetUserStoreForAssemblyPath()
+ {
+ TestHelper.WipeStores();
+
+ using (var isf = IsolatedStorageFile.GetUserStoreForAssembly())
+ {
+ string root = isf.GetUserRootDirectory();
+ Assert.EndsWith("/.config/.isolated-storage", root);
+ }
+ }
+
+ [Fact]
+ public void GetUserStoreForDomainPath()
+ {
+ TestHelper.WipeStores();
+
+ using (var isf = IsolatedStorageFile.GetUserStoreForDomain())
+ {
+ string root = isf.GetUserRootDirectory();
+ Assert.EndsWith("/.config/.isolated-storage", root);
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+
+namespace System.IO.IsolatedStorage
+{
+ public partial class HelperTests
+ {
+ [Theory,
+ InlineData(IsolatedStorageScope.User),
+ InlineData(IsolatedStorageScope.Machine),
+ ]
+ public void GetRandomDirectory(IsolatedStorageScope scope)
+ {
+ using (var temp = new TempDirectory())
+ {
+ string randomDir = Helper.GetRandomDirectory(temp.Path, scope);
+ Assert.True(Directory.Exists(randomDir));
+ }
+ }
+ }
+}
Assert.Equal(randomPath, Helper.GetExistingRandomDirectory(temp.Path));
}
}
-
- [Theory,
- InlineData(IsolatedStorageScope.User),
- InlineData(IsolatedStorageScope.Machine),
- ]
- public void GetRandomDirectory(IsolatedStorageScope scope)
- {
- using (var temp = new TempDirectory())
- {
- string randomDir = Helper.GetRandomDirectory(temp.Path, scope);
- Assert.True(Directory.Exists(randomDir));
- }
- }
}
}
string randomUserRoot = Helper.GetRandomDirectory(userRoot, IsolatedStorageScope.User);
roots.Add(randomUserRoot);
- // Application scope doesn't go under a random dir
- roots.Add(userRoot);
return roots;
}
+
+ /// <summary>
+ /// The actual root of the store (housekeeping files are kept here in NetFX)
+ /// </summary>
+ public static string GetIdentityRootDirectory(this IsolatedStorageFile isf)
+ {
+ return isf.GetUserRootDirectory();
+ }
}
}
return roots;
}
+
+ /// <summary>
+ /// The actual root of the store (housekeeping files are kept here in NetFX)
+ /// </summary>
+ public static string GetIdentityRootDirectory(this IsolatedStorageFile isf)
+ {
+ return Path.GetDirectoryName(isf.GetUserRootDirectory().TrimEnd(Path.DirectorySeparatorChar));
+ }
}
}
\ No newline at end of file
return (string)s_rootDirectoryProperty.GetValue(isf);
}
- /// <summary>
- /// The actual root of the store (housekeeping files are kept here in NetFX)
- /// </summary>
- public static string GetIdentityRootDirectory(this IsolatedStorageFile isf)
- {
- return Path.GetDirectoryName(isf.GetUserRootDirectory().TrimEnd(Path.DirectorySeparatorChar));
- }
/// <summary>
/// Simple wrapper to create the given file (and close the handle)