@@ -2492,6 +2492,116 @@ def my_mkdir(path, mode=0o777):
24922492 self .assertNotIn (str (p12 ), concurrently_created )
24932493 self .assertTrue (p .exists ())
24942494
2495+ @unittest .skipIf (
2496+ is_emscripten or is_wasi ,
2497+ "umask is not implemented on Emscripten/WASI."
2498+ )
2499+ @unittest .skipIf (
2500+ sys .platform == "android" ,
2501+ "Android filesystem may not honor requested permissions."
2502+ )
2503+ def test_mkdir_parents_umask (self ):
2504+ # Test that parent directories respect umask when parent_mode is not set
2505+ p = self .cls (self .base , 'umasktest' , 'child' )
2506+ self .assertFalse (p .exists ())
2507+ if os .name != 'nt' :
2508+ with os_helper .temp_umask (0o002 ):
2509+ p .mkdir (0o755 , parents = True )
2510+ self .assertTrue (p .exists ())
2511+ # Leaf directory gets the specified mode
2512+ self .assertEqual (p .stat ().st_mode & 0o777 , 0o755 )
2513+ # Parent directory respects umask (0o777 & ~0o002 = 0o775)
2514+ self .assertEqual (p .parent .stat ().st_mode & 0o777 , 0o775 )
2515+
2516+ @unittest .skipIf (
2517+ is_emscripten or is_wasi ,
2518+ "umask is not implemented on Emscripten/WASI."
2519+ )
2520+ @unittest .skipIf (
2521+ sys .platform == "android" ,
2522+ "Android filesystem may not honor requested permissions."
2523+ )
2524+ def test_mkdir_with_parent_mode (self ):
2525+ # Test the parent_mode parameter
2526+ p = self .cls (self .base , 'newdirPM' , 'subdirPM' )
2527+ self .assertFalse (p .exists ())
2528+ if os .name != 'nt' :
2529+ with os_helper .temp_umask (0o022 ):
2530+ # Specify different modes for parent and leaf directories
2531+ p .mkdir (0o755 , parents = True , parent_mode = 0o750 )
2532+ self .assertTrue (p .exists ())
2533+ self .assertTrue (p .is_dir ())
2534+ # Leaf directory gets the mode parameter
2535+ self .assertEqual (p .stat ().st_mode & 0o777 , 0o755 )
2536+ # Parent directory gets the parent_mode parameter
2537+ self .assertEqual (p .parent .stat ().st_mode & 0o777 , 0o750 )
2538+
2539+ @unittest .skipIf (
2540+ is_emscripten or is_wasi ,
2541+ "umask is not implemented on Emscripten/WASI."
2542+ )
2543+ @unittest .skipIf (
2544+ sys .platform == "android" ,
2545+ "Android filesystem may not honor requested permissions."
2546+ )
2547+ def test_mkdir_parent_mode_deep_hierarchy (self ):
2548+ # Test parent_mode with deep directory hierarchy
2549+ p = self .cls (self .base , 'level1PM' , 'level2PM' , 'level3PM' )
2550+ self .assertFalse (p .exists ())
2551+ if os .name != 'nt' :
2552+ with os_helper .temp_umask (0o022 ):
2553+ p .mkdir (0o755 , parents = True , parent_mode = 0o700 )
2554+ self .assertTrue (p .exists ())
2555+ # Check that all parent directories have parent_mode
2556+ level1 = self .cls (self .base , 'level1PM' )
2557+ level2 = level1 / 'level2PM'
2558+ self .assertEqual (level1 .stat ().st_mode & 0o777 , 0o700 )
2559+ self .assertEqual (level2 .stat ().st_mode & 0o777 , 0o700 )
2560+ # Leaf directory has the regular mode
2561+ self .assertEqual (p .stat ().st_mode & 0o777 , 0o755 )
2562+
2563+ @unittest .skipIf (
2564+ is_emscripten or is_wasi ,
2565+ "umask is not implemented on Emscripten/WASI."
2566+ )
2567+ @unittest .skipIf (
2568+ sys .platform == "android" ,
2569+ "Android filesystem may not honor requested permissions."
2570+ )
2571+ def test_mkdir_parent_mode_combined_with_umask (self ):
2572+ # parent_mode, like mode, is combined with the process umask; it does
2573+ # not bypass it.
2574+ p = self .cls (self .base , 'umaskPM' , 'child' )
2575+ self .assertFalse (p .exists ())
2576+ if os .name != 'nt' :
2577+ with os_helper .temp_umask (0o022 ):
2578+ p .mkdir (0o777 , parents = True , parent_mode = 0o777 )
2579+ self .assertTrue (p .exists ())
2580+ # 0o777 is masked down to 0o755 by the 0o022 umask, for both
2581+ # the leaf (mode) and the parent (parent_mode).
2582+ self .assertEqual (p .stat ().st_mode & 0o777 , 0o755 )
2583+ self .assertEqual (p .parent .stat ().st_mode & 0o777 , 0o755 )
2584+
2585+ @unittest .skipIf (
2586+ is_emscripten or is_wasi ,
2587+ "umask is not implemented on Emscripten/WASI."
2588+ )
2589+ @unittest .skipIf (
2590+ sys .platform == "android" ,
2591+ "Android filesystem may not honor requested permissions."
2592+ )
2593+ def test_mkdir_parent_mode_same_as_mode (self ):
2594+ # Test setting parent_mode same as mode
2595+ p = self .cls (self .base , 'samedirPM' , 'subdirPM' )
2596+ self .assertFalse (p .exists ())
2597+ if os .name != 'nt' :
2598+ with os_helper .temp_umask (0o022 ):
2599+ p .mkdir (0o705 , parents = True , parent_mode = 0o705 )
2600+ self .assertTrue (p .exists ())
2601+ # Both directories should have the same mode
2602+ self .assertEqual (p .stat ().st_mode & 0o777 , 0o705 )
2603+ self .assertEqual (p .parent .stat ().st_mode & 0o777 , 0o705 )
2604+
24952605 @needs_symlinks
24962606 def test_symlink_to (self ):
24972607 P = self .cls (self .base )
0 commit comments