[disorderfs] 01/01: Ensure readdir(2) returns consistent (and unique) inode numbers. (Closes: #898287)
Chris Lamb
chris at chris-lamb.co.uk
Thu May 10 16:29:47 CEST 2018
This is an automated email from the git hooks/post-receive script.
lamby pushed a commit to branch master
in repository disorderfs.
commit 39e29c4ef96319a4c716832a73ad5fd62ed9ff75
Author: Chris Lamb <lamby at debian.org>
Date: Wed May 9 18:00:23 2018 -0700
Ensure readdir(2) returns consistent (and unique) inode numbers. (Closes: #898287)
---
disorderfs.cpp | 13 +++++----
tests/inodes | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/disorderfs.cpp b/disorderfs.cpp
index 8cf189e..a8258b2 100644
--- a/disorderfs.cpp
+++ b/disorderfs.cpp
@@ -68,7 +68,7 @@ namespace {
}
int wrap (int retval) { return retval == -1 ? -errno : 0; }
- using Dirents = std::vector<std::string>;
+ using Dirents = std::vector<std::pair<std::string, ino_t>>;
// The libc versions of seteuid, etc. set the credentials for all threads.
// We need to set credentials for a single thread only, so call the syscalls directly.
@@ -270,7 +270,7 @@ int main (int argc, char** argv)
// Add some of our own hard-coded FUSE options:
fuse_opt_add_arg(&fargs, "-o");
- fuse_opt_add_arg(&fargs, "atomic_o_trunc,default_permissions"); // XXX: other mount options?
+ fuse_opt_add_arg(&fargs, "atomic_o_trunc,default_permissions,use_ino"); // XXX: other mount options?
if (config.multi_user) {
fuse_opt_add_arg(&fargs, "-o");
fuse_opt_add_arg(&fargs, "allow_other");
@@ -429,7 +429,7 @@ int main (int argc, char** argv)
struct dirent* dirent_p;
int res;
while ((res = readdir_r(d, &dirent_storage, &dirent_p)) == 0 && dirent_p) {
- dirents->emplace_back(dirent_p->d_name);
+ dirents->emplace_back(std::make_pair(dirent_p->d_name, dirent_p->d_ino));
}
if (config.sort_dirents) {
std::sort(dirents->begin(), dirents->end());
@@ -447,14 +447,17 @@ int main (int argc, char** argv)
};
disorderfs_fuse_operations.readdir = [] (const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* info) {
Dirents& dirents = *get_fuse_data<Dirents*>(info);
+ struct stat st;
+ memset(&st, 0, sizeof(st));
if (config.shuffle_dirents) {
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(dirents.begin(), dirents.end(), g);
}
- for (const std::string& dirent : dirents) {
- if (filler(buf, dirent.c_str(), nullptr, 0) != 0) {
+ for (const auto dirent : dirents) {
+ st.st_ino = dirent.second;
+ if (filler(buf, dirent.first.c_str(), &st, 0) != 0) {
return -ENOMEM;
}
}
diff --git a/tests/inodes b/tests/inodes
new file mode 100755
index 0000000..afd5695
--- /dev/null
+++ b/tests/inodes
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+. ./common
+
+TEMPDIR="$(mktemp -d -t inodes.XXXXXXXXXX)"
+
+trap "Unmount 2>/dev/null; rm -rf ${TEMPDIR}" EXIT
+
+Setup () {
+ cat >${TEMPDIR}/inodes.cpp <<EOF
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#include <map>
+#include <iostream>
+
+struct linux_dirent {
+ unsigned long d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ char d_name[];
+};
+
+#define BUF_SIZE 1024
+
+void perror_and_die (const char* s)
+{
+ std::perror(s);
+ std::abort();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fd, nread, ret = EXIT_SUCCESS;
+ char buf[BUF_SIZE];
+ struct stat st;
+ const std::string dirname = argc > 1 ? argv[1] : ".";
+ struct linux_dirent *d;
+ std::map<ino_t, std::string> inodes;
+
+ if ((fd = open(dirname.c_str(), O_RDONLY | O_DIRECTORY)) == -1)
+ perror_and_die("open");
+
+ while ((nread = syscall(SYS_getdents, fd, buf, BUF_SIZE)) > 0) {
+ for (int pos = 0; pos < nread; pos += d->d_reclen) {
+ d = (struct linux_dirent *) (buf + pos);
+
+ std::string filename = dirname + "/" + std::string(d->d_name);
+ if (stat(filename.c_str(), &st) == -1)
+ perror_and_die("stat");
+
+ if (d->d_ino != st.st_ino) {
+ std::cerr << filename << ": inode from getdents does not match stat: "
+ << d->d_ino << " != " << st.st_ino << std::endl;
+ ret = EXIT_FAILURE;
+ }
+
+ if (inodes.find(d->d_ino) == inodes.end()) {
+ inodes[d->d_ino] = filename;
+ } else {
+ std::cerr << filename << ": duplicate inode: " << d->d_ino
+ << " used by " << inodes[d->d_ino] << std::endl;
+ ret = EXIT_FAILURE;
+ }
+ }
+ }
+
+ if (nread == -1)
+ perror_and_die("open");
+
+ exit(ret);
+}
+EOF
+ g++ -Wall -o${TEMPDIR}/inodes ${TEMPDIR}/inodes.cpp || Fail "Could not compile testcase"
+}
+
+Setup
+Mount
+${TEMPDIR}/inodes target || Fail "inodes"
+Unmount
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/disorderfs.git
More information about the rb-commits
mailing list