diff options
author | helg <helg@cvs.openbsd.org> | 2017-11-17 15:45:18 +0000 |
---|---|---|
committer | helg <helg@cvs.openbsd.org> | 2017-11-17 15:45:18 +0000 |
commit | dc8873ed97fb2c79df44958dde9eda388417901b (patch) | |
tree | 6575346dfd9cc95d0c6115a4142a6b9ac69f4172 /lib/libfuse | |
parent | 2f6c2b9dab4d8fb2c13128a3d9638e362839377d (diff) |
Fixes the following bugs when getcwd(3) is used on a fuse file system
Endless loop if directory nested more than one level from root of file system
Current directory not found if the parent directory contains more children than
will fit in the buffer passed to VOP_READDIR(9)
Open and close directory in fusefs_readdir if dir is not already open.
Now behaves as if readdir_ino option was passed to fuse so that directories in
path have a valid ino.
ok mpi@
Diffstat (limited to 'lib/libfuse')
-rw-r--r-- | lib/libfuse/fuse.h | 3 | ||||
-rw-r--r-- | lib/libfuse/fuse_ops.c | 31 |
2 files changed, 24 insertions, 10 deletions
diff --git a/lib/libfuse/fuse.h b/lib/libfuse/fuse.h index 243701d6d53..301472debdd 100644 --- a/lib/libfuse/fuse.h +++ b/lib/libfuse/fuse.h @@ -1,4 +1,4 @@ -/* $OpenBSD: fuse.h,v 1.12 2014/01/20 15:01:59 syl Exp $ */ +/* $OpenBSD: fuse.h,v 1.13 2017/11/17 15:45:17 helg Exp $ */ /* * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> * @@ -89,6 +89,7 @@ typedef int (*fuse_fill_dir_t)(void *, const char *, const struct stat *, off_t); typedef struct fuse_dirhandle { + struct fuse *fuse; fuse_fill_dir_t filler; void *buf; int filled; diff --git a/lib/libfuse/fuse_ops.c b/lib/libfuse/fuse_ops.c index 74853d17444..e91b1fa4790 100644 --- a/lib/libfuse/fuse_ops.c +++ b/lib/libfuse/fuse_ops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fuse_ops.c,v 1.26 2016/09/07 17:53:35 natano Exp $ */ +/* $OpenBSD: fuse_ops.c,v 1.27 2017/11/17 15:45:17 helg Exp $ */ /* * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> * @@ -217,12 +217,15 @@ static int ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf, off_t off) { + struct fuse *f; struct fuse_dirhandle *fd = dh; + struct fuse_vnode *v; struct fusebuf *fbuf; struct dirent *dir; uint32_t namelen; uint32_t len; + f = fd->fuse; fbuf = fd->buf; namelen = strnlen(name, MAXNAMLEN); len = GENERIC_DIRSIZ(namelen); @@ -242,13 +245,21 @@ ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf, if (off) fd->filled = 0; - if (stbuf) { - dir->d_fileno = stbuf->st_ino; + /* TODO Add support for use_ino and readdir_ino */ + v = get_vn_by_name_and_parent(f, (uint8_t *)name, fbuf->fb_ino); + if (v == NULL) { + if (strcmp(name, ".") == 0) + dir->d_fileno = fbuf->fb_ino; + else + dir->d_fileno = 0xffffffff; + } else + dir->d_fileno = v->ino; + + if (stbuf) dir->d_type = IFTODT(stbuf->st_mode); - } else { - dir->d_fileno = 0xffffffff; + else dir->d_type = DT_UNKNOWN; - } + dir->d_reclen = len; dir->d_off = off + len; /* XXX */ strlcpy(dir->d_name, name, sizeof(dir->d_name)); @@ -295,7 +306,7 @@ ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf) ffi.fh = fbuf->fb_io_fd; offset = fbuf->fb_io_off; size = fbuf->fb_io_len; - startsave = 0; + startsave = offset; fbuf->fb_dat = calloc(1, size); @@ -314,11 +325,12 @@ ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf) if (!vn->fd->filled) { vn->fd->filler = ifuse_fill_readdir; vn->fd->buf = fbuf; - vn->fd->filled = 0; vn->fd->full = 0; vn->fd->size = size; vn->fd->off = offset; vn->fd->idx = 0; + vn->fd->fuse = f; + vn->fd->start = offset; startsave = vn->fd->start; realname = build_realname(f, vn->ino); @@ -345,7 +357,8 @@ ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf) if (fbuf->fb_err) { fbuf->fb_len = 0; vn->fd->filled = 1; - } + } else if (vn->fd->full && fbuf->fb_len == 0) + fbuf->fb_err = -ENOBUFS; if (fbuf->fb_len == 0) free(fbuf->fb_dat); |