aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfarlongsignal <141166749+farlongsignal@users.noreply.github.com>2024-03-24 21:54:19 +0100
committerGitHub <noreply@github.com>2024-03-24 21:54:19 +0100
commitdd95d13aaca940a310628f31bfcdd2deb38ad377 (patch)
tree9981af9e654c5209a5f3ec6dc34c165b13bdb48a
parentf01d9277cb6faface1d8b048db4eddb71b2f5d78 (diff)
downloadlibfuse-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.c29
1 files changed, 21 insertions, 8 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 2a88918..f619c00 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -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 {