Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change IsolatedStorageFile path for mobile #83380

Merged
merged 15 commits into from
May 11, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
<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" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,57 @@ namespace System.IO.IsolatedStorage
{
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)
{
// This is the relevant special folder for the given scope plus IsolatedStorageDirectoryName.
// It is meant to replicate the behavior of the VM ComIsolatedStorage::GetRootDir().
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment isn't meaningful for us, I'd remove it.

//
// 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. .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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these example paths are from Android, I'd also add iOS examples to make it clearer

//
// 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
{
specialFolder =
IsMachine(scope) ? Environment.SpecialFolder.CommonApplicationData :
IsRoaming(scope) ? Environment.SpecialFolder.LocalApplicationData:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to change this case on Android since we had the breaking change of Environment.SpecialFolder.LocalApplicationData between Xamarin and dotnet:

Xamarin /data/user/0/com.companyname.testandroidxamarin/files/.local/share
dotnet /data/user/0/com.companyname.TestMauiNet7/files

You can use hardcoded SpecialFolder.UserProfile + ".local/share" for that when OperatingSystem.IsAndroid()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general I'd recommend creating a sample app that uses all possible combinations for IsolatedStorageFile scopes and then comparing each computed path between Xamarin and dotnet to make sure they match

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;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,68 @@
// 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));
}
}
}

This file was deleted.

Loading