diff options
author | Martin Pärtel <martin.partel@gmail.com> | 2021-02-03 11:53:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-03 09:53:21 +0000 |
commit | 5012a05ac875c1988263faaa77177c27c62c52bb (patch) | |
tree | 0207e1ee07d56e020798b89b30bea75d10559f74 | |
parent | b9e3ea01dbbbba9518da216dd29c042af871ae31 (diff) | |
download | fuse-5012a05ac875c1988263faaa77177c27c62c52bb.tar.gz |
Fix returning inode numbers from readdir() in offset==0 mode. (#584)
- Test added for all passthrough examples.
- passthrough.c uses offset==0 mode. The others don't.
- passthrough.c changed to set FUSE_FILL_DIR_PLUS to make the test pass.
- This fixes #583.
-rw-r--r-- | ChangeLog.rst | 1 | ||||
-rw-r--r-- | example/passthrough.c | 2 | ||||
-rwxr-xr-x | lib/fuse.c | 2 | ||||
-rw-r--r-- | test/meson.build | 3 | ||||
-rw-r--r-- | test/readdir_inode.c | 45 | ||||
-rwxr-xr-x | test/test_examples.py | 19 |
6 files changed, 69 insertions, 3 deletions
diff --git a/ChangeLog.rst b/ChangeLog.rst index 47b993a..718033a 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -4,6 +4,7 @@ Unreleased Changes * Allow "nonempty" as a mount option, for backwards compatibility with fusermount 2. The option has no effect since mounting over non-empty directories is allowed by default. +* Fix returning inode numbers from readdir() in offset==0 mode. libfuse 3.10.1 (2020-12-07) =========================== diff --git a/example/passthrough.c b/example/passthrough.c index 08273ff..86ac698 100644 --- a/example/passthrough.c +++ b/example/passthrough.c @@ -132,7 +132,7 @@ static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, memset(&st, 0, sizeof(st)); st.st_ino = de->d_ino; st.st_mode = de->d_type << 12; - if (filler(buf, de->d_name, &st, 0, 0)) + if (filler(buf, de->d_name, &st, 0, FUSE_FILL_DIR_PLUS)) break; } @@ -3566,7 +3566,7 @@ static int fill_dir_plus(void *dh_, const char *name, const struct stat *statp, return 1; } - if (off && statp && (flags & FUSE_FILL_DIR_PLUS)) { + if (statp && (flags & FUSE_FILL_DIR_PLUS)) { e.attr = *statp; if (!is_dot_or_dotdot(name)) { diff --git a/test/meson.build b/test/meson.build index 5c5c2e6..12d3c41 100644 --- a/test/meson.build +++ b/test/meson.build @@ -10,6 +10,9 @@ endforeach td += executable('test_syscalls', 'test_syscalls.c', include_directories: include_dirs, install: false) +td += executable('readdir_inode', 'readdir_inode.c', + include_directories: include_dirs, + install: false) test_scripts = [ 'conftest.py', 'pytest.ini', 'test_examples.py', 'util.py', 'test_ctests.py' ] diff --git a/test/readdir_inode.c b/test/readdir_inode.c new file mode 100644 index 0000000..7f46c0a --- /dev/null +++ b/test/readdir_inode.c @@ -0,0 +1,45 @@ +/* + * Prints each directory entry and its inode as returned by 'readdir'. + * Skips '.' and '..' because readdir is not required to return them and + * some of our examples don't. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> + +int main(int argc, char* argv[]) +{ + DIR* dirp; + struct dirent* dent; + + if (argc != 2) { + fprintf(stderr, "Usage: readdir_inode dir\n"); + return 1; + } + + dirp = opendir(argv[1]); + if (dirp == NULL) { + perror("failed to open directory"); + return 2; + } + + errno = 0; + dent = readdir(dirp); + while (dent != NULL) { + if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) { + printf("%llu %s\n", (unsigned long long)dent->d_ino, dent->d_name); + } + dent = readdir(dirp); + } + if (errno != 0) { + perror("failed to read directory entry"); + return 3; + } + + closedir(dirp); + + return 0; +} diff --git a/test/test_examples.py b/test/test_examples.py index da50b2a..aab970f 100755 --- a/test/test_examples.py +++ b/test/test_examples.py @@ -72,6 +72,15 @@ class raii_tmpdir: def short_tmpdir(): return raii_tmpdir() +def readdir_inode(dir): + cmd = base_cmdline + [ pjoin(basename, 'test', 'readdir_inode'), dir ] + with subprocess.Popen(cmd, stdout=subprocess.PIPE, + universal_newlines=True) as proc: + lines = proc.communicate()[0].splitlines() + lines.sort() + return lines + + @pytest.mark.parametrize("cmdline_builder", (invoke_directly, invoke_mount_fuse, invoke_mount_fuse_drop_privileges)) @pytest.mark.parametrize("options", powerset(options)) @@ -602,6 +611,10 @@ def tst_readdir(src_dir, mnt_dir): listdir_should.sort() assert listdir_is == listdir_should + inodes_is = readdir_inode(mnt_newdir) + inodes_should = readdir_inode(src_newdir) + assert inodes_is == inodes_should + os.unlink(file_) os.unlink(subfile) os.rmdir(subdir) @@ -623,6 +636,10 @@ def tst_readdir_big(src_dir, mnt_dir): listdir_should = sorted(os.listdir(src_dir)) assert listdir_is == listdir_should + inodes_is = readdir_inode(mnt_dir) + inodes_should = readdir_inode(src_dir) + assert inodes_is == inodes_should + for fname in fnames: stat_src = os.stat(pjoin(src_dir, fname)) stat_mnt = os.stat(pjoin(mnt_dir, fname)) @@ -631,7 +648,7 @@ def tst_readdir_big(src_dir, mnt_dir): assert stat_src.st_ctime == stat_mnt.st_ctime assert stat_src.st_size == stat_mnt.st_size os.unlink(pjoin(src_dir, fname)) - + def tst_truncate_path(mnt_dir): assert len(TEST_DATA) > 1024 |