Change-Id: Iba99e590f051638285d1d1949311a08f5a5f1a82
Signed-off-by: Kelvin Zhang <[email protected]>
---
 dump/main.c              |  70 ++-----------------------
 include/erofs/internal.h |   5 ++
 lib/namei.c              | 108 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 67 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index 71b44b4..b728703 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..632461e 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..ee76e82 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -274,3 +274,111 @@ 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

Reply via email to