]> granicus.if.org Git - llvm/commitdiff
lit: support long paths on Windows
authorSaleem Abdulrasool <compnerd@compnerd.org>
Fri, 5 Apr 2019 16:48:00 +0000 (16:48 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Fri, 5 Apr 2019 16:48:00 +0000 (16:48 +0000)
Use ctypes to call into SHFileOperationW with the extended NT path to allow us
to remove paths which exceed 261 characters on Windows. This functionality is
exercised by swift's test suite.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357778 91177308-0d34-0410-b5e6-96231b3b80d8

utils/lit/lit/TestRunner.py
utils/lit/lit/util.py

index 55d16b3751804056815c2a155f1ca7798389509f..8a1842f147ae27cc1cd6d5203c553beafa54698f 100644 (file)
@@ -353,7 +353,7 @@ def executeBuiltinMkdir(cmd, cmd_shenv):
             lit.util.mkdir_p(dir)
         else:
             try:
-                os.mkdir(dir)
+                lit.util.mkdir(dir)
             except OSError as err:
                 stderr.write("Error: 'mkdir' command failed, %s\n" % str(err))
                 exitCode = 1
@@ -613,7 +613,49 @@ def executeBuiltinRm(cmd, cmd_shenv):
                 if not recursive:
                     stderr.write("Error: %s is a directory\n" % path)
                     exitCode = 1
-                shutil.rmtree(path, onerror = on_rm_error if force else None)
+                if platform.system() == 'Windows':
+                    # NOTE: use ctypes to access `SHFileOperationsW` on Windows to
+                    # use the NT style path to get access to long file paths which
+                    # cannot be removed otherwise.
+                    from ctypes.wintypes import BOOL, HWND, LPCWSTR, POINTER, UINT, WORD
+                    from ctypes import c_void_p, byref
+                    from ctypes import Structure
+                    from ctypes import windll, WinError
+
+                    class SHFILEOPSTRUCTW(Structure):
+                        _fields_ = [
+                                ('hWnd', HWND),
+                                ('wFunc', UINT),
+                                ('pFrom', LPCWSTR),
+                                ('pTo', LPCWSTR),
+                                ('fFlags', WORD),
+                                ('fAnyOperationsAborted', BOOL),
+                                ('hNameMappings', c_void_p),
+                                ('lpszProgressTitle', LPCWSTR),
+                        ]
+
+                    FO_MOVE, FO_COPY, FO_DELETE, FO_RENAME = xrange(1, 5)
+
+                    FOF_SILENT = 4
+                    FOF_NOCONFIRMATION = 16
+                    FOF_NOCONFIRMMKDIR = 512
+                    FOF_NOERRORUI = 1024
+
+                    FOF_NO_UI = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR
+
+                    SHFileOperationW = windll.shell32.SHFileOperationW
+                    SHFileOperationW.argtypes = [POINTER(SHFILEOPSTRUCTW)]
+
+                    path = os.path.abspath(path)
+
+                    operation = SHFILEOPSTRUCTW(wFunc=UINT(FO_DELETE),
+                                                pFrom=LPCWSTR(unicode(path + '\0')),
+                                                fFlags=FOF_NO_UI)
+                    result = SHFileOperationW(byref(operation))
+                    if result:
+                        raise WinError(result)
+                else:
+                    shutil.rmtree(path, onerror = on_rm_error if force else None)
             else:
                 if force and not os.access(path, os.W_OK):
                     os.chmod(path,
index 44de061c629b15a280657b0dd27d04d6278f064d..3b1391115a533cab120e1ddcf7def368fca16690 100644 (file)
@@ -142,6 +142,25 @@ def detectCPUs():
     return 1  # Default
 
 
+def mkdir(path):
+    try:
+        if platform.system() == 'Windows':
+            from ctypes import windll
+            from ctypes import GetLastError, WinError
+
+            path = os.path.abspath(path)
+            NTPath = unicode(r'\\?\%s' % path)
+            if not windll.kernel32.CreateDirectoryW(NTPath, None):
+                raise WinError(GetLastError())
+        else:
+            os.mkdir(path)
+    except OSError:
+        e = sys.exc_info()[1]
+        # ignore EEXIST, which may occur during a race condition
+        if e.errno != errno.EEXIST:
+            raise
+
+
 def mkdir_p(path):
     """mkdir_p(path) - Make the "path" directory, if it does not exist; this
     will also make directories for any missing parent directories."""
@@ -152,13 +171,7 @@ def mkdir_p(path):
     if parent != path:
         mkdir_p(parent)
 
-    try:
-        os.mkdir(path)
-    except OSError:
-        e = sys.exc_info()[1]
-        # Ignore EEXIST, which may occur during a race condition.
-        if e.errno != errno.EEXIST:
-            raise
+    mkdir(path)
 
 
 def listdir_files(dirname, suffixes=None, exclude_filenames=None):