Copy from ISO
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>FileTime.Tools.VirtualDiskSources</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public interface IVirtualDiskContentProvider : IContentProvider
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public interface IVirtualDiskContentProviderFactory
|
||||
{
|
||||
IVirtualDiskContentProvider Create(IContentProvider parentContentProvider);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources.Abstractions;
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public interface IVirtualDiskSubContentProvider : ISubContentProvider
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Tools.VirtualDiskSources.Abstractions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
@@ -13,6 +12,8 @@ public static class Startup
|
||||
services.TryAddSingleton<IVirtualDiskSubContentProvider, VirtualDiskSubContentProvider>();
|
||||
services.AddSingleton<ISubContentProvider>(sp => sp.GetRequiredService<IVirtualDiskSubContentProvider>());
|
||||
services.AddSingleton<IPreStartupHandler, DiscUtilsInitializer>();
|
||||
services.TryAddSingleton<IVirtualDiskContentProviderFactory, VirtualDiskContentProviderFactory>();
|
||||
services.TryAddSingleton<IContentReaderFactory<VirtualDiskContentProvider>, VirtualDiskContentReaderFactory>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,50 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using DiscUtils.Udf;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentProvider : SubContentProviderBase
|
||||
public class VirtualDiskContentProvider : SubContentProviderBase, IVirtualDiskContentProvider
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
|
||||
public VirtualDiskContentProvider(
|
||||
IContentProvider parentContentProvider,
|
||||
ITimelessContentProvider timelessContentProvider)
|
||||
IContentProvider parentContentProvider,
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
: base(parentContentProvider, "virtual-disk", timelessContentProvider)
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var elementNativePath = element.NativePath!;
|
||||
|
||||
var supportedPath = await ParentContentProvider.GetSupportedPathPart(elementNativePath);
|
||||
if (supportedPath is null) return null;
|
||||
|
||||
var parentItem = await ParentContentProvider.GetItemByNativePathAsync(supportedPath, element.PointInTime);
|
||||
if (parentItem is not IElement parentElement) return null;
|
||||
|
||||
|
||||
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
|
||||
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
|
||||
|
||||
await using var readerStream = reader.AsStream();
|
||||
using var discReader = new UdfReader(readerStream);
|
||||
|
||||
var subPath = elementNativePath.Path.Substring(supportedPath.Path.Length + 2 + Constants.SubContentProviderRootContainer.Length);
|
||||
var fileInfo = discReader.GetFileInfo(subPath);
|
||||
|
||||
await using var contentReader = fileInfo.Open(FileMode.Open, FileAccess.Read);
|
||||
var data = new byte[1024 * 1024];
|
||||
var readAsync = await contentReader.ReadAsync(data, cancellationToken);
|
||||
|
||||
return data[0..readAsync].ToArray();
|
||||
}
|
||||
|
||||
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path)
|
||||
=> ParentContentProvider.GetVolumeSizeInfo(path);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentProviderFactory : IVirtualDiskContentProviderFactory
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
|
||||
public VirtualDiskContentProviderFactory(
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public IVirtualDiskContentProvider Create(IContentProvider parentContentProvider)
|
||||
=> new VirtualDiskContentProvider(parentContentProvider, _timelessContentProvider, _contentAccessorFactory);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentReader : IContentReader
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
private readonly ICollection<IDisposable> _disposables;
|
||||
public int PreferredBufferSize => 1024 * 1024;
|
||||
public long? Position => _stream.Position;
|
||||
|
||||
public VirtualDiskContentReader(Stream stream, ICollection<IDisposable> disposables)
|
||||
{
|
||||
_stream = stream;
|
||||
_disposables = disposables;
|
||||
}
|
||||
|
||||
public async Task<byte[]> ReadBytesAsync(int bufferSize, int? offset = null)
|
||||
{
|
||||
var data = new byte[bufferSize];
|
||||
var read = await _stream.ReadAsync(data, offset ?? 0, bufferSize);
|
||||
|
||||
return data[..read].ToArray();
|
||||
}
|
||||
|
||||
public void SetPosition(long position) => _stream.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
public Stream AsStream() => _stream;
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_stream.Dispose();
|
||||
foreach (var disposable in _disposables)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using DiscUtils.Udf;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
public class VirtualDiskContentReaderFactory : IContentReaderFactory<VirtualDiskContentProvider>
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
|
||||
public VirtualDiskContentReaderFactory(IContentAccessorFactory contentAccessorFactory)
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public async Task<IContentReader> CreateContentReaderAsync(IElement element)
|
||||
{
|
||||
if (element.Provider is not VirtualDiskContentProvider provider)
|
||||
throw new ArgumentException(
|
||||
"Provider must be VirtualDiskContentProvider, but it is " + element.Provider.GetType(),
|
||||
nameof(element));
|
||||
|
||||
var elementNativePath = element.NativePath!;
|
||||
|
||||
var supportedPath = (await provider.ParentContentProvider.GetSupportedPathPart(elementNativePath))!;
|
||||
|
||||
var parentElement = (IElement) await provider.ParentContentProvider.GetItemByNativePathAsync(supportedPath, element.PointInTime);
|
||||
|
||||
|
||||
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
|
||||
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
|
||||
|
||||
var readerStream = reader.AsStream();
|
||||
var discReader = new UdfReader(readerStream);
|
||||
|
||||
var subPath = elementNativePath.Path.Substring(supportedPath.Path.Length + 2 + Constants.SubContentProviderRootContainer.Length);
|
||||
var fileInfo = discReader.GetFileInfo(subPath);
|
||||
|
||||
var contentReader = fileInfo.Open(FileMode.Open, FileAccess.Read);
|
||||
|
||||
return new VirtualDiskContentReader(contentReader, new IDisposable[] {discReader, readerStream, contentReader});
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using DiscUtils;
|
||||
using DiscUtils.Iso9660;
|
||||
using DiscUtils.Udf;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
using FileTime.Tools.VirtualDiskSources.Abstractions;
|
||||
|
||||
namespace FileTime.Tools.VirtualDiskSources;
|
||||
|
||||
@@ -14,14 +12,17 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IVirtualDiskContentProviderFactory _virtualDiskContentProviderFactory;
|
||||
|
||||
public VirtualDiskSubContentProvider(
|
||||
IContentAccessorFactory contentAccessorFactory,
|
||||
ITimelessContentProvider timelessContentProvider
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IVirtualDiskContentProviderFactory virtualDiskContentProviderFactory
|
||||
)
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_virtualDiskContentProviderFactory = virtualDiskContentProviderFactory;
|
||||
}
|
||||
|
||||
public Task<bool> CanHandleAsync(IElement parentElement)
|
||||
@@ -36,7 +37,7 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
{
|
||||
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
|
||||
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
|
||||
|
||||
|
||||
await using var readerStream = reader.AsStream();
|
||||
var discReader = new UdfReader(readerStream);
|
||||
|
||||
@@ -48,15 +49,18 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
var rootFullName = new FullName(rootFullNameBase);
|
||||
var rootNativePath = new NativePath(rootNativePathBase);
|
||||
|
||||
return CreateContainer(discReader.Root,
|
||||
var container = CreateContainer(
|
||||
discReader,
|
||||
discReader.Root,
|
||||
rootFullName,
|
||||
rootNativePath,
|
||||
parentElement.Provider,
|
||||
parentElement.Parent!,
|
||||
parentElement.PointInTime,
|
||||
itemInitializationSettings);
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
return ResolveNonRootChild(discReader, parentElement, itemPath, pointInTime, itemInitializationSettings);
|
||||
}
|
||||
|
||||
@@ -74,7 +78,7 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
|
||||
var childFullName = new FullName(childFullNameBase);
|
||||
var childNativePath = new NativePath(childNativePathBase);
|
||||
|
||||
|
||||
var parent = new AbsolutePath(_timelessContentProvider, pointInTime, childFullName.GetParent()!, AbsolutePathType.Container);
|
||||
|
||||
var container = discReader.Root;
|
||||
@@ -89,6 +93,7 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
if (container.GetDirectories().FirstOrDefault(d => d.Name == pathParts[^1]) is { } childContainer)
|
||||
{
|
||||
return CreateContainer(
|
||||
discReader,
|
||||
childContainer,
|
||||
childFullName,
|
||||
childNativePath,
|
||||
@@ -99,22 +104,26 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
);
|
||||
}
|
||||
|
||||
if (container.GetFiles().FirstOrDefault(d => d.Name == pathParts[^1]) is { } childElement)
|
||||
if (container.GetFiles().FirstOrDefault(d => d.Name == pathParts[^1]) is not { } childElement)
|
||||
{
|
||||
return CreateElement(
|
||||
childElement,
|
||||
childFullName,
|
||||
childNativePath,
|
||||
parentElement.Provider,
|
||||
parent,
|
||||
pointInTime
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -138,7 +147,7 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
SupportsDelete.False,
|
||||
false,
|
||||
FormatAttributes(sourceContainer.Attributes),
|
||||
new VirtualDiskContentProvider(parentContentProvider, _timelessContentProvider),
|
||||
_virtualDiskContentProviderFactory.Create(parentContentProvider),
|
||||
false,
|
||||
pointInTime,
|
||||
exceptions,
|
||||
@@ -148,7 +157,11 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
|
||||
if (!initializationSettings.SkipChildInitialization)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => LoadChildren(container, sourceContainer, children, pointInTime, exceptions));
|
||||
ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
LoadChildren(container, sourceContainer, children, pointInTime, exceptions);
|
||||
discReader.Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
return container;
|
||||
@@ -204,7 +217,7 @@ public class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider
|
||||
false,
|
||||
FormatAttributes(childElement.Attributes),
|
||||
childElement.Length,
|
||||
new VirtualDiskContentProvider(parentContentProvider, _timelessContentProvider),
|
||||
_virtualDiskContentProviderFactory.Create(parentContentProvider),
|
||||
pointInTime,
|
||||
new ObservableCollection<Exception>(),
|
||||
new ReadOnlyExtensionCollection(new ExtensionCollection())
|
||||
|
||||
Reference in New Issue
Block a user