Skip to content

Commit 43970a1

Browse files
authored
Add custom DMG building (#149)
Add custom DMG creator +semver:major
1 parent 0469037 commit 43970a1

File tree

66 files changed

+8365
-925
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+8365
-925
lines changed

Directory.Packages.props

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
</PackageVersion>
1414
<PackageVersion Include="CSharpFunctionalExtensions" Version="3.6.0" />
1515
<PackageVersion Include="CSharpFunctionalExtensions.FluentAssertions" Version="3.6.0" />
16-
<PackageVersion Include="DotnetPackaging.Formats.Dmg.Iso" Version="0.0.9" />
17-
<PackageVersion Include="DotnetPackaging.Formats.Dmg.Udif" Version="0.0.9" />
16+
<PackageVersion Include="DotnetPackaging.Dmg.Iso" Version="0.0.9" />
17+
<PackageVersion Include="DotnetPackaging.Dmg.Udif" Version="0.0.9" />
1818
<PackageVersion Include="FluentAssertions" Version="8.8.0" />
1919
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.0" />
2020
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
@@ -39,6 +39,7 @@
3939
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
4040
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.12" />
4141
<PackageVersion Include="System.CommandLine" Version="2.0.0" />
42+
<PackageVersion Include="System.Reactive" Version="6.1.0" />
4243
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.16" />
4344
<PackageVersion Include="System.Security.Permissions" Version="10.0.0" />
4445
<PackageVersion Include="TestableIO.System.IO.Abstractions.Extensions" Version="2.2.5" />

DotnetPackaging.sln

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetPackaging.Exe.Tests",
4545
EndProject
4646
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetPackaging.Deb.Tests", "test\DotnetPackaging.Deb.Tests\DotnetPackaging.Deb.Tests.csproj", "{B9A9B63E-2D76-4BA5-BA23-8151082C9049}"
4747
EndProject
48+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetPackaging.Hfs.Tests", "test\DotnetPackaging.Hfs.Tests\DotnetPackaging.Hfs.Tests.csproj", "{36B6320D-7C18-4C3B-83BB-C70147356FF8}"
49+
EndProject
50+
EndProject
51+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetPackaging.Dmg.MachO", "src\DotnetPackaging.Dmg.MachO\DotnetPackaging.Dmg.MachO.csproj", "{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}"
52+
EndProject
53+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetPackaging.Dmg.Udif", "src\DotnetPackaging.Dmg.Udif\DotnetPackaging.Dmg.Udif.csproj", "{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}"
54+
EndProject
55+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetPackaging.Dmg.Hfs", "src\DotnetPackaging.Dmg.Hfs\DotnetPackaging.Dmg.Hfs.csproj", "{2330C179-9A15-4FC4-9FEA-45D59603714C}"
56+
EndProject
4857
Global
4958
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5059
Debug|Any CPU = Debug|Any CPU
@@ -247,6 +256,54 @@ Global
247256
{B9A9B63E-2D76-4BA5-BA23-8151082C9049}.Release|x64.Build.0 = Release|Any CPU
248257
{B9A9B63E-2D76-4BA5-BA23-8151082C9049}.Release|x86.ActiveCfg = Release|Any CPU
249258
{B9A9B63E-2D76-4BA5-BA23-8151082C9049}.Release|x86.Build.0 = Release|Any CPU
259+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
260+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
261+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Debug|x64.ActiveCfg = Debug|Any CPU
262+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Debug|x64.Build.0 = Debug|Any CPU
263+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Debug|x86.ActiveCfg = Debug|Any CPU
264+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Debug|x86.Build.0 = Debug|Any CPU
265+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
266+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Release|Any CPU.Build.0 = Release|Any CPU
267+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Release|x64.ActiveCfg = Release|Any CPU
268+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Release|x64.Build.0 = Release|Any CPU
269+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Release|x86.ActiveCfg = Release|Any CPU
270+
{36B6320D-7C18-4C3B-83BB-C70147356FF8}.Release|x86.Build.0 = Release|Any CPU
271+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
272+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Debug|Any CPU.Build.0 = Debug|Any CPU
273+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Debug|x64.ActiveCfg = Debug|Any CPU
274+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Debug|x64.Build.0 = Debug|Any CPU
275+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Debug|x86.ActiveCfg = Debug|Any CPU
276+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Debug|x86.Build.0 = Debug|Any CPU
277+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Release|Any CPU.ActiveCfg = Release|Any CPU
278+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Release|Any CPU.Build.0 = Release|Any CPU
279+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Release|x64.ActiveCfg = Release|Any CPU
280+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Release|x64.Build.0 = Release|Any CPU
281+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Release|x86.ActiveCfg = Release|Any CPU
282+
{3C7EA8CB-775E-4DF4-9571-C8A0867B058F}.Release|x86.Build.0 = Release|Any CPU
283+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
284+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Debug|Any CPU.Build.0 = Debug|Any CPU
285+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Debug|x64.ActiveCfg = Debug|Any CPU
286+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Debug|x64.Build.0 = Debug|Any CPU
287+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Debug|x86.ActiveCfg = Debug|Any CPU
288+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Debug|x86.Build.0 = Debug|Any CPU
289+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Release|Any CPU.ActiveCfg = Release|Any CPU
290+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Release|Any CPU.Build.0 = Release|Any CPU
291+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Release|x64.ActiveCfg = Release|Any CPU
292+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Release|x64.Build.0 = Release|Any CPU
293+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Release|x86.ActiveCfg = Release|Any CPU
294+
{E1B2E09B-405A-4E8D-89DE-80D4F2AC7097}.Release|x86.Build.0 = Release|Any CPU
295+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
296+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Debug|Any CPU.Build.0 = Debug|Any CPU
297+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Debug|x64.ActiveCfg = Debug|Any CPU
298+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Debug|x64.Build.0 = Debug|Any CPU
299+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Debug|x86.ActiveCfg = Debug|Any CPU
300+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Debug|x86.Build.0 = Debug|Any CPU
301+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Release|Any CPU.ActiveCfg = Release|Any CPU
302+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Release|Any CPU.Build.0 = Release|Any CPU
303+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Release|x64.ActiveCfg = Release|Any CPU
304+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Release|x64.Build.0 = Release|Any CPU
305+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Release|x86.ActiveCfg = Release|Any CPU
306+
{2330C179-9A15-4FC4-9FEA-45D59603714C}.Release|x86.Build.0 = Release|Any CPU
250307
EndGlobalSection
251308
GlobalSection(SolutionProperties) = preSolution
252309
HideSolutionNode = FALSE
@@ -258,6 +315,7 @@ Global
258315
{DD050A6C-D84F-47AC-8453-18A57F751587} = {7E0C2A39-1C29-4B5D-9D45-1B6B7E7A77B6}
259316
{C9B6586A-332B-40B0-9F2B-BBFFD7F5CFCB} = {7E0C2A39-1C29-4B5D-9D45-1B6B7E7A77B6}
260317
{B9A9B63E-2D76-4BA5-BA23-8151082C9049} = {7E0C2A39-1C29-4B5D-9D45-1B6B7E7A77B6}
318+
{36B6320D-7C18-4C3B-83BB-C70147356FF8} = {7E0C2A39-1C29-4B5D-9D45-1B6B7E7A77B6}
261319
EndGlobalSection
262320
GlobalSection(ExtensibilityGlobals) = postSolution
263321
SolutionGuid = {1D869DF1-9147-472D-A3D9-D519518A6951}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
namespace DotnetPackaging.Hfs;
2+
3+
/// <summary>
4+
/// HFS+ Allocation File.
5+
/// A bitmap where each bit represents one allocation block.
6+
/// 0 = free, 1 = used.
7+
/// </summary>
8+
public sealed class AllocationBitmap
9+
{
10+
private readonly byte[] bitmap;
11+
private readonly uint totalBlocks;
12+
private uint usedBlocks;
13+
14+
public AllocationBitmap(uint totalBlocks)
15+
{
16+
this.totalBlocks = totalBlocks;
17+
var byteCount = (totalBlocks + 7) / 8;
18+
bitmap = new byte[byteCount];
19+
}
20+
21+
/// <summary>
22+
/// Total number of allocation blocks.
23+
/// </summary>
24+
public uint TotalBlocks => totalBlocks;
25+
26+
/// <summary>
27+
/// Number of used blocks.
28+
/// </summary>
29+
public uint UsedBlocks => usedBlocks;
30+
31+
/// <summary>
32+
/// Number of free blocks.
33+
/// </summary>
34+
public uint FreeBlocks => totalBlocks - usedBlocks;
35+
36+
/// <summary>
37+
/// Size of the bitmap in bytes.
38+
/// </summary>
39+
public int Size => bitmap.Length;
40+
41+
/// <summary>
42+
/// Marks a single block as used.
43+
/// </summary>
44+
public void MarkUsed(uint blockIndex)
45+
{
46+
if (blockIndex >= totalBlocks)
47+
throw new ArgumentOutOfRangeException(nameof(blockIndex));
48+
49+
var byteIndex = blockIndex / 8;
50+
var bitIndex = 7 - (int)(blockIndex % 8); // Big-endian bit order
51+
52+
if ((bitmap[byteIndex] & (1 << bitIndex)) == 0)
53+
{
54+
bitmap[byteIndex] |= (byte)(1 << bitIndex);
55+
usedBlocks++;
56+
}
57+
}
58+
59+
/// <summary>
60+
/// Marks a range of blocks as used.
61+
/// </summary>
62+
public void MarkUsed(uint startBlock, uint count)
63+
{
64+
for (uint i = 0; i < count; i++)
65+
{
66+
MarkUsed(startBlock + i);
67+
}
68+
}
69+
70+
/// <summary>
71+
/// Allocates a contiguous range of blocks and returns the start block.
72+
/// Returns null if not enough contiguous free blocks are available.
73+
/// </summary>
74+
public uint? Allocate(uint count, uint startHint = 0)
75+
{
76+
if (count == 0) return 0;
77+
78+
uint consecutive = 0;
79+
uint startBlock = 0;
80+
81+
for (uint i = startHint; i < totalBlocks; i++)
82+
{
83+
if (IsFree(i))
84+
{
85+
if (consecutive == 0)
86+
startBlock = i;
87+
88+
consecutive++;
89+
90+
if (consecutive >= count)
91+
{
92+
MarkUsed(startBlock, count);
93+
return startBlock;
94+
}
95+
}
96+
else
97+
{
98+
consecutive = 0;
99+
}
100+
}
101+
102+
// If not found from startHint, try from 0 if startHint > 0?
103+
// For our rigorous linear Writer, we usually want strictly forward, but generic bitmap should scan all.
104+
// But for now, strict forward is fine for the Writer's purpose.
105+
106+
return null;
107+
}
108+
109+
/// <summary>
110+
/// Checks if a block is free.
111+
/// </summary>
112+
public bool IsFree(uint blockIndex)
113+
{
114+
if (blockIndex >= totalBlocks) return false;
115+
116+
var byteIndex = blockIndex / 8;
117+
var bitIndex = 7 - (int)(blockIndex % 8);
118+
return (bitmap[byteIndex] & (1 << bitIndex)) == 0;
119+
}
120+
121+
/// <summary>
122+
/// Gets the bitmap bytes.
123+
/// </summary>
124+
public byte[] ToBytes() => (byte[])bitmap.Clone();
125+
126+
/// <summary>
127+
/// Creates an IByteSource from this bitmap.
128+
/// </summary>
129+
public IByteSource ToByteSource() => ByteSource.FromBytes(bitmap);
130+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using DotnetPackaging.Hfs.BTree;
2+
3+
namespace DotnetPackaging.Hfs.Attributes;
4+
5+
/// <summary>
6+
/// HFS+ Attributes B-Tree.
7+
/// Stores extended attributes for files and folders.
8+
/// For simple volumes, this tree may be empty.
9+
/// </summary>
10+
public sealed class AttributesBTree
11+
{
12+
private readonly BTreeFile btree;
13+
14+
public AttributesBTree(int nodeSize = 4096)
15+
{
16+
// Attribute key max length: fsck_hfs expects 266
17+
btree = new BTreeFile(nodeSize, maxKeyLength: 266);
18+
}
19+
20+
/// <summary>
21+
/// Gets the underlying B-tree.
22+
/// </summary>
23+
public BTreeFile BTree => btree;
24+
25+
/// <summary>
26+
/// Gets the total size in bytes.
27+
/// </summary>
28+
public int TotalSize => btree.TotalSize;
29+
30+
/// <summary>
31+
/// Serializes to bytes.
32+
/// </summary>
33+
public byte[] ToBytes() => btree.ToBytes();
34+
35+
/// <summary>
36+
/// Creates an IByteSource.
37+
/// </summary>
38+
public IByteSource ToByteSource() => btree.ToByteSource();
39+
}

0 commit comments

Comments
 (0)