📄 fat.c
字号:
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2002 by Linus Nielsen Feltzing
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "fat.h"
#define SECTOR_SIZE 512
#define MAX_BLOCK_SIZE 2048
#define BYTES2INT16(array,pos) \
(array[pos] | (array[pos+1] << 8 ))
#define BYTES2INT32(array,pos) \
((long)array[pos] | ((long)array[pos+1] << 8 ) | \
((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
/* BPB offsets; generic */
#define BS_JMPBOOT 0
#define BS_OEMNAME 3
#define BPB_BYTSPERSEC 11
#define BPB_SECPERCLUS 13
#define BPB_RSVDSECCNT 14
#define BPB_NUMFATS 16
#define BPB_ROOTENTCNT 17
#define BPB_TOTSEC16 19
#define BPB_MEDIA 21
#define BPB_FATSZ16 22
#define BPB_SECPERTRK 24
#define BPB_NUMHEADS 26
#define BPB_HIDDSEC 28
#define BPB_TOTSEC32 32
/* fat32 */
#define BPB_FATSZ32 36
#define BPB_EXTFLAGS 40
#define BPB_FSVER 42
#define BPB_ROOTCLUS 44
#define BPB_FSINFO 48
#define BPB_BKBOOTSEC 50
#define BS_32_DRVNUM 64
#define BS_32_BOOTSIG 66
#define BS_32_VOLID 67
#define BS_32_VOLLAB 71
#define BS_32_FILSYSTYPE 82
#define BPB_LAST_WORD 510
/* attributes */
#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
#define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \
FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \
FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE )
/* NTRES flags */
#define FAT_NTRES_LC_NAME 0x08
#define FAT_NTRES_LC_EXT 0x10
#define FATDIR_NAME 0
#define FATDIR_ATTR 11
#define FATDIR_NTRES 12
#define FATDIR_CRTTIMETENTH 13
#define FATDIR_CRTTIME 14
#define FATDIR_CRTDATE 16
#define FATDIR_LSTACCDATE 18
#define FATDIR_FSTCLUSHI 20
#define FATDIR_WRTTIME 22
#define FATDIR_WRTDATE 24
#define FATDIR_FSTCLUSLO 26
#define FATDIR_FILESIZE 28
#define FATLONG_ORDER 0
#define FATLONG_TYPE 12
#define FATLONG_CHKSUM 13
#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
#define DIR_ENTRY_SIZE 32
#define NAME_BYTES_PER_ENTRY 13
#define FAT_BAD_MARK 0x0ffffff7
#define FAT_EOF_MARK 0x0ffffff8
struct fsinfo {
unsigned long freecount; /* last known free cluster count */
unsigned long nextfree; /* first cluster to start looking for free
clusters, or 0xffffffff for no hint */
};
/* fsinfo offsets */
#define FSINFO_FREECOUNT 488
#define FSINFO_NEXTFREE 492
#define FAT_CACHE_SIZE 0x20
#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
struct fat_cache_entry
{
long secnum;
bool inuse;
bool dirty;
};
static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
struct bpb
{
int bpb_bytspersec; /* Bytes per sector, typically 512 */
unsigned int bpb_secperclus; /* Sectors per cluster */
int bpb_rsvdseccnt; /* Number of reserved sectors */
int bpb_numfats; /* Number of FAT structures, typically 2 */
int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */
int bpb_media; /* Media type (typically 0xf0 or 0xf8) */
int bpb_fatsz16; /* Number of used sectors per FAT structure */
unsigned long bpb_totsec32; /* Number of sectors on the volume
(new 32-bit) */
unsigned int last_word; /* 0xAA55 */
/**** FAT32 specific *****/
long bpb_fatsz32;
long bpb_rootclus;
long bpb_fsinfo;
/* variables for internal use */
unsigned long fatsize;
unsigned long totalsectors;
unsigned long rootdirsector;
unsigned long firstdatasector;
unsigned long startsector;
unsigned long dataclusters;
struct fsinfo fsinfo;
#ifdef HAVE_FAT16SUPPORT
int bpb_rootentcnt; /* Number of dir entries in the root */
/* internals for FAT16 support */
bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
unsigned int rootdiroffset; /* sector offset of root dir relative to start
* of first pseudo cluster */
#endif /* #ifdef HAVE_FAT16SUPPORT */
#ifdef HAVE_MULTIVOLUME
int drive; /* on which physical device is this located */
bool mounted; /* flag if this volume is mounted */
#endif
};
static const unsigned char utf8comp[6] =
{
0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
};
static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
struct mutex
{
bool locked;
};
static struct mutex cache_mutex;
/****************************************************************************
* Simple mutex functions
****************************************************************************/
void mutex_init(struct mutex *m)
{
m->locked = false;
}
void mutex_lock(struct mutex *m)
{
/* Wait until the lock is open... */
while(m->locked)
{
}
// sleep_thread();
// wake_up_thread();
/* ...and lock it */
m->locked = true;
}
void mutex_unlock(struct mutex *m)
{
m->locked = false;
}
static long cluster2sec( long cluster )
{
struct bpb* fat_bpb = &fat_bpbs[0];
long zerocluster;
// NATE: This is to deal with when fat_mount sets the root cluster to negative
if (cluster < 0)
zerocluster = 0;
else
zerocluster = 2;
if (cluster > (long)(fat_bpb->dataclusters + 1))
{
DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster);
return -1;
}
return (cluster - zerocluster) * fat_bpb->bpb_secperclus
+ fat_bpb->firstdatasector;
}
void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
{
#ifndef HAVE_MULTIVOLUME
const int volume = 0;
#endif
struct bpb* fat_bpb = &fat_bpbs[volume];
if (size)
*size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
if (free)
*free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
}
void fat_init(void)
{
unsigned int i;
mutex_init(&cache_mutex);
/* mark the FAT cache as unused */
for(i = 0;i < FAT_CACHE_SIZE;i++)
{
fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
fat_cache[i].inuse = false;
fat_cache[i].dirty = false;
#ifdef HAVE_MULTIVOLUME
fat_cache[i].fat_vol = NULL;
#endif
}
#ifdef HAVE_MULTIVOLUME
/* mark the possible volumes as not mounted */
for (i=0; i<NUM_VOLUMES;i++)
{
fat_bpbs[i].mounted = false;
}
#endif
}
static void flush_fat_sector(struct fat_cache_entry *fce,
unsigned char *sectorbuf)
{
int rc;
long secnum;
/* With multivolume, use only the FAT info from the cached sector! */
#ifdef HAVE_MULTIVOLUME
secnum = fce->secnum + fce->fat_vol->startsector;
#else
secnum = fce->secnum + fat_bpbs[0].startsector;
#endif
/* Write to the first FAT */
rc = rb_fat_write_sectors(IF_MV2(fce->fat_vol->drive,)
secnum, 1,
(unsigned short*)sectorbuf);
if(rc < 0)
{
panicf("flush_fat_sector() - Could not write sector %ld"
" (error %d)\n",
secnum, rc);
}
#ifdef HAVE_MULTIVOLUME
if(fce->fat_vol->bpb_numfats > 1)
#else
if(fat_bpbs[0].bpb_numfats > 1)
#endif
{
/* Write to the second FAT */
#ifdef HAVE_MULTIVOLUME
secnum += fce->fat_vol->fatsize;
#else
secnum += fat_bpbs[0].fatsize;
#endif
rc = rb_fat_write_sectors(IF_MV2(fce->fat_vol->drive,)
secnum, 1, (unsigned short*)sectorbuf);
if(rc < 0)
{
panicf("flush_fat_sector() - Could not write sector %ld"
" (error %d)\n",
secnum, rc);
}
}
fce->dirty = false;
}
static int update_fsinfo( void )
{
struct bpb* fat_bpb = &fat_bpbs[0];
unsigned char fsinfo[SECTOR_SIZE];
unsigned long* intptr;
int rc;
/* update fsinfo */
rc = rb_fat_read_sectors( fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,(short*)fsinfo);
if (rc < 0)
{
DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
return rc * 10 - 1;
}
intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
*intptr = (fat_bpb->fsinfo.freecount);
intptr = (long*)&(fsinfo[FSINFO_NEXTFREE]);
*intptr = (fat_bpb->fsinfo.nextfree);
rc = rb_fat_write_sectors( fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,(short*)fsinfo);
// rc = writeLogicalSector( fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1, (short*) fsinfo);
if (rc < 0)
{
DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
return rc * 10 - 2;
}
return 0;
}
static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
{
int i;
int rc;
unsigned char *sec;
LDEBUGF("flush_fat()\n");
mutex_lock(&cache_mutex);
for(i = 0;i < FAT_CACHE_SIZE;i++)
{
struct fat_cache_entry *fce = &fat_cache[i];
if(fce->inuse
#ifdef HAVE_MULTIVOLUME
&& fce->fat_vol == fat_bpb
#endif
&& fce->dirty)
{
sec = fat_cache_sectors[i];
flush_fat_sector(fce, sec);
}
}
mutex_unlock(&cache_mutex);
rc = update_fsinfo(IF_MV(fat_bpb));
if (rc < 0)
return rc * 10 - 3;
return 0;
}
//static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
// long fatsector, bool dirty)
unsigned char* cache_fat_sector(IF_MV2(struct bpb* fat_bpb,)
long fatsector, bool dirty)
{
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
int cache_index = secnum & FAT_CACHE_MASK;
struct fat_cache_entry *fce = &fat_cache[cache_index];
unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
int rc;
mutex_lock(&cache_mutex); /* make changes atomic */
/* Delete the cache entry if it isn't the sector we want */
if(fce->inuse && (fce->secnum != secnum
#ifdef HAVE_MULTIVOLUME
|| fce->fat_vol != fat_bpb
#endif
))
{
/* Write back if it is dirty */
if(fce->dirty)
{
flush_fat_sector(fce, sectorbuf);
}
fce->inuse = false;
}
/* Load the sector if it is not cached */
if(!fce->inuse)
{
rc = rb_fat_read_sectors(IF_MV2(fat_bpb->drive,)
secnum + fat_bpb->startsector,1,
(unsigned short*)sectorbuf);
if(rc < 0)
{
DEBUGF( "cache_fat_sector() - Could not read sector %ld"
" (error %d)\n", secnum, rc);
mutex_unlock(&cache_mutex);
return NULL;
}
fce->inuse = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -