summaryrefslogtreecommitdiffstats
path: root/fs/fat/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat/fat.c')
-rw-r--r--fs/fat/fat.c135
1 files changed, 68 insertions, 67 deletions
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index dbb8db92f0..1f95eb4caf 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;
OpenPOWER on IntegriCloud