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

If fd_readdir returns a zero inode, call fstatat to get the inode value. #345

Merged
merged 2 commits into from
Dec 2, 2022

Conversation

sunfishcode
Copy link
Member

On some systems, fd_readdir may not implement the d_ino field and may set it to zero. When this happens, have wasi-libc call fstatat to get the inode number.

See the discussion in
WebAssembly/wasi-filesystem#65 for details.

off_t d_ino = entry.d_ino;
if (d_ino == 0) {
if (fstatat(dirp->fd, dirent->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) != 0) {
return NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ENOENT etc can happen because of concurrent activities.
aborting on a fstat error here seems like an overreaction to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea about ENOENT. I've made it continue on that.


// `fd_readdir` implementations may set the inode field to zero if the
// the inode number is unknown. In that case, do an `fstatat` to get the
// inode number.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it (ie. d_ino can be 0) going to be a part of the official spec of fd_readdir?
otherwise i'm not sure if it's a good idea to have a workaround here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the idea here would be that we'd document that d_ino can be zero at the WASI level. I've now filed WebAssembly/wasi-filesystem#71 to track this.

Copy link
Contributor

@loganek loganek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might consider squashing some commits before the merge to keep the history clean.

@loganek
Copy link
Contributor

loganek commented Nov 29, 2022

I think that's an interesting scenario worth covering in https://github.com/WebAssembly/wasi-testsuite, would you mind adding a test for that?

@sunfishcode
Copy link
Member Author

Unfortunately, I don't know of a way to write a test for this with our current infrastructure. It requires an fd_readdir implementation which returns a 0 inode, which isn't something we can easily arrange. This might be doable in the future with virutalization though.

… value.

On some systems, `fd_readdir` may not implement the `d_ino` field and
may set it to zero. When this happens, have wasi-libc call `fstatat` to
get the inode number.

See the discussion in
WebAssembly/wasi-filesystem#65 for details.
@sunfishcode
Copy link
Member Author

In terms of standardizing this behavior, worst case if we don't standardize it is that wasi-libc makes redundant stat-atcalls which don't have any effect.

A potential concern is atomicity. With a separate stat-at call, there is a potential window between when one set of directory entries is read and when their inodes are read. My sense is that this isn't a problem, because directory traversal isn't atomic in general. If there are other processes creating and removing and renaming files in a directory at the same time as a readdir is iterating through the directory, the readdir isn't guaranteed to see an atomic snapshot.

That said, thinking about this led me to think about the case where a file is replaced by another filesystem object with a different type. That's straightforward to handle, so I've now added code to this PR to handle it.

@sunfishcode
Copy link
Member Author

There haven't been any objections to this approach on the spec side, and this doesn't break compatibility, so I'm going to go ahead and land this.

@sunfishcode sunfishcode merged commit be1ffd6 into main Dec 2, 2022
@sunfishcode sunfishcode deleted the sunfishcode/d_off branch December 2, 2022 01:44
if (fstatat(dirp->fd, dirent->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) != 0) {
if (errno == ENOENT) {
// The file disappeared before we could read it, so skip it.
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't you need to advance buffer_processed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I've now filed #352 to fix that and one other bug.

codefromthecrypt pushed a commit to tetratelabs/wazero that referenced this pull request Feb 23, 2023
wasi_snapshot_preview1 recently requires fd_readdir to return actual
inode values. On zero, wasi-libc will call fdstat to retrieve them.

This introduces our own `platform.Dirent` type and `Readdir` function
which a later change will allow fetching of inodes.

See WebAssembly/wasi-libc#345

Signed-off-by: Adrian Cole <adrian@tetrate.io>
codefromthecrypt added a commit to tetratelabs/wazero that referenced this pull request Feb 23, 2023
wasi_snapshot_preview1 recently requires fd_readdir to return actual
inode values. On zero, wasi-libc will call fdstat to retrieve them.

This introduces our own `platform.Dirent` type and `Readdir` function
which a later change will allow fetching of inodes.

See WebAssembly/wasi-libc#345

Signed-off-by: Adrian Cole <adrian@tetrate.io>
john-sharratt pushed a commit to john-sharratt/wasix-libc that referenced this pull request Mar 6, 2023
… value. (WebAssembly#345)

* If `fd_readdir` returns a zero inode, call `fstatat` to get the inode value.

On some systems, `fd_readdir` may not implement the `d_ino` field and
may set it to zero. When this happens, have wasi-libc call `fstatat` to
get the inode number.

See the discussion in
WebAssembly/wasi-filesystem#65 for details.

* Update the `d_type` field too, in case it changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants