From e2841b3fd4183c2d7031c15531490a26006a5dee Mon Sep 17 00:00:00 2001 From: LTRData Date: Tue, 12 Dec 2023 17:14:08 +0100 Subject: [PATCH] Optimized file streams for read-only file systems --- .../Internals/MasterFileTableEntry.cs | 2 +- Library/DiscUtils.Ntfs/NtfsFileStream.cs | 46 ++++++++++++++++--- Library/DiscUtils.Ntfs/NtfsFileSystem.cs | 7 ++- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Library/DiscUtils.Ntfs/Internals/MasterFileTableEntry.cs b/Library/DiscUtils.Ntfs/Internals/MasterFileTableEntry.cs index cceff29bc..e11180672 100644 --- a/Library/DiscUtils.Ntfs/Internals/MasterFileTableEntry.cs +++ b/Library/DiscUtils.Ntfs/Internals/MasterFileTableEntry.cs @@ -193,7 +193,7 @@ public SparseStream Open(IAttributeLocator attr, FileAccess access) return null; } - return new NtfsFileStream(File, directoryEntry.Value, attr.AttributeType, attr.Identifier, access); + return NtfsFileStream.Open(File, directoryEntry.Value, attr.AttributeType, attr.Identifier, access); } public IEnumerable> GetClusters(IAttributeLocator attr) => diff --git a/Library/DiscUtils.Ntfs/NtfsFileStream.cs b/Library/DiscUtils.Ntfs/NtfsFileStream.cs index 84a708630..3420589fb 100644 --- a/Library/DiscUtils.Ntfs/NtfsFileStream.cs +++ b/Library/DiscUtils.Ntfs/NtfsFileStream.cs @@ -32,26 +32,60 @@ namespace DiscUtils.Ntfs; internal sealed class NtfsFileStream : SparseStream { private SparseStream _baseStream; + + public SparseStream BaseStream => _baseStream; + private readonly DirectoryEntry _entry; private readonly File _file; private bool _isDirty; - public NtfsFileStream(File file, DirectoryEntry entry, AttributeType attrType, string attrName, + public static SparseStream Open(File file, DirectoryEntry entry, AttributeType attrType, string attrName, FileAccess access) + { + var baseStream = file.OpenStream(attrType, attrName, access); + + if (baseStream is null) + { + return null; + } + + if (file.Context.ReadOnly) + { + return baseStream; + } + else + { + return new NtfsFileStream(entry, file, baseStream); + } + } + + private NtfsFileStream(DirectoryEntry entry, File file, SparseStream baseStream) { _entry = entry; _file = file; - _baseStream = _file.OpenStream(attrType, attrName, access); + _baseStream = baseStream; } - public NtfsFileStream(File file, DirectoryEntry entry, AttributeType attrType, ushort attrId, + public static SparseStream Open(File file, DirectoryEntry entry, AttributeType attrType, ushort attrId, FileAccess access) { - _entry = entry; - _file = file; - _baseStream = _file.OpenStream(attrId, attrType, access); + var baseStream = file.OpenStream(attrId, attrType, access); + + if (baseStream is null) + { + return null; + } + + if (file.Context.ReadOnly) + { + return baseStream; + } + else + { + return new NtfsFileStream(entry, file, baseStream); + } } public override bool CanRead diff --git a/Library/DiscUtils.Ntfs/NtfsFileSystem.cs b/Library/DiscUtils.Ntfs/NtfsFileSystem.cs index fb66615c7..e0b168327 100644 --- a/Library/DiscUtils.Ntfs/NtfsFileSystem.cs +++ b/Library/DiscUtils.Ntfs/NtfsFileSystem.cs @@ -2055,7 +2055,12 @@ public SparseStream OpenFile(string path, FileMode mode, FileAccess access, NewF } } - var stream = new NtfsFileStream(file, entry.Value, attributeType, attributeName, access); + var stream = NtfsFileStream.Open(file, entry.Value, attributeType, attributeName, access); + + if (stream is null) + { + throw new InvalidFileSystemException("File system corrupt"); + } if (mode is FileMode.Create or FileMode.Truncate) {