📄 fat.c
字号:
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: fat.c,v 1.84 2004/01/26 10:14:46 linusnielsen Exp $ * * 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 <math.h>#include <stdlib.h>#include <ctype.h>#include <stdbool.h>#include "fat.h"#include "ata.h"#include "debug.h"#include "panic.h"#include "system.h"#include "timefuncs.h"#define BYTES2INT16(array,pos) \ (array[pos] | (array[pos+1] << 8 ))#define BYTES2INT32(array,pos) \ (array[pos] | (array[pos+1] << 8 ) | \ (array[pos+2] << 16 ) | (array[pos+3] << 24 ))#define FATTYPE_FAT12 0#define FATTYPE_FAT16 1#define FATTYPE_FAT32 2/* 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/* fat12/16 */#define BS_DRVNUM 36#define BS_RESERVED1 37#define BS_BOOTSIG 38#define BS_VOLID 39#define BS_VOLLAB 43#define BS_FILSYSTYPE 54/* 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 )#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 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/* filename charset conversion table */static const unsigned char unicode2iso8859_2[] = { 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x0100 */ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x0108 */ 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110 */ 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x0118 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0130 */ 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x0138 */ 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x0140 */ 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0148 */ 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x0150 */ 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x0158 */ 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x0160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x0168 */ 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0170 */ 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x0178 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0188 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0190 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0198 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0208 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0210 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0218 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0220 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0228 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0230 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0238 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0248 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0250 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0258 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0260 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0268 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0270 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0278 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0288 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0290 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0298 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0x02c0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02d0 */ 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0x02d8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x02f8 */};struct fsinfo { unsigned int freecount; /* last known free cluster count */ unsigned int nextfree; /* first cluster to start looking for free clusters, or 0xffffffff for no hint */};/* fsinfo offsets */#define FSINFO_FREECOUNT 488#define FSINFO_NEXTFREE 492struct bpb{ char bs_oemname[9]; /* OEM string, ending with \0 */ int bpb_bytspersec; /* Bytes per sectory, 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_rootentcnt; /* Number of dir entries in the root */ 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 */ int bpb_secpertrk; /* Number of sectors per track */ int bpb_numheads; /* Number of heads */ int bpb_hiddsec; /* Hidden sectors before the volume */ unsigned int bpb_totsec32; /* Number of sectors on the volume (new 32-bit) */ int last_word; /* 0xAA55 */ /**** FAT12/16 specific *****/ int bs_drvnum; /* Drive number */ int bs_bootsig; /* Is 0x29 if the following 3 fields are valid */ unsigned int bs_volid; /* Volume ID */ char bs_vollab[12]; /* Volume label, 11 chars plus \0 */ char bs_filsystype[9]; /* File system type, 8 chars plus \0 */ /**** FAT32 specific *****/ int bpb_fatsz32; int bpb_extflags; int bpb_fsver; int bpb_rootclus; int bpb_fsinfo; int bpb_bkbootsec; /* variables for internal use */ unsigned int fatsize; unsigned int totalsectors; unsigned int rootdirsector; unsigned int firstdatasector; unsigned int startsector; unsigned int dataclusters; struct fsinfo fsinfo;};static struct bpb fat_bpb;static int update_fsinfo(void);static int first_sector_of_cluster(int cluster);static int bpb_is_sane(void);static void *cache_fat_sector(int secnum);static int create_dos_name(unsigned char *name, unsigned char *newname);static unsigned int find_free_cluster(unsigned int start);static int transfer( unsigned int start, int count, char* buf, bool write );#define FAT_CACHE_SIZE 0x20#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)struct fat_cache_entry{ int 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];static int sec2cluster(unsigned int sec){ if ( sec < fat_bpb.firstdatasector ) { DEBUGF( "sec2cluster() - Bad sector number (%d)\n", sec); return -1; } return ((sec - fat_bpb.firstdatasector) / fat_bpb.bpb_secperclus) + 2;}static int cluster2sec(int cluster){ int max_cluster = fat_bpb.totalsectors - fat_bpb.firstdatasector / fat_bpb.bpb_secperclus + 1; if(cluster > max_cluster) { DEBUGF( "cluster2sec() - Bad cluster number (%d)\n", cluster); return -1; } return first_sector_of_cluster(cluster);}static int first_sector_of_cluster(int cluster){ return (cluster - 2) * fat_bpb.bpb_secperclus + fat_bpb.firstdatasector;}int fat_startsector(void){ return fat_bpb.startsector;}void fat_size(unsigned int* size, unsigned int* free){ if (size) *size = fat_bpb.dataclusters * fat_bpb.bpb_secperclus / 2; if (free) *free = fat_bpb.fsinfo.freecount * fat_bpb.bpb_secperclus / 2;}int fat_mount(int startsector){ unsigned char buf[SECTOR_SIZE]; int rc; int datasec; unsigned int i; 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; } /* Read the sector */ rc = ata_read_sectors(startsector,1,buf); if(rc) { DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc); return rc * 10 - 1; } memset(&fat_bpb, 0, sizeof(struct bpb)); fat_bpb.startsector = startsector; strncpy(fat_bpb.bs_oemname, &buf[BS_OEMNAME], 8); fat_bpb.bs_oemname[8] = 0; fat_bpb.bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC); fat_bpb.bpb_secperclus = buf[BPB_SECPERCLUS]; fat_bpb.bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT); fat_bpb.bpb_numfats = buf[BPB_NUMFATS]; fat_bpb.bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16); fat_bpb.bpb_media = buf[BPB_MEDIA]; fat_bpb.bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16); fat_bpb.bpb_fatsz32 = BYTES2INT32(buf,BPB_FATSZ32); fat_bpb.bpb_secpertrk = BYTES2INT16(buf,BPB_SECPERTRK); fat_bpb.bpb_numheads = BYTES2INT16(buf,BPB_NUMHEADS); fat_bpb.bpb_hiddsec = BYTES2INT32(buf,BPB_HIDDSEC); fat_bpb.bpb_totsec32 = BYTES2INT32(buf,BPB_TOTSEC32); fat_bpb.last_word = BYTES2INT16(buf,BPB_LAST_WORD); /* calculate a few commonly used values */ if (fat_bpb.bpb_fatsz16 != 0) fat_bpb.fatsize = fat_bpb.bpb_fatsz16; else fat_bpb.fatsize = fat_bpb.bpb_fatsz32; if (fat_bpb.bpb_totsec16 != 0) fat_bpb.totalsectors = fat_bpb.bpb_totsec16; else fat_bpb.totalsectors = fat_bpb.bpb_totsec32; fat_bpb.firstdatasector = fat_bpb.bpb_rsvdseccnt + fat_bpb.bpb_numfats * fat_bpb.fatsize; /* Determine FAT type */ datasec = fat_bpb.totalsectors - fat_bpb.firstdatasector; fat_bpb.dataclusters = datasec / fat_bpb.bpb_secperclus;#ifdef TEST_FAT /* we are sometimes testing with "illegally small" fat32 images, so we don't use the proper fat32 test case for test code */ if ( fat_bpb.bpb_fatsz16 )#else if ( fat_bpb.dataclusters < 65525 )#endif { DEBUGF("This is not FAT32. Go away!\n"); return -2; } fat_bpb.bpb_extflags = BYTES2INT16(buf,BPB_EXTFLAGS); fat_bpb.bpb_fsver = BYTES2INT16(buf,BPB_FSVER); fat_bpb.bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS); fat_bpb.bpb_fsinfo = BYTES2INT16(buf,BPB_FSINFO); fat_bpb.bpb_bkbootsec = BYTES2INT16(buf,BPB_BKBOOTSEC); fat_bpb.bs_drvnum = buf[BS_32_DRVNUM]; fat_bpb.bs_bootsig = buf[BS_32_BOOTSIG]; if(fat_bpb.bs_bootsig == 0x29) { fat_bpb.bs_volid = BYTES2INT32(buf,BS_32_VOLID); strncpy(fat_bpb.bs_vollab, &buf[BS_32_VOLLAB], 11); strncpy(fat_bpb.bs_filsystype, &buf[BS_32_FILSYSTYPE], 8); } rc = bpb_is_sane(); if (rc < 0) { DEBUGF( "fat_mount() - BPB is not sane\n"); return rc * 10 - 3; } fat_bpb.rootdirsector = cluster2sec(fat_bpb.bpb_rootclus); /* Read the fsinfo sector */ rc = ata_read_sectors(startsector + fat_bpb.bpb_fsinfo, 1, buf); if (rc < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -