diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4_common.c | 48 | ||||
-rw-r--r-- | fs/ext4/ext4fs.c | 177 | ||||
-rw-r--r-- | fs/fs.c | 6 |
3 files changed, 171 insertions, 60 deletions
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 76f7102456e..cc150cf824f 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -2046,24 +2046,23 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, unsigned int fpos = 0; int status; loff_t actread; - struct ext2fs_node *diro = (struct ext2fs_node *) dir; #ifdef DEBUG if (name != NULL) printf("Iterate dir %s\n", name); #endif /* of DEBUG */ - if (!diro->inode_read) { - status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); + if (!dir->inode_read) { + status = ext4fs_read_inode(dir->data, dir->ino, &dir->inode); if (status == 0) return 0; } /* Search the file. */ - while (fpos < le32_to_cpu(diro->inode.size)) { + while (fpos < le32_to_cpu(dir->inode.size)) { struct ext2_dirent dirent; - status = ext4fs_read_file(diro, fpos, - sizeof(struct ext2_dirent), - (char *)&dirent, &actread); + status = ext4fs_read_file(dir, fpos, + sizeof(struct ext2_dirent), + (char *)&dirent, &actread); if (status < 0) return 0; @@ -2077,7 +2076,7 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, struct ext2fs_node *fdiro; int type = FILETYPE_UNKNOWN; - status = ext4fs_read_file(diro, + status = ext4fs_read_file(dir, fpos + sizeof(struct ext2_dirent), dirent.namelen, filename, @@ -2089,7 +2088,7 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, if (!fdiro) return 0; - fdiro->data = diro->data; + fdiro->data = dir->data; fdiro->ino = le32_to_cpu(dirent.inode); filename[dirent.namelen] = '\0'; @@ -2104,7 +2103,7 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, else if (dirent.filetype == FILETYPE_REG) type = FILETYPE_REG; } else { - status = ext4fs_read_inode(diro->data, + status = ext4fs_read_inode(dir->data, le32_to_cpu (dirent.inode), &fdiro->inode); @@ -2138,35 +2137,6 @@ int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, *fnode = fdiro; return 1; } - } else { - if (fdiro->inode_read == 0) { - status = ext4fs_read_inode(diro->data, - le32_to_cpu( - dirent.inode), - &fdiro->inode); - if (status == 0) { - free(fdiro); - return 0; - } - fdiro->inode_read = 1; - } - switch (type) { - case FILETYPE_DIRECTORY: - printf("<DIR> "); - break; - case FILETYPE_SYMLINK: - printf("<SYM> "); - break; - case FILETYPE_REG: - printf(" "); - break; - default: - printf("< ? > "); - break; - } - printf("%10u %s\n", - le32_to_cpu(fdiro->inode.size), - filename); } free(fdiro); } diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 15587e92e3e..dfecfa0b4e8 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -21,17 +21,36 @@ */ #include <blk.h> +#include <div64.h> +#include <errno.h> #include <ext_common.h> #include <ext4fs.h> -#include "ext4_common.h" -#include <div64.h> #include <malloc.h> #include <part.h> #include <u-boot/uuid.h> +#include "ext4_common.h" int ext4fs_symlinknest; struct ext_filesystem ext_fs; +/** + * struct ext4_dir_stream - ext4 directory stream + * + * @parent: partition data used by fs layer. + * This field must be at the beginning of the structure. + * All other fields are private to the ext4 driver. + * @root: root directory node + * @dir: directory node + * @dirent: directory stream entry + * @fpos: file position in directory + */ +struct ext4_dir_stream { + struct fs_dir_stream parent; + char *dirname; + struct fs_dirent dirent; + unsigned int fpos; +}; + struct ext_filesystem *get_fs(void) { return &ext_fs; @@ -182,39 +201,159 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, return 0; } -int ext4fs_ls(const char *dirname) +int ext4fs_opendir(const char *dirname, struct fs_dir_stream **dirsp) { - struct ext2fs_node *dirnode = NULL; - int status; + struct ext4_dir_stream *dirs; + struct ext2fs_node *dir = NULL; + int ret; - if (dirname == NULL) - return 0; + *dirsp = NULL; - status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, - FILETYPE_DIRECTORY); - if (status != 1) { - printf("** Can not find directory. **\n"); - if (dirnode) - ext4fs_free_node(dirnode, &ext4fs_root->diropen); - return 1; + dirs = calloc(1, sizeof(struct ext4_dir_stream)); + if (!dirs) + return -ENOMEM; + dirs->dirname = strdup(dirname); + if (!dirs) { + free(dirs); + return -ENOMEM; } - ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); - ext4fs_free_node(dirnode, &ext4fs_root->diropen); + ret = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dir, + FILETYPE_DIRECTORY); + if (ret == 1) { + ret = 0; + *dirsp = (struct fs_dir_stream *)dirs; + } else { + ret = -ENOENT; + } - return 0; + if (dir) + ext4fs_free_node(dir, &ext4fs_root->diropen); + + return ret; +} + +int ext4fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp) +{ + struct ext4_dir_stream *dirs = (struct ext4_dir_stream *)fs_dirs; + struct fs_dirent *dent = &dirs->dirent; + struct ext2fs_node *dir = NULL; + int ret; + loff_t actread; + struct ext2fs_node fdiro; + int len; + struct ext2_dirent dirent; + + *dentp = NULL; + + ret = ext4fs_find_file(dirs->dirname, &ext4fs_root->diropen, &dir, + FILETYPE_DIRECTORY); + if (ret != 1) { + ret = -ENOENT; + goto out; + } + if (!dir->inode_read) { + ret = ext4fs_read_inode(dir->data, dir->ino, &dir->inode); + if (!ret) { + ret = -EIO; + goto out; + } + } + + if (dirs->fpos >= le32_to_cpu(dir->inode.size)) + return -ENOENT; + + memset(dent, 0, sizeof(struct fs_dirent)); + + while (dirs->fpos < le32_to_cpu(dir->inode.size)) { + ret = ext4fs_read_file(dir, dirs->fpos, + sizeof(struct ext2_dirent), + (char *)&dirent, &actread); + if (ret < 0) + return -ret; + + if (!dirent.direntlen) + return -EIO; + + if (dirent.namelen) + break; + + dirs->fpos += le16_to_cpu(dirent.direntlen); + } + + len = min(FS_DIRENT_NAME_LEN - 1, (int)dirent.namelen); + + ret = ext4fs_read_file(dir, dirs->fpos + sizeof(struct ext2_dirent), + len, dent->name, &actread); + if (ret < 0) + goto out; + dent->name[len] = '\0'; + + fdiro.data = dir->data; + fdiro.ino = le32_to_cpu(dirent.inode); + + ret = ext4fs_read_inode(dir->data, fdiro.ino, &fdiro.inode); + if (!ret) { + ret = -EIO; + goto out; + } + + switch (le16_to_cpu(fdiro.inode.mode) & FILETYPE_INO_MASK) { + case FILETYPE_INO_DIRECTORY: + dent->type = FS_DT_DIR; + break; + case FILETYPE_INO_SYMLINK: + dent->type = FS_DT_LNK; + break; + case FILETYPE_INO_REG: + dent->type = FS_DT_REG; + break; + default: + dent->type = FILETYPE_UNKNOWN; + } + + rtc_to_tm(fdiro.inode.atime, &dent->access_time); + rtc_to_tm(fdiro.inode.ctime, &dent->create_time); + rtc_to_tm(fdiro.inode.mtime, &dent->change_time); + + dirs->fpos += le16_to_cpu(dirent.direntlen); + dent->size = fdiro.inode.size; + *dentp = dent; + ret = 0; + +out: + if (dir) + ext4fs_free_node(dir, &ext4fs_root->diropen); + + return ret; +} + +void ext4fs_closedir(struct fs_dir_stream *fs_dirs) +{ + struct ext4_dir_stream *dirs = (struct ext4_dir_stream *)fs_dirs; + + if (!dirs) + return; + + free(dirs->dirname); + free(dirs); } int ext4fs_exists(const char *filename) { struct ext2fs_node *dirnode = NULL; int filetype; + int ret; if (!filename) return 0; - return ext4fs_find_file1(filename, &ext4fs_root->diropen, &dirnode, - &filetype); + ret = ext4fs_find_file1(filename, &ext4fs_root->diropen, &dirnode, + &filetype); + if (dirnode) + ext4fs_free_node(dirnode, &ext4fs_root->diropen); + + return ret; } int ext4fs_size(const char *filename, loff_t *size) @@ -220,7 +220,7 @@ static struct fstype_info fstypes[] = { .null_dev_desc_ok = false, .probe = ext4fs_probe, .close = ext4fs_close, - .ls = ext4fs_ls, + .ls = fs_ls_generic, .exists = ext4fs_exists, .size = ext4fs_size, .read = ext4_read_file, @@ -232,7 +232,9 @@ static struct fstype_info fstypes[] = { .ln = fs_ln_unsupported, #endif .uuid = ext4fs_uuid, - .opendir = fs_opendir_unsupported, + .opendir = ext4fs_opendir, + .readdir = ext4fs_readdir, + .closedir = ext4fs_closedir, .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, }, |