diff options
author | farlongsignal <141166749+farlongsignal@users.noreply.github.com> | 2024-03-24 21:54:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-24 21:54:19 +0100 |
commit | dd95d13aaca940a310628f31bfcdd2deb38ad377 (patch) | |
tree | 9981af9e654c5209a5f3ec6dc34c165b13bdb48a | |
parent | f01d9277cb6faface1d8b048db4eddb71b2f5d78 (diff) | |
download | libfuse-dd95d13aaca940a310628f31bfcdd2deb38ad377.tar.gz |
fix readdirplus when filler is called with zero offset (#896)
fixes #235
In fill_dir_plus(), there's a lookup for caching dirent attributes.
However, when offset = 0 the cache metadata from the lookup is lost
as only the entry attributes are passed when added to the list. Kernel
doesn't cache the attributes since .ino = 0.
This change moves the entry lookup to happen just before the relevant
fuse_add_direntry_plus() calls
-rw-r--r-- | lib/fuse.c | 29 |
1 files changed, 21 insertions, 8 deletions
@@ -3541,14 +3541,6 @@ static int fill_dir_plus(void *dh_, const char *name, const struct stat *statp, if (statp && (flags & FUSE_FILL_DIR_PLUS)) { e.attr = *statp; - - if (!is_dot_or_dotdot(name)) { - res = do_lookup(f, dh->nodeid, name, &e); - if (res) { - dh->error = res; - return 1; - } - } } else { e.attr.st_ino = FUSE_UNKNOWN_INO; if (statp) { @@ -3577,6 +3569,16 @@ static int fill_dir_plus(void *dh_, const char *name, const struct stat *statp, if (extend_contents(dh, dh->needlen) == -1) return 1; + if (statp && (flags & FUSE_FILL_DIR_PLUS)) { + if (!is_dot_or_dotdot(name)) { + res = do_lookup(f, dh->nodeid, name, &e); + if (res) { + dh->error = res; + return 1; + } + } + } + newlen = dh->len + fuse_add_direntry_plus(dh->req, dh->contents + dh->len, dh->needlen - dh->len, name, @@ -3649,6 +3651,7 @@ static int readdir_fill_from_list(fuse_req_t req, struct fuse_dh *dh, { off_t pos; struct fuse_direntry *de = dh->first; + int res; dh->len = 0; @@ -3673,6 +3676,16 @@ static int readdir_fill_from_list(fuse_req_t req, struct fuse_dh *dh, .ino = 0, .attr = de->stat, }; + + if (!is_dot_or_dotdot(de->name)) { + res = do_lookup(dh->fuse, dh->nodeid, + de->name, &e); + if (res) { + dh->error = res; + return 1; + } + } + thislen = fuse_add_direntry_plus(req, p, rem, de->name, &e, pos); } else { |