diff --git a/fs/fs_fat32.c b/fs/fs_fat32.c index 9edd320c4d..f4bed845e3 100644 --- a/fs/fs_fat32.c +++ b/fs/fs_fat32.c @@ -78,14 +78,18 @@ #define MBR_GETSECPERCLUS(p) UBYTE_VAL(p,BS_SECPERCLUS) #define MBR_GETNUMFATS(p) UBYTE_VAL(p,BS_NUMFATS) #define MBR_GETMEDIA(p) UBYTE_VAL(p,BS_MEDIA) -#define MBR_GETDRVNUM(p) UBYTE_VAL(p,BS32_DRVNUM) -#define MBR_GETBOOTSIG(p) UBYTE_VAL(p,BS32_BOOTSIG) +#define MBR_GETDRVNUM16(p) UBYTE_VAL(p,BS16_DRVNUM) +#define MBR_GETDRVNUM32(p) UBYTE_VAL(p,BS32_DRVNUM) +#define MBR_GETBOOTSIG16(p) UBYTE_VAL(p,BS16_BOOTSIG) +#define MBR_GETBOOTSIG32(p) UBYTE_VAL(p,BS32_BOOTSIG) #define MBR_PUTSECPERCLUS(p,v) UBYTE_PUT(p,BS_SECPERCLUS),v) #define MBR_PUTNUMFATS(p,v) UBYTE_PUT(p,BS_NUMFATS,v) #define MBR_PUTMEDIA(p,v) UBYTE_PUT(p,BS_MEDIA,v) -#define MBR_PUTDRVNUM(p,v) UBYTE_PUT(p,BS32_DRVNUM,v) -#define MBR_PUTBOOTSIG(p,v) UBYTE_PUT(p,BS32_BOOTSIG,v) +#define MBR_PUTDRVNUM16(p,v) UBYTE_PUT(p,BS16_DRVNUM,v) +#define MBR_PUTDRVNUM32(p,v) UBYTE_PUT(p,BS32_DRVNUM,v) +#define MBR_PUTBOOTSIG16(p,v) UBYTE_PUT(p,BS16_BOOTSIG,v) +#define MBR_PUTBOOTSIG32(p,v) UBYTE_PUT(p,BS32_BOOTSIG,v) /* For the all targets, unaligned values need to be accessed byte-by-byte. * Some architectures may handle unaligned accesses with special interrupt @@ -97,12 +101,14 @@ #define MBR_GETBYTESPERSEC(p) fat_getuint16(UBYTE_PTR(p,BS_BYTESPERSEC)) #define MBR_GETROOTENTCNT(p) fat_getuint16(UBYTE_PTR(p,BS_ROOTENTCNT)) #define MBR_GETTOTSEC16(p) fat_getuint16(UBYTE_PTR(p,BS_TOTSEC16)) -#define MBR_GETVOLID(p) fat_getuint32(UBYTE_PTR(p,BS32_VOLID)) +#define MBR_GETVOLID16(p) fat_getuint32(UBYTE_PTR(p,BS16_VOLID)) +#define MBR_GETVOLID32(p) fat_getuint32(UBYTE_PTR(p,BS32_VOLID)) #define MBR_PUTBYTESPERSEC(p,v) fat_putuint16(UBYTE_PTR(p,BS_BYTESPERSEC),v) #define MBR_PUTROOTENTCNT(p,v) fat_putuint16(UBYTE_PTR(p,BS_ROOTENTCNT),v) #define MBR_PUTTOTSEC16(p,v) fat_putuint16(UBYTE_PTR(p,BS_TOTSEC16),v) -#define MBR_PUTVOLID(p,v) fat_putuint32(UBYTE_PTR(p,BS32_VOLID),v) +#define MBR_PUTVOLID16(p,v) fat_putuint32(UBYTE_PTR(p,BS16_VOLID),v) +#define MBR_PUTVOLID32(p,v) fat_putuint32(UBYTE_PTR(p,BS32_VOLID),v) /* But for multi-byte values, the endian-ness of the target vs. the little * endian order of the byte stream or alignment of the data within the byte @@ -468,8 +474,11 @@ static int fat_readfsinfo(struct fat_mountpt_s *fs) static int fat_checkbootrecord(struct fat_mountpt_s *fs) { - uint32 ndatasectors; - uint32 fatsize; + uint32 ndatasectors; + uint32 fatsize; + uint16 rootentcnt; + uint16 rootdirsectors = 0; + boolean notfat32 = FALSE; /* Verify the MBR signature at offset 510 in the sector (true even * if the sector size is greater than 512. All FAT file systems have @@ -479,7 +488,6 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs) */ if (MBR_GETSIGNATURE(fs->fs_buffer) != 0xaa55 || - MBR_GETROOTENTCNT(fs->fs_buffer) != 0 || MBR_GETBYTESPERSEC(fs->fs_buffer) != fs->fs_hwsectorsize) { return -ENODEV; @@ -490,16 +498,30 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs) * volume has < 4085 cluseter, a FAT16 volume has fewer than 65,525 * clusters, and any larger is FAT32. * - * Determine the number of sectors in a FAT. + * Get the number of 32-bit directory entries in root directory (zero + * for FAT32. */ + fs->fs_rootentcnt = MBR_GETROOTENTCNT(fs->fs_buffer); + if (fs->fs_rootentcnt != 0) + { + notfat32 = TRUE; /* Must be zero for FAT32 */ + rootdirsectors = (32 * fs->fs_rootentcnt + fs->fs_hwsectorsize - 1) / fs->fs_hwsectorsize; + } + + /* Determine the number of sectors in a FAT. */ + fs->fs_fatsize = MBR_GETFATSZ16(fs->fs_buffer); /* Should be zero */ - if (!fs->fs_fatsize) + if (fs->fs_fatsize) + { + notfat32 = TRUE; /* Must be zero for FAT32 */ + } + else { fs->fs_fatsize = MBR_GETFATSZ32(fs->fs_buffer); } - if (fs->fs_fatsize >= fs->fs_hwnsectors) + if (!fs->fs_fatsize || fs->fs_fatsize >= fs->fs_hwnsectors) { return -ENODEV; } @@ -507,12 +529,16 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs) /* Get the total number of sectors on the volume. */ fs->fs_fattotsec = MBR_GETTOTSEC16(fs->fs_buffer); /* Should be zero */ - if (!fs->fs_fattotsec) + if (fs->fs_fattotsec) + { + notfat32 = TRUE; /* Must be zero for FAT32 */ + } + else { fs->fs_fattotsec = MBR_GETTOTSEC32(fs->fs_buffer); } - if (fs->fs_fattotsec > fs->fs_hwnsectors) + if (!fs->fs_fattotsec || fs->fs_fattotsec > fs->fs_hwnsectors) { return -ENODEV; } @@ -532,7 +558,7 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs) /* Get the total number of data sectors */ - ndatasectors = fs->fs_fattotsec - fs->fs_fatresvdseccount - fatsize; + ndatasectors = fs->fs_fattotsec - fs->fs_fatresvdseccount - fatsize - rootdirsectors; if (ndatasectors > fs->fs_hwnsectors) { return -ENODEV; @@ -548,7 +574,23 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs) /* Finally, the test: */ - if (fs->fs_nclusters < 65525) + if (fs->fs_nclusters < 4085) + { + fs->fs_fsinfo = 0; + fs->fs_type = FSTYPE_FAT12; + } + else if (fs->fs_nclusters < 65525) + { + fs->fs_fsinfo = 0; + fs->fs_type = FSTYPE_FAT16; + } + + else if (!notfat32) + { + fs->fs_fsinfo = fs->fs_fatbase + MBR_GETFSINFO(fs->fs_buffer); + fs->fs_type = FSTYPE_FAT32; + } + else { return -ENODEV; } @@ -557,10 +599,18 @@ static int fat_checkbootrecord(struct fat_mountpt_s *fs) * from the boot record that we will need later. */ - fs->fs_fsinfo = fs->fs_fatbase + MBR_GETFSINFO(fs->fs_buffer); fs->fs_fatbase += fs->fs_fatresvdseccount; - fs->fs_database = fs->fs_fatbase + fatsize; - fs->fs_rootclus = MBR_GETROOTCLUS(fs->fs_buffer); + + if (fs->fs_type == FSTYPE_FAT32) + { + fs->fs_rootbase = MBR_GETROOTCLUS(fs->fs_buffer); + } + else + { + fs->fs_rootbase = fs->fs_fatbase + fatsize; + } + + fs->fs_database = fs->fs_fatbase + fatsize + fs->fs_rootentcnt / (fs->fs_hwsectorsize / 32); fs->fs_fsifreecount = 0xffffffff; return OK; @@ -675,13 +725,16 @@ static int fat_mount(struct fat_mountpt_s *fs, boolean writeable) } /* We have what appears to be a valid FAT filesystem! Now read the - * FSINFO sector. + * FSINFO sector (FAT32 only) */ - ret = fat_readfsinfo(fs); - if (ret != OK) + if (fs->fs_type == FSTYPE_FAT32) { - goto errout_with_buffer; + ret = fat_readfsinfo(fs); + if (ret != OK) + { + goto errout_with_buffer; + } } /* We did it! */ diff --git a/fs/fs_fat32.h b/fs/fs_fat32.h index 996af5c542..3368029ba5 100644 --- a/fs/fs_fat32.h +++ b/fs/fs_fat32.h @@ -61,7 +61,7 @@ #define BS_SECPERCLUS 13 /* 1@13: Sectors per allocation unit: 2**n, n=0..7 */ #define BS_RESVDSECCOUNT 14 /* 2@14: Reserved sector count: Usually 32 */ #define BS_NUMFATS 16 /* 1@16: Number of FAT data structures: always 2 */ -#define BS_ROOTENTCNT 17 /* 2@17: FAT12/16: Must be 0 for FAT32*/ +#define BS_ROOTENTCNT 17 /* 2@17: FAT12/16: Must be 0 for FAT32 */ #define BS_TOTSEC16 19 /* 2@19: FAT12/16: Must be 0, see BS32_totsec32 */ #define BS_MEDIA 21 /* 1@21: Media code: f0, f8, f9-fa, fc-ff */ #define BS_FATSZ16 22 /* 2@22: FAT12/16: Must be 0, see BS32_fatsz32 */ @@ -70,6 +70,15 @@ #define BS_HIDSEC 28 /* 4@28: Count of hidden sectors preceding FAT */ #define BS_TOTSEC32 32 /* 4@32: Total count of sectors on the volume */ +/* The following fields are only valid for FAT12/16 */ + +#define BS16_DRVNUM 36 /* 1@36: Drive number for MSDOS bootstrap */ + /* 1@37: Reserverd (zero) */ +#define BS16_BOOTSIG 38 /* 1@38: Extended boot signature: 0x29 if following valid */ +#define BS16_VOLID 39 /* 4@39: Volume serial number */ +#define BS16_VOLLAB 43 /* 11@43: Volume label */ +#define BS16_FILESYSTYPE 54 /* 8@54: "FAT12 ", "FAT16 ", or "FAT " */ + /* The following fields are only valid for FAT32 */ #define BS32_FATSZ32 36 /* 4@36: Count of sectors occupied by one FAT */ @@ -96,6 +105,12 @@ #define BS_SIGNATURE 510 /* 2@510: Valid MBRs have 0x55aa here */ +/* File system types */ + +#define FSTYPE_FAT12 0 +#define FSTYPE_FAT16 1 +#define FSTYPE_FAT32 2 + /**************************************************************************** * These offset describe the FSINFO sector */ @@ -157,15 +172,17 @@ struct fat_mountpt_s size_t fs_hwsectorsize; /* HW: Sector size reported by block driver*/ size_t fs_hwnsectors; /* HW: The number of sectors reported by the hardware */ size_t fs_fatbase; /* Logical block of start of filesystem (past resd sectors) */ + size_t fs_rootbase; /* MBR: Cluster no. of 1st cluster of root dir */ size_t fs_database; /* Logical block of start data sectors */ size_t fs_fsinfo; /* MBR: Sector number of FSINFO sector */ uint32 fs_nclusters; /* Maximum number of data clusters */ - uint32 fs_rootclus; /* MBR: Cluster no. of 1st cluster of root dir */ uint32 fs_fatsize; /* MBR: Count of sectors occupied by one fat */ uint32 fs_fattotsec; /* MBR: Total count of sectors on the volume */ uint32 fs_fsifreecount; /* FSI: Last free cluster count on volume */ uint32 fs_fsinextfree; /* FSI: Cluster number of 1st free cluster */ uint16 fs_fatresvdseccount; /* MBR: The total number of reserved sectors */ + uint16 fs_rootentcnt; /* MBR: Count of 32-bit root directory entries */ + ubyte fs_type; /* FSTYPE_FAT12, FSTYPE_FAT16, or FSTYPE_FAT32 */ ubyte fs_fatnumfats; /* MBR: Number of FATs (probably 2) */ ubyte fs_fatsecperclus; /* MBR: Sectors per allocation unit: 2**n, n=0..7 */ ubyte *fs_buffer; /* This is an allocated buffer to hold one sector