[WIP] [PATCH v4 09/12] erofs-utils: fuse: clean up readdir

Gao Xiang hsiangkao at aol.com
Sun Nov 15 05:25:14 AEDT 2020


Signed-off-by: Gao Xiang <hsiangkao at aol.com>
---
 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 <blucerlee at gmail.com>
  */
-#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



More information about the Linux-erofs mailing list