diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-03 15:49:47 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-03 15:49:47 +0000 |
commit | 3cc3559fdf6f774cc522953484f91075352a84c8 (patch) | |
tree | 25a37c478eabdeaabeb7e5c38e6558dc272cc362 /lib/dir.c | |
parent | 5ff981c61150de1c5402b8db27252fa35b81167d (diff) | |
parent | 3888d132f2cfbf66afa3149706c77a48535c80fc (diff) | |
download | erofs-utils-3cc3559fdf6f774cc522953484f91075352a84c8.tar.gz |
Snap for 10428683 from 3888d132f2cfbf66afa3149706c77a48535c80fc to mainline-adbd-releaseaml_adb_341520010aml_adb_341517070aml_adb_340912530aml_adb_340912350aml_adb_340912200aml_adb_340912000android14-mainline-adbd-release
Change-Id: I6cec967dc0f21b6fe4df1fa5bf2658478c23f1d7
Diffstat (limited to 'lib/dir.c')
-rw-r--r-- | lib/dir.c | 109 |
1 files changed, 105 insertions, 4 deletions
@@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 -#include "erofs/print.h" -#include "erofs/dir.h" #include <stdlib.h> #include <sys/stat.h> +#include "erofs/print.h" +#include "erofs/dir.h" static int traverse_dirents(struct erofs_dir_context *ctx, void *dentry_blk, unsigned int lblk, @@ -127,7 +127,7 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck) erofs_off_t pos; char buf[EROFS_BLKSIZ]; - if ((dir->i_mode & S_IFMT) != S_IFDIR) + if (!S_ISDIR(dir->i_mode)) return -ENOTDIR; ctx->flags &= ~EROFS_READDIR_ALL_SPECIAL_FOUND; @@ -148,7 +148,7 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck) nameoff = le16_to_cpu(de->nameoff); if (nameoff < sizeof(struct erofs_dirent) || - nameoff >= PAGE_SIZE) { + nameoff >= EROFS_BLKSIZ) { erofs_err("invalid de[0].nameoff %u @ nid %llu, lblk %u", nameoff, dir->nid | 0ULL, lblk); return -EFSCORRUPTED; @@ -167,3 +167,104 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck) } return err; } + +#define EROFS_PATHNAME_FOUND 1 + +struct erofs_get_pathname_context { + struct erofs_dir_context ctx; + erofs_nid_t target_nid; + char *buf; + size_t size; + size_t pos; +}; + +static int erofs_get_pathname_iter(struct erofs_dir_context *ctx) +{ + int ret; + struct erofs_get_pathname_context *pathctx = (void *)ctx; + const char *dname = ctx->dname; + size_t len = ctx->de_namelen; + size_t pos = pathctx->pos; + + if (ctx->dot_dotdot) + return 0; + + if (ctx->de_nid == pathctx->target_nid) { + if (pos + len + 2 > pathctx->size) { + erofs_err("get_pathname buffer not large enough: len %zd, size %zd", + pos + len + 2, pathctx->size); + return -ERANGE; + } + + pathctx->buf[pos++] = '/'; + strncpy(pathctx->buf + pos, dname, len); + pathctx->buf[pos + len] = '\0'; + return EROFS_PATHNAME_FOUND; + } + + if (ctx->de_ftype == EROFS_FT_DIR || ctx->de_ftype == EROFS_FT_UNKNOWN) { + struct erofs_inode dir = { .nid = ctx->de_nid }; + + ret = erofs_read_inode_from_disk(&dir); + if (ret) { + erofs_err("read inode failed @ nid %llu", dir.nid | 0ULL); + return ret; + } + + if (S_ISDIR(dir.i_mode)) { + ctx->dir = &dir; + pathctx->pos = pos + len + 1; + ret = erofs_iterate_dir(ctx, false); + pathctx->pos = pos; + if (ret == EROFS_PATHNAME_FOUND) { + pathctx->buf[pos++] = '/'; + strncpy(pathctx->buf + pos, dname, len); + } + return ret; + } else if (ctx->de_ftype == EROFS_FT_DIR) { + erofs_err("i_mode and file_type are inconsistent @ nid %llu", + dir.nid | 0ULL); + } + } + return 0; +} + +int erofs_get_pathname(erofs_nid_t nid, char *buf, size_t size) +{ + int ret; + struct erofs_inode root = { .nid = sbi.root_nid }; + struct erofs_get_pathname_context pathctx = { + .ctx.flags = 0, + .ctx.dir = &root, + .ctx.cb = erofs_get_pathname_iter, + .target_nid = nid, + .buf = buf, + .size = size, + .pos = 0, + }; + + if (nid == root.nid) { + if (size < 2) { + erofs_err("get_pathname buffer not large enough: len 2, size %zd", + size); + return -ERANGE; + } + + buf[0] = '/'; + buf[1] = '\0'; + return 0; + } + + ret = erofs_read_inode_from_disk(&root); + if (ret) { + erofs_err("read inode failed @ nid %llu", root.nid | 0ULL); + return ret; + } + + ret = erofs_iterate_dir(&pathctx.ctx, false); + if (ret == EROFS_PATHNAME_FOUND) + return 0; + if (!ret) + return -ENOENT; + return ret; +} |