All of lore.kernel.org
 help / color / mirror / Atom feed
* erofs-utils: lib: add API to get pathname of EROFS inode
@ 2021-12-17 12:30 Igor Eisberg
  2021-12-17 14:20 ` Igor Eisberg
  2021-12-18  0:52 ` Gao Xiang
  0 siblings, 2 replies; 4+ messages in thread
From: Igor Eisberg @ 2021-12-17 12:30 UTC (permalink / raw)
  To: linux-erofs


[-- Attachment #1.1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #1.2: Type: text/html, Size: 26 bytes --]

[-- Attachment #2: 0001-erofs-utils-lib-add-API-to-get-pathname-of-EROFS-ino.patch --]
[-- Type: application/octet-stream, Size: 7289 bytes --]

From 3061d65ebab01802782bfe791b829bc00b386f91 Mon Sep 17 00:00:00 2001
From: Igor Ostapenko <igoreisberg@gmail.com>
Date: Fri, 17 Dec 2021 14:08:23 +0200
Subject: erofs-utils: lib: add API to get pathname of EROFS inode

* General-purpose erofs_get_pathname function utilizing erofs_iterate_dir,
  with recursion and a reused context to avoid overflowing the stack.
  Recommended buffer size is PATH_MAX. Zero-filling the buffer is not
  necessary.
* dump: PATH_MAX+1 is not required since the definition of PATH_MAX is
  "chars in a path name including nul".
* Fix missing ctx->de_ftype = de->file_type; in traverse_dirents
  (was never set).
* Return err from erofs_iterate_dir instead of hardcoded 0, to allow
  breaking the iteration by the callback using a non-zero return code.

Signed-off-by: Igor Ostapenko <igoreisberg@gmail.com>
---
 dump/main.c         | 72 ++--------------------------------
 include/erofs/dir.h |  1 +
 lib/dir.c           | 96 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 98 insertions(+), 71 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index 7f3f743..3c3cc3f 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -328,71 +328,6 @@ static inline int erofs_checkdirent(struct erofs_dirent *de,
 	return dname_len;
 }
 
-static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
-		erofs_nid_t target, char *path, unsigned int pos)
-{
-	int err;
-	erofs_off_t offset;
-	char buf[EROFS_BLKSIZ];
-	struct erofs_inode inode = { .nid = nid };
-
-	path[pos++] = '/';
-	if (target == sbi.root_nid)
-		return 0;
-
-	err = erofs_read_inode_from_disk(&inode);
-	if (err) {
-		erofs_err("read inode failed @ nid %llu", nid | 0ULL);
-		return err;
-	}
-
-	offset = 0;
-	while (offset < inode.i_size) {
-		erofs_off_t maxsize = min_t(erofs_off_t,
-					inode.i_size - offset, EROFS_BLKSIZ);
-		struct erofs_dirent *de = (void *)buf;
-		struct erofs_dirent *end;
-		unsigned int nameoff;
-
-		err = erofs_pread(&inode, buf, maxsize, offset);
-		if (err)
-			return err;
-
-		nameoff = le16_to_cpu(de->nameoff);
-		end = (void *)buf + nameoff;
-		while (de < end) {
-			const char *dname;
-			int len;
-
-			nameoff = le16_to_cpu(de->nameoff);
-			dname = (char *)buf + nameoff;
-			len = erofs_checkdirent(de, end, maxsize, dname);
-			if (len < 0)
-				return len;
-
-			if (le64_to_cpu(de->nid) == target) {
-				memcpy(path + pos, dname, len);
-				path[pos + len] = '\0';
-				return 0;
-			}
-
-			if (de->file_type == EROFS_FT_DIR &&
-			    le64_to_cpu(de->nid) != parent_nid &&
-			    le64_to_cpu(de->nid) != nid) {
-				memcpy(path + pos, dname, len);
-				err = erofs_get_pathname(le64_to_cpu(de->nid),
-						nid, target, path, pos + len);
-				if (!err)
-					return 0;
-				memset(path + pos, 0, len);
-			}
-			++de;
-		}
-		offset += maxsize;
-	}
-	return -1;
-}
-
 static int erofsdump_map_blocks(struct erofs_inode *inode,
 		struct erofs_map_blocks *map, int flags)
 {
@@ -411,7 +346,7 @@ static void erofsdump_show_fileinfo(bool show_extent)
 	erofs_off_t size;
 	u16 access_mode;
 	struct erofs_inode inode = { .nid = dumpcfg.nid };
-	char path[PATH_MAX + 1] = {0};
+	char path[PATH_MAX];
 	char access_mode_str[] = "rwxrwxrwx";
 	char timebuf[128] = {0};
 	unsigned int extent_count = 0;
@@ -441,8 +376,7 @@ static void erofsdump_show_fileinfo(bool show_extent)
 		return;
 	}
 
-	err = erofs_get_pathname(sbi.root_nid, sbi.root_nid,
-				 inode.nid, path, 0);
+	err = erofs_get_pathname(&inode, path, sizeof(path));
 	if (err < 0) {
 		erofs_err("file path not found @ nid %llu", inode.nid | 0ULL);
 		return;
@@ -598,7 +532,7 @@ static void erofsdump_print_statistic(void)
 		.cb = erofsdump_dirent_iter,
 		.de_nid = sbi.root_nid,
 		.dname = "",
-		.de_namelen = 0
+		.de_namelen = 0,
 	};
 
 	err = erofsdump_readdir(&ctx);
diff --git a/include/erofs/dir.h b/include/erofs/dir.h
index 25d6ce7..9d56f3f 100644
--- a/include/erofs/dir.h
+++ b/include/erofs/dir.h
@@ -45,6 +45,7 @@ struct erofs_dir_context {
 
 /* iterate over inodes that are in directory */
 int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck);
+int erofs_get_pathname(struct erofs_inode *inode, char *buf, size_t size);
 
 #ifdef __cplusplus
 }
diff --git a/lib/dir.c b/lib/dir.c
index 63e35ba..a3edf0b 100644
--- a/lib/dir.c
+++ b/lib/dir.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
+#include <stdlib.h>
 #include "erofs/print.h"
 #include "erofs/dir.h"
-#include <stdlib.h>
 
 static int traverse_dirents(struct erofs_dir_context *ctx,
 			    void *dentry_blk, unsigned int lblk,
@@ -64,6 +64,7 @@ static int traverse_dirents(struct erofs_dir_context *ctx,
 
 		ctx->dname = de_name;
 		ctx->de_namelen = de_namelen;
+		ctx->de_ftype = de->file_type;
 		ctx->dot_dotdot = is_dot_dotdot_len(de_name, de_namelen);
 		if (ctx->dot_dotdot) {
 			switch (de_namelen) {
@@ -121,7 +122,7 @@ out:
 int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
 {
 	struct erofs_inode *dir = ctx->dir;
-	int err;
+	int err = 0;
 	erofs_off_t pos;
 	char buf[EROFS_BLKSIZ];
 
@@ -163,5 +164,96 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
 			  dir->nid | 0ULL);
 		return -EFSCORRUPTED;
 	}
+	return err;
+}
+
+#define EROFS_PATHNAME_FOUND 1
+
+struct get_pathname_context {
+	struct erofs_dir_context ctx;
+	erofs_nid_t nid;
+	char *buf;
+	size_t size;
+	size_t pos;
+};
+
+static int get_pathname_iter(struct erofs_dir_context *ctx)
+{
+	int ret;
+	struct get_pathname_context *pctx = (void *)ctx;
+	const char *dname = ctx->dname;
+	size_t len = ctx->de_namelen;
+	size_t pos = pctx->pos;
+
+	if (ctx->de_nid == pctx->nid) {
+		if (pos + len + 2 > pctx->size) {
+			erofs_err("get_pathname buffer not large enough: len %zd, size %zd",
+				  pos + len + 2, pctx->size);
+			return -ENOMEM;
+		}
+
+		pctx->buf[pos++] = '/';
+		strncpy(pctx->buf + pos, dname, len);
+		pctx->buf[pos + len] = '\0';
+		return EROFS_PATHNAME_FOUND;
+	}
+
+	if (ctx->de_ftype == EROFS_FT_DIR && !ctx->dot_dotdot) {
+		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;
+		}
+
+		ctx->dir = &dir;
+		pctx->pos = pos + len + 1;
+		ret = erofs_iterate_dir(ctx, false);
+		pctx->pos = pos;
+		if (ret == EROFS_PATHNAME_FOUND) {
+			pctx->buf[pos++] = '/';
+			strncpy(pctx->buf + pos, dname, len);
+		}
+		return ret;
+	}
 	return 0;
 }
+
+int erofs_get_pathname(struct erofs_inode *inode, char *buf, size_t size)
+{
+	int ret;
+	struct erofs_inode root = { .nid = sbi.root_nid };
+	struct get_pathname_context pctx = {
+		.ctx.flags = EROFS_READDIR_VALID_PNID,
+		.ctx.pnid = root.nid,
+		.ctx.dir = &root,
+		.ctx.cb = get_pathname_iter,
+		.nid = inode->nid,
+		.buf = buf,
+		.size = size,
+		.pos = 0,
+	};
+
+	if (inode->nid == root.nid) {
+		if (size == 0) {
+			erofs_err("get_pathname buffer not large enough: len 1, size %zd",
+				  size);
+			return -ENOMEM;
+		}
+
+		buf[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(&pctx.ctx, false);
+	if (ret == EROFS_PATHNAME_FOUND)
+		return 0;
+	return ret;
+}
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-12-18  0:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-17 12:30 erofs-utils: lib: add API to get pathname of EROFS inode Igor Eisberg
2021-12-17 14:20 ` Igor Eisberg
2021-12-17 16:47   ` Igor Eisberg
2021-12-18  0:52 ` Gao Xiang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.