diff options
-rw-r--r-- | extras/browse.c | 15 | ||||
-rw-r--r-- | include/sqfs/inode.h | 21 | ||||
-rw-r--r-- | lib/sqfs/inode.c | 44 |
3 files changed, 76 insertions, 4 deletions
diff --git a/extras/browse.c b/extras/browse.c index 1179b33..1d6417f 100644 --- a/extras/browse.c +++ b/extras/browse.c @@ -3,6 +3,7 @@ #include "sqfs/id_table.h" #include "sqfs/inode.h" #include "sqfs/super.h" +#include "sqfs/error.h" #include "sqfs/dir.h" #include "sqfs/io.h" @@ -358,16 +359,22 @@ static void stat_cmd(const char *filename) if (inode->data.dir_ext.size == 0) break; - idx = (sqfs_dir_index_t *)inode->extra; + for (i = 0; ; ++i) { + ret = sqfs_inode_unpack_dir_index_entry(inode, &idx, i); + if (ret == SQFS_ERROR_OUT_OF_BOUNDS) + break; + if (ret < 0) { + printf("Error reading index, error code %d\n", + ret); + break; + } - for (i = 0; i < inode->data.dir_ext.inodex_count; ++i) { printf("\tIndex: %u\n", idx->index); printf("\tStart block: %u\n", idx->start_block); printf("\tSize: %u\n", idx->size + 1); printf("\tEntry: %.*s\n\n", idx->size + 1, idx->name); - idx = (sqfs_dir_index_t *) - ((char *)idx + sizeof(*idx) + idx->size + 1); + free(idx); } break; } diff --git a/include/sqfs/inode.h b/include/sqfs/inode.h index 2b4a550..f2b6ede 100644 --- a/include/sqfs/inode.h +++ b/include/sqfs/inode.h @@ -696,6 +696,27 @@ SQFS_API int sqfs_inode_get_frag_location(const sqfs_inode_generic_t *inode, SQFS_API int sqfs_inode_get_file_block_start(const sqfs_inode_generic_t *inode, sqfs_u64 *location); +/** + * @brief Unpack the a directory index structure from an inode. + * + * The generic inode contains in its payload the raw directory index (with + * bytes swapped to host enian), but still with single byte alignment. This + * function seeks through the blob using an integer index (not offset) and + * fiddles the raw data out into a propperly aligned, external structure. + * + * @param inode A pointer to an inode. + * @param out Returns the index entry. Can be freed with a single free call. + * @param index An index value between 0 and inodex_count. + * + * @return Zero on success, @ref SQFS_ERROR_OUT_OF_BOUNDS if the given index + * points outside the directory index. Can return other error codes + * (e.g. if the inode isn't a directory or allocation failed). + */ +SQFS_API +int sqfs_inode_unpack_dir_index_entry(const sqfs_inode_generic_t *inode, + sqfs_dir_index_t **out, + size_t index); + #ifdef __cplusplus } #endif diff --git a/lib/sqfs/inode.c b/lib/sqfs/inode.c index bb1ccef..3a4ec09 100644 --- a/lib/sqfs/inode.c +++ b/lib/sqfs/inode.c @@ -9,10 +9,13 @@ #include "sqfs/inode.h" #include "sqfs/error.h" +#include "sqfs/dir.h" #include <string.h> #include <stdlib.h> +#include "util.h" + static int inverse_type[] = { [SQFS_INODE_DIR] = SQFS_INODE_EXT_DIR, [SQFS_INODE_FILE] = SQFS_INODE_EXT_FILE, @@ -386,3 +389,44 @@ int sqfs_inode_get_file_block_start(const sqfs_inode_generic_t *inode, return 0; } + +int sqfs_inode_unpack_dir_index_entry(const sqfs_inode_generic_t *inode, + sqfs_dir_index_t **out, + size_t index) +{ + sqfs_dir_index_t ent; + size_t offset; + char *ptr; + + if (inode->base.type != SQFS_INODE_EXT_DIR) { + if (inode->base.type == SQFS_INODE_DIR) + return SQFS_ERROR_OUT_OF_BOUNDS; + + return SQFS_ERROR_NOT_DIR; + } + + offset = 0; + ptr = (char *)inode->extra; + + for (;;) { + if (offset >= inode->num_dir_idx_bytes) + return SQFS_ERROR_OUT_OF_BOUNDS; + + if (index == 0) + break; + + memcpy(&ent, ptr + offset, sizeof(ent)); + offset += sizeof(ent) + ent.size + 1; + index -= 1; + } + + memcpy(&ent, ptr + offset, sizeof(ent)); + + *out = alloc_flex(sizeof(ent), 1, ent.size + 2); + if (*out == NULL) + return SQFS_ERROR_ALLOC; + + memcpy(*out, &ent, sizeof(ent)); + memcpy((*out)->name, ptr + offset + sizeof(ent), ent.size + 1); + return 0; +} |