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)
{