[PATCH v7 1/2] Add API to get full pathname of an inode
Kelvin Zhang
zhangkelvin at google.com
Sat Dec 18 06:47:19 AEDT 2021
Signed-off-by: Kelvin Zhang <zhangkelvin at google.com>
---
dump/main.c | 70 +----------------------
include/erofs/internal.h | 5 ++
lib/namei.c | 120 +++++++++++++++++++++++++++++++++++++--
3 files changed, 124 insertions(+), 71 deletions(-)
diff --git a/dump/main.c b/dump/main.c
index 71b44b4..7dbb6e4 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -11,6 +11,7 @@
#include "erofs/print.h"
#include "erofs/inode.h"
#include "erofs/io.h"
+#include "erofs/internal.h"
#ifdef HAVE_LIBUUID
#include <uuid.h>
@@ -365,71 +366,6 @@ static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid)
return 0;
}
-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 (de->nid == target) {
- memcpy(path + pos, dname, len);
- path[pos + len] = '\0';
- return 0;
- }
-
- if (de->file_type == EROFS_FT_DIR &&
- de->nid != parent_nid &&
- de->nid != nid) {
- memcpy(path + pos, dname, len);
- err = erofs_get_pathname(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)
{
@@ -478,12 +414,12 @@ 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_inode_name(&sbi, inode.nid, path, PATH_MAX+1);
if (err < 0) {
erofs_err("file path not found @ nid %llu", inode.nid | 0ULL);
return;
}
+ printf("Path: %s\n", path);
strftime(timebuf, sizeof(timebuf),
"%Y-%m-%d %H:%M:%S", localtime((time_t *)&inode.i_ctime));
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index a68de32..e5454ee 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -305,6 +305,11 @@ int erofs_read_superblock(void);
int erofs_read_inode_from_disk(struct erofs_inode *vi);
int erofs_ilookup(const char *path, struct erofs_inode *vi);
int erofs_read_inode_from_disk(struct erofs_inode *vi);
+// Get full path name of an inode, return 0 if success
+int erofs_get_inode_name(const struct erofs_sb_info *sbi,
+ erofs_nid_t target,
+ char *output_buffer,
+ size_t capacity);
/* data.c */
int erofs_pread(struct erofs_inode *inode, char *buf,
diff --git a/lib/namei.c b/lib/namei.c
index 7377e74..88d2f6d 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -48,7 +48,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
vi->inode_isize = sizeof(struct erofs_inode_extended);
ret = dev_read(0, buf + sizeof(*dic), inode_loc + sizeof(*dic),
- sizeof(*die) - sizeof(*dic));
+ sizeof(*die) - sizeof(*dic));
if (ret < 0)
return -EIO;
@@ -169,7 +169,7 @@ struct erofs_dirent *find_target_dirent(erofs_nid_t pnid,
/* a corrupted entry is found */
if (nameoff + de_namelen > maxsize ||
- de_namelen > EROFS_NAME_LEN) {
+ de_namelen > EROFS_NAME_LEN) {
erofs_err("bogus dirent @ nid %llu", pnid | 0ULL);
DBG_BUGON(1);
return ERR_PTR(-EFSCORRUPTED);
@@ -203,7 +203,7 @@ int erofs_namei(struct nameidata *nd,
offset = 0;
while (offset < vi.i_size) {
erofs_off_t maxsize = min_t(erofs_off_t,
- vi.i_size - offset, EROFS_BLKSIZ);
+ vi.i_size - offset, EROFS_BLKSIZ);
struct erofs_dirent *de = (void *)buf;
unsigned int nameoff;
@@ -213,7 +213,7 @@ int erofs_namei(struct nameidata *nd,
nameoff = le16_to_cpu(de->nameoff);
if (nameoff < sizeof(struct erofs_dirent) ||
- nameoff >= PAGE_SIZE) {
+ nameoff >= PAGE_SIZE) {
erofs_err("invalid de[0].nameoff %u @ nid %llu",
nameoff, nid | 0ULL);
return -EFSCORRUPTED;
@@ -274,3 +274,115 @@ int erofs_ilookup(const char *path, struct erofs_inode *vi)
vi->nid = nd.nid;
return erofs_read_inode_from_disk(vi);
}
+
+static inline int erofs_checkdirent(const struct erofs_dirent *de,
+ const struct erofs_dirent *last_de,
+ u32 maxsize,
+ const char *dname)
+{
+ int dname_len;
+ unsigned int nameoff = le16_to_cpu(de->nameoff);
+
+ if (nameoff < sizeof(struct erofs_dirent) || nameoff >= PAGE_SIZE) {
+ erofs_err("invalid de[0].nameoff %u @ nid %llu", nameoff, de->nid | 0ULL);
+ return -EFSCORRUPTED;
+ }
+ dname_len = (de + 1 >= last_de) ? strnlen(dname, maxsize - nameoff)
+ : le16_to_cpu(de[1].nameoff) - nameoff;
+ /* a corrupted entry is found */
+ if (nameoff + dname_len > maxsize || dname_len > EROFS_NAME_LEN) {
+ erofs_err("bogus dirent @ nid %llu", le64_to_cpu(de->nid) | 0ULL);
+ DBG_BUGON(1);
+ return -EFSCORRUPTED;
+ }
+ if (de->file_type >= EROFS_FT_MAX) {
+ erofs_err("invalid file type %llu", de->nid);
+ return -EFSCORRUPTED;
+ }
+ return dname_len;
+}
+
+int erofs_get_pathname(const struct erofs_sb_info *sbi,
+ erofs_nid_t nid,
+ erofs_nid_t parent_nid,
+ erofs_nid_t target,
+ char *path,
+ size_t capacity)
+{
+ if (capacity <= 1) {
+ return -2;
+ }
+ int err;
+ erofs_off_t offset;
+ char buf[EROFS_BLKSIZ];
+ struct erofs_inode inode = { .nid = nid };
+
+ path[0] = '/';
+ 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;
+ // First char is '/', last char is '\0'
+ // so usable capacity is |capacity| - 2
+ if (len > capacity - 2) {
+ len = capacity - 2;
+ }
+ if (de->nid == target) {
+ memcpy(path + 1, dname, len);
+ path[1 + len] = '\0';
+ return 0;
+ }
+
+ if (de->file_type == EROFS_FT_DIR &&
+ de->nid != parent_nid &&
+ de->nid != nid) {
+ memcpy(path + 1, dname, len);
+ err = erofs_get_pathname(sbi, de->nid, nid,
+ target, path + 1 + len, capacity - 1 - len);
+ if (!err)
+ return 0;
+ memset(path + 1, 0, len);
+ }
+ ++de;
+ }
+ offset += maxsize;
+ }
+ return -1;
+}
+
+int erofs_get_inode_name(const struct erofs_sb_info *sbi,
+ erofs_nid_t target,
+ char *path,
+ size_t capacity)
+{
+ return erofs_get_pathname(sbi, sbi->root_nid, sbi->root_nid, target, path, capacity);
+}
+
--
2.34.1.173.g76aa8bc2d0-goog
More information about the Linux-erofs
mailing list