private static void DeleteFile(string fileName, FileStream fStream, FAT12_BOOT_SECTOR bootSector, FAT12_MOUNT_INFO mountInfo)
        {
            byte[] buf = new byte[512];
            FAT12_FILE_ENTRY fat12FileEntry;

            /* Get 8.3 directory name */
            char[] DosFileName = new char[12];
            ToDosFileName(fileName, ref DosFileName);
            DosFileName[11] = '\0';

            /* 16 entries per sector, 14 sectors total */
            for (int sector = 0; sector < 14; sector++)
            {
                /* Read in sector */
                fStream.Seek((mountInfo.rootOffset + sector) * 512, SeekOrigin.Begin);
                fStream.Read(buf, 0, 512);

                /* Get file info */
                GCHandle pinnedBuf = GCHandle.Alloc(buf, GCHandleType.Pinned);
                int count = 0;
                unsafe
                {
                    fat12FileEntry = (FAT12_FILE_ENTRY)Marshal.PtrToStructure(pinnedBuf.AddrOfPinnedObject() + (count * sizeof(FAT12_FILE_ENTRY)), typeof(FAT12_FILE_ENTRY));
                }

                for (int i = 0; i < 16; i++)
                {
                    /* Get current filename */
                    char[] name = new char[12];
                    unsafe
                    {
                        for (int j = 0; j < 11; j++)
                            name[j] = (char)fat12FileEntry.Filename[j];
                    }
                    name[11] = '\0';

                    /* Find a match? */
                    if (String.Compare(String.Concat(DosFileName), String.Concat(name)) == 0)
                    {
                        FreeClusterChain(fat12FileEntry.FirstCluster, fStream);

                        unsafe
                        {
                            fat12FileEntry.Filename[0] = 0xE5;
                            fStream.Seek((mountInfo.rootOffset + sector) * 512 + (count * sizeof(FAT12_FILE_ENTRY)), SeekOrigin.Begin);
                            Marshal.StructureToPtr(fat12FileEntry, pinnedBuf.AddrOfPinnedObject(), true);
                            fStream.Write(buf, 0, sizeof(FAT12_FILE_ENTRY));
                        }

                        return;
                    }

                    count++;
                    unsafe
                    {
                        fat12FileEntry = (FAT12_FILE_ENTRY)Marshal.PtrToStructure(pinnedBuf.AddrOfPinnedObject() + (count * sizeof(FAT12_FILE_ENTRY)), typeof(FAT12_FILE_ENTRY));
                    }
                }

                pinnedBuf.Free();
            }

            return;
        }
        private static FAT12_FILE_ENTRY? OpenSubDirectory(string fileName, FileStream fStream, FAT12_MOUNT_INFO mountInfo, FAT12_FILE_ENTRY? curFile)
        {
            byte[] buf = new byte[512];
            FAT12_FILE_ENTRY fat12FileEntry;

            /* Get 8.3 directory name */
            char[] DosFileName = new char[12];
            ToDosFileName(fileName, ref DosFileName);
            DosFileName[11] = '\0';

            /* 16 entries per sector, 14 sectors total */
            for (int sector = 0; sector < 14; sector++)
            {
                /* Read in sector */
                fStream.Seek(mountInfo.rootOffset + sector, SeekOrigin.Begin);
                fStream.Read(buf, 0, 512);

                /* Get file info */
                GCHandle pinnedBuf = GCHandle.Alloc(buf, GCHandleType.Pinned);
                int count = 0;
                unsafe
                {
                    fat12FileEntry = (FAT12_FILE_ENTRY)Marshal.PtrToStructure(pinnedBuf.AddrOfPinnedObject() + (count * sizeof(FAT12_FILE_ENTRY)), typeof(FAT12_FILE_ENTRY));
                }

                for (int i = 0; i < 16; i++)
                {
                    /* Get current filename */
                    char[] name = new char[12];
                    unsafe
                    {
                        for (int j = 0; j < 11; j++)
                            name[j] = (char)fat12FileEntry.Filename[j];
                    }
                    name[11] = '\0';

                    /* Find a match? */
                    if (String.Compare(DosFileName.ToString(), name.ToString()) == 0)
                    {
                        /* Found it, set up file info */
                        /* strcpy(file.name, DirectoryName); */
                        /* file.currentCluster = directory->FirstCluster; */

                        return fat12FileEntry;
                    }

                    count++;
                    unsafe
                    {
                        fat12FileEntry = (FAT12_FILE_ENTRY)Marshal.PtrToStructure(pinnedBuf.AddrOfPinnedObject() + (count * sizeof(FAT12_FILE_ENTRY)), typeof(FAT12_FILE_ENTRY));
                    }
                }

                pinnedBuf.Free();
            }

            return null;
        }
        static void SaveFileToDiskImage(string fileName, FileStream fStream, FAT12_BOOT_SECTOR bootSector, FAT12_MOUNT_INFO mountInfo)
        {
            /* First delete the file if it exists */
            DeleteFile(fileName, fStream, bootSector, mountInfo);

            byte[] buf = new byte[512];
            FAT12_FILE_ENTRY fat12FileEntry;

            /* Get 8.3 directory name */
            char[] DosFileName = new char[12];
            ToDosFileName(fileName, ref DosFileName);
            DosFileName[11] = '\0';

            /* 16 entries per sector, 14 sectors total */
            for (int sector = 0; sector < 14; sector++)
            {
                /* Read in sector */
                fStream.Seek((mountInfo.rootOffset + sector) * 512, SeekOrigin.Begin);
                fStream.Read(buf, 0, 512);

                /* Get file info */
                GCHandle pinnedBuf = GCHandle.Alloc(buf, GCHandleType.Pinned);
                int count = 0;
                unsafe
                {
                    fat12FileEntry = (FAT12_FILE_ENTRY)Marshal.PtrToStructure(pinnedBuf.AddrOfPinnedObject() + (count * sizeof(FAT12_FILE_ENTRY)), typeof(FAT12_FILE_ENTRY));
                }

                for (int i = 0; i < 16; i++)
                {
                    /* I'm looking for an entry beginning with \0 or 0xE5 */
                    unsafe
                    {
                        if (fat12FileEntry.Filename[0] == '\0' || fat12FileEntry.Filename[0] == 0xE5)
                        {
                            /* Found a blank file entry */
                            for (int j = 0; j < 8; j++)
                                fat12FileEntry.Filename[j] = (byte)DosFileName[j];
                            for (int j = 0; j < 3; j++)
                                fat12FileEntry.Ext[j] = (byte)DosFileName[j + 8];

                            fat12FileEntry.Attrib = 0;
                            /* TODO: Set the date and times */
                            fat12FileEntry.DateCreated = 0;
                            fat12FileEntry.DateLastAccessed = 0;
                            fat12FileEntry.LastModDate = 0;
                            fat12FileEntry.LastModTime = 0;
                            fat12FileEntry.TimeCreated = 0;
                            fat12FileEntry.TimeCreatedMs = 0;
                            fat12FileEntry.FileSize = 0;

                            fat12FileEntry.FirstCluster = GetFirstFreeCluster(fStream, 2);

                            UInt16 currentCluster = fat12FileEntry.FirstCluster;
                            FileStream inputFile = new FileStream(fileName, FileMode.Open);
                            byte[] inputBuffer = new byte[512];
                            int readBytes = 0;
                            while ((readBytes = inputFile.Read(inputBuffer, 0, 512)) > 0)
                            {
                                fat12FileEntry.FileSize += (uint)readBytes;
                                fStream.Seek((31 + currentCluster) * 512, SeekOrigin.Begin);
                                fStream.Write(inputBuffer, 0, readBytes);

                                if (fStream.Length > fat12FileEntry.FileSize)
                                { /* Allocate next block */
                                    UInt16 nextBlock = GetFirstFreeCluster(fStream, (UInt16)(currentCluster + 1));
                                    MarkBlockChain(fStream, currentCluster, nextBlock);
                                    currentCluster = nextBlock;
                                }
                            }

                            MarkBlockChain(fStream, currentCluster, 0xFFF);

                            fStream.Seek((mountInfo.rootOffset + sector) * 512 + (count * sizeof(FAT12_FILE_ENTRY)), SeekOrigin.Begin);
                            Marshal.StructureToPtr(fat12FileEntry, pinnedBuf.AddrOfPinnedObject(), true);
                            fStream.Write(buf, 0, sizeof(FAT12_FILE_ENTRY));

                            return;
                        }

                        count++;
                        unsafe
                        {
                            fat12FileEntry = (FAT12_FILE_ENTRY)Marshal.PtrToStructure(pinnedBuf.AddrOfPinnedObject() + (count * sizeof(FAT12_FILE_ENTRY)), typeof(FAT12_FILE_ENTRY));
                        }
                    }
                }

                pinnedBuf.Free();
            }
        }
        static void Main(string[] args)
        {
            string imageFileName = args[0];

            FileInfo image = new FileInfo(imageFileName);
            FileStream fStream;
            if (image.Exists)
                fStream = image.Open(FileMode.Open, FileAccess.ReadWrite);
            else
                fStream = createNewFloppyImage(image);

            FAT12_BOOT_SECTOR bootSector = LoadBootSector(fStream);
            FAT12_MOUNT_INFO mount_info = new FAT12_MOUNT_INFO();

            mount_info.numSectors = bootSector.Bpb.NumSectors;
            mount_info.fatOffset = 1;
            mount_info.fatSize = bootSector.Bpb.SectorsPerFat;
            mount_info.fatEntrySize = 8;
            mount_info.numRootEntries = bootSector.Bpb.NumDirEntries;
            mount_info.rootOffset = (uint)(bootSector.Bpb.NumberOfFats * bootSector.Bpb.SectorsPerFat) + 1;
            mount_info.rootSize = (uint)(bootSector.Bpb.NumDirEntries * 32) / bootSector.Bpb.BytesPerSector;

            for (int i = 1; i < args.Length; i++)
            {
                SaveFileToDiskImage(args[i], fStream, bootSector, mount_info);
            }
        }