public static long FindUnusedRegion(PrivateHeader privateHeader, TOCBlock tocBlock, int sectorCount) { bool[] bitmap = GetPrivateRegionUsageBitmap(privateHeader, tocBlock); // Reserve the first, second, third, third-last and second-last sectors for TOCBlocks bitmap[0] = true; bitmap[1] = true; bitmap[2] = true; bitmap[privateHeader.PrivateRegionSizeLBA - 3] = true; bitmap[privateHeader.PrivateRegionSizeLBA - 2] = true; int startIndex = 0; int freeCount = 0; for (int index = 0; index < bitmap.Length; index++) { if (bitmap[index] == false) // free { if (freeCount == 0) { startIndex = index; } freeCount++; if (freeCount == sectorCount) { return((long)privateHeader.PrivateRegionStartLBA + startIndex); } } else { freeCount = 0; } } return(-1); }
/// <summary> /// Update the database to point to the new extent location (same or different disk) /// </summary> public static void UpdateExtentLocation(DiskGroupDatabase database, DynamicVolume volume, DynamicDiskExtent relocatedExtent) { PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(relocatedExtent.Disk); DiskRecord targetDiskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid); VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid); List <DatabaseRecord> records = new List <DatabaseRecord>(); ExtentRecord sourceExtentRecord = database.FindExtentByExtentID(relocatedExtent.ExtentID); ExtentRecord relocatedExtentRecord = (ExtentRecord)sourceExtentRecord.Clone(); relocatedExtentRecord.DiskId = targetDiskRecord.DiskId; relocatedExtentRecord.DiskOffsetLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(relocatedExtent.FirstSector, privateHeader); records.Add(relocatedExtentRecord); // we should update the disk records foreach (DynamicDiskExtent extent in volume.Extents) { DiskRecord diskRecord = database.FindDiskByDiskID(relocatedExtentRecord.DiskId); // there could be multiple extents on the same disk, make sure we only add each disk once if (!records.Contains(diskRecord)) { diskRecord = (DiskRecord)diskRecord.Clone(); records.Add(diskRecord); } } // when moving to a new disk, we should update the new disk record as well if (!records.Contains(targetDiskRecord)) { records.Add(targetDiskRecord.Clone()); } database.UpdateDatabase(records); }
public static VolumeManagerDatabase ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { VolumeManagerDatabaseHeader databaseHeader = VolumeManagerDatabaseHeader.ReadFromDisk(disk, privateHeader, tocBlock); if (databaseHeader == null || !databaseHeader.IsVersionSupported) { return(null); } // The first VBLK entry is the subsequent entry to the VMDB header. // Note: On a disk with 4KB sectors, VBLKs will reside in the same sector as the VMDB header. ulong firstSector = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart; // we skip the VMDB int databaseLength = (int)(databaseHeader.HeaderSize + databaseHeader.NumberOfVBlks * databaseHeader.BlockSize); int sectorCount = (int)Math.Ceiling(databaseLength / (double)disk.BytesPerSector); byte[] databaseBytes = disk.ReadSectors((long)firstSector, sectorCount); int numberOfFragments = (int)(databaseHeader.NumberOfVBlks - FirstSequenceNumber); List <DatabaseRecord> databaseRecords = ReadDatabaseRecords(databaseBytes, (int)databaseHeader.HeaderSize, (int)databaseHeader.BlockSize, numberOfFragments); // read all KLog blocks KernelUpdateLog kernelUpdateLog = KernelUpdateLog.ReadFromDisk(disk, privateHeader, tocBlock); DynamicDisk dynamicDisk = new DynamicDisk(disk, privateHeader, tocBlock); return(new VolumeManagerDatabaseCopy(dynamicDisk, databaseHeader, databaseRecords, kernelUpdateLog)); }
public static TOCBlock ReadFromDisk(Disk disk, PrivateHeader privateHeader, bool usePrimaryTOC) { ulong sectorIndex; if (usePrimaryTOC) { sectorIndex = privateHeader.PrivateRegionStartLBA + privateHeader.PrimaryTocLBA; } else { sectorIndex = privateHeader.PrivateRegionStartLBA + privateHeader.SecondaryTocLBA; } byte[] sector = disk.ReadSector((long)sectorIndex); string signature = ByteReader.ReadAnsiString(sector, 0x00, 8); if (signature == TOCBlockSignature) { TOCBlock tocBlock = new TOCBlock(sector); if (tocBlock.IsChecksumValid) { return(tocBlock); } } return(null); }
public TOCBlock(byte[] buffer) { if (buffer.Length > Length) { // Checksum only applies to the first 512 bytes (even when the sector size > 512 bytes) buffer = ByteReader.ReadBytes(buffer, 0, 512); } Signature = ByteReader.ReadAnsiString(buffer, 0x00, 8); uint checksum = BigEndianConverter.ToUInt32(buffer, 0x08); UpdateSequenceNumber = BigEndianConverter.ToUInt64(buffer, 0x0C); // 16 zeros int offset = 0x24; // If the first character is not null (0x00), then there is a region defined while (buffer[offset] != 0) { TOCRegion region = new TOCRegion(buffer, offset); Regions.Add(region); offset += TOCRegion.Length; } BigEndianWriter.WriteUInt32(buffer, 0x08, (uint)0); // we exclude the checksum field from checksum calculations m_isChecksumValid = (checksum == PrivateHeader.CalculateChecksum(buffer)); }
public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, VolumeManagerDatabaseHeader header) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart; byte[] bytes = header.GetBytes(); disk.WriteSectors((long)sectorIndex, bytes); }
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 void AddDiskToRaid5Volume(List <DynamicDisk> disks, Raid5Volume volume, DiskExtent newExtent, ref long bytesCopied) { DiskGroupDatabase database = DiskGroupDatabase.ReadFromDisks(disks, volume.DiskGroupGuid); if (database == null) { throw new DatabaseNotFoundException(); } // If there will be a power failure during the conversion, our RAID volume will resync during boot, // To prevent destruction of the data, we temporarily convert the array to striped volume VolumeManagerDatabaseHelper.ConvertRaidToStripedVolume(database, volume.VolumeGuid); ulong newExtentID = VolumeManagerDatabaseHelper.AddNewExtentToVolume(database, volume, newExtent); // Backup the first sector of the first extent to the last sector of the new extent // (We replace the filesystem boot record with our own sector for recovery purposes) byte[] filesystemBootRecord = volume.Extents[0].ReadSector(0); newExtent.WriteSectors(newExtent.TotalSectors - 1, filesystemBootRecord); AddDiskOperationBootRecord resumeRecord = new AddDiskOperationBootRecord(); resumeRecord.VolumeGuid = volume.VolumeGuid; PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(newExtent.Disk); // privateHeader cannot be null at this point resumeRecord.NumberOfCommittedSectors = 0; // we use volume.WriteSectors so that the parity information will be update // this way, we could recover the first sector of each extent if a disk will fail volume.WriteSectors(0, resumeRecord.GetBytes()); ResumeAddDiskToRaid5Volume(disks, volume, new DynamicDiskExtent(newExtent, newExtentID), resumeRecord, ref bytesCopied); }
public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, KernelUpdateLogPage record) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.LogStart + record.PageIndex; byte[] sector = record.GetBytes(); disk.WriteSectors((long)sectorIndex, sector); }
public static KernelUpdateLogPage ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, int kLogIndex) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.LogStart + (uint)kLogIndex; byte[] sector = disk.ReadSector((long)sectorIndex); KernelUpdateLogPage result = new KernelUpdateLogPage(sector); return(result); }
public static VolumeManagerDatabase ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { VolumeManagerDatabaseHeader databaseHeader = VolumeManagerDatabaseHeader.ReadFromDisk(disk, privateHeader, tocBlock); if (databaseHeader == null) { return(null); } List <DatabaseRecord> databaseRecords = new List <DatabaseRecord>(); // The first VBLK entry is the subsequent entry to the VMDB, which located at (ConfigurationStartLBA + Item1Start) ulong firstSector = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart + 1; // we skip the VMDB int sectorCount = (int)Math.Ceiling((long)databaseHeader.NumberOfVBlks * databaseHeader.BlockSize / (decimal)disk.BytesPerSector); byte[] databaseBytes = disk.ReadSectors((long)firstSector, sectorCount); // read all VBLK blocks: // Note: fragments are not necessarily contiguous! Dictionary <uint, List <DatabaseRecordFragment> > fragments = new Dictionary <uint, List <DatabaseRecordFragment> >(); for (uint index = 0; index < databaseHeader.NumberOfVBlks - 4; index++) { byte[] fragmentBytes = new byte[databaseHeader.BlockSize]; #warning long array index not supported Array.Copy(databaseBytes, (int)(index * databaseHeader.BlockSize), fragmentBytes, 0, (int)databaseHeader.BlockSize); DatabaseRecordFragment fragment = DatabaseRecordFragment.GetDatabaseRecordFragment(fragmentBytes); if (fragment != null) // null fragment means VBLK is empty { if (fragments.ContainsKey(fragment.GroupNumber)) { fragments[fragment.GroupNumber].Add(fragment); } else { List <DatabaseRecordFragment> recordFragments = new List <DatabaseRecordFragment>(); recordFragments.Add(fragment); fragments.Add(fragment.GroupNumber, recordFragments); } } } // We have all the fragments and we can now assemble the records: // We assume that fragments with lower FragmentNumber appear in the database before fragments // of the same group with higher FragmentNumber. foreach (List <DatabaseRecordFragment> recorFragments in fragments.Values) { DatabaseRecord databaseRecord = DatabaseRecord.GetDatabaseRecord(recorFragments); databaseRecords.Add(databaseRecord); } // read all KLog blocks KernelUpdateLog kernelUpdateLog = KernelUpdateLog.ReadFromDisk(disk, privateHeader, tocBlock); DynamicDisk dynamicDisk = new DynamicDisk(disk, privateHeader, tocBlock); return(new VolumeManagerDatabase(dynamicDisk, databaseHeader, databaseRecords, kernelUpdateLog)); }
public static TOCBlock ReadFromDisk(Disk disk, PrivateHeader privateHeader) { TOCBlock tocBlock = ReadFromDisk(disk, privateHeader, true); if (tocBlock == null) { tocBlock = ReadFromDisk(disk, privateHeader, false); } return(tocBlock); }
public static VolumeManagerDatabase ReadFromDisk(Disk disk, PrivateHeader privateHeader) { TOCBlock tocBlock = TOCBlock.ReadFromDisk(disk, privateHeader); if (tocBlock != null) { return(ReadFromDisk(disk, privateHeader, tocBlock)); } return(null); }
public static ulong CreateSimpleVolume(DiskGroupDatabase database, DiskExtent extent) { List <DatabaseRecord> records = new List <DatabaseRecord>(); VolumeRecord volumeRecord = new VolumeRecord(); volumeRecord.Id = database.AllocateNewRecordID(); volumeRecord.Name = GetNextSimpleVolumeName(database.VolumeRecords); volumeRecord.VolumeTypeString = "gen"; volumeRecord.StateString = "ACTIVE"; volumeRecord.ReadPolicy = ReadPolicyName.Select; volumeRecord.VolumeNumber = GetNextVolumeNumber(database.VolumeRecords); volumeRecord.VolumeFlags = VolumeFlags.Writeback | VolumeFlags.DefaultUnknown; volumeRecord.NumberOfComponents = 1; volumeRecord.SizeLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extent.TotalSectors, extent.BytesPerSector); volumeRecord.PartitionType = PartitionType.RAW; volumeRecord.VolumeGuid = Guid.NewGuid(); records.Add(volumeRecord); ComponentRecord componentRecord = new ComponentRecord(); componentRecord.Id = database.AllocateNewRecordID(); componentRecord.Name = volumeRecord.Name + "-01"; componentRecord.StateString = "ACTIVE"; componentRecord.ExtentLayout = ExtentLayoutName.Concatenated; componentRecord.NumberOfExtents = 1; componentRecord.VolumeId = volumeRecord.VolumeId; componentRecord.HasStripedExtentsFlag = false; componentRecord.NumberOfColumns = 0; records.Add(componentRecord); // we should update the disk record PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(extent.Disk); DiskRecord diskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid); diskRecord = (DiskRecord)diskRecord.Clone(); records.Add(diskRecord); ExtentRecord extentRecord = new ExtentRecord(); extentRecord.Name = GetNextExtentName(database.ExtentRecords, diskRecord.Name); extentRecord.DiskOffsetLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(extent.FirstSector, privateHeader); extentRecord.SizeLBA = volumeRecord.SizeLBA; extentRecord.ComponentId = componentRecord.ComponentId; extentRecord.DiskId = diskRecord.DiskId; extentRecord.HasColumnIndexFlag = false; records.Add(extentRecord); database.UpdateDatabase(records); return(volumeRecord.VolumeId); }
/// <summary> /// This method will write privateHeader to disk as well /// </summary> public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { privateHeader.UpdateSequenceNumber++; tocBlock.UpdateSequenceNumber++; byte[] bytes = tocBlock.GetBytes(); disk.WriteSectors((long)(privateHeader.PrivateRegionStartLBA + privateHeader.PreviousPrimaryTocLBA), bytes); disk.WriteSectors((long)(privateHeader.PrivateRegionStartLBA + privateHeader.PreviousSecondaryTocLBA), bytes); privateHeader.PrimaryTocLBA = privateHeader.PreviousPrimaryTocLBA; privateHeader.SecondaryTocLBA = privateHeader.PreviousSecondaryTocLBA; PrivateHeader.WriteToDisk(disk, privateHeader); }
public static VolumeManagerDatabase ReadFromDisk(Disk disk) { if (DynamicDisk.IsDynamicDisk(disk)) { PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(disk); if (privateHeader != null) { return(ReadFromDisk(disk, privateHeader)); } } return(null); }
// The secondary TOC is usually alternated between the third-last and the second-last sectors of the private region. public static long FindUnusedLBAForSecondaryToc(PrivateHeader privateHeader, TOCBlock tocBlock) { bool[] bitmap = GetPrivateRegionUsageBitmap(privateHeader, tocBlock); for (int index = bitmap.Length - 1; index >= 0; index--) { if (bitmap[index] == false) { return((long)privateHeader.PrivateRegionStartLBA + index); } } return(-1); }
/// <summary> /// Support null disks /// </summary> public static long GetExtentStartSector(DynamicDisk disk, ExtentRecord extentRecord) { long publicRegionStartLBA = 0; int bytesPerDiskSector = DynamicColumn.DefaultBytesPerSector; // default for missing disks if (disk != null) { bytesPerDiskSector = disk.BytesPerSector; PrivateHeader privateHeader = disk.PrivateHeader; publicRegionStartLBA = (long)privateHeader.PublicRegionStartLBA; } return(PublicRegionHelper.TranslateFromPublicRegionLBA((long)extentRecord.DiskOffsetLBA, publicRegionStartLBA, bytesPerDiskSector)); }
public static KernelUpdateLog ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { List <KernelUpdateLogPage> pages = new List <KernelUpdateLogPage>(); KernelUpdateLogPage firstPage = KernelUpdateLogPage.ReadFromDisk(disk, privateHeader, tocBlock, 0); pages.Add(firstPage); for (int index = 2; index < firstPage.NumberOfPages; index++) { KernelUpdateLogPage page = KernelUpdateLogPage.ReadFromDisk(disk, privateHeader, tocBlock, index); pages.Add(page); } return(new KernelUpdateLog(pages)); }
public static KernelUpdateLogPage ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, int pageIndex) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.LogStart + (uint)(pageIndex * Length / disk.BytesPerSector); int pageOffset = (pageIndex * Length) % disk.BytesPerSector; byte[] sector = disk.ReadSector((long)sectorIndex); if (pageOffset > 0) { sector = ByteReader.ReadBytes(sector, pageOffset, Length); } KernelUpdateLogPage result = new KernelUpdateLogPage(sector); return(result); }
public void SetLastEntry(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, ulong committedTransactionID, ulong pendingTransactionID) { if (m_pages.Count > 0) { m_pages[0].SetLastEntry(committedTransactionID, pendingTransactionID); // Windows kernel stores the last committedTransactionID / pendingTransactionID in memory, // and it will overwrite the values we write as soon as dmadmin is started, // However, it doesn't seem to cause any issues KernelUpdateLogPage.WriteToDisk(disk, privateHeader, tocBlock, m_pages[0]); } else { throw new InvalidOperationException("KLog records have not been previously read from disk"); } }
/// <param name="targetOffset">in bytes</param> public static bool IsMoveLocationValid(DynamicDiskExtent sourceExtent, DynamicDisk targetDisk, long targetOffset) { bool isSameDisk = (sourceExtent.Disk == targetDisk.Disk); List <DynamicDiskExtent> extents = GetDiskExtents(targetDisk); // extents are sorted by first sector if (extents == null) { return(false); } PrivateHeader privateHeader = targetDisk.PrivateHeader; if (sourceExtent.BytesPerSector != targetDisk.BytesPerSector) { // We must not move an extent to another disk that has different sector size return(false); } if (targetOffset % privateHeader.BytesPerSector > 0) { return(false); } long targetSector = targetOffset / targetDisk.BytesPerSector; DiskExtent targetExtent = new DiskExtent(targetDisk.Disk, targetSector, sourceExtent.Size); List <DiskExtent> usedExtents = new List <DiskExtent>(); foreach (DynamicDiskExtent extent in extents) { if (!isSameDisk || extent.FirstSector != sourceExtent.FirstSector) { usedExtents.Add(extent); } } long publicRegionStartSector = (long)privateHeader.PublicRegionStartLBA; long publicRegionSize = (long)privateHeader.PublicRegionSizeLBA * targetDisk.BytesPerSector; List <DiskExtent> unallocatedExtents = DiskExtentsHelper.GetUnallocatedExtents(targetDisk.Disk, publicRegionStartSector, publicRegionSize, usedExtents); foreach (DiskExtent extent in unallocatedExtents) { if (extent.FirstSector <= targetExtent.FirstSector && targetExtent.LastSector <= extent.LastSector) { return(true); } } return(false); }
public static VolumeManagerDatabaseHeader ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart; byte[] sector = disk.ReadSector((long)sectorIndex); string signature = ByteReader.ReadAnsiString(sector, 0x00, 4); if (signature == VolumeManagerDatabaseSignature) { return(new VolumeManagerDatabaseHeader(sector)); } else { return(null); } }
public static DynamicDisk ReadFromDisk(Disk disk) { if (IsDynamicDisk(disk)) { PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(disk); if (privateHeader != null) { TOCBlock tocBlock = TOCBlock.ReadFromDisk(disk, privateHeader); if (tocBlock != null) { return(new DynamicDisk(disk, privateHeader, tocBlock)); } } } return(null); }
public static PrivateHeader ReadFromDisk(Disk disk, long sectorIndex, bool returnPrivateHeaderWithInvalidChecksum) { byte[] sector = disk.ReadSector(sectorIndex); string signature = ByteReader.ReadAnsiString(sector, 0x00, 8); if (signature == PrivateHeaderSignature) { PrivateHeader privateHeader = new PrivateHeader(sector); if (privateHeader.IsChecksumValid || returnPrivateHeaderWithInvalidChecksum) { return(privateHeader); } } return(null); }
public static void WriteToDisk(Disk disk, PrivateHeader privateHeader) { byte[] bytes = privateHeader.GetBytes(); disk.WriteSectors((long)(privateHeader.PrivateRegionStartLBA + privateHeader.PrimaryPrivateHeaderLBA), bytes); disk.WriteSectors((long)(privateHeader.PrivateRegionStartLBA + privateHeader.SecondaryPrivateHeaderLBA), bytes); // update sector 6 if a Private Header is already present there byte[] sector = disk.ReadSector(PrivateHeaderSectorIndex); string signature = ByteReader.ReadAnsiString(sector, 0x00, 8); if (signature == PrivateHeaderSignature) { disk.WriteSectors(PrivateHeaderSectorIndex, bytes); } }
public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, VolumeManagerDatabaseHeader header) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart; byte[] headerBytes = header.GetBytes(); if (disk.BytesPerSector > Length) { byte[] sectorBytes = disk.ReadSector((long)sectorIndex); ByteWriter.WriteBytes(sectorBytes, 0, headerBytes); disk.WriteSectors((long)sectorIndex, sectorBytes); } else { disk.WriteSectors((long)sectorIndex, headerBytes); } }
public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock, KernelUpdateLogPage page) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.LogStart + (uint)(page.PageIndex * Length / disk.BytesPerSector); int pageOffset = ((int)page.PageIndex * Length) % disk.BytesPerSector; byte[] pageBytes = page.GetBytes(); if (disk.BytesPerSector > Length) { byte[] sectorBytes = disk.ReadSector((long)sectorIndex); ByteWriter.WriteBytes(sectorBytes, pageOffset, pageBytes); disk.WriteSectors((long)sectorIndex, sectorBytes); } else { disk.WriteSectors((long)sectorIndex, pageBytes); } }
private static bool[] GetPrivateRegionUsageBitmap(PrivateHeader privateHeader, TOCBlock tocBlock) { // usage bitmap: bool[] bitmap = new bool[privateHeader.PrivateRegionSizeLBA]; bitmap[privateHeader.PrimaryPrivateHeaderLBA] = true; bitmap[privateHeader.SecondaryPrivateHeaderLBA] = true; bitmap[privateHeader.PrimaryTocLBA] = true; bitmap[privateHeader.SecondaryTocLBA] = true; foreach (TOCRegion region in tocBlock.Regions) { for (int index = 0; index < (int)region.SizeLBA; index++) { bitmap[(int)region.StartLBA + index] = true; } } return(bitmap); }
/// <summary> /// This method will write privateHeader to disk as well /// </summary> public static void WriteToDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { privateHeader.UpdateSequenceNumber++; tocBlock.UpdateSequenceNumber++; byte[] tocBytes = tocBlock.GetBytes(); if (disk.BytesPerSector > Length) { tocBytes = ByteUtils.Concatenate(tocBytes, new byte[disk.BytesPerSector - TOCBlock.Length]); } long alternatePrimaryTOCLBA = PrivateRegionHelper.FindUnusedLBAForPrimaryToc(privateHeader, tocBlock); long alternateSecondaryTOCLBA = PrivateRegionHelper.FindUnusedLBAForSecondaryToc(privateHeader, tocBlock); disk.WriteSectors(alternatePrimaryTOCLBA, tocBytes); disk.WriteSectors(alternateSecondaryTOCLBA, tocBytes); privateHeader.PrimaryTocLBA = (ulong)alternatePrimaryTOCLBA; privateHeader.SecondaryTocLBA = (ulong)alternateSecondaryTOCLBA; PrivateHeader.WriteToDisk(disk, privateHeader); }