summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extras/browse.c15
-rw-r--r--include/sqfs/inode.h21
-rw-r--r--lib/sqfs/inode.c44
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;
+}