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 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); }
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 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 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); }
/// <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); }
// 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); }
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"); } }
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 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 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); } }
/// <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); }
public static void WriteDatabaseRecordFragment(DynamicDisk disk, DatabaseRecordFragment fragment, int blockSize) { if (fragment.SequenceNumber < FirstSequenceNumber) { throw new ArgumentException("VBLK SequenceNumber must start from 4"); } PrivateHeader privateHeader = disk.PrivateHeader; TOCBlock tocBlock = disk.TOCBlock; ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart; int fragmentsPerSector = (int)(disk.Disk.BytesPerSector / blockSize); sectorIndex += (ulong)(fragment.SequenceNumber / fragmentsPerSector); byte[] sectorBytes = disk.Disk.ReadSector((long)sectorIndex); byte[] fragmentBytes = fragment.GetBytes(blockSize); // should we use the same database header? int indexInSector = (int)(fragment.SequenceNumber % fragmentsPerSector); Array.Copy(fragmentBytes, 0, sectorBytes, indexInSector * blockSize, blockSize); disk.Disk.WriteSectors((long)sectorIndex, sectorBytes); }
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); }
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 DynamicDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock) { m_disk = disk; m_privateHeader = privateHeader; m_tocBlock = tocBlock; }
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 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 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 long FindUnusedSector(PrivateHeader privateHeader, TOCBlock tocBlock) { return(FindUnusedRegion(privateHeader, tocBlock, 1)); }
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 kLogIndex) { ulong sectorIndex = privateHeader.PrivateRegionStartLBA + tocBlock.LogStart + (uint)kLogIndex; byte[] sector = disk.ReadSector((long)sectorIndex); KernelUpdateLogPage result = new KernelUpdateLogPage(sector); return(result); }