Skip to content

Add Dir::metadata_at & Dir::symlink_metadata_at - #163024

Open
RalfJung wants to merge 3 commits into
rust-lang:mainfrom
RalfJung:dir-metadata-at
Open

RalfJung wants to merge 3 commits into
rust-lang:mainfrom
RalfJung:dir-metadata-at

Conversation

@RalfJung

@RalfJung RalfJung commented Sep 19, 2026

Copy link
Copy Markdown
Member

View all comments

This adds methods to Dir that allow querying the metadata of files/directories relative to a Dir. Miri would really like to be able to do this so I figured I'd give it a shot. :)

The first commit refactors the Unix DirEntry methods a bit with cfg_select to avoid repeating the cfg condition.

Tracking issue: #120426

try-jobs: test-x86_64-msvc-1

@rustbot

rustbot commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Any special-casing of Miri in the standard library requires review.

cc @rust-lang/miri

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Sep 19, 2026
@rustbot

rustbot commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 13 candidates
  • Random selection from 6 candidates

Comment on lines +250 to +268
fn metadata_at_native(&self, path: &[u16], reparse: ReparsePoint) -> io::Result<FileAttr> {
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag());

// Attempt to open the file normally.
// FIXME: `fs::metadata` has a fallback path when that fails. That has not (yet) been ported
// to directory handles.
let name = UnicodeStrRef::from_slice(path);
let object_attributes = c::OBJECT_ATTRIBUTES {
RootDirectory: self.handle.as_raw_handle(),
ObjectName: name.as_ptr().cast_mut(),
..c::OBJECT_ATTRIBUTES::with_length()
};
let create_opt = 0; // We don't want to create anything, only open existing things.
let handle = unsafe { nt_create_file(&opts, &object_attributes, create_opt)? };
File { handle }.file_attr()
}

@RalfJung RalfJung Sep 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@ChrisDenton I hope this makes sense, I am mostly guessing here.^^ Especially about passing 0 for create_opt; the only other caller passes if dir { c::FILE_DIRECTORY_FILE } else { c::FILE_NON_DIRECTORY_FILE } but we cannot know in advance whether this is a directory or a file...

I also didn't copy the complicated fallback stuff from fs::metadata as I had no idea what that would look like with directory handles. I hope this first step is still useful and we can always add more fallback code later?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I left some notes but essentially NT APIs are a bit different to the higher level win32 APIs. I'm ok with a partial implementation since I think I'm likely going to be rewriting (or at least refactoring) a lot of this anyway.

@RalfJung

This comment was marked as resolved.

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Sep 19, 2026
Add `Dir::metadata_at` & `Dir::symlink_metadata_at`


try-job: test*msvc*
@rust-log-analyzer

This comment has been minimized.

@RalfJung
RalfJung force-pushed the dir-metadata-at branch 2 times, most recently from 23f96b7 to 473f0c0 Compare September 19, 2026 16:44
@rust-log-analyzer

This comment has been minimized.

@RalfJung

RalfJung commented Sep 19, 2026

Copy link
Copy Markdown
Member Author

Hm...

thread 'fs::tests::test_dir_metadata_at' (6552) panicked at library\std\src\fs\tests.rs:2812:5:
dir.open_file_with("subdir/bar.txt",
&OpenOptions::new().create(true).write(true)) failed with: The filename, directory name, or volume label syntax is incorrect. (os error 123)

Does this not support /? That would then likely affect the other Dir methods as well and would be inconsistent with the normal fs methods AFAIK.

This isn't even in my new method, the failure is from

dir.open_file_with("subdir/bar.txt", &OpenOptions::new().create(true).write(true))

I should file an issue... EDIT: #163032

@RalfJung

This comment was marked as outdated.

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Sep 19, 2026
Add `Dir::metadata_at` & `Dir::symlink_metadata_at`


try-job: test-*-msvc-1
Comment thread library/std/src/fs.rs
/// }
/// ```
#[unstable(feature = "dirfd", issue = "120426")]
pub fn metadata_at<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {

@RalfJung RalfJung Sep 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The name does match the operation in fs that it corresponds to -- but Dir::metadata is already taken. So I went for a new name, inspired by the Linux naming scheme with the *at calls working on directory handles.

Alternatives that have been suggested or that I can think of:

  • Use just metadata for this, and ask people to write dir.metadata(".") to get the metadata of the directory itself. But that seems silly in terms of the extra syscalls it causes.
  • Use just metadata for this, and use self_metadata/metadata_self or so for the metadata of the directory handle itself.

View changes since the review

@rust-log-analyzer

This comment has been minimized.

@rust-bors rust-bors Bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 19, 2026
@rust-bors

This comment was marked as outdated.

@RalfJung

This comment was marked as resolved.

@RalfJung

This comment was marked as outdated.

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Sep 19, 2026
Add `Dir::metadata_at` & `Dir::symlink_metadata_at`


try-job: test-*-msvc-1
@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment was marked as outdated.

Comment thread library/std/src/sys/fs/windows/dir.rs Outdated
Comment thread library/std/src/sys/fs/windows/dir.rs Outdated
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag());

@ChrisDenton ChrisDenton Sep 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

custom_flags is currently ignored by nt_create_file and those are the wrong types of flags anyway (win32 flags instead of the lower level NT). You'll need to do something like:

let create_opt = if reparse == ReparsePoint::Open { c::FILE_OPEN_REPARSE_POINT } else { 0 };

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hm, so is the existing code also wrong then? rename_native also sets custom_flags.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'll add a FIXME.

@RalfJung
RalfJung force-pushed the dir-metadata-at branch 2 times, most recently from 9fc06fa to 5877c7e Compare September 20, 2026 08:35
@RalfJung

Copy link
Copy Markdown
Member Author

@bors try jobs=test-x86_64-msvc-1

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Sep 20, 2026
Add `Dir::metadata_at` & `Dir::symlink_metadata_at`


try-job: test-x86_64-msvc-1
@rust-bors

rust-bors Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 0cc8c9a (0cc8c9a6dfc0223a5b3b11673ea1a7bdb5483ea8)
Base parent: feaadee (feaadeeaca7db0594da854e7c8c07495341c7439)

@RalfJung

Copy link
Copy Markdown
Member Author

That seems to have worked, thanks. :-)

@rust-bors

This comment has been minimized.

@rustbot

rustbot commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rust-log-analyzer

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants