[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