Example #1
0
        public static void ExtendGPTPartition(GPTPartition partition, long numberOfAdditionalExtentSectors)
        {
            Disk disk = partition.Disk;
            GuidPartitionTableHeader primaryHeader   = GuidPartitionTableHeader.ReadPrimaryFromDisk(disk);
            GuidPartitionTableHeader secondaryHeader = GuidPartitionTableHeader.ReadSecondaryFromDisk(disk, primaryHeader);

            if (primaryHeader == null || secondaryHeader == null)
            {
                throw new NotImplementedException("Cannot extend GPT disk with corrupted header");
            }

            if (primaryHeader.PartitionArrayCRC32 != secondaryHeader.PartitionArrayCRC32)
            {
                throw new NotImplementedException("Cannot extend GPT disk with mismatched partition arrays");
            }

            List <GuidPartitionEntry> entries = GuidPartitionTable.ReadEntriesFromDisk(disk);

            foreach (GuidPartitionEntry entry in entries)
            {
                if ((long)entry.FirstLBA == partition.FirstSector)
                {
                    entry.LastLBA += (ulong)numberOfAdditionalExtentSectors;
                    GuidPartitionEntry.WriteToDisk(disk, primaryHeader, entry);
                    GuidPartitionEntry.WriteToDisk(disk, secondaryHeader, entry);
                    break;
                }
            }

            primaryHeader.PartitionArrayCRC32 = GuidPartitionTable.ComputePartitionArrayCRC32(disk, primaryHeader);
            GuidPartitionTableHeader.WriteToDisk(disk, primaryHeader);
            secondaryHeader.PartitionArrayCRC32 = GuidPartitionTable.ComputePartitionArrayCRC32(disk, secondaryHeader);
            GuidPartitionTableHeader.WriteToDisk(disk, secondaryHeader);
        }
        private static List <GuidPartitionEntry> ReadEntriesFromDisk(Disk disk, GuidPartitionTableHeader header)
        {
            int bufferLength  = (int)(header.NumberOfPartitionEntries * header.SizeOfPartitionEntry);
            int sectorsToRead = (int)Math.Ceiling((double)bufferLength / disk.BytesPerSector);

            byte[] buffer = disk.ReadSectors((long)header.PartitionEntriesLBA, sectorsToRead);
            if (buffer.Length > bufferLength)
            {
                buffer = ByteReader.ReadBytes(buffer, 0, bufferLength);
            }
            uint expectedCRC32 = CRC32.Compute(buffer);

            if (header.PartitionArrayCRC32 != expectedCRC32)
            {
                return(null);
            }

            int offset = 0;
            List <GuidPartitionEntry> result = new List <GuidPartitionEntry>();

            for (int index = 0; index < header.NumberOfPartitionEntries; index++)
            {
                GuidPartitionEntry entry = new GuidPartitionEntry(buffer, offset);
                entry.EntryIndex = index;
                // Unused entries use Guid.Empty as PartitionTypeGuid
                if (entry.PartitionTypeGuid != Guid.Empty)
                {
                    result.Add(entry);
                }
                offset += (int)header.SizeOfPartitionEntry;
            }
            return(result);
        }
        public static void WriteToDisk(Disk disk, GuidPartitionTableHeader header, GuidPartitionEntry entry)
        {
            long sectorIndex      = (long)header.PartitionEntriesLBA + entry.EntryIndex * header.SizeOfPartitionEntry / disk.BytesPerSector;
            int  entriesPerSector = (int)(disk.BytesPerSector / header.SizeOfPartitionEntry);
            int  indexInSector    = (int)(entry.EntryIndex % entriesPerSector);

            byte[] buffer = disk.ReadSector(sectorIndex);
            entry.WriteBytes(buffer, indexInSector * (int)header.SizeOfPartitionEntry);
            disk.WriteSectors(sectorIndex, buffer);
        }
        public static void InitializeDisk(Disk disk, long firstUsableLBA, long reservedPartitionSizeLBA)
        {
            if (reservedPartitionSizeLBA > 0 && reservedPartitionSizeLBA * disk.BytesPerSector < 1024 * 1024)
            {
                // The LDM database will take 1MB out of the reserved partition.
                // less than 1MB will cause the conversion to dynamic disk to fail.
                throw new ArgumentException("Reserved partition size must be at least 1MB");
            }

            List <GuidPartitionEntry> partitionEntries = new List <GuidPartitionEntry>();

            if (reservedPartitionSizeLBA > 0)
            {
                GuidPartitionEntry reservedEntry = new GuidPartitionEntry();
                reservedEntry.PartitionGuid     = Guid.NewGuid();
                reservedEntry.PartitionTypeGuid = GPTPartition.MicrosoftReservedPartititionTypeGuid;
                reservedEntry.FirstLBA          = (ulong)firstUsableLBA;
                reservedEntry.LastLBA           = (ulong)(firstUsableLBA + reservedPartitionSizeLBA - 1);
                reservedEntry.PartitionName     = "Microsoft reserved partition";
                partitionEntries.Add(reservedEntry);
            }
            InitializeDisk(disk, firstUsableLBA, partitionEntries);
        }