Skip to content

Conversation

@asder8215
Copy link
Contributor

@asder8215 asder8215 commented Oct 28, 2025

The current implementation of create_dir_all(...) in std::fs operates recursively. As mentioned in #124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:

Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.

@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 Oct 28, 2025
@rustbot
Copy link
Collaborator

rustbot commented Oct 28, 2025

r? @tgross35

rustbot has assigned @tgross35.
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

@rustbot

This comment has been minimized.

@asder8215 asder8215 requested a review from bjorn3 October 28, 2025 12:52
@workingjubilee
Copy link
Member

Why does this need to manipulate a list of uncreated_dirs at all? Can't we just path.ancestors().rev() and start making directories? So what if we try to recreate the root of the filesystem. Aside from being silly, we'll just get io::ErrorKind::AlreadyExists.

@workingjubilee
Copy link
Member

workingjubilee commented Oct 28, 2025

🥴 Answer to jubilee: It's not a reversible iterator!!!

@workingjubilee
Copy link
Member

jubilee's counterargument to jubilee's counterargument: Okay, so we'd have to use path.ancestors().nth(i) instead, sure? But you get the idea.

@workingjubilee
Copy link
Member

workingjubilee commented Oct 28, 2025

Please feel free to question/reject my comment/suggestion if you feel it is incorrect/scope-creeping, I only am bringing it up because I had precisely this thought after wondering why code I had earlier written elsewhere was doing try_exists and then using create_dir_all.

@workingjubilee
Copy link
Member

workingjubilee commented Oct 28, 2025

Followup response to jubilee: what about create_dir_all("./somewhere/../../something")?

in the tune of "Khaaan!": RELATIVE PAAATHS!

@asder8215
Copy link
Contributor Author

Hey jubilee, I took your suggestion and iterate through the Ancestors Iterator. One thing that I did differently however is that instead of using path.ancestors().nth(i) to repeatedly traverse through the iterator up until the uncreated directory, I used a counter and .take() to pre-allocate the exact memory to hold the remaining directories that I need to create and then just use a reversed iterator on that.

Does this approach look good to you?

@workingjubilee
Copy link
Member

workingjubilee commented Oct 29, 2025

Yes, allocating once instead of many times sounds like a reasonable improvement in the spirit of my note, so if others are cool with it, then I'm cool! That way it's "just" a classic space vs. time tradeoff and getting the main improvement we're looking for.

@asder8215
Copy link
Contributor Author

Hi @tgross35, I noticed that you were the assignee for this pull request. I wanted to ask if there is anything I should change with this PR/commits or if everything looks alright?

@tgross35
Copy link
Contributor

tgross35 commented Nov 4, 2025

I haven't looked at this yet so I'm going to

r? @workingjubilee

who has. (I know it's at your limit so feel free to reroll again or throw it back if you want)

@rustbot rustbot assigned workingjubilee and unassigned tgross35 Nov 4, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 4, 2025

workingjubilee is currently at their maximum review capacity.
They may take a while to respond.

Copy link
Contributor

@tbu- tbu- left a comment

Choose a reason for hiding this comment

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

This now always allocates something on the heap when there's at least two directories that are created. Probably not worth optimizing away.

View changes since this review

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@asder8215
Copy link
Contributor Author

r? libs

@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 8, 2025
@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 14, 2025
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 14, 2025
…dir-all, r=Mark-Simulacrum

Implement create_dir_all() to operate iteratively instead of recursively

The current implementation of `create_dir_all(...)` in std::fs operates recursively. As mentioned in rust-lang#124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:
```
Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.
```
bors added a commit that referenced this pull request Dec 14, 2025
Rollup of 7 pull requests

Successful merges:

 - #146794 (std: reorganize pipe implementations)
 - #148196 (Implement create_dir_all() to operate iteratively instead of recursively)
 - #148490 (dangling pointer from temp cleanup)
 - #149864 (std: Don't use `linkat` on the `wasm32-wasi*` targets)
 - #149885 (replace addr_of_mut with &raw mut in maybeuninit docs)
 - #149949 (Cleanup of attribute parsing errors)
 - #149969 (don't use no_main and no_core to test IBT)

Failed merges:

 - #148847 (Share Timespec between Unix and Hermit)

r? `@ghost`
`@rustbot` modify labels: rollup
@matthiaskrgr
Copy link
Member

@bors r-
#149993 (comment)

@bors bors 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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Dec 14, 2025
@asder8215
Copy link
Contributor Author

asder8215 commented Dec 14, 2025

@Mark-Simulacrum I didn't know that aarch64-msvc-1 produces a "Access is denied. (os error 5)" message when it mkdirs on "/" directory (running on x86_64 linux, which gives me a file exists error).

I updated the code to add a check on whether the path given or path seen in ancestor is root via checking if its parent is None, so that it either returns Ok(()) immediately or breaks out of the for ancestor in ancestors loop immediately. Let me know what you think and I'll combine the commits into one.

@asder8215
Copy link
Contributor Author

r? libs

@rustbot rustbot assigned jhpratt and unassigned Mark-Simulacrum Jan 9, 2026
@jhpratt
Copy link
Member

jhpratt commented Jan 10, 2026

@bors r=Mark-Simulacrum,jhpratt

@rust-bors rust-bors bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 10, 2026
@rust-bors
Copy link
Contributor

rust-bors bot commented Jan 10, 2026

📌 Commit 167ad11 has been approved by Mark-Simulacrum,jhpratt

It is now in the queue for this repository.

Zalathar added a commit to Zalathar/rust that referenced this pull request Jan 10, 2026
…=Mark-Simulacrum,jhpratt

Implement create_dir_all() to operate iteratively instead of recursively

The current implementation of `create_dir_all(...)` in std::fs operates recursively. As mentioned in rust-lang#124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:
```
Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.
```
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 10, 2026
…=Mark-Simulacrum,jhpratt

Implement create_dir_all() to operate iteratively instead of recursively

The current implementation of `create_dir_all(...)` in std::fs operates recursively. As mentioned in rust-lang#124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:
```
Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.
```
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jan 10, 2026
…=Mark-Simulacrum,jhpratt

Implement create_dir_all() to operate iteratively instead of recursively

The current implementation of `create_dir_all(...)` in std::fs operates recursively. As mentioned in rust-lang#124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:
```
Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.
```
rust-bors bot added a commit that referenced this pull request Jan 11, 2026
Rollup of 11 pull requests

Successful merges:

 - #148196 (Implement create_dir_all() to operate iteratively instead of recursively)
 - #150494 ( Fix dso_local for external statics with linkage)
 - #150788 (THIR patterns: Replace `AscribeUserType` and `ExpandedConstant` wrappers with per-node data)
 - #150799 (Fix ICE: can't type-check body of DefId  for issue #148729)
 - #150804 (Remove std_detect_file_io and std_detect_dlsym_getauxval features)
 - #150852 (std: sys: fs: uefi: Implement File::write)
 - #150871 (Use f64 NaN in documentation instead of sqrt(-1.0))
 - #150878 (Emit an error for linking staticlibs on BPF)
 - #150911 (Add missing documentation for globs feature)
 - #150913 (compiler: Forward attributes to eii-expanded macros)
 - #150916 (Once again, reorganize the EII tests a bit)

r? @ghost
rust-bors bot added a commit that referenced this pull request Jan 11, 2026
Rollup of 12 pull requests

Successful merges:

 - #150947 (alloctests: Don't run the longer partial-sort tests under Miri)
 - #148196 (Implement create_dir_all() to operate iteratively instead of recursively)
 - #150494 ( Fix dso_local for external statics with linkage)
 - #150788 (THIR patterns: Replace `AscribeUserType` and `ExpandedConstant` wrappers with per-node data)
 - #150799 (Fix ICE: can't type-check body of DefId  for issue #148729)
 - #150804 (Remove std_detect_file_io and std_detect_dlsym_getauxval features)
 - #150852 (std: sys: fs: uefi: Implement File::write)
 - #150871 (Use f64 NaN in documentation instead of sqrt(-1.0))
 - #150878 (Emit an error for linking staticlibs on BPF)
 - #150911 (Add missing documentation for globs feature)
 - #150913 (compiler: Forward attributes to eii-expanded macros)
 - #150916 (Once again, reorganize the EII tests a bit)

r? @ghost
@rust-bors rust-bors bot merged commit dda4963 into rust-lang:main Jan 11, 2026
11 checks passed
@rustbot rustbot added this to the 1.94.0 milestone Jan 11, 2026
rust-timer added a commit that referenced this pull request Jan 11, 2026
Rollup merge of #148196 - std-fs-iterative-create-dir-all, r=Mark-Simulacrum,jhpratt

Implement create_dir_all() to operate iteratively instead of recursively

The current implementation of `create_dir_all(...)` in std::fs operates recursively. As mentioned in #124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:
```
Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.
```
@asder8215 asder8215 deleted the std-fs-iterative-create-dir-all branch January 12, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.