diff options
Diffstat (limited to 'fs/fat/fat.c')
-rw-r--r-- | fs/fat/fat.c | 135 |
1 files changed, 68 insertions, 67 deletions
diff --git a/fs/fat/fat.c b/fs/fat/fat.c index dbb8db9..1f95eb4 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -43,50 +43,30 @@ static void downcase (char *str) } } -static block_dev_desc_t *cur_dev = NULL; +static block_dev_desc_t *cur_dev; +static unsigned int cur_part_nr; +static disk_partition_t cur_part_info; -static unsigned long part_offset = 0; - -static int cur_part = 1; - -#define DOS_PART_TBL_OFFSET 0x1be -#define DOS_PART_MAGIC_OFFSET 0x1fe +#define DOS_BOOT_MAGIC_OFFSET 0x1fe #define DOS_FS_TYPE_OFFSET 0x36 #define DOS_FS32_TYPE_OFFSET 0x52 -static int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr) +static int disk_read(__u32 block, __u32 nr_blocks, void *buf) { - if (cur_dev == NULL) + if (!cur_dev || !cur_dev->block_read) return -1; - startblock += part_offset; - - if (cur_dev->block_read) { - return cur_dev->block_read(cur_dev->dev, startblock, getsize, - (unsigned long *) bufptr); - } - return -1; + return cur_dev->block_read(cur_dev->dev, + cur_part_info.start + block, nr_blocks, buf); } int fat_register_device (block_dev_desc_t * dev_desc, int part_no) { unsigned char buffer[dev_desc->blksz]; - if (!dev_desc->block_read) - return -1; + /* First close any currently found FAT filesystem */ + cur_dev = NULL; - cur_dev = dev_desc; - /* check if we have a MBR (on floppies we have only a PBR) */ - if (dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *)buffer) != 1) { - printf("** Can't read from device %d **\n", - dev_desc->dev); - return -1; - } - if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || - buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { - /* no signature found */ - return -1; - } #if (defined(CONFIG_CMD_IDE) || \ defined(CONFIG_CMD_MG_DISK) || \ defined(CONFIG_CMD_SATA) || \ @@ -94,45 +74,54 @@ int fat_register_device (block_dev_desc_t * dev_desc, int part_no) defined(CONFIG_CMD_USB) || \ defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) ) - { - disk_partition_t info; - - /* First we assume there is a MBR */ - if (!get_partition_info(dev_desc, part_no, &info)) { - part_offset = info.start; - cur_part = part_no; - } else if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], - "FAT", 3) == 0) || - (strncmp((char *)&buffer[DOS_FS32_TYPE_OFFSET], - "FAT32", 5) == 0)) { - /* ok, we assume we are on a PBR only */ - cur_part = 1; - part_offset = 0; - } else { + + /* Read the partition table, if present */ + if (!get_partition_info(dev_desc, part_no, &cur_part_info)) { + cur_dev = dev_desc; + cur_part_nr = part_no; + } +#endif + + /* Otherwise it might be a superfloppy (whole-disk FAT filesystem) */ + if (!cur_dev) { + if (part_no != 1) { printf("** Partition %d not valid on device %d **\n", - part_no, dev_desc->dev); + part_no, dev_desc->dev); return -1; } + + cur_dev = dev_desc; + cur_part_nr = 1; + cur_part_info.start = 0; + cur_part_info.size = dev_desc->lba; + cur_part_info.blksz = dev_desc->blksz; + memset(cur_part_info.name, 0, sizeof(cur_part_info.name)); + memset(cur_part_info.type, 0, sizeof(cur_part_info.type)); } -#else - if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3) == 0) || - (strncmp((char *)&buffer[DOS_FS32_TYPE_OFFSET], "FAT32", 5) == 0)) { - /* ok, we assume we are on a PBR only */ - cur_part = 1; - part_offset = 0; - } else { - /* FIXME we need to determine the start block of the - * partition where the DOS FS resides. This can be done - * by using the get_partition_info routine. For this - * purpose the libpart must be included. - */ - part_offset = 32; - cur_part = 1; + + /* Make sure it has a valid FAT header */ + if (disk_read(0, 1, buffer) != 1) { + cur_dev = NULL; + return -1; } -#endif - return 0; + + /* Check if it's actually a DOS volume */ + if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { + cur_dev = NULL; + return -1; + } + + /* Check for FAT12/FAT16/FAT32 filesystem */ + if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) + return 0; + if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) + return 0; + + cur_dev = NULL; + return -1; } + /* * Get the first occurence of a directory delimiter ('/' or '\') in a string. * Return index into string if found, -1 otherwise. @@ -285,6 +274,8 @@ get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer, { __u32 idx = 0; __u32 startsect; + __u32 nr_sect; + int ret; if (clustnum > 0) { startsect = mydata->data_begin + @@ -295,16 +286,19 @@ get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer, debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); - if (disk_read(startsect, size / mydata->sect_size, buffer) < 0) { - debug("Error reading data\n"); + nr_sect = size / mydata->sect_size; + ret = disk_read(startsect, nr_sect, buffer); + if (ret != nr_sect) { + debug("Error reading data (got %d)\n", ret); return -1; } if (size % mydata->sect_size) { __u8 tmpbuf[mydata->sect_size]; idx = size / mydata->sect_size; - if (disk_read(startsect + idx, 1, tmpbuf) < 0) { - debug("Error reading data\n"); + ret = disk_read(startsect + idx, 1, tmpbuf); + if (ret != 1) { + debug("Error reading data (got %d)\n", ret); return -1; } buffer += idx * mydata->sect_size; @@ -633,6 +627,7 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect, } #ifdef CONFIG_SUPPORT_VFAT if (dols && mkcksum(dentptr->name) == prevcksum) { + prevcksum = 0xffff; dentptr++; continue; } @@ -813,6 +808,11 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize, mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; mydata->clust_size = bs.cluster_size; + if (mydata->sect_size != cur_part_info.blksz) { + printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n", + mydata->sect_size, cur_part_info.blksz); + return -1; + } if (mydata->fatsize == 32) { mydata->data_begin = mydata->rootdir_sect - @@ -963,6 +963,7 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize, #ifdef CONFIG_SUPPORT_VFAT else if (dols == LS_ROOT && mkcksum(dentptr->name) == prevcksum) { + prevcksum = 0xffff; dentptr++; continue; } @@ -1170,7 +1171,7 @@ int file_fat_detectfs (void) vol_label[11] = '\0'; volinfo.fs_type[5] = '\0'; - printf("Partition %d: Filesystem: %s \"%s\"\n", cur_part, + printf("Partition %d: Filesystem: %s \"%s\"\n", cur_part_nr, volinfo.fs_type, vol_label); return 0; |