Пример #1
0
        protected bool SetClusterEntryValue(uint cluster, uint nextcluster)
        {
            uint fatOffset = 0;

            if (fatType == FATType.FAT12)
            {
                fatOffset = (cluster + (cluster / 2));
            }
            else if (fatType == FATType.FAT16)
            {
                fatOffset = cluster * 2;
            }
            else             //if (type == FatType.FAT32)
            {
                fatOffset = cluster * 4;
            }

            uint sector       = fatStart + (fatOffset / bytesPerSector);
            uint sectorOffset = fatOffset % bytesPerSector;
            uint nbrSectors   = 1;

            if ((fatType == FATType.FAT12) && (sectorOffset == bytesPerSector - 1))
            {
                nbrSectors = 2;
            }

            BinaryFormat fat = new BinaryFormat(partition.ReadBlock(sector, nbrSectors));

            if (fatType == FATType.FAT12)
            {
                uint clustervalue = fat.GetUShort(sectorOffset);

                if (cluster % 2 == 1)
                {
                    clustervalue = ((clustervalue & 0xF) | (nextcluster << 4));
                }
                else
                {
                    clustervalue = ((clustervalue & 0xf000) | (nextcluster));
                }

                fat.SetUShort(sectorOffset, (ushort)clustervalue);
            }
            else if (fatType == FATType.FAT16)
            {
                fat.SetUShort(sectorOffset, (ushort)nextcluster);
            }
            else             //if (type == FatType.FAT32)
            {
                fat.SetUInt(sectorOffset, nextcluster);
            }

            partition.WriteBlock(sector, nbrSectors, fat.Data);

            return(true);
        }
Пример #2
0
        /// <summary>
        /// Identifies the drive.
        /// </summary>
        protected void IdentifyDrive()
        {
            byte         drive = (byte)(((deviceHead & 0x10) != 0x10) ? 0 : 1);
            byte         d     = (byte)('0' + drive + 1);
            BinaryFormat data  = new BinaryFormat(bufferData);

            data.Fill(0, 0, 512);

            // fixed drive and over 5Mb/sec
            data.SetUShort(0x00, 0x140);
            // Serial Number
            data.Fill(0x0A * 2, d, 20);
            data.SetByte(0x0A * 2, d);
            // Firmware version
            data.Fill(0x17 * 2, d, 8);
            data.SetChar(0x17 * 2 + 0, '1');
            data.SetChar(0x17 * 2 + 1, '.');
            data.SetChar(0x17 * 2 + 2, '0');
            // Model Number
            data.Fill(0x1B * 2, d, 40);
            data.SetChar(0x17 * 2 + 0, 'D');
            data.SetChar(0x17 * 2 + 1, 'R');
            data.SetChar(0x17 * 2 + 2, 'I');
            data.SetChar(0x17 * 2 + 3, 'V');
            data.SetChar(0x17 * 2 + 4, 'E');
            data.SetByte(0x1B * 2 + 5, d);
            // lba28
            data.SetUInt(0x3C * 2, (uint)(driveFiles[drive].Length / 512));

            commandStatus = (byte)((commandStatus | 0x08) & ~0x80);             // Set DRQ (bit 3), clear BUSY (bit 7)

            status = DeviceStatus.IdentifyDrive;
        }
Пример #3
0
        /// <summary>
        /// Reads the LBA48.
        /// </summary>
        /// <param name="operation">The operation.</param>
        /// <param name="drive">The drive.</param>
        /// <param name="lba">The lba.</param>
        /// <param name="data">The data.</param>
        /// <param name="offset">The offset.</param>
        /// <returns></returns>
        protected bool ReadLBA48(SectorOperation operation, uint drive, uint lba, byte[] data, uint offset)
        {
            if (drive > MaximunDriveCount)
            {
                return(false);
            }

            FeaturePort.Write8(0);
            FeaturePort.Write8(0);

            SectorCountPort.Write8(0);
            SectorCountPort.Write8(1);

            LBALowPort.Write8((byte)((lba >> 24) & 0xFF));
            LBALowPort.Write8((byte)(lba & 0xFF));

            LBAMidPort.Write8((byte)((lba >> 32) & 0xFF));
            LBAMidPort.Write8((byte)((lba >> 8) & 0xFF));

            LBAHighPort.Write8((byte)((lba >> 40) & 0xFF));
            LBAHighPort.Write8((byte)((lba >> 16) & 0xFF));

            DeviceHeadPort.Write8((byte)(0x40 | (drive << 4)));

            if (operation == SectorOperation.Write)
            {
                CommandPort.Write8(0x34);
            }
            else
            {
                CommandPort.Write8(0x24);
            }

            if (!WaitForReqisterReady())
            {
                return(false);
            }

            BinaryFormat sector = new BinaryFormat(data);

            //TODO: Don't use PIO
            if (operation == SectorOperation.Read)
            {
                for (uint index = 0; index < 256; index++)
                {
                    sector.SetUShort(offset + (index * 2), DataPort.Read16());
                }
            }
            else
            {
                for (uint index = 0; index < 256; index++)
                {
                    DataPort.Write16(sector.GetUShort(offset + (index * 2)));
                }
            }

            return(true);
        }
Пример #4
0
        public override void MakeDirectory(string DirName)
        {
            //TODO: Same Entry Exist exception.
            FatFileLocation location = FindEntry(new FileSystem.Find.Empty(), FatCurrentDirectoryEntry);

            uint FirstCluster = AllocateFirstCluster();

            var xdata = new byte[512 * SectorsPerCluster];

            this.IDevice.Read(location.DirectorySector, SectorsPerCluster, xdata);
            BinaryFormat directory = new BinaryFormat(xdata);

            directory.SetString(Entry.DOSName + location.DirectorySectorIndex * 32, "            ", 11);
            directory.SetString(Entry.DOSName + location.DirectorySectorIndex * 32, DirName);

            directory.SetByte(Entry.FileAttributes + location.DirectorySectorIndex * 32, (byte)0x10);
            directory.SetByte(Entry.Reserved + location.DirectorySectorIndex * 32, 0);
            directory.SetByte(Entry.CreationTimeFine + location.DirectorySectorIndex * 32, 0);
            directory.SetUShort(Entry.CreationTime + location.DirectorySectorIndex * 32, 0);
            directory.SetUShort(Entry.CreationDate + location.DirectorySectorIndex * 32, 0);
            directory.SetUShort(Entry.LastAccessDate + location.DirectorySectorIndex * 32, 0);
            directory.SetUShort(Entry.LastModifiedTime + location.DirectorySectorIndex * 32, 0);
            directory.SetUShort(Entry.LastModifiedDate + location.DirectorySectorIndex * 32, 0);
            directory.SetUShort(Entry.FirstCluster + location.DirectorySectorIndex * 32, (ushort)FirstCluster);
            directory.SetUInt(Entry.FileSize + location.DirectorySectorIndex * 32, 0);
            this.IDevice.Write(location.DirectorySector, SectorsPerCluster, xdata);

            FatFileLocation loc = FindEntry(new FileSystem.Find.Empty(), FirstCluster);

            xdata = new byte[512 * SectorsPerCluster];
            this.IDevice.Read(loc.DirectorySector, SectorsPerCluster, xdata);
            directory = new BinaryFormat(xdata);
            for (int i = 0; i < 2; i++)
            {
                directory.SetString(Entry.DOSName + loc.DirectorySectorIndex * 32, "            ", 11);
                if (i == 0)
                {
                    directory.SetString(Entry.DOSName + loc.DirectorySectorIndex * 32, ".");
                    directory.SetUShort(Entry.FirstCluster + loc.DirectorySectorIndex * 32, (ushort)FirstCluster);
                }
                else
                {
                    directory.SetString(Entry.DOSName + loc.DirectorySectorIndex * 32, "..");
                    directory.SetUShort(Entry.FirstCluster + loc.DirectorySectorIndex * 32, (ushort)FatCurrentDirectoryEntry);
                }
                directory.SetByte(Entry.FileAttributes + loc.DirectorySectorIndex * 32, (byte)0x10);
                directory.SetByte(Entry.Reserved + loc.DirectorySectorIndex * 32, 0);
                directory.SetByte(Entry.CreationTimeFine + loc.DirectorySectorIndex * 32, 0);
                directory.SetUShort(Entry.CreationTime + loc.DirectorySectorIndex * 32, 0);
                directory.SetUShort(Entry.CreationDate + loc.DirectorySectorIndex * 32, 0);
                directory.SetUShort(Entry.LastAccessDate + loc.DirectorySectorIndex * 32, 0);
                directory.SetUShort(Entry.LastModifiedTime + loc.DirectorySectorIndex * 32, 0);
                directory.SetUShort(Entry.LastModifiedDate + loc.DirectorySectorIndex * 32, 0);
                directory.SetUInt(Entry.FileSize + loc.DirectorySectorIndex * 32, 0);
                loc.DirectorySectorIndex += 1;
            }

            this.IDevice.Write(loc.DirectorySector, SectorsPerCluster, xdata);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        protected bool PerformLBA28(SectorOperation operation, uint driveNbr, uint lba, byte[] data, uint offset)
        {
            FeaturePort.Write8(0);
            SectorCountPort.Write8(1);

            LBALowPort.Write8((byte)(lba & 0xFF));
            LBAMidPort.Write8((byte)((lba >> 8) & 0xFF));
            LBAHighPort.Write8((byte)((lba >> 16) & 0xFF));

            DeviceHeadPort.Write8((byte)(0xE0 | (driveNbr << 4) | ((lba >> 24) & 0x0F)));

            if (operation == SectorOperation.Write)
            {
                CommandPort.Write8(IDECommand.WriteSectorsWithRetry);
            }
            else
            {
                CommandPort.Write8(IDECommand.ReadSectorsWithRetry);
            }

            if (!WaitForReqisterReady())
            {
                return(false);
            }

            BinaryFormat sector = new BinaryFormat(data);

            //TODO: Don't use PIO
            if (operation == SectorOperation.Read)
            {
                for (uint index = 0; index < 256; index++)
                {
                    sector.SetUShort(offset + (index * 2), DataPort.Read16());
                }
            }
            else
            {
                for (uint index = 0; index < 256; index++)
                {
                    DataPort.Write16(sector.GetUShort(offset + (index * 2)));
                }
            }

            return(true);
        }
Пример #7
0
        /// <summary>
        /// Opens the specified drive NBR.
        /// </summary>
        /// <param name="drive">The drive NBR.</param>
        /// <returns></returns>
        public bool Open(uint drive)
        {
            if (drive > MaximunDriveCount)
            {
                return(false);
            }

            if (!driveInfo[drive].Present)
            {
                return(false);
            }

            if (drive == 0)
            {
                DeviceHeadPort.Write8(0xA0);
            }
            else
            if (drive == 1)
            {
                DeviceHeadPort.Write8(0xB0);
            }
            else
            {
                return(false);
            }

            CommandPort.Write8(IDECommands.IdentifyDrive);

            if (!WaitForReqisterReady())
            {
                return(false);
            }

            BinaryFormat info = new BinaryFormat(new byte[512]);

            for (uint index = 0; index < 256; index++)
            {
                info.SetUShort(index * 2, DataPort.Read16());
            }

            driveInfo[drive].MaxLBA = info.GetUInt(IdentifyDrive.MaxLBA28);

            return(true);
        }
Пример #8
0
        // doesn't work since uint should be uint64
        //protected bool ReadLBA48 (SectorOperation operation, uint drive, uint lba, MemoryBlock memory)
        //{
        //    FeaturePort.Write8 (0);
        //    FeaturePort.Write8 (0);

        //    SectorCountPort.Write8 (0);
        //    SectorCountPort.Write8 (1);

        //    LBALowPort.Write8 ((byte)((lba >> 24) & 0xFF));
        //    LBALowPort.Write8 ((byte)(lba & 0xFF));

        //    LBAMidPort.Write8 ((byte)((lba >> 32) & 0xFF));
        //    LBAMidPort.Write8 ((byte)((lba >> 8) & 0xFF));

        //    LBAHighPort.Write8 ((byte)((lba >> 40) & 0xFF));
        //    LBAHighPort.Write8 ((byte)((lba >> 16) & 0xFF));

        //    DeviceHeadPort.Write8 ((byte)(0x40 | (drive << 4)));

        //    if (operation == SectorOperation.Write)
        //        CommandPort.Write8 (0x34);
        //    else
        //        CommandPort.Write8 (0x24);

        //    if (!WaitForReqisterReady ())
        //        return false;

        //    //TODO: Don't use PIO
        //    if (operation == SectorOperation.Read) {
        //        for (uint index = 0; index < 256; index++)
        //            memory.SetUShort (index * 2, DataPort.Read16 ());
        //    }
        //    else {
        //        for (uint index = 0; index < 256; index++)
        //            DataPort.WriteUShort (memory.GetUShort (index * 2));
        //    }

        //    return true;
        //}

        public bool Open(uint driveNbr)
        {
            if (driveNbr == 0)
            {
                DeviceHeadPort.Write8(0xA0);
            }
            else
            if (driveNbr == 1)
            {
                DeviceHeadPort.Write8(0xB0);
            }
            else
            {
                return(false);
            }

            CommandPort.Write8(IDECommand.IdentifyDrive);

            if (!WaitForReqisterReady())
            {
                return(false);
            }

            BinaryFormat info = new BinaryFormat(new byte[512]);

            for (uint index = 0; index < 256; index++)
            {
                info.SetUShort(index * 2, DataPort.Read16());
            }

            driveInfo[driveNbr].MaxLBA = info.GetUInt(IdentifyDrive.MaxLBA28);

            // legacy info
            driveInfo[driveNbr].Heads           = info.GetUShort(IdentifyDrive.LogicalHeads);
            driveInfo[driveNbr].Cylinders       = info.GetUShort(IdentifyDrive.LogicalCylinders);
            driveInfo[driveNbr].SectorsPerTrack = info.GetUShort(IdentifyDrive.LogicalSectors);

            return(true);
        }
Пример #9
0
        public bool Format(FATSettings fatSettings)
        {
            if (!partition.CanWrite)
            {
                return(false);
            }

            this.fatType   = fatSettings.FatType;
            bytesPerSector = 512;

            totalSectors = partition.BlockCount;

            sectorsPerCluster = GetSectorsPerClusterByTotalSectors(fatType, totalSectors);
            nbrFats           = 2;

            if (fatType == FATType.FAT32)
            {
                reservedSectors = 32;
                rootEntries     = 0;
            }
            else
            {
                reservedSectors = 1;
                rootEntries     = 512;
            }

            rootDirSectors = (((rootEntries * 32) + (bytesPerSector - 1)) / bytesPerSector);
            fatStart       = reservedSectors;

            uint val1 = totalSectors - (reservedSectors + rootDirSectors);
            uint val2 = (uint)((256 * sectorsPerCluster) + nbrFats);

            if (fatType == FATType.FAT32)
            {
                val2 = val2 / 2;
            }

            uint sectorsperfat = (val1 + (val2 - 1)) / val2;

            BinaryFormat bootSector = new BinaryFormat(512);

            bootSector.SetUInt(BootSector.JumpInstruction, 0);
            bootSector.SetString(BootSector.EOMName, "MSWIN4.1");
            bootSector.SetUShort(BootSector.BytesPerSector, (ushort)bytesPerSector);
            bootSector.SetByte(BootSector.SectorsPerCluster, (byte)sectorsPerCluster);
            bootSector.SetUShort(BootSector.ReservedSectors, (ushort)reservedSectors);
            bootSector.SetByte(BootSector.FatAllocationTables, nbrFats);
            bootSector.SetUShort(BootSector.MaxRootDirEntries, (ushort)rootEntries);

            if (totalSectors > 0xFFFF)
            {
                bootSector.SetUShort(BootSector.TotalSectors, 0);
                bootSector.SetUInt(BootSector.FAT32_TotalSectors, totalClusters);
            }
            else
            {
                bootSector.SetUShort(BootSector.TotalSectors, (ushort)totalSectors);
                bootSector.SetUInt(BootSector.FAT32_TotalSectors, 0);
            }

            bootSector.SetByte(BootSector.MediaDescriptor, 0xF8);

            if (fatType == FATType.FAT32)
            {
                bootSector.SetUShort(BootSector.SectorsPerFAT, 0);
            }
            else
            {
                bootSector.SetUShort(BootSector.SectorsPerFAT, (ushort)sectorsperfat);
            }

            bootSector.SetUShort(BootSector.SectorsPerTrack, 0);              ////FIXME
            bootSector.SetUInt(BootSector.HiddenSectors, 0);

            if (fatType != FATType.FAT32)
            {
                bootSector.SetByte(BootSector.PhysicalDriveNbr, 0x80);
                bootSector.SetByte(BootSector.ReservedCurrentHead, 0);
                bootSector.SetByte(BootSector.ExtendedBootSignature, 0x29);
                bootSector.SetBytes(BootSector.IDSerialNumber, fatSettings.SerialID, 0, (uint)(fatSettings.SerialID.Length <= 4 ? fatSettings.SerialID.Length : 4));
                bootSector.SetString(BootSector.VolumeLabel, "            ");                   // 12 blank spaces
                bootSector.SetString(BootSector.VolumeLabel, fatSettings.VolumeLabel, (uint)(fatSettings.VolumeLabel.Length <= 12 ? fatSettings.VolumeLabel.Length : 12));
                bootSector.SetUShort(BootSector.BootSectorSignature, 0x55AA);
                //BootSector.OSBootCode // TODO
            }

            if (fatType == FATType.FAT12)
            {
                bootSector.SetString(BootSector.FATType, "FAT12   ");
            }
            else if (fatType == FATType.FAT16)
            {
                bootSector.SetString(BootSector.FATType, "FAT16   ");
            }
            else             // if (type == FatType.FAT32)
            {
                bootSector.SetString(BootSector.FATType, "FAT32   ");
            }

            if (fatType == FATType.FAT32)
            {
                bootSector.SetUInt(BootSector.FAT32_SectorPerFAT, sectorsperfat);
                bootSector.SetByte(BootSector.FAT32_Flags, 0);
                bootSector.SetUShort(BootSector.FAT32_Version, 0);
                bootSector.SetUInt(BootSector.FAT32_ClusterNumberOfRoot, 2);
                bootSector.SetUShort(BootSector.FAT32_SectorFSInformation, 1);
                bootSector.SetUShort(BootSector.FAT32_SecondBootSector, 6);
                //FAT32_Reserved1
                bootSector.SetByte(BootSector.FAT32_PhysicalDriveNbr, 0x80);
                bootSector.SetByte(BootSector.FAT32_Reserved2, 0);
                bootSector.SetByte(BootSector.FAT32_ExtendedBootSignature, 0x29);
                bootSector.SetBytes(BootSector.FAT32_IDSerialNumber, fatSettings.SerialID, 0, (uint)(fatSettings.SerialID.Length <= 4 ? fatSettings.SerialID.Length : 4));
                bootSector.SetString(BootSector.FAT32_VolumeLabel, "            ");                   // 12 blank spaces
                bootSector.SetString(BootSector.FAT32_VolumeLabel, fatSettings.VolumeLabel, (uint)(fatSettings.VolumeLabel.Length <= 12 ? fatSettings.VolumeLabel.Length : 12));
                bootSector.SetString(BootSector.FAT32_FATType, "FAT32   ");
                //BootSector.OSBootCode // TODO
            }

            // Write Boot Sector
            partition.WriteBlock(0, 1, bootSector.Data);

            // Write backup Boot Sector
            if (fatType == FATType.FAT32)
            {
                partition.WriteBlock(0, 1, bootSector.Data);                    // FIXME: wrong block #
            }

            // create FSInfo Structure
            if (fatType == FATType.FAT32)
            {
                BinaryFormat infoSector = new BinaryFormat(512);

                infoSector.SetUInt(FSInfo.FSI_LeadSignature, 0x41615252);
                //FSInfo.FSI_Reserved1
                infoSector.SetUInt(FSInfo.FSI_StructureSigature, 0x61417272);
                infoSector.SetUInt(FSInfo.FSI_FreeCount, 0xFFFFFFFF);
                infoSector.SetUInt(FSInfo.FSI_NextFree, 0xFFFFFFFF);
                //FSInfo.FSI_Reserved2
                bootSector.SetUInt(FSInfo.FSI_TrailSignature, 0xAA550000);

                partition.WriteBlock(1, 1, infoSector.Data);
                partition.WriteBlock(7, 1, infoSector.Data);

                // create 2nd sector
                BinaryFormat secondSector = new BinaryFormat(512);

                secondSector.SetUInt((ushort)FSInfo.FSI_TrailSignature2, 0xAA55);

                partition.WriteBlock(2, 1, secondSector.Data);
                partition.WriteBlock(8, 1, secondSector.Data);
            }

            // create fats
            /// TODO: incomplete
            BinaryFormat emptyFat = new BinaryFormat(512);

            // clear primary & secondary fats entries
            for (uint i = fatStart; i < fatStart + 1; i++)                      //FIXME
            {
                partition.WriteBlock(i, 1, emptyFat.Data);
            }

            // first block is special
            BinaryFormat firstFat = new BinaryFormat(512);

            // TODO: incomplete
            partition.WriteBlock(reservedSectors, 1, emptyFat.Data);

            return(ReadBootSector());
        }
Пример #10
0
        public static void PatchSyslinux_3_72(PartitionDevice partitionDevice, FatFileSystem fat)
        {
            // Locate ldlinux.sys file for patching
            string filename = "ldlinux.sys";
            string name     = (Path.GetFileNameWithoutExtension(filename) + Path.GetExtension(filename).PadRight(4).Substring(0, 4)).ToUpper();

            var location = fat.FindEntry(name);

            if (location.IsValid)
            {
                // Read boot sector
                var bootSector = new 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
                var firstCluster = new 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
                    var 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);
                }
            }
        }