Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108311169
D28605.id83811.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D28605.id83811.diff
View Options
diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c
--- a/sys/fs/fuse/fuse_internal.c
+++ b/sys/fs/fuse/fuse_internal.c
@@ -583,7 +583,7 @@
u_long **cookiesp)
{
int err = 0;
- int bytesavail;
+ int oreclen;
size_t freclen;
struct dirent *de;
@@ -620,10 +620,10 @@
err = EINVAL;
break;
}
- bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)
+ oreclen = GENERIC_DIRSIZ((struct pseudo_dirent *)
&fudge->namelen);
- if (bytesavail > uio_resid(uio)) {
+ if (oreclen > uio_resid(uio)) {
/* Out of space for the dir so we are done. */
err = -1;
break;
@@ -633,12 +633,13 @@
* the requested offset in the directory is found.
*/
if (*fnd_start != 0) {
- fiov_adjust(cookediov, bytesavail);
- bzero(cookediov->base, bytesavail);
+ fiov_adjust(cookediov, oreclen);
+ bzero(cookediov->base, oreclen);
de = (struct dirent *)cookediov->base;
de->d_fileno = fudge->ino;
- de->d_reclen = bytesavail;
+ de->d_off = fudge->off;
+ de->d_reclen = oreclen;
de->d_type = fudge->type;
de->d_namlen = fudge->namelen;
memcpy((char *)cookediov->base + sizeof(struct dirent) -
diff --git a/tests/sys/fs/fusefs/Makefile b/tests/sys/fs/fusefs/Makefile
--- a/tests/sys/fs/fusefs/Makefile
+++ b/tests/sys/fs/fusefs/Makefile
@@ -71,6 +71,9 @@
MOUNT= ${SRCTOP}/sbin/mount
# Suppress warnings that GCC generates for the libc++ and gtest headers.
CXXWARNFLAGS.gcc+= -Wno-placement-new -Wno-attributes
+# Suppress Wcast-align for readdir.cc, because it is unavoidable when using
+# getdirentries.
+CXXWARNFLAGS.readdir.cc+= -Wno-cast-align
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 80000
CXXWARNFLAGS+= -Wno-class-memaccess
.endif
diff --git a/tests/sys/fs/fusefs/readdir.cc b/tests/sys/fs/fusefs/readdir.cc
--- a/tests/sys/fs/fusefs/readdir.cc
+++ b/tests/sys/fs/fusefs/readdir.cc
@@ -62,6 +62,9 @@
}
};
+const char dot[] = ".";
+const char dotdot[] = "..";
+
/* FUSE_READDIR returns nothing but "." and ".." */
TEST_F(Readdir, dots)
{
@@ -72,8 +75,6 @@
struct dirent *de;
vector<struct dirent> ents(2);
vector<struct dirent> empty_ents(0);
- const char dot[] = ".";
- const char dotdot[] = "..";
expect_lookup(RELPATH, ino);
expect_opendir(ino);
@@ -98,11 +99,6 @@
de = readdir(dir);
ASSERT_NE(nullptr, de) << strerror(errno);
EXPECT_EQ(2ul, de->d_fileno);
- /*
- * fuse(4) doesn't actually set d_off, which is ok for now because
- * nothing uses it.
- */
- //EXPECT_EQ(2000, de->d_off);
EXPECT_EQ(DT_DIR, de->d_type);
EXPECT_EQ(sizeof(dotdot), de->d_namlen);
EXPECT_EQ(0, strcmp(dotdot, de->d_name));
@@ -111,7 +107,6 @@
de = readdir(dir);
ASSERT_NE(nullptr, de) << strerror(errno);
EXPECT_EQ(3ul, de->d_fileno);
- //EXPECT_EQ(3000, de->d_off);
EXPECT_EQ(DT_DIR, de->d_type);
EXPECT_EQ(sizeof(dot), de->d_namlen);
EXPECT_EQ(0, strcmp(dot, de->d_name));
@@ -153,8 +148,11 @@
leakdir(dir);
}
-/* getdirentries(2) can use a larger buffer size than readdir(3) */
-TEST_F(Readdir, getdirentries)
+/*
+ * getdirentries(2) can use a larger buffer size than readdir(3). It also has
+ * some additional non-standardized fields in the returned dirent.
+ */
+TEST_F(Readdir, getdirentries_empty)
{
const char FULLPATH[] = "mountpoint/some_dir";
const char RELPATH[] = "some_dir";
@@ -186,6 +184,62 @@
leak(fd);
}
+/*
+ * The dirent.d_off field can be used with lseek to position the directory so
+ * that getdirentries will return the subsequent dirent.
+ */
+TEST_F(Readdir, getdirentries_seek)
+{
+ const char FULLPATH[] = "mountpoint/some_dir";
+ const char RELPATH[] = "some_dir";
+ vector<struct dirent> ents0(2);
+ vector<struct dirent> ents1(1);
+ uint64_t ino = 42;
+ int fd;
+ const size_t bufsize = 8192;
+ char buf[bufsize];
+ struct dirent *de0, *de1;
+ ssize_t r;
+
+ expect_lookup(RELPATH, ino);
+ expect_opendir(ino);
+
+ ents0[0].d_fileno = 2;
+ ents0[0].d_off = 2000;
+ ents0[0].d_namlen = sizeof(dotdot);
+ ents0[0].d_type = DT_DIR;
+ strncpy(ents0[0].d_name, dotdot, ents0[0].d_namlen);
+ expect_readdir(ino, 0, ents0);
+ ents0[1].d_fileno = 3;
+ ents0[1].d_off = 3000;
+ ents0[1].d_namlen = sizeof(dot);
+ ents0[1].d_type = DT_DIR;
+ ents1[0].d_fileno = 3;
+ ents1[0].d_off = 3000;
+ ents1[0].d_namlen = sizeof(dot);
+ ents1[0].d_type = DT_DIR;
+ strncpy(ents1[0].d_name, dot, ents1[0].d_namlen);
+ expect_readdir(ino, 0, ents0);
+ expect_readdir(ino, 2000, ents1);
+
+ fd = open(FULLPATH, O_DIRECTORY);
+ ASSERT_LE(0, fd) << strerror(errno);
+ r = getdirentries(fd, buf, sizeof(buf), 0);
+ ASSERT_LT(0, r) << strerror(errno);
+ de0 = (struct dirent*)&buf[0];
+ ASSERT_EQ(2000, de0->d_off);
+ ASSERT_LT(de0->d_reclen + offsetof(struct dirent, d_fileno), bufsize);
+ de1 = (struct dirent*)(&(buf[de0->d_reclen]));
+ ASSERT_EQ(3ul, de1->d_fileno);
+
+ r = lseek(fd, de0->d_off, SEEK_SET);
+ ASSERT_LE(0, r);
+ r = getdirentries(fd, buf, sizeof(buf), 0);
+ ASSERT_LT(0, r) << strerror(errno);
+ de0 = (struct dirent*)&buf[0];
+ ASSERT_EQ(3000, de0->d_off);
+}
+
/*
* Nothing bad should happen if getdirentries is called on two file descriptors
* which were concurrently open, but one has already been closed.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 24, 6:45 PM (12 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16097075
Default Alt Text
D28605.id83811.diff (5 KB)
Attached To
Mode
D28605: fusefs: set d_off during VOP_READDIR
Attached
Detach File
Event Timeline
Log In to Comment