rust-lang / rust-lang/libs-team
ACP: O_DIRECTORY open flag on OpenOptionsExt
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 178
- Forks
- 28
- Avg merge
- 15m
- Merged PRs (30d)
- 1
Description
Proposal
Problem statement
OpenOptions can only express "open this path only if it is a directory" through custom_flags
and a target-specific constant:
OpenOptions::new().read(true).custom_flags(libc::O_DIRECTORY).open(path)?;
That is a libc dependency or a value you define per target, or handing the open to a crate like
rustix.
Doing the check separately without O_DIRECTORY is not desirable, and could introduce race
conditions or undesirable side effects.
The intent is portable, O_DIRECTORY is POSIX and means the same thing on every unix that has it.
Only the value is platform-specific.
Motivating examples or use cases
Today everyone who needs it has to take a libc dependency, or define the target-specific value
for the flag.
Yazi opens a directory it just created and then works through the descriptor, with custom_flags(O_DIRECTORY | O_NOFOLLOW).
uutils' dd does the same to implement iflag=directory.
None of them would drop libc for this one option, they use other flags too. The benefit of the
proposed API is a named, discoverable option instead of a raw i32, and one that a later
custom_flags call does not overwrite.
Code that reaches for libc only to name this flag could drop the dependency by relying on it.
Solution sketch
// std::os::unix::fs::OpenOptionsExt
/// Sets the option to require that the path is a directory.
///
/// If set, the open passes `O_DIRECTORY` and fails with
/// `io::ErrorKind::NotADirectory` when the path is not a directory.
fn directory(&mut self, directory: bool) -> &mut Self;
Same shape as the other OpenOptions setters, read(bool) and create(bool).
- No new
ErrorKind:ENOTDIRalready decodes toNotADirectory. - Combinations that cannot work are left to the OS: for example, with
.write(true)the open fails
withEISDIR. - A few tier 3 targets have no
O_DIRECTORYinlibc, see open questions below.
Alternatives
custom_flagswith the constant fromlibc, or a crate like rustix performing the open. Both
approaches add a dependency, or platform-specific handling.- A portable option on
OpenOptions, suggested before. Opening a directory succeeds
on unix but needs an extra flag on Windows, so an option could carry that intent instead of
leaving it to the platform.
Open questions
- On the tier 3 targets whose
libchas noO_DIRECTORY, shoulddirectory(true)have no effect
(silently skip), or should the open fail withErrorKind::Unsupported? example: std skips
O_NOFOLLOWon some of them. - Naming.
directory(bool)follows 842, which named its method after the flag.
Other names could be considered:require_directory(bool)says what it does more directly but doesn't follow the convention.
Links and related work
- 842: where this was mentioned, as worth discussing in separate ACP.
- 64144: opening a directory succeeds, so the mistake surfaces at the first read.
- dirfd: directory handles, same motivation.
- Prior art:
rustix::fs::OFlags::DIRECTORY,
nix::fcntl::OFlag::O_DIRECTORY.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the proposed OpenOptionsExt API and the existing Unix handling referenced in library/std/src/sys/fs/unix.rs. Review ACP 842, the tier 3 targets lacking O_DIRECTORY, and the linked prior discussions before evaluating the open questions. Done means the method name, unsupported-platform behavior, and flag interactions have a settled design.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100