Signed-off-by: Gao Xiang <[email protected]>
---
 fuse/main.c   |   2 +-
 fuse/readir.c | 155 +++++++++++++++++++++++---------------------------
 fuse/readir.h |   4 +-
 3 files changed, 74 insertions(+), 87 deletions(-)

diff --git a/fuse/main.c b/fuse/main.c
index 9ac8149c88d9..a4b7a3692c19 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -182,7 +182,7 @@ static int erofsfuse_readlink(const char *path, char 
*buffer, size_t size)
 static struct fuse_operations erofs_ops = {
        .readlink = erofsfuse_readlink,
        .getattr = erofs_getattr,
-       .readdir = erofs_readdir,
+       .readdir = erofsfuse_readdir,
        .open = erofs_open,
        .read = erofsfuse_read,
        .init = erofs_init,
diff --git a/fuse/readir.c b/fuse/readir.c
index a405dd702d84..2e90c95c38aa 100644
--- a/fuse/readir.c
+++ b/fuse/readir.c
@@ -4,114 +4,101 @@
  *
  * Created by Li Guifu <[email protected]>
  */
-#include "readir.h"
-#include <errno.h>
-#include <linux/fs.h>
-#include <sys/stat.h>
+#include <fuse.h>
+#include <fuse_opt.h>
 
-#include "erofs/defs.h"
 #include "erofs/internal.h"
-#include "erofs_fs.h"
-#include "erofs/io.h"
 #include "erofs/print.h"
 
-erofs_nid_t split_entry(char *entry, off_t ofs, char *end, char *name,
-                       uint32_t dirend)
+static int erofs_fill_dentries(struct erofs_inode *dir,
+                              fuse_fill_dir_t filler, void *buf,
+                              void *dblk, unsigned int nameoff,
+                              unsigned int maxsize)
 {
-       struct erofs_dirent *de = (struct erofs_dirent *)(entry + ofs);
-       uint16_t nameoff = le16_to_cpu(de->nameoff);
-       const char *de_name = entry + nameoff;
-       uint32_t de_namelen;
-
-       if ((void *)(de + 1) >= (void *)end)
-               de_namelen = strnlen(de_name, dirend - nameoff);
-       else
-               de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
-
-       memcpy(name, de_name, de_namelen);
-       name[de_namelen] = '\0';
-       return le64_to_cpu(de->nid);
-}
-
-int fill_dir(char *entrybuf, fuse_fill_dir_t filler, void *buf,
-            uint32_t dirend)
-{
-       uint32_t ofs;
-       uint16_t nameoff;
-       char *end;
-       char name[EROFS_BLKSIZ];
-
-       nameoff = le16_to_cpu(((struct erofs_dirent *)entrybuf)->nameoff);
-       end = entrybuf + nameoff;
-       ofs = 0;
-       while (ofs < nameoff) {
-               (void)split_entry(entrybuf, ofs, end, name, dirend);
-               filler(buf, name, NULL, 0);
-               ofs += sizeof(struct erofs_dirent);
+       struct erofs_dirent *de = dblk;
+       const struct erofs_dirent *end = dblk + nameoff;
+       char namebuf[EROFS_NAME_LEN];
+
+       while (de < end) {
+               const char *de_name;
+               unsigned int de_namelen;
+
+               nameoff = le16_to_cpu(de->nameoff);
+               de_name = (char *)dblk + nameoff;
+
+               /* the last dirent in the block? */
+               if (de + 1 >= end)
+                       de_namelen = strnlen(de_name, maxsize - nameoff);
+               else
+                       de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+               /* a corrupted entry is found */
+               if (nameoff + de_namelen > maxsize ||
+                   de_namelen > EROFS_NAME_LEN) {
+                       erofs_err("bogus dirent @ nid %llu", dir->nid | 0ULL);
+                       DBG_BUGON(1);
+                       return -EFSCORRUPTED;
+               }
+
+               memcpy(namebuf, de_name, de_namelen);
+               namebuf[de_namelen] = '\0';
+
+               filler(buf, namebuf, NULL, 0);
+               ++de;
        }
-
        return 0;
 }
 
-/** Function to add an entry in a readdir() operation
- *
- * @param buf the buffer passed to the readdir() operation
- * @param name the file name of the directory entry
- * @param stat file attributes, can be NULL
- * @param off offset of the next entry or zero
- * @return 1 if buffer is full, zero otherwise
- */
-int erofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-                 off_t offset, struct fuse_file_info *fi)
+int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                     off_t offset, struct fuse_file_info *fi)
 {
        int ret;
-       struct erofs_inode v;
-       char dirsbuf[EROFS_BLKSIZ];
-       uint32_t dir_nr, dir_off, nr_cnt;
+       struct erofs_inode dir;
+       char dblk[EROFS_BLKSIZ];
+       erofs_off_t pos;
 
        erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
        UNUSED(fi);
 
-       ret = erofs_ilookup(path, &v);
+       ret = erofs_ilookup(path, &dir);
        if (ret)
                return ret;
 
-       erofs_dbg("path=%s nid = %llu", path, v.nid | 0ULL);
+       erofs_dbg("path=%s nid = %llu", path, dir.nid | 0ULL);
 
-       if (!S_ISDIR(v.i_mode))
+       if (!S_ISDIR(dir.i_mode))
                return -ENOTDIR;
 
-       if (!v.i_size)
+       if (!dir.i_size)
                return 0;
 
-       dir_nr = erofs_blknr(v.i_size);
-       dir_off = erofs_blkoff(v.i_size);
-       nr_cnt = 0;
-
-       erofs_dbg("dir_size=%llu dir_nr = %u dir_off=%u",
-                 v.i_size | 0ULL, dir_nr, dir_off);
-
-       while (nr_cnt < dir_nr) {
-               memset(dirsbuf, 0, sizeof(dirsbuf));
-               ret = blk_read(dirsbuf, v.u.i_blkaddr + nr_cnt, 1);
-               if (ret < 0)
-                       return -EIO;
-               fill_dir(dirsbuf, filler, buf, EROFS_BLKSIZ);
-               ++nr_cnt;
-       }
-
-       if (v.datalayout == EROFS_INODE_FLAT_INLINE) {
-               off_t addr;
-
-               addr = iloc(v.nid) + v.inode_isize + v.xattr_isize;
-
-               memset(dirsbuf, 0, sizeof(dirsbuf));
-               ret = dev_read(dirsbuf, addr, dir_off);
-               if (ret < 0)
-                       return -EIO;
-               fill_dir(dirsbuf, filler, buf, dir_off);
+       pos = 0;
+       while (pos < dir.i_size) {
+               unsigned int nameoff, maxsize;
+               struct erofs_dirent *de;
+
+               maxsize = min_t(unsigned int, EROFS_BLKSIZ,
+                               dir.i_size - pos);
+               ret = erofs_pread(&dir, dblk, maxsize, pos);
+               if (ret)
+                       return ret;
+
+               de = (struct erofs_dirent *)dblk;
+               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, dir.nid | 0ULL);
+                       ret = -EFSCORRUPTED;
+                       break;
+               }
+
+               ret = erofs_fill_dentries(&dir, filler, buf,
+                                         dblk, nameoff, maxsize);
+               if (ret)
+                       break;
+               pos += maxsize;
        }
-
        return 0;
 }
 
diff --git a/fuse/readir.h b/fuse/readir.h
index ee2ab8bdd0f0..16b878fe9f29 100644
--- a/fuse/readir.h
+++ b/fuse/readir.h
@@ -10,8 +10,8 @@
 #include <fuse.h>
 #include <fuse_opt.h>
 
-int erofs_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
-              off_t offset, struct fuse_file_info *fi);
+int erofsfuse_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
+                     off_t offset, struct fuse_file_info *fi);
 
 
 #endif
-- 
2.24.0

Reply via email to