88use clap:: builder:: ValueParser ;
99use clap:: parser:: ValuesRef ;
1010use clap:: { Arg , ArgAction , ArgMatches , Command } ;
11+ use std:: collections:: VecDeque ;
1112use std:: ffi:: OsString ;
1213use std:: path:: { Path , PathBuf } ;
1314#[ cfg( not( windows) ) ]
@@ -218,7 +219,6 @@ fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
218219
219220// Create a directory at the given path.
220221// Uses iterative approach instead of recursion to avoid stack overflow with deep nesting.
221- // `is_parent` argument is not used on windows
222222#[ allow( unused_variables) ]
223223fn create_dir ( path : & Path , is_parent : bool , config : & Config ) -> UResult < ( ) > {
224224 let path_exists = path. exists ( ) ;
@@ -235,24 +235,22 @@ fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> {
235235 // Iterative implementation: collect all directories to create, then create them
236236 // This avoids stack overflow with deeply nested directories
237237 if config. recursive {
238- // Collect all parent directories that need to be created
239- let mut dirs_to_create = Vec :: new ( ) ;
238+ // Collect all parent directories to process
239+ let mut dirs_to_process = VecDeque :: new ( ) ;
240240 let mut current = path;
241241
242- // Walk up the tree collecting non-existent directories
242+ // Walk up the tree collecting all parent directories
243243 while let Some ( parent) = current. parent ( ) {
244- if parent == Path :: new ( "" ) || parent . exists ( ) {
244+ if parent == Path :: new ( "" ) {
245245 break ;
246246 }
247- dirs_to_create. push ( parent) ;
247+
248+ dirs_to_process. push_front ( parent) ;
248249 current = parent;
249250 }
250251
251- // Reverse to create from root to leaf
252- dirs_to_create. reverse ( ) ;
253-
254- // Create each parent directory
255- for dir in dirs_to_create {
252+ // Process each parent directory (already in correct order)
253+ for dir in dirs_to_process {
256254 create_single_dir ( dir, true , config) ?;
257255 }
258256 }
@@ -262,6 +260,7 @@ fn create_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<()> {
262260}
263261
264262// Helper function to create a single directory with appropriate permissions
263+ // `is_parent` argument is not used on windows
265264#[ allow( unused_variables) ]
266265fn create_single_dir ( path : & Path , is_parent : bool , config : & Config ) -> UResult < ( ) > {
267266 let path_exists = path. exists ( ) ;
@@ -313,7 +312,24 @@ fn create_single_dir(path: &Path, is_parent: bool, config: &Config) -> UResult<(
313312 Ok ( ( ) )
314313 }
315314
316- Err ( _) if path. is_dir ( ) => Ok ( ( ) ) ,
315+ Err ( _) if path. is_dir ( ) => {
316+ // Directory already exists - check if this is a logical directory creation
317+ // (i.e., not just a parent reference like "test_dir/..")
318+ let ends_with_dotdot = matches ! (
319+ path. components( ) . next_back( ) ,
320+ Some ( std:: path:: Component :: ParentDir )
321+ ) ;
322+
323+ // Print verbose message for logical directories, even if they exist
324+ // This matches GNU behavior for paths like "test_dir/../test_dir_a"
325+ if config. verbose && is_parent && config. recursive && !ends_with_dotdot {
326+ println ! (
327+ "{}" ,
328+ translate!( "mkdir-verbose-created-directory" , "util_name" => uucore:: util_name( ) , "path" => path. quote( ) )
329+ ) ;
330+ }
331+ Ok ( ( ) )
332+ }
317333 Err ( e) => Err ( e. into ( ) ) ,
318334 }
319335}
0 commit comments