From 0e7b2348ea8fbfd9cb9fb532d552e27a9636010a Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Fri, 22 Sep 2023 20:46:58 +0200 Subject: libsqfs: Add the path lookup function back to the dir reader Signed-off-by: David Oberhollenzer --- extras/browse.c | 47 +++++------------------------ include/sqfs/dir_reader.h | 17 +++++++++++ lib/sqfs/src/dir_reader.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 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; +} -- cgit v1.2.3