-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 81bbedf
Showing
32 changed files
with
2,718 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
bin | ||
obj | ||
publish | ||
.vs | ||
.idea | ||
.vscode | ||
*.user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using DiskPartitionInfo.FluentApi; | ||
|
||
namespace DiskPartitionInfo | ||
{ | ||
public static class DiskPartitionInfo | ||
{ | ||
public static IMbrReader ReadMbr() | ||
=> new MbrReader(); | ||
|
||
public static IGptReaderLocation ReadGpt() | ||
=> new GptReader(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Runtime.InteropServices; | ||
|
||
namespace DiskPartitionInfo.Extensions | ||
{ | ||
internal static class ByteArrayExtensions | ||
{ | ||
internal static T ToStruct<T>(this byte[] bytes) | ||
where T : struct | ||
{ | ||
T result; | ||
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); | ||
|
||
try | ||
{ | ||
result = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject())!; | ||
} | ||
finally | ||
{ | ||
handle.Free(); | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// TODO: Deduplicate this and the MbrReader.Windows.cs | ||
#pragma warning disable CA1416 // This call site is reachable on all platforms. | ||
#if Windows | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Management; | ||
using DiskPartitionInfo.Gpt; | ||
|
||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
internal partial class GptReader | ||
{ | ||
/// <inheritdoc/> | ||
public GuidPartitionTable FromPhysicalDriveNumber(int driveNumber) | ||
=> FromPath(@"\\.\PhysicalDrive" + driveNumber); | ||
|
||
/// <inheritdoc/> | ||
public GuidPartitionTable FromVolumeLetter(string volumeLetter) | ||
{ | ||
if (!volumeLetter.EndsWith(':')) | ||
volumeLetter += ':'; | ||
|
||
var partition = GetPartitions(volumeLetter).FirstOrDefault(); | ||
|
||
if (partition is null) | ||
throw new ArgumentException( | ||
$"Could not find a drive for volume {volumeLetter}", nameof(volumeLetter)); | ||
|
||
var drive = GetDrives(partition["DeviceID"].ToString()!).FirstOrDefault(); | ||
|
||
if (drive is null) | ||
throw new ArgumentException( | ||
$"Could not find a drive for volume {volumeLetter}", nameof(volumeLetter)); | ||
|
||
return FromPath(drive["DeviceID"].ToString()!); | ||
} | ||
|
||
private static IEnumerable<ManagementBaseObject> GetPartitions(string volumeLetter) | ||
=> ExecuteWmicQuery($@" | ||
ASSOCIATORS OF | ||
{{Win32_LogicalDisk.DeviceID='{volumeLetter}'}} | ||
WHERE | ||
AssocClass = Win32_LogicalDiskToPartition"); | ||
|
||
private static IEnumerable<ManagementBaseObject> GetDrives(string partitionId) | ||
=> ExecuteWmicQuery($@" | ||
ASSOCIATORS OF | ||
{{Win32_DiskPartition.DeviceID='{partitionId}'}} | ||
WHERE | ||
AssocClass = Win32_DiskDriveToDiskPartition"); | ||
|
||
private static IEnumerable<ManagementBaseObject> ExecuteWmicQuery(string query) | ||
{ | ||
var queryResults = new ManagementObjectSearcher(query); | ||
var result = queryResults.Get(); | ||
|
||
return result is null | ||
? Enumerable.Empty<ManagementBaseObject>() | ||
: result.OfType<ManagementBaseObject>(); | ||
} | ||
} | ||
} | ||
#endif | ||
#pragma warning restore CA1416 // This call site is reachable on all platforms. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using DiskPartitionInfo.Extensions; | ||
using DiskPartitionInfo.Gpt; | ||
using GptPartitionStruct = DiskPartitionInfo.Models.GptPartitionEntry; | ||
using GptStruct = DiskPartitionInfo.Models.GuidPartitionTable; | ||
|
||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
internal partial class GptReader : IGptReader, IGptReaderLocation | ||
{ | ||
private const int SectorSize = 512; | ||
|
||
private bool _usePrimary = true; | ||
|
||
/// <inheritdoc/> | ||
public IGptReader Primary() | ||
{ | ||
_usePrimary = true; | ||
return this; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public IGptReader Secondary() | ||
{ | ||
_usePrimary = false; | ||
return this; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public GuidPartitionTable FromPath(string path) | ||
{ | ||
using var stream = File.OpenRead(path); | ||
|
||
return FromStream(stream); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public GuidPartitionTable FromStream(Stream stream) | ||
{ | ||
if (_usePrimary) | ||
stream.Seek(SectorSize, SeekOrigin.Begin); | ||
else | ||
stream.Seek(-1 * SectorSize, SeekOrigin.End); | ||
|
||
var gpt = ReadGpt(stream); | ||
|
||
stream.Seek((long) gpt.PartitionsArrayLba * SectorSize, SeekOrigin.Begin); | ||
|
||
var partitions = ReadPartitions(stream, gpt); | ||
|
||
return new GuidPartitionTable(gpt, partitions); | ||
} | ||
|
||
private static GptStruct ReadGpt(Stream stream) | ||
{ | ||
var gptData = new byte[SectorSize]; | ||
stream.Read(buffer: gptData, offset: 0, count: SectorSize); | ||
|
||
return gptData.ToStruct<GptStruct>(); | ||
} | ||
|
||
private static List<GptPartitionStruct> ReadPartitions(Stream stream, GptStruct gpt) | ||
{ | ||
var partitions = new List<GptPartitionStruct>(); | ||
|
||
for (var i = 0; i < gpt.PartitionsCount; ++i) | ||
{ | ||
var partition = new byte[gpt.PartitionEntryLength]; | ||
|
||
stream.Read(buffer: partition, offset: 0, count: (int) gpt.PartitionEntryLength); | ||
partitions.Add(partition.ToStruct<GptPartitionStruct>()); | ||
} | ||
|
||
return partitions; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System.IO; | ||
using DiskPartitionInfo.Gpt; | ||
|
||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
public interface IGptReader | ||
{ | ||
#if Windows | ||
/// <summary> | ||
/// Reads the GPT from the physical drive given its number. | ||
/// </summary> | ||
/// <param name="driveNumber">Drive number, e.g. 0 or 3.</param> | ||
/// <returns>The GUID Partition Table information.</returns> | ||
GuidPartitionTable FromPhysicalDriveNumber(int driveNumber); | ||
|
||
/// <summary> | ||
/// Reads the GPT record from the physical drive given a volume letter. | ||
/// GPT will be read from the corresponding physical drive if it exists. | ||
/// </summary> | ||
/// <param name="volumeLetter">Volume letter, e.g. C: or F:.</param> | ||
/// <returns>The GUID Partition Table information.</returns> | ||
GuidPartitionTable FromVolumeLetter(string volumeLetter); | ||
#endif | ||
|
||
/// <summary> | ||
/// Reads the GPT from the given path. | ||
/// It can be a path to a file or to a physical drive. | ||
/// </summary> | ||
/// <param name="path">Path to disk or file to read from, | ||
/// e.g. C:\GPT.bin or ../disk.img.</param> | ||
/// <returns>The GUID Partition Table information.</returns> | ||
GuidPartitionTable FromPath(string path); | ||
|
||
/// <summary> | ||
/// Reads the GPT from the given stream. | ||
/// The stream is not automatically closed after read operation. | ||
/// </summary> | ||
/// <param name="stream">Stream to read from.</param> | ||
/// <returns>The GUID Partition Table information.</returns> | ||
GuidPartitionTable FromStream(Stream stream); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
public interface IGptReaderLocation | ||
{ | ||
/// <summary> | ||
/// Read the primary GPT located at the beginning of the disk. | ||
/// </summary> | ||
IGptReader Primary(); | ||
|
||
/// <summary> | ||
/// Read the secondary GPT located at the end of the disk. | ||
/// </summary> | ||
IGptReader Secondary(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System.IO; | ||
using DiskPartitionInfo.Mbr; | ||
|
||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
public interface IMbrReader | ||
{ | ||
#if Windows | ||
/// <summary> | ||
/// Reads the MBR from the physical drive given its number. | ||
/// </summary> | ||
/// <param name="driveNumber">Drive number, e.g. 0 or 3.</param> | ||
/// <returns>The Master Boot Record information.</returns> | ||
MasterBootRecord FromPhysicalDriveNumber(int driveNumber); | ||
|
||
/// <summary> | ||
/// Reads the MBR record from the physical drive given a volume letter. | ||
/// MBR will be read from the corresponding physical drive if it exists. | ||
/// </summary> | ||
/// <param name="volumeLetter">Volume letter, e.g. C: or F:.</param> | ||
/// <returns>The Master Boot Record information.</returns> | ||
MasterBootRecord FromVolumeLetter(string volumeLetter); | ||
#endif | ||
|
||
/// <summary> | ||
/// Reads the MBR from the given path. | ||
/// It can be a path to a file or to a physical drive. | ||
/// </summary> | ||
/// <param name="path">Path to disk or file to read from, | ||
/// e.g. C:\MBR.bin or ../disk.img.</param> | ||
/// <returns>The Master Boot Record information.</returns> | ||
MasterBootRecord FromPath(string path); | ||
|
||
/// <summary> | ||
/// Reads the MBR from the given stream. | ||
/// The stream is not automatically closed after read operation. | ||
/// </summary> | ||
/// <param name="stream">Stream to read from.</param> | ||
/// <returns>The Master Boot Record information.</returns> | ||
MasterBootRecord FromStream(Stream stream); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#pragma warning disable CA1416 // This call site is reachable on all platforms. | ||
#if Windows | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Management; | ||
using DiskPartitionInfo.Mbr; | ||
|
||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
internal partial class MbrReader : IMbrReader | ||
{ | ||
/// <inheritdoc/> | ||
public MasterBootRecord FromPhysicalDriveNumber(int driveNumber) | ||
=> FromPath(@"\\.\PhysicalDrive" + driveNumber); | ||
|
||
/// <inheritdoc/> | ||
public MasterBootRecord FromVolumeLetter(string volumeLetter) | ||
{ | ||
if (!volumeLetter.EndsWith(':')) | ||
volumeLetter += ':'; | ||
|
||
var partition = GetPartitions(volumeLetter).FirstOrDefault(); | ||
|
||
if (partition is null) | ||
throw new ArgumentException( | ||
$"Could not find a drive for volume {volumeLetter}", nameof(volumeLetter)); | ||
|
||
var drive = GetDrives(partition["DeviceID"].ToString()!).FirstOrDefault(); | ||
|
||
if (drive is null) | ||
throw new ArgumentException( | ||
$"Could not find a drive for volume {volumeLetter}", nameof(volumeLetter)); | ||
|
||
return FromPath(drive["DeviceID"].ToString()!); | ||
} | ||
|
||
private static IEnumerable<ManagementBaseObject> GetPartitions(string volumeLetter) | ||
=> ExecuteWmicQuery($@" | ||
ASSOCIATORS OF | ||
{{Win32_LogicalDisk.DeviceID='{volumeLetter}'}} | ||
WHERE | ||
AssocClass = Win32_LogicalDiskToPartition"); | ||
|
||
private static IEnumerable<ManagementBaseObject> GetDrives(string partitionId) | ||
=> ExecuteWmicQuery($@" | ||
ASSOCIATORS OF | ||
{{Win32_DiskPartition.DeviceID='{partitionId}'}} | ||
WHERE | ||
AssocClass = Win32_DiskDriveToDiskPartition"); | ||
|
||
private static IEnumerable<ManagementBaseObject> ExecuteWmicQuery(string query) | ||
{ | ||
var queryResults = new ManagementObjectSearcher(query); | ||
var result = queryResults.Get(); | ||
|
||
return result is null | ||
? Enumerable.Empty<ManagementBaseObject>() | ||
: result.OfType<ManagementBaseObject>(); | ||
} | ||
} | ||
} | ||
#endif | ||
#pragma warning restore CA1416 // This call site is reachable on all platforms. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System.IO; | ||
using DiskPartitionInfo.Extensions; | ||
using DiskPartitionInfo.Mbr; | ||
using DiskPartitionInfo.Models; | ||
|
||
namespace DiskPartitionInfo.FluentApi | ||
{ | ||
internal partial class MbrReader : IMbrReader | ||
{ | ||
private const int MbrLength = 512; | ||
|
||
/// <inheritdoc/> | ||
public MasterBootRecord FromPath(string path) | ||
{ | ||
using var stream = File.OpenRead(path); | ||
|
||
return FromStream(stream); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public MasterBootRecord FromStream(Stream stream) | ||
{ | ||
var data = new byte[MbrLength]; | ||
stream.Read(buffer: data, offset: 0, count: MbrLength); | ||
|
||
var mbr = data.ToStruct<ClassicalMasterBootRecord>(); | ||
return new MasterBootRecord(mbr); | ||
} | ||
} | ||
} |
Oops, something went wrong.