Skip to content

truncate: correctly handle file (non-)creation#6108

Merged
sylvestre merged 3 commits intouutils:mainfrom
BenWiederhake:dev-truncate-reference-create
Mar 23, 2024
Merged

truncate: correctly handle file (non-)creation#6108
sylvestre merged 3 commits intouutils:mainfrom
BenWiederhake:dev-truncate-reference-create

Conversation

@BenWiederhake
Copy link
Copy Markdown
Collaborator

@BenWiederhake BenWiederhake commented Mar 23, 2024

This PR fixes three issues:

  • The tests test_reference and test_truncate_bytes_size had dead code with comments "Uncomment when XYZ is implemented", but XYZ was already implemented two years ago. So I uncommented it.
  • The implementations for "reference-only" and "reference-and-size" lacked the logic that "file not truncated because it's missing" is not an error when --no-create. So I moved the code from the "size-only" implementation to the common function.
  • The fifo-check was copy-pasted in all three implementations, and contained a bug where a missing file would error out. This is fixed here.

Note that truncate still has a TOCTOU bug: The fifo check is done on the path, not on the file(descriptor), which leaves a (very short) window of time where a regular file could be swapped out for a fifo. The "correct way" is probably to drop the fifo check entirely and instead open the file in a special non-blocking way: https://users.rust-lang.org/t/opening-a-fifo-for-writing-hangs/107738 However, I'm not gonna touch that.

return Err(USimpleError::new(
1,
format!(
"cannot open {} for writing: No such device or address",
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.

This error message is indeed a clear indication that we're doing something wrong. We should be making a syscall that returns "No such device or address". That shouldn't block merging this PR though, we can indeed fix that later if you don't want to do it now.

strace shows this call as the one generating that error:

openat(AT_FDCWD, "blabla", O_WRONLY|O_NONBLOCK) = -1 ENXIO (No such device or address)

This Rust code:

OpenOptions::new().write(true).create(true).open("myfifo");

actually does the following syscall:

openat(AT_FDCWD, "myfifo", O_WRONLY|O_CLOEXEC)

Looks like the O_NONBLOCK is the culprit there. So maybe we can just fix this by setting the same mode as GNU via OpenOptionsExt and the appropriate libc constants?

This got me the right error message:

OpenOptions::new().write(true).custom_flags(libc::O_NONBLOCK).open("myfifo");

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.

Yes, opening the file in non-blocking mode is probably the right way forward, and your code looks correct. However, I don't want to fix this particular aspect in this PR; please note that this fifo-toctou-bug already existed before this PR, and remains unchanged.

@github-actions
Copy link
Copy Markdown

GNU testsuite comparison:

Congrats! The gnu test tests/mv/backup-dir is no longer failing!
Congrats! The gnu test tests/truncate/truncate-parameters is no longer failing!

@BenWiederhake
Copy link
Copy Markdown
Collaborator Author

BenWiederhake commented Mar 23, 2024

Oops! Looks like this broke everything on windows.

The fifo check used to include 'metadata(filename)?', which would error
if the file does not exist. In our case however, this is not an error.
@BenWiederhake BenWiederhake force-pushed the dev-truncate-reference-create branch from ad34bf9 to a1ad751 Compare March 23, 2024 16:51
@BenWiederhake
Copy link
Copy Markdown
Collaborator Author

Changes since last push:

  • Completely dropped the "avoid making redundant call to stat" commit, as it only makes sense on some platforms, and doesn't have any tangible impact anyway
  • Re-introduce #[cfg(unix)] when checking for fifos. This was present in the original code, but I accidentally removed it at some point. Now it is never deleted in the commits. This fixes Windows builds.

@github-actions
Copy link
Copy Markdown

GNU testsuite comparison:

Congrats! The gnu test tests/truncate/truncate-parameters is no longer failing!

@sylvestre
Copy link
Copy Markdown
Contributor

excellent! i guess it is ready ?

@sylvestre sylvestre merged commit ff1ecf6 into uutils:main Mar 23, 2024
@BenWiederhake BenWiederhake deleted the dev-truncate-reference-create branch March 23, 2024 18:05
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.

3 participants