static void CreateDiskImage(System.IO.FileStream fs, FATFormatInfo fi)
 {
     if (fs.Length != 0)
     {
         fs.SetLength(0);
     }
     FileCompression.CompressStream(fs);
     FileCompression.SetSparse(fs);
     FileCompression.WriteZeros(fs, 0, fi.TotalSectors * 512);
     FormatDiskImage(fs, fi, false);
 }
 public static void CreateDiskImage(System.IO.Stream s, FATFormatInfo fi)
 {
     if (s.GetType() == typeof(System.IO.FileStream))
     {
         CreateDiskImage((System.IO.FileStream)s, fi);
         return;
     }
     s.SetLength(0);
     FileCompression.WriteZeros(s, 0, (long)fi.TotalSectors * 512);
     FormatDiskImage(s, fi, false);
 }
        static void FormatDiskImage(System.IO.Stream s, FATFormatInfo fi, bool MustInitialize)
        {
            var assembly = typeof(FATFormatter).GetTypeInfo().Assembly;

            byte[] bootsect;
            using (var stream = assembly.GetManifestResourceStream(fi.Type == FATType.FAT32
                ? "OSDevelopment.Resources.bootsect32"
                : "OSDevelopment.Resources.bootsect16"))
            {
                bootsect = new byte[stream.Length];
                stream.Read(bootsect, 0, (int)stream.Length);
            }
            if (!s.CanWrite || !s.CanSeek)
            {
                throw new System.IO.IOException();
            }
            if (fi.Type == FATType.None)
            {
                fi.Type = DefaultFatType(fi.TotalSectors);
            }
            if (fi.Type != FATType.FAT16 && fi.Type != FATType.FAT32)
            {
                throw new NotSupportedException();
            }
            if (!ValidFatType(fi.Type, fi.TotalSectors))
            {
                throw new FATException("Invalid type of FAT, given sector count.");
            }
            if (fi.BootSector == null)
            {
                fi.BootSector = bootsect;
            }
            s.Seek(0, System.IO.SeekOrigin.Begin);
            System.IO.BinaryWriter bw = new System.IO.BinaryWriter(s);
            // Get sectors per cluster
            uint spc = 0;

            {
                uint[][] t = fi.Type == FATType.FAT16 ? FAT16Table : FAT32Table;
                foreach (uint[] i in t)
                {
                    if (i[0] >= fi.TotalSectors)
                    {
                        spc = i[1];
                        break;
                    }
                }
            }
#if DEBUG
            System.Diagnostics.Debug.Assert(spc != 0); // Should have been prevented by ValidFatType().
#endif
            // Get FAT sectors
            uint fatsz;
            {
                uint rootsec = fi.Type == FATType.FAT32 ? 0u : 32u;
                uint resvd   = fi.Type == FATType.FAT32 ? 32u : 1u;
                uint t1      = fi.TotalSectors - (resvd + rootsec);
                uint t2      = (256 * spc) + 2;
                if (fi.Type == FATType.FAT32)
                {
                    t2 /= 2;
                }
                fatsz = (t1 + (t2 - 1)) / t2;
            }
            if (MustInitialize)
            {
                // FAT32: 2 fats + 32 reserved + root cluster; FAT16: 2 fats + 1 reserved + 32 root directory
                FileCompression.WriteZeros(s, 0, (long)(fatsz * 2 + (fi.Type == FATType.FAT32 ? 32 + spc : 33)) * 512);
                s.Seek(0, System.IO.SeekOrigin.Begin);
            }
            switch (fi.Type)
            {
            case FATType.FAT16:
            {
                s.Write(fi.BootSector, 0, 512);
                s.Seek(11, System.IO.SeekOrigin.Begin);
                bw.Write((ushort)512); // Bytes per sector
                bw.Write((byte)spc);   // sectors per cluster
                bw.Write((ushort)1);   // Reserved sector count
                bw.Write((byte)2);     // Number of FATs
                bw.Write((ushort)512); // Number of root entries
                if (fi.TotalSectors < 65536)
                {
                    bw.Write((ushort)fi.TotalSectors);     // Total sectors 16
                }
                else
                {
                    bw.Write((ushort)0);
                }
                bw.Write(fi.MediaType);       // Media type
                bw.Write((ushort)fatsz);      // FAT sectors
                bw.Write(fi.SectorsPerTrack); // Sectors per track
                bw.Write(fi.Heads);           // Number of heads
                bw.Write((uint)0);            // Hidden sectors
                if (fi.TotalSectors >= 65536)
                {
                    bw.Write(fi.TotalSectors);     // Total sectors 32
                }
                else
                {
                    bw.Write((uint)0);
                }
                bw.Write(fi.DriveNumber); // drv num
                bw.Write((byte)0);        // resvd
                bw.Write((byte)0x29);     // ext boot sig
                bw.Write((uint)System.DateTime.Now.ToFileTime());
                if (!string.IsNullOrEmpty(fi.VolumeLabel))
                {
                    string lab = fi.VolumeLabel.ToUpper();
                    if (lab.Length > 11)
                    {
                        lab = lab.Remove(11);
                    }
                    while (lab.Length < 11)
                    {
                        lab += "\x20";
                    }
                    bw.Write(lab.ToCharArray());
                }
                else
                {
                    bw.Write("NO NAME    ".ToCharArray());
                }
                bw.Write("FAT16   ".ToCharArray());
                for (uint pos = 1; pos <= fatsz + 1; pos += fatsz)
                {
                    s.Seek((long)pos * 512, System.IO.SeekOrigin.Begin);
                    bw.Write((uint)(0xFFFFFF00 | fi.MediaType));
                }
                break;
            }

            case FATType.FAT32:
            {
                for (long pos = 0; pos <= 3072; pos += 3072)
                {
                    s.Seek(pos, System.IO.SeekOrigin.Begin);
                    s.Write(fi.BootSector, 0, 512);
                    s.Seek(pos + 11, System.IO.SeekOrigin.Begin);
                    bw.Write((ushort)512);                    // Bytes per sector
                    bw.Write((byte)spc);                      // sectors per cluster
                    bw.Write((ushort)32);                     // Reserved sector count
                    bw.Write((byte)2);                        // Number of FATs
                    bw.Write((ushort)0);                      // Number of root entries
                    bw.Write((ushort)0);                      // Total sectors 16
                    bw.Write(fi.MediaType);                   // Media type
                    bw.Write((ushort)0);                      // FAT sectors 16
                    bw.Write(fi.SectorsPerTrack);             // Sectors per track
                    bw.Write(fi.Heads);                       // Number of heads
                    bw.Write((uint)0);                        // Hidden sectors
                    bw.Write(fi.TotalSectors);                // Total sectors 32
                    bw.Write(fatsz);                          // FAT sectors 32
                    bw.Write((ushort)0);                      // Flags
                    bw.Write((ushort)0);                      // Version
                    bw.Write((uint)2);                        // Root cluster
                    bw.Write((ushort)1);                      // FSInfo sector
                    bw.Write((ushort)6);                      // Backup boot sector
                    s.Seek(12, System.IO.SeekOrigin.Current); // Reserved bytes
                    bw.Write((byte)fi.DriveNumber);           // Drive number
                    bw.Write((byte)0);                        // Reserved
                    bw.Write((byte)0x29);                     // ext boot sig
                    bw.Write((uint)System.DateTime.Now.ToFileTime());
                    if (!string.IsNullOrEmpty(fi.VolumeLabel))
                    {
                        string lab = fi.VolumeLabel.ToUpper();
                        if (lab.Length > 11)
                        {
                            lab = lab.Remove(11);
                        }
                        while (lab.Length < 11)
                        {
                            lab += "\x20";
                        }
                        bw.Write(lab.ToCharArray());
                    }
                    else
                    {
                        bw.Write("NO NAME    ".ToCharArray());
                    }
                    bw.Write("FAT32   ".ToCharArray());
                    s.Seek(pos + 512, System.IO.SeekOrigin.Begin);
                    byte[] fsinfo;
                    using (var stream = assembly.GetManifestResourceStream("OSDevelopment.Resources.fsinfo"))
                    {
                        fsinfo = new byte[stream.Length];
                        stream.Read(fsinfo, 0, (int)stream.Length);
                    }
                    s.Write(fsinfo, 0, 512);
                    s.Seek(510, System.IO.SeekOrigin.Current);
                    bw.Write((ushort)0xAA55);     // so that all three sectors have 0xAA55
                }
                for (long pos = 32; pos <= fatsz + 32; pos += fatsz)
                {
                    s.Seek(pos * 512, System.IO.SeekOrigin.Begin);
                    bw.Write((uint)(0x0FFFFF00 | fi.MediaType)); // First entry with media type
                    bw.Write((uint)(0x0FFFFFFF));                // Cluster 1 with eoc mark
                    bw.Write((uint)(0x0FFFFFFF));                // Cluster 2 used for root dorectory, mark next as eoc
                }
                break;
            }
            }
        }