Files
FileTime2/src/Tools/FileTime.Tools.VirtualDiskSources/VirtualDiskSubContentProvider.cs
2023-09-15 21:46:17 +02:00

246 lines
8.2 KiB
C#

using System.Collections.ObjectModel;
using DiscUtils;
using DiscUtils.Udf;
using FileTime.Core.ContentAccess;
using FileTime.Core.Enums;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
namespace FileTime.Tools.VirtualDiskSources;
public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
{
private readonly IContentAccessorFactory _contentAccessorFactory;
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IVirtualDiskContentProviderFactory _virtualDiskContentProviderFactory;
public VirtualDiskSubContentProvider(
IContentAccessorFactory contentAccessorFactory,
ITimelessContentProvider timelessContentProvider,
IVirtualDiskContentProviderFactory virtualDiskContentProviderFactory
)
{
_contentAccessorFactory = contentAccessorFactory;
_timelessContentProvider = timelessContentProvider;
_virtualDiskContentProviderFactory = virtualDiskContentProviderFactory;
}
public Task<bool> CanHandleAsync(IElement parentElement)
=> Task.FromResult(parentElement.NativePath?.Path.EndsWith(".iso", StringComparison.OrdinalIgnoreCase) ?? false);
public async Task<IItem?> GetItemByFullNameAsync(
IElement parentElement,
FullName itemPath,
PointInTime pointInTime,
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default)
{
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
await using var readerStream = reader.GetStream();
var discReader = new UdfReader(readerStream);
if (itemPath.Path.Length == 0 || itemPath.Path == Constants.SubContentProviderRootContainer)
{
var rootFullNameBase = parentElement.FullName!.Path + Constants.SeparatorChar + Constants.SubContentProviderRootContainer;
var rootNativePathBase = parentElement.NativePath!.Path + Constants.SeparatorChar + Constants.SubContentProviderRootContainer;
var rootFullName = new FullName(rootFullNameBase);
var rootNativePath = new NativePath(rootNativePathBase);
var container = CreateContainer(
discReader,
discReader.Root,
rootFullName,
rootNativePath,
parentElement.Provider,
parentElement.Parent!,
parentElement.PointInTime,
itemInitializationSettings);
return container;
}
return ResolveNonRootChild(discReader, parentElement, itemPath, pointInTime, itemInitializationSettings);
}
private IItem? ResolveNonRootChild(
UdfReader discReader,
IElement parentElement,
FullName itemPath,
PointInTime pointInTime,
ItemInitializationSettings itemInitializationSettings = default)
{
var pathParts = itemPath.Path.Split(Constants.SeparatorChar);
var childFullNameBase = parentElement.FullName!.Path + Constants.SeparatorChar + itemPath.Path;
var childNativePathBase = parentElement.NativePath!.Path + Constants.SeparatorChar + itemPath.Path;
var childFullName = new FullName(childFullNameBase);
var childNativePath = new NativePath(childNativePathBase);
var parent = new AbsolutePath(
_timelessContentProvider,
pointInTime,
childFullName.GetParent()!,
AbsolutePathType.Container
);
var container = discReader.Root;
for (var i = 1; i < pathParts.Length - 1; i++)
{
if (container is null) break;
container = container.GetDirectories().FirstOrDefault(d => d.Name == pathParts[i]);
}
if (container is null) return null;
if (container.GetDirectories().FirstOrDefault(d => d.Name == pathParts[^1]) is { } childContainer)
{
return CreateContainer(
discReader,
childContainer,
childFullName,
childNativePath,
parentElement.Provider,
parent,
pointInTime,
itemInitializationSettings
);
}
if (container.GetFiles().FirstOrDefault(d => d.Name == pathParts[^1]) is not { } childElement)
{
return null;
}
var element = CreateElement(
childElement,
childFullName,
childNativePath,
parentElement.Provider,
parent,
pointInTime
);
discReader.Dispose();
return element;
}
private IContainer CreateContainer(
UdfReader discReader,
DiscDirectoryInfo sourceContainer,
FullName fullName,
NativePath nativePath,
IContentProvider parentContentProvider,
AbsolutePath parent,
PointInTime pointInTime,
ItemInitializationSettings initializationSettings)
{
var children = new ObservableCollection<AbsolutePath>();
var exceptions = new ObservableCollection<Exception>();
var container = new Container(
sourceContainer.Name,
sourceContainer.Name,
fullName,
nativePath,
parent,
true,
true,
sourceContainer.CreationTime,
sourceContainer.LastWriteTime,
SupportsDelete.False,
false,
FormatAttributes(sourceContainer.Attributes),
_virtualDiskContentProviderFactory.Create(parentContentProvider),
false,
pointInTime,
exceptions,
new ReadOnlyExtensionCollection(new ExtensionCollection()),
children
);
if (!initializationSettings.SkipChildInitialization)
{
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
container.StartLoading();
LoadChildren(container, sourceContainer, children, pointInTime, exceptions);
}
finally
{
discReader.Dispose();
container.StopLoading();
}
});
}
return container;
}
private void LoadChildren(
Container container,
DiscDirectoryInfo sourceContainer,
ObservableCollection<AbsolutePath> children,
PointInTime pointInTime,
ObservableCollection<Exception> exceptions
)
{
foreach (var discDirectoryInfo in sourceContainer.GetDirectories())
{
children.Add(new AbsolutePath(
_timelessContentProvider,
pointInTime,
container.FullName.GetChild(discDirectoryInfo.Name),
AbsolutePathType.Container)
);
}
foreach (var fileInfo in sourceContainer.GetFiles())
{
children.Add(new AbsolutePath(
_timelessContentProvider,
pointInTime,
container.FullName.GetChild(fileInfo.Name),
AbsolutePathType.Element)
);
}
}
private IElement CreateElement(DiscFileInfo childElement,
FullName fullname,
NativePath nativePath,
IContentProvider parentContentProvider,
AbsolutePath parent,
PointInTime pointInTime)
{
var element = new Element(
childElement.Name,
childElement.Name,
fullname,
nativePath,
parent,
true,
true,
childElement.CreationTime,
childElement.LastWriteTime,
SupportsDelete.False,
false,
FormatAttributes(childElement.Attributes),
childElement.Length,
_virtualDiskContentProviderFactory.Create(parentContentProvider),
pointInTime,
new ObservableCollection<Exception>(),
new ReadOnlyExtensionCollection(new ExtensionCollection())
);
return element;
}
private string FormatAttributes(FileAttributes attributes)
{
return "";
}
}