From 752815bb2ee8cd90ff9fa85da2eaa3df5523a930 Mon Sep 17 00:00:00 2001 From: LTRData Date: Fri, 24 May 2024 18:05:35 +0200 Subject: [PATCH] Optimizations and fixes * HashStreamCore had issues on net46, backported new implementation instead * Fixed some Span empty checks that had mistakenly been compares to null * More use of new ArgumentNullException.ThrowIfNull etc, where possible * Test cases modified to test with correct path separator for running platform * Some test case helper methods moved to the common Helpers class --- .../DiscUtilsRegistryStorage.cs | 25 ++-- .../Compression/BZip2DecoderStream.cs | 4 + .../DiscUtils.Core/Compression/ZlibStream.cs | 4 + Library/DiscUtils.Core/DiscFileSystemInfo.cs | 4 + .../Partitions/BiosPartitionedDiskBuilder.cs | 8 ++ .../AccessControl/GenericAce.cs | 5 +- .../GenericSecurityDescriptor.cs | 4 + .../AccessControl/ObjectAce.cs | 9 +- .../WindowsSecurity/AccessControl/RawAcl.cs | 6 +- .../AccessControl/RawSecurityDescriptor.cs | 4 + .../WindowsSecurity/NTAccount.cs | 8 ++ Library/DiscUtils.Fat/FatFileSystem.cs | 4 + Library/DiscUtils.Fat/FileName.cs | 4 + Library/DiscUtils.HfsPlus/AttributeKey.cs | 4 + Library/DiscUtils.HfsPlus/CatalogKey.cs | 4 + Library/DiscUtils.HfsPlus/Directory.cs | 4 + Library/DiscUtils.HfsPlus/ExtentKey.cs | 4 + Library/DiscUtils.Registry/RegistryKey.cs | 7 ++ .../SquashFileSystemBuilder.cs | 4 + .../Builder/StreamBuilder.cs | 16 +-- Library/DiscUtils.Streams/BuiltStream.cs | 12 +- Library/DiscUtils.Streams/StreamBuffer.cs | 4 + .../Util/CompatExtensions.cs | 11 ++ .../DiscUtils.Streams/Util/StreamUtilities.cs | 9 +- Library/DiscUtils.Vhd/DynamicStream.cs | 36 +++--- .../VirtualFileSystemDirectoryEntry.cs | 19 ++- Library/DiscUtils.Xva/HashStreamCore.cs | 119 ------------------ .../DiscUtils.Xva/VirtualMachineBuilder.cs | 67 ++-------- Tests/LibraryTests/Btrfs/SampleDataTests.cs | 50 ++------ Tests/LibraryTests/Helpers/Helpers.cs | 42 ++++++- Tests/LibraryTests/Xfs/SampleDataTests.cs | 21 ++-- 31 files changed, 237 insertions(+), 285 deletions(-) diff --git a/Library/DiscUtils.BootConfig/DiscUtilsRegistryStorage.cs b/Library/DiscUtils.BootConfig/DiscUtilsRegistryStorage.cs index 4f51abdf0..e499addd6 100644 --- a/Library/DiscUtils.BootConfig/DiscUtilsRegistryStorage.cs +++ b/Library/DiscUtils.BootConfig/DiscUtilsRegistryStorage.cs @@ -29,11 +29,6 @@ namespace DiscUtils.BootConfig; internal class DiscUtilsRegistryStorage : BaseStorage { - private const string ElementsPathTemplate = @"Objects\{0}\Elements"; - private const string ElementPathTemplate = @"Objects\{0}\Elements\{1:X8}"; - private const string ObjectTypePathTemplate = @"Objects\{0}\Description"; - //private const string ObjectsPath = @"Objects"; - private readonly RegistryKey _rootKey; public DiscUtilsRegistryStorage(RegistryKey key) @@ -82,7 +77,7 @@ public override IEnumerable EnumerateObjects() public override IEnumerable EnumerateElements(Guid obj) { - var path = string.Format(CultureInfo.InvariantCulture, ElementsPathTemplate, obj.ToString("B")); + var path = $@"Objects\{obj:B}\Elements"; var parentKey = _rootKey.OpenSubKey(path); foreach (var key in parentKey.GetSubKeyNames()) { @@ -92,7 +87,7 @@ public override IEnumerable EnumerateElements(Guid obj) public override int GetObjectType(Guid obj) { - var path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, obj.ToString("B")); + var path = $@"Objects\{obj:B}\Description"; var descKey = _rootKey.OpenSubKey(path); @@ -102,13 +97,13 @@ public override int GetObjectType(Guid obj) public override bool HasValue(Guid obj, int element) { - var path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element); + var path = $@"Objects\{obj:B}\Elements\{element:X8}"; return _rootKey.OpenSubKey(path) != null; } public override bool ObjectExists(Guid obj) { - var path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, obj.ToString("B")); + var path = $@"Objects\{obj:B}\Description"; return _rootKey.OpenSubKey(path) != null; } @@ -116,7 +111,7 @@ public override bool ObjectExists(Guid obj) public override Guid CreateObject(Guid obj, int type) { var realObj = obj == Guid.Empty ? Guid.NewGuid() : obj; - var path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, realObj.ToString("B")); + var path = $@"Objects\{realObj:B}\Description"; var key = _rootKey.CreateSubKey(path); key.SetValue("Type", type, RegistryValueType.Dword); @@ -126,35 +121,35 @@ public override Guid CreateObject(Guid obj, int type) public override void CreateElement(Guid obj, int element) { - var path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element); + var path = $@"Objects\{obj:B}\Elements\{element:X8}"; _rootKey.CreateSubKey(path); } public override void DeleteObject(Guid obj) { - var path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, obj.ToString("B")); + var path = $@"Objects\{obj:B}\Description"; _rootKey.DeleteSubKeyTree(path); } public override void DeleteElement(Guid obj, int element) { - var path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element); + var path = $@"Objects\{obj:B}\Elements\{element:X8}"; _rootKey.DeleteSubKeyTree(path); } private object GetValue(Guid obj, int element) { - var path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element); + var path = $@"Objects\{obj:B}\Elements\{element:X8}"; var key = _rootKey.OpenSubKey(path); return key.GetValue("Element"); } private void SetValue(Guid obj, int element, object value) { - var path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element); + var path = $@"Objects\{obj:B}\Elements\{element:X8}"; var key = _rootKey.OpenSubKey(path); key.SetValue("Element", value); } diff --git a/Library/DiscUtils.Core/Compression/BZip2DecoderStream.cs b/Library/DiscUtils.Core/Compression/BZip2DecoderStream.cs index 37877e634..235386a30 100644 --- a/Library/DiscUtils.Core/Compression/BZip2DecoderStream.cs +++ b/Library/DiscUtils.Core/Compression/BZip2DecoderStream.cs @@ -128,10 +128,14 @@ public override long Position /// The number of bytes read. public override int Read(byte[] buffer, int offset, int count) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(buffer); +#else if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } +#endif return Read(buffer.AsSpan(offset, count)); } diff --git a/Library/DiscUtils.Core/Compression/ZlibStream.cs b/Library/DiscUtils.Core/Compression/ZlibStream.cs index 4e20129d9..1d0052578 100644 --- a/Library/DiscUtils.Core/Compression/ZlibStream.cs +++ b/Library/DiscUtils.Core/Compression/ZlibStream.cs @@ -281,10 +281,14 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati private static void CheckParams(byte[] buffer, int offset, int count) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(buffer); +#else if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } +#endif if (offset < 0 || offset > buffer.Length) { diff --git a/Library/DiscUtils.Core/DiscFileSystemInfo.cs b/Library/DiscUtils.Core/DiscFileSystemInfo.cs index 83d50cd2f..bc57079a4 100644 --- a/Library/DiscUtils.Core/DiscFileSystemInfo.cs +++ b/Library/DiscUtils.Core/DiscFileSystemInfo.cs @@ -34,10 +34,14 @@ public class DiscFileSystemInfo { internal DiscFileSystemInfo(DiscFileSystem fileSystem, string path) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(path); +#else if (path == null) { throw new ArgumentNullException(nameof(path)); } +#endif var wrongPathSep = System.IO.Path.DirectorySeparatorChar == '\\' ? '/' : '\\'; diff --git a/Library/DiscUtils.Core/Partitions/BiosPartitionedDiskBuilder.cs b/Library/DiscUtils.Core/Partitions/BiosPartitionedDiskBuilder.cs index cf1c99c25..10c586623 100644 --- a/Library/DiscUtils.Core/Partitions/BiosPartitionedDiskBuilder.cs +++ b/Library/DiscUtils.Core/Partitions/BiosPartitionedDiskBuilder.cs @@ -71,10 +71,14 @@ public BiosPartitionedDiskBuilder(long capacity, Geometry biosGeometry) )] public BiosPartitionedDiskBuilder(long capacity, byte[] bootSectors, Geometry biosGeometry) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(bootSectors); +#else if (bootSectors == null) { throw new ArgumentNullException(nameof(bootSectors)); } +#endif _capacity = capacity; _biosGeometry = biosGeometry; @@ -94,10 +98,14 @@ public BiosPartitionedDiskBuilder(long capacity, byte[] bootSectors, Geometry bi /// The disk to clone. public BiosPartitionedDiskBuilder(VirtualDisk sourceDisk) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(sourceDisk); +#else if (sourceDisk == null) { throw new ArgumentNullException(nameof(sourceDisk)); } +#endif _capacity = sourceDisk.Capacity; _biosGeometry = sourceDisk.BiosGeometry; diff --git a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericAce.cs b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericAce.cs index b7397d614..420f0cda6 100644 --- a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericAce.cs +++ b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericAce.cs @@ -3,6 +3,7 @@ using LTRData.Extensions.Split; using System; using System.Globalization; +using System.IO; using System.Linq; using System.Text; @@ -117,7 +118,7 @@ public static bool TryCreateFromBinaryForm(byte[] binaryForm, int offset, out Ge public static GenericAce CreateFromBinaryForm(ReadOnlySpan binaryForm) { - if (binaryForm == null) + if (binaryForm.IsEmpty) { throw new ArgumentNullException(nameof(binaryForm)); } @@ -142,7 +143,7 @@ public static bool TryCreateFromBinaryForm(ReadOnlySpan binaryForm, out Ge { genericAce = null; - if (binaryForm == null || 1 > binaryForm.Length) + if (binaryForm.IsEmpty || 1 > binaryForm.Length) { return false; } diff --git a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericSecurityDescriptor.cs b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericSecurityDescriptor.cs index d11698951..b54d85e98 100644 --- a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericSecurityDescriptor.cs +++ b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/GenericSecurityDescriptor.cs @@ -51,10 +51,14 @@ public int BinaryLength public void GetBinaryForm(byte[] binaryForm, int offset) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(binaryForm); +#else if (null == binaryForm) { throw new ArgumentNullException(nameof(binaryForm)); } +#endif var binaryLength = BinaryLength; if (offset < 0 || offset > binaryForm.Length - binaryLength) diff --git a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/ObjectAce.cs b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/ObjectAce.cs index d9a47c024..955369169 100644 --- a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/ObjectAce.cs +++ b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/ObjectAce.cs @@ -195,14 +195,7 @@ internal override string GetSddlForm() inhObjType = _inheritedObjectType.ToString("D"); } - return string.Format(CultureInfo.InvariantCulture, - "({0};{1};{2};{3};{4};{5})", - GetSddlAceType(AceType), - GetSddlAceFlags(AceFlags), - GetSddlAccessRights(AccessMask), - objType, - inhObjType, - SecurityIdentifier.GetSddlForm()); + return $"({GetSddlAceType(AceType)};{GetSddlAceFlags(AceFlags)};{GetSddlAccessRights(AccessMask)};{objType};{inhObjType};{SecurityIdentifier.GetSddlForm()})"; } private static AceType ConvertType(AceQualifier qualifier, bool isCallback) diff --git a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawAcl.cs b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawAcl.cs index cba76aaac..66da3e9c5 100644 --- a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawAcl.cs +++ b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawAcl.cs @@ -27,7 +27,7 @@ public static bool TryParse(byte[] binaryForm, int offset, out RawAcl rawAcl) => public RawAcl(ReadOnlySpan binaryForm) { - if (binaryForm == null) + if (binaryForm.IsEmpty) { throw new ArgumentNullException(nameof(binaryForm)); } @@ -147,10 +147,14 @@ public override void GetBinaryForm(Span binaryForm) public void InsertAce(int index, GenericAce ace) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(ace); +#else if (ace == null) { throw new ArgumentNullException(nameof(ace)); } +#endif _list.Insert(index, ace); } diff --git a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawSecurityDescriptor.cs b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawSecurityDescriptor.cs index 71370d29c..4b78f7d4a 100644 --- a/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawSecurityDescriptor.cs +++ b/Library/DiscUtils.Core/WindowsSecurity/AccessControl/RawSecurityDescriptor.cs @@ -21,10 +21,14 @@ public class RawSecurityDescriptor : GenericSecurityDescriptor public RawSecurityDescriptor(string sddlForm) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(sddlForm); +#else if (sddlForm == null) { throw new ArgumentNullException(nameof(sddlForm)); } +#endif SetSddlForm(sddlForm.Replace(" ", "")); diff --git a/Library/DiscUtils.Core/WindowsSecurity/NTAccount.cs b/Library/DiscUtils.Core/WindowsSecurity/NTAccount.cs index c979d09cb..9f01586f2 100644 --- a/Library/DiscUtils.Core/WindowsSecurity/NTAccount.cs +++ b/Library/DiscUtils.Core/WindowsSecurity/NTAccount.cs @@ -8,6 +8,9 @@ public sealed class NTAccount : IdentityReference public NTAccount(string name) { +#if NET8_0_OR_GREATER + ArgumentException.ThrowIfNullOrWhiteSpace(name); +#else if (name == null) { throw new ArgumentNullException(nameof(name)); @@ -17,12 +20,16 @@ public NTAccount(string name) { throw new ArgumentException("empty", nameof(name)); } +#endif Value = name; } public NTAccount(string domainName, string accountName) { +#if NET8_0_OR_GREATER + ArgumentException.ThrowIfNullOrWhiteSpace(accountName); +#else if (accountName == null) { throw new ArgumentNullException(nameof(accountName)); @@ -32,6 +39,7 @@ public NTAccount(string domainName, string accountName) { throw new ArgumentException("empty", nameof(accountName)); } +#endif if (domainName == null) { diff --git a/Library/DiscUtils.Fat/FatFileSystem.cs b/Library/DiscUtils.Fat/FatFileSystem.cs index ed02a66e9..0fdf20f3d 100644 --- a/Library/DiscUtils.Fat/FatFileSystem.cs +++ b/Library/DiscUtils.Fat/FatFileSystem.cs @@ -1176,6 +1176,9 @@ public override IEnumerable GetFileSystemEntries(string path, string sea /// The target directory name. public override void MoveDirectory(string sourceDirectoryName, string destinationDirectoryName) { +#if NET8_0_OR_GREATER + ArgumentException.ThrowIfNullOrWhiteSpace(nameof(destinationDirectoryName)); +#else if (string.IsNullOrEmpty(destinationDirectoryName)) { if (destinationDirectoryName == null) @@ -1185,6 +1188,7 @@ public override void MoveDirectory(string sourceDirectoryName, string destinatio throw new ArgumentException("Invalid destination name (empty string)"); } +#endif var destId = GetDirectoryEntry(destinationDirectoryName, out var destParent); if (destParent == null) diff --git a/Library/DiscUtils.Fat/FileName.cs b/Library/DiscUtils.Fat/FileName.cs index e7a31a448..7152658ac 100644 --- a/Library/DiscUtils.Fat/FileName.cs +++ b/Library/DiscUtils.Fat/FileName.cs @@ -92,10 +92,14 @@ public FileName(ReadOnlySpan data) public FileName(string name, Encoding encoding) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(name); +#else if (name is null) { throw new ArgumentNullException(nameof(name)); } +#endif if (name.Length > 255) { diff --git a/Library/DiscUtils.HfsPlus/AttributeKey.cs b/Library/DiscUtils.HfsPlus/AttributeKey.cs index 16aaf9aee..284514e2b 100644 --- a/Library/DiscUtils.HfsPlus/AttributeKey.cs +++ b/Library/DiscUtils.HfsPlus/AttributeKey.cs @@ -68,10 +68,14 @@ public override int CompareTo(BTreeKey other) public int CompareTo(AttributeKey other) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(other); +#else if (other == null) { throw new ArgumentNullException(nameof(other)); } +#endif if (FileId != other.FileId) { diff --git a/Library/DiscUtils.HfsPlus/CatalogKey.cs b/Library/DiscUtils.HfsPlus/CatalogKey.cs index b393c8922..4683e931b 100644 --- a/Library/DiscUtils.HfsPlus/CatalogKey.cs +++ b/Library/DiscUtils.HfsPlus/CatalogKey.cs @@ -45,10 +45,14 @@ public CatalogKey(CatalogNodeId nodeId, string name) public int CompareTo(CatalogKey other) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(other); +#else if (other == null) { throw new ArgumentNullException(nameof(other)); } +#endif if (NodeId != other.NodeId) { diff --git a/Library/DiscUtils.HfsPlus/Directory.cs b/Library/DiscUtils.HfsPlus/Directory.cs index fcd4e8e50..54595927f 100644 --- a/Library/DiscUtils.HfsPlus/Directory.cs +++ b/Library/DiscUtils.HfsPlus/Directory.cs @@ -79,6 +79,9 @@ public DirEntry Self public DirEntry GetEntryByName(string name) { +#if NET8_0_OR_GREATER + ArgumentException.ThrowIfNullOrWhiteSpace(name); +#else if (name == null) { throw new ArgumentNullException(nameof(name)); @@ -88,6 +91,7 @@ public DirEntry GetEntryByName(string name) { throw new ArgumentException("Attempt to lookup empty file name", nameof(name)); } +#endif var dirEntryData = Context.Catalog.Find(new CatalogKey(NodeId, name)); if (dirEntryData == null) diff --git a/Library/DiscUtils.HfsPlus/ExtentKey.cs b/Library/DiscUtils.HfsPlus/ExtentKey.cs index 3ccf466d1..306d6d85a 100644 --- a/Library/DiscUtils.HfsPlus/ExtentKey.cs +++ b/Library/DiscUtils.HfsPlus/ExtentKey.cs @@ -47,10 +47,14 @@ public ExtentKey(CatalogNodeId cnid, uint startBlock, bool resource_fork = false public int CompareTo(ExtentKey other) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(other); +#else if (other == null) { throw new ArgumentNullException(nameof(other)); } +#endif // Sort by file id, fork type, then starting block if (NodeId != other.NodeId) diff --git a/Library/DiscUtils.Registry/RegistryKey.cs b/Library/DiscUtils.Registry/RegistryKey.cs index 0ca05efa4..878e359d6 100644 --- a/Library/DiscUtils.Registry/RegistryKey.cs +++ b/Library/DiscUtils.Registry/RegistryKey.cs @@ -48,8 +48,15 @@ public sealed class RegistryKey internal RegistryKey(RegistryHive hive, KeyNodeCell cell) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(hive); + ArgumentNullException.ThrowIfNull(cell); + _hive = hive; + _cell = cell; +#else _hive = hive ?? throw new ArgumentNullException(nameof(hive)); _cell = cell ?? throw new ArgumentNullException(nameof(cell)); +#endif } /// diff --git a/Library/DiscUtils.SquashFs/SquashFileSystemBuilder.cs b/Library/DiscUtils.SquashFs/SquashFileSystemBuilder.cs index a65c28418..87c4228a6 100644 --- a/Library/DiscUtils.SquashFs/SquashFileSystemBuilder.cs +++ b/Library/DiscUtils.SquashFs/SquashFileSystemBuilder.cs @@ -376,10 +376,14 @@ public override async Task BuildAsync(CancellationToken cancellationToke /// The output stream must support seeking and writing. public override void Build(Stream output) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(output); +#else if (output == null) { throw new ArgumentNullException(nameof(output)); } +#endif if (!output.CanWrite) { diff --git a/Library/DiscUtils.Streams/Builder/StreamBuilder.cs b/Library/DiscUtils.Streams/Builder/StreamBuilder.cs index f4049369f..4543409d9 100644 --- a/Library/DiscUtils.Streams/Builder/StreamBuilder.cs +++ b/Library/DiscUtils.Streams/Builder/StreamBuilder.cs @@ -61,13 +61,7 @@ public virtual Task BuildAsync(CancellationToken cancellationToken) public virtual void Build(Stream output) { using var src = Build(); - var buffer = new byte[64 * 1024]; - var numRead = src.Read(buffer, 0, buffer.Length); - while (numRead != 0) - { - output.Write(buffer, 0, numRead); - numRead = src.Read(buffer, 0, buffer.Length); - } + src.CopyTo(output); } /// @@ -78,13 +72,7 @@ public virtual void Build(Stream output) public virtual async Task BuildAsync(Stream output, CancellationToken cancellationToken) { using var src = await BuildAsync(cancellationToken).ConfigureAwait(false); - var buffer = new byte[64 * 1024]; - var numRead = await src.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); - while (numRead != 0) - { - await output.WriteAsync(buffer.AsMemory(0, numRead), cancellationToken).ConfigureAwait(false); - numRead = await src.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); - } + await src.CopyToAsync(output, cancellationToken).ConfigureAwait(false); } /// diff --git a/Library/DiscUtils.Streams/BuiltStream.cs b/Library/DiscUtils.Streams/BuiltStream.cs index d438c4879..90d4af0ed 100644 --- a/Library/DiscUtils.Streams/BuiltStream.cs +++ b/Library/DiscUtils.Streams/BuiltStream.cs @@ -31,7 +31,7 @@ namespace DiscUtils.Streams; public class BuiltStream : SparseStream { - private Stream _baseStream; + private ZeroStream _baseStream; private BuilderExtent _currentExtent; private readonly List _extents; @@ -417,6 +417,10 @@ private struct ExtentRangeComparer : IComparer { public int Compare(BuilderExtent x, BuilderExtent y) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(x); + ArgumentNullException.ThrowIfNull(y); +#else if (x == null) { throw new ArgumentNullException(nameof(x)); @@ -426,6 +430,7 @@ public int Compare(BuilderExtent x, BuilderExtent y) { throw new ArgumentNullException(nameof(y)); } +#endif if (x.Start + x.Length <= y.Start) { @@ -448,6 +453,10 @@ private struct ExtentStartComparer : IComparer { public int Compare(BuilderExtent x, BuilderExtent y) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(x); + ArgumentNullException.ThrowIfNull(y); +#else if (x == null) { throw new ArgumentNullException(nameof(x)); @@ -457,6 +466,7 @@ public int Compare(BuilderExtent x, BuilderExtent y) { throw new ArgumentNullException(nameof(y)); } +#endif var val = x.Start - y.Start; if (val < 0) diff --git a/Library/DiscUtils.Streams/StreamBuffer.cs b/Library/DiscUtils.Streams/StreamBuffer.cs index b73f882ae..b250bca90 100644 --- a/Library/DiscUtils.Streams/StreamBuffer.cs +++ b/Library/DiscUtils.Streams/StreamBuffer.cs @@ -43,10 +43,14 @@ public sealed class StreamBuffer : Buffer /// Whether to dispose stream, when this object is disposed. public StreamBuffer(Stream stream, Ownership ownership) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(stream); +#else if (stream == null) { throw new ArgumentNullException(nameof(stream)); } +#endif _stream = stream as SparseStream; if (_stream == null) diff --git a/Library/DiscUtils.Streams/Util/CompatExtensions.cs b/Library/DiscUtils.Streams/Util/CompatExtensions.cs index 6ecd41b8e..8b158f2ba 100644 --- a/Library/DiscUtils.Streams/Util/CompatExtensions.cs +++ b/Library/DiscUtils.Streams/Util/CompatExtensions.cs @@ -15,20 +15,28 @@ public abstract class CompatibilityStream : Stream { public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(buffer); +#else if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } +#endif return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(buffer); +#else if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } +#endif return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); } @@ -229,6 +237,9 @@ public static void AppendData(this IncrementalHash hash, ReadOnlySpan data ArrayPool.Shared.Return(bytes); } } + + public static Task CopyToAsync(this Stream source, Stream target, CancellationToken cancellationToken) + => source.CopyToAsync(target, bufferSize: 80 * 1024, cancellationToken); #endif } diff --git a/Library/DiscUtils.Streams/Util/StreamUtilities.cs b/Library/DiscUtils.Streams/Util/StreamUtilities.cs index 07d8ffa09..ab052632d 100644 --- a/Library/DiscUtils.Streams/Util/StreamUtilities.cs +++ b/Library/DiscUtils.Streams/Util/StreamUtilities.cs @@ -39,7 +39,13 @@ public static class StreamUtilities /// The number of bytes to read / write. public static void AssertBufferParameters(byte[] buffer, int offset, int count) { - if (buffer is null) +#if NET8_0_OR_GREATER + ArgumentNullException.ThrowIfNull(buffer); + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); + ArgumentOutOfRangeException.ThrowIfLessThan(buffer.Length, offset + count); +#else + if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } @@ -58,6 +64,7 @@ public static void AssertBufferParameters(byte[] buffer, int offset, int count) { throw new ArgumentException("buffer is too small", nameof(buffer)); } +#endif } #region Stream Manipulation diff --git a/Library/DiscUtils.Vhd/DynamicStream.cs b/Library/DiscUtils.Vhd/DynamicStream.cs index 7a95ab0b8..b12f1b378 100644 --- a/Library/DiscUtils.Vhd/DynamicStream.cs +++ b/Library/DiscUtils.Vhd/DynamicStream.cs @@ -52,30 +52,36 @@ public class DynamicStream : MappedStream internal DynamicStream(Stream fileStream, DynamicHeader dynamicHeader, long length, SparseStream parentStream, Ownership ownsParentStream) { - if (fileStream == null) - { - throw new ArgumentNullException(nameof(fileStream)); - } +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(fileStream); + ArgumentNullException.ThrowIfNull(dynamicHeader); + ArgumentNullException.ThrowIfNull(parentStream); - if (dynamicHeader == null) - { - throw new ArgumentNullException(nameof(dynamicHeader)); - } + _fileStream = fileStream; + _dynamicHeader = dynamicHeader; + _parentStream = parentStream; +#else + _fileStream = fileStream + ?? throw new ArgumentNullException(nameof(fileStream)); - if (parentStream == null) - { - throw new ArgumentNullException(nameof(parentStream)); - } + _dynamicHeader = dynamicHeader + ?? throw new ArgumentNullException(nameof(dynamicHeader)); + + _parentStream = parentStream + ?? throw new ArgumentNullException(nameof(parentStream)); + +#endif +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfNegative(length); +#else if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length), length, "Negative lengths not allowed"); } +#endif - _fileStream = fileStream; - _dynamicHeader = dynamicHeader; _length = length; - _parentStream = parentStream; _ownsParentStream = ownsParentStream; _blockBitmaps = new byte[_dynamicHeader.MaxTableEntries][]; diff --git a/Library/DiscUtils.VirtualFileSystem/VirtualFileSystemDirectoryEntry.cs b/Library/DiscUtils.VirtualFileSystem/VirtualFileSystemDirectoryEntry.cs index 47ec0f1e4..107c655f9 100644 --- a/Library/DiscUtils.VirtualFileSystem/VirtualFileSystemDirectoryEntry.cs +++ b/Library/DiscUtils.VirtualFileSystem/VirtualFileSystemDirectoryEntry.cs @@ -38,21 +38,38 @@ public const UnixFilePermissions DefaultUnixFilePermissions internal VirtualFileSystemDirectoryEntry(VirtualFileSystem fileSystem) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(fileSystem); + FileSystem = fileSystem; +#else FileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); +#endif } internal VirtualFileSystemDirectoryEntry(VirtualFileSystemDirectory parent, string name) { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(parent); + ArgumentNullException.ThrowIfNull(parent.FileSystem); + + Parent = parent; + FileSystem = parent.FileSystem; +#else Parent = parent ?? throw new ArgumentNullException(nameof(parent)); FileSystem = parent.FileSystem ?? throw new ArgumentException("FileSystem property is null", nameof(parent)); +#endif - if (string.IsNullOrEmpty(name)) +#if NET8_0_OR_GREATER + ArgumentException.ThrowIfNullOrWhiteSpace(name); +#else + if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("File names cannot be null or empty", nameof(name)); } +#endif parent.AddEntry(name, this); diff --git a/Library/DiscUtils.Xva/HashStreamCore.cs b/Library/DiscUtils.Xva/HashStreamCore.cs index 9af8f7f76..3b8e3b722 100644 --- a/Library/DiscUtils.Xva/HashStreamCore.cs +++ b/Library/DiscUtils.Xva/HashStreamCore.cs @@ -28,7 +28,6 @@ using DiscUtils.Streams; using DiscUtils.Streams.Compatibility; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER internal class HashStreamCore : CompatibilityStream { private readonly IncrementalHash _hashAlg; @@ -155,121 +154,3 @@ protected override void Dispose(bool disposing) } } } -#else -internal class HashStreamDotnet : CompatibilityStream -{ - private Stream _wrapped; - private Ownership _ownWrapped; - - private HashAlgorithm _hashAlg; - - private long _hashPos; - - public HashStreamDotnet(Stream wrapped, Ownership ownsWrapped, HashAlgorithm hashAlg) - { - _wrapped = wrapped; - _ownWrapped = ownsWrapped; - _hashAlg = hashAlg; - } - - public override bool CanRead => _wrapped.CanRead; - - public override bool CanSeek => _wrapped.CanSeek; - - public override bool CanWrite => _wrapped.CanWrite; - - public override long Length => _wrapped.Length; - - public override long Position - { - get => _wrapped.Position; - - set => _wrapped.Position = value; - } - - public override void Flush() - { - _wrapped.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (Position != _hashPos) - { - throw new InvalidOperationException("Reads must be contiguous"); - } - - var numRead = _wrapped.Read(buffer, offset, count); - - _hashAlg.TransformBlock(buffer, offset, numRead, buffer, offset); - _hashPos += numRead; - - return numRead; - } - - public override int Read(Span buffer) => - CompatExtensions.ReadUsingArray(this, buffer); - - public override long Seek(long offset, SeekOrigin origin) - { - return _wrapped.Seek(offset, origin); - } - - public override void SetLength(long value) - { - _wrapped.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - _wrapped.Write(buffer, offset, count); - } - - public override void Write(ReadOnlySpan buffer) => _wrapped.Write(buffer); - - public override Task FlushAsync(CancellationToken cancellationToken) => - _wrapped.FlushAsync(cancellationToken); - - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (Position != _hashPos) - { - throw new InvalidOperationException("Reads must be contiguous"); - } - - var numRead = await _wrapped.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - - _hashAlg.TransformBlock(buffer, offset, numRead, buffer, offset); - _hashPos += numRead; - - return numRead; - } - - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) => - CompatExtensions.ReadUsingArrayAsync(this, buffer, cancellationToken); - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => - _wrapped.WriteAsync(buffer, offset, count, cancellationToken); - - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => - _wrapped.WriteAsync(buffer, cancellationToken); - - public override void WriteByte(byte value) => _wrapped.WriteByte(value); - - protected override void Dispose(bool disposing) - { - try - { - if (disposing && _ownWrapped == Ownership.Dispose && _wrapped != null) - { - _wrapped.Dispose(); - _wrapped = null; - } - } - finally - { - base.Dispose(disposing); - } - } -} -#endif diff --git a/Library/DiscUtils.Xva/VirtualMachineBuilder.cs b/Library/DiscUtils.Xva/VirtualMachineBuilder.cs index 172a51269..30048049f 100644 --- a/Library/DiscUtils.Xva/VirtualMachineBuilder.cs +++ b/Library/DiscUtils.Xva/VirtualMachineBuilder.cs @@ -30,6 +30,7 @@ using System.Threading.Tasks; using DiscUtils.Archives; using DiscUtils.Streams; +using LTRData.Extensions.Formatting; namespace DiscUtils.Xva; @@ -137,25 +138,14 @@ public override Stream Build() } Stream chunkHashStream; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER var hashAlgCore = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); chunkHashStream = new HashStreamCore(chunkStream, Ownership.Dispose, hashAlgCore); -#else - HashAlgorithm hashAlgDotnet = new SHA1Managed(); - chunkHashStream = new HashStreamDotnet(chunkStream, Ownership.Dispose, hashAlgDotnet); -#endif tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}", diskIds[diskIdx], i), chunkHashStream); - byte[] hash; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER - hash = hashAlgCore.GetHashAndReset(); -#else - hashAlgDotnet.TransformFinalBlock(new byte[0], 0, 0); - hash = hashAlgDotnet.Hash; -#endif + var hash = hashAlgCore.GetHashAndReset(); - var hashString = BitConverter.ToString(hash).Replace("-", "").ToLower(); + var hashString = hash.ToHexString(); var hashStringAscii = Encoding.ASCII.GetBytes(hashString); tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}.checksum", diskIds[diskIdx], i), hashStringAscii); @@ -171,25 +161,14 @@ public override Stream Build() Stream chunkStream = new ZeroStream(Sizes.OneMiB); Stream chunkHashStream; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER var hashAlgCore = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); chunkHashStream = new HashStreamCore(chunkStream, Ownership.Dispose, hashAlgCore); -#else - HashAlgorithm hashAlgDotnet = new SHA1Managed(); - chunkHashStream = new HashStreamDotnet(chunkStream, Ownership.Dispose, hashAlgDotnet); -#endif tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}", diskIds[diskIdx], lastActualChunk), chunkHashStream); - byte[] hash; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER - hash = hashAlgCore.GetHashAndReset(); -#else - hashAlgDotnet.TransformFinalBlock(new byte[0], 0, 0); - hash = hashAlgDotnet.Hash; -#endif + var hash = hashAlgCore.GetHashAndReset(); - var hashString = BitConverter.ToString(hash).Replace("-", "").ToLower(); + var hashString = hash.ToHexString(); var hashStringAscii = Encoding.ASCII.GetBytes(hashString); tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}.checksum", diskIds[diskIdx], lastActualChunk), hashStringAscii); } @@ -242,26 +221,14 @@ public override Task BuildAsync(CancellationToken cancellationToken) chunkStream = new SubStream(diskStream, i * Sizes.OneMiB, Sizes.OneMiB); } - Stream chunkHashStream; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER var hashAlgCore = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); - chunkHashStream = new HashStreamCore(chunkStream, Ownership.Dispose, hashAlgCore); -#else - HashAlgorithm hashAlgDotnet = new SHA1Managed(); - chunkHashStream = new HashStreamDotnet(chunkStream, Ownership.Dispose, hashAlgDotnet); -#endif + var chunkHashStream = new HashStreamCore(chunkStream, Ownership.Dispose, hashAlgCore); tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}", diskIds[diskIdx], i), chunkHashStream); - byte[] hash; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER - hash = hashAlgCore.GetHashAndReset(); -#else - hashAlgDotnet.TransformFinalBlock(new byte[0], 0, 0); - hash = hashAlgDotnet.Hash; -#endif + var hash = hashAlgCore.GetHashAndReset(); - var hashString = BitConverter.ToString(hash).Replace("-", "").ToLower(); + var hashString = hash.ToHexString(); var hashStringAscii = Encoding.ASCII.GetBytes(hashString); tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}.checksum", diskIds[diskIdx], i), hashStringAscii); @@ -276,26 +243,14 @@ public override Task BuildAsync(CancellationToken cancellationToken) { Stream chunkStream = new ZeroStream(Sizes.OneMiB); - Stream chunkHashStream; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER var hashAlgCore = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); - chunkHashStream = new HashStreamCore(chunkStream, Ownership.Dispose, hashAlgCore); -#else - HashAlgorithm hashAlgDotnet = new SHA1Managed(); - chunkHashStream = new HashStreamDotnet(chunkStream, Ownership.Dispose, hashAlgDotnet); -#endif + var chunkHashStream = new HashStreamCore(chunkStream, Ownership.Dispose, hashAlgCore); tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}", diskIds[diskIdx], lastActualChunk), chunkHashStream); - byte[] hash; -#if NETSTANDARD || NETCOREAPP || NET461_OR_GREATER - hash = hashAlgCore.GetHashAndReset(); -#else - hashAlgDotnet.TransformFinalBlock(new byte[0], 0, 0); - hash = hashAlgDotnet.Hash; -#endif + var hash = hashAlgCore.GetHashAndReset(); - var hashString = BitConverter.ToString(hash).Replace("-", "").ToLower(); + var hashString = hash.ToHexString(); var hashStringAscii = Encoding.ASCII.GetBytes(hashString); tarBuilder.AddFile(string.Format(CultureInfo.InvariantCulture, "Ref:{0}/{1:D8}.checksum", diskIds[diskIdx], lastActualChunk), hashStringAscii); } diff --git a/Tests/LibraryTests/Btrfs/SampleDataTests.cs b/Tests/LibraryTests/Btrfs/SampleDataTests.cs index 803b1f7b4..a918fdca9 100644 --- a/Tests/LibraryTests/Btrfs/SampleDataTests.cs +++ b/Tests/LibraryTests/Btrfs/SampleDataTests.cs @@ -9,7 +9,9 @@ using DiscUtils.Streams; using DiscUtils.Vhdx; using LibraryTests.Utilities; +using LTRData.Extensions.Formatting; using Xunit; +using static LibraryTests.Helpers.Helpers; namespace LibraryTests.Btrfs; @@ -20,7 +22,7 @@ public void BtrfsVhdxZip() { DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(Disk).GetTypeInfo().Assembly); DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(BtrfsFileSystem).GetTypeInfo().Assembly); - using var vhdx = Helpers.Helpers.LoadTestDataFileFromGZipFile("Btrfs", "btrfs.vhdx.gz"); + using var vhdx = LoadTestDataFileFromGZipFile("Btrfs", "btrfs.vhdx.gz"); using var diskImage = new DiskImageFile(vhdx, Ownership.Dispose); using var disk = new Disk(new List { diskImage }, Ownership.Dispose); var manager = new VolumeManager(disk); @@ -47,45 +49,17 @@ public void BtrfsVhdxZip() Assert.Equal(256UL, subvolumes[0].Id); Assert.Equal("subvolume", subvolumes[0].Name); - Assert.Equal("text\n", GetFileContent(@"\folder\subfolder\file", btrfs)); - Assert.Equal("f64464c2024778f347277de6fa26fe87", GetFileChecksum(@"\folder\subfolder\f64464c2024778f347277de6fa26fe87", btrfs)); - Assert.Equal("fa121c8b73cf3b01a4840b1041b35e9f", GetFileChecksum(@"\folder\subfolder\fa121c8b73cf3b01a4840b1041b35e9f", btrfs)); - IsAllZero(@"folder\subfolder\sparse", btrfs); - Assert.Equal("test\n", GetFileContent(@"\subvolume\subvolumefolder\subvolumefile", btrfs)); - Assert.Equal("b0d5fae237588b6641f974459404d197", GetFileChecksum(@"\folder\subfolder\compressed", btrfs)); - Assert.Equal("test\n", GetFileContent(@"\folder\symlink", btrfs)); //PR#36 - Assert.Equal("b0d5fae237588b6641f974459404d197", GetFileChecksum(@"\folder\subfolder\lzo", btrfs)); + Assert.Equal("text\n", GetFileContent(Path.Combine("folder","subfolder", "file"), btrfs)); + Assert.Equal("f64464c2024778f347277de6fa26fe87", GetFileChecksum(Path.Combine("folder", "subfolder", "f64464c2024778f347277de6fa26fe87"), btrfs)); + Assert.Equal("fa121c8b73cf3b01a4840b1041b35e9f", GetFileChecksum(Path.Combine("folder", "subfolder", "fa121c8b73cf3b01a4840b1041b35e9f"), btrfs)); + AssertAllZero(Path.Combine("folder", "subfolder", "sparse"), btrfs); + Assert.Equal("test\n", GetFileContent(Path.Combine("subvolume", "subvolumefolder", "subvolumefile"), btrfs)); + Assert.Equal("b0d5fae237588b6641f974459404d197", GetFileChecksum(Path.Combine("folder", "subfolder", "compressed"), btrfs)); + Assert.Equal("test\n", GetFileContent(Path.Combine("folder", "symlink"), btrfs)); //PR#36 + Assert.Equal("b0d5fae237588b6641f974459404d197", GetFileChecksum(Path.Combine("folder", "subfolder", "lzo"), btrfs)); } using var subvolume = new BtrfsFileSystem(volume.Open(), new BtrfsFileSystemOptions { SubvolumeId = 256, VerifyChecksums = true }); - Assert.Equal("test\n", GetFileContent(@"\subvolumefolder\subvolumefile", subvolume)); - } - - private static void IsAllZero(string path, DiscFileSystem fs) - { - var fileInfo = fs.GetFileInfo(path); - var buffer = new byte[4 * Sizes.OneKiB]; - using var file = fileInfo.OpenRead(); - var count = file.Read(buffer, 0, buffer.Length); - for (var i = 0; i < count; i++) - { - Assert.Equal(0, buffer[i]); - } - } - - private static string GetFileContent(string path, IFileSystem fs) - { - var fileInfo = fs.GetFileInfo(path); - using var file = fileInfo.OpenText(); - return file.ReadToEnd(); - } - - private static string GetFileChecksum(string path, DiscFileSystem fs) - { - var fileInfo = fs.GetFileInfo(path); - using var md5 = MD5.Create(); - using var file = fileInfo.OpenRead(); - var checksum = md5.ComputeHash(file); - return BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower(); + Assert.Equal("test\n", GetFileContent(Path.Combine("subvolumefolder", "subvolumefile"), subvolume)); } } \ No newline at end of file diff --git a/Tests/LibraryTests/Helpers/Helpers.cs b/Tests/LibraryTests/Helpers/Helpers.cs index 2f6c13d53..a46ee329e 100644 --- a/Tests/LibraryTests/Helpers/Helpers.cs +++ b/Tests/LibraryTests/Helpers/Helpers.cs @@ -1,6 +1,11 @@ -using System; +using DiscUtils; +using DiscUtils.Streams; +using LTRData.Extensions.Formatting; +using System; using System.IO; using System.IO.Compression; +using System.Security.Cryptography; +using Xunit; namespace LibraryTests.Helpers; @@ -36,4 +41,39 @@ public static Stream LoadTestDataFileFromGZipFile(string projectName, string dat return ms; } + public static string GetFileChecksum(string path, IFileSystem fs) + { +#if NETCOREAPP + var fileInfo = fs.GetFileInfo(path); + using var file = fileInfo.OpenRead(); + Span checksum = stackalloc byte[MD5.HashSizeInBytes]; + MD5.HashData(file, checksum); + return checksum.ToHexString(); +#else + var fileInfo = fs.GetFileInfo(path); + using var md5 = MD5.Create(); + using var file = fileInfo.OpenRead(); + var checksum = md5.ComputeHash(file); + return checksum.ToHexString(); +#endif + } + + public static void AssertAllZero(string path, IFileSystem fs) + { + var fileInfo = fs.GetFileInfo(path); + var buffer = new byte[4 * Sizes.OneKiB]; + using var file = fileInfo.OpenRead(); + var count = file.Read(buffer, 0, buffer.Length); + for (var i = 0; i < count; i++) + { + Assert.Equal(0, buffer[i]); + } + } + + public static string GetFileContent(string path, IFileSystem fs) + { + var fileInfo = fs.GetFileInfo(path); + using var file = fileInfo.OpenText(); + return file.ReadToEnd(); + } } diff --git a/Tests/LibraryTests/Xfs/SampleDataTests.cs b/Tests/LibraryTests/Xfs/SampleDataTests.cs index 3ced762d5..f15cb5124 100644 --- a/Tests/LibraryTests/Xfs/SampleDataTests.cs +++ b/Tests/LibraryTests/Xfs/SampleDataTests.cs @@ -10,6 +10,7 @@ using LibraryTests.Utilities; using Xunit; using File=System.IO.File; +using static LibraryTests.Helpers.Helpers; namespace LibraryTests.Xfs; @@ -72,28 +73,22 @@ public void Xfs5VhdxZip() private static void ValidateContent(DiscFileSystem xfs) { Assert.True(xfs.DirectoryExists("")); - Assert.True(xfs.FileExists("folder\\nested\\file")); + Assert.True(xfs.FileExists(Path.Combine("folder", "nested", "file"))); Assert.Empty(xfs.GetFileSystemEntries("empty")); for (var i = 1; i <= 1000; i++) { - Assert.True(xfs.FileExists($"folder\\file.{i}"), $"File file.{i} not found"); + Assert.True(xfs.FileExists(Path.Combine("folder", $"file.{i}")), $"File file.{i} not found"); } - using (var file = xfs.OpenFile("folder\\file.100", FileMode.Open)) - { - var md5 = MD5.Create().ComputeHash(file); - Assert.Equal("620f0b67a91f7f74151bc5be745b7110", BitConverter.ToString(md5).ToLowerInvariant().Replace("-", string.Empty)); - } + var md5 = GetFileChecksum(Path.Combine("folder", "file.100"), xfs); + Assert.Equal("620f0b67a91f7f74151bc5be745b7110", md5); - using (var file = xfs.OpenFile("folder\\file.random", FileMode.Open)) - { - var md5 = MD5.Create().ComputeHash(file); - Assert.Equal("9a202a11d6e87688591eb97714ed56f1", BitConverter.ToString(md5).ToLowerInvariant().Replace("-", string.Empty)); - } + md5 = GetFileChecksum(Path.Combine("folder", "file.random"), xfs); + Assert.Equal("9a202a11d6e87688591eb97714ed56f1", md5); for (var i = 1; i <= 999; i++) { - Assert.True(xfs.FileExists($"huge\\{i}"), $"File huge/{i} not found"); + Assert.True(xfs.FileExists(Path.Combine("huge", $"{i}")), $"File huge/{i} not found"); } } } \ No newline at end of file