libfat improvements: now actually works, and uses fat32.
This commit is contained in:
parent
cf5ba963c0
commit
b1362ccb40
|
@ -327,6 +327,9 @@ void build_ListCallback(FsEntry* fs, EListCallbackArg arg)
|
||||||
{
|
{
|
||||||
char* fname = (strlen(fs->cAlternateFileName)>0) ? fs->cAlternateFileName : fs->cFileName;
|
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)
|
if(arg == EListCallbackArg_Pop)
|
||||||
{
|
{
|
||||||
currFatFile = fatStack.top();
|
currFatFile = fatStack.top();
|
||||||
|
@ -384,15 +387,22 @@ static BOOL cflash_build_fat()
|
||||||
currPath = sFlashPath;
|
currPath = sFlashPath;
|
||||||
list_files(sFlashPath.c_str(), count_ListCallback);
|
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.
|
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)
|
//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;
|
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);
|
EmuFat fat(file);
|
||||||
EmuFatVolume vol;
|
EmuFatVolume vol;
|
||||||
u8 ok = vol.init(&fat);
|
u8 ok = vol.init(&fat);
|
||||||
vol.format(dataSectors);
|
vol.formatNew(dataSectors);
|
||||||
|
|
||||||
reconstruct(&currFatFile);
|
reconstruct(&currFatFile);
|
||||||
currFatFile.openRoot(&vol);
|
currFatFile.openRoot(&vol);
|
||||||
|
@ -772,11 +782,6 @@ static unsigned int cflash_read(unsigned int address)
|
||||||
{
|
{
|
||||||
unsigned int ret_value = 0;
|
unsigned int ret_value = 0;
|
||||||
size_t elems_read = 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)
|
switch (address)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
|
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
|
||||||
/*
|
//Copyright (C) 2009 by William Greiman
|
||||||
* Copyright (C) 2009 by William Greiman
|
|
||||||
*
|
//based on mkdosfs - utility to create FAT/MS-DOS filesystems
|
||||||
* This file is free software: you can redistribute it and/or modify
|
//Copyright (C) 1991 Linus Torvalds <torvalds@klaava.helsinki.fi>
|
||||||
* it under the terms of the GNU General Public License as published by
|
//Copyright (C) 1992-1993 Remy Card <card@masi.ibp.fr>
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
//Copyright (C) 1993-1994 David Hudson <dave@humbug.demon.co.uk>
|
||||||
* (at your option) any later version.
|
//Copyright (C) 1998 H. Peter Anvin <hpa@zytor.com>
|
||||||
*
|
//Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
||||||
* 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
|
|
||||||
* <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "emufat.h"
|
#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,
|
0x0E, 0x1F, 0xBE, 0x77, 0x7C, 0xAC, 0x22, 0xC0, 0x74, 0x0B, 0x56, 0xB4, 0x0E, 0xBB, 0x07, 0x00,
|
||||||
0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50,
|
0xCD, 0x10, 0x5E, 0xEB, 0xF0, 0x32, 0xE4, 0xCD, 0x16, 0xCD, 0x19, 0xEB, 0xFE, 0x54, 0x68, 0x69,
|
||||||
0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62,
|
0x73, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
|
||||||
0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79, 0x20, 0x61,
|
0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73,
|
||||||
0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65,
|
0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
|
||||||
0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E,
|
0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A,
|
||||||
0x2E, 0x2E, 0x20, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E, 0x2E, 0x2E, 0x20, 0x0D,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
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,
|
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;
|
delete m_pFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u8 EmuFat::cacheRawBlock(u32 blockNumber, u8 action)
|
u8 EmuFat::cacheRawBlock(u32 blockNumber, u8 action)
|
||||||
{
|
{
|
||||||
if (cache_.cacheBlockNumber_ != blockNumber) {
|
if (cache_.cacheBlockNumber_ != blockNumber) {
|
||||||
|
@ -105,6 +142,11 @@ u8 EmuFat::cacheZeroBlock(u32 blockNumber)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuFat::cacheReset()
|
||||||
|
{
|
||||||
|
reconstruct(&cache_);
|
||||||
|
}
|
||||||
|
|
||||||
u8 EmuFat::cacheFlush() {
|
u8 EmuFat::cacheFlush() {
|
||||||
if (cache_.cacheDirty_) {
|
if (cache_.cacheDirty_) {
|
||||||
if (!writeBlock(cache_.cacheBlockNumber_, cache_.cacheBuffer_.data)) {
|
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;i<bs->reservedSectorCount;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;i<bs->fatCount;i++)
|
||||||
|
for(int j=0;j<fat_length;j++,ctr++)
|
||||||
|
dev_->writeBlock(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;i<size_root_dir_in_sectors;i++)
|
||||||
|
dev_->writeBlock(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.
|
//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
|
//it would be nice if someone who understood fat better could modify the root
|
||||||
//directory setup to use reasonable code instead of magic arrays
|
//directory setup to use reasonable code instead of magic arrays
|
||||||
bool EmuFatVolume::format(u32 sectors)
|
bool EmuFatVolume::format(u32 sectors)
|
||||||
{
|
{
|
||||||
u32 volumeStartBlock = 0;
|
//u32 volumeStartBlock = 0;
|
||||||
dev_->truncate(0);
|
//dev_->truncate(0);
|
||||||
dev_->truncate(sectors*512);
|
//dev_->truncate(sectors*512);
|
||||||
if (!dev_->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_WRITE)) return false;
|
//if (!dev_->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_WRITE)) return false;
|
||||||
memset(&dev_->cache_.cacheBuffer_,0,sizeof(dev_->cache_.cacheBuffer_));
|
//memset(&dev_->cache_.cacheBuffer_,0,sizeof(dev_->cache_.cacheBuffer_));
|
||||||
TFat32BootSector* bs = &dev_->cache_.cacheBuffer_.fbs;
|
//TFat32BootSector* bs = &dev_->cache_.cacheBuffer_.fbs;
|
||||||
TBiosParmBlock* bpb = &bs->bpb;
|
//TBiosParmBlock* bpb = &bs->bpb;
|
||||||
|
|
||||||
bs->jmpToBootCode[0] = 0xEB;
|
//bs->jmpToBootCode[0] = 0xEB;
|
||||||
bs->jmpToBootCode[1] = 0x3C;
|
//bs->jmpToBootCode[1] = 0x3C;
|
||||||
bs->jmpToBootCode[2] = 0x90;
|
//bs->jmpToBootCode[2] = 0x90;
|
||||||
memcpy(bs->oemName,"mkdosfs",8);
|
//memcpy(bs->oemName,"mkdosfs",8);
|
||||||
bs->driveNumber = 0;
|
//bs->driveNumber = 0;
|
||||||
bs->reserved1 = 0;
|
//bs->reserved1 = 0;
|
||||||
bs->bootSignature = 0x29;
|
//bs->bootSignature = 0x29;
|
||||||
bs->volumeSerialNumber = 0;
|
//bs->volumeSerialNumber = 0;
|
||||||
memcpy(bs->volumeLabel," ",11);
|
//memcpy(bs->volumeLabel," ",11);
|
||||||
memcpy(bs->fileSystemType,"FAT16 ",8);
|
//memcpy(bs->fileSystemType,"FAT16 ",8);
|
||||||
memcpy(bs->bootCode,mkdosfs_bootcode,420);
|
//memcpy(bs->bootCode,mkdosfs_bootcode,420);
|
||||||
bs->bootSectorSig0 = 0x55;
|
//bs->bootSectorSig0 = 0x55;
|
||||||
bs->bootSectorSig1 = 0xAA;
|
//bs->bootSectorSig1 = 0xAA;
|
||||||
|
|
||||||
bpb->bytesPerSector = 512;
|
//bpb->bytesPerSector = 512;
|
||||||
bpb->sectorsPerCluster = 4;
|
//bpb->sectorsPerCluster = 4;
|
||||||
bpb->reservedSectorCount = 1;
|
//bpb->reservedSectorCount = 1;
|
||||||
bpb->fatCount = 2;
|
//bpb->fatCount = 2;
|
||||||
bpb->rootDirEntryCount = 512;
|
//bpb->rootDirEntryCount = 512;
|
||||||
bpb->totalSectors16 = 0;
|
//bpb->totalSectors16 = 0;
|
||||||
bpb->mediaType = 0xF8;
|
//bpb->mediaType = 0xF8;
|
||||||
bpb->sectorsPerFat16 = 32;
|
//bpb->sectorsPerFat16 = 32;
|
||||||
bpb->sectorsPerTrack = 32;
|
//bpb->sectorsPerTrack = 32;
|
||||||
bpb->headCount = 64;
|
//bpb->headCount = 64;
|
||||||
bpb->hiddenSectors = 0;
|
//bpb->hiddenSectors = 0;
|
||||||
bpb->totalSectors32 = sectors;
|
//bpb->totalSectors32 = sectors;
|
||||||
bpb->fat32Flags = 0xbe0d;
|
//bpb->fat32Flags = 0xbe0d;
|
||||||
bpb->fat32Version = 0x20Fd;
|
//bpb->fat32Version = 0x20Fd;
|
||||||
bpb->fat32RootCluster = 0x20202020;
|
//bpb->fat32RootCluster = 0x20202020;
|
||||||
bpb->fat32FSInfo = 0x2020;
|
//bpb->fat32FSInfo = 0x2020;
|
||||||
bpb->fat32BackBootBlock = 0x2020;
|
//bpb->fat32BackBootBlock = 0x2020;
|
||||||
|
|
||||||
if(!dev_->cacheFlush())
|
//if(!dev_->cacheFlush())
|
||||||
return false;
|
// 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] =
|
//static const u8 rootEntry[8] =
|
||||||
{
|
//{
|
||||||
0xF8, 0xFF, 0xFF, 0xFF,
|
// 0xF8, 0xFF, 0xFF, 0xFF,
|
||||||
} ;
|
//} ;
|
||||||
|
|
||||||
memcpy(dev_->cache_.cacheBuffer_.data,rootEntry,4);
|
//memcpy(dev_->cache_.cacheBuffer_.data,rootEntry,4);
|
||||||
|
|
||||||
if(!dev_->cacheFlush())
|
//if(!dev_->cacheFlush())
|
||||||
return false;
|
// 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())
|
//if(!dev_->cacheFlush())
|
||||||
return false;
|
// return false;
|
||||||
|
|
||||||
return init(dev_,0);
|
//return init(dev_,0);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuFatVolume::init(EmuFat* dev, u8 part) {
|
bool EmuFatVolume::init(EmuFat* dev, u8 part) {
|
||||||
|
@ -253,16 +658,16 @@ bool EmuFatVolume::init(EmuFat* dev, u8 part) {
|
||||||
volumeStartBlock = p->firstSector;
|
volumeStartBlock = p->firstSector;
|
||||||
}
|
}
|
||||||
if (!dev->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_READ)) return false;
|
if (!dev->cacheRawBlock(volumeStartBlock, EmuFat::CACHE_FOR_READ)) return false;
|
||||||
TBiosParmBlock* bpb = &dev->cache_.cacheBuffer_.fbs.bpb;
|
TFat32BootSector* bs = &dev->cache_.cacheBuffer_.fbs;
|
||||||
if (bpb->bytesPerSector != 512 ||
|
if (bs->bytesPerSector != 512 ||
|
||||||
bpb->fatCount == 0 ||
|
bs->fatCount == 0 ||
|
||||||
bpb->reservedSectorCount == 0 ||
|
bs->reservedSectorCount == 0 ||
|
||||||
bpb->sectorsPerCluster == 0) {
|
bs->sectorsPerCluster == 0) {
|
||||||
// not valid FAT volume
|
// not valid FAT volume
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fatCount_ = bpb->fatCount;
|
fatCount_ = bs->fatCount;
|
||||||
blocksPerCluster_ = bpb->sectorsPerCluster;
|
blocksPerCluster_ = bs->sectorsPerCluster;
|
||||||
|
|
||||||
// determine shift that is same as multiply by blocksPerCluster_
|
// determine shift that is same as multiply by blocksPerCluster_
|
||||||
clusterSizeShift_ = 0;
|
clusterSizeShift_ = 0;
|
||||||
|
@ -270,23 +675,23 @@ bool EmuFatVolume::init(EmuFat* dev, u8 part) {
|
||||||
// error if not power of 2
|
// error if not power of 2
|
||||||
if (clusterSizeShift_++ > 7) return false;
|
if (clusterSizeShift_++ > 7) return false;
|
||||||
}
|
}
|
||||||
blocksPerFat_ = bpb->sectorsPerFat16 ?
|
blocksPerFat_ = bs->sectorsPerFat16 ?
|
||||||
bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
|
bs->sectorsPerFat16 : bs->fat32.sectorsPerFat32;
|
||||||
|
|
||||||
fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
|
fatStartBlock_ = volumeStartBlock + bs->reservedSectorCount;
|
||||||
|
|
||||||
// count for FAT16 zero for FAT32
|
// count for FAT16 zero for FAT32
|
||||||
rootDirEntryCount_ = bpb->rootDirEntryCount;
|
rootDirEntryCount_ = bs->rootDirEntryCount;
|
||||||
|
|
||||||
// directory start for FAT16 dataStart for FAT32
|
// directory start for FAT16 dataStart for FAT32
|
||||||
rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
|
rootDirStart_ = fatStartBlock_ + bs->fatCount * blocksPerFat_;
|
||||||
|
|
||||||
// data start for FAT16 and FAT32
|
// 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
|
// total blocks for FAT16 or FAT32
|
||||||
u32 totalBlocks = bpb->totalSectors16 ?
|
u32 totalBlocks = bs->totalSectors16 ?
|
||||||
bpb->totalSectors16 : bpb->totalSectors32;
|
bs->totalSectors16 : bs->totalSectors32;
|
||||||
// total data blocks
|
// total data blocks
|
||||||
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
||||||
|
|
||||||
|
@ -299,7 +704,7 @@ bool EmuFatVolume::init(EmuFat* dev, u8 part) {
|
||||||
} else if (clusterCount_ < 65525) {
|
} else if (clusterCount_ < 65525) {
|
||||||
fatType_ = 16;
|
fatType_ = 16;
|
||||||
} else {
|
} else {
|
||||||
rootDirStart_ = bpb->fat32RootCluster;
|
rootDirStart_ = bs->fat32.fat32RootCluster;
|
||||||
fatType_ = 32;
|
fatType_ = 32;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
|
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
|
||||||
/*
|
//Copyright (C) 2009 by William Greiman
|
||||||
* Copyright (C) 2009 by William Greiman
|
|
||||||
*
|
//based on mkdosfs - utility to create FAT/MS-DOS filesystems
|
||||||
* This file is free software: you can redistribute it and/or modify
|
//Copyright (C) 1991 Linus Torvalds <torvalds@klaava.helsinki.fi>
|
||||||
* it under the terms of the GNU General Public License as published by
|
//Copyright (C) 1992-1993 Remy Card <card@masi.ibp.fr>
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
//Copyright (C) 1993-1994 David Hudson <dave@humbug.demon.co.uk>
|
||||||
* (at your option) any later version.
|
//Copyright (C) 1998 H. Peter Anvin <hpa@zytor.com>
|
||||||
*
|
//Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
||||||
* 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
|
|
||||||
* <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef EMUFAT_H
|
#ifndef EMUFAT_H
|
||||||
#define EMUFAT_H
|
#define EMUFAT_H
|
||||||
|
@ -25,6 +32,10 @@
|
||||||
#include "emufile.h"
|
#include "emufile.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define BOOTCODE_SIZE 448
|
||||||
|
#define BOOTCODE_FAT32_SIZE 420
|
||||||
|
|
||||||
|
|
||||||
// use the gnu style oflag in open()
|
// use the gnu style oflag in open()
|
||||||
/** open() oflag for reading */
|
/** open() oflag for reading */
|
||||||
static const u8 EO_READ = 0X01;
|
static const u8 EO_READ = 0X01;
|
||||||
|
@ -129,16 +140,29 @@ struct __PACKED TMasterBootRecord {
|
||||||
u8 mbrSig1;
|
u8 mbrSig1;
|
||||||
};
|
};
|
||||||
|
|
||||||
//BIOS parameter block
|
struct __PACKED msdos_volume_info {
|
||||||
//The BIOS parameter block describes the physical layout of a FAT volume.
|
u8 drive_number; /* BIOS drive number */
|
||||||
struct __PACKED TBiosParmBlock {
|
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
|
//Count of bytes per sector. This value may take on only the
|
||||||
//following values: 512, 1024, 2048 or 4096
|
//following values: 512, 1024, 2048 or 4096
|
||||||
u16 bytesPerSector;
|
u16 bytesPerSector;
|
||||||
//Number of sectors per allocation unit. This value must be a
|
//Number of sectors per allocation unit. This value must be a
|
||||||
//power of 2 that is greater than 0. The legal values are
|
//power of 2 that is greater than 0. The legal values are
|
||||||
//1, 2, 4, 8, 16, 32, 64, and 128.
|
//1, 2, 4, 8, 16, 32, 64, and 128.
|
||||||
u8 sectorsPerCluster;
|
u8 sectorsPerCluster; //cluster_size
|
||||||
//Number of sectors before the first FAT.
|
//Number of sectors before the first FAT.
|
||||||
//This value must not be zero.
|
//This value must not be zero.
|
||||||
u16 reservedSectorCount;
|
u16 reservedSectorCount;
|
||||||
|
@ -151,7 +175,7 @@ struct __PACKED TBiosParmBlock {
|
||||||
//value should always specify a count that when multiplied by 32
|
//value should always specify a count that when multiplied by 32
|
||||||
//results in a multiple of bytesPerSector. FAT16 volumes should
|
//results in a multiple of bytesPerSector. FAT16 volumes should
|
||||||
//use the value 512.
|
//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 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
|
//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
|
//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
|
//of the volume. This field can be 0; if it is 0, then
|
||||||
//totalSectors16 must be non-zero.
|
//totalSectors16 must be non-zero.
|
||||||
u32 totalSectors32;
|
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.
|
union {
|
||||||
struct __PACKED TFat32BootSector {
|
struct __PACKED {
|
||||||
//X86 jmp to boot program
|
msdos_volume_info vi;
|
||||||
u8 jmpToBootCode[3];
|
u8 boot_code[BOOTCODE_SIZE];
|
||||||
//informational only - don't depend on it
|
} oldfat;
|
||||||
u8 oemName[8];
|
|
||||||
//BIOS Parameter Block
|
struct __PACKED
|
||||||
TBiosParmBlock bpb;
|
{
|
||||||
//for int0x13 use value 0X80 for hard drive
|
//Count of sectors occupied by one FAT on FAT32 volumes.
|
||||||
u8 driveNumber;
|
u32 sectorsPerFat32; //fat32_length; /* sectors/FAT */
|
||||||
//used by Windows NT - should be zero for FAT
|
|
||||||
u8 reserved1;
|
//This field is only defined for FAT32 media and does not exist on
|
||||||
//0X29 if next three fields are valid
|
//FAT12 and FAT16 media.
|
||||||
u8 bootSignature;
|
//Bits 0-3 -- Zero-based number of active FAT.
|
||||||
//usually generated by combining date and time
|
// Only valid if mirroring is disabled.
|
||||||
u32 volumeSerialNumber;
|
//Bits 4-6 -- Reserved.
|
||||||
//should match volume label in root dir
|
//Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||||
u8 volumeLabel[11];
|
// -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
|
||||||
//informational only - don't depend on it
|
//Bits 8-15 -- Reserved.
|
||||||
u8 fileSystemType[8];
|
u16 fat32Flags;// flags; /* bit 8: fat mirroring, low 4: active fat */
|
||||||
//X86 boot code
|
|
||||||
u8 bootCode[420];
|
//FAT32 version. High byte is major revision number.
|
||||||
//must be 0X55
|
//Low byte is minor revision number. Only 0.0 define.
|
||||||
u8 bootSectorSig0;
|
u16 fat32Version;//version[2]; /* major, minor filesystem version */
|
||||||
//must be 0XAA
|
|
||||||
u8 bootSectorSig1;
|
//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"
|
#include "PACKED_END.h"
|
||||||
|
@ -586,6 +605,7 @@ public:
|
||||||
bool init(EmuFat* dev, u8 part);
|
bool init(EmuFat* dev, u8 part);
|
||||||
|
|
||||||
bool format(u32 sectors);
|
bool format(u32 sectors);
|
||||||
|
bool formatNew(u32 sectors);
|
||||||
|
|
||||||
// inline functions that return volume info
|
// inline functions that return volume info
|
||||||
//The volume's cluster size in blocks.
|
//The volume's cluster size in blocks.
|
||||||
|
@ -687,6 +707,7 @@ private:
|
||||||
void cacheSetDirty() {cache_.cacheDirty_ |= CACHE_FOR_WRITE;}
|
void cacheSetDirty() {cache_.cacheDirty_ |= CACHE_FOR_WRITE;}
|
||||||
u8 cacheZeroBlock(u32 blockNumber);
|
u8 cacheZeroBlock(u32 blockNumber);
|
||||||
u8 cacheFlush();
|
u8 cacheFlush();
|
||||||
|
void cacheReset();
|
||||||
|
|
||||||
//IO functions:
|
//IO functions:
|
||||||
u8 readBlock(u32 block, u8* dst);
|
u8 readBlock(u32 block, u8* dst);
|
||||||
|
|
|
@ -24,4 +24,42 @@ EMUFILE* EMUFILE::memwrap(EMUFILE* fp)
|
||||||
file->fread(mem->buf(),file->size());
|
file->fread(mem->buf(),file->size());
|
||||||
delete file;
|
delete file;
|
||||||
return mem;
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EMUFILE_MEMORY::_fread(const void *ptr, size_t bytes){
|
||||||
|
u32 remain = len-pos;
|
||||||
|
u32 todo = std::min<u32>(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<todo;i++)
|
||||||
|
*dst++ = *src++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy((void*)ptr,buf()+pos,todo);
|
||||||
|
}
|
||||||
|
pos += todo;
|
||||||
|
if(todo<bytes)
|
||||||
|
failbit = true;
|
||||||
|
return todo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EMUFILE_FILE::truncate(s32 length)
|
||||||
|
{
|
||||||
|
fflush(fp);
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
_chsize(_fileno(fp),length);
|
||||||
|
#else
|
||||||
|
ftruncate(fileno(fp),length);
|
||||||
|
#endif
|
||||||
|
fclose(fp);
|
||||||
|
fp = NULL;
|
||||||
|
open(fname.c_str(),mode);
|
||||||
}
|
}
|
|
@ -176,15 +176,7 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t _fread(const void *ptr, size_t bytes){
|
virtual size_t _fread(const void *ptr, size_t bytes);
|
||||||
u32 remain = len-pos;
|
|
||||||
u32 todo = std::min<u32>(remain,(u32)bytes);
|
|
||||||
memcpy((void*)ptr,buf()+pos,todo);
|
|
||||||
pos += todo;
|
|
||||||
if(todo<bytes)
|
|
||||||
failbit = true;
|
|
||||||
return todo;
|
|
||||||
}
|
|
||||||
|
|
||||||
//removing these return values for now so we can find any code that might be using them and make sure
|
//removing these return values for now so we can find any code that might be using them and make sure
|
||||||
//they handle the return values correctly
|
//they handle the return values correctly
|
||||||
|
@ -230,6 +222,8 @@ public:
|
||||||
class EMUFILE_FILE : public EMUFILE {
|
class EMUFILE_FILE : public EMUFILE {
|
||||||
protected:
|
protected:
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
|
std::string fname;
|
||||||
|
char mode[16];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void open(const char* fname, const char* mode)
|
void open(const char* fname, const char* mode)
|
||||||
|
@ -237,6 +231,8 @@ private:
|
||||||
fp = fopen(fname,mode);
|
fp = fopen(fname,mode);
|
||||||
if(!fp)
|
if(!fp)
|
||||||
failbit = true;
|
failbit = true;
|
||||||
|
this->fname = fname;
|
||||||
|
strcpy(this->mode,mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -255,14 +251,7 @@ public:
|
||||||
|
|
||||||
bool is_open() { return fp != NULL; }
|
bool is_open() { return fp != NULL; }
|
||||||
|
|
||||||
virtual void truncate(s32 length)
|
virtual void truncate(s32 length);
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
_chsize(_fileno(fp),length);
|
|
||||||
#else
|
|
||||||
ftruncate(fileno(fp),length);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int fprintf(const char *format, ...) {
|
virtual int fprintf(const char *format, ...) {
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
|
Loading…
Reference in New Issue