aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-09-22 20:46:58 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-10-24 15:57:18 +0200
commit0e7b2348ea8fbfd9cb9fb532d552e27a9636010a (patch)
tree6a1352d49e1598e55ade71f922c92cb2a77ba78c
parent7f89eb3cfff465cf32d03a2ae6919252eae67e9b (diff)
libsqfs: Add the path lookup function back to the dir reader
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--extras/browse.c47
-rw-r--r--include/sqfs/dir_reader.h17
-rw-r--r--lib/sqfs/src/dir_reader.c75
3 files changed, 99 insertions, 40 deletions
diff --git a/extras/browse.c b/extras/browse.c
index 00e5dbe..70537f2 100644
--- a/extras/browse.c
+++ b/extras/browse.c
@@ -34,55 +34,22 @@ static char *prompt;
static int resolve_ref(const char *path, sqfs_u64 *out)
{
- sqfs_dir_reader_state_t state;
sqfs_inode_generic_t *inode;
- sqfs_dir_node_t *ent;
- const char *end;
sqfs_u64 ref;
- size_t len;
int ret;
- ref = *path == '/' ? super.root_inode_ref : working_dir;
-
- while (path != NULL && *path != '\0') {
- if (*path == '/') {
- while (*path == '/')
- ++path;
- continue;
- }
-
- end = strchr(path, '/');
- len = (end == NULL) ? strlen(path) : (size_t)(end - path);
-
- ret = sqfs_dir_reader_get_inode(dr, ref, &inode);
- if (ret != 0)
- return ret;
+ ref = (*path == '/') ? super.root_inode_ref : working_dir;
- ret = sqfs_dir_reader_open_dir(dr, inode, &state, 0);
+ ret = sqfs_dir_reader_get_inode(dr, ref, &inode);
+ if (ret == 0) {
+ ret = sqfs_dir_reader_resolve_path(dr, path, inode, &ref);
sqfs_free(inode);
- if (ret != 0)
- return ret;
-
- do {
- ret = sqfs_dir_reader_read(dr, &state, &ent);
- if (ret < 0)
- return ret;
- if (ret > 0)
- return 1;
-
- ret = strncmp((const char *)ent->name, path, len);
- free(ent);
- if (ret == 0 && ent->name[len] != '\0')
- return 1;
- } while (ret != 0);
-
- ref = state.ent_ref;
- path = end;
+ if (ret == 0)
+ *out = ref;
}
- *out = ref;
- return 0;
+ return ret;
}
static char *add_prefix(const char *pfx, size_t pfxlen, char *path)
diff --git a/include/sqfs/dir_reader.h b/include/sqfs/dir_reader.h
index ceac22b..50d3636 100644
--- a/include/sqfs/dir_reader.h
+++ b/include/sqfs/dir_reader.h
@@ -273,6 +273,23 @@ SQFS_API int sqfs_dir_reader_get_root_inode(sqfs_dir_reader_t *rd,
SQFS_API int sqfs_dir_reader_resolve_inum(sqfs_dir_reader_t *rd,
sqfs_u32 inode, sqfs_u64 *ref);
+/**
+ * @brief Try to resole a path into an inode reference
+ *
+ * @memberof sqfs_dir_reader_t
+ *
+ * @param rd A pointer to a directory reader.
+ * @param path A path to resolve, NULL is interpreted as empty path.
+ * @param root A directory inode to start from or NULL for the filesystem root.
+ * @param out Retrns an inode reference on success.
+ *
+ * @return Zero on success, a negative @ref SQFS_ERROR number on failure.
+ */
+SQFS_API int sqfs_dir_reader_resolve_path(sqfs_dir_reader_t *rd,
+ const char *path,
+ const sqfs_inode_generic_t *root,
+ sqfs_u64 *out);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/sqfs/src/dir_reader.c b/lib/sqfs/src/dir_reader.c
index 6920a7d..29d7c33 100644
--- a/lib/sqfs/src/dir_reader.c
+++ b/lib/sqfs/src/dir_reader.c
@@ -296,3 +296,78 @@ int sqfs_dir_reader_resolve_inum(sqfs_dir_reader_t *rd,
*ref = *((sqfs_u64 *)rbtree_node_value(node));
return 0;
}
+
+int sqfs_dir_reader_resolve_path(sqfs_dir_reader_t *rd, const char *path,
+ const sqfs_inode_generic_t *root,
+ sqfs_u64 *out)
+{
+ bool is_first = true;
+
+ while (path != NULL && *path != '\0') {
+ sqfs_dir_reader_state_t state;
+ int ret;
+
+ if (*path == '/') {
+ while (*path == '/')
+ ++path;
+ continue;
+ }
+
+ if (is_first && root != NULL) {
+ ret = sqfs_dir_reader_open_dir(rd, root, &state, 0);
+ } else {
+ sqfs_inode_generic_t *inode = NULL;
+
+ if (is_first)
+ *out = rd->super.root_inode_ref;
+
+ ret = sqfs_dir_reader_get_inode(rd, *out, &inode);
+ if (ret == 0) {
+ ret = sqfs_dir_reader_open_dir(rd, inode,
+ &state, 0);
+ }
+
+ sqfs_free(inode);
+ }
+
+ is_first = false;
+ if (ret != 0)
+ return ret;
+
+ for (;;) {
+ sqfs_dir_node_t *ent;
+ size_t len;
+
+ ret = sqfs_dir_reader_read(rd, &state, &ent);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ return SQFS_ERROR_NO_ENTRY;
+
+ len = ent->size + 1;
+ ret = strncmp((const char *)ent->name, path, len);
+ sqfs_free(ent);
+
+ if (ret == 0 &&
+ (path[len] == '/' || path[len] == '\0')) {
+ path += len;
+ break;
+ }
+ }
+
+ *out = state.ent_ref;
+ }
+
+ if (is_first) {
+ if (root == NULL) {
+ *out = rd->super.root_inode_ref;
+ return 0;
+ }
+
+ return sqfs_dir_reader_resolve_inum(rd,
+ root->base.inode_number,
+ out);
+ }
+
+ return 0;
+}