Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seeking in directory inode does not work on drvfs #5938

Closed
jvwag opened this issue Sep 17, 2020 · 2 comments
Closed

Seeking in directory inode does not work on drvfs #5938

jvwag opened this issue Sep 17, 2020 · 2 comments

Comments

@jvwag
Copy link

jvwag commented Sep 17, 2020

Environment

Windows build number: Microsoft Windows [Version 10.0.19041.508]
Your Distribution version: Ubuntu 20.04
Whether the issue is on WSL 2 and/or WSL 1: WSL2, Linux version 4.19.128-microsoft-standard (oe-user@oe-host) (gcc version 8.2.0 (GCC)) #1 SMP Tue Jun 23 12:58:10 UTC 2020

Steps to reproduce

When an application reads the contents of a p9-drvfs directory the driver does not obey a seek: it will not move its pointer.

I found this when looking deeper into a PHP/composer issue and noticed a difference in the implementation of PHP's scandir and PHP's DirectoryIterator class. Using strace I noticed the system calls for getting the directory index were different. PHP's scandir would open a directory and multiple getdents64 calls would follow (32kb of buffers in Ubuntu, 2k in Alpine). While PHP's DirectoryIterator would open, do one getdents64 call, lseek to 0, and then do subsequent getdents64 calls. It seems the seek to 0 did not alter the output of the following getdents64 calls. The PHP implementation was expecting to start at the top of the structure, resulting in missing files in the directory listing as result of the PHP implementation. Although, when the buffer was looped (complete structure was read using one getdents64 call, a seek to 0 was done (this may not have done anything)) getdents64 would read the structure from offset 0.

PHP's scandir or /bin/ls of a directory using Alpine would result in the following strace:

open("/tmp/testdir", O_RDONLY|O_CLOEXEC|O_DIRECTORY) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents64(3, /* 44 entries */, 2048)   = 2048
getdents64(3, /* 41 entries */, 2048)   = 2024
getdents64(3, /* 23 entries */, 2048)   = 1064
getdents64(3, /* 0 entries */, 2048)    = 0
close(3)

PHP's DirectoryIterator class using Alpine would result in the following strace:

open("/tmp/testdir", O_RDONLY|O_CLOEXEC|O_DIRECTORY) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents64(3, /* 44 entries */, 2048)   = 2048
lseek(3, 0, SEEK_SET)                   = 0
getdents64(3, /* 41 entries */, 2048)   = 2024              <--- Expected: 44 entries, then: 41, 23, 0
getdents64(3, /* 23 entries */, 2048)   = 1064
getdents64(3, /* 0 entries */, 2048)    = 0
close(3)

PHP's DirectoryIterator class using Ubuntu has a way larger buffer (32k): it does not happen here

openat(AT_FDCWD, "/tmp/testdir", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=512, ...}) = 0
getdents64(3, /* 108 entries */, 32768) = 5136
lseek(3, 0, SEEK_SET)                   = 0
getdents64(3, /* 108 entries */, 32768) = 5136
close(3)

Given a directory with large filenames, PHP's DirectoryIterator on Ubuntu will result in the same: missing 118 files.

openat(AT_FDCWD, "/tmp/testdir-with-1000-255char-filenames/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0777, st_size=512, ...}) = 0
getdents64(3, /* 118 entries */, 32768) = 32528
lseek(3, 0, SEEK_SET)                   = 0
getdents64(3, /* 117 entries */, 32768) = 32760
getdents64(3, /* 117 entries */, 32768) = 32760
getdents64(3, /* 117 entries */, 32768) = 32760
<snip>
getdents64(3, /* 117 entries */, 32768) = 32760
getdents64(3, /* 56 entries */, 32768)  = 15680
getdents64(3, /* 0 entries */, 32768)   = 0

Analyzing the given behavior I suspect the seeking in the directory structure was not implemented. This does not happen on the ext4 filesystem.

I'm not sure if seeking in a directory file pointer is logical or needed, but there are software implementations using this that will break if not implemented.

Referencing a PHP ticket with the same symptoms: https://bugs.php.net/bug.php?id=80056

Expected behavior

open("/tmp/testdir", O_RDONLY|O_CLOEXEC|O_DIRECTORY) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents64(3, /* 44 entries */, 2048)   = 2048
lseek(3, 0, SEEK_SET)                   = 0
getdents64(3, /* 44 entries */, 2048)   = 2048
getdents64(3, /* 41 entries */, 2048)   = 2024
getdents64(3, /* 23 entries */, 2048)   = 1064
getdents64(3, /* 0 entries */, 2048)    = 0
close(3)

Actual behavior

open("/tmp/testdir", O_RDONLY|O_CLOEXEC|O_DIRECTORY) = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents64(3, /* 44 entries */, 2048)   = 2048
lseek(3, 0, SEEK_SET)                   = 0
getdents64(3, /* 41 entries */, 2048)   = 2024              <--- Expected: 44 entries, then: 41, 23, 0
getdents64(3, /* 23 entries */, 2048)   = 1064
getdents64(3, /* 0 entries */, 2048)    = 0
close(3)
@therealkenc
Copy link
Collaborator

/dupe #5074

@ghost
Copy link

ghost commented Sep 17, 2020

Hi! We've identified this issue as a duplicate of another one that already exists in this repository. This specific instance is being closed in favor of tracking the concern over on the referenced thread.

Thanks for your report!

@ghost ghost closed this as completed Sep 17, 2020
@ghost ghost added the duplicate label Sep 17, 2020
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants