public static async Task <LoadSegBlock> Parse(byte[] blockBytes) { var blockStream = new MemoryStream(blockBytes); var identifier = await blockStream.ReadAsciiString(); // Identifier 32 bit word : 'LSEG' if (!identifier.Equals(BlockIdentifiers.LoadSegBlock)) { throw new IOException("Invalid load seg block identifier"); } var size = await blockStream.ReadUInt32(); // Size of the structure for checksums var checksum = await blockStream.ReadInt32(); // Checksum of the structure var hostId = await blockStream.ReadUInt32(); // SCSI Target ID of host var nextLoadSegBlock = await blockStream.ReadInt32(); // block number of the next LoadSegBlock, -1 for last var calculatedChecksum = await BlockHelper.CalculateChecksum(blockBytes, 8); if (checksum != calculatedChecksum) { throw new IOException("Invalid load seg block checksum"); } var length = (size - 5) * 4; var data = new byte[length]; Array.Copy(blockBytes, 5 * 4, data, 0, length); return(new LoadSegBlock { BlockBytes = blockBytes, Checksum = checksum, HostId = hostId, NextLoadSegBlock = nextLoadSegBlock, Data = data }); }
public static async Task <IEnumerable <FileSystemHeaderBlock> > Read( RigidDiskBlock rigidDiskBlock, Stream stream) { if (rigidDiskBlock.FileSysHdrList == BlockIdentifiers.EndOfBlock) { return(Enumerable.Empty <FileSystemHeaderBlock>()); } var fileSystemHeaderBlocks = new List <FileSystemHeaderBlock>(); var fileSysHdrList = rigidDiskBlock.FileSysHdrList; do { // calculate file system header block offset var fileSystemHeaderBlockOffset = rigidDiskBlock.BlockSize * fileSysHdrList; // seek partition block offset stream.Seek(fileSystemHeaderBlockOffset, SeekOrigin.Begin); // read block var block = await BlockHelper.ReadBlock(stream); // parse file system header block var fileSystemHeaderBlock = await Parse(block); fileSystemHeaderBlocks.Add(fileSystemHeaderBlock); // get next partition list block and increase partition number fileSysHdrList = fileSystemHeaderBlock.NextFileSysHeaderBlock; } while (fileSysHdrList > 0 && fileSysHdrList != BlockIdentifiers.EndOfBlock); foreach (var fileSystemHeaderBlock in fileSystemHeaderBlocks) { fileSystemHeaderBlock.LoadSegBlocks = await LoadSegBlockReader.Read(rigidDiskBlock, fileSystemHeaderBlock, stream); } return(fileSystemHeaderBlocks); }
public static async Task <RigidDiskBlock> Read(Stream stream) { var rdbIndex = 0; var blockSize = 512; var rdbLocationLimit = 16; RigidDiskBlock rigidDiskBlock; // read rigid disk block from one of the first 15 blocks do { // calculate block offset var blockOffset = blockSize * rdbIndex; // seek block offset stream.Seek(blockOffset, SeekOrigin.Begin); // read block var block = await BlockHelper.ReadBlock(stream); // read rigid disk block rigidDiskBlock = await Parse(block); rdbIndex++; } while (rdbIndex < rdbLocationLimit && rigidDiskBlock == null); // fail, if rigid disk block is null if (rigidDiskBlock == null) { return(null); } rigidDiskBlock.PartitionBlocks = await PartitionBlockReader.Read(rigidDiskBlock, stream); rigidDiskBlock.BadBlocks = await BadBlockReader.Read(rigidDiskBlock, stream); return(rigidDiskBlock); }
public static async Task <BadBlock> Parse(byte[] blockBytes) { var blockStream = new MemoryStream(blockBytes); var identifier = await blockStream.ReadAsciiString(); // Identifier 32 bit word : 'BADB' if (!identifier.Equals(BlockIdentifiers.BadBlock)) { throw new IOException("Invalid bad block identifier"); } await blockStream.ReadUInt32(); // Size of the structure for checksums var checksum = await blockStream.ReadInt32(); // Checksum of the structure var hostId = await blockStream.ReadUInt32(); // SCSI Target ID of host, not really used var nextBadBlock = await blockStream.ReadUInt32(); // next BadBlock block var calculatedChecksum = await BlockHelper.CalculateChecksum(blockBytes, 8); if (checksum != calculatedChecksum) { throw new IOException("Invalid bad block checksum"); } var data = await blockStream.ReadBytes(((blockBytes.Length / 4) - 6) / 2); return(new BadBlock { BlockBytes = blockBytes, Checksum = checksum, HostId = hostId, NextBadBlock = nextBadBlock, Data = data }); }
public static async Task <byte[]> BuildBlock(PartitionBlock partitionBlock) { var blockStream = new MemoryStream(partitionBlock.BlockBytes == null || partitionBlock.BlockBytes.Length == 0 ? new byte[BlockSize.PartitionBlock * 4] : partitionBlock.BlockBytes); await blockStream.WriteAsciiString(BlockIdentifiers.PartitionBlock); await blockStream.WriteLittleEndianUInt32(BlockSize.PartitionBlock); // size // skip checksum, calculated when block is built blockStream.Seek(4, SeekOrigin.Current); await blockStream.WriteLittleEndianUInt32(partitionBlock .HostId); // SCSI Target ID of host, not really used await blockStream.WriteLittleEndianUInt32(partitionBlock .NextPartitionBlock); // Block number of the next PartitionBlock await blockStream.WriteLittleEndianUInt32(partitionBlock.Flags); // Part Flags (NOMOUNT and BOOTABLE) // skip reserved blockStream.Seek(4 * 2, SeekOrigin.Current); await blockStream.WriteLittleEndianUInt32(partitionBlock.DevFlags); // Preferred flags for OpenDevice var driveName = partitionBlock.DriveName.Length > 31 ? partitionBlock.DriveName.Substring(0, 31) : partitionBlock.DriveName; await blockStream.WriteBytes(new[] { Convert.ToByte(driveName.Length) }); await blockStream.WriteString(driveName, 31); // skip reserved blockStream.Seek(4 * 15, SeekOrigin.Current); await blockStream.WriteLittleEndianUInt32(partitionBlock.SizeOfVector); // Size of Environment vector await blockStream.WriteLittleEndianUInt32(partitionBlock .SizeBlock); // Size of the blocks in 32 bit words, usually 128 await blockStream.WriteLittleEndianUInt32(partitionBlock.SecOrg); // Not used; must be 0 await blockStream.WriteLittleEndianUInt32(partitionBlock.Surfaces); // Number of heads (surfaces) await blockStream.WriteLittleEndianUInt32(partitionBlock .Sectors); // Disk sectors per block, used with SizeBlock, usually 1 await blockStream.WriteLittleEndianUInt32(partitionBlock .BlocksPerTrack); // Blocks per track. drive specific await blockStream.WriteLittleEndianUInt32(partitionBlock .Reserved); // DOS reserved blocks at start of partition. await blockStream.WriteLittleEndianUInt32(partitionBlock .PreAlloc); // DOS reserved blocks at end of partition await blockStream.WriteLittleEndianUInt32(partitionBlock.Interleave); // Not used, usually 0 await blockStream.WriteLittleEndianUInt32(partitionBlock.LowCyl); // First cylinder of the partition await blockStream.WriteLittleEndianUInt32(partitionBlock.HighCyl); // Last cylinder of the partition await blockStream.WriteLittleEndianUInt32(partitionBlock.NumBuffer); // Initial # DOS of buffers. await blockStream.WriteLittleEndianUInt32(partitionBlock.BufMemType); // Type of mem to allocate for buffers await blockStream.WriteLittleEndianUInt32(partitionBlock .MaxTransfer); // Max number of bytes to transfer at a time await blockStream.WriteLittleEndianUInt32(partitionBlock.Mask); // Address Mask to block out certain memory await blockStream.WriteLittleEndianUInt32(partitionBlock.BootPriority); // Boot priority for autoboot await blockStream.WriteBytes(partitionBlock.DosType); // # Dostype of the file system await blockStream.WriteLittleEndianUInt32(partitionBlock.Baud); // Baud rate for serial handler await blockStream.WriteLittleEndianUInt32(partitionBlock.Control); // Control word for handler/filesystem await blockStream.WriteLittleEndianUInt32(partitionBlock .BootBlocks); // Number of blocks containing boot code // skip reserved blockStream.Seek(4 * 12, SeekOrigin.Current); // calculate and update checksum var blockBytes = blockStream.ToArray(); partitionBlock.Checksum = await BlockHelper.UpdateChecksum(blockBytes, 8); partitionBlock.BlockBytes = blockBytes; return(blockBytes); }
public static async Task <FileSystemHeaderBlock> Parse(byte[] blockBytes) { var blockStream = new MemoryStream(blockBytes); var identifier = await blockStream.ReadAsciiString(); // Identifier 32 bit word : 'RDSK' if (!identifier.Equals(BlockIdentifiers.FileSystemHeaderBlock)) { throw new IOException("Invalid file system header block identifier"); } await blockStream.ReadUInt32(); // Size of the structure for checksums var checksum = await blockStream.ReadInt32(); // Checksum of the structure var hostId = await blockStream.ReadUInt32(); // SCSI Target ID of host, not really used var nextFileSysHeaderBlock = await blockStream.ReadUInt32(); // Block number of the next FileSysHeaderBlock var flags = await blockStream.ReadUInt32(); // Flags // read reserved, unused word for (var i = 0; i < 2; i++) { await blockStream.ReadBytes(4); } var dosType = await blockStream .ReadBytes(4); // # Dostype of the file system, file system description: match this with partition environment's DE_DOSTYPE entry var version = await blockStream.ReadUInt32(); // filesystem version 0x0027001b == 39.27 var patchFlags = await blockStream.ReadUInt32(); var type = await blockStream.ReadUInt32(); var task = await blockStream.ReadUInt32(); var fileSysLock = await blockStream.ReadUInt32(); var handler = await blockStream.ReadUInt32(); var stackSize = await blockStream.ReadUInt32(); var priority = await blockStream.ReadInt32(); var startup = await blockStream.ReadInt32(); var segListBlocks = await blockStream.ReadInt32(); // first of linked list of LoadSegBlocks var globalVec = await blockStream.ReadInt32(); blockStream.Seek(172, SeekOrigin.Begin); var fileSystemName = await blockStream.ReadNullTerminatedString(); var calculatedChecksum = await BlockHelper.CalculateChecksum(blockBytes, 8); if (checksum != calculatedChecksum) { throw new IOException("Invalid file system header block checksum"); } return(new FileSystemHeaderBlock { BlockBytes = blockBytes, Checksum = checksum, HostId = hostId, NextFileSysHeaderBlock = nextFileSysHeaderBlock, Flags = flags, DosType = dosType, Version = version, PatchFlags = patchFlags, Type = type, Task = task, Lock = fileSysLock, Handler = handler, StackSize = stackSize, Priority = priority, Startup = startup, SegListBlocks = segListBlocks, GlobalVec = globalVec, FileSystemName = fileSystemName }); }
public static async Task <byte[]> BuildBlock(RigidDiskBlock rigidDiskBlock) { var blockStream = new MemoryStream(rigidDiskBlock.BlockBytes == null || rigidDiskBlock.BlockBytes.Length == 0 ? new byte[BlockSize.RigidDiskBlock * 4] : rigidDiskBlock.BlockBytes); await blockStream.WriteAsciiString(BlockIdentifiers.RigidDiskBlock); await blockStream.WriteLittleEndianUInt32(BlockSize.RigidDiskBlock); // size // skip checksum, calculated when block is built blockStream.Seek(4, SeekOrigin.Current); await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.HostId); // SCSI Target ID of host, not really used await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.BlockSize); // Size of disk blocks await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.Flags); // RDB Flags await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.BadBlockList); // Bad block list await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.PartitionList); // Partition list await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.FileSysHdrList); // File system header list await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.DriveInitCode); // Drive specific init code await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.BootBlockList); // Amiga OS 4 Boot Blocks // read reserved, unused word, need to be set to $ffffffff var reservedBytes = new byte[] { 255, 255, 255, 255 }; for (var i = 0; i < 5; i++) { await blockStream.WriteBytes(reservedBytes); } // physical drive characteristics await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.Cylinders); // Number of the cylinders of the drive await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.Sectors); // Number of sectors of the drive await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.Heads); // Number of heads of the drive await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.Interleave); // Interleave await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.ParkingZone); // Head parking cylinder // read reserved, unused word, need to be set to $ffffffff reservedBytes = new byte[4]; for (var i = 0; i < 3; i++) { await blockStream.WriteBytes(reservedBytes); } await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .WritePreComp); // Starting cylinder of write pre-compensation await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .ReducedWrite); // Starting cylinder of reduced write current await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.StepRate); // Step rate of the drive // read reserved, unused word, need to be set to $ffffffff for (var i = 0; i < 5; i++) { await blockStream.WriteBytes(reservedBytes); } // logical drive characteristics await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .RdbBlockLo); // low block of range reserved for hardblocks await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .RdbBlockHi); // high block of range for these hardblocks await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .LoCylinder); // low cylinder of partitionable disk area await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .HiCylinder); // high cylinder of partitionable data area await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .CylBlocks); // number of blocks available per cylinder await blockStream.WriteLittleEndianUInt32(rigidDiskBlock.AutoParkSeconds); // zero for no auto park await blockStream.WriteLittleEndianUInt32(rigidDiskBlock .HighRsdkBlock); // highest block used by RDSK (not including replacement bad blocks) await blockStream.WriteBytes(reservedBytes); // read reserved, unused word // drive identification await blockStream.WriteString(rigidDiskBlock.DiskVendor, 8, 32); await blockStream.WriteString(rigidDiskBlock.DiskProduct, 16, 32); await blockStream.WriteString(rigidDiskBlock.DiskRevision, 4, 32); // write controller vendor if (!string.IsNullOrWhiteSpace(rigidDiskBlock.ControllerVendor)) { await blockStream.WriteString(rigidDiskBlock.ControllerVendor, 8, 32); } else { await blockStream.WriteBytes(new byte[8]); } // write controller product if (!string.IsNullOrWhiteSpace(rigidDiskBlock.ControllerProduct)) { await blockStream.WriteString(rigidDiskBlock.ControllerProduct, 16, 32); } else { await blockStream.WriteBytes(new byte[16]); } // write controller revision if (!string.IsNullOrWhiteSpace(rigidDiskBlock.ControllerRevision)) { await blockStream.WriteString(rigidDiskBlock.ControllerRevision, 4, 32); } else { await blockStream.WriteBytes(new byte[4]); } await blockStream.WriteBytes(reservedBytes); // read reserved, unused word // calculate and update checksum var blockBytes = blockStream.ToArray(); rigidDiskBlock.Checksum = await BlockHelper.UpdateChecksum(blockBytes, 8); rigidDiskBlock.BlockBytes = blockBytes; return(blockBytes); }
public static async Task WriteBlock(RigidDiskBlock rigidDiskBlock, Stream stream) { // update block pointers to maintain rigid disk block structure BlockHelper.UpdateBlockPointers(rigidDiskBlock); // seek rigid disk block offset stream.Seek(rigidDiskBlock.RdbBlockLo * 512, SeekOrigin.Begin); var rigidDiskBlockBytes = await BuildBlock(rigidDiskBlock); await stream.WriteBytes(rigidDiskBlockBytes); if (rigidDiskBlock.PartitionList != BlockIdentifiers.EndOfBlock) { // seek partition block index offset stream.Seek(rigidDiskBlock.PartitionList * 512, SeekOrigin.Begin); foreach (var partitionBlock in rigidDiskBlock.PartitionBlocks) { var partitionBlockBytes = await PartitionBlockWriter.BuildBlock(partitionBlock); await stream.WriteBytes(partitionBlockBytes); if (partitionBlock.NextPartitionBlock == BlockIdentifiers.EndOfBlock) { break; } // seek next partition block index offset stream.Seek(partitionBlock.NextPartitionBlock * 512, SeekOrigin.Begin); } } if (rigidDiskBlock.FileSysHdrList != BlockIdentifiers.EndOfBlock) { // seek file system header block index offset stream.Seek(rigidDiskBlock.FileSysHdrList * 512, SeekOrigin.Begin); foreach (var fileSystemHeaderBlock in rigidDiskBlock.FileSystemHeaderBlocks) { var fileSystemHeaderBytes = await FileSystemHeaderBlockWriter.BuildBlock(fileSystemHeaderBlock); await stream.WriteBytes(fileSystemHeaderBytes); // seek load seg block index offset stream.Seek(fileSystemHeaderBlock.SegListBlocks * 512, SeekOrigin.Begin); foreach (var loadSegBlock in fileSystemHeaderBlock.LoadSegBlocks) { var loadSegBlockBytes = await LoadSegBlockWriter.BuildBlock(loadSegBlock); await stream.WriteBytes(loadSegBlockBytes); if (loadSegBlock.NextLoadSegBlock == -1) { break; } // seek next load seg block index offset stream.Seek(loadSegBlock.NextLoadSegBlock * 512, SeekOrigin.Begin); } if (fileSystemHeaderBlock.NextFileSysHeaderBlock == BlockIdentifiers.EndOfBlock) { break; } // seek next file system header block index offset stream.Seek(fileSystemHeaderBlock.NextFileSysHeaderBlock * 512, SeekOrigin.Begin); } } if (rigidDiskBlock.BadBlockList != BlockIdentifiers.EndOfBlock) { // seek bad block index offset stream.Seek(rigidDiskBlock.BadBlockList * 512, SeekOrigin.Begin); foreach (var badBlock in rigidDiskBlock.BadBlocks) { var badBlockBytes = await BadBlockWriter.BuildBlock(badBlock); await stream.WriteBytes(badBlockBytes); if (badBlock.NextBadBlock == BlockIdentifiers.EndOfBlock) { break; } // seek next bad block index offset stream.Seek(badBlock.NextBadBlock * 512, SeekOrigin.Begin); } } }
public static async Task <RigidDiskBlock> Parse(byte[] blockBytes) { var blockStream = new MemoryStream(blockBytes); var magic = await blockStream.ReadAsciiString(); // Identifier 32 bit word : 'RDSK' if (!magic.Equals(BlockIdentifiers.RigidDiskBlock)) { return(null); } await blockStream.ReadUInt32(); // Size of the structure for checksums var checksum = await blockStream.ReadInt32(); // Checksum of the structure var hostId = await blockStream.ReadUInt32(); // SCSI Target ID of host, not really used var blockSize = await blockStream.ReadUInt32(); // Size of disk blocks var flags = await blockStream.ReadUInt32(); // RDB Flags var badBlockList = await blockStream.ReadUInt32(); // Bad block list var partitionList = await blockStream.ReadUInt32(); // Partition list var fileSysHdrList = await blockStream.ReadUInt32(); // File system header list var driveInitCode = await blockStream.ReadUInt32(); // Drive specific init code var bootBlockList = await blockStream.ReadUInt32(); // Amiga OS 4 Boot Blocks // skip reserved blockStream.Seek(4 * 5, SeekOrigin.Current); // physical drive characteristics var cylinders = await blockStream.ReadUInt32(); // Number of the cylinders of the drive var sectors = await blockStream.ReadUInt32(); // Number of sectors of the drive var heads = await blockStream.ReadUInt32(); // Number of heads of the drive var interleave = await blockStream.ReadUInt32(); // Interleave var parkingZone = await blockStream.ReadUInt32(); // Head parking cylinder // skip reserved blockStream.Seek(4 * 3, SeekOrigin.Current); var writePreComp = await blockStream.ReadUInt32(); // Starting cylinder of write pre-compensation var reducedWrite = await blockStream.ReadUInt32(); // Starting cylinder of reduced write current var stepRate = await blockStream.ReadUInt32(); // Step rate of the drive // skip reserved blockStream.Seek(4 * 5, SeekOrigin.Current); // logical drive characteristics var rdbBlockLo = await blockStream.ReadUInt32(); // low block of range reserved for hardblocks var rdbBlockHi = await blockStream.ReadUInt32(); // high block of range for these hardblocks var loCylinder = await blockStream.ReadUInt32(); // low cylinder of partitionable disk area var hiCylinder = await blockStream.ReadUInt32(); // high cylinder of partitionable data area var cylBlocks = await blockStream.ReadUInt32(); // number of blocks available per cylinder var autoParkSeconds = await blockStream.ReadUInt32(); // zero for no auto park var highRsdkBlock = await blockStream.ReadUInt32(); // highest block used by RDSK (not including replacement bad blocks) // skip reserved blockStream.Seek(4, SeekOrigin.Current); // drive identification var diskVendor = (await blockStream.ReadBytes(8)).ReadNullTerminatedString().Trim(); var diskProduct = (await blockStream.ReadBytes(16)).ReadNullTerminatedString().Trim(); var diskRevision = (await blockStream.ReadBytes(4)).ReadNullTerminatedString().Trim(); var controllerVendor = (await blockStream.ReadBytes(8)).ReadNullTerminatedString().Trim(); var controllerProduct = (await blockStream.ReadBytes(16)).ReadNullTerminatedString().Trim(); var controllerRevision = (await blockStream.ReadBytes(4)).ReadNullTerminatedString().Trim(); // skip reserved blockStream.Seek(4, SeekOrigin.Current); // calculate size of disk in bytes var diskSize = (long)cylinders * heads * sectors * blockSize; var calculatedChecksum = await BlockHelper.CalculateChecksum(blockBytes, 8); if (checksum != calculatedChecksum) { throw new Exception("Invalid rigid disk block checksum"); } return(new RigidDiskBlock { BlockBytes = blockBytes, Checksum = checksum, HostId = hostId, BlockSize = blockSize, Flags = flags, BadBlockList = badBlockList, PartitionList = partitionList, FileSysHdrList = fileSysHdrList, DriveInitCode = driveInitCode, BootBlockList = bootBlockList, Cylinders = cylinders, Sectors = sectors, Heads = heads, Interleave = interleave, ParkingZone = parkingZone, WritePreComp = writePreComp, ReducedWrite = reducedWrite, StepRate = stepRate, RdbBlockLo = rdbBlockLo, RdbBlockHi = rdbBlockHi, LoCylinder = loCylinder, HiCylinder = hiCylinder, CylBlocks = cylBlocks, AutoParkSeconds = autoParkSeconds, HighRsdkBlock = highRsdkBlock, DiskVendor = diskVendor, DiskProduct = diskProduct, DiskRevision = diskRevision, ControllerVendor = controllerVendor, ControllerProduct = controllerProduct, ControllerRevision = controllerRevision, DiskSize = diskSize }); }
public static async Task <PartitionBlock> Parse(RigidDiskBlock rigidDiskBlock, byte[] blockBytes) { var blockStream = new MemoryStream(blockBytes); var magic = await blockStream.ReadAsciiString(); // Identifier 32 bit word : 'PART' if (!magic.Equals(BlockIdentifiers.PartitionBlock)) { return(null); } await blockStream.ReadUInt32(); // Size of the structure for checksums var checksum = await blockStream.ReadInt32(); // Checksum of the structure var hostId = await blockStream.ReadUInt32(); // SCSI Target ID of host, not really used var nextPartitionBlock = await blockStream.ReadUInt32(); // Block number of the next PartitionBlock var flags = await blockStream.ReadUInt32(); // Part Flags (NOMOUNT and BOOTABLE) // skip reserved blockStream.Seek(4 * 2, SeekOrigin.Current); var devFlags = await blockStream.ReadUInt32(); // Preferred flags for OpenDevice var driveNameLength = (await blockStream.ReadBytes(1)).FirstOrDefault(); // Preferred DOS device name: BSTR form var driveName = await blockStream.ReadString(driveNameLength); // # Preferred DOS device name: BSTR form if (driveNameLength < 31) { await blockStream.ReadBytes(31 - driveNameLength); } // skip reserved blockStream.Seek(4 * 15, SeekOrigin.Current); var sizeOfVector = await blockStream.ReadUInt32(); // Size of Environment vector var sizeBlock = await blockStream.ReadUInt32(); // Size of the blocks in 32 bit words, usually 128 var secOrg = await blockStream.ReadUInt32(); // Not used; must be 0 var surfaces = await blockStream.ReadUInt32(); // Number of heads (surfaces) var sectors = await blockStream.ReadUInt32(); // Disk sectors per block, used with SizeBlock, usually 1 var blocksPerTrack = await blockStream.ReadUInt32(); // Blocks per track. drive specific var reserved = await blockStream.ReadUInt32(); // DOS reserved blocks at start of partition. var preAlloc = await blockStream.ReadUInt32(); // DOS reserved blocks at end of partition var interleave = await blockStream.ReadUInt32(); // Not used, usually 0 var lowCyl = await blockStream.ReadUInt32(); // First cylinder of the partition var highCyl = await blockStream.ReadUInt32(); // Last cylinder of the partition var numBuffer = await blockStream.ReadUInt32(); // Initial # DOS of buffers. var bufMemType = await blockStream.ReadUInt32(); // Type of mem to allocate for buffers var maxTransfer = await blockStream.ReadUInt32(); // Max number of bytes to transfer at a time var mask = await blockStream.ReadUInt32(); // Address Mask to block out certain memory var bootPriority = await blockStream.ReadUInt32(); // Boot priority for autoboot var dosType = await blockStream.ReadBytes(4); // # Dostype of the file system var baud = await blockStream.ReadUInt32(); // Baud rate for serial handler var control = await blockStream.ReadUInt32(); // Control word for handler/filesystem var bootBlocks = await blockStream.ReadUInt32(); // Number of blocks containing boot code // skip reserved blockStream.Seek(4 * 12, SeekOrigin.Current); // calculate size of partition in bytes var partitionSize = (long)(highCyl - lowCyl + 1) * surfaces * blocksPerTrack * rigidDiskBlock.BlockSize; var calculatedChecksum = await BlockHelper.CalculateChecksum(blockBytes, 8); if (checksum != calculatedChecksum) { throw new Exception("Invalid partition block checksum"); } var fileSystemBlockSize = sizeBlock * 4; return(new PartitionBlock { BlockBytes = blockBytes, Checksum = checksum, HostId = hostId, NextPartitionBlock = nextPartitionBlock, Flags = flags, DevFlags = devFlags, DriveName = driveName, SizeOfVector = sizeOfVector, SizeBlock = sizeBlock, SecOrg = secOrg, Surfaces = surfaces, Sectors = sectors, BlocksPerTrack = blocksPerTrack, Reserved = reserved, PreAlloc = preAlloc, Interleave = interleave, LowCyl = lowCyl, HighCyl = highCyl, NumBuffer = numBuffer, BufMemType = bufMemType, MaxTransfer = maxTransfer, Mask = mask, BootPriority = bootPriority, DosType = dosType, Baud = baud, Control = control, BootBlocks = bootBlocks, PartitionSize = partitionSize, FileSystemBlockSize = fileSystemBlockSize, }); }
public static async Task <byte[]> BuildBlock(FileSystemHeaderBlock fileSystemHeaderBlock) { var blockStream = new MemoryStream( fileSystemHeaderBlock.BlockBytes == null || fileSystemHeaderBlock.BlockBytes.Length == 0 ? new byte[BlockSize.FileSystemHeaderBlock * 4] : fileSystemHeaderBlock.BlockBytes); await blockStream.WriteAsciiString(BlockIdentifiers.FileSystemHeaderBlock); await blockStream.WriteLittleEndianUInt32(BlockSize.FileSystemHeaderBlock); // size // skip checksum, calculated when block is built blockStream.Seek(4, SeekOrigin.Current); await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock .HostId); // SCSI Target ID of host, not really used await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock .NextFileSysHeaderBlock); // Block number of the next FileSysHeaderBlock await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.Flags); // Flags // skip reserved blockStream.Seek(4 * 2, SeekOrigin.Current); await blockStream .WriteBytes(fileSystemHeaderBlock .DosType); // # Dostype of the file system, file system description: match this with partition environment's DE_DOSTYPE entry await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock .Version); // filesystem version 0x0027001b == 39.27 await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.PatchFlags); await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.Type); await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.Task); await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.Lock); await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.Handler); await blockStream.WriteLittleEndianUInt32(fileSystemHeaderBlock.StackSize); await blockStream.WriteLittleEndianInt32(fileSystemHeaderBlock.Priority); await blockStream.WriteLittleEndianInt32(fileSystemHeaderBlock.Startup); await blockStream.WriteLittleEndianInt32(fileSystemHeaderBlock .SegListBlocks); // first of linked list of LoadSegBlocks await blockStream.WriteLittleEndianInt32(fileSystemHeaderBlock.GlobalVec); // skip reserved blockStream.Seek((23 + 21) * 4, SeekOrigin.Current); // calculate and update checksum var blockBytes = blockStream.ToArray(); fileSystemHeaderBlock.Checksum = await BlockHelper.UpdateChecksum(blockBytes, 8); fileSystemHeaderBlock.BlockBytes = blockBytes; return(blockBytes); }