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

Create shadow file systems in configured LocalTempPath #15637

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 19 additions & 19 deletions src/Umbraco.Core/IO/ShadowWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ namespace Umbraco.Cms.Core.IO;

internal class ShadowWrapper : IFileSystem, IFileProviderFactory
{
private static readonly string ShadowFsPath = Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs";
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IIOHelper _ioHelper;
private const string ShadowFsPath = "ShadowFs";

private readonly Func<bool?>? _isScoped;
private readonly IIOHelper _ioHelper;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ILoggerFactory _loggerFactory;
private readonly string _shadowPath;
private readonly Func<bool?>? _isScoped;

private string? _shadowDir;
private ShadowFileSystem? _shadowFileSystem;

public ShadowWrapper(IFileSystem innerFileSystem, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory, string shadowPath, Func<bool?>? isScoped = null)
{
InnerFileSystem = innerFileSystem;

_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_loggerFactory = loggerFactory;
Expand All @@ -35,18 +37,19 @@ private IFileSystem FileSystem
{
get
{
if (_isScoped is not null && _shadowFileSystem is not null)
Func<bool?>? isScoped = _isScoped;
if (isScoped is not null && _shadowFileSystem is not null)
{
var isScoped = _isScoped!();
bool? scoped = isScoped();

// if the filesystem is created *after* shadowing starts, it won't be shadowing
// better not ignore that situation and raised a meaningful (?) exception
if (isScoped.HasValue && isScoped.Value && _shadowFileSystem == null)
// better not ignore that situation and raise a meaningful (?) exception
if (scoped.HasValue && scoped.Value && _shadowFileSystem == null)
{
throw new Exception("The filesystems are shadowing, but this filesystem is not.");
}

return isScoped.HasValue && isScoped.Value
return scoped.HasValue && scoped.Value
? _shadowFileSystem
: InnerFileSystem;
}
Expand All @@ -56,8 +59,7 @@ private IFileSystem FileSystem
}

/// <inheritdoc />
public IFileProvider? Create() =>
InnerFileSystem.TryCreateFileProvider(out IFileProvider? fileProvider) ? fileProvider : null;
public IFileProvider? Create() => InnerFileSystem.TryCreateFileProvider(out IFileProvider? fileProvider) ? fileProvider : null;

public IEnumerable<string> GetDirectories(string path) => FileSystem.GetDirectories(path);

Expand All @@ -69,8 +71,7 @@ private IFileSystem FileSystem

public void AddFile(string path, Stream stream) => FileSystem.AddFile(path, stream);

public void AddFile(string path, Stream stream, bool overrideExisting) =>
FileSystem.AddFile(path, stream, overrideExisting);
public void AddFile(string path, Stream stream, bool overrideExisting) => FileSystem.AddFile(path, stream, overrideExisting);

public IEnumerable<string> GetFiles(string path) => FileSystem.GetFiles(path);

Expand Down Expand Up @@ -107,8 +108,7 @@ public static string CreateShadowId(IHostingEnvironment hostingEnvironment)
{
var id = GuidUtils.ToBase32String(Guid.NewGuid(), idLength);

var virt = ShadowFsPath + "/" + id;
var shadowDir = hostingEnvironment.MapPathContentRoot(virt);
var shadowDir = Path.Combine(hostingEnvironment.LocalTempPath, ShadowFsPath, id);
if (Directory.Exists(shadowDir))
{
continue;
Expand All @@ -129,10 +129,10 @@ internal void Shadow(string id)
// note: no thread-safety here, because ShadowFs is thread-safe due to the check
// on ShadowFileSystemsScope.None - and if None is false then we should be running
// in a single thread anyways
var virt = Path.Combine(ShadowFsPath, id, _shadowPath);
_shadowDir = _hostingEnvironment.MapPathContentRoot(virt);
var rootUrl = Path.Combine(ShadowFsPath, id, _shadowPath);
_shadowDir = Path.Combine(_hostingEnvironment.LocalTempPath, rootUrl);
Directory.CreateDirectory(_shadowDir);
var tempfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _loggerFactory.CreateLogger<PhysicalFileSystem>(), _shadowDir, _hostingEnvironment.ToAbsolute(virt));
var tempfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _loggerFactory.CreateLogger<PhysicalFileSystem>(), _shadowDir, rootUrl);
_shadowFileSystem = new ShadowFileSystem(InnerFileSystem, tempfs);
}

Expand Down Expand Up @@ -160,7 +160,7 @@ internal void UnShadow(bool complete)

// shadowPath make be path/to/dir, remove each
dir = dir!.Replace('/', Path.DirectorySeparatorChar);
var min = _hostingEnvironment.MapPathContentRoot(ShadowFsPath).Length;
var min = Path.Combine(_hostingEnvironment.LocalTempPath, ShadowFsPath).Length;
var pos = dir.LastIndexOf(Path.DirectorySeparatorChar);
while (pos > min)
{
Expand Down