summaryrefslogtreecommitdiff
path: root/lib/sqfs/dir_reader/dir_reader.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqfs/dir_reader/dir_reader.c')
-rw-r--r--lib/sqfs/dir_reader/dir_reader.c166
1 files changed, 146 insertions, 20 deletions
diff --git a/lib/sqfs/dir_reader/dir_reader.c b/lib/sqfs/dir_reader/dir_reader.c
index 969b71d..8a074aa 100644
--- a/lib/sqfs/dir_reader/dir_reader.c
+++ b/lib/sqfs/dir_reader/dir_reader.c
@@ -11,6 +11,7 @@ static void dir_reader_destroy(sqfs_object_t *obj)
{
sqfs_dir_reader_t *rd = (sqfs_dir_reader_t *)obj;
+ sqfs_dir_reader_dcache_cleanup(rd);
sqfs_destroy(rd->meta_inode);
sqfs_destroy(rd->meta_dir);
free(rd);
@@ -26,6 +27,9 @@ static sqfs_object_t *dir_reader_copy(const sqfs_object_t *obj)
memcpy(copy, rd, sizeof(*copy));
+ if (sqfs_dir_reader_dcache_init_copy(copy, rd))
+ goto fail_cache;
+
copy->meta_inode = sqfs_copy(rd->meta_inode);
if (copy->meta_inode == NULL)
goto fail_mino;
@@ -38,6 +42,8 @@ static sqfs_object_t *dir_reader_copy(const sqfs_object_t *obj)
fail_mdir:
sqfs_destroy(copy->meta_inode);
fail_mino:
+ sqfs_dir_reader_dcache_cleanup(copy);
+fail_cache:
free(copy);
return NULL;
}
@@ -50,22 +56,22 @@ sqfs_dir_reader_t *sqfs_dir_reader_create(const sqfs_super_t *super,
sqfs_dir_reader_t *rd;
sqfs_u64 start, limit;
- if (flags != 0)
+ if (flags & ~SQFS_DIR_READER_ALL_FLAGS)
return NULL;
rd = calloc(1, sizeof(*rd));
if (rd == NULL)
return NULL;
+ if (sqfs_dir_reader_dcache_init(rd, flags))
+ goto fail_dcache;
+
start = super->inode_table_start;
limit = super->directory_table_start;
rd->meta_inode = sqfs_meta_reader_create(file, cmp, start, limit);
-
- if (rd->meta_inode == NULL) {
- free(rd);
- return NULL;
- }
+ if (rd->meta_inode == NULL)
+ goto fail_mino;
start = super->directory_table_start;
limit = super->id_table_start;
@@ -77,17 +83,22 @@ sqfs_dir_reader_t *sqfs_dir_reader_create(const sqfs_super_t *super,
limit = super->export_table_start;
rd->meta_dir = sqfs_meta_reader_create(file, cmp, start, limit);
-
- if (rd->meta_dir == NULL) {
- sqfs_destroy(rd->meta_inode);
- free(rd);
- return NULL;
- }
+ if (rd->meta_dir == NULL)
+ goto fail_mdir;
((sqfs_object_t *)rd)->destroy = dir_reader_destroy;
((sqfs_object_t *)rd)->copy = dir_reader_copy;
rd->super = super;
+ rd->flags = flags;
+ rd->state = DIR_STATE_NONE;
return rd;
+fail_mdir:
+ sqfs_destroy(rd->meta_inode);
+fail_mino:
+ sqfs_dir_reader_dcache_cleanup(rd);
+fail_dcache:
+ free(rd);
+ return NULL;
}
int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd,
@@ -96,15 +107,18 @@ int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd,
{
sqfs_u64 block_start;
size_t size, offset;
+ sqfs_u32 parent;
- if (flags != 0)
+ 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;
@@ -112,6 +126,27 @@ int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd,
return SQFS_ERROR_NOT_DIR;
}
+ if ((rd->flags & SQFS_DIR_READER_DOT_ENTRIES) &&
+ !(flags & SQFS_DIR_OPEN_NO_DOT_ENTRIES)) {
+ if (sqfs_dir_reader_dcache_find(rd, inode->base.inode_number,
+ &rd->cur_ref)) {
+ return SQFS_ERROR_NO_ENTRY;
+ }
+
+ if (rd->cur_ref == rd->super->root_inode_ref) {
+ rd->parent_ref = rd->cur_ref;
+ } else if (sqfs_dir_reader_dcache_find(rd, parent,
+ &rd->parent_ref)) {
+ return SQFS_ERROR_NO_ENTRY;
+ }
+
+ rd->state = DIR_STATE_OPENED;
+ } else {
+ rd->state = DIR_STATE_ENTRIES;
+ }
+
+ rd->start_state = rd->state;
+
memset(&rd->hdr, 0, sizeof(rd->hdr));
rd->size = size;
rd->entries = 0;
@@ -128,12 +163,50 @@ int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd,
return sqfs_meta_reader_seek(rd->meta_dir, block_start, offset);
}
+static int mk_dummy_entry(const char *str, sqfs_dir_entry_t **out)
+{
+ size_t len = strlen(str);
+ sqfs_dir_entry_t *ent;
+
+ ent = calloc(1, sizeof(sqfs_dir_entry_t) + len + 1);
+ if (ent == NULL)
+ return SQFS_ERROR_ALLOC;
+
+ ent->type = SQFS_INODE_DIR;
+ ent->size = len - 1;
+
+ strcpy((char *)ent->name, str);
+
+ *out = ent;
+ return 0;
+}
+
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) {
+ case DIR_STATE_OPENED:
+ err = mk_dummy_entry(".", out);
+ if (err == 0)
+ rd->state = DIR_STATE_DOT;
+ return err;
+ case DIR_STATE_DOT:
+ err = mk_dummy_entry("..", out);
+ if (err == 0)
+ rd->state = DIR_STATE_DOT_DOT;
+ return err;
+ case DIR_STATE_DOT_DOT:
+ rd->state = DIR_STATE_ENTRIES;
+ break;
+ case DIR_STATE_ENTRIES:
+ break;
+ default:
+ return SQFS_ERROR_SEQUENCE;
+ }
+
if (!rd->entries) {
if (rd->size <= sizeof(rd->hdr))
return 1;
@@ -173,9 +246,13 @@ int sqfs_dir_reader_read(sqfs_dir_reader_t *rd, sqfs_dir_entry_t **out)
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;
+ rd->state = rd->start_state;
if (rd->size <= sizeof(rd->hdr))
return 0;
@@ -189,7 +266,10 @@ int sqfs_dir_reader_find(sqfs_dir_reader_t *rd, const char *name)
sqfs_dir_entry_t *ent;
int ret;
- if (rd->size != rd->start_size) {
+ 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;
@@ -213,12 +293,42 @@ int sqfs_dir_reader_get_inode(sqfs_dir_reader_t *rd,
sqfs_inode_generic_t **inode)
{
sqfs_u64 block_start;
+ sqfs_u16 offset;
+ 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;
+ default:
+ return SQFS_ERROR_SEQUENCE;
+ }
- block_start = rd->hdr.start_block;
+ ret = sqfs_meta_reader_read_inode(rd->meta_inode, rd->super,
+ block_start, offset, inode);
+ if (ret != 0)
+ return ret;
- return sqfs_meta_reader_read_inode(rd->meta_inode, rd->super,
- block_start, rd->inode_offset,
- inode);
+ 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)
+ return ret;
+ }
+
+ return 0;
}
int sqfs_dir_reader_get_root_inode(sqfs_dir_reader_t *rd,
@@ -226,7 +336,23 @@ int sqfs_dir_reader_get_root_inode(sqfs_dir_reader_t *rd,
{
sqfs_u64 block_start = rd->super->root_inode_ref >> 16;
sqfs_u16 offset = rd->super->root_inode_ref & 0xFFFF;
+ int ret;
+
+ ret = sqfs_meta_reader_read_inode(rd->meta_inode, rd->super,
+ block_start, offset, inode);
- return sqfs_meta_reader_read_inode(rd->meta_inode, rd->super,
- block_start, offset, 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 = rd->super->root_inode_ref;
+
+ ret = sqfs_dir_reader_dcache_add(rd, inum, ref);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
}