} // End BeginProcessing protected override void ProcessRecord() { MasterBootRecord mbr = MasterBootRecord.Get(drivePath); if (mbr.PartitionTable[0].SystemID == "EFI_GPT_DISK") { if (asBytes) { WriteObject(GuidPartitionTable.GetBytes(drivePath)); } else { WriteObject(new GuidPartitionTable(drivePath)); } } else { if (asBytes) { WriteObject(MasterBootRecord.GetBytes(drivePath)); } else { WriteObject(mbr); } } } // End ProcessRecord
public static void Main4(string[] args) { string label = "Zap!"; long capacity = 2L << 40; int blockSize = 4 << 20; using (var diskStream = File.Create("big.vhdx")) using (var disk = Disk.InitializeDynamic(diskStream, Ownership.Dispose, capacity, blockSize)) { var gpt = GuidPartitionTable.Initialize(disk); gpt.Create(gpt.FirstUsableSector, gpt.LastUsableSector, GuidPartitionTypes.WindowsBasicData, 0, null); var volume = VolumeManager.GetPhysicalVolumes(disk).First(); uint bytesPerSector = (uint)(volume.PhysicalGeometry?.BytesPerSector ?? 512); var clusterCount = 1 << 25;// uint.MaxValue - 16; var clusterSize = capacity / clusterCount; var clusterBits = (int)Math.Ceiling(Math.Log(clusterSize) / Math.Log(2)); if (clusterBits > 18) { clusterBits = 18; } //clusterBits = 20; using (var fs = ExFatFileSystem.Format(volume, new ExFatFormatOptions { SectorsPerCluster = (1u << clusterBits) / bytesPerSector }, label: label)) { } } }
private void btnOK_Click(object sender, EventArgs e) { long firstUsableLBA = 64; // for alignment purposes long reservedPartitionSizeInMB = (long)numericMicrosoftReservedPartitionSize.Value; long bytesAvailable = (m_disk.TotalSectors - firstUsableLBA) * m_disk.BytesPerSector; if (reservedPartitionSizeInMB * 1024 * 1024 > bytesAvailable) { MessageBox.Show("Invalid Reserved Partition Size specified, not enough space on the disk.", "Error"); return; } if (m_disk is PhysicalDisk) { bool success = ((PhysicalDisk)m_disk).ExclusiveLock(); if (!success) { MessageBox.Show("Failed to lock the disk.", "Error"); return; } } long reservedPartitionSizeLBA = reservedPartitionSizeInMB * 1024 * 1024 / m_disk.BytesPerSector; GuidPartitionTable.InitializeDisk(m_disk, firstUsableLBA, reservedPartitionSizeLBA); if (m_disk is PhysicalDisk) { ((PhysicalDisk)m_disk).ReleaseLock(); ((PhysicalDisk)m_disk).UpdateProperties(); } this.DialogResult = DialogResult.OK; this.Close(); }
protected override void ProcessRecord() { MasterBootRecord mbr = MasterBootRecord.Get(drivePath); if (mbr.PartitionTable[0].SystemID != "EFI_GPT_DISK") { foreach (PartitionEntry partition in mbr.PartitionTable) { if (partition.SystemID != "EMPTY") { WriteObject(partition); } else if (partition.SystemID.Contains("EXTENDED")) { // Add code to parse EXTENDED partitions } } } else { GuidPartitionTable gpt = new GuidPartitionTable(drivePath); foreach (GuidPartitionTableEntry entry in gpt.PartitionTable) { WriteObject(entry); } } }
public static bool IsDynamicDisk(Disk disk) { MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(disk); if (mbr != null) { if (mbr.PartitionTable[0].PartitionType == (byte)PartitionTypeName.DynamicData) { return(true); } else if (mbr.IsGPTBasedDisk) { List <GuidPartitionEntry> entries = GuidPartitionTable.ReadEntriesFromDisk(disk); if (entries != null) { if (GuidPartitionEntryCollection.ContainsPartitionTypeGuid(entries, GPTPartition.PrivateRegionPartitionTypeGuid) && GuidPartitionEntryCollection.ContainsPartitionTypeGuid(entries, GPTPartition.PublicRegionPartitionTypeGuid)) { return(true); } } } return(false); } else { // if the disk has no master boot record, it can be a dynamic disk if it has a valid PrivateHeader at sector 6 PrivateHeader privateHeader = PrivateHeader.ReadFromDiskStart(disk); return(privateHeader != null); } }
public static Geometry FindGeometry(Stream stream) { var geometryType = "UNKN"; Geometry geometry = null; // Always check GPT first as it as an MBR-encapsulated partition scheme if (GuidPartitionTable.Detect(stream)) { geometry = GuidPartitionTable.DetectGeometry(stream); geometryType = "GPT"; } else if (BiosPartitionTable.IsValid(stream)) { geometry = BiosPartitionTable.DetectGeometry(stream); geometryType = "MBR"; } if (geometry == null) { Logger.Warn("Could not find valid partitioning table to read geometry"); return(Geometry.FromCapacity(stream.Length)); } Logger.Info("{0}/BPS:{1}; SPT:{2}; HPC:{3}; CL:{4}; TS:{5}; CP:{6}", geometryType, geometry.BytesPerSector, geometry.SectorsPerTrack, geometry.HeadsPerCylinder, geometry.Cylinders, geometry.TotalSectorsLong, geometry.Capacity); return(geometry); }
protected override void ProcessRecord() { MasterBootRecord mbr = MasterBootRecord.Get(drivePath); if (mbr.PartitionTable[0].SystemID != "EFI_GPT_DISK") { foreach (PartitionEntry partition in mbr.PartitionTable) { if (partition.SystemID != "EMPTY") { WriteObject(partition); } else if (partition.SystemID.Contains("EXTENDED")) { // Add code to parse EXTENDED partitions } } } else { GuidPartitionTable gpt = new GuidPartitionTable(drivePath); foreach (GuidPartitionTableEntry entry in gpt.PartitionTable) { WriteObject(entry); } } } // ProcessRecord
public static PartitionTable FindPartitionTable(Stream stream) { PartitionTable partitionTable = null; // Always check GPT first as it as an MBR-encapsulated partition scheme if (GuidPartitionTable.Detect(stream)) { partitionTable = new GuidPartitionTable( stream, GuidPartitionTable.DetectGeometry(stream)); Logger.Info("Detected partition table: GPT"); } else if (BiosPartitionTable.IsValid(stream)) { partitionTable = new BiosPartitionTable( stream, BiosPartitionTable.DetectGeometry(stream)); Logger.Info("Detected partition table: MBR"); } if (partitionTable == null) { Logger.Info("Could not find valid partition table"); return(null); } return(partitionTable); }
private void CreateVhdx(bool allowKeepDebug, long length) { var diskStream = CreateVhdxStream(allowKeepDebug); Disk = Disk.InitializeDynamic(diskStream, Ownership.Dispose, length, 128 << 20); var gpt = GuidPartitionTable.Initialize(Disk); gpt.Create(gpt.FirstUsableSector, gpt.LastUsableSector, GuidPartitionTypes.WindowsBasicData, 0, null); var volume = VolumeManager.GetPhysicalVolumes(Disk).First(); uint bytesPerSector = (uint)(volume.PhysicalGeometry?.BytesPerSector ?? 512); var clusterCount = 1 << 25; var clusterSize = length / clusterCount; var clusterBits = (int)Math.Ceiling(Math.Log(clusterSize) / Math.Log(2)); if (clusterBits > 18) { clusterBits = 18; } else if (clusterBits < 11) { clusterBits = 11; } FileSystem = ExFatEntryFilesystem.Format(volume.Open(), new ExFatFormatOptions { SectorsPerCluster = (1u << clusterBits) / bytesPerSector }); }
private void ResizeVolume() { long additionalNumberOfSectors = m_additionalNumberOfBytes / m_volume.BytesPerSector; btnBack.Enabled = false; btnNext.Enabled = false; m_processing = true; m_resizeTimer = new System.Windows.Forms.Timer(); m_resizeTimer.Interval = 1000; m_resizeTimer.Tick += new EventHandler(ResizeTimer_Tick); m_resizeTimer.Start(); Thread thread = new Thread(delegate() { // Because of performance implications, we must fill the container // before writing the updated TrueCrypt header to the end of the container. // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2011/09/22/10215053.aspx long oldSize = m_disk.Size; m_bytesToFill = additionalNumberOfSectors * m_disk.BytesPerSector; try { m_disk.Extend(m_bytesToFill); } catch (IOException ex) { MessageBox.Show(ex.Message, "Error"); this.Invoke((MethodInvoker) delegate() { btnBack.Enabled = true; btnNext.Enabled = true; }); return; } if (chkFillWithRandomData.Checked) { TrueCryptResize.FillAllocatedSpaceWithData(m_disk, oldSize, ref m_bytesFilled); } MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(m_disk); if (mbr != null && mbr.IsGPTBasedDisk) { GuidPartitionTable.RebaseDisk(m_disk, mbr); } m_resizeStatus = TrueCryptResize.ExtendVolumeAndFileSystem(m_disk, m_password, additionalNumberOfSectors); // reinitialize the partition / volume m_partition = VolumeSelectionHelper.GetLastPartition(m_disk); m_volume = new TrueCryptVolume(m_partition, m_password); m_processing = false; }); thread.Start(); if (chkFillWithRandomData.Checked) { progressBarFillWithRandomData.Visible = true; } }
} // End BeginProcessing protected override void ProcessRecord() { if (asBytes) { WriteObject(GuidPartitionTable.GetBytes(drivePath)); } else { WriteObject(new GuidPartitionTable(drivePath)); } } // End ProcessRecord
public void Initialize() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); Assert.Equal(0, table.Count); } }
public Nand(Stream stream, Keyset keyset) { var disc = new GuidPartitionTable(stream, Geometry.Null); GuidPartitionInfo[] partitions = disc.Partitions.Select(x => (GuidPartitionInfo)x).ToArray(); ProdInfo = partitions.FirstOrDefault(x => x.Name == "PRODINFO"); ProdInfoF = partitions.FirstOrDefault(x => x.Name == "PRODINFOF"); Safe = partitions.FirstOrDefault(x => x.Name == "SAFE"); System = partitions.FirstOrDefault(x => x.Name == "SYSTEM"); User = partitions.FirstOrDefault(x => x.Name == "USER"); Keyset = keyset; }
private static void CreateVirtualDisk(string filePath, int size) { using (FileStream fsStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) using (VirtualDisk disk = DiscUtils.Vhd.Disk.InitializeDynamic(fsStream, DiscUtils.Streams.Ownership.Dispose, size * 1024 * 1024)) { GuidPartitionTable.Initialize(disk, WellKnownPartitionType.WindowsNtfs); PhysicalVolumeInfo volume = VolumeManager.GetPhysicalVolumes(disk)[0]; NtfsFileSystem.Format(volume, "CryptoBox"); } }
/// <summary> /// The ProcessRecord instantiates a MasterBootRecord Object /// and outputs all Partitions that are not of the EMPTY type /// </summary> protected override void ProcessRecord() { MasterBootRecord mbr = MasterBootRecord.Get(drivePath); if (mbr.PartitionTable[0].SystemId != "EFI_GPT_DISK") { WriteObject(mbr.GetPartitionTable(), true); } else { WriteObject(GuidPartitionTable.Get(drivePath).GetPartitionTable(), true); } }
/// <summary> /// The ProcessRecord instantiates a MasterBootRecord Object /// and outputs all Partitions that are not of the EMPTY type /// </summary> protected override void ProcessRecord() { MasterBootRecord mbr = MasterBootRecord.Get(drivePath); if (mbr.PartitionTable[0].SystemID != "EFI_GPT_DISK") { WriteObject(mbr.GetPartitionTable(), true); } else { GuidPartitionTable gpt = new GuidPartitionTable(drivePath); WriteObject(gpt.GetPartitionTable(), true); } }
public void CreateSmallWholeDisk() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.Create(WellKnownPartitionType.WindowsFat, true); // Make sure the partition fills from first to last usable. Assert.Equal(table.FirstUsableSector, table[idx].FirstSector); Assert.Equal(table.LastUsableSector, table[idx].LastSector); } }
public void CreateBySize() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 3 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.Create(2 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false); // Make sure the partition is within 10% of the size requested. Assert.True((2 * 1024 * 2) * 0.9 < table[idx].SectorCount); Assert.Equal(table.FirstUsableSector, table[idx].FirstSector); } }
public void CreateBySizeInGap() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 300 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); table.Create(10 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false); table.Create((20 * 1024 * 1024) / 512, ((30 * 1024 * 1024) / 512) - 1, GuidPartitionTypes.WindowsBasicData, 0, "Data Partition"); table.Create((60 * 1024 * 1024) / 512, ((70 * 1024 * 1024) / 512) - 1, GuidPartitionTypes.WindowsBasicData, 0, "Data Partition"); int idx = table.Create(20 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false); Assert.Equal(((30 * 1024 * 1024) / 512), table[idx].FirstSector); Assert.Equal(((50 * 1024 * 1024) / 512) - 1, table[idx].LastSector); } }
public void CreateLargeWholeDisk() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 200 * 1024L * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.Create(WellKnownPartitionType.WindowsFat, true); Assert.Equal(2, table.Partitions.Count); Assert.Equal(GuidPartitionTypes.MicrosoftReserved, table[0].GuidType); Assert.Equal(128 * 1024 * 1024, table[0].SectorCount * 512); // Make sure the partition fills from first to last usable, allowing for MicrosoftReserved sector. Assert.Equal(table[0].LastSector + 1, table[idx].FirstSector); Assert.Equal(table.LastUsableSector, table[idx].LastSector); } }
public void Delete() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 10 * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); Assert.Equal(0, table.Create(1 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false)); Assert.Equal(1, table.Create(2 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false)); Assert.Equal(2, table.Create(3 * 1024 * 1024, WellKnownPartitionType.WindowsFat, false)); long[] sectorCount = new long[] { table[0].SectorCount, table[1].SectorCount, table[2].SectorCount }; table.Delete(1); Assert.Equal(2, table.Count); Assert.Equal(sectorCount[2], table[1].SectorCount); } }
bool GetGptPartitionTable(out GuidPartitionTable partitionTable) { try { partitionTable = new GuidPartitionTable(_fs, DiskGeometry); } catch (Exception) { partitionTable = null; } // CHECKME: Count refers to the number of PARTITION TABLES, not partitions? if (partitionTable == null || partitionTable.Count <= 0) { Debug.WriteLine("No GPT partition table detected"); return(false); } return(true); }
public void DeviceValue_Gpt() { SparseMemoryStream ms = new SparseMemoryStream(); ms.SetLength(80 * 1024 * 1024); GuidPartitionTable gpt = GuidPartitionTable.Initialize(ms, Geometry.FromCapacity(ms.Length)); gpt.Create(WellKnownPartitionType.WindowsNtfs, true); VolumeManager volMgr = new VolumeManager(ms); RegistryHive hive = RegistryHive.Create(new MemoryStream()); Store s = Store.Initialize(hive.Root); BcdObject obj = s.CreateInherit(InheritType.AnyObject); Element el = obj.AddElement(WellKnownElement.LibraryApplicationDevice, ElementValue.ForDevice(Guid.Empty, volMgr.GetPhysicalVolumes()[0])); el = obj.GetElement(WellKnownElement.LibraryApplicationDevice); Assert.IsNotNullOrEmpty(el.Value.ToString()); }
public Nand(Stream stream, Keyset keyset) { var disc = new GuidPartitionTable(stream, Geometry.Null); GuidPartitionInfo[] partitions = disc.Partitions.Select(x => (GuidPartitionInfo)x).ToArray(); ProdInfo = partitions.FirstOrDefault(x => x.Name == "PRODINFO"); ProdInfoF = partitions.FirstOrDefault(x => x.Name == "PRODINFOF"); Package2 = new GuidPartitionInfo[] { partitions.FirstOrDefault(x => x.Name == "BCPKG2-1-Normal-Main"), partitions.FirstOrDefault(x => x.Name == "BCPKG2-2-Normal-Sub"), partitions.FirstOrDefault(x => x.Name == "BCPKG2-3-SafeMode-Main"), partitions.FirstOrDefault(x => x.Name == "BCPKG2-4-SafeMode-Sub"), partitions.FirstOrDefault(x => x.Name == "BCPKG2-5-Repair-Main"), partitions.FirstOrDefault(x => x.Name == "BCPKG2-6-Repair-Sub") }; Safe = partitions.FirstOrDefault(x => x.Name == "SAFE"); System = partitions.FirstOrDefault(x => x.Name == "SYSTEM"); User = partitions.FirstOrDefault(x => x.Name == "USER"); Keyset = keyset; }
public static PrivateHeader ReadFromGPTBasedDisk(Disk disk) { List <GuidPartitionEntry> entries = GuidPartitionTable.ReadEntriesFromDisk(disk); int index = GuidPartitionEntryCollection.GetIndexOfPartitionTypeGuid(entries, GPTPartition.PrivateRegionPartitionTypeGuid); // the private header will be located at the last sector of the private region PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(disk, (long)entries[index].LastLBA, true); if (privateHeader != null) { if (privateHeader.IsChecksumValid) { return(privateHeader); } else { // primary has invalid checksum, try secondary private header long sectorIndex = (long)(privateHeader.PrivateRegionStartLBA + privateHeader.SecondaryPrivateHeaderLBA); return(ReadFromDisk(disk, sectorIndex, false)); } } return(null); }
public void CreateAlignedWholeDisk() { MemoryStream ms = new MemoryStream(); using (Disk disk = Disk.InitializeDynamic(ms, Ownership.Dispose, 200 * 1024L * 1024 * 1024)) { GuidPartitionTable table = GuidPartitionTable.Initialize(disk); int idx = table.CreateAligned(WellKnownPartitionType.WindowsFat, true, 1024 * 1024); Assert.Equal(2, table.Partitions.Count); Assert.Equal(GuidPartitionTypes.MicrosoftReserved, table[0].GuidType); Assert.Equal(128 * 1024 * 1024, table[0].SectorCount * 512); // Make sure the partition is aligned Assert.Equal(0, table[idx].FirstSector % 2048); Assert.Equal(0, (table[idx].LastSector + 1) % 2048); // Ensure partition fills most of the disk Assert.True((table[idx].SectorCount * 512) > disk.Capacity * 0.9); } }
private static int StartInternal() { if (!GuidPartitionTable.Detect(mSourceStream)) { throw new InvalidDataException( "Source does not contain a supported partitioning scheme"); } Logger.Debug("Detecting disc geometry of source..."); var geometry = GuidPartitionTable.DetectGeometry(mSourceStream); Logger.Debug("Reading GPT partition table from source..."); var partitionTable = new GuidPartitionTable(mSourceStream, geometry); if (partitionTable.Count <= 0) { return(SUCCESS); // nothing to clone here } // adjust source length if (FixedLengthStream.IsFixedDiskStream(mSourceStream)) { mSourceStream.SetLength(geometry.Capacity); } Geometry destGeometry = null; if (FixedLengthStream.IsFixedDiskStream(mDestinationStream)) { // If we write to a disk, we need our own geometry for that destination destGeometry = Geometry.FromCapacity(mDestinationStream.Length, geometry.BytesPerSector); } else { // If we are just writing to a file, we take the most exact copy we get destGeometry = geometry; } // Set the new size of the destination stream Logger.Verbose("Updating length of destination: {0} -> {1}", mDestinationStream.Length, destGeometry.Capacity); mDestinationStream.SetLength(destGeometry.Capacity); if (mFullClone) { Logger.Warn("Starting full clone..."); CloneStream(0, 0, mSourceStream, mDestinationStream); return(SUCCESS); } Logger.Debug("Initializing new GPT partition table on destination..."); var destPartitionTable = GuidPartitionTable.Initialize(mDestinationStream, destGeometry); var availableSpace = destGeometry.Capacity; var usedSpace = 0L; // correct available space by remove unusable sectors // heading sectors availableSpace -= (destPartitionTable.FirstUsableSector * destGeometry.BytesPerSector); // ending sectors availableSpace -= ((destGeometry.TotalSectorsLong - destPartitionTable.FirstUsableSector - destPartitionTable.LastUsableSector) * destGeometry.BytesPerSector); // 1. calculate unresizeable space if we are required too if (destGeometry.Capacity < geometry.Capacity) { Logger.Info("Calculating space for new destination partitions..."); var unresizeableSpace = 0L; for (int i = 0; i < partitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); var srcPartitionSize = srcPartition.SectorCount * geometry.BytesPerSector; var isResizeable = true; // If the file system is not support, we have to perform // a byte-for-byte cloning and cannot resize this partition if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream)) { Logger.Verbose("Partition{0}: contains no or unsupported file system"); isResizeable = false; } // If we have a critical partition, we shouldn't resize that either if (!IsSupportedPartitionType(srcPartitionType)) { Logger.Verbose("Partition{0}: unsupported partition type"); isResizeable = false; } // if caller want to do a byte-for-byte clone, mark every partition // as unresizeable if (mForceExactCloning) { isResizeable = false; } Logger.Debug("Partition #{0} on source: isResizeable={1}", i, isResizeable); if (!isResizeable) { // if it's not resizeable, account the space and continue unresizeableSpace += srcPartitionSize; Logger.Debug("Partition #{0} on source: unresizeable, size is {1} " + "(total unresizable {2}/used {3})", i, srcPartitionSize, unresizeableSpace, usedSpace); } else { // if it is resizeable, we have to report how much space we need var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream); usedSpace += srcPartitionFS.UsedSpace; Logger.Debug("Partition #{0} on source: resizeable, space is {1} " + "(total unresizable {2}/used {3})", i, usedSpace, unresizeableSpace, usedSpace); } } // reduce the dynamically available space ... availableSpace -= unresizeableSpace; // ... and assert it if (availableSpace < 0) { throw new InvalidOperationException("Cannot clone, destination is " + String.Format("{0:#,##0}", -availableSpace) + " Bytes too small"); } // assert the used space too if (availableSpace - usedSpace < 0) { throw new InvalidOperationException("Cannot clone, destination is " + String.Format("{0:#,##0}", availableSpace - usedSpace) + " Bytes too small"); } } else { Logger.Info("Destination can contain source, no need to resize partitions!"); } // 2. calculate the size for each new partition var destPartitionSizes = new long[partitionTable.Count]; for (int i = 0; i < partitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); var srcPartitionSize = srcPartition.SectorCount * geometry.BytesPerSector; // if the destination can take more data, skip every check if (geometry.Capacity <= destGeometry.Capacity) { Logger.Debug("Partition{0}: Destination can contain full partition, continue...", i); destPartitionSizes[i] = srcPartitionSize; availableSpace -= srcPartitionSize; continue; } var isResizeable = true; // If the device-systme is not support, we have to perform // a byte-for-byte cloning and cannot resize this partition if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream)) { isResizeable = false; } // If we have a critical partition, we shouldn't resize that either if (!IsSupportedPartitionType(srcPartitionType)) { isResizeable = false; } // if caller want to do a byte-for-byte clone, mark every partition // as unresizeable if (mForceExactCloning) { isResizeable = false; } Logger.Debug("Partition #{0} on source: isResizeable={1}", i, isResizeable); // If our friend is not resizeable, set size and stop processing it if (!isResizeable) { destPartitionSizes[i] = srcPartitionSize; Logger.Debug("Partition #{0} on source: unresizeable, size is {1} " + "(total available {2}/used {3})", i, usedSpace, availableSpace, usedSpace); // DO NOT ALIGN <availableSpace> HERE!!! // Has already been done in step 1 continue; } // // OK. If we are here, a resizeable partition awaits processing // var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream); // First we need to check if we need to reqsize the current partition. // For that, calculate the space that is left for future partitions. If the // result is OK (less or equal to the available size), we can skip // resizing the the current one. // Make sure to remove the factor of this partition from usedSpace first if (((usedSpace - srcPartitionFS.UsedSpace) + srcPartitionSize) <= availableSpace) { // update usedSpace usedSpace -= srcPartitionFS.UsedSpace; // align availableSpace availableSpace -= srcPartitionSize; // we are good to skip resizing this one. assign size and early exit destPartitionSizes[i] = srcPartitionSize; Logger.Debug( "Partition #{0} on source: resizeable, space is {1}, size is {2} " + "(total available {3}/used {4})", i, srcPartitionFS.UsedSpace, srcPartitionSize, availableSpace, usedSpace); continue; } // So this partition is too large, let's resize it to the biggest size possible var maxPartitionSize = Math.Max( // Occupied space is the absolute minimal space we need srcPartitionFS.UsedSpace, // This is the largest space possible. Take the still available space // and remove still required space, while also remove the factor for // the current partition availableSpace - (usedSpace - srcPartitionFS.UsedSpace) ); Logger.Debug( "Partition #{0} on source: resizeable, max. space is {1} " + "(total available {2}/used {3})", i, maxPartitionSize, availableSpace, usedSpace); // update usedSpace usedSpace -= srcPartitionFS.UsedSpace; // align availableSpace availableSpace -= maxPartitionSize; destPartitionSizes[i] = maxPartitionSize; } // a last assert of the available space, just to be sure if (availableSpace < 0) { throw new InvalidOperationException("Cannot clone, destination is " + String.Format("{0:#.##0}", -availableSpace) + " Bytes too small"); } // 2. create the new partitions with the aligned sizes for (int i = 0; i < partitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); // manueal type adjusting if (NtfsFileSystem.Detect(srcPartitionStream)) { srcPartitionType = WellKnownPartitionType.WindowsNtfs; } else if (FatFileSystem.Detect(srcPartitionStream)) { srcPartitionType = WellKnownPartitionType.WindowsFat; } var destPartitionSize = destPartitionSizes[i]; Logger.Debug("Creating partition table: #{0}; {1}/{2}@0x{3}-{4}", i, srcPartition.Name, srcPartition.Identity, srcPartition.FirstSector.ToString("X2"), destPartitionSize); destPartitionTable.Create( destPartitionSize, srcPartitionType, true //doesn't matter on GPT tables ); } // 3. make sure the count of partitions is the same if (partitionTable.Count != destPartitionTable.Count) { throw new InvalidOperationException( "Failed to create proper GUID partition table"); } // 4. do the real cloning for (int i = 0; i < destPartitionTable.Count; i++) { var srcPartition = (GuidPartitionInfo)partitionTable[i]; var srcPartitionStream = srcPartition.Open(); var srcPartitionType = GetWellKnownPartitionType(srcPartition); var destPartition = (GuidPartitionInfo)destPartitionTable[i]; var destPartitionStream = destPartition.Open(); var destPartitionSize = destPartitionSizes[i]; var requiresExactCloning = false; // To support all possible file-systems, perform a byte-for-byte // cloning if the file-system is not supported by us. if (!DiscHandler.IsStreamSupportedFileSystem(srcPartitionStream)) { requiresExactCloning = true; } // If we have a critical partition, we should skip that one too if (srcPartitionType == WellKnownPartitionType.BiosBoot || srcPartitionType == WellKnownPartitionType.EfiSystem || srcPartitionType == WellKnownPartitionType.MicrosoftReserved) { requiresExactCloning = true; } // if caller want to do a byte-for-byte clone, let's enable it if (mForceExactCloning) { requiresExactCloning = true; } if (requiresExactCloning) { var taskId = (mTaskIdCounter++); Logger.Info("[{0}/{1}] cp-fs : {2}/{3}@0x{4}", i, taskId, srcPartition.Name, srcPartition.Identity, srcPartition.FirstSector.ToString("X2")); CloneStream(i, taskId, srcPartitionStream, destPartitionStream); } else { var srcPartitionFS = DiscHandler.GetFileSystem(srcPartitionStream); var srcPartitionBootCode = srcPartitionFS.ReadBootCode(); var destPartitionFS = DiscHandler.FormatFileSystemWithTemplate( srcPartitionStream, destPartitionStream, destPartition.FirstSector, destPartition.SectorCount, destPartitionSize ); // Tracks all NTFS file IDs for hard link recognition // <Source FS File ID, Destination FS File ID> var ntfsHardlinkTracker = new Dictionary <uint, uint>(); // last clone each single with here Action <DiscDirectoryInfo, DiscDirectoryInfo> cloneSrcFsToDestFs = null; cloneSrcFsToDestFs = new Action <DiscDirectoryInfo, DiscDirectoryInfo>( (sourceDir, destDir) => { // recursive enumeration. save to create directory without checks for // parent directories. var taskId = (mTaskIdCounter++); Logger.Info("[{0}/{1}] mk-dir : {2}", i, taskId, destDir.FullName); destDir.Create(); // copy files if there are any foreach (var sourceFile in sourceDir.GetFiles()) { var skipCopying = false; taskId = (mTaskIdCounter++); var sourceFileStream = sourceFile.Open(FileMode.Open, FileAccess.Read); var destFileName = Path.Combine(destDir.FullName, sourceFile.Name); Logger.Info("[{0}/{1}] mk-file: {2}", i, taskId, destFileName); var destFileStream = destPartitionFS.OpenFile( destFileName, FileMode.Create, FileAccess.Write); var destFile = new DiscFileInfo(destPartitionFS, destFileName); // NTFS hard link handling if (destPartitionFS is NtfsFileSystem) { var ntfsSourceFS = (NtfsFileSystem)srcPartitionFS; var ntfsDestFS = (NtfsFileSystem)destPartitionFS; var sourceFileNtfsEntry = ntfsSourceFS.GetDirectoryEntry( sourceFile.FullName); var sourceFileNtfsRef = ntfsSourceFS.GetFile( sourceFileNtfsEntry.Reference); var destFileNtfsEntry = ntfsDestFS.GetDirectoryEntry( destFile.FullName); var destFileNtfsRef = ntfsDestFS.GetFile( destFileNtfsEntry.Reference); var sourceFileNtfsId = sourceFileNtfsRef.IndexInMft; // check if this files was already processed once if (ntfsHardlinkTracker.ContainsKey(sourceFileNtfsId)) { var trackedDestFileNtfsRef = ntfsDestFS.GetFile( ntfsHardlinkTracker[sourceFileNtfsId]); // if we have a hardlink-match, close the old stream // and delete the file destFileStream.Close(); destFile.Delete(); // then create the hardlink and mention that we don't // want/need to copy the content anymore Logger.Info("[{0}/{1}] mk-lnk : {2} => {3}", i, taskId, sourceFileNtfsRef.Names[0], destFile.FullName); ntfsDestFS.CreateHardLink( trackedDestFileNtfsRef.DirectoryEntry, destFile.FullName); skipCopying = true; } else { Logger.Verbose("[{0}/{1}] rg-lnk : {2}#{3} -> {4}#{5}", i, taskId, sourceFileNtfsRef.Names[0], sourceFileNtfsRef.IndexInMft, destFileNtfsRef.Names[0], destFileNtfsRef.IndexInMft); // if not, track it ntfsHardlinkTracker.Add(sourceFileNtfsRef.IndexInMft, destFileNtfsRef.IndexInMft); } } if (!skipCopying) { Logger.Info("[{0}/{1}] cp-file: {2}", i, taskId, destFile.FullName); CloneStream(i, taskId, sourceFileStream, destFileStream); } // clone basic file informationsdestFile Logger.Verbose("[{0}/{1}] cp-meta: {2}", i, taskId, destFile.FullName); destFile.Attributes = sourceFile.Attributes; destFile.CreationTime = sourceFile.CreationTime; destFile.CreationTimeUtc = sourceFile.CreationTimeUtc; destFile.IsReadOnly = sourceFile.IsReadOnly; destFile.LastAccessTime = sourceFile.LastAccessTime; destFile.LastAccessTimeUtc = sourceFile.LastAccessTimeUtc; destFile.LastWriteTime = sourceFile.LastWriteTime; destFile.LastWriteTimeUtc = sourceFile.LastWriteTimeUtc; // file-system based cloning if (destPartitionFS is NtfsFileSystem) { Logger.Verbose("[{0}/{1}] cp-fsec: {2}", i, taskId, destFile.FullName); var ntfsSourceFS = (NtfsFileSystem)srcPartitionFS; var ntfsDestFS = (NtfsFileSystem)destPartitionFS; var destFileNtfsEntry = ntfsDestFS.GetDirectoryEntry( destFile.FullName); var destFileNtfsRef = ntfsDestFS.GetFile( destFileNtfsEntry.Reference); // clone security descriptors var sourceNtfsSecurity = ntfsSourceFS.GetSecurity( sourceFile.FullName); ntfsDestFS.SetSecurity(destFile.FullName, sourceNtfsSecurity); // clone short names if destination file is not a hard link if (destFileNtfsEntry.Details.FileNameNamespace != FileNameNamespace.Posix || !destFileNtfsRef.HasWin32OrDosName) { Logger.Verbose("[{0}/{1}] cp-shrt: {2}", i, taskId, destFile.FullName); var sourceNtfsShortName = ntfsSourceFS.GetShortName( sourceFile.FullName); if (sourceNtfsShortName != null) { ntfsSourceFS.SetShortName(destFile.FullName, sourceNtfsShortName); } } } } // advance recursion into directories foreach (var sourceDirectory in sourceDir.GetDirectories()) { if (srcPartitionFS is FatFileSystem) { // Don't copy SYSTEM~1 on FAT. Just don't do it... if (sourceDirectory.Name.Equals("SYSTEM~1")) { continue; } } cloneSrcFsToDestFs(sourceDirectory, new DiscDirectoryInfo( destPartitionFS, Path.Combine(destDir.FullName, sourceDirectory.Name) ) ); } }); cloneSrcFsToDestFs(srcPartitionFS.Root, destPartitionFS.Root); } } return(SUCCESS); }
internal GuidPartitionInfo(GuidPartitionTable table, GptEntry entry) { _table = table; _entry = entry; }
protected override void ProcessRecord() { PSObject diskObject = null; VirtualDisk disk = null; if (InputObject != null) { diskObject = InputObject; disk = diskObject.BaseObject as VirtualDisk; } if (disk == null && string.IsNullOrEmpty(LiteralPath)) { WriteError(new ErrorRecord( new ArgumentException("No disk specified"), "NoDiskSpecified", ErrorCategory.InvalidArgument, null)); return; } if (disk == null) { diskObject = SessionState.InvokeProvider.Item.Get(LiteralPath)[0]; VirtualDisk vdisk = diskObject.BaseObject as VirtualDisk; if (vdisk == null) { WriteError(new ErrorRecord( new ArgumentException("Path specified is not a virtual disk"), "BadDiskSpecified", ErrorCategory.InvalidArgument, null)); return; } disk = vdisk; } PartitionTable pt = null; if (VolumeManager == VolumeManagerType.Bios) { pt = BiosPartitionTable.Initialize(disk); } else { pt = GuidPartitionTable.Initialize(disk); } if (Signature != 0) { disk.Signature = Signature; } else { disk.Signature = new Random().Next(); } // Changed volume layout, force a rescan var drive = diskObject.Properties["PSDrive"].Value as VirtualDiskPSDriveInfo; if (drive != null) { drive.RescanVolumes(); } WriteObject(disk); }
private static int StartInternal() { Info("====== Starting Partition Table Checks ======"); DoingCheck(); if (!GuidPartitionTable.Detect(mLeftStream)) { Error("Could not find valid GUID Partition Table on left stream"); return(ERROR); } Info("Found valid GUID Partition Table on left stream"); DoingCheck(); if (!GuidPartitionTable.Detect(mRightStream)) { Error("Could not find valid GUID Partition Table on right stream"); return(ERROR); } Info("Found valid GUID Partition Table on right stream"); var leftGeometry = GuidPartitionTable.DetectGeometry(mLeftStream); var leftPartitionTable = new GuidPartitionTable(mLeftStream, leftGeometry); var rightGeometry = GuidPartitionTable.DetectGeometry(mRightStream); var rightPartitionTable = new GuidPartitionTable(mRightStream, rightGeometry); // adjust length if (FixedLengthStream.IsFixedDiskStream(mLeftStream)) { mLeftStream.SetLength(leftGeometry.Capacity); } if (FixedLengthStream.IsFixedDiskStream(mRightStream)) { mRightStream.SetLength(leftGeometry.Capacity); } DoingCheck(); if (leftPartitionTable.Count != rightPartitionTable.Count) { Error("Non-equal count of partitions (Left: {0}, Right {1})", leftPartitionTable.Count, rightPartitionTable.Count); return(ERROR); } Info("Matching count of partitions ({0})", leftPartitionTable.Count); Info("====== Starting Partition Checks ======"); for (int i = 0; i < leftPartitionTable.Count; i++) { var leftPartition = leftPartitionTable[i]; var rightPartition = rightPartitionTable[i]; DoingCheck(); if (leftPartition.BiosType != rightPartition.BiosType) { Error("Partition{0}: Non-matching BIOS partition type " + "(Left: 0x{1:X2}, Right: 0x{2:X2})", i, leftPartition.BiosType, rightPartition.BiosType); return(ERROR); } Info("Partition{0}: Matching BIOS partition type (0x{1:X2})", i, leftPartition.BiosType); DoingCheck(); if (leftPartition.GuidType != rightPartition.GuidType) { Error("Partition{0}: Non-matching GUID partition type " + "(Left: {1}, Right: {2})", i, leftPartition.GuidType, rightPartition.GuidType); return(ERROR); } Info("Partition{0}: Matching GUID partition type ({1})", i, leftPartition.GuidType); DoingCheck(); if (leftPartition.VolumeType != rightPartition.VolumeType) { Error("Partition{0}: Non-matching physical partition type " + "(Left: 0x{1:X}/{1}, Right: 0x{2:X}/{2})", i, leftPartition.VolumeType, rightPartition.VolumeType); return(ERROR); } Info("Partition{0}: Matching physical partition type (0x{1:X}/{1})", i, leftPartition.VolumeType); } Info("====== Starting File System Checks ======"); for (int i = 0; i < leftPartitionTable.Count; i++) { var leftPartition = leftPartitionTable[i]; var leftPartitionStream = leftPartition.Open(); var leftPartitionValidFS = DiscHandler.IsStreamSupportedFileSystem(leftPartitionStream); var rightPartition = rightPartitionTable[i]; var rightPartitionStream = rightPartition.Open(); var rightPartitionValidFS = DiscHandler.IsStreamSupportedFileSystem(rightPartitionStream); if (!leftPartitionValidFS) { Info("Partition{0}: Left stream does not contain supported file system", i); } if (!rightPartitionValidFS) { Info("Partition{0}: Right stream does not contain supported file system", i); } if (leftPartitionValidFS && rightPartitionValidFS) { Info("Partition{0}: Running checks on file-system layer", i); var leftFileSystem = DiscHandler.GetFileSystem(leftPartitionStream); var rightFileSystem = DiscHandler.GetFileSystem(rightPartitionStream); if (leftFileSystem.UsedSpace != rightFileSystem.UsedSpace) { Warning("Partition{0}: Non-matching amount of used space " + "(Left: 0x{1:X2}/{2}, Right: 0x{3:X2}/{4})", i, leftFileSystem.UsedSpace, FormatBytes(leftFileSystem.UsedSpace, 3), rightFileSystem.UsedSpace, FormatBytes(rightFileSystem.UsedSpace, 3)); } Action <DiscDirectoryInfo, DiscDirectoryInfo> traverseFiles = null; traverseFiles = new Action <DiscDirectoryInfo, DiscDirectoryInfo>( (leftBaseDir, rightBaseDir) => { var leftFiles = leftBaseDir.GetFiles(); var rightFiles = rightBaseDir.GetFiles(); DoingCheck(); if (leftFiles.Length != rightFiles.Length) { Warning("Partition{0}: Non-matching amount of files in {1} " + "(Left: {2}, Right: {3})", i, leftBaseDir.FullName, leftFiles.Length, rightFiles.Length); var checkedFiles = new List <DiscFileInfo>(); foreach (var leftFile in leftFiles) { var matchingRightFiles = rightFiles.Where(f => f.Name == leftFile.Name); DoingCheck(); if (matchingRightFiles.Count() >= 2) { Error("Partition{0}:{1}: Found invalid file entry in " + "file system, looked up file with {2} results", i, leftBaseDir.FullName, matchingRightFiles.Count()); } DoingCheck(); if (matchingRightFiles.Count() == 1) { checkedFiles.Add(leftFile); var rightFile = matchingRightFiles.First(); var leftFileStream = leftFile.OpenRead(); var rightFileStream = rightFile.OpenRead(); DoByteComparison(leftFileStream, rightFileStream, i, leftFile.FullName); leftFileStream.Close(); rightFileStream.Close(); DoMetaDataComparison(i, leftFile, rightFile); if (leftFileSystem is NtfsFileSystem) { DoNtfsSecurityComparison(i, (NtfsFileSystem)leftFileSystem, leftFile, (NtfsFileSystem)rightFileSystem, rightFile); } } else // == 0 { Warning("Partition{0}:{1}: Found file in left " + "file system only", i, leftFile.FullName); } } foreach (var rightFile in rightFiles) { DoingCheck(); if (!checkedFiles.Any(f => f.Name == rightFile.Name)) { Warning("Partition{0}:{1}: Found file in right " + "file system only", i, rightFile.FullName); } } } else { for (int j = 0; j < leftFiles.Length; j++) { var leftFile = leftFiles[j]; var leftFileStream = leftFile.OpenRead(); var rightFile = rightFiles[j]; var rightFileStream = rightFile.OpenRead(); DoByteComparison(leftFileStream, rightFileStream, i, leftFile.FullName); leftFileStream.Close(); rightFileStream.Close(); DoMetaDataComparison(i, leftFile, rightFile); if (leftFileSystem is NtfsFileSystem) { DoNtfsSecurityComparison(i, (NtfsFileSystem)leftFileSystem, leftFile, (NtfsFileSystem)rightFileSystem, rightFile); } } } // advance recursion into directories var leftDirectories = leftBaseDir.GetDirectories(); var rightDirectories = rightBaseDir.GetDirectories(); DoingCheck(); if (leftDirectories.Length != rightDirectories.Length) { Warning("Partition{0}: Non-matching amount of directories in {1} " + "(Left: {2}, Right: {3})", i, leftBaseDir.FullName, leftDirectories.Length, rightDirectories.Length); var checkedDirectories = new List <DiscFileInfo>(); foreach (var leftDirectory in leftDirectories) { var matchingRightFiles = rightDirectories.Where(f => f.Name == leftDirectory.Name); DoingCheck(); if (matchingRightFiles.Count() >= 2) { Error("Partition{0}:{1}: Found invalid directory entry in " + "file system, looked up file with {2} results", i, leftBaseDir.FullName, matchingRightFiles.Count()); } DoingCheck(); if (matchingRightFiles.Count() == 1) { var rightDirectory = matchingRightFiles.First(); traverseFiles(leftDirectory, rightDirectory); } else // == 0 { Warning("Partition{0}:{1}: Found directory in left " + "file system only", i, leftDirectory.FullName); } } foreach (var rightFile in rightDirectories) { DoingCheck(); if (!checkedDirectories.Any(f => f.Name == rightFile.Name)) { Warning("Partition{0}:{1}: Found file in right " + "file system only", i, rightFile.FullName); } } } else { for (int j = 0; j < leftDirectories.Length; j++) { var leftDirectory = leftDirectories[j]; var rightDirectory = leftDirectories[j]; traverseFiles(leftDirectory, rightDirectory); } } }); traverseFiles(leftFileSystem.Root, rightFileSystem.Root); } else { Info("Partition{0}: Running checks on data layer", i); // This can can be run because of the fact that we don't resize // unsupported partitions but run byte-for-byte copy with them DoByteComparison(leftPartitionStream, rightPartitionStream, i, null); } } return(SUCCESS); }