diff options
author | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2015-10-14 10:46:36 +0200 |
---|---|---|
committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2015-10-14 10:46:36 +0200 |
commit | 13a3972585af60ec367d209cedbd3601e0c77467 (patch) | |
tree | 4b3312669b3e501f6bc10b39d8c7bbf516f07aac /fs/fat/fat.c | |
parent | 208bd51396fb606dbdcf45b064e6b372d7dd3e81 (diff) | |
parent | 297faccca2235e359012118495b9b73451d54bb9 (diff) |
Merge remote-tracking branch 'u-boot/master'
Diffstat (limited to 'fs/fat/fat.c')
-rw-r--r-- | fs/fat/fat.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/fs/fat/fat.c b/fs/fat/fat.c index bccc3e3ed8..f939bc5dee 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -16,6 +16,7 @@ #include <asm/byteorder.h> #include <part.h> #include <malloc.h> +#include <memalign.h> #include <linux/compiler.h> #include <linux/ctype.h> @@ -45,11 +46,18 @@ static disk_partition_t cur_part_info; static int disk_read(__u32 block, __u32 nr_blocks, void *buf) { + ulong ret; + if (!cur_dev || !cur_dev->block_read) return -1; - return cur_dev->block_read(cur_dev->dev, - cur_part_info.start + block, nr_blocks, buf); + ret = cur_dev->block_read(cur_dev->dev, + cur_part_info.start + block, nr_blocks, buf); + + if (nr_blocks && ret == 0) + return -1; + + return ret; } int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info) @@ -895,6 +903,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, strcpy(fnamecopy, filename); downcase(fnamecopy); +root_reparse: if (*fnamecopy == '\0') { if (!dols) goto exit; @@ -1180,6 +1189,34 @@ rootdir_done: if (isdir && !(dentptr->attr & ATTR_DIR)) goto exit; + /* + * If we are looking for a directory, and found a directory + * type entry, and the entry is for the root directory (as + * denoted by a cluster number of 0), jump back to the start + * of the function, since at least on FAT12/16, the root dir + * lives in a hard-coded location and needs special handling + * to parse, rather than simply following the cluster linked + * list in the FAT, like other directories. + */ + if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) { + /* + * Modify the filename to remove the prefix that gets + * back to the root directory, so the initial root dir + * parsing code can continue from where we are without + * confusion. + */ + strcpy(fnamecopy, nextname ?: ""); + /* + * Set up state the same way as the function does when + * first started. This is required for the root dir + * parsing code operates in its expected environment. + */ + subname = ""; + cursect = mydata->rootdir_sect; + isdir = 0; + goto root_reparse; + } + if (idx >= 0) subname = nextname; } |