Skip to content

Fix an edge for certain platforms that views trailing cur dir components as a separate missing directory components - #162267

Open
asder8215 wants to merge 1 commit into
rust-lang:mainfrom
asder8215:create_dir_all_trailing_cur_dir
Open

asder8215 wants to merge 1 commit into
rust-lang:mainfrom
asder8215:create_dir_all_trailing_cur_dir

Conversation

@asder8215

@asder8215 asder8215 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #162243.

I talk about what the problem is in more details within the issue, but essentially when you have trailing cur dir components, e.g. "/tmp/foo/.", some platforms may fail with mkdir on this path because it could consider "foo" and the "." as two separate missing path components to create instead of normalizing the given path and seeing that "foo" is the only missing directory here (in which case mkdir should succeed).

What this PR does is it normalizes the provided path, so we don't experience this issue on certain platforms whose mkdir function do not normalize the cur dir component away (as all platforms should succeed with "/tmp/foo/."). There's Rust Playground link that @Raniz85 made that demonstrates the NotFound error occurring on "/tmp/foo/.".

…nts as a separate missing directory components via normalizing the provided path
@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 3, 2026
@rustbot

rustbot commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

r? @clarfonthey

rustbot has assigned @clarfonthey.
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 ChrisDenton, Darksonn, JohnTitor, Mark-Simulacrum, clarfonthey

@clarfonthey

Copy link
Copy Markdown
Contributor

Hmm, this is an interesting one. Right now, the behaviour of as_path on Components does do this (and tbh, I had no idea that components had the behaviour of removing ., but it makes sense), and it makes sense why Components::as_path does this, but I would not necessarily expect for that to hold in all cases for all time, especially since there is a compelling case that Components::as_path always returns the path passed in, even if there are current-directory components on the sides, before the first iteration.

I think it might be better to simply add a private method like Components::as_path_without_trailing_current_dir_components (you can bikeshed the name, or leave it as that long abomination) that currently just defers to as_path, so that we could potentially alter as_path to change how this behaviour works while still exploiting the fact that the behaviour is needed to solve this particular issue.

For example, I would expect that some of the prefix-parsing you do for Components might remove current-dir prefixes but there is no need to strip suffixes, so, maybe performance is better if we don't do that in advance.

Also, this isn't strictly required for this PR, but, it would be nice to document this semi-weird behaviour on Components::as_path. Something like: because of the various ways components removes/normalizes parts of paths, the resulting path is only guaranteed to have the same components, not be identical to its original OsStr representation.

@asder8215

Copy link
Copy Markdown
Contributor Author

but I would not necessarily expect for that to hold in all cases for all time, especially since there is a compelling case that Components::as_path always returns the path passed in, even if there are current-directory components on the sides, before the first iteration.

Are you referring to cases like "/tmp/foo/./bar"? In this case, We don't need to worry about the cur dir components in the middle of the path because Path::parent will normalize this out since it uses Components::next_back which normalizes away trailing separators and cur dir component if it's not the starting component.

For example, I would expect that some of the prefix-parsing you do for Components might remove current-dir prefixes but there is no need to strip suffixes, so, maybe performance is better if we don't do that in advance.

I'm a little bit confused by what you mean here. If I recall correctly, for prefixed components (current implementation), the Prefix exists in its own field prefix, and I believe we wouldn't be able to remove cur dir components out of Windows Prefix components via Components::as_path. The closest thing I can think of is DeviceNS prefix components, which starts with //./, but it has to follow with a device name from the doc comment, so Components::as_path should normalize any cur dir component inside there.

I think it might be better to simply add a private method like Components::as_path_without_trailing_current_dir_components (you can bikeshed the name, or leave it as that long abomination) that currently just defers to as_path, so that we could potentially alter as_path to change how this behaviour works while still exploiting the fact that the behaviour is needed to solve this particular issue.

I was considering on creating an ACP for this. I know we have a similar unstable function trim_trailing_sep, but I think it would've been more useful to have that function trim both trailing separators and trailing cur dirs (though we could also have a separate function, e.g. normalize_trailing_comps, for this purpose if need be). It probably would warrant less work compared to constructing a Components iterator and having Components::as_path do the work of normalizing trailing components for us.

I'm okay with doing a private method like what you suggested, but I think it a FIXME comment could also work here with suggesting that we should have a method that encapsulate the behavior of trimming trailing cur dir instead of relying on Components::as_path.

@asder8215

Copy link
Copy Markdown
Contributor Author

Also, this isn't strictly required for this PR, but, it would be nice to document this semi-weird behaviour on Components::as_path. Something like: because of the various ways components removes/normalizes parts of paths, the resulting path is only guaranteed to have the same components, not be identical to its original OsStr representation.

I can clarify the docs on Components::as_path in the Components rewrite PR.

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

Labels

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std::fs::create_dir_all fails on path ending with . if it does not already exist

3 participants