📄 fat.c
字号:
}
utf8 = utf16LEdecode(ptr + index + 1, utf8, 5);
utf8 = utf16LEdecode(ptr + index + 14, utf8, 6);
utf8 = utf16LEdecode(ptr + index + 28, utf8, 2);
}
*utf8 = 0;
}
done = true;
sectoridx = 0;
i++;
break;
}
}
}
/* save this sector, for longname use */
if ( sectoridx )
memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE );
else
memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
sectoridx += SECTOR_SIZE;
}
return 0;
}
static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry)
{
#ifdef HAVE_FAT16SUPPORT
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
if (fat_bpb->is_fat16)
{
int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
unsigned short* sec;
sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
if (!sec)
{
DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
return -1;
}
return letoh16(sec[offset]);
}
else
#endif /* #ifdef HAVE_FAT16SUPPORT */
{
long sector = entry / CLUSTERS_PER_FAT_SECTOR;
int offset = entry % CLUSTERS_PER_FAT_SECTOR;
unsigned long* sec;
sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, false);
if (!sec)
{
DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector);
return -1;
}
return letoh32(sec[offset]) & 0x0fffffff;
}
}
static long get_next_cluster(IF_MV2(struct bpb* fat_bpb,) long cluster)
{
long next_cluster;
long eof_mark = FAT_EOF_MARK;
#ifdef HAVE_FAT16SUPPORT
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
if (fat_bpb->is_fat16)
{
eof_mark &= 0xFFFF; /* only 16 bit */
if (cluster < 0) /* FAT16 root dir */
return cluster + 1; /* don't use the FAT */
}
#endif
next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
/* is this last cluster in chain? */
if ( next_cluster >= eof_mark )
return 0;
else
return next_cluster;
}
static unsigned long find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned long startcluster)
{
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
unsigned long sector;
unsigned long offset;
unsigned long i;
#ifdef HAVE_FAT16SUPPORT
if (fat_bpb->is_fat16)
{
sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
for (i = 0; i<fat_bpb->fatsize; i++) {
unsigned int j;
unsigned int nr = (i + sector) % fat_bpb->fatsize;
unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
if ( !fat )
break;
for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
if (letoh16(fat[k]) == 0x0000) {
unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
/* Ignore the reserved clusters 0 & 1, and also
cluster numbers out of bounds */
if ( c < 2 || c > fat_bpb->dataclusters+1 )
continue;
LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
fat_bpb->fsinfo.nextfree = c;
return c;
}
}
offset = 0;
}
}
else
#endif /* #ifdef HAVE_FAT16SUPPORT */
{
sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
for (i = 0; i<fat_bpb->fatsize; i++) {
unsigned int j;
unsigned long nr = (i + sector) % fat_bpb->fatsize;
unsigned long* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr, false);
if ( !fat )
break;
for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
if (!(letoh32(fat[k]) & 0x0fffffff)) {
unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
/* Ignore the reserved clusters 0 & 1, and also
cluster numbers out of bounds */
if ( c < 2 || c > fat_bpb->dataclusters+1 )
continue;
LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
fat_bpb->fsinfo.nextfree = c;
return c;
}
}
offset = 0;
}
}
LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster);
return 0; /* 0 is an illegal cluster number */
}
static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,)
unsigned long entry,
unsigned long val)
{
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
#ifdef HAVE_FAT16SUPPORT
if (fat_bpb->is_fat16)
{
int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
unsigned short* sec;
val &= 0xFFFF;
LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
if (entry==val)
panicf("Creating FAT loop: %lx,%lx\n",entry,val);
if ( entry < 2 )
panicf("Updating reserved FAT entry %ld.\n",entry);
sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
if (!sec)
{
DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector);
return -1;
}
if ( val ) {
if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
fat_bpb->fsinfo.freecount--;
}
else {
if (letoh16(sec[offset]))
fat_bpb->fsinfo.freecount++;
}
LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
sec[offset] = htole16(val);
}
else
#endif /* #ifdef HAVE_FAT16SUPPORT */
{
long sector = entry / CLUSTERS_PER_FAT_SECTOR;
int offset = entry % CLUSTERS_PER_FAT_SECTOR;
unsigned long* sec;
LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val);
if (entry==val)
panicf("Creating FAT loop: %lx,%lx\n",entry,val);
if ( entry < 2 )
panicf("Updating reserved FAT entry %ld.\n",entry);
sec = cache_fat_sector(IF_MV2(fat_bpb,) sector, true);
if (!sec)
{
DEBUGF( "update_fat_entry() - Could not cache sector %ld\n", sector);
return -1;
}
if ( val ) {
if (!(letoh32(sec[offset]) & 0x0fffffff) &&
fat_bpb->fsinfo.freecount > 0)
fat_bpb->fsinfo.freecount--;
}
else {
if (letoh32(sec[offset]) & 0x0fffffff)
fat_bpb->fsinfo.freecount++;
}
LDEBUGF("update_fat_entry: %ld free clusters\n", fat_bpb->fsinfo.freecount);
/* don't change top 4 bits */
sec[offset] &= htole32(0xf0000000);
sec[offset] |= htole32(val & 0x0fffffff);
}
return 0;
}
static long next_write_cluster(struct fat_file* file,
long oldcluster,
long* newsector)
{
#ifdef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[file->volume];
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
long cluster = 0;
long sector;
LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
if (oldcluster)
cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
if (!cluster) {
if (oldcluster > 0)
cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
else if (oldcluster == 0)
cluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
#ifdef HAVE_FAT16SUPPORT
else /* negative, pseudo-cluster of the root dir */
return 0; /* impossible to append something to the root */
#endif
if (cluster) {
if (oldcluster)
update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
else
file->firstcluster = cluster;
update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
}
else {
#ifdef TEST_FAT
if (fat_bpb->fsinfo.freecount>0)
panicf("There is free space, but find_free_cluster() "
"didn't find it!\n");
#endif
DEBUGF("next_write_cluster(): Disk full!\n");
return 0;
}
}
sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
if (sector<0)
return 0;
*newsector = sector;
return cluster;
}
static int transfer(IF_MV2(struct bpb* fat_bpb,)
unsigned long start, long count, char* buf, bool write )
{
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
int rc;
LDEBUGF("transfer(s=%lx, c=%lx, %s)\n",
start+ fat_bpb->startsector, count, write?"write":"read");
if (write) {
unsigned long firstallowed;
#ifdef HAVE_FAT16SUPPORT
if (fat_bpb->is_fat16)
firstallowed = fat_bpb->rootdirsector;
else
#endif
firstallowed = fat_bpb->firstdatasector;
if (start < firstallowed)
panicf("Write %ld before data\n", firstallowed - start);
if (start + count > fat_bpb->totalsectors)
panicf("Write %ld after data\n",
start + count - fat_bpb->totalsectors);
rc = rb_fat_write_sectors(IF_MV2(fat_bpb->drive,)
start + fat_bpb->startsector, count, (unsigned short*)buf);
}
else
rc = rb_fat_read_sectors(IF_MV2(fat_bpb->drive,)
start + fat_bpb->startsector, count, (unsigned short*)buf);
if (rc < 0) {
DEBUGF( "transfer() - Couldn't %s sector %lx"
" (error code %d)\n",
write ? "write":"read", start, rc);
return rc;
}
return 0;
}
long fat_readwrite( struct fat_file *file, long sectorcount,
void* buf, bool write )
{
#ifdef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[file->volume];
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
long cluster = file->lastcluster;
long sector = file->lastsector;
long clusternum = file->clusternum;
long numsec = file->sectornum;
bool eof = file->eof;
long first=0, last=0;
long i;
int rc;
LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n",
file->firstcluster,sectorcount,(long)buf,write?"write":"read");
LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
sector,numsec, eof?1:0);
if ( eof && !write)
return 0;
/* find sequential sectors and write them all at once */
for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
numsec++;
if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
long oldcluster = cluster;
if (write)
cluster = next_write_cluster(file, cluster, §or);
else {
cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
}
clusternum++;
numsec=1;
if (!cluster) {
eof = true;
if ( write ) {
/* remember last cluster, in case
we want to append to the file */
cluster = oldcluster;
clusternum--;
i = -1; /* Error code */
break;
}
}
else
eof = false;
}
else {
if (sector)
sector++;
else {
/* look up first sector of file */
sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
numsec=1;
#ifdef HAVE_FAT16SUPPORT
if (file->firstcluster < 0)
{ /* FAT16 root dir */
sector += fat_bpb->rootdiroffset;
numsec += fat_bpb->rootdiroffset;
}
#endif
}
}
if (!first)
first = sector;
if ( ((sector != first) && (sector != last+1)) || /* not sequential */
(last-first+1 == 256) ) { /* max 256 sectors per ata request */
long count = last - first + 1;
rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
if (rc < 0)
return rc * 10 - 1;
buf = (char *)buf + count * SECTOR_SIZE;
first = sector;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -