Skip to content

Fix rename + calculateAt() - #27761

Open
hoodmane wants to merge 2 commits into
emscripten-core:mainfrom
hoodmane:fix-rename-with-at-syscalls
Open

hoodmane wants to merge 2 commits into
emscripten-core:mainfrom
hoodmane:fix-rename-with-at-syscalls

Conversation

@hoodmane

@hoodmane hoodmane commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

There is a bug in calculateAt(): if the directory node in the file system is renamed, calculateAt() will look up the path field and get a stale path. The regression test indicates the problem:

  1. create a/file.txt and b/subdir/file.txt
  2. set dirfd = open("b/subdir")
  3. rename b/subdir to b/subdir_moved
  4. add a symlink from b/subdir to a
  5. unlinkat(dirfd, "file.txt")

In the last step it should remove b/subdir_moved/file.txt and not remove a/file.txt. To fix we use FS.getPath(dirstream.node) to calculate the path, rather than using the dirstream.path field.

In NODERAWFS, this doesn't work, so I left it broken.

Comment thread src/lib/libsyscall.js Outdated
Comment thread src/lib/libsyscall.js Outdated
There is a bug in calculateAt(): if the directory node in the file system is
renamed, calculateAt() will look up the path field and get a stale path. The
regression test indicates the problem:

1. create a/file.txt and b/subdir/file.txt
2. set dirfd = open("b/subdir")
3. rename b/subdir to b/subdir_moved
4. add a symlink from b/subdir to a
5. unlinkat(dirfd, "file.txt")

In the last step it should remove b/subdir_moved/file.txt and not remove
a/file.txt. To fix we use `FS.getPath(dirstream.node)` to calculate the path,
rather than using the `dirstream.path` field.

In NODERAWFS, this doesn't work, so I left it broken.
@hoodmane
hoodmane force-pushed the fix-rename-with-at-syscalls branch from 38270df to 1ceefcd Compare September 22, 2026 19:28
@hoodmane
hoodmane force-pushed the fix-rename-with-at-syscalls branch from 1ceefcd to f8b0eba Compare September 22, 2026 19:30
Comment thread src/lib/libfs.js
}
set path(val) {
this._path = val;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this needed? i.e. can we make this a getter only?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Well sockfs, pipefs, and noderawfs all use it.

Comment thread src/lib/libnoderawfs.js
FS[key] = _wrapNodeStreamFunc(value, FS[key]);
}`,
}
`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Revert this?

unlink("unlinkat-dir/file");
rmdir("unlinkat-dir");
rmdir("unlinkat-dir-new");
#endif

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we make this into its own test_unlinkat.c? If it can fail independently of unlink then maybe it makes sense?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Can do that.


closedir(d);

#ifndef NODERAWFS // TODO: Fix NODERAWFS unlinkat() too.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do you know why NODERAWFS fails here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah but it's a bit of a tricky problem. We only have a directory descriptor and the original path that we opened the directory descriptor at. If the directory or any of its parents moved, the path changed but there is no way to find that out. Node doesn't expose unlinkat or any of the *at family operations.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hmm.. that is unfortunate.

This branch has not been deployed

No deployments
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.

2 participants