diff --git a/desmume/src/addons/compactFlash.cpp b/desmume/src/addons/compactFlash.cpp
index 476424171..40b7a9ade 100644
--- a/desmume/src/addons/compactFlash.cpp
+++ b/desmume/src/addons/compactFlash.cpp
@@ -327,6 +327,9 @@ void build_ListCallback(FsEntry* fs, EListCallbackArg arg)
{
char* fname = (strlen(fs->cAlternateFileName)>0) ? fs->cAlternateFileName : fs->cFileName;
+ //we use cFileName always because it is a LFN and we are making sure that we always make a fat32 image
+ fname = fs->cFileName;
+
if(arg == EListCallbackArg_Pop)
{
currFatFile = fatStack.top();
@@ -384,15 +387,22 @@ static BOOL cflash_build_fat()
currPath = sFlashPath;
list_files(sFlashPath.c_str(), count_ListCallback);
+ dataSectors += 8; //a few for reserved sectors, etc.
+
dataSectors += 16*1024*1024/512; //add 16MB worth of write space. this is probably enough for anyone, but maybe it should be configurable.
//we could always suggest to users to add a big file to their directory to overwrite (that would cause the image to get padded)
+
+ //this seems to be the minimum size that will turn into a solid fat32
+ if(dataSectors<36*1024*1024/512)
+ dataSectors = 36*1024*1024/512;
delete file;
- file = new EMUFILE_MEMORY(dataSectors*512+1);
+ file = new EMUFILE_MEMORY(dataSectors*512);
+ //file = new EMUFILE_FILE("c:\\temp.ima","rb+");
EmuFat fat(file);
EmuFatVolume vol;
u8 ok = vol.init(&fat);
- vol.format(dataSectors);
+ vol.formatNew(dataSectors);
reconstruct(&currFatFile);
currFatFile.openRoot(&vol);
@@ -772,11 +782,6 @@ static unsigned int cflash_read(unsigned int address)
{
unsigned int ret_value = 0;
size_t elems_read = 0;
-#if 0 /* used by next if 0 block */
-#define BUFFERED_BLOCK_SIZE 512
- static u8 block_buffer[BUFFERED_BLOCK_SIZE];
- static s32 buffered_start_index = -1;
-#endif
switch (address)
{
diff --git a/desmume/src/emufat.cpp b/desmume/src/emufat.cpp
index 7af09d68c..78fdeba1c 100644
--- a/desmume/src/emufat.cpp
+++ b/desmume/src/emufat.cpp
@@ -1,36 +1,74 @@
-//Copyright (C) 2009-2010 DeSmuME team
+/* Copyright 2009-2010 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see .
+*/
+
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
-/*
- * Copyright (C) 2009 by William Greiman
- *
- * This file is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
+//Copyright (C) 2009 by William Greiman
+
+//based on mkdosfs - utility to create FAT/MS-DOS filesystems
+//Copyright (C) 1991 Linus Torvalds
+//Copyright (C) 1992-1993 Remy Card
+//Copyright (C) 1993-1994 David Hudson
+//Copyright (C) 1998 H. Peter Anvin
+//Copyright (C) 1998-2005 Roman Hodek
#include "emufat.h"
-static const u8 mkdosfs_bootcode[420] =
+#define LE16(x) (x)
+#define LE32(x) (x)
+
+
+#define MAX_CLUST_12 ((1 << 12) - 16)
+#define MAX_CLUST_16 ((1 << 16) - 16)
+#define MIN_CLUST_32 65529
+/* M$ says the high 4 bits of a FAT32 FAT entry are reserved and don't belong
+* to the cluster number. So the max. cluster# is based on 2^28 */
+#define MAX_CLUST_32 ((1 << 28) - 16)
+#define FAT12_THRESHOLD 4085
+#define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */
+#define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */
+#define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */
+#define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature */
+static const int sector_size = 512;
+#define BLOCK_SIZE 512
+#define HARD_SECTOR_SIZE 512
+#define SECTORS_PER_BLOCK ( BLOCK_SIZE / HARD_SECTOR_SIZE )
+#define FAT_EOF (0x0ffffff8)
+#define BOOT_SIGN 0xAA55 /* Boot sector magic number */
+
+struct __PACKED fat32_fsinfo {
+ u32 reserved1; /* Nothing as far as I can tell */
+ u32 signature; /* 0x61417272L */
+ u32 free_clusters; /* Free cluster count. -1 if unknown */
+ u32 next_cluster; /* Most recently allocated cluster.
+ * Unused under Linux. */
+ u32 reserved2[4];
+};
+
+//see mkdosfs for the disassembly
+static const u8 mkdosfs_bootcode_fat32[420] =
{
- 0xFE, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62,
- 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50,
- 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62,
- 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79, 0x20, 0x61,
- 0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65,
- 0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E,
- 0x2E, 0x2E, 0x20, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0E, 0x1F, 0xBE, 0x77, 0x7C, 0xAC, 0x22, 0xC0, 0x74, 0x0B, 0x56, 0xB4, 0x0E, 0xBB, 0x07, 0x00,
+ 0xCD, 0x10, 0x5E, 0xEB, 0xF0, 0x32, 0xE4, 0xCD, 0x16, 0xCD, 0x19, 0xEB, 0xFE, 0x54, 0x68, 0x69,
+ 0x73, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
+ 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73,
+ 0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
+ 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A,
+ 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F,
+ 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E, 0x2E, 0x2E, 0x20, 0x0D,
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -80,7 +118,6 @@ EmuFat::~EmuFat()
delete m_pFile;
}
-
u8 EmuFat::cacheRawBlock(u32 blockNumber, u8 action)
{
if (cache_.cacheBlockNumber_ != blockNumber) {
@@ -105,6 +142,11 @@ u8 EmuFat::cacheZeroBlock(u32 blockNumber)
return true;
}
+void EmuFat::cacheReset()
+{
+ reconstruct(&cache_);
+}
+
u8 EmuFat::cacheFlush() {
if (cache_.cacheDirty_) {
if (!writeBlock(cache_.cacheBlockNumber_, cache_.cacheBuffer_.data)) {
@@ -165,74 +207,437 @@ void EmuFat::truncate(u32 size)
//-------------------------------------------------------------------------------------
+inline int cdiv (int a, int b)
+{
+ return (a + b - 1) / b;
+}
+
+bool calculateClusterSize(TFat32BootSector* bsp, u32 avail_sectors, u32& cluster_count, u32& fat_length, int size_fat_by_user, int &size_fat)
+{
+ TFat32BootSector &bs = *bsp;
+ const u32 fatdata = avail_sectors;
+ int maxclustsize = bsp->sectorsPerCluster;
+
+ u32 fatlength12, fatlength16, fatlength32;
+ u32 maxclust12, maxclust16, maxclust32;
+ u32 clust12, clust16, clust32;
+do {
+ printf( "Trying with %d sectors/cluster:\n", bs.sectorsPerCluster );
+
+ /* The factor 2 below avoids cut-off errors for nr_fats == 1.
+ * The "nr_fats*3" is for the reserved first two FAT entries */
+ clust12 = 2*((u64) fatdata *sector_size + bs.fatCount*3) /
+ (2*(int) bs.sectorsPerCluster * sector_size + bs.fatCount*3);
+ fatlength12 = cdiv (((clust12+2) * 3 + 1) >> 1, sector_size);
+ /* Need to recalculate number of clusters, since the unused parts of the
+ * FATS and data area together could make up space for an additional,
+ * not really present cluster. */
+ clust12 = (fatdata - bs.fatCount*fatlength12)/bs.sectorsPerCluster;
+ maxclust12 = (fatlength12 * 2 * sector_size) / 3;
+ if (maxclust12 > MAX_CLUST_12)
+ maxclust12 = MAX_CLUST_12;
+ printf( "FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
+ clust12, fatlength12, maxclust12, MAX_CLUST_12 );
+ if (clust12 > maxclust12-2) {
+ clust12 = 0;
+ printf( "FAT12: too much clusters\n" );
+ }
+
+ clust16 = ((u64) fatdata *sector_size + bs.fatCount*4) /
+ ((int) bs.sectorsPerCluster * sector_size + bs.fatCount*2);
+ fatlength16 = cdiv ((clust16+2) * 2, sector_size);
+ /* Need to recalculate number of clusters, since the unused parts of the
+ * FATS and data area together could make up space for an additional,
+ * not really present cluster. */
+ clust16 = (fatdata - bs.fatCount*fatlength16)/bs.sectorsPerCluster;
+ maxclust16 = (fatlength16 * sector_size) / 2;
+ if (maxclust16 > MAX_CLUST_16)
+ maxclust16 = MAX_CLUST_16;
+ printf( "FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
+ clust16, fatlength16, maxclust16, MAX_CLUST_16 );
+ if (clust16 > maxclust16-2) {
+ printf( "FAT16: too much clusters\n" );
+ clust16 = 0;
+ }
+ /* The < 4078 avoids that the filesystem will be misdetected as having a
+ * 12 bit FAT. */
+ if (clust16 < FAT12_THRESHOLD && !(size_fat_by_user && size_fat == 16)) {
+ printf( clust16 < FAT12_THRESHOLD ?
+ "FAT16: would be misdetected as FAT12\n" :
+ "FAT16: too much clusters\n" );
+ clust16 = 0;
+ }
+
+ clust32 = ((u64) fatdata *sector_size + bs.fatCount*8) /
+ ((int) bs.sectorsPerCluster * sector_size + bs.fatCount*4);
+ fatlength32 = cdiv ((clust32+2) * 4, sector_size);
+ /* Need to recalculate number of clusters, since the unused parts of the
+ * FATS and data area together could make up space for an additional,
+ * not really present cluster. */
+ clust32 = (fatdata - bs.fatCount*fatlength32)/bs.sectorsPerCluster;
+ maxclust32 = (fatlength32 * sector_size) / 4;
+ if (maxclust32 > MAX_CLUST_32)
+ maxclust32 = MAX_CLUST_32;
+ if (clust32 && clust32 < MIN_CLUST_32 && !(size_fat_by_user && size_fat == 32)) {
+ clust32 = 0;
+ printf( "FAT32: not enough clusters (%d)\n", MIN_CLUST_32);
+ }
+ printf( "FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
+ clust32, fatlength32, maxclust32, MAX_CLUST_32 );
+ if (clust32 > maxclust32) {
+ clust32 = 0;
+ printf( "FAT32: too much clusters\n" );
+ }
+
+ if ((clust12 && (size_fat == 0 || size_fat == 12)) ||
+ (clust16 && (size_fat == 0 || size_fat == 16)) ||
+ (clust32 && size_fat == 32))
+ break;
+
+ bs.sectorsPerCluster <<= 1;
+ } while (bs.sectorsPerCluster && bs.sectorsPerCluster <= maxclustsize);
+
+
+ /* Use the optimal FAT size if not specified;
+ * FAT32 is (not yet) choosen automatically */
+ if (!size_fat) {
+ size_fat = (clust16 > clust12) ? 16 : 12;
+ printf( "Choosing %d bits for FAT\n", size_fat );
+ }
+
+ switch (size_fat) {
+ case 12:
+ cluster_count = clust12;
+ fat_length = fatlength12;
+ bs.sectorsPerFat16 = LE16(fatlength12);
+ break;
+ case 16:
+ if (clust16 < FAT12_THRESHOLD) {
+ if (size_fat_by_user) {
+ printf("WARNING: Not enough clusters for a "
+ "16 bit FAT! The filesystem will be\n"
+ "misinterpreted as having a 12 bit FAT without "
+ "mount option \"fat=16\".\n" );
+ return false;
+ }
+ else {
+ printf("This filesystem has an unfortunate size. "
+ "A 12 bit FAT cannot provide\n"
+ "enough clusters, but a 16 bit FAT takes up a little "
+ "bit more space so that\n"
+ "the total number of clusters becomes less than the "
+ "threshold value for\n"
+ "distinction between 12 and 16 bit FATs.\n" );
+ return false;
+ }
+ }
+ cluster_count = clust16;
+ fat_length = fatlength16;
+ bs.sectorsPerFat16 = LE16(fatlength16);
+ break;
+
+case 32:
+ if (clust32 < MIN_CLUST_32)
+ printf("WARNING: Not enough clusters for a 32 bit FAT!\n");
+ cluster_count = clust32;
+ fat_length = fatlength32;
+ bs.sectorsPerFat16 = LE16(0);
+ bs.fat32.sectorsPerFat32 = LE32(fatlength32);
+ break;
+
+ }
+
+ return true;
+}
+
+static void mark_FAT_cluster (int size_fat, u8* fat, int cluster, unsigned int value)
+{
+ switch( size_fat ) {
+case 12:
+ value &= 0x0fff;
+ if (((cluster * 3) & 0x1) == 0)
+ {
+ fat[3 * cluster / 2] = (unsigned char) (value & 0x00ff);
+ fat[(3 * cluster / 2) + 1] = (unsigned char) ((fat[(3 * cluster / 2) + 1] & 0x00f0)
+ | ((value & 0x0f00) >> 8));
+ }
+ else
+ {
+ fat[3 * cluster / 2] = (unsigned char) ((fat[3 * cluster / 2] & 0x000f) | ((value & 0x000f) << 4));
+ fat[(3 * cluster / 2) + 1] = (unsigned char) ((value & 0x0ff0) >> 4);
+ }
+ break;
+
+case 16:
+ value &= 0xffff;
+ fat[2 * cluster] = (unsigned char) (value & 0x00ff);
+ fat[(2 * cluster) + 1] = (unsigned char) (value >> 8);
+ break;
+
+case 32:
+ value &= 0xfffffff;
+ fat[4 * cluster] = (unsigned char) (value & 0x000000ff);
+ fat[(4 * cluster) + 1] = (unsigned char) ((value & 0x0000ff00) >> 8);
+ fat[(4 * cluster) + 2] = (unsigned char) ((value & 0x00ff0000) >> 16);
+ fat[(4 * cluster) + 3] = (unsigned char) ((value & 0xff000000) >> 24);
+ break;
+ }
+}
+
+//use 36M as minimum fat32 size (or else mkdosfs complains)
+//this function assumes fat32. it could be redone to be intelligent by making another pass through mkdosfs and analyzing it again
+//but we onnly targeted fat32 our first time through
+bool EmuFatVolume::formatNew(u32 sectors)
+{
+ u32 volumeStartBlock = 0;
+ TFat32BootSector bsrec;
+ memset(&bsrec,0,sizeof(TFat32BootSector));
+ TFat32BootSector *bs = &bsrec;
+
+ //perform same analysis (we guess) as mkdosfs
+
+ //"fake values"
+ bs->sectorsPerTrack = 32;
+ bs->headCount = 64;
+ //def_hd_params:
+ bs->mediaType = 0xF8;
+ bs->rootDirEntryCount = LE16(512); //Default to 512 entries - N.B. this is overwritten later
+ static const u32 BLOCK_SIZE_BITS = 9;
+ const u32 sz_mb = (sectors+(1<<(20-BLOCK_SIZE_BITS))-1) >> (20-BLOCK_SIZE_BITS);
+ bs->sectorsPerCluster =
+ sz_mb > 16*1024 ? 32 :
+ sz_mb > 8*1024 ? 16 :
+ sz_mb > 260 ? 8 :
+ 1;
+ //(fat16 and fat12 would start at 4 sectors per cluster)
+
+ memcpy (bs->oemName, "mkdosfs", 8);
+ bs->rootDirEntryCount = 0; //Under FAT32, the root dir is in a cluster chain, and this is signalled by bs.dir_entries being 0
+ bs->fat32.vi.volume_id = 0; //not generating a volume id.. just use 0 for determinism's sake
+ memcpy(bs->fat32.vi.volume_label," ",11);
+ bs->jmpToBootCode[0] = 0xEB;
+ bs->jmpToBootCode[1] = 0x58; //this value is only for fat32 //Patch in the correct offset to the boot code
+ bs->jmpToBootCode[2] = 0x90;
+
+ memcpy(bs->fat32.boot_code,mkdosfs_bootcode_fat32,420);
+ bs->boot_sign[0] = 0x55;
+ bs->boot_sign[1] = 0xAA;
+
+ bs->reservedSectorCount = LE16(32);
+ bs->fatCount = 2;
+ bs->hiddenSectors = LE32(0);
+
+ u32 fatdata = sectors - cdiv (bs->rootDirEntryCount * 32, 512) - bs->reservedSectorCount;
+
+ u32 cluster_count;
+ u32 fat_length;
+ int size_fat = 32;
+ if(!calculateClusterSize(bs, fatdata, cluster_count, fat_length, 1, size_fat))
+ return false;
+ //TODO - this function whacks values we set earlier. gross. either mkdosfs is sloppy or i dont understand it.
+ //anyway, whack that dup code
+ switch(size_fat)
+ {
+ case 12: memcpy(bs->oldfat.vi.fs_type, MSDOS_FAT12_SIGN, 8); break;
+ case 16: memcpy(bs->oldfat.vi.fs_type, MSDOS_FAT16_SIGN, 8); break;
+ case 32: memcpy(bs->fat32.vi.fs_type, MSDOS_FAT32_SIGN, 8); break;
+ }
+
+ bs->bytesPerSector = 512;
+
+ //set up additional FAT32 fields
+ bs->fat32.fat32Flags = LE16(0);
+ bs->fat32.fat32Version = LE16(0);
+ bs->fat32.fat32RootCluster = LE32(2);
+ bs->fat32.fat32FSInfo = LE16(1);
+ u32 backup_boot = (bs->reservedSectorCount>= 7) ? 6 : (bs->reservedSectorCount >= 2) ? bs->reservedSectorCount-1 : 0;
+ printf( "Using sector %d as backup boot sector (0 = none)\n",backup_boot );
+ bs->fat32.fat32BackBootBlock = LE16(backup_boot);
+ memset(bs->fat32.fat32Reserved,0,sizeof(bs->fat32.fat32Reserved));
+
+ if(sectors>= 65536) {
+ bs->totalSectors16 = LE16(0);
+ bs->totalSectors32 = LE32(sectors);
+ } else {
+ bs->totalSectors16 = LE16(sectors);
+ bs->totalSectors32 = LE32(0);
+ }
+
+ if (!cluster_count)
+ {
+ //if (sectors_per_cluster) /* If yes, die if we'd spec'd sectors per cluster */
+ // die ("Too many clusters for file system - try more sectors per cluster");
+ //else
+ printf("Attempting to create a too large file system");
+ return false;
+ }
+
+ u32 start_data_sector = (bs->reservedSectorCount + bs->fatCount * fat_length) * (sector_size/512);
+ u32 start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK;
+
+ if (sectors < start_data_block + 32) /* Arbitrary undersize file system! */
+ {
+ printf("Too few blocks for viable file system");
+ return false;
+ }
+
+ bs->fat32.vi.ext_boot_sign = MSDOS_EXT_SIGN;
+
+ //Make the file allocation tables!
+ u8* fat = new u8[fat_length * sector_size];
+ memset( fat, 0, fat_length * sector_size );
+ mark_FAT_cluster (size_fat, fat, 0, 0xffffffff); /* Initial fat entries */
+ mark_FAT_cluster (size_fat, fat, 1, 0xffffffff);
+ fat[0] = bs->mediaType; /* Put media type in first byte! */
+ if (size_fat == 32) {
+ /* Mark cluster 2 as EOF (used for root dir) */
+ mark_FAT_cluster (size_fat, fat, 2, FAT_EOF);
+ }
+
+ u32 size_root_dir = (size_fat == 32) ? bs->sectorsPerCluster*sector_size :
+ bs->rootDirEntryCount * sizeof (TDirectoryEntry);
+ //u8* root_dir = new u8[size_root_dir];
+ //memset(root_dir, 0, size_root_dir);
+ u32 size_root_dir_in_sectors = size_root_dir/512;
+
+
+ u8* info_sector = NULL;
+ if (size_fat == 32) {
+ /* For FAT32, create an info sector */
+ fat32_fsinfo *info;
+
+ info_sector = new u8[sector_size];
+ memset(info_sector, 0, sector_size);
+ /* fsinfo structure is at offset 0x1e0 in info sector by observation */
+ info = (fat32_fsinfo *)(info_sector + 0x1e0);
+
+ /* Info sector magic */
+ info_sector[0] = 'R';
+ info_sector[1] = 'R';
+ info_sector[2] = 'a';
+ info_sector[3] = 'A';
+
+ /* Magic for fsinfo structure */
+ info->signature = LE32(0x61417272);
+ /* We've allocated cluster 2 for the root dir. */
+ info->free_clusters = LE32(cluster_count - 1);
+ info->next_cluster = LE32(2);
+
+ /* Info sector also must have boot sign */
+ *(u16 *)(info_sector + 0x1fe) = LE16(BOOT_SIGN);
+ }
+
+ //-------------
+
+ //write_tables()
+ u8* blank_sector = new u8[512];
+ memset(blank_sector,0,512);
+
+ dev_->cacheReset();
+ dev_->truncate(0);
+ dev_->truncate(sectors*512);
+ /* clear all reserved sectors */
+ for(int i=0;ireservedSectorCount;i++)
+ dev_->writeBlock(0,blank_sector);
+ /* seek back to sector 0 and write the boot sector */
+ dev_->writeBlock(0,(const u8*)bs);
+ /* on FAT32, write the info sector and backup boot sector */
+ if (size_fat == 32)
+ {
+ dev_->writeBlock(bs->fat32.fat32FSInfo,info_sector);
+ if(bs->fat32.fat32BackBootBlock)
+ dev_->writeBlock(bs->fat32.fat32BackBootBlock,(const u8*)bs);
+ }
+ /* seek to start of FATS and write them all */
+ int ctr=bs->reservedSectorCount;
+ for (int i=0;ifatCount;i++)
+ for(int j=0;jwriteBlock(ctr,fat+j*sector_size);
+
+ /* Write the root directory directly after the last FAT. This is the root
+ * dir area on FAT12/16, and the first cluster on FAT32. */
+ for(int i=0;iwriteBlock(ctr,blank_sector);
+
+ delete[] blank_sector;
+ delete[] info_sector;
+ delete[] fat;
+
+ return init(dev_,0);
+
+ //return true;
+}
+
//well, there are a lot of ways to format a disk. this is just a simple one.
//it would be nice if someone who understood fat better could modify the root
//directory setup to use reasonable code instead of magic arrays
bool EmuFatVolume::format(u32 sectors)
{
- u32 volumeStartBlock = 0;
- dev_->truncate(0);
- dev_->truncate(sectors*512);
- if (!dev_->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_WRITE)) return false;
- memset(&dev_->cache_.cacheBuffer_,0,sizeof(dev_->cache_.cacheBuffer_));
- TFat32BootSector* bs = &dev_->cache_.cacheBuffer_.fbs;
- TBiosParmBlock* bpb = &bs->bpb;
+ //u32 volumeStartBlock = 0;
+ //dev_->truncate(0);
+ //dev_->truncate(sectors*512);
+ //if (!dev_->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_WRITE)) return false;
+ //memset(&dev_->cache_.cacheBuffer_,0,sizeof(dev_->cache_.cacheBuffer_));
+ //TFat32BootSector* bs = &dev_->cache_.cacheBuffer_.fbs;
+ //TBiosParmBlock* bpb = &bs->bpb;
- bs->jmpToBootCode[0] = 0xEB;
- bs->jmpToBootCode[1] = 0x3C;
- bs->jmpToBootCode[2] = 0x90;
- memcpy(bs->oemName,"mkdosfs",8);
- bs->driveNumber = 0;
- bs->reserved1 = 0;
- bs->bootSignature = 0x29;
- bs->volumeSerialNumber = 0;
- memcpy(bs->volumeLabel," ",11);
- memcpy(bs->fileSystemType,"FAT16 ",8);
- memcpy(bs->bootCode,mkdosfs_bootcode,420);
- bs->bootSectorSig0 = 0x55;
- bs->bootSectorSig1 = 0xAA;
+ //bs->jmpToBootCode[0] = 0xEB;
+ //bs->jmpToBootCode[1] = 0x3C;
+ //bs->jmpToBootCode[2] = 0x90;
+ //memcpy(bs->oemName,"mkdosfs",8);
+ //bs->driveNumber = 0;
+ //bs->reserved1 = 0;
+ //bs->bootSignature = 0x29;
+ //bs->volumeSerialNumber = 0;
+ //memcpy(bs->volumeLabel," ",11);
+ //memcpy(bs->fileSystemType,"FAT16 ",8);
+ //memcpy(bs->bootCode,mkdosfs_bootcode,420);
+ //bs->bootSectorSig0 = 0x55;
+ //bs->bootSectorSig1 = 0xAA;
- bpb->bytesPerSector = 512;
- bpb->sectorsPerCluster = 4;
- bpb->reservedSectorCount = 1;
- bpb->fatCount = 2;
- bpb->rootDirEntryCount = 512;
- bpb->totalSectors16 = 0;
- bpb->mediaType = 0xF8;
- bpb->sectorsPerFat16 = 32;
- bpb->sectorsPerTrack = 32;
- bpb->headCount = 64;
- bpb->hiddenSectors = 0;
- bpb->totalSectors32 = sectors;
- bpb->fat32Flags = 0xbe0d;
- bpb->fat32Version = 0x20Fd;
- bpb->fat32RootCluster = 0x20202020;
- bpb->fat32FSInfo = 0x2020;
- bpb->fat32BackBootBlock = 0x2020;
+ //bpb->bytesPerSector = 512;
+ //bpb->sectorsPerCluster = 4;
+ //bpb->reservedSectorCount = 1;
+ //bpb->fatCount = 2;
+ //bpb->rootDirEntryCount = 512;
+ //bpb->totalSectors16 = 0;
+ //bpb->mediaType = 0xF8;
+ //bpb->sectorsPerFat16 = 32;
+ //bpb->sectorsPerTrack = 32;
+ //bpb->headCount = 64;
+ //bpb->hiddenSectors = 0;
+ //bpb->totalSectors32 = sectors;
+ //bpb->fat32Flags = 0xbe0d;
+ //bpb->fat32Version = 0x20Fd;
+ //bpb->fat32RootCluster = 0x20202020;
+ //bpb->fat32FSInfo = 0x2020;
+ //bpb->fat32BackBootBlock = 0x2020;
- if(!dev_->cacheFlush())
- return false;
+ //if(!dev_->cacheFlush())
+ // return false;
- if (!dev_->cacheRawBlock(1, EmuFat::CACHE_FOR_WRITE)) return false;
+ //if (!dev_->cacheRawBlock(1, EmuFat::CACHE_FOR_WRITE)) return false;
- static const u8 rootEntry[8] =
- {
- 0xF8, 0xFF, 0xFF, 0xFF,
- } ;
+ //static const u8 rootEntry[8] =
+ //{
+ // 0xF8, 0xFF, 0xFF, 0xFF,
+ //} ;
- memcpy(dev_->cache_.cacheBuffer_.data,rootEntry,4);
+ //memcpy(dev_->cache_.cacheBuffer_.data,rootEntry,4);
- if(!dev_->cacheFlush())
- return false;
+ //if(!dev_->cacheFlush())
+ // return false;
- if (!dev_->cacheRawBlock(33, EmuFat::CACHE_FOR_WRITE)) return false;
+ //if (!dev_->cacheRawBlock(33, EmuFat::CACHE_FOR_WRITE)) return false;
- memcpy(dev_->cache_.cacheBuffer_.data,rootEntry,4);
+ //memcpy(dev_->cache_.cacheBuffer_.data,rootEntry,4);
- if(!dev_->cacheFlush())
- return false;
+ //if(!dev_->cacheFlush())
+ // return false;
- return init(dev_,0);
+ //return init(dev_,0);
+
+ return false;
}
bool EmuFatVolume::init(EmuFat* dev, u8 part) {
@@ -253,16 +658,16 @@ bool EmuFatVolume::init(EmuFat* dev, u8 part) {
volumeStartBlock = p->firstSector;
}
if (!dev->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_READ)) return false;
- TBiosParmBlock* bpb = &dev->cache_.cacheBuffer_.fbs.bpb;
- if (bpb->bytesPerSector != 512 ||
- bpb->fatCount == 0 ||
- bpb->reservedSectorCount == 0 ||
- bpb->sectorsPerCluster == 0) {
+ TFat32BootSector* bs = &dev->cache_.cacheBuffer_.fbs;
+ if (bs->bytesPerSector != 512 ||
+ bs->fatCount == 0 ||
+ bs->reservedSectorCount == 0 ||
+ bs->sectorsPerCluster == 0) {
// not valid FAT volume
return false;
}
- fatCount_ = bpb->fatCount;
- blocksPerCluster_ = bpb->sectorsPerCluster;
+ fatCount_ = bs->fatCount;
+ blocksPerCluster_ = bs->sectorsPerCluster;
// determine shift that is same as multiply by blocksPerCluster_
clusterSizeShift_ = 0;
@@ -270,23 +675,23 @@ bool EmuFatVolume::init(EmuFat* dev, u8 part) {
// error if not power of 2
if (clusterSizeShift_++ > 7) return false;
}
- blocksPerFat_ = bpb->sectorsPerFat16 ?
- bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
+ blocksPerFat_ = bs->sectorsPerFat16 ?
+ bs->sectorsPerFat16 : bs->fat32.sectorsPerFat32;
- fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
+ fatStartBlock_ = volumeStartBlock + bs->reservedSectorCount;
// count for FAT16 zero for FAT32
- rootDirEntryCount_ = bpb->rootDirEntryCount;
+ rootDirEntryCount_ = bs->rootDirEntryCount;
// directory start for FAT16 dataStart for FAT32
- rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
+ rootDirStart_ = fatStartBlock_ + bs->fatCount * blocksPerFat_;
// data start for FAT16 and FAT32
- dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512);
+ dataStartBlock_ = rootDirStart_ + ((32 * bs->rootDirEntryCount + 511)/512);
// total blocks for FAT16 or FAT32
- u32 totalBlocks = bpb->totalSectors16 ?
- bpb->totalSectors16 : bpb->totalSectors32;
+ u32 totalBlocks = bs->totalSectors16 ?
+ bs->totalSectors16 : bs->totalSectors32;
// total data blocks
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
@@ -299,7 +704,7 @@ bool EmuFatVolume::init(EmuFat* dev, u8 part) {
} else if (clusterCount_ < 65525) {
fatType_ = 16;
} else {
- rootDirStart_ = bpb->fat32RootCluster;
+ rootDirStart_ = bs->fat32.fat32RootCluster;
fatType_ = 32;
}
return true;
diff --git a/desmume/src/emufat.h b/desmume/src/emufat.h
index 2745d6ef7..6ecdc8b61 100644
--- a/desmume/src/emufat.h
+++ b/desmume/src/emufat.h
@@ -1,22 +1,29 @@
-//Copyright (C) 2009-2010 DeSmuME team
+/* Copyright 2009-2010 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see .
+*/
+
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
-/*
- * Copyright (C) 2009 by William Greiman
- *
- * This file is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * .
- */
+//Copyright (C) 2009 by William Greiman
+
+//based on mkdosfs - utility to create FAT/MS-DOS filesystems
+//Copyright (C) 1991 Linus Torvalds
+//Copyright (C) 1992-1993 Remy Card
+//Copyright (C) 1993-1994 David Hudson
+//Copyright (C) 1998 H. Peter Anvin
+//Copyright (C) 1998-2005 Roman Hodek
+
#ifndef EMUFAT_H
#define EMUFAT_H
@@ -25,6 +32,10 @@
#include "emufile.h"
#include
+#define BOOTCODE_SIZE 448
+#define BOOTCODE_FAT32_SIZE 420
+
+
// use the gnu style oflag in open()
/** open() oflag for reading */
static const u8 EO_READ = 0X01;
@@ -129,16 +140,29 @@ struct __PACKED TMasterBootRecord {
u8 mbrSig1;
};
-//BIOS parameter block
-//The BIOS parameter block describes the physical layout of a FAT volume.
-struct __PACKED TBiosParmBlock {
+struct __PACKED msdos_volume_info {
+ u8 drive_number; /* BIOS drive number */
+ u8 RESERVED; /* Unused */
+ u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
+ u32 volume_id; /* Volume ID number */
+ u8 volume_label[11];/* Volume label */
+ u8 fs_type[8]; /* Typically FAT12 or FAT16 */
+};
+
+//Boot sector for a FAT16 or FAT32 volume.
+struct __PACKED TFat32BootSector {
+ //X86 jmp to boot program
+ u8 jmpToBootCode[3];
+ //informational only - don't depend on it
+ u8 oemName[8];
+
//Count of bytes per sector. This value may take on only the
//following values: 512, 1024, 2048 or 4096
u16 bytesPerSector;
//Number of sectors per allocation unit. This value must be a
//power of 2 that is greater than 0. The legal values are
//1, 2, 4, 8, 16, 32, 64, and 128.
- u8 sectorsPerCluster;
+ u8 sectorsPerCluster; //cluster_size
//Number of sectors before the first FAT.
//This value must not be zero.
u16 reservedSectorCount;
@@ -151,7 +175,7 @@ struct __PACKED TBiosParmBlock {
//value should always specify a count that when multiplied by 32
//results in a multiple of bytesPerSector. FAT16 volumes should
//use the value 512.
- u16 rootDirEntryCount;
+ u16 rootDirEntryCount; //dir_entries
//This field is the old 16-bit total count of sectors on the volume.
//This count includes the count of all sectors in all four regions
//of the volume. This field can be 0; if it is 0, then totalSectors32
@@ -182,61 +206,56 @@ struct __PACKED TBiosParmBlock {
//of the volume. This field can be 0; if it is 0, then
//totalSectors16 must be non-zero.
u32 totalSectors32;
- //Count of sectors occupied by one FAT on FAT32 volumes.
- u32 sectorsPerFat32;
- //This field is only defined for FAT32 media and does not exist on
- //FAT12 and FAT16 media.
- //Bits 0-3 -- Zero-based number of active FAT.
- // Only valid if mirroring is disabled.
- //Bits 4-6 -- Reserved.
- //Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
- // -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
- //Bits 8-15 -- Reserved.
- u16 fat32Flags;
- //FAT32 version. High byte is major revision number.
- //Low byte is minor revision number. Only 0.0 define.
- u16 fat32Version;
- //Cluster number of the first cluster of the root directory for FAT32.
- //This usually 2 but not required to be 2.
- u32 fat32RootCluster;
- //Sector number of FSINFO structure in the reserved area of the
- //FAT32 volume. Usually 1.
- u16 fat32FSInfo;
- //If non-zero, indicates the sector number in the reserved area
- //of the volume of a copy of the boot record. Usually 6.
- //No value other than 6 is recommended.
- u16 fat32BackBootBlock;
- //Reserved for future expansion. Code that formats FAT32 volumes
- //should always set all of the bytes of this field to 0.
- u8 fat32Reserved[12];
-};
-//Boot sector for a FAT16 or FAT32 volume.
-struct __PACKED TFat32BootSector {
- //X86 jmp to boot program
- u8 jmpToBootCode[3];
- //informational only - don't depend on it
- u8 oemName[8];
- //BIOS Parameter Block
- TBiosParmBlock bpb;
- //for int0x13 use value 0X80 for hard drive
- u8 driveNumber;
- //used by Windows NT - should be zero for FAT
- u8 reserved1;
- //0X29 if next three fields are valid
- u8 bootSignature;
- //usually generated by combining date and time
- u32 volumeSerialNumber;
- //should match volume label in root dir
- u8 volumeLabel[11];
- //informational only - don't depend on it
- u8 fileSystemType[8];
- //X86 boot code
- u8 bootCode[420];
- //must be 0X55
- u8 bootSectorSig0;
- //must be 0XAA
- u8 bootSectorSig1;
+ union {
+ struct __PACKED {
+ msdos_volume_info vi;
+ u8 boot_code[BOOTCODE_SIZE];
+ } oldfat;
+
+ struct __PACKED
+ {
+ //Count of sectors occupied by one FAT on FAT32 volumes.
+ u32 sectorsPerFat32; //fat32_length; /* sectors/FAT */
+
+ //This field is only defined for FAT32 media and does not exist on
+ //FAT12 and FAT16 media.
+ //Bits 0-3 -- Zero-based number of active FAT.
+ // Only valid if mirroring is disabled.
+ //Bits 4-6 -- Reserved.
+ //Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
+ // -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
+ //Bits 8-15 -- Reserved.
+ u16 fat32Flags;// flags; /* bit 8: fat mirroring, low 4: active fat */
+
+ //FAT32 version. High byte is major revision number.
+ //Low byte is minor revision number. Only 0.0 define.
+ u16 fat32Version;//version[2]; /* major, minor filesystem version */
+
+ //Cluster number of the first cluster of the root directory for FAT32.
+ //This usually 2 but not required to be 2.
+ u32 fat32RootCluster; //root_cluster; /* first cluster in root directory */
+
+ //Sector number of FSINFO structure in the reserved area of the
+ //FAT32 volume. Usually 1.
+ u16 fat32FSInfo;// info_sector; /* filesystem info sector */
+
+ //If non-zero, indicates the sector number in the reserved area
+ //of the volume of a copy of the boot record. Usually 6.
+ //No value other than 6 is recommended.
+ u16 fat32BackBootBlock; //backup_boot; /* backup boot sector */
+
+ //Reserved for future expansion. Code that formats FAT32 volumes
+ //should always set all of the bytes of this field to 0.
+ u8 fat32Reserved[12]; //reserved2[6]; /* Unused */
+
+ msdos_volume_info vi;
+
+ u8 boot_code[BOOTCODE_FAT32_SIZE];
+ } fat32;
+ };
+
+ u8 boot_sign[2];
};
#include "PACKED_END.h"
@@ -586,6 +605,7 @@ public:
bool init(EmuFat* dev, u8 part);
bool format(u32 sectors);
+ bool formatNew(u32 sectors);
// inline functions that return volume info
//The volume's cluster size in blocks.
@@ -687,6 +707,7 @@ private:
void cacheSetDirty() {cache_.cacheDirty_ |= CACHE_FOR_WRITE;}
u8 cacheZeroBlock(u32 blockNumber);
u8 cacheFlush();
+ void cacheReset();
//IO functions:
u8 readBlock(u32 block, u8* dst);
diff --git a/desmume/src/emufile.cpp b/desmume/src/emufile.cpp
index 7a05ba999..1b2206895 100644
--- a/desmume/src/emufile.cpp
+++ b/desmume/src/emufile.cpp
@@ -24,4 +24,42 @@ EMUFILE* EMUFILE::memwrap(EMUFILE* fp)
file->fread(mem->buf(),file->size());
delete file;
return mem;
+}
+
+size_t EMUFILE_MEMORY::_fread(const void *ptr, size_t bytes){
+ u32 remain = len-pos;
+ u32 todo = std::min(remain,(u32)bytes);
+ if(len==0)
+ {
+ failbit = true;
+ return 0;
+ }
+ if(todo<=4)
+ {
+ u8* src = buf()+pos;
+ u8* dst = (u8*)ptr;
+ for(int i=0;i(remain,(u32)bytes);
- memcpy((void*)ptr,buf()+pos,todo);
- pos += todo;
- if(todofname = fname;
+ strcpy(this->mode,mode);
}
public:
@@ -255,14 +251,7 @@ public:
bool is_open() { return fp != NULL; }
- virtual void truncate(s32 length)
- {
- #ifdef _MSC_VER
- _chsize(_fileno(fp),length);
- #else
- ftruncate(fileno(fp),length);
- #endif
- }
+ virtual void truncate(s32 length);
virtual int fprintf(const char *format, ...) {
va_list argptr;