Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions .github/workflows/publish-nuget.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
name: NuGet push (tag)

on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
on:
workflow_dispatch:

env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true

jobs:
build:
runs-on: windows-2019
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
fetch-depth: 50
lfs: 'true'
# We do not need to fetch tags, as we're already at a tagged build - it should be available automatically
dotnet-version: 10.0.x

- name: Setup .NET Core 7.0
uses: actions/setup-dotnet@v1
with:
dotnet-version: '7.0.x'
- name: Build
run: dotnet build -c Release

- name: Pack
run: dotnet pack -c Release -o ${{ github.workspace }}/build
run: dotnet pack -c Release -o ${{ github.workspace }}/build --no-build

- name: NuGet push
run: dotnet nuget push *.nupkg --skip-duplicate -k ${{secrets.NUGET_KEY}} -s https://api.nuget.org/v3/index.json
Expand Down
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -386,3 +386,19 @@ artifacts-dotnet-releaser/
# Verify
*.received.*
*#

# Build outputs in Library folder
Library/net*/
Library/netstandard*/
net10.0/

# Build outputs in root
netstandard*/

# Build outputs in Tests folder
Tests/net*/
Tests/netstandard*/

# Build outputs in Utilities folder
Utilities/net*/
Utilities/netstandard*/
5 changes: 3 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@

<DebugType>portable</DebugType>

<PackageProjectUrl>https://github.com/LTRData/DiscUtils</PackageProjectUrl>
<PackageProjectUrl>https://github.com/Devedse/DiscUtils</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>

<Company>LTR Data</Company>
<Authors>Kenneth Bell;LordMike;Olof Lagerkvist</Authors>
<OutputPath>..\$(Configuration)</OutputPath>
<FileVersion>1.0.72</FileVersion>
<FileVersion>1.0.102</FileVersion>

<GenerateDocumentationFile>true</GenerateDocumentationFile>

<NoWarn>CS1591;CS0649</NoWarn>
<EmitCompilerGeneratedFiles>false</EmitCompilerGeneratedFiles>

</PropertyGroup>

Expand Down
1 change: 1 addition & 0 deletions DiscUtils.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<Project Path="Library/DiscUtils.Xfs/DiscUtils.Xfs.csproj" />
<Project Path="Library/DiscUtils.Xva/DiscUtils.Xva.csproj" />
<Project Path="Library/DiscUtils/DiscUtils.csproj" />
<Project Path="Library/DiscUtils.SourceGenerator/DiscUtils.SourceGenerator.csproj" />
</Folder>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
Expand Down
8 changes: 7 additions & 1 deletion Library/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net46;net48;net8.0;net9.0;net10.0</TargetFrameworks>
<GeneratePackageOnBuild Condition="'$(Configuration)' == 'Release'">true</GeneratePackageOnBuild>
<PackageId>LTRData.$(MSBuildProjectName)</PackageId>
<PackageId>Devedse.$(MSBuildProjectName)</PackageId>
<PackageOutputPath>$(LocalNuGetPath)</PackageOutputPath>
<PackageVersion>$(FileVersion)</PackageVersion>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand All @@ -26,6 +26,8 @@
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)../SigningKey.snk</AssemblyOriginatorKeyFile>
<SignAssembly>false</SignAssembly>
<EmitCompilerGeneratedFiles>false</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)Generated</CompilerGeneratedFilesOutputPath>
<DelaySign>false</DelaySign>
</PropertyGroup>

Expand All @@ -37,4 +39,8 @@
</PackageReference>
</ItemGroup>

<ItemGroup Condition="'$(IsSourceGenerator)' != 'true'">
<ProjectReference Include="$(MSBuildThisFileDirectory)DiscUtils.SourceGenerator\DiscUtils.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" GlobalPropertiesToRemove="TargetFramework" SkipGetTargetFrameworkProperties="true" />
</ItemGroup>

</Project>
9 changes: 9 additions & 0 deletions Library/DiscUtils.Core/DiskImageBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,18 @@ public static DiskImageBuilder GetBuilder(string type, string variant)
/// 'foo', the files 'foo.vmdk' and 'foo-flat.vmdk' could be returned.</remarks>
public abstract IEnumerable<DiskImageFileSpecification> Build(string baseName);

// Set this to true to enable AoT compatiblity
public static bool ShouldUseVirtualDiskManagerTypeMap { get; set; }

[MemberNotNull(nameof(_typeMap))]
private static void InitializeMaps()
{
if (ShouldUseVirtualDiskManagerTypeMap)
{
_typeMap = VirtualDiskManager.TypeMap;
return;
}

var typeMap = new Dictionary<string, VirtualDiskFactory>();

foreach (var type in typeof(VirtualDisk).Assembly.GetTypes())
Expand Down
20 changes: 15 additions & 5 deletions Library/DiscUtils.Core/Partitions/PartitionTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,29 +54,39 @@ public abstract class PartitionTable
/// </summary>
public abstract Geometry? DiskGeometry { get; }

private static List<PartitionTableFactory>? _factories;

private static List<PartitionTableFactory> Factories
{
get
{
if (field == null)
if (_factories == null)
{
var factories = new List<PartitionTableFactory>();

foreach (var type in typeof(VolumeManager).Assembly.GetTypes())
{
foreach (var attr in type.GetCustomAttributes<PartitionTableFactoryAttribute>(false))
{
factories.Add((PartitionTableFactory)Activator.CreateInstance(type)!);
factories.Add((PartitionTableFactory)Activator.CreateInstance(type, true)!);
}
}

field = factories;
_factories = factories;
}

return field;
return _factories;
}
}

internal static void RegisterPartitionTableFactory(PartitionTableFactory factory)
{
if (_factories == null)
{
_factories = new List<PartitionTableFactory>();
}

set;
_factories.Add(factory);
}

/// <summary>
Expand Down
8 changes: 4 additions & 4 deletions Library/DiscUtils.Core/VirtualDisk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,12 @@ public static VirtualDisk CreateDisk(DiscFileSystem fileSystem, string type, str
var uri = PathToUri(path);
VirtualDisk result;

if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportType))
if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportFactory))
{
throw new FileNotFoundException($"Unable to parse path '{path}'", path);
}

var transport = (VirtualDiskTransport)Activator.CreateInstance(transportType)!;
var transport = transportFactory();

try
{
Expand Down Expand Up @@ -499,12 +499,12 @@ public static VirtualDisk CreateDisk(DiscFileSystem fileSystem, string type, str
var uri = PathToUri(path);
VirtualDisk? result = null;

if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportType))
if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportFactory))
{
throw new FileNotFoundException($"Unable to parse path '{uri}'", path);
}

var transport = (VirtualDiskTransport)Activator.CreateInstance(transportType)!;
var transport = transportFactory();

try
{
Expand Down
51 changes: 45 additions & 6 deletions Library/DiscUtils.Core/VirtualDiskManager.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using DiscUtils.Internal;
using System;
using System.Collections.Generic;
using System.Reflection;
using DiscUtils.Internal;

namespace DiscUtils;

Expand All @@ -14,10 +14,10 @@ static VirtualDiskManager()
{
ExtensionMap = new Dictionary<string, VirtualDiskFactory>(StringComparer.OrdinalIgnoreCase);
TypeMap = new Dictionary<string, VirtualDiskFactory>(StringComparer.OrdinalIgnoreCase);
DiskTransports = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
DiskTransports = new Dictionary<string, Func<VirtualDiskTransport>>(StringComparer.OrdinalIgnoreCase);
}

internal static Dictionary<string, Type> DiskTransports { get; }
internal static Dictionary<string, Func<VirtualDiskTransport>> DiskTransports { get; }
internal static Dictionary<string, VirtualDiskFactory> ExtensionMap { get; }

/// <summary>
Expand All @@ -33,7 +33,46 @@ static VirtualDiskManager()
internal static Dictionary<string, VirtualDiskFactory> TypeMap { get; }

/// <summary>
/// Locates VirtualDiskFactory factories attributed with VirtualDiskFactoryAttribute, and types marked with VirtualDiskTransportAttribute, that are able to work with Virtual Disk types.
/// Registers a VirtualDiskFactory instance.
/// </summary>
/// <param name="factory">The factory to register.</param>
public static void RegisterVirtualDiskFactory(VirtualDiskFactory factory)
{
var type = factory.GetType();
var diskFactoryAttribute = type.GetCustomAttribute<VirtualDiskFactoryAttribute>(false);
if (diskFactoryAttribute != null)
{
if (!TypeMap.ContainsKey(diskFactoryAttribute.Type))
{
TypeMap.Add(diskFactoryAttribute.Type, factory);
}

foreach (var extension in diskFactoryAttribute.FileExtensions)
{
if (!ExtensionMap.ContainsKey(extension))
{
ExtensionMap.Add(extension, factory);
}
}
}
}

/// <summary>
/// Registers a VirtualDiskTransport factory.
/// </summary>
/// <param name="scheme">The URI scheme.</param>
/// <param name="factory">The factory method.</param>
internal static void RegisterVirtualDiskTransport(string scheme, Func<VirtualDiskTransport> factory)
{
if (!DiskTransports.ContainsKey(scheme))
{
DiskTransports.Add(scheme, factory);
}
}

/// <summary>
/// Locates VirtualDiskFactory factories attributed with VirtualDiskFactoryAttribute, and types marked with VirtualDiskTransportAttribute,
/// that are able to work with Virtual Disk types.
/// </summary>
/// <param name="assembly">An assembly to scan</param>
public static void RegisterVirtualDiskTypes(Assembly assembly)
Expand All @@ -55,7 +94,7 @@ public static void RegisterVirtualDiskTypes(Assembly assembly)
var diskTransportAttribute = type.GetCustomAttribute<VirtualDiskTransportAttribute>(false);
if (diskTransportAttribute != null)
{
DiskTransports.Add(diskTransportAttribute.Scheme, type);
DiskTransports.Add(diskTransportAttribute.Scheme, () => (VirtualDiskTransport)Activator.CreateInstance(type)!);
}
}
}
Expand Down
31 changes: 25 additions & 6 deletions Library/DiscUtils.Core/VolumeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,45 @@ public VolumeManager(Stream initialDiskContent)

private static readonly object _syncObj = new();

private static ConcurrentBag<LogicalVolumeFactory>? _logicalVolumeFactories;

private static ConcurrentBag<LogicalVolumeFactory> LogicalVolumeFactories
{
get
{
if (field == null)
if (_logicalVolumeFactories == null)
{
lock (_syncObj)
{
if (field == null)
if (_logicalVolumeFactories == null)
{
var factories = new ConcurrentBag<LogicalVolumeFactory>(GetLogicalVolumeFactories(_coreAssembly));
field = factories;
_logicalVolumeFactories = new ConcurrentBag<LogicalVolumeFactory>(GetLogicalVolumeFactories(_coreAssembly));
}
}
}

return field;
return _logicalVolumeFactories;
}
}

/// <summary>
/// Register a new LogicalVolumeFactory instance.
/// </summary>
/// <param name="factory">The factory to register.</param>
internal static void RegisterLogicalVolumeFactory(LogicalVolumeFactory factory)
{
if (_logicalVolumeFactories == null)
{
lock (_syncObj)
{
if (_logicalVolumeFactories == null)
{
_logicalVolumeFactories = new ConcurrentBag<LogicalVolumeFactory>();
}
}
}

set;
_logicalVolumeFactories.Add(factory);
}

private static IEnumerable<LogicalVolumeFactory> GetLogicalVolumeFactories(Assembly assembly)
Expand Down
31 changes: 31 additions & 0 deletions Library/DiscUtils.Registry/Bin.cs
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be wrong in several ways. It needs to implement reading from other locations of the hive file outside of current bin object, so _buffer cannot be used to get all data. There are also a few errors in offset calculations, and I am also not sure whether the total length calculation is really reliable. I will try to find out how this can be resolved in some way.

Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,37 @@ public Span<byte> ReadRawCellData(int cellIndex, Span<byte> maxBytes)
{
var index = cellIndex - _header.FileOffset;
var len = Math.Abs(EndianUtilities.ToInt32LittleEndian(_buffer, index));

// Check if this is a "big data" cell (signature "db")
// Big data cells are used for values larger than ~16KB
if (len >= 6 && _buffer[index + 4] == 0x64 && _buffer[index + 5] == 0x62) // "db"
{
// Big data format:
// 0x00: signature "db" (2 bytes)
// 0x02: number of segments (2 bytes)
// 0x04: offset to list of cell indices (4 bytes)
var numSegments = EndianUtilities.ToUInt16LittleEndian(_buffer.AsSpan(index + 6));
var listOffset = EndianUtilities.ToInt32LittleEndian(_buffer.AsSpan(index + 8));

// Read the list of cell indices
var listIndex = listOffset - _header.FileOffset;
var bytesWritten = 0;

for (var i = 0; i < numSegments && bytesWritten < maxBytes.Length; i++)
{
var segmentCellIndex = EndianUtilities.ToInt32LittleEndian(_buffer.AsSpan(listIndex + i * 4));
var segmentIndex = segmentCellIndex - _header.FileOffset;
var segmentLen = Math.Abs(EndianUtilities.ToInt32LittleEndian(_buffer, segmentIndex)) - 4;

var bytesToCopy = Math.Min(segmentLen, maxBytes.Length - bytesWritten);
_buffer.AsSpan(segmentIndex + 4, bytesToCopy).CopyTo(maxBytes.Slice(bytesWritten));
bytesWritten += bytesToCopy;
}

return maxBytes.Slice(0, bytesWritten);
}

// Regular cell data
var result = maxBytes.Slice(0, Math.Min(len - 4, maxBytes.Length));
_buffer.AsSpan(index + 4, result.Length).CopyTo(result);
return result;
Expand Down
Loading