/// <summary> /// Creates the header. /// </summary> /// <param name="blocks">The blocks.</param> /// <param name="guid">The GUID.</param> /// <param name="lastSnapGuid">The last snap GUID.</param> /// <param name="diskGeometry">The disk geometry.</param> /// <returns></returns> public static byte[] CreateHeader(uint blocks, byte[] guid, byte[] lastSnapGuid, DiskGeometry diskGeometry) { Mosa.ClassLib.BinaryFormat binaryHeader = new Mosa.ClassLib.BinaryFormat(512); binaryHeader.SetString(VHIHeaderOffset.HeaderText, HeaderText, (uint)HeaderText.Length); binaryHeader.SetByte(VHIHeaderOffset.HeaderText + 0x25, 0x0A); binaryHeader.SetUInt(VHIHeaderOffset.ImageSignature, 0xBEda107F); binaryHeader.SetUInt(VHIHeaderOffset.Version, 0x00010001); binaryHeader.SetUInt(VHIHeaderOffset.HeaderSize, 0x180); binaryHeader.SetUInt(VHIHeaderOffset.ImageType, 0x02); binaryHeader.SetUInt(VHIHeaderOffset.ImageFlags, 0x00); binaryHeader.SetUInt(VHIHeaderOffset.OffsetBlocks, 0x200); binaryHeader.SetUInt(VHIHeaderOffset.OffsetData, 0x400); binaryHeader.SetUInt(VHIHeaderOffset.DiskGeometryCylinders, 0); // diskGeometry.Cylinders); binaryHeader.SetUInt(VHIHeaderOffset.DiskGeometryHeads, 0); // diskGeometry.Heads); binaryHeader.SetUInt(VHIHeaderOffset.DiskGeometrySectors, 0); // diskGeometry.SectorsPerTrack); binaryHeader.SetUInt(VHIHeaderOffset.SectorSize, 512); binaryHeader.SetULong(VHIHeaderOffset.DiskSize, blocks * 512); binaryHeader.SetUInt(VHIHeaderOffset.BlockSize, 0x100000); binaryHeader.SetUInt(VHIHeaderOffset.BlockExtraData, 0); binaryHeader.SetUInt(VHIHeaderOffset.BlocksInHDD, (uint)((blocks * 512) / 0x100000)); binaryHeader.SetUInt(VHIHeaderOffset.BlocksAllocated, (uint)((blocks * 512) / 0x100000)); binaryHeader.SetBytes(VHIHeaderOffset.UUID, guid, 0, 16); binaryHeader.SetBytes(VHIHeaderOffset.UUIDLastSnap, lastSnapGuid, 0, 16); return binaryHeader.Data; }
/// <summary> /// Creates the VHD footer. /// </summary> /// <param name="blocks">The blocks.</param> /// <param name="timeStamp">The time stamp.</param> /// <param name="guid">The GUID.</param> /// <param name="diskGeometry">The disk geometry.</param> /// <returns></returns> static public byte[] CreateFooter(ulong blocks, uint timeStamp, byte[] guid, DiskGeometry diskGeometry) { Mosa.ClassLib.BinaryFormat binaryFooter = new Mosa.ClassLib.BinaryFormat(512); binaryFooter.SetString(VHDFooterOffset.Cookie, "conectix", 8); binaryFooter.SetUIntReversed(VHDFooterOffset.Features, 0x00000002); binaryFooter.SetUIntReversed(VHDFooterOffset.FileFormatVersion, 0x00010000); binaryFooter.SetULong(VHDFooterOffset.DataOffset, ~(ulong)0); binaryFooter.SetUIntReversed(VHDFooterOffset.TimeStamp, timeStamp); binaryFooter.SetString(VHDFooterOffset.CreatorApplication, "MOSA", 4); binaryFooter.SetUIntReversed(VHDFooterOffset.CreatorVersion, 0x00050000); binaryFooter.SetUIntReversed(VHDFooterOffset.CreatorHostOS, 0x5769326B); // Windows binaryFooter.SetULongReversed(VHDFooterOffset.OriginalSize, blocks * 512); binaryFooter.SetULongReversed(VHDFooterOffset.CurrentSize, blocks * 512); binaryFooter.SetUShortReversed(VHDFooterOffset.DiskGeometryCylinders, diskGeometry.Cylinders); binaryFooter.SetByte(VHDFooterOffset.DiskGeometryHeads, diskGeometry.Heads); binaryFooter.SetByte(VHDFooterOffset.DiskGeometrySectors, (byte)diskGeometry.SectorsPerTrack); binaryFooter.SetUIntReversed(VHDFooterOffset.DiskType, 0x02); // Fixed disk binaryFooter.SetUIntReversed(VHDFooterOffset.Checksum, 0x00); binaryFooter.SetBytes(VHDFooterOffset.UniqueId, guid, 0, 16); binaryFooter.SetByte(VHDFooterOffset.SavedState, 0x00); // No saved state uint checksum = 0; for (uint index = 0; index < 512; index++) { checksum += binaryFooter.Data[index]; } binaryFooter.SetUIntReversed(VHDFooterOffset.Checksum, ~checksum); return(binaryFooter.Data); }
/// <summary> /// Creates the VHD footer. /// </summary> /// <param name="blocks">The blocks.</param> /// <param name="timeStamp">The time stamp.</param> /// <param name="guid">The GUID.</param> /// <param name="diskGeometry">The disk geometry.</param> /// <returns></returns> public static byte[] CreateFooter(ulong blocks, uint timeStamp, byte[] guid, DiskGeometry diskGeometry) { Mosa.ClassLib.BinaryFormat binaryFooter = new Mosa.ClassLib.BinaryFormat(512); binaryFooter.SetString(VHDFooterOffset.Cookie, "conectix", 8); binaryFooter.SetUIntReversed(VHDFooterOffset.Features, 0x00000002); binaryFooter.SetUIntReversed(VHDFooterOffset.FileFormatVersion, 0x00010000); binaryFooter.SetULong(VHDFooterOffset.DataOffset, ~(ulong)0); binaryFooter.SetUIntReversed(VHDFooterOffset.TimeStamp, timeStamp); binaryFooter.SetString(VHDFooterOffset.CreatorApplication, "MOSA", 4); binaryFooter.SetUIntReversed(VHDFooterOffset.CreatorVersion, 0x00050000); binaryFooter.SetUIntReversed(VHDFooterOffset.CreatorHostOS, 0x5769326B); // Windows binaryFooter.SetULongReversed(VHDFooterOffset.OriginalSize, blocks*512); binaryFooter.SetULongReversed(VHDFooterOffset.CurrentSize, blocks * 512); binaryFooter.SetUShortReversed(VHDFooterOffset.DiskGeometryCylinders, diskGeometry.Cylinders); binaryFooter.SetByte(VHDFooterOffset.DiskGeometryHeads, diskGeometry.Heads); binaryFooter.SetByte(VHDFooterOffset.DiskGeometrySectors, (byte)diskGeometry.SectorsPerTrack); binaryFooter.SetUIntReversed(VHDFooterOffset.DiskType, 0x02); // Fixed disk binaryFooter.SetUIntReversed(VHDFooterOffset.Checksum, 0x00); binaryFooter.SetBytes(VHDFooterOffset.UniqueId, guid, 0, 16); binaryFooter.SetByte(VHDFooterOffset.SavedState, 0x00); // No saved state uint checksum = 0; for (uint index = 0; index < 512; index++) checksum += binaryFooter.Data[index]; binaryFooter.SetUIntReversed(VHDFooterOffset.Checksum, ~checksum); return binaryFooter.Data; }
/// <summary> /// Computes the CHS given a disk geometry /// </summary> /// <param name="diskGeometry">The disk geometry.</param> /// <param name="lba">The lba.</param> public void SetCHS(DiskGeometry diskGeometry, ulong lba) { if ((lba / (uint)(diskGeometry.SectorsPerTrack * diskGeometry.Heads) > 1023)) lba = (uint)diskGeometry.Heads * diskGeometry.SectorsPerTrack * 1024 - 1; Sector = (ushort)(lba % diskGeometry.SectorsPerTrack + 1); lba /= diskGeometry.SectorsPerTrack; Head = (byte)(lba % diskGeometry.Heads); lba /= diskGeometry.Heads; Cylinder = (ushort)(lba & 0xFF); Sector |= (ushort)((lba >> 2) & 0xC0); }
/// <summary> /// Writes the master boot block. /// </summary> /// <returns></returns> public bool Write() { if (!diskDevice.CanWrite) { return(false); } BinaryFormat masterboot = new BinaryFormat(new byte[512]); masterboot.SetUInt(MBR.DiskSignature, diskSignature); masterboot.SetUShort(MBR.MBRSignature, MBRConstant.MBRSignature); if (code != null) { for (uint index = 0; ((index < MBRConstant.CodeAreaSize) && (index < code.Length)); index++) { masterboot.SetByte(index, code[index]); } } for (uint index = 0; index < MaxMBRPartitions; index++) { if (Partitions[index].TotalBlocks != 0) { uint offset = MBR.FirstPartition + (index * 16); masterboot.SetByte(offset + PartitionRecord.Status, (byte)(Partitions[index].Bootable ? 0x80 : 0x00)); masterboot.SetByte(offset + PartitionRecord.PartitionType, Partitions[index].PartitionType); masterboot.SetUInt(offset + PartitionRecord.LBA, Partitions[index].StartLBA); masterboot.SetUInt(offset + PartitionRecord.Sectors, Partitions[index].TotalBlocks); DiskGeometry diskGeometry = new DiskGeometry(); diskGeometry.GuessGeometry(diskDevice.TotalBlocks); CHS chsStart = new CHS(); CHS chsEnd = new CHS(); chsStart.SetCHS(diskGeometry, Partitions[index].StartLBA); chsEnd.SetCHS(diskGeometry, Partitions[index].StartLBA + Partitions[index].TotalBlocks - 1); masterboot.SetByte(offset + PartitionRecord.FirstCRS, chsStart.Head); masterboot.SetByte(offset + PartitionRecord.FirstCRS + 1, (byte)((chsStart.Sector & 0x3F) | ((chsStart.Cylinder >> 8) & 0x03))); masterboot.SetByte(offset + PartitionRecord.FirstCRS + 2, (byte)(chsStart.Cylinder & 0xFF)); masterboot.SetByte(offset + PartitionRecord.LastCRS, chsEnd.Head); masterboot.SetByte(offset + PartitionRecord.LastCRS + 1, (byte)((chsEnd.Sector & 0x3F) | ((chsEnd.Cylinder >> 8) & 0x03))); masterboot.SetByte(offset + PartitionRecord.LastCRS + 2, (byte)(chsEnd.Cylinder & 0xFF)); } } diskDevice.WriteBlock(0, 1, masterboot.Data); return(true); }
/// <summary> /// Computes the CHS given a disk geometry /// </summary> /// <param name="diskGeometry">The disk geometry.</param> /// <param name="lba">The lba.</param> public void SetCHS(DiskGeometry diskGeometry, ulong lba) { if ((lba / (uint)(diskGeometry.SectorsPerTrack * diskGeometry.Heads) > 1023)) { lba = (uint)diskGeometry.Heads * diskGeometry.SectorsPerTrack * 1024 - 1; } Sector = (ushort)(lba % diskGeometry.SectorsPerTrack + 1); lba /= diskGeometry.SectorsPerTrack; Head = (byte)(lba % diskGeometry.Heads); lba /= diskGeometry.Heads; Cylinder = (ushort)(lba & 0xFF); Sector |= (ushort)((lba >> 2) & 0xC0); }
/// <summary> /// Initializes a new instance of the <see cref="CHS"/> struct. /// </summary> /// <param name="diskGeometry">The disk geometry.</param> /// <param name="lba">The lba.</param> public CHS(DiskGeometry diskGeometry, ulong lba) { SetCHS(diskGeometry, lba); }
/// <summary> /// Creates the specified options. /// </summary> /// <param name="options">The options.</param> public static void Create(BootImageOptions options) { if (File.Exists(options.DiskImageFileName)) { File.Delete(options.DiskImageFileName); } uint blockCount = options.BlockCount; if (blockCount == 0) { blockCount = 8400 + 1; foreach (var file in options.IncludeFiles) { blockCount += ((uint)file.Content.Length / SectorSize) + 1; } } var diskGeometry = new DiskGeometry(); diskGeometry.GuessGeometry(blockCount); // Create disk image file var diskDevice = new BlockFileStream(options.DiskImageFileName); if (options.ImageFormat == ImageFormat.VDI) { // Create header var header = VDI.CreateHeader( blockCount, options.MediaGuid.ToByteArray(), options.MediaLastSnapGuid.ToByteArray(), diskGeometry ); diskDevice.WriteBlock(0, 1, header); var map = VDI.CreateImageMap(blockCount); diskDevice.WriteBlock(1, (uint)(map.Length / SectorSize), map); diskDevice.BlockOffset = 1 + (uint)(map.Length / 512); } // Expand disk image diskDevice.WriteBlock(blockCount - 1, 1, new byte[SectorSize]); // Create partition device PartitionDevice partitionDevice; if (options.MBROption) { // Create master boot block record var mbr = new MasterBootBlock(diskDevice); // Setup partition entry mbr.DiskSignature = 0x12345678; mbr.Partitions[0].Bootable = true; mbr.Partitions[0].StartLBA = diskGeometry.SectorsPerTrack; mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA; switch (options.FileSystem) { case FileSystem.FAT12: mbr.Partitions[0].PartitionType = PartitionType.FAT12; break; case FileSystem.FAT16: mbr.Partitions[0].PartitionType = PartitionType.FAT16; break; case FileSystem.FAT32: mbr.Partitions[0].PartitionType = PartitionType.FAT32; break; default: break; } mbr.Code = options.MBRCode; mbr.Write(); partitionDevice = new PartitionDevice(diskDevice, mbr.Partitions[0], false); } else { partitionDevice = new PartitionDevice(diskDevice, false); } // Set FAT settings var fatSettings = new FatSettings(); switch (options.FileSystem) { case FileSystem.FAT12: fatSettings.FATType = FatType.FAT12; break; case FileSystem.FAT16: fatSettings.FATType = FatType.FAT16; break; case FileSystem.FAT32: fatSettings.FATType = FatType.FAT32; break; default: break; } fatSettings.FloppyMedia = false; fatSettings.VolumeLabel = options.VolumeLabel; fatSettings.SerialID = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; fatSettings.SectorsPerTrack = diskGeometry.SectorsPerTrack; fatSettings.NumberOfHeads = diskGeometry.Heads; fatSettings.HiddenSectors = diskGeometry.SectorsPerTrack; fatSettings.OSBootCode = options.FatBootCode; // Create FAT file system var fat = new FatFileSystem(partitionDevice); if (!fat.Format(fatSettings)) { throw new Exception("ERROR: Invalid FAT settings"); } fat.SetVolumeName(options.VolumeLabel); foreach (var includeFile in options.IncludeFiles) { var fileAttributes = new FatFileAttributes(); if (includeFile.Archive) fileAttributes |= FatFileAttributes.Archive; if (includeFile.ReadOnly) fileAttributes |= FatFileAttributes.ReadOnly; if (includeFile.Hidden) fileAttributes |= FatFileAttributes.Hidden; if (includeFile.System) fileAttributes |= FatFileAttributes.System; string newname = (Path.GetFileNameWithoutExtension(includeFile.Filename).PadRight(8).Substring(0, 8) + Path.GetExtension(includeFile.Filename).PadRight(4).Substring(1, 3)).ToUpper(); var location = fat.CreateFile(newname, fileAttributes); if (!location.IsValid) throw new Exception("Unable to write file"); var fatFileStream = new FatFileStream(fat, location); fatFileStream.Write(includeFile.Content, 0, includeFile.Content.Length); fatFileStream.Flush(); } if (options.PatchSyslinuxOption) { if (options.BootLoader == BootLoader.Syslinux_6_03) { Syslinux.PatchSyslinux_6_03(partitionDevice, fat); } else if (options.BootLoader == BootLoader.Syslinux_3_72) { Syslinux.PatchSyslinux_3_72(partitionDevice, fat); } } if (options.ImageFormat == ImageFormat.VHD) { // Create footer var footer = VHD.CreateFooter( blockCount, (uint)(DateTime.Now - (new DateTime(2000, 1, 1, 0, 0, 0))).Seconds, options.MediaGuid.ToByteArray(), diskGeometry ); diskDevice.WriteBlock(blockCount, 1, footer); } diskDevice.Dispose(); }
/// <summary> /// Creates the specified options. /// </summary> /// <param name="options">The options.</param> public static void Create(Options options) { if (File.Exists(options.DiskImageFileName)) { File.Delete(options.DiskImageFileName); } uint blockCount = options.BlockCount; if (blockCount == 0) { blockCount = 8400 + 1; foreach (var file in options.IncludeFiles) { blockCount += ((uint)file.Content.Length / 512) + 1; } } var diskGeometry = new Mosa.DeviceSystem.DiskGeometry(); diskGeometry.GuessGeometry(blockCount); // Create disk image file BlockFileStream diskDevice = new BlockFileStream(options.DiskImageFileName); if (options.ImageFormat == ImageFormatType.VDI) { // Create header byte[] header = Mosa.DeviceSystem.VDI.CreateHeader( blockCount, options.MediaGuid.ToByteArray(), options.MediaLastSnapGuid.ToByteArray(), diskGeometry ); diskDevice.WriteBlock(0, 1, header); byte[] map = Mosa.DeviceSystem.VDI.CreateImageMap(blockCount); diskDevice.WriteBlock(1, (uint)(map.Length / 512), map); diskDevice.BlockOffset = 1 + (uint)(map.Length / 512); } // Expand disk image diskDevice.WriteBlock(blockCount - 1, 1, new byte[512]); // Create partition device PartitionDevice partitionDevice; if (options.MBROption) { // Create master boot block record MasterBootBlock mbr = new MasterBootBlock(diskDevice); // Setup partition entry mbr.DiskSignature = 0x12345678; mbr.Partitions[0].Bootable = true; mbr.Partitions[0].StartLBA = diskGeometry.SectorsPerTrack; mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA; switch (options.FileSystem) { case FileSystemType.FAT12: mbr.Partitions[0].PartitionType = PartitionType.FAT12; break; case FileSystemType.FAT16: mbr.Partitions[0].PartitionType = PartitionType.FAT16; break; case FileSystemType.FAT32: mbr.Partitions[0].PartitionType = PartitionType.FAT32; break; default: break; } mbr.Code = options.MBRCode; mbr.Write(); partitionDevice = new PartitionDevice(diskDevice, mbr.Partitions[0], false); } else { partitionDevice = new PartitionDevice(diskDevice, false); } // Set FAT settings FatSettings fatSettings = new FatSettings(); switch (options.FileSystem) { case FileSystemType.FAT12: fatSettings.FATType = FatType.FAT12; break; case FileSystemType.FAT16: fatSettings.FATType = FatType.FAT16; break; case FileSystemType.FAT32: fatSettings.FATType = FatType.FAT32; break; default: break; } fatSettings.FloppyMedia = false; fatSettings.VolumeLabel = options.VolumeLabel; fatSettings.SerialID = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; fatSettings.SectorsPerTrack = diskGeometry.SectorsPerTrack; fatSettings.NumberOfHeads = diskGeometry.Heads; fatSettings.HiddenSectors = diskGeometry.SectorsPerTrack; fatSettings.OSBootCode = options.FatBootCode; // Create FAT file system FatFileSystem fat = new FatFileSystem(partitionDevice); if (!fat.Format(fatSettings)) { throw new Exception("ERROR: Invalid FAT settings"); } fat.SetVolumeName(options.VolumeLabel); foreach (var includeFile in options.IncludeFiles) { Mosa.FileSystem.FAT.FatFileAttributes fileAttributes = new Mosa.FileSystem.FAT.FatFileAttributes(); if (includeFile.Archive) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Archive; if (includeFile.ReadOnly) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.ReadOnly; if (includeFile.Hidden) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Hidden; if (includeFile.System) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.System; //byte[] file = File.ReadAllBytes(includeFile.Filename); string newname = (Path.GetFileNameWithoutExtension(includeFile.Filename).PadRight(8).Substring(0, 8) + Path.GetExtension(includeFile.Filename).PadRight(4).Substring(1, 3)).ToUpper(); FatFileLocation location = fat.CreateFile(newname, fileAttributes, 0); if (!location.Valid) throw new Exception("Unable to write file"); FatFileStream fatFileStream = new FatFileStream(fat, location); fatFileStream.Write(includeFile.Content, 0, includeFile.Content.Length); fatFileStream.Flush(); } if (options.PatchSyslinuxOption) { // Locate ldlinux.sys file for patching string filename = "ldlinux.sys"; string name = (Path.GetFileNameWithoutExtension(filename) + Path.GetExtension(filename).PadRight(4).Substring(0, 4)).ToUpper(); FatFileLocation location = fat.FindEntry(new Mosa.FileSystem.FAT.Find.WithName(name), 0); if (location.Valid) { // Read boot sector Mosa.ClassLib.BinaryFormat bootSector = new Mosa.ClassLib.BinaryFormat(partitionDevice.ReadBlock(0, 1)); // Set the first sector location of the file bootSector.SetUInt(0x1F8, fat.GetSectorByCluster(location.FirstCluster)); // Change jump address bootSector.SetUInt(0x01, 0x58); // Write back patched boot sector partitionDevice.WriteBlock(0, 1, bootSector.Data); // Get the file size & number of sectors used uint fileSize = fat.GetFileSize(location.DirectorySector, location.DirectorySectorIndex); uint sectorCount = (fileSize + 511) >> 9; uint[] sectors = new uint[65]; uint nsec = 0; // Create list of the first 65 sectors of the file for (uint cluster = location.FirstCluster; ((cluster != 0) & (nsec <= 64)); cluster = fat.GetNextCluster(cluster)) { uint sec = fat.GetSectorByCluster(cluster); for (uint s = 0; s < fat.SectorsPerCluster; s++) sectors[nsec++] = sec + s; } // Read the first cluster of the file Mosa.ClassLib.BinaryFormat firstCluster = new Mosa.ClassLib.BinaryFormat(fat.ReadCluster(location.FirstCluster)); uint patchArea = 0; // Search for 0x3EB202FE (magic) for (patchArea = 0; (firstCluster.GetUInt(patchArea) != 0x3EB202FE) && (patchArea < fat.ClusterSizeInBytes); patchArea += 4) ; patchArea = patchArea + 8; if (patchArea < fat.ClusterSizeInBytes) { // Set up the totals firstCluster.SetUShort(patchArea, (ushort)(fileSize >> 2)); firstCluster.SetUShort(patchArea + 2, (ushort)(sectorCount - 1)); // Clear sector entries firstCluster.Fill(patchArea + 8, 0, 64 * 4); // Set sector entries for (nsec = 0; nsec < 64; nsec++) firstCluster.SetUInt(patchArea + 8 + (nsec * 4), sectors[nsec + 1]); // Clear out checksum firstCluster.SetUInt(patchArea + 4, 0); // Write back the updated cluster fat.WriteCluster(location.FirstCluster, firstCluster.Data); // Re-Calculate checksum by opening the file FatFileStream file = new FatFileStream(fat, location); uint csum = 0x3EB202FE; for (uint index = 0; index < (file.Length >> 2); index++) { uint value = (uint)file.ReadByte() | ((uint)file.ReadByte() << 8) | ((uint)file.ReadByte() << 16) | ((uint)file.ReadByte() << 24); csum -= value; } // Set the checksum firstCluster.SetUInt(patchArea + 4, csum); // Write patched cluster back to disk fat.WriteCluster(location.FirstCluster, firstCluster.Data); } } } if (options.ImageFormat == ImageFormatType.VHD) { // Create footer byte[] footer = Mosa.DeviceSystem.VHD.CreateFooter( blockCount, (uint)(DateTime.Now - (new DateTime(2000, 1, 1, 0, 0, 0))).Seconds, options.MediaGuid.ToByteArray(), diskGeometry ); diskDevice.WriteBlock(blockCount, 1, footer); } diskDevice.Dispose(); }
/// <summary> /// Main /// </summary> /// <param name="args">The args.</param> /// <returns></returns> static int Main(string[] args) { Console.WriteLine(); Console.WriteLine("MakeImageBoot v1.0 [www.mosa-project.org]"); Console.WriteLine("Copyright 2010. New BSD License."); Console.WriteLine("Written by Philipp Garcia ([email protected])"); Console.WriteLine(); string mbrFilename = string.Empty; string fatcodeFilename = string.Empty; string volumeLabel = string.Empty; ImageFormat imageFormat = ImageFormat.VHD; bool mbrOption = true; bool patchSyslinuxOption = false; bool floppyMedia = false; uint blockCount = 1024 * 1024 / 512; FileSystem fileSystem = FileSystem.FAT12; List<IncludeFile> includeFiles = new List<IncludeFile>(); bool valid = (args.Length < 2); if (valid) valid = System.IO.File.Exists(args[0]); if (valid) { Console.WriteLine("Usage: CreateBootImage <boot.config file> <image name>"); Console.Error.WriteLine("ERROR: Missing arguments"); return -1; } Console.WriteLine("Building image..."); try { StreamReader reader = File.OpenText(args[0]); while (true) { string line = reader.ReadLine(); if (line == null) break; if (string.IsNullOrEmpty(line)) continue; string[] parts = line.Split('\t'); switch (parts[0].Trim()) { case "-mbr": mbrOption = true; mbrFilename = (parts.Length > 1) ? parts[1] : null; break; case "-boot": fatcodeFilename = (parts.Length > 1) ? parts[1] : null; break; case "-vhd": imageFormat = ImageFormat.VHD; break; case "-img": imageFormat = ImageFormat.IMG; break; case "-vdi": imageFormat = ImageFormat.VDI; break; case "-syslinux": patchSyslinuxOption = true; break; case "-fat12": fileSystem = FileSystem.FAT12; break; case "-fat16": fileSystem = FileSystem.FAT16; break; case "-fat32": fileSystem = FileSystem.FAT32; break; case "-file": if (parts.Length > 2) includeFiles.Add(new IncludeFile(parts[1], parts[2])); else includeFiles.Add(new IncludeFile(parts[1])); break; case "-blocks": blockCount = Convert.ToUInt32(parts[1]); break; case "-volume": volumeLabel = parts[1]; break; case "-floppy": floppyMedia = true; break; default: break; } } reader.Close(); if (System.IO.File.Exists(args[1])) System.IO.File.Delete(args[1]); DiskGeometry diskGeometry = new Mosa.DeviceSystem.DiskGeometry(); diskGeometry.GuessGeometry(blockCount); Console.WriteLine("Disk Geometry CHS = " + diskGeometry.Cylinders + "/" + diskGeometry.Heads + "/" + diskGeometry.SectorsPerTrack); // Create disk image file Mosa.EmulatedDevices.Synthetic.DiskDevice diskDevice = new Mosa.EmulatedDevices.Synthetic.DiskDevice(args[1]); if (imageFormat == ImageFormat.VDI) { // Create header byte[] header = Mosa.DeviceSystem.VDI.CreateHeader( blockCount, Guid.NewGuid().ToByteArray(), Guid.NewGuid().ToByteArray(), diskGeometry ); diskDevice.WriteBlock(0, 1, header); byte[] map = Mosa.DeviceSystem.VDI.CreateImageMap(blockCount); diskDevice.WriteBlock(1, (uint)(map.Length / 512), map); diskDevice.BlockOffset = 1 + (uint)(map.Length / 512); } // Expand disk image diskDevice.WriteBlock(blockCount - 1, 1, new byte[512]); // Create partition device PartitionDevice partitionDevice; if (mbrOption) { // Create master boot block record MasterBootBlock mbr = new MasterBootBlock(diskDevice); // Setup partition entry mbr.DiskSignature = 0x12345678; mbr.Partitions[0].Bootable = true; mbr.Partitions[0].StartLBA = diskGeometry.SectorsPerTrack; mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA; switch (fileSystem) { case FileSystem.FAT12: mbr.Partitions[0].PartitionType = PartitionType.FAT12; break; case FileSystem.FAT16: mbr.Partitions[0].PartitionType = PartitionType.FAT16; break; case FileSystem.FAT32: mbr.Partitions[0].PartitionType = PartitionType.FAT32; break; default: break; } if (!string.IsNullOrEmpty(mbrFilename)) mbr.Code = ReadFile(mbrFilename); mbr.Write(); partitionDevice = new PartitionDevice(diskDevice, mbr.Partitions[0], false); } else { partitionDevice = new PartitionDevice(diskDevice, false); } // Set FAT settings FatSettings fatSettings = new FatSettings(); switch (fileSystem) { case FileSystem.FAT12: fatSettings.FATType = FatType.FAT12; break; case FileSystem.FAT16: fatSettings.FATType = FatType.FAT16; break; case FileSystem.FAT32: fatSettings.FATType = FatType.FAT32; break; default: break; } fatSettings.FloppyMedia = floppyMedia; fatSettings.VolumeLabel = volumeLabel; fatSettings.SerialID = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; fatSettings.SectorsPerTrack = diskGeometry.SectorsPerTrack; fatSettings.NumberOfHeads = diskGeometry.Heads; fatSettings.HiddenSectors = diskGeometry.SectorsPerTrack; if (!string.IsNullOrEmpty(fatcodeFilename)) fatSettings.OSBootCode = ReadFile(fatcodeFilename); // Create FAT file system FatFileSystem fat = new FatFileSystem(partitionDevice); fat.Format(fatSettings); fat.SetVolumeName(volumeLabel); foreach (IncludeFile includeFile in includeFiles) { string filename = includeFile.Filename; Mosa.FileSystem.FAT.FatFileAttributes fileAttributes = new Mosa.FileSystem.FAT.FatFileAttributes(); if (includeFile.Archive) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Archive; if (includeFile.ReadOnly) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.ReadOnly; if (includeFile.Hidden) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Hidden; if (includeFile.System) fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.System; byte[] file = ReadFile(filename); string newname = (Path.GetFileNameWithoutExtension(includeFile.Newname).PadRight(8).Substring(0, 8) + Path.GetExtension(includeFile.Newname).PadRight(3).Substring(1, 3)).ToUpper(); FatFileLocation location = fat.CreateFile(newname, fileAttributes, 0); if (!location.Valid) throw new Exception("Unable to write file"); FatFileStream fatFileStream = new FatFileStream(fat, location); fatFileStream.Write(file, 0, file.Length); fatFileStream.Flush(); } if (patchSyslinuxOption) { // Locate ldlinux.sys file for patching string filename = "ldlinux.sys"; string name = (Path.GetFileNameWithoutExtension(filename) + Path.GetExtension(filename).PadRight(3).Substring(0, 4)).ToUpper(); FatFileLocation location = fat.FindEntry(new Mosa.FileSystem.FAT.Find.WithName(name), 0); if (location.Valid) { // Read boot sector Mosa.ClassLib.BinaryFormat bootSector = new Mosa.ClassLib.BinaryFormat(partitionDevice.ReadBlock(0, 1)); // Set the first sector location of the file bootSector.SetUInt(0x1F8, fat.GetSectorByCluster(location.FirstCluster)); // Change jump address bootSector.SetUInt(0x01, 0x58); // Write back patched boot sector partitionDevice.WriteBlock(0, 1, bootSector.Data); // Get the file size & number of sectors used uint fileSize = fat.GetFileSize(location.DirectorySector, location.DirectorySectorIndex); uint sectorCount = (fileSize + 511) >> 9; uint[] sectors = new uint[65]; uint nsec = 0; // Create list of the first 65 sectors of the file for (uint cluster = location.FirstCluster; ((cluster != 0) & (nsec <= 64)); cluster = fat.GetNextCluster(cluster)) { uint sec = fat.GetSectorByCluster(cluster); for (uint s = 0; s < fat.SectorsPerCluster; s++) sectors[nsec++] = sec + s; } // Read the first cluster of the file Mosa.ClassLib.BinaryFormat firstCluster = new Mosa.ClassLib.BinaryFormat(fat.ReadCluster(location.FirstCluster)); uint patchArea = 0; // Search for 0x3EB202FE (magic) for (patchArea = 0; (firstCluster.GetUInt(patchArea) != 0x3EB202FE) && (patchArea < fat.ClusterSizeInBytes); patchArea += 4) ; patchArea = patchArea + 8; if (patchArea < fat.ClusterSizeInBytes) { // Set up the totals firstCluster.SetUShort(patchArea, (ushort)(fileSize >> 2)); firstCluster.SetUShort(patchArea + 2, (ushort)(sectorCount - 1)); // Clear sector entries firstCluster.Fill(patchArea + 8, 0, 64 * 4); // Set sector entries for (nsec = 0; nsec < 64; nsec++) firstCluster.SetUInt(patchArea + 8 + (nsec * 4), sectors[nsec + 1]); // Clear out checksum firstCluster.SetUInt(patchArea + 4, 0); // Write back the updated cluster fat.WriteCluster(location.FirstCluster, firstCluster.Data); // Re-Calculate checksum by openning the file FatFileStream file = new FatFileStream(fat, location); uint csum = 0x3EB202FE; for (uint index = 0; index < (file.Length >> 2); index++) { uint value = (uint)file.ReadByte() | ((uint)file.ReadByte() << 8) | ((uint)file.ReadByte() << 16) | ((uint)file.ReadByte() << 24); csum -= value; } // Set the checksum firstCluster.SetUInt(patchArea + 4, csum); // Write patched cluster back to disk fat.WriteCluster(location.FirstCluster, firstCluster.Data); } } } if (imageFormat == ImageFormat.VHD) { // Create footer byte[] footer = Mosa.DeviceSystem.VHD.CreateFooter( blockCount, (uint)(DateTime.Now - (new DateTime(2000, 1, 1, 0, 0, 0))).Seconds, Guid.NewGuid().ToByteArray(), diskGeometry ); diskDevice.WriteBlock(blockCount, 1, footer); } Console.WriteLine("Completed!"); } catch (Exception e) { Console.Error.WriteLine("Error: " + e.ToString()); return -1; } return 0; }
/// <summary> /// Creates the specified options. /// </summary> /// <param name="options">The options.</param> static public void Create(Options options) { if (File.Exists(options.DiskImageFileName)) { File.Delete(options.DiskImageFileName); } uint blockCount = options.BlockCount; if (blockCount == 0) { blockCount = 8400 + 1; foreach (var file in options.IncludeFiles) { blockCount += ((uint)file.Content.Length / 512) + 1; } } var diskGeometry = new Mosa.DeviceSystem.DiskGeometry(); diskGeometry.GuessGeometry(blockCount); // Create disk image file BlockFileStream diskDevice = new BlockFileStream(options.DiskImageFileName); if (options.ImageFormat == ImageFormatType.VDI) { // Create header byte[] header = Mosa.DeviceSystem.VDI.CreateHeader( blockCount, options.MediaGuid.ToByteArray(), options.MediaLastSnapGuid.ToByteArray(), diskGeometry ); diskDevice.WriteBlock(0, 1, header); byte[] map = Mosa.DeviceSystem.VDI.CreateImageMap(blockCount); diskDevice.WriteBlock(1, (uint)(map.Length / 512), map); diskDevice.BlockOffset = 1 + (uint)(map.Length / 512); } // Expand disk image diskDevice.WriteBlock(blockCount - 1, 1, new byte[512]); // Create partition device PartitionDevice partitionDevice; if (options.MBROption) { // Create master boot block record MasterBootBlock mbr = new MasterBootBlock(diskDevice); // Setup partition entry mbr.DiskSignature = 0x12345678; mbr.Partitions[0].Bootable = true; mbr.Partitions[0].StartLBA = diskGeometry.SectorsPerTrack; mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA; switch (options.FileSystem) { case FileSystemType.FAT12: mbr.Partitions[0].PartitionType = PartitionType.FAT12; break; case FileSystemType.FAT16: mbr.Partitions[0].PartitionType = PartitionType.FAT16; break; case FileSystemType.FAT32: mbr.Partitions[0].PartitionType = PartitionType.FAT32; break; default: break; } mbr.Code = options.MBRCode; mbr.Write(); partitionDevice = new PartitionDevice(diskDevice, mbr.Partitions[0], false); } else { partitionDevice = new PartitionDevice(diskDevice, false); } // Set FAT settings FatSettings fatSettings = new FatSettings(); switch (options.FileSystem) { case FileSystemType.FAT12: fatSettings.FATType = FatType.FAT12; break; case FileSystemType.FAT16: fatSettings.FATType = FatType.FAT16; break; case FileSystemType.FAT32: fatSettings.FATType = FatType.FAT32; break; default: break; } fatSettings.FloppyMedia = false; fatSettings.VolumeLabel = options.VolumeLabel; fatSettings.SerialID = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; fatSettings.SectorsPerTrack = diskGeometry.SectorsPerTrack; fatSettings.NumberOfHeads = diskGeometry.Heads; fatSettings.HiddenSectors = diskGeometry.SectorsPerTrack; fatSettings.OSBootCode = options.FatBootCode; // Create FAT file system FatFileSystem fat = new FatFileSystem(partitionDevice); if (!fat.Format(fatSettings)) { throw new Exception("ERROR: Invalid FAT settings"); } fat.SetVolumeName(options.VolumeLabel); foreach (var includeFile in options.IncludeFiles) { Mosa.FileSystem.FAT.FatFileAttributes fileAttributes = new Mosa.FileSystem.FAT.FatFileAttributes(); if (includeFile.Archive) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Archive; } if (includeFile.ReadOnly) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.ReadOnly; } if (includeFile.Hidden) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Hidden; } if (includeFile.System) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.System; } //byte[] file = File.ReadAllBytes(includeFile.Filename); string newname = (Path.GetFileNameWithoutExtension(includeFile.Filename).PadRight(8).Substring(0, 8) + Path.GetExtension(includeFile.Filename).PadRight(4).Substring(1, 3)).ToUpper(); FatFileLocation location = fat.CreateFile(newname, fileAttributes, 0); if (!location.Valid) { throw new Exception("Unable to write file"); } FatFileStream fatFileStream = new FatFileStream(fat, location); fatFileStream.Write(includeFile.Content, 0, includeFile.Content.Length); fatFileStream.Flush(); } if (options.PatchSyslinuxOption) { // Locate ldlinux.sys file for patching string filename = "ldlinux.sys"; string name = (Path.GetFileNameWithoutExtension(filename) + Path.GetExtension(filename).PadRight(4).Substring(0, 4)).ToUpper(); FatFileLocation location = fat.FindEntry(new Mosa.FileSystem.FAT.Find.WithName(name), 0); if (location.Valid) { // Read boot sector Mosa.ClassLib.BinaryFormat bootSector = new Mosa.ClassLib.BinaryFormat(partitionDevice.ReadBlock(0, 1)); // Set the first sector location of the file bootSector.SetUInt(0x1F8, fat.GetSectorByCluster(location.FirstCluster)); // Change jump address bootSector.SetUInt(0x01, 0x58); // Write back patched boot sector partitionDevice.WriteBlock(0, 1, bootSector.Data); // Get the file size & number of sectors used uint fileSize = fat.GetFileSize(location.DirectorySector, location.DirectorySectorIndex); uint sectorCount = (fileSize + 511) >> 9; uint[] sectors = new uint[65]; uint nsec = 0; // Create list of the first 65 sectors of the file for (uint cluster = location.FirstCluster; ((cluster != 0) & (nsec <= 64)); cluster = fat.GetNextCluster(cluster)) { uint sec = fat.GetSectorByCluster(cluster); for (uint s = 0; s < fat.SectorsPerCluster; s++) { sectors[nsec++] = sec + s; } } // Read the first cluster of the file Mosa.ClassLib.BinaryFormat firstCluster = new Mosa.ClassLib.BinaryFormat(fat.ReadCluster(location.FirstCluster)); uint patchArea = 0; // Search for 0x3EB202FE (magic) for (patchArea = 0; (firstCluster.GetUInt(patchArea) != 0x3EB202FE) && (patchArea < fat.ClusterSizeInBytes); patchArea += 4) { ; } patchArea = patchArea + 8; if (patchArea < fat.ClusterSizeInBytes) { // Set up the totals firstCluster.SetUShort(patchArea, (ushort)(fileSize >> 2)); firstCluster.SetUShort(patchArea + 2, (ushort)(sectorCount - 1)); // Clear sector entries firstCluster.Fill(patchArea + 8, 0, 64 * 4); // Set sector entries for (nsec = 0; nsec < 64; nsec++) { firstCluster.SetUInt(patchArea + 8 + (nsec * 4), sectors[nsec + 1]); } // Clear out checksum firstCluster.SetUInt(patchArea + 4, 0); // Write back the updated cluster fat.WriteCluster(location.FirstCluster, firstCluster.Data); // Re-Calculate checksum by opening the file FatFileStream file = new FatFileStream(fat, location); uint csum = 0x3EB202FE; for (uint index = 0; index < (file.Length >> 2); index++) { uint value = (uint)file.ReadByte() | ((uint)file.ReadByte() << 8) | ((uint)file.ReadByte() << 16) | ((uint)file.ReadByte() << 24); csum -= value; } // Set the checksum firstCluster.SetUInt(patchArea + 4, csum); // Write patched cluster back to disk fat.WriteCluster(location.FirstCluster, firstCluster.Data); } } } if (options.ImageFormat == ImageFormatType.VHD) { // Create footer byte[] footer = Mosa.DeviceSystem.VHD.CreateFooter( blockCount, (uint)(DateTime.Now - (new DateTime(2000, 1, 1, 0, 0, 0))).Seconds, options.MediaGuid.ToByteArray(), diskGeometry ); diskDevice.WriteBlock(blockCount, 1, footer); } diskDevice.Dispose(); }
/// <summary> /// Writes the master boot block. /// </summary> /// <returns></returns> public bool Write() { if (!diskDevice.CanWrite) { return false; } BinaryFormat masterboot = new BinaryFormat(new byte[512]); masterboot.SetUInt(MBR.DiskSignature, diskSignature); masterboot.SetUShort(MBR.MBRSignature, MBRConstant.MBRSignature); if (code != null) for (uint index = 0; ((index < MBRConstant.CodeAreaSize) && (index < code.Length)); index++) masterboot.SetByte(index, code[index]); for (uint index = 0; index < MaxMBRPartitions; index++) if (Partitions[index].TotalBlocks != 0) { uint offset = MBR.FirstPartition + (index * 16); masterboot.SetByte(offset + PartitionRecord.Status, (byte)(Partitions[index].Bootable ? 0x80 : 0x00)); masterboot.SetByte(offset + PartitionRecord.PartitionType, Partitions[index].PartitionType); masterboot.SetUInt(offset + PartitionRecord.LBA, Partitions[index].StartLBA); masterboot.SetUInt(offset + PartitionRecord.Sectors, Partitions[index].TotalBlocks); DiskGeometry diskGeometry = new DiskGeometry(); diskGeometry.GuessGeometry(diskDevice.TotalBlocks); CHS chsStart = new CHS(); CHS chsEnd = new CHS(); chsStart.SetCHS(diskGeometry, Partitions[index].StartLBA); chsEnd.SetCHS(diskGeometry, Partitions[index].StartLBA + Partitions[index].TotalBlocks - 1); masterboot.SetByte(offset + PartitionRecord.FirstCRS, chsStart.Head); masterboot.SetByte(offset + PartitionRecord.FirstCRS + 1, (byte)((chsStart.Sector & 0x3F) | ((chsStart.Cylinder >> 8) & 0x03))); masterboot.SetByte(offset + PartitionRecord.FirstCRS + 2, (byte)(chsStart.Cylinder & 0xFF)); masterboot.SetByte(offset + PartitionRecord.LastCRS, chsEnd.Head); masterboot.SetByte(offset + PartitionRecord.LastCRS + 1, (byte)((chsEnd.Sector & 0x3F) | ((chsEnd.Cylinder >> 8) & 0x03))); masterboot.SetByte(offset + PartitionRecord.LastCRS + 2, (byte)(chsEnd.Cylinder & 0xFF)); } diskDevice.WriteBlock(0, 1, masterboot.Data); return true; }
/// <summary> /// Creates the header. /// </summary> /// <param name="blocks">The blocks.</param> /// <param name="guid">The GUID.</param> /// <param name="lastSnapGuid">The last snap GUID.</param> /// <param name="diskGeometry">The disk geometry.</param> /// <returns></returns> static public byte[] CreateHeader(uint blocks, byte[] guid, byte[] lastSnapGuid, DiskGeometry diskGeometry) { Mosa.ClassLib.BinaryFormat binaryHeader = new Mosa.ClassLib.BinaryFormat(512); binaryHeader.SetString(VHIHeaderOffset.HeaderText, HeaderText, (uint)HeaderText.Length); binaryHeader.SetByte(VHIHeaderOffset.HeaderText + 0x25, 0x0A); binaryHeader.SetUInt(VHIHeaderOffset.ImageSignature, 0xBEda107F); binaryHeader.SetUInt(VHIHeaderOffset.Version, 0x00010001); binaryHeader.SetUInt(VHIHeaderOffset.HeaderSize, 0x180); binaryHeader.SetUInt(VHIHeaderOffset.ImageType, 0x02); binaryHeader.SetUInt(VHIHeaderOffset.ImageFlags, 0x00); binaryHeader.SetUInt(VHIHeaderOffset.OffsetBlocks, 0x200); binaryHeader.SetUInt(VHIHeaderOffset.OffsetData, 0x400); binaryHeader.SetUInt(VHIHeaderOffset.DiskGeometryCylinders, 0); // diskGeometry.Cylinders); binaryHeader.SetUInt(VHIHeaderOffset.DiskGeometryHeads, 0); // diskGeometry.Heads); binaryHeader.SetUInt(VHIHeaderOffset.DiskGeometrySectors, 0); // diskGeometry.SectorsPerTrack); binaryHeader.SetUInt(VHIHeaderOffset.SectorSize, 512); binaryHeader.SetULong(VHIHeaderOffset.DiskSize, blocks * 512); binaryHeader.SetUInt(VHIHeaderOffset.BlockSize, 0x100000); binaryHeader.SetUInt(VHIHeaderOffset.BlockExtraData, 0); binaryHeader.SetUInt(VHIHeaderOffset.BlocksInHDD, (uint)((blocks * 512) / 0x100000)); binaryHeader.SetUInt(VHIHeaderOffset.BlocksAllocated, (uint)((blocks * 512) / 0x100000)); binaryHeader.SetBytes(VHIHeaderOffset.UUID, guid, 0, 16); binaryHeader.SetBytes(VHIHeaderOffset.UUIDLastSnap, lastSnapGuid, 0, 16); return(binaryHeader.Data); }
/// <summary> /// Main /// </summary> /// <param name="args">The args.</param> /// <returns></returns> static int Main(string[] args) { Console.WriteLine(); Console.WriteLine("MakeImageBoot v1.0 [www.mosa-project.org]"); Console.WriteLine("Copyright 2010. New BSD License."); Console.WriteLine("Written by Philipp Garcia ([email protected])"); Console.WriteLine(); string mbrFilename = string.Empty; string fatcodeFilename = string.Empty; string volumeLabel = string.Empty; ImageFormat imageFormat = ImageFormat.VHD; bool mbrOption = true; bool patchSyslinuxOption = false; bool floppyMedia = false; uint blockCount = 1024 * 1024 / 512; FileSystem fileSystem = FileSystem.FAT12; List <IncludeFile> includeFiles = new List <IncludeFile>(); bool valid = (args.Length < 2); if (valid) { valid = System.IO.File.Exists(args[0]); } if (valid) { Console.WriteLine("Usage: CreateBootImage <boot.config file> <image name>"); Console.Error.WriteLine("ERROR: Missing arguments"); return(-1); } Console.WriteLine("Building image..."); try { StreamReader reader = File.OpenText(args[0]); while (true) { string line = reader.ReadLine(); if (line == null) { break; } if (string.IsNullOrEmpty(line)) { continue; } string[] parts = line.Split('\t'); switch (parts[0].Trim()) { case "-mbr": mbrOption = true; mbrFilename = (parts.Length > 1) ? parts[1] : null; break; case "-boot": fatcodeFilename = (parts.Length > 1) ? parts[1] : null; break; case "-vhd": imageFormat = ImageFormat.VHD; break; case "-img": imageFormat = ImageFormat.IMG; break; case "-vdi": imageFormat = ImageFormat.VDI; break; case "-syslinux": patchSyslinuxOption = true; break; case "-fat12": fileSystem = FileSystem.FAT12; break; case "-fat16": fileSystem = FileSystem.FAT16; break; case "-fat32": fileSystem = FileSystem.FAT32; break; case "-file": if (parts.Length > 2) { includeFiles.Add(new IncludeFile(parts[1], parts[2])); } else { includeFiles.Add(new IncludeFile(parts[1])); } break; case "-blocks": blockCount = Convert.ToUInt32(parts[1]); break; case "-volume": volumeLabel = parts[1]; break; case "-floppy": floppyMedia = true; break; default: break; } } reader.Close(); if (System.IO.File.Exists(args[1])) { System.IO.File.Delete(args[1]); } DiskGeometry diskGeometry = new Mosa.DeviceSystem.DiskGeometry(); diskGeometry.GuessGeometry(blockCount); Console.WriteLine("Disk Geometry CHS = " + diskGeometry.Cylinders + "/" + diskGeometry.Heads + "/" + diskGeometry.SectorsPerTrack); // Create disk image file Mosa.EmulatedDevices.Synthetic.DiskDevice diskDevice = new Mosa.EmulatedDevices.Synthetic.DiskDevice(args[1]); if (imageFormat == ImageFormat.VDI) { // Create header byte[] header = Mosa.DeviceSystem.VDI.CreateHeader( blockCount, Guid.NewGuid().ToByteArray(), Guid.NewGuid().ToByteArray(), diskGeometry ); diskDevice.WriteBlock(0, 1, header); byte[] map = Mosa.DeviceSystem.VDI.CreateImageMap(blockCount); diskDevice.WriteBlock(1, (uint)(map.Length / 512), map); diskDevice.BlockOffset = 1 + (uint)(map.Length / 512); } // Expand disk image diskDevice.WriteBlock(blockCount - 1, 1, new byte[512]); // Create partition device PartitionDevice partitionDevice; if (mbrOption) { // Create master boot block record MasterBootBlock mbr = new MasterBootBlock(diskDevice); // Setup partition entry mbr.DiskSignature = 0x12345678; mbr.Partitions[0].Bootable = true; mbr.Partitions[0].StartLBA = diskGeometry.SectorsPerTrack; mbr.Partitions[0].TotalBlocks = blockCount - mbr.Partitions[0].StartLBA; switch (fileSystem) { case FileSystem.FAT12: mbr.Partitions[0].PartitionType = PartitionType.FAT12; break; case FileSystem.FAT16: mbr.Partitions[0].PartitionType = PartitionType.FAT16; break; case FileSystem.FAT32: mbr.Partitions[0].PartitionType = PartitionType.FAT32; break; default: break; } if (!string.IsNullOrEmpty(mbrFilename)) { mbr.Code = ReadFile(mbrFilename); } mbr.Write(); partitionDevice = new PartitionDevice(diskDevice, mbr.Partitions[0], false); } else { partitionDevice = new PartitionDevice(diskDevice, false); } // Set FAT settings FatSettings fatSettings = new FatSettings(); switch (fileSystem) { case FileSystem.FAT12: fatSettings.FATType = FatType.FAT12; break; case FileSystem.FAT16: fatSettings.FATType = FatType.FAT16; break; case FileSystem.FAT32: fatSettings.FATType = FatType.FAT32; break; default: break; } fatSettings.FloppyMedia = floppyMedia; fatSettings.VolumeLabel = volumeLabel; fatSettings.SerialID = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; fatSettings.SectorsPerTrack = diskGeometry.SectorsPerTrack; fatSettings.NumberOfHeads = diskGeometry.Heads; fatSettings.HiddenSectors = diskGeometry.SectorsPerTrack; if (!string.IsNullOrEmpty(fatcodeFilename)) { fatSettings.OSBootCode = ReadFile(fatcodeFilename); } // Create FAT file system FatFileSystem fat = new FatFileSystem(partitionDevice); fat.Format(fatSettings); fat.SetVolumeName(volumeLabel); foreach (IncludeFile includeFile in includeFiles) { string filename = includeFile.Filename; Mosa.FileSystem.FAT.FatFileAttributes fileAttributes = new Mosa.FileSystem.FAT.FatFileAttributes(); if (includeFile.Archive) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Archive; } if (includeFile.ReadOnly) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.ReadOnly; } if (includeFile.Hidden) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.Hidden; } if (includeFile.System) { fileAttributes |= Mosa.FileSystem.FAT.FatFileAttributes.System; } byte[] file = ReadFile(filename); string newname = (Path.GetFileNameWithoutExtension(includeFile.Newname).PadRight(8).Substring(0, 8) + Path.GetExtension(includeFile.Newname).PadRight(3).Substring(1, 3)).ToUpper(); FatFileLocation location = fat.CreateFile(newname, fileAttributes, 0); if (!location.Valid) { throw new Exception("Unable to write file"); } FatFileStream fatFileStream = new FatFileStream(fat, location); fatFileStream.Write(file, 0, file.Length); fatFileStream.Flush(); } if (patchSyslinuxOption) { // Locate ldlinux.sys file for patching string filename = "ldlinux.sys"; string name = (Path.GetFileNameWithoutExtension(filename) + Path.GetExtension(filename).PadRight(3).Substring(0, 4)).ToUpper(); FatFileLocation location = fat.FindEntry(new Mosa.FileSystem.FAT.Find.WithName(name), 0); if (location.Valid) { // Read boot sector Mosa.ClassLib.BinaryFormat bootSector = new Mosa.ClassLib.BinaryFormat(partitionDevice.ReadBlock(0, 1)); // Set the first sector location of the file bootSector.SetUInt(0x1F8, fat.GetSectorByCluster(location.FirstCluster)); // Change jump address bootSector.SetUInt(0x01, 0x58); // Write back patched boot sector partitionDevice.WriteBlock(0, 1, bootSector.Data); // Get the file size & number of sectors used uint fileSize = fat.GetFileSize(location.DirectorySector, location.DirectorySectorIndex); uint sectorCount = (fileSize + 511) >> 9; uint[] sectors = new uint[65]; uint nsec = 0; // Create list of the first 65 sectors of the file for (uint cluster = location.FirstCluster; ((cluster != 0) & (nsec <= 64)); cluster = fat.GetNextCluster(cluster)) { uint sec = fat.GetSectorByCluster(cluster); for (uint s = 0; s < fat.SectorsPerCluster; s++) { sectors[nsec++] = sec + s; } } // Read the first cluster of the file Mosa.ClassLib.BinaryFormat firstCluster = new Mosa.ClassLib.BinaryFormat(fat.ReadCluster(location.FirstCluster)); uint patchArea = 0; // Search for 0x3EB202FE (magic) for (patchArea = 0; (firstCluster.GetUInt(patchArea) != 0x3EB202FE) && (patchArea < fat.ClusterSizeInBytes); patchArea += 4) { ; } patchArea = patchArea + 8; if (patchArea < fat.ClusterSizeInBytes) { // Set up the totals firstCluster.SetUShort(patchArea, (ushort)(fileSize >> 2)); firstCluster.SetUShort(patchArea + 2, (ushort)(sectorCount - 1)); // Clear sector entries firstCluster.Fill(patchArea + 8, 0, 64 * 4); // Set sector entries for (nsec = 0; nsec < 64; nsec++) { firstCluster.SetUInt(patchArea + 8 + (nsec * 4), sectors[nsec + 1]); } // Clear out checksum firstCluster.SetUInt(patchArea + 4, 0); // Write back the updated cluster fat.WriteCluster(location.FirstCluster, firstCluster.Data); // Re-Calculate checksum by openning the file FatFileStream file = new FatFileStream(fat, location); uint csum = 0x3EB202FE; for (uint index = 0; index < (file.Length >> 2); index++) { uint value = (uint)file.ReadByte() | ((uint)file.ReadByte() << 8) | ((uint)file.ReadByte() << 16) | ((uint)file.ReadByte() << 24); csum -= value; } // Set the checksum firstCluster.SetUInt(patchArea + 4, csum); // Write patched cluster back to disk fat.WriteCluster(location.FirstCluster, firstCluster.Data); } } } if (imageFormat == ImageFormat.VHD) { // Create footer byte[] footer = Mosa.DeviceSystem.VHD.CreateFooter( blockCount, (uint)(DateTime.Now - (new DateTime(2000, 1, 1, 0, 0, 0))).Seconds, Guid.NewGuid().ToByteArray(), diskGeometry ); diskDevice.WriteBlock(blockCount, 1, footer); } Console.WriteLine("Completed!"); } catch (Exception e) { Console.Error.WriteLine("Error: " + e.ToString()); return(-1); } return(0); }