]> Git Repo - J-u-boot.git/blobdiff - fs/fat/fat.c
Merge commit '0344c602eadc0802776b65ff90f0a02c856cf53c' as 'lib/mbedtls/external...
[J-u-boot.git] / fs / fat / fat.c
index df9ea2c028fcf855902e3924cdae0e7182bd8941..e2570e81676875d54911ceec27a8d1bedc1c32d5 100644 (file)
@@ -8,7 +8,8 @@
  * 2003-03-10 - [email protected] - ported to uboot
  */
 
-#include <common.h>
+#define LOG_CATEGORY   LOGC_FS
+
 #include <blk.h>
 #include <config.h>
 #include <exports.h>
 #include <fs.h>
 #include <log.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 #include <part.h>
 #include <malloc.h>
 #include <memalign.h>
 #include <asm/cache.h>
 #include <linux/compiler.h>
 #include <linux/ctype.h>
+#include <linux/log2.h>
+
+/* maximum number of clusters for FAT12 */
+#define MAX_FAT12      0xFF4
 
 /*
  * Convert a string to lowercase.  Converts at most 'len' characters,
@@ -97,8 +103,8 @@ int fat_register_device(struct blk_desc *dev_desc, int part_no)
        /* Read the partition table, if present */
        if (part_get_info(dev_desc, part_no, &info)) {
                if (part_no != 0) {
-                       printf("** Partition %d not valid on device %d **\n",
-                                       part_no, dev_desc->devnum);
+                       log_err("Partition %d invalid on device %d\n", part_no,
+                               dev_desc->devnum);
                        return -1;
                }
 
@@ -108,9 +114,7 @@ int fat_register_device(struct blk_desc *dev_desc, int part_no)
                info.name[0] = 0;
                info.type[0] = 0;
                info.bootable = 0;
-#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-               info.uuid[0] = 0;
-#endif
+               disk_partition_clr_uuid(&info);
        }
 
        return fat_set_blk_dev(dev_desc, &info);
@@ -168,7 +172,7 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry)
        __u32 ret = 0x00;
 
        if (CHECK_CLUST(entry, mydata->fatsize)) {
-               printf("Error: Invalid FAT entry: 0x%08x\n", entry);
+               log_err("Invalid FAT entry: %#08x\n", entry);
                return ret;
        }
 
@@ -483,6 +487,73 @@ static __u8 mkcksum(struct nameext *nameext)
        return ret;
 }
 
+/*
+ * Determine if the FAT type is FAT12 or FAT16
+ *
+ * Based on fat_fill_super() from the Linux kernel's fs/fat/inode.c
+ */
+static int determine_legacy_fat_bits(const boot_sector *bs)
+{
+       u16 fat_start = bs->reserved;
+       u32 dir_start = fat_start + bs->fats * bs->fat_length;
+       u32 rootdir_sectors = get_unaligned_le16(bs->dir_entries) *
+                             sizeof(dir_entry) /
+                             get_unaligned_le16(bs->sector_size);
+       u32 data_start = dir_start + rootdir_sectors;
+       u16 sectors = get_unaligned_le16(bs->sectors);
+       u32 total_sectors = sectors ? sectors : bs->total_sect;
+       u32 total_clusters = (total_sectors - data_start) /
+                            bs->cluster_size;
+
+       return (total_clusters > MAX_FAT12) ? 16 : 12;
+}
+
+/*
+ * Determines if the boot sector's media field is valid
+ *
+ * Based on fat_valid_media() from Linux kernel's include/linux/msdos_fs.h
+ */
+static int fat_valid_media(u8 media)
+{
+       return media >= 0xf8 || media == 0xf0;
+}
+
+/*
+ * Determines if the given boot sector is valid
+ *
+ * Based on fat_read_bpb() from the Linux kernel's fs/fat/inode.c
+ */
+static int is_bootsector_valid(const boot_sector *bs)
+{
+       u16 sector_size = get_unaligned_le16(bs->sector_size);
+       u16 dir_per_block = sector_size / sizeof(dir_entry);
+
+       if (!bs->reserved)
+               return 0;
+
+       if (!bs->fats)
+               return 0;
+
+       if (!fat_valid_media(bs->media))
+               return 0;
+
+       if (!is_power_of_2(sector_size) ||
+           sector_size < 512 ||
+           sector_size > 4096)
+               return 0;
+
+       if (!is_power_of_2(bs->cluster_size))
+               return 0;
+
+       if (!bs->fat_length && !bs->fat32_length)
+               return 0;
+
+       if (get_unaligned_le16(bs->dir_entries) & (dir_per_block - 1))
+               return 0;
+
+       return 1;
+}
+
 /*
  * Read boot sector and volume info from a FAT filesystem
  */
@@ -506,7 +577,8 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
 
        if (disk_read(0, 1, block) < 0) {
                debug("Error: reading block\n");
-               goto fail;
+               ret = -1;
+               goto out_free;
        }
 
        memcpy(bs, block, sizeof(boot_sector));
@@ -516,8 +588,14 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
        bs->heads = FAT2CPU16(bs->heads);
        bs->total_sect = FAT2CPU32(bs->total_sect);
 
+       if (!is_bootsector_valid(bs)) {
+               debug("Error: bootsector is invalid\n");
+               ret = -1;
+               goto out_free;
+       }
+
        /* FAT32 entries */
-       if (bs->fat_length == 0) {
+       if (!bs->fat_length && bs->fat32_length) {
                /* Assume FAT32 */
                bs->fat32_length = FAT2CPU32(bs->fat32_length);
                bs->flags = FAT2CPU16(bs->flags);
@@ -528,28 +606,11 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
                *fatsize = 32;
        } else {
                vistart = (volume_info *)&(bs->fat32_length);
-               *fatsize = 0;
+               *fatsize = determine_legacy_fat_bits(bs);
        }
        memcpy(volinfo, vistart, sizeof(volume_info));
 
-       if (*fatsize == 32) {
-               if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0)
-                       goto exit;
-       } else {
-               if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) {
-                       *fatsize = 12;
-                       goto exit;
-               }
-               if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) {
-                       *fatsize = 16;
-                       goto exit;
-               }
-       }
-
-       debug("Error: broken fs_type sign\n");
-fail:
-       ret = -1;
-exit:
+out_free:
        free(block);
        return ret;
 }
@@ -571,7 +632,7 @@ static int get_fs_info(fsdata *mydata)
                mydata->total_sect = bs.total_sect;
        } else {
                mydata->fatlength = bs.fat_length;
-               mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0];
+               mydata->total_sect = get_unaligned_le16(bs.sectors);
                if (!mydata->total_sect)
                        mydata->total_sect = bs.total_sect;
        }
@@ -583,22 +644,22 @@ static int get_fs_info(fsdata *mydata)
 
        mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats;
 
-       mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
+       mydata->sect_size = get_unaligned_le16(bs.sector_size);
        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);
+               log_err("FAT sector size mismatch (fs=%u, dev=%lu)\n",
+                       mydata->sect_size, cur_part_info.blksz);
                return -1;
        }
        if (mydata->clust_size == 0) {
-               printf("Error: FAT cluster size not set\n");
+               log_err("FAT cluster size not set\n");
                return -1;
        }
        if ((unsigned int)mydata->clust_size * mydata->sect_size >
            MAX_CLUSTSIZE) {
-               printf("Error: FAT cluster size too big (cs=%u, max=%u)\n",
-                      (unsigned int)mydata->clust_size * mydata->sect_size,
-                      MAX_CLUSTSIZE);
+               log_err("FAT cluster size too big (cs=%u, max=%u)\n",
+                       (uint)mydata->clust_size * mydata->sect_size,
+                       MAX_CLUSTSIZE);
                return -1;
        }
 
@@ -607,8 +668,7 @@ static int get_fs_info(fsdata *mydata)
                                        (mydata->clust_size * 2);
                mydata->root_cluster = bs.root_cluster;
        } else {
-               mydata->rootdir_size = ((bs.dir_entries[1]  * (int)256 +
-                                        bs.dir_entries[0]) *
+               mydata->rootdir_size = (get_unaligned_le16(bs.dir_entries) *
                                         sizeof(dir_entry)) /
                                         mydata->sect_size;
                mydata->data_begin = mydata->rootdir_sect +
@@ -1144,8 +1204,8 @@ int file_fat_detectfs(void)
                return 1;
        }
 
-       if (IS_ENABLED(CONFIG_HAVE_BLOCK_DEVICE)) {
-               printf("Interface:  %s\n", blk_get_if_type_name(cur_dev->if_type));
+       if (blk_enabled()) {
+               printf("Interface:  %s\n", blk_get_uclass_name(cur_dev->uclass_id));
                printf("  Device %d: ", cur_dev->devnum);
                dev_print(cur_dev);
        }
@@ -1157,9 +1217,8 @@ int file_fat_detectfs(void)
 
        memcpy(vol_label, volinfo.volume_label, 11);
        vol_label[11] = '\0';
-       volinfo.fs_type[5] = '\0';
 
-       printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label);
+       printf("Filesystem: FAT%d \"%s\"\n", fatsize, vol_label);
 
        return 0;
 }
@@ -1194,7 +1253,7 @@ out:
 static void __maybe_unused fat2rtc(u16 date, u16 time, struct rtc_time *tm)
 {
        tm->tm_mday = date & 0x1f;
-       tm->tm_mon = (date & 0x1e0) >> 4;
+       tm->tm_mon = (date & 0x1e0) >> 5;
        tm->tm_year = (date >> 9) + 1980;
 
        tm->tm_sec = (time & 0x1f) << 1;
@@ -1243,8 +1302,8 @@ out_free_itr:
        return ret;
 }
 
-int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
-                    loff_t maxsize, loff_t *actread)
+int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
+                 loff_t *actread)
 {
        fsdata fsdata;
        fat_itr *itr;
@@ -1261,12 +1320,12 @@ int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
        if (ret)
                goto out_free_both;
 
-       debug("reading %s at pos %llu\n", filename, pos);
+       debug("reading %s at pos %llu\n", filename, offset);
 
        /* For saving default max clustersize memory allocated to malloc pool */
        dir_entry *dentptr = itr->dent;
 
-       ret = get_contents(&fsdata, dentptr, pos, buffer, maxsize, actread);
+       ret = get_contents(&fsdata, dentptr, offset, buf, len, actread);
 
 out_free_both:
        free(fsdata.fatbuf);
@@ -1280,25 +1339,13 @@ int file_fat_read(const char *filename, void *buffer, int maxsize)
        loff_t actread;
        int ret;
 
-       ret =  file_fat_read_at(filename, 0, buffer, maxsize, &actread);
+       ret =  fat_read_file(filename, buffer, 0, maxsize, &actread);
        if (ret)
                return ret;
        else
                return actread;
 }
 
-int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
-                 loff_t *actread)
-{
-       int ret;
-
-       ret = file_fat_read_at(filename, offset, buf, len, actread);
-       if (ret)
-               printf("** Unable to read file %s **\n", filename);
-
-       return ret;
-}
-
 typedef struct {
        struct fs_dir_stream parent;
        struct fs_dirent dirent;
This page took 0.038329 seconds and 4 git commands to generate.