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