diff options
Diffstat (limited to 'lib/sqfs')
-rw-r--r-- | lib/sqfs/dir_reader/dir_reader.c | 123 | ||||
-rw-r--r-- | lib/sqfs/dir_reader/internal.h | 10 | ||||
-rw-r--r-- | lib/sqfs/readdir.c | 95 |
3 files changed, 120 insertions, 108 deletions
diff --git a/lib/sqfs/dir_reader/dir_reader.c b/lib/sqfs/dir_reader/dir_reader.c index 8a074aa..5ed0eff 100644 --- a/lib/sqfs/dir_reader/dir_reader.c +++ b/lib/sqfs/dir_reader/dir_reader.c @@ -105,29 +105,24 @@ int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd, const sqfs_inode_generic_t *inode, sqfs_u32 flags) { - sqfs_u64 block_start; - size_t size, offset; sqfs_u32 parent; + int ret; if (flags & (~SQFS_DIR_OPEN_ALL_FLAGS)) return SQFS_ERROR_UNSUPPORTED; - if (inode->base.type == SQFS_INODE_DIR) { - parent = inode->data.dir.parent_inode; - size = inode->data.dir.size; - offset = inode->data.dir.offset; - block_start = inode->data.dir.start_block; - } else if (inode->base.type == SQFS_INODE_EXT_DIR) { - parent = inode->data.dir_ext.parent_inode; - size = inode->data.dir_ext.size; - offset = inode->data.dir_ext.offset; - block_start = inode->data.dir_ext.start_block; - } else { - return SQFS_ERROR_NOT_DIR; - } + ret = sqfs_readdir_state_init(&rd->it, rd->super, inode); + if (ret) + return ret; if ((rd->flags & SQFS_DIR_READER_DOT_ENTRIES) && !(flags & SQFS_DIR_OPEN_NO_DOT_ENTRIES)) { + if (inode->base.type == SQFS_INODE_EXT_DIR) { + parent = inode->data.dir_ext.parent_inode; + } else { + parent = inode->data.dir.parent_inode; + } + if (sqfs_dir_reader_dcache_find(rd, inode->base.inode_number, &rd->cur_ref)) { return SQFS_ERROR_NO_ENTRY; @@ -146,21 +141,7 @@ int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd, } rd->start_state = rd->state; - - memset(&rd->hdr, 0, sizeof(rd->hdr)); - rd->size = size; - rd->entries = 0; - - block_start += rd->super->directory_table_start; - - rd->dir_block_start = block_start; - rd->dir_offset = offset; - rd->start_size = size; - - if (rd->size <= sizeof(rd->hdr)) - return 0; - - return sqfs_meta_reader_seek(rd->meta_dir, block_start, offset); + return 0; } static int mk_dummy_entry(const char *str, sqfs_dir_entry_t **out) @@ -183,8 +164,6 @@ static int mk_dummy_entry(const char *str, sqfs_dir_entry_t **out) int sqfs_dir_reader_read(sqfs_dir_reader_t *rd, sqfs_dir_entry_t **out) { - sqfs_dir_entry_t *ent; - size_t count; int err; switch (rd->state) { @@ -207,41 +186,8 @@ int sqfs_dir_reader_read(sqfs_dir_reader_t *rd, sqfs_dir_entry_t **out) return SQFS_ERROR_SEQUENCE; } - if (!rd->entries) { - if (rd->size <= sizeof(rd->hdr)) - return 1; - - err = sqfs_meta_reader_read_dir_header(rd->meta_dir, &rd->hdr); - if (err) - return err; - - rd->size -= sizeof(rd->hdr); - rd->entries = rd->hdr.count + 1; - } - - if (rd->size <= sizeof(*ent)) { - rd->size = 0; - rd->entries = 0; - return 1; - } - - err = sqfs_meta_reader_read_dir_ent(rd->meta_dir, &ent); - if (err) - return err; - - count = sizeof(*ent) + strlen((const char *)ent->name); - - if (count > rd->size) { - rd->size = 0; - rd->entries = 0; - } else { - rd->size -= count; - rd->entries -= 1; - } - - rd->inode_offset = ent->offset; - *out = ent; - return 0; + return sqfs_meta_reader_readdir(rd->meta_dir, &rd->it, + out, NULL, &rd->ent_ref); } int sqfs_dir_reader_rewind(sqfs_dir_reader_t *rd) @@ -249,16 +195,9 @@ int sqfs_dir_reader_rewind(sqfs_dir_reader_t *rd) if (rd->state == DIR_STATE_NONE) return SQFS_ERROR_SEQUENCE; - memset(&rd->hdr, 0, sizeof(rd->hdr)); - rd->size = rd->start_size; - rd->entries = 0; + sqfs_readdir_state_reset(&rd->it); rd->state = rd->start_state; - - if (rd->size <= sizeof(rd->hdr)) - return 0; - - return sqfs_meta_reader_seek(rd->meta_dir, rd->dir_block_start, - rd->dir_offset); + return 0; } int sqfs_dir_reader_find(sqfs_dir_reader_t *rd, const char *name) @@ -266,14 +205,9 @@ int sqfs_dir_reader_find(sqfs_dir_reader_t *rd, const char *name) sqfs_dir_entry_t *ent; int ret; - if (rd->state == DIR_STATE_NONE) - return SQFS_ERROR_SEQUENCE; - - if (rd->size != rd->start_size || rd->state != rd->start_state) { - ret = sqfs_dir_reader_rewind(rd); - if (ret) - return ret; - } + ret = sqfs_dir_reader_rewind(rd); + if (ret != 0) + return ret; do { ret = sqfs_dir_reader_read(rd, &ent); @@ -292,36 +226,25 @@ int sqfs_dir_reader_find(sqfs_dir_reader_t *rd, const char *name) int sqfs_dir_reader_get_inode(sqfs_dir_reader_t *rd, sqfs_inode_generic_t **inode) { - sqfs_u64 block_start; - sqfs_u16 offset; + sqfs_u64 ref; int ret; switch (rd->state) { - case DIR_STATE_DOT: - block_start = rd->cur_ref >> 16; - offset = rd->cur_ref & 0x0FFFF; - break; - case DIR_STATE_DOT_DOT: - block_start = rd->parent_ref >> 16; - offset = rd->parent_ref & 0x0FFFF; - break; - case DIR_STATE_ENTRIES: - block_start = rd->hdr.start_block; - offset = rd->inode_offset; - break; + case DIR_STATE_DOT: ref = rd->cur_ref; break; + case DIR_STATE_DOT_DOT: ref = rd->parent_ref; break; + case DIR_STATE_ENTRIES: ref = rd->ent_ref; break; default: return SQFS_ERROR_SEQUENCE; } ret = sqfs_meta_reader_read_inode(rd->meta_inode, rd->super, - block_start, offset, inode); + ref >> 16, ref & 0x0FFFF, inode); if (ret != 0) return ret; if ((*inode)->base.type == SQFS_INODE_DIR || (*inode)->base.type == SQFS_INODE_EXT_DIR) { sqfs_u32 inum = (*inode)->base.inode_number; - sqfs_u64 ref = (block_start << 16) | rd->inode_offset; ret = sqfs_dir_reader_dcache_add(rd, inum, ref); if (ret != 0) diff --git a/lib/sqfs/dir_reader/internal.h b/lib/sqfs/dir_reader/internal.h index cd20b69..4dbe728 100644 --- a/lib/sqfs/dir_reader/internal.h +++ b/lib/sqfs/dir_reader/internal.h @@ -38,14 +38,7 @@ struct sqfs_dir_reader_t { sqfs_meta_reader_t *meta_inode; const sqfs_super_t *super; - sqfs_dir_header_t hdr; - sqfs_u64 dir_block_start; - size_t entries; - size_t size; - - size_t start_size; - sqfs_u16 dir_offset; - sqfs_u16 inode_offset; + sqfs_readdir_state_t it; sqfs_u32 flags; @@ -53,6 +46,7 @@ struct sqfs_dir_reader_t { int state; sqfs_u64 parent_ref; sqfs_u64 cur_ref; + sqfs_u64 ent_ref; rbtree_t dcache; }; diff --git a/lib/sqfs/readdir.c b/lib/sqfs/readdir.c index 8899475..e2dbcd4 100644 --- a/lib/sqfs/readdir.c +++ b/lib/sqfs/readdir.c @@ -9,6 +9,8 @@ #include "sqfs/meta_reader.h" #include "sqfs/error.h" +#include "sqfs/super.h" +#include "sqfs/inode.h" #include "sqfs/dir.h" #include "compat.h" @@ -64,3 +66,96 @@ int sqfs_meta_reader_read_dir_ent(sqfs_meta_reader_t *m, *result = out; return 0; } + +int sqfs_readdir_state_init(sqfs_readdir_state_t *s, const sqfs_super_t *super, + const sqfs_inode_generic_t *inode) +{ + memset(s, 0, sizeof(*s)); + + if (inode->base.type == SQFS_INODE_DIR) { + s->init.block = inode->data.dir.start_block; + s->init.offset = inode->data.dir.offset; + s->init.size = inode->data.dir.size; + } else if (inode->base.type == SQFS_INODE_EXT_DIR) { + s->init.block = inode->data.dir_ext.start_block; + s->init.offset = inode->data.dir_ext.offset; + s->init.size = inode->data.dir_ext.size; + } else { + return SQFS_ERROR_NOT_DIR; + } + + s->init.block += super->directory_table_start; + s->current = s->init; + return 0; +} + +int sqfs_meta_reader_readdir(sqfs_meta_reader_t *m, sqfs_readdir_state_t *it, + sqfs_dir_entry_t **ent, + sqfs_u32 *inum, sqfs_u64 *iref) +{ + size_t count; + int ret; + + if (it->entries == 0) { + sqfs_dir_header_t hdr; + + if (it->current.size <= sizeof(hdr)) + goto out_eof; + + ret = sqfs_meta_reader_seek(m, it->current.block, + it->current.offset); + if (ret != 0) + return ret; + + ret = sqfs_meta_reader_read_dir_header(m, &hdr); + if (ret != 0) + return ret; + + sqfs_meta_reader_get_position(m, &it->current.block, + &it->current.offset); + + it->current.size -= sizeof(hdr); + it->entries = hdr.count + 1; + it->inum_base = hdr.inode_number; + it->inode_block = hdr.start_block; + } + + if (it->current.size <= sizeof(**ent)) + goto out_eof; + + ret = sqfs_meta_reader_seek(m, it->current.block, it->current.offset); + if (ret != 0) + return ret; + + ret = sqfs_meta_reader_read_dir_ent(m, ent); + if (ret) + return ret; + + sqfs_meta_reader_get_position(m, &it->current.block, + &it->current.offset); + + it->current.size -= sizeof(**ent); + it->entries -= 1; + + count = (*ent)->size + 1; + + if (count >= it->current.size) { + it->current.size = 0; + } else { + it->current.size -= count; + } + + if (inum != NULL) + *inum = it->inum_base + (*ent)->inode_diff; + + if (iref != NULL) { + *iref = (sqfs_u64)it->inode_block << 16UL; + *iref |= (*ent)->offset; + } + + return 0; +out_eof: + it->current.size = 0; + it->entries = 0; + return 1; +} |