diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/dev.c | 1 | ||||
-rw-r--r-- | fs/ext4/ext4_common.c | 16 | ||||
-rw-r--r-- | fs/ext4/ext4_write.c | 10 | ||||
-rw-r--r-- | fs/fat/fat.c | 41 | ||||
-rw-r--r-- | fs/fat/fat_write.c | 227 | ||||
-rw-r--r-- | fs/ubifs/super.c | 3 | ||||
-rw-r--r-- | fs/ubifs/ubifs.c | 2 |
7 files changed, 186 insertions, 114 deletions
diff --git a/fs/ext4/dev.c b/fs/ext4/dev.c index c77c02c..20f5256 100644 --- a/fs/ext4/dev.c +++ b/fs/ext4/dev.c @@ -25,6 +25,7 @@ #include <common.h> #include <config.h> +#include <memalign.h> #include <ext4fs.h> #include <ext_common.h> #include "ext4_common.h" diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index cab5465..727a2f7 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -24,6 +24,7 @@ #include <ext4fs.h> #include <inttypes.h> #include <malloc.h> +#include <memalign.h> #include <stddef.h> #include <linux/stat.h> #include <linux/time.h> @@ -614,8 +615,7 @@ static int parse_path(char **arr, char *dirname) arr[i] = zalloc(strlen("/") + 1); if (!arr[i]) return -ENOMEM; - - arr[i++] = "/"; + memcpy(arr[i++], "/", strlen("/")); /* add each path entry after root */ while (token != NULL) { @@ -745,6 +745,11 @@ end: fail: free(depth_dirname); free(parse_dirname); + for (i = 0; i < depth; i++) { + if (!ptr[i]) + break; + free(ptr[i]); + } free(ptr); free(parent_inode); free(first_inode); @@ -765,6 +770,7 @@ static int check_filename(char *filename, unsigned int blknr) struct ext2_dirent *previous_dir = NULL; char *ptr = NULL; struct ext_filesystem *fs = get_fs(); + int ret = -1; /* get the first block of root */ first_block_no_of_root = blknr; @@ -818,12 +824,12 @@ static int check_filename(char *filename, unsigned int blknr) if (ext4fs_put_metadata(root_first_block_addr, first_block_no_of_root)) goto fail; - return inodeno; + ret = inodeno; } fail: free(root_first_block_buffer); - return -1; + return ret; } int ext4fs_filename_check(char *filename) @@ -2040,7 +2046,7 @@ static char *ext4fs_read_symlink(struct ext2fs_node *node) status = ext4fs_read_file(diro, 0, __le32_to_cpu(diro->inode.size), symlink, &actread); - if (status == 0) { + if ((status < 0) || (actread == 0)) { free(symlink); return 0; } diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index fbc4c4b..e027916 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -23,6 +23,7 @@ #include <common.h> +#include <memalign.h> #include <linux/stat.h> #include <div64.h> #include "ext4_common.h" @@ -986,26 +987,17 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset, return -1; } - /* mount the filesystem */ - if (!ext4fs_mount(0)) { - printf("** Error Bad ext4 partition **\n"); - goto fail; - } - ret = ext4fs_write(filename, buf, len); - if (ret) { printf("** Error ext4fs_write() **\n"); goto fail; } - ext4fs_close(); *actwrite = len; return 0; fail: - ext4fs_close(); *actwrite = 0; return -1; diff --git a/fs/fat/fat.c b/fs/fat/fat.c index bccc3e3..f939bc5 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; } diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 98b88ad..af828d0 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -30,6 +30,8 @@ static void uppercase(char *str, int len) static int total_sector; static int disk_write(__u32 block, __u32 nr_blocks, void *buf) { + ulong ret; + if (!cur_dev || !cur_dev->block_write) return -1; @@ -39,8 +41,13 @@ static int disk_write(__u32 block, __u32 nr_blocks, void *buf) return -1; } - return cur_dev->block_write(cur_dev->dev, - cur_part_info.start + block, nr_blocks, buf); + ret = cur_dev->block_write(cur_dev->dev, + cur_part_info.start + block, + nr_blocks, buf); + if (nr_blocks && ret == 0) + return -1; + + return ret; } /* @@ -548,8 +555,9 @@ static int set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) { - int idx = 0; + __u32 idx = 0; __u32 startsect; + int ret; if (clustnum > 0) startsect = mydata->data_begin + @@ -559,26 +567,45 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, debug("clustnum: %d, startsect: %d\n", clustnum, startsect); - if ((size / mydata->sect_size) > 0) { - if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { - debug("Error writing data\n"); + if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { + ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); + + printf("FAT: Misaligned buffer address (%p)\n", buffer); + + while (size >= mydata->sect_size) { + memcpy(tmpbuf, buffer, mydata->sect_size); + ret = disk_write(startsect++, 1, tmpbuf); + if (ret != 1) { + debug("Error writing data (got %d)\n", ret); + return -1; + } + + buffer += mydata->sect_size; + size -= mydata->sect_size; + } + } else if (size >= mydata->sect_size) { + idx = size / mydata->sect_size; + ret = disk_write(startsect, idx, buffer); + if (ret != idx) { + debug("Error writing data (got %d)\n", ret); return -1; } - } - if (size % mydata->sect_size) { - __u8 tmpbuf[mydata->sect_size]; + startsect += idx; + idx *= mydata->sect_size; + buffer += idx; + size -= idx; + } - idx = size / mydata->sect_size; - buffer += idx * mydata->sect_size; - memcpy(tmpbuf, buffer, size % mydata->sect_size); + if (size) { + ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); - if (disk_write(startsect + idx, 1, tmpbuf) < 0) { - debug("Error writing data\n"); + memcpy(tmpbuf, buffer, size); + ret = disk_write(startsect, 1, tmpbuf); + if (ret != 1) { + debug("Error writing data (got %d)\n", ret); return -1; } - - return 0; } return 0; @@ -683,6 +710,14 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, debug("%llu bytes\n", filesize); + if (!curclust) { + if (filesize) { + debug("error: nonempty clusterless file!\n"); + return -1; + } + return 0; + } + actsize = bytesperclust; endclust = curclust; do { @@ -694,28 +729,17 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, goto getit; if (CHECK_CLUST(newclust, mydata->fatsize)) { - debug("curclust: 0x%x\n", newclust); + debug("newclust: 0x%x\n", newclust); debug("Invalid FAT entry\n"); return 0; } endclust = newclust; actsize += bytesperclust; } - /* actsize >= file size */ - actsize -= bytesperclust; - /* set remaining clusters */ - if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { - debug("error: writing cluster\n"); - return -1; - } /* set remaining bytes */ - *gotsize += actsize; - filesize -= actsize; - buffer += actsize; actsize = filesize; - - if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) { + if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) { debug("error: writing cluster\n"); return -1; } @@ -738,8 +762,8 @@ getit: filesize -= actsize; buffer += actsize; - if (CHECK_CLUST(curclust, mydata->fatsize)) { - debug("curclust: 0x%x\n", curclust); + if (CHECK_CLUST(newclust, mydata->fatsize)) { + debug("newclust: 0x%x\n", newclust); debug("Invalid FAT entry\n"); return 0; } @@ -749,15 +773,24 @@ getit: } /* - * Fill dir_entry + * Set start cluster in directory entry */ -static void fill_dentry(fsdata *mydata, dir_entry *dentptr, - const char *filename, __u32 start_cluster, __u32 size, __u8 attr) +static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr, + __u32 start_cluster) { if (mydata->fatsize == 32) dentptr->starthi = cpu_to_le16((start_cluster & 0xffff0000) >> 16); dentptr->start = cpu_to_le16(start_cluster & 0xffff); +} + +/* + * Fill dir_entry + */ +static void fill_dentry(fsdata *mydata, dir_entry *dentptr, + const char *filename, __u32 start_cluster, __u32 size, __u8 attr) +{ + set_start_cluster(mydata, dentptr, start_cluster); dentptr->size = cpu_to_le32(size); dentptr->attr = attr; @@ -1012,91 +1045,89 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, if (retdent) { /* Update file size and start_cluster in a directory entry */ retdent->size = cpu_to_le32(size); - start_cluster = FAT2CPU16(retdent->start); - if (mydata->fatsize == 32) - start_cluster |= - (FAT2CPU16(retdent->starthi) << 16); - - ret = check_overflow(mydata, start_cluster, size); - if (ret) { - printf("Error: %llu overflow\n", size); - goto exit; - } + start_cluster = START(retdent); + + if (start_cluster) { + if (size) { + ret = check_overflow(mydata, start_cluster, + size); + if (ret) { + printf("Error: %llu overflow\n", size); + goto exit; + } + } - ret = clear_fatent(mydata, start_cluster); - if (ret) { - printf("Error: clearing FAT entries\n"); - goto exit; - } + ret = clear_fatent(mydata, start_cluster); + if (ret) { + printf("Error: clearing FAT entries\n"); + goto exit; + } - ret = set_contents(mydata, retdent, buffer, size, actwrite); - if (ret < 0) { - printf("Error: writing contents\n"); - goto exit; - } - debug("attempt to write 0x%llx bytes\n", *actwrite); + if (!size) + set_start_cluster(mydata, retdent, 0); + } else if (size) { + ret = start_cluster = find_empty_cluster(mydata); + if (ret < 0) { + printf("Error: finding empty cluster\n"); + goto exit; + } - /* Flush fat buffer */ - ret = flush_fat_buffer(mydata); - if (ret) { - printf("Error: flush fat buffer\n"); - goto exit; - } + ret = check_overflow(mydata, start_cluster, size); + if (ret) { + printf("Error: %llu overflow\n", size); + goto exit; + } - /* Write directory table to device */ - ret = set_cluster(mydata, dir_curclust, - get_dentfromdir_block, - mydata->clust_size * mydata->sect_size); - if (ret) { - printf("Error: writing directory entry\n"); - goto exit; + set_start_cluster(mydata, retdent, start_cluster); } } else { /* Set short name to set alias checksum field in dir_slot */ set_name(empty_dentptr, filename); fill_dir_slot(mydata, &empty_dentptr, filename); - ret = start_cluster = find_empty_cluster(mydata); - if (ret < 0) { - printf("Error: finding empty cluster\n"); - goto exit; - } + if (size) { + ret = start_cluster = find_empty_cluster(mydata); + if (ret < 0) { + printf("Error: finding empty cluster\n"); + goto exit; + } - ret = check_overflow(mydata, start_cluster, size); - if (ret) { - printf("Error: %llu overflow\n", size); - goto exit; + ret = check_overflow(mydata, start_cluster, size); + if (ret) { + printf("Error: %llu overflow\n", size); + goto exit; + } + } else { + start_cluster = 0; } /* Set attribute as archieve for regular file */ fill_dentry(mydata, empty_dentptr, filename, start_cluster, size, 0x20); - ret = set_contents(mydata, empty_dentptr, buffer, size, - actwrite); - if (ret < 0) { - printf("Error: writing contents\n"); - goto exit; - } - debug("attempt to write 0x%llx bytes\n", *actwrite); + retdent = empty_dentptr; + } - /* Flush fat buffer */ - ret = flush_fat_buffer(mydata); - if (ret) { - printf("Error: flush fat buffer\n"); - goto exit; - } + ret = set_contents(mydata, retdent, buffer, size, actwrite); + if (ret < 0) { + printf("Error: writing contents\n"); + goto exit; + } + debug("attempt to write 0x%llx bytes\n", *actwrite); - /* Write directory table to device */ - ret = set_cluster(mydata, dir_curclust, - get_dentfromdir_block, - mydata->clust_size * mydata->sect_size); - if (ret) { - printf("Error: writing directory entry\n"); - goto exit; - } + /* Flush fat buffer */ + ret = flush_fat_buffer(mydata); + if (ret) { + printf("Error: flush fat buffer\n"); + goto exit; } + /* Write directory table to device */ + ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block, + mydata->clust_size * mydata->sect_size); + if (ret) + printf("Error: writing directory entry\n"); + exit: free(mydata->fatbuf); return ret; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 0bf52db..41763a1 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -28,6 +28,9 @@ #include <linux/writeback.h> #else +#include <common.h> +#include <malloc.h> +#include <memalign.h> #include <linux/compat.h> #include <linux/stat.h> #include <linux/err.h> diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index 4daa7fa..f7a0847 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -23,6 +23,8 @@ * Adrian Hunter */ +#include <common.h> +#include <memalign.h> #include "ubifs.h" #include <u-boot/zlib.h> |