Skip to content
Open
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
4 changes: 2 additions & 2 deletions DiscUtils.Ebs/DiskExtent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ public DiskExtent(DiskImageFile ebsDisk) {

while (response == null || response.NextToken != null) {

response = EbsDisk.EbsClient.ListSnapshotBlocks(new ListSnapshotBlocksRequest {
response = EbsDisk.EbsClient.ListSnapshotBlocksAsync(new ListSnapshotBlocksRequest {
MaxResults = 500,
SnapshotId = EbsDisk.SnapshotId,
NextToken = response?.NextToken
});
}).GetAwaiter().GetResult();

foreach(var block in response.Blocks) {
SnapshotBlocks[block.BlockIndex] = new Block(block.BlockIndex, block.BlockToken);
Expand Down
4 changes: 2 additions & 2 deletions DiscUtils.Ebs/DiskImageFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ public DiskImageFile(string snapshotId, AWSCredentials credentials, RegionEndpoi
SnapshotId = snapshotId;
EbsClient = new AmazonEBSClient(credentials.GetCredentials().AccessKey, credentials.GetCredentials().SecretKey, region);

var result = EbsClient.ListSnapshotBlocks(new ListSnapshotBlocksRequest() {
var result = EbsClient.ListSnapshotBlocksAsync(new ListSnapshotBlocksRequest() {
MaxResults = 1,
SnapshotId = snapshotId
});
}).GetAwaiter().GetResult();

if (result.HttpStatusCode != HttpStatusCode.OK)
throw new AmazonEBSException($"Failed to query EBS block with error {result.HttpStatusCode}");
Expand Down
8 changes: 4 additions & 4 deletions DiscUtils.Ebs/EbsMappedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ public EbsMappedStream(string snapshotId, AWSCredentials credentials, RegionEndp

while (response == null || response.NextToken != null) {

response = EbsClient.ListSnapshotBlocks(new ListSnapshotBlocksRequest {
response = EbsClient.ListSnapshotBlocksAsync(new ListSnapshotBlocksRequest {
MaxResults = 500,
SnapshotId = SnapshotId,
StartingBlockIndex = 0,
NextToken = response?.NextToken
});
}).GetAwaiter().GetResult();

if (response.HttpStatusCode != HttpStatusCode.OK)
throw new AmazonEBSException($"Failed to query EBS block with error {response.HttpStatusCode}");
Expand Down Expand Up @@ -94,11 +94,11 @@ public override int Read(byte[] buffer, int offset, int count) {

void GetBlockData(Block block, byte[] buffer, int offset) {

var result = EbsClient.GetSnapshotBlock(new GetSnapshotBlockRequest() {
var result = EbsClient.GetSnapshotBlockAsync(new GetSnapshotBlockRequest() {
BlockIndex = block.Index,
BlockToken = block.Token,
SnapshotId = SnapshotId
});
}).GetAwaiter().GetResult();

if(result.HttpStatusCode != System.Net.HttpStatusCode.OK) {
throw new IOException($"Failed to read EBS block {block.Index} with HTTP error {result.HttpStatusCode}");
Expand Down
53 changes: 46 additions & 7 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,34 @@ static VirtualDisk GetEBSDiskImage(string snapshotId, string profile, string aws
}

static VirtualDisk GetLocalDiskImage(string path) {
return VirtualDisk.OpenDisk(path, FileAccess.Read);

// DiscUtils 0.16.13's generic VirtualDisk.OpenDisk(path) routes through a
// file locator that hardcodes a Windows '\' path separator, which breaks on
// Linux/macOS (e.g. "/tmp\/disk.img"). The per-format path constructors use
// a working locator, so dispatch by extension to those instead. Using the
// path (not stream) constructor is important: multi-extent disks (e.g. a
// VMDK descriptor pointing at -flat/-s001 extents) need the locator to
// resolve their sibling files. The stream constructor only handles
// self-contained images and throws "Unknown type" / "Only Monolithic
// Sparse ... can be accessed via a stream" for split/flat disks.
var ext = Path.GetExtension(path).ToLowerInvariant();

switch (ext) {
case ".vhd":
return new DiscUtils.Vhd.Disk(path, FileAccess.Read);
case ".vhdx":
return new DiscUtils.Vhdx.Disk(path, FileAccess.Read);
case ".vmdk":
return new DiscUtils.Vmdk.Disk(path, FileAccess.Read);
case ".dmg":
// Dmg has no path constructor; it is always a single self-contained file.
return new DiscUtils.Dmg.Disk(
new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read),
Ownership.Dispose);
default:
// .img/.raw/.dd/.bin and anything else: treat as a raw sector image.
return new DiscUtils.Raw.Disk(path, FileAccess.Read);
}
}


Expand Down Expand Up @@ -160,19 +187,19 @@ static void Main(string[] args) {

foreach (var file in fs.GetDirectories(filePath)) {
var dirInfo = fs.GetDirectoryInfo(file);
Console.WriteLine($"{dirInfo.LastWriteTimeUtc} {"DIR",-15} {Path.GetFileName(file)}");
Console.WriteLine($"{dirInfo.LastWriteTimeUtc} {"DIR",-15} {LeafName(file)}");
}

foreach (var file in fs.GetFiles(filePath)) {
var fileInfo = fs.GetFileInfo(file);
Console.WriteLine($"{fileInfo.LastWriteTimeUtc} { $"{fileInfo.Length / 1024.0 / 1024.0: 0.00}MB",-16} {Path.GetFileName(file)}");
Console.WriteLine($"{fileInfo.LastWriteTimeUtc} { $"{fileInfo.Length / 1024.0 / 1024.0: 0.00}MB",-16} {LeafName(file)}");
}

} else {

var fileStream = fs.OpenFile(filePath, FileMode.Open, FileAccess.Read);
Console.WriteLine($"[+] Opened file with path {filePath} for with size: {fileStream.Length}");
File.WriteAllBytes(Path.GetFileName(filePath), StreamUtilities.ReadExact(fileStream, (int)fileStream.Length));
File.WriteAllBytes(LeafName(filePath), StreamUtilities.ReadExact(fileStream, (int)fileStream.Length));
}
}
} else {
Expand Down Expand Up @@ -255,7 +282,7 @@ private static void UI_ItemChanged(string itemValue) {
static private async Task DownloadFile(string volumePath) {

using (var fileStream = CurrentFileSystem.OpenFile(volumePath, FileMode.Open, FileAccess.Read)) {
using (var outputStream = new FileStream(Path.GetFileName(volumePath), FileMode.OpenOrCreate, FileAccess.ReadWrite)) {
using (var outputStream = new FileStream(LeafName(volumePath), FileMode.OpenOrCreate, FileAccess.ReadWrite)) {
byte[] buffer = new byte[512 * 1024];
long totalRead = 0;

Expand Down Expand Up @@ -340,6 +367,18 @@ private static void Ui_ItemSelected(string itemValue) {
}
}

// DiscUtils returns in-disk paths using the volume's separator (e.g. '\' for
// NTFS/FAT). Path.GetFileName only strips the host OS separator, so on Linux it
// leaves the whole "\Windows\..." path intact in listings and download output
// filenames. Take the leaf after either separator so behaviour matches Windows.
static string LeafName(string path) {
if (string.IsNullOrEmpty(path)) {
return path;
}
int idx = path.LastIndexOfAny(new[] { '\\', '/' });
return idx < 0 ? path : path.Substring(idx + 1);
}

static string GetHumanSize(long size) {
if (size < 1024) {
return $"{size}";
Expand All @@ -356,8 +395,8 @@ static string GetHumanSize(long size) {

private static void UpdateView() {
UI.UpdateCurrentPathItems(new string[] { ".." }
.Concat(CurrentFileSystem.GetDirectories(CurrentPath).Select(pi => Path.GetFileName(pi))
.Concat(CurrentFileSystem.GetFiles(CurrentPath)).Select(pi => Path.GetFileName(pi)))
.Concat(CurrentFileSystem.GetDirectories(CurrentPath).Select(pi => LeafName(pi))
.Concat(CurrentFileSystem.GetFiles(CurrentPath)).Select(pi => LeafName(pi)))
.ToList());
}
}
Expand Down
7 changes: 2 additions & 5 deletions Volumiser.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand All @@ -11,10 +12,6 @@
<PackageReference Include="DiscUtils.Containers" Version="0.16.13" />
<PackageReference Include="DiscUtils.FileSystems" Version="0.16.13" />
<PackageReference Include="DiscUtils.Lvm" Version="0.16.13" />
<PackageReference Include="dnMerge" Version="0.5.15">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Terminal.Gui" Version="1.8.2" />
</ItemGroup>

Expand Down