[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