|
33 | 33 | from test.support import TESTFN, FakePath |
34 | 34 |
|
35 | 35 | TESTFN2 = TESTFN + "2" |
| 36 | +TESTFN_SRC = TESTFN + "_SRC" |
| 37 | +TESTFN_DST = TESTFN + "_DST" |
36 | 38 | MACOS = sys.platform.startswith("darwin") |
37 | 39 | AIX = sys.platform[:3] == 'aix' |
38 | 40 | try: |
@@ -2083,6 +2085,41 @@ def test_move_dir_caseinsensitive(self): |
2083 | 2085 | os.rmdir(dst_dir) |
2084 | 2086 |
|
2085 | 2087 |
|
| 2088 | + @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0 |
| 2089 | + and hasattr(os, 'lchflags') |
| 2090 | + and hasattr(stat, 'SF_IMMUTABLE') |
| 2091 | + and hasattr(stat, 'UF_OPAQUE'), |
| 2092 | + 'root privileges required') |
| 2093 | + def test_move_dir_permission_denied(self): |
| 2094 | + # bpo-42782: shutil.move should not create destination directories |
| 2095 | + # if the source directory cannot be removed. |
| 2096 | + try: |
| 2097 | + os.mkdir(TESTFN_SRC) |
| 2098 | + os.lchflags(TESTFN_SRC, stat.SF_IMMUTABLE) |
| 2099 | + |
| 2100 | + # Testing on an empty immutable directory |
| 2101 | + # TESTFN_DST should not exist if shutil.move failed |
| 2102 | + self.assertRaises(PermissionError, shutil.move, TESTFN_SRC, TESTFN_DST) |
| 2103 | + self.assertFalse(TESTFN_DST in os.listdir()) |
| 2104 | + |
| 2105 | + # Create a file and keep the directory immutable |
| 2106 | + os.lchflags(TESTFN_SRC, stat.UF_OPAQUE) |
| 2107 | + os_helper.create_empty_file(os.path.join(TESTFN_SRC, 'child')) |
| 2108 | + os.lchflags(TESTFN_SRC, stat.SF_IMMUTABLE) |
| 2109 | + |
| 2110 | + # Testing on a non-empty immutable directory |
| 2111 | + # TESTFN_DST should not exist if shutil.move failed |
| 2112 | + self.assertRaises(PermissionError, shutil.move, TESTFN_SRC, TESTFN_DST) |
| 2113 | + self.assertFalse(TESTFN_DST in os.listdir()) |
| 2114 | + finally: |
| 2115 | + if os.path.exists(TESTFN_SRC): |
| 2116 | + os.lchflags(TESTFN_SRC, stat.UF_OPAQUE) |
| 2117 | + os_helper.rmtree(TESTFN_SRC) |
| 2118 | + if os.path.exists(TESTFN_DST): |
| 2119 | + os.lchflags(TESTFN_DST, stat.UF_OPAQUE) |
| 2120 | + os_helper.rmtree(TESTFN_DST) |
| 2121 | + |
| 2122 | + |
2086 | 2123 | class TestCopyFile(unittest.TestCase): |
2087 | 2124 |
|
2088 | 2125 | class Faux(object): |
|
0 commit comments