@@ -216,8 +216,8 @@ fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
216216 Ok ( ( ) )
217217}
218218
219- // Return true if the directory at `path` has been created by this call .
220- // `is_parent` argument is not used on windows
219+ // Create a directory at the given path .
220+ // Uses iterative approach instead of recursion to avoid stack overflow with deep nesting.
221221#[ allow( unused_variables) ]
222222fn create_dir ( path : & Path , is_parent : bool , config : & Config ) -> UResult < ( ) > {
223223 let path_exists = path. exists ( ) ;
@@ -231,15 +231,41 @@ fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> {
231231 return Ok ( ( ) ) ;
232232 }
233233
234+ // Iterative implementation: collect all directories to create, then create them
235+ // This avoids stack overflow with deeply nested directories
234236 if config. recursive {
235- match path. parent ( ) {
236- Some ( p) => create_dir ( p, true , config) ?,
237- None => {
238- USimpleError :: new ( 1 , translate ! ( "mkdir-error-failed-to-create-tree" ) ) ;
237+ // Pre-allocate approximate capacity to avoid reallocations
238+ let mut dirs_to_create = Vec :: with_capacity ( 16 ) ;
239+ let mut current = path;
240+
241+ // First pass: collect all parent directories
242+ while let Some ( parent) = current. parent ( ) {
243+ if parent == Path :: new ( "" ) {
244+ break ;
245+ }
246+ dirs_to_create. push ( parent) ;
247+ current = parent;
248+ }
249+
250+ // Second pass: create directories from root to leaf
251+ // Only create those that don't exist
252+ for dir in dirs_to_create. iter ( ) . rev ( ) {
253+ if !dir. exists ( ) {
254+ create_single_dir ( dir, true , config) ?;
239255 }
240256 }
241257 }
242258
259+ // Create the target directory
260+ create_single_dir ( path, is_parent, config)
261+ }
262+
263+ // Helper function to create a single directory with appropriate permissions
264+ // `is_parent` argument is not used on windows
265+ #[ allow( unused_variables) ]
266+ fn create_single_dir ( path : & Path , is_parent : bool , config : & Config ) -> UResult < ( ) > {
267+ let path_exists = path. exists ( ) ;
268+
243269 match std:: fs:: create_dir ( path) {
244270 Ok ( ( ) ) => {
245271 if config. verbose {
@@ -287,7 +313,24 @@ fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> {
287313 Ok ( ( ) )
288314 }
289315
290- Err ( _) if path. is_dir ( ) => Ok ( ( ) ) ,
316+ Err ( _) if path. is_dir ( ) => {
317+ // Directory already exists - check if this is a logical directory creation
318+ // (i.e., not just a parent reference like "test_dir/..")
319+ let ends_with_parent_dir = matches ! (
320+ path. components( ) . next_back( ) ,
321+ Some ( std:: path:: Component :: ParentDir )
322+ ) ;
323+
324+ // Print verbose message for logical directories, even if they exist
325+ // This matches GNU behavior for paths like "test_dir/../test_dir_a"
326+ if config. verbose && is_parent && config. recursive && !ends_with_parent_dir {
327+ println ! (
328+ "{}" ,
329+ translate!( "mkdir-verbose-created-directory" , "util_name" => uucore:: util_name( ) , "path" => path. quote( ) )
330+ ) ;
331+ }
332+ Ok ( ( ) )
333+ }
291334 Err ( e) => Err ( e. into ( ) ) ,
292335 }
293336}
0 commit comments