diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4_common.c | 76 | ||||
-rw-r--r-- | fs/ext4/ext4_common.h | 2 | ||||
-rw-r--r-- | fs/ext4/ext4_journal.c | 22 | ||||
-rw-r--r-- | fs/ext4/ext4_write.c | 66 | ||||
-rw-r--r-- | fs/ext4/ext4fs.c | 51 | ||||
-rw-r--r-- | fs/fat/fat.c | 47 | ||||
-rw-r--r-- | fs/fs.c | 44 |
7 files changed, 237 insertions, 71 deletions
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 67e2471bd3..464c33d0d7 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -190,7 +190,7 @@ uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) return res; } -void put_ext4(uint64_t off, void *buf, uint32_t size) +void put_ext4(uint64_t off, const void *buf, uint32_t size) { uint64_t startblock; uint64_t remainder; @@ -510,7 +510,8 @@ restart: restart_read: /* read the block no allocated to a file */ - first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx); + first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx, + NULL); if (first_block_no_of_root <= 0) goto fail; @@ -607,7 +608,7 @@ restart_read: dir->direntlen = cpu_to_le16(fs->blksz - totalbytes); dir->namelen = strlen(filename); - dir->filetype = FILETYPE_REG; /* regular file */ + dir->filetype = file_type; temp_dir = (char *)dir; temp_dir = temp_dir + sizeof(struct ext2_dirent); memcpy(temp_dir, filename, strlen(filename)); @@ -646,7 +647,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname) /* get the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(parent_inode, blk_idx); + blknr = read_allocated_block(parent_inode, blk_idx, NULL); if (blknr <= 0) goto fail; @@ -943,7 +944,7 @@ int ext4fs_filename_unlink(char *filename) /* read the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(g_parent_inode, blk_idx); + blknr = read_allocated_block(g_parent_inode, blk_idx, NULL); if (blknr <= 0) break; inodeno = unlink_filename(filename, blknr); @@ -1522,7 +1523,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, #endif static struct ext4_extent_header *ext4fs_get_extent_block - (struct ext2_data *data, char *buf, + (struct ext2_data *data, struct ext_block_cache *cache, struct ext4_extent_header *ext_block, uint32_t fileblock, int log2_blksz) { @@ -1546,17 +1547,19 @@ static struct ext4_extent_header *ext4fs_get_extent_block break; } while (fileblock >= le32_to_cpu(index[i].ei_block)); - if (--i < 0) - return NULL; + /* + * If first logical block number is higher than requested fileblock, + * it is a sparse file. This is handled on upper layer. + */ + if (i > 0) + i--; block = le16_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); - - if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz, - buf)) - ext_block = (struct ext4_extent_header *)buf; - else + block <<= log2_blksz; + if (!ext_cache_read(cache, (lbaint_t)block, blksz)) return NULL; + ext_block = (struct ext4_extent_header *)cache->buf; } } @@ -1584,7 +1587,7 @@ static int ext4fs_blockgroup int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) { - struct ext2_block_group blkgrp; + struct ext2_block_group *blkgrp; struct ext2_sblock *sblock = &data->sblock; struct ext_filesystem *fs = get_fs(); int log2blksz = get_fs()->dev_desc->log2blksz; @@ -1592,17 +1595,28 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) long int blkno; unsigned int blkoff; + /* Allocate blkgrp based on gdsize (for 64-bit support). */ + blkgrp = zalloc(get_fs()->gdsize); + if (!blkgrp) + return 0; + /* It is easier to calculate if the first inode is 0. */ ino--; status = ext4fs_blockgroup(data, ino / le32_to_cpu - (sblock->inodes_per_group), &blkgrp); - if (status == 0) + (sblock->inodes_per_group), blkgrp); + if (status == 0) { + free(blkgrp); return 0; + } inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; - blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) + + blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) + (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; blkoff = (ino % inodes_per_block) * fs->inodesz; + + /* Free blkgrp as it is no longer required. */ + free(blkgrp); + /* Read the inode. */ status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) - log2blksz), blkoff, @@ -1613,7 +1627,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) return 1; } -long int read_allocated_block(struct ext2_inode *inode, int fileblock) +long int read_allocated_block(struct ext2_inode *inode, int fileblock, + struct ext_block_cache *cache) { long int blknr; int blksz; @@ -1630,20 +1645,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { long int startblock, endblock; - char *buf = zalloc(blksz); - if (!buf) - return -ENOMEM; + struct ext_block_cache *c, cd; struct ext4_extent_header *ext_block; struct ext4_extent *extent; int i; + + if (cache) { + c = cache; + } else { + c = &cd; + ext_cache_init(c); + } ext_block = - ext4fs_get_extent_block(ext4fs_root, buf, + ext4fs_get_extent_block(ext4fs_root, c, (struct ext4_extent_header *) inode->b.blocks.dir_blocks, fileblock, log2_blksz); if (!ext_block) { printf("invalid extent block\n"); - free(buf); + if (!cache) + ext_cache_fini(c); return -EINVAL; } @@ -1655,19 +1676,22 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (startblock > fileblock) { /* Sparse file */ - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } else if (fileblock < endblock) { start = le16_to_cpu(extent[i].ee_start_hi); start = (start << 32) + le32_to_cpu(extent[i].ee_start_lo); - free(buf); + if (!cache) + ext_cache_fini(c); return (fileblock - startblock) + start; } } - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h index 1ee81ab7ce..4dff1914d9 100644 --- a/fs/ext4/ext4_common.h +++ b/fs/ext4/ext4_common.h @@ -72,7 +72,7 @@ int ext4fs_iget(int inode_no, struct ext2_inode *inode); void ext4fs_allocate_blocks(struct ext2_inode *file_inode, unsigned int total_remaining_blocks, unsigned int *total_no_of_block); -void put_ext4(uint64_t off, void *buf, uint32_t size); +void put_ext4(uint64_t off, const void *buf, uint32_t size); struct ext2_block_group *ext4fs_get_group_descriptor (const struct ext_filesystem *fs, uint32_t bg_idx); uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg, diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c index 148593da7f..6adbab93a6 100644 --- a/fs/ext4/ext4_journal.c +++ b/fs/ext4/ext4_journal.c @@ -347,7 +347,7 @@ void recover_transaction(int prev_desc_logical_no) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, (struct ext2_inode *)&inode_journal); blknr = read_allocated_block((struct ext2_inode *) - &inode_journal, i); + &inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); p_jdb = (char *)temp_buff; @@ -372,7 +372,7 @@ void recover_transaction(int prev_desc_logical_no) be32_to_cpu(jdb->h_sequence)) == 0) continue; } - blknr = read_allocated_block(&inode_journal, i); + blknr = read_allocated_block(&inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, metadata_buff); put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz), @@ -419,7 +419,8 @@ int ext4fs_check_journal_state(int recovery_flag) } ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); - blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK); + blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, + NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -443,7 +444,7 @@ int ext4fs_check_journal_state(int recovery_flag) i = be32_to_cpu(jsb->s_first); while (1) { - blknr = read_allocated_block(&inode_journal, i); + blknr = read_allocated_block(&inode_journal, i, NULL); memset(temp_buff1, '\0', fs->blksz); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff1); @@ -537,7 +538,7 @@ end: ext4_read_superblock((char *)fs->sb); blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), (struct journal_superblock_t *)temp_buff, (uint32_t) fs->blksz); @@ -566,7 +567,7 @@ static void update_descriptor_block(long int blknr) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -618,7 +619,7 @@ static void update_commit_block(long int blknr) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; @@ -645,16 +646,17 @@ void ext4fs_update_journal(void) long int blknr; int i; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL); update_descriptor_block(blknr); for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { if (journal_ptr[i]->blknr == -1) break; - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, + NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), journal_ptr[i]->buf, fs->blksz); } - blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++); + blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL); update_commit_block(blknr); printf("update journal finished\n"); } diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c index 4eb77c327e..504d23a895 100644 --- a/fs/ext4/ext4_write.c +++ b/fs/ext4/ext4_write.c @@ -465,6 +465,15 @@ static int ext4fs_delete_file(int inodeno) if (le32_to_cpu(inode.size) % fs->blksz) no_blocks++; + /* + * special case for symlinks whose target are small enough that + *it fits in struct ext2_inode.b.symlink: no block had been allocated + */ + if ((le16_to_cpu(inode.mode) & S_IFLNK) && + le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) { + no_blocks = 0; + } + if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */ struct ext4_extent_header *eh = @@ -479,7 +488,7 @@ static int ext4fs_delete_file(int inodeno) /* release data blocks */ for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(&inode, i); + blknr = read_allocated_block(&inode, i, NULL); if (blknr == 0) continue; if (blknr < 0) @@ -695,7 +704,7 @@ void ext4fs_deinit(void) ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); + EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *)temp_buff; @@ -752,7 +761,7 @@ void ext4fs_deinit(void) * contigous sectors as ext4fs_read_file */ static int ext4fs_write_file(struct ext2_inode *file_inode, - int pos, unsigned int len, char *buf) + int pos, unsigned int len, const char *buf) { int i; int blockcnt; @@ -764,7 +773,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, int delayed_start = 0; int delayed_extent = 0; int delayed_next = 0; - char *delayed_buf = NULL; + const char *delayed_buf = NULL; /* Adjust len so it we can't read past the end of the file. */ if (len > filesize) @@ -776,7 +785,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, long int blknr; int blockend = fs->blksz; int skipfirst = 0; - blknr = read_allocated_block(file_inode, i); + blknr = read_allocated_block(file_inode, i, NULL); if (blknr <= 0) return -1; @@ -816,7 +825,6 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, (uint32_t) delayed_extent); previous_block_number = -1; } - memset(buf, 0, fs->blksz - skipfirst); } buf += fs->blksz - skipfirst; } @@ -830,8 +838,8 @@ static int ext4fs_write_file(struct ext2_inode *file_inode, return len; } -int ext4fs_write(const char *fname, unsigned char *buffer, - unsigned long sizebytes) +int ext4fs_write(const char *fname, const char *buffer, + unsigned long sizebytes, int type) { int ret = 0; struct ext2_inode *file_inode = NULL; @@ -854,8 +862,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer, struct ext2_block_group *bgd = NULL; struct ext_filesystem *fs = get_fs(); ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); + bool store_link_in_inode = false; memset(filename, 0x00, 256); + if (type != FILETYPE_REG && type != FILETYPE_SYMLINK) + return -1; + g_parent_inode = zalloc(fs->inodesz); if (!g_parent_inode) goto fail; @@ -893,8 +905,16 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (ret) goto fail; } - /* calucalate how many blocks required */ - bytes_reqd_for_file = sizebytes; + + /* calculate how many blocks required */ + if (type == FILETYPE_SYMLINK && + sizebytes <= sizeof(file_inode->b.symlink)) { + store_link_in_inode = true; + bytes_reqd_for_file = 0; + } else { + bytes_reqd_for_file = sizebytes; + } + blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { blks_reqd_for_file++; @@ -907,7 +927,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, goto fail; } - inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG); + inodeno = ext4fs_update_parent_dentry(filename, type); if (inodeno == -1) goto fail; /* prepare file inode */ @@ -915,14 +935,23 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (!inode_buffer) goto fail; file_inode = (struct ext2_inode *)inode_buffer; - file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | - S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH); + file_inode->size = cpu_to_le32(sizebytes); + if (type == FILETYPE_SYMLINK) { + file_inode->mode = cpu_to_le16(S_IFLNK | S_IRWXU | S_IRWXG | + S_IRWXO); + if (store_link_in_inode) { + strncpy(file_inode->b.symlink, buffer, sizebytes); + sizebytes = 0; + } + } else { + file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP | + S_IROTH | S_IXGRP | S_IXOTH); + } /* ToDo: Update correct time */ file_inode->mtime = cpu_to_le32(timestamp); file_inode->atime = cpu_to_le32(timestamp); file_inode->ctime = cpu_to_le32(timestamp); file_inode->nlinks = cpu_to_le16(1); - file_inode->size = cpu_to_le32(sizebytes); /* Allocate data blocks */ ext4fs_allocate_blocks(file_inode, blocks_remaining, @@ -949,7 +978,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer, if (ext4fs_put_metadata(temp_ptr, itable_blkno)) goto fail; /* copy the file content into data blocks */ - if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { + if (ext4fs_write_file(file_inode, 0, sizebytes, buffer) == -1) { printf("Error in copying content\n"); /* FIXME: Deallocate data blocks */ goto fail; @@ -1014,7 +1043,7 @@ int ext4_write_file(const char *filename, void *buf, loff_t offset, return -1; } - ret = ext4fs_write(filename, buf, len); + ret = ext4fs_write(filename, buf, len, FILETYPE_REG); if (ret) { printf("** Error ext4fs_write() **\n"); goto fail; @@ -1029,3 +1058,8 @@ fail: return -1; } + +int ext4fs_create_link(const char *target, const char *fname) +{ + return ext4fs_write(fname, target, strlen(target), FILETYPE_SYMLINK); +} diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 2a28031d14..26db677a1f 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -62,6 +62,9 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, lbaint_t delayed_next = 0; char *delayed_buf = NULL; short status; + struct ext_block_cache cache; + + ext_cache_init(&cache); if (blocksize <= 0) return -1; @@ -77,9 +80,11 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, int blockoff = pos - (blocksize * i); int blockend = blocksize; int skipfirst = 0; - blknr = read_allocated_block(&(node->inode), i); - if (blknr < 0) + blknr = read_allocated_block(&node->inode, i, &cache); + if (blknr < 0) { + ext_cache_fini(&cache); return -1; + } blknr = blknr << log2_fs_blocksize; @@ -109,8 +114,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = blknr; delayed_start = blknr; delayed_extent = blockend; @@ -136,8 +143,10 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = -1; } /* Zero no more than `len' bytes. */ @@ -153,12 +162,15 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, status = ext4fs_devread(delayed_start, delayed_skipfirst, delayed_extent, delayed_buf); - if (status == 0) + if (status == 0) { + ext_cache_fini(&cache); return -1; + } previous_block_number = -1; } *actread = len; + ext_cache_fini(&cache); return 0; } @@ -252,3 +264,32 @@ int ext4fs_uuid(char *uuid_str) return -ENOSYS; #endif } + +void ext_cache_init(struct ext_block_cache *cache) +{ + memset(cache, 0, sizeof(*cache)); +} + +void ext_cache_fini(struct ext_block_cache *cache) +{ + free(cache->buf); + ext_cache_init(cache); +} + +int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size) +{ + /* This could be more lenient, but this is simple and enough for now */ + if (cache->buf && cache->block == block && cache->size == size) + return 1; + ext_cache_fini(cache); + cache->buf = malloc(size); + if (!cache->buf) + return 0; + if (!ext4fs_devread(block, 0, size, cache->buf)) { + free(cache->buf); + return 0; + } + cache->block = block; + cache->size = size; + return 1; +} diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 6ade4ea54e..c5997c2173 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -602,8 +602,13 @@ static int get_fs_info(fsdata *mydata) mydata->data_begin = mydata->rootdir_sect + mydata->rootdir_size - (mydata->clust_size * 2); - mydata->root_cluster = - sect_to_clust(mydata, mydata->rootdir_sect); + + /* + * The root directory is not cluster-aligned and may be on a + * "negative" cluster, this will be handled specially in + * next_cluster(). + */ + mydata->root_cluster = 0; } mydata->fatbufnum = -1; @@ -733,20 +738,38 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) itr->last_cluster = 0; } -static void *next_cluster(fat_itr *itr) +static void *next_cluster(fat_itr *itr, unsigned *nbytes) { fsdata *mydata = itr->fsdata; /* for silly macros */ int ret; u32 sect; + u32 read_size; /* have we reached the end? */ if (itr->last_cluster) return NULL; - sect = clust_to_sect(itr->fsdata, itr->next_clust); + if (itr->is_root && itr->fsdata->fatsize != 32) { + /* + * The root directory is located before the data area and + * cannot be indexed using the regular unsigned cluster + * numbers (it may start at a "negative" cluster or not at a + * cluster boundary at all), so consider itr->next_clust to be + * a offset in cluster-sized units from the start of rootdir. + */ + unsigned sect_offset = itr->next_clust * itr->fsdata->clust_size; + unsigned remaining_sects = itr->fsdata->rootdir_size - sect_offset; + sect = itr->fsdata->rootdir_sect + sect_offset; + /* do not read past the end of rootdir */ + read_size = min_t(u32, itr->fsdata->clust_size, + remaining_sects); + } else { + sect = clust_to_sect(itr->fsdata, itr->next_clust); + read_size = itr->fsdata->clust_size; + } - debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", - sect, itr->fsdata->clust_size, DIRENTSPERBLOCK); + debug("FAT read(sect=%d), clust_size=%d, read_size=%u, DIRENTSPERBLOCK=%zd\n", + sect, itr->fsdata->clust_size, read_size, DIRENTSPERBLOCK); /* * NOTE: do_fat_read_at() had complicated logic to deal w/ @@ -757,18 +780,17 @@ static void *next_cluster(fat_itr *itr) * dent at a time and iteratively constructing the vfat long * name. */ - ret = disk_read(sect, itr->fsdata->clust_size, - itr->block); + ret = disk_read(sect, read_size, itr->block); if (ret < 0) { debug("Error: reading block\n"); return NULL; } + *nbytes = read_size * itr->fsdata->sect_size; itr->clust = itr->next_clust; if (itr->is_root && itr->fsdata->fatsize != 32) { itr->next_clust++; - sect = clust_to_sect(itr->fsdata, itr->next_clust); - if (sect - itr->fsdata->rootdir_sect >= + if (itr->next_clust * itr->fsdata->clust_size >= itr->fsdata->rootdir_size) { debug("nextclust: 0x%x\n", itr->next_clust); itr->last_cluster = 1; @@ -787,9 +809,8 @@ static void *next_cluster(fat_itr *itr) static dir_entry *next_dent(fat_itr *itr) { if (itr->remaining == 0) { - struct dir_entry *dent = next_cluster(itr); - unsigned nbytes = itr->fsdata->sect_size * - itr->fsdata->clust_size; + unsigned nbytes; + struct dir_entry *dent = next_cluster(itr, &nbytes); /* have we reached the last cluster? */ if (!dent) { @@ -90,6 +90,11 @@ static inline int fs_write_unsupported(const char *filename, void *buf, return -1; } +static inline int fs_ln_unsupported(const char *filename, const char *target) +{ + return -1; +} + static inline void fs_close_unsupported(void) { } @@ -154,6 +159,7 @@ struct fstype_info { void (*closedir)(struct fs_dir_stream *dirs); int (*unlink)(const char *filename); int (*mkdir)(const char *dirname); + int (*ln)(const char *filename, const char *target); }; static struct fstype_info fstypes[] = { @@ -181,6 +187,7 @@ static struct fstype_info fstypes[] = { .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, + .ln = fs_ln_unsupported, }, #endif @@ -197,8 +204,10 @@ static struct fstype_info fstypes[] = { .read = ext4_read_file, #ifdef CONFIG_CMD_EXT4_WRITE .write = ext4_write_file, + .ln = ext4fs_create_link, #else .write = fs_write_unsupported, + .ln = fs_ln_unsupported, #endif .uuid = ext4fs_uuid, .opendir = fs_opendir_unsupported, @@ -222,6 +231,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, #endif #ifdef CONFIG_CMD_UBIFS @@ -240,6 +250,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, #endif #ifdef CONFIG_FS_BTRFS @@ -258,6 +269,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, #endif { @@ -275,6 +287,7 @@ static struct fstype_info fstypes[] = { .opendir = fs_opendir_unsupported, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, }, }; @@ -602,6 +615,22 @@ int fs_mkdir(const char *dirname) return ret; } +int fs_ln(const char *fname, const char *target) +{ + struct fstype_info *info = fs_get_info(fs_type); + int ret; + + ret = info->ln(fname, target); + + if (ret < 0) { + printf("** Unable to create link %s -> %s **\n", fname, target); + ret = -1; + } + fs_close(); + + return ret; +} + int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype) { @@ -840,3 +869,18 @@ int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], return 0; } + +int do_ln(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype) +{ + if (argc != 5) + return CMD_RET_USAGE; + + if (fs_set_blk_dev(argv[1], argv[2], fstype)) + return 1; + + if (fs_ln(argv[3], argv[4])) + return 1; + + return 0; +} |