[PATCH 1/4] sb: Fix long path support in copy_tree and removeall path support.

Chris Johns chrisj at rtems.org
Tue Aug 8 23:39:31 UTC 2017


The change lets the LM32 target build on Windows which has temporary
install paths greater than the Win32 API max size. The buildroot path
compression is still needed as the GNU assembler does not like paths
that exceed the max Windows limit.

Closes #2992.
---
 source-builder/sb/path.py | 99 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 64 insertions(+), 35 deletions(-)

diff --git a/source-builder/sb/path.py b/source-builder/sb/path.py
index 2c20248..5f48d26 100644
--- a/source-builder/sb/path.py
+++ b/source-builder/sb/path.py
@@ -34,6 +34,7 @@ import string
 import error
 
 windows = os.name == 'nt'
+win_maxpath = 254
 
 def host(path):
     if path is not None:
@@ -46,13 +47,16 @@ def host(path):
                 path[1] in string.ascii_uppercase):
                 path = '%s:%s' % (path[1], path[2:])
             path = path.replace('/', '\\')
-            if not path.startswith('\\\\?\\') and len(path) > 254:
-                path = '\\\\?\\' + path
+            if len(path) > win_maxpath:
+                if path.startswith('\\\\?\\'):
+                    path = path[4:]
+                path = u'\\'.join([u'\\\\?', path])
     return path
 
 def shell(path):
     if path is not None:
         if windows:
+            path = path.encode('ascii', 'ignore')
             if path.startswith('\\\\?\\'):
                 path = path[4:]
             if len(path) > 1 and path[1] == ':':
@@ -84,13 +88,22 @@ def splitext(path):
     root, ext = os.path.splitext(host(path))
     return shell(root), ext
 
+def listdir(path):
+    hp = host(path)
+    if not os.path.exists(hp):
+        return []
+    return os.listdir(hp)
+
 def exists(paths):
+    def _exists(p):
+        return os.path.basename(p) in listdir(dirname(p))
+
     if type(paths) == list:
         results = []
         for p in paths:
-            results += [os.path.exists(host(p))]
+            results += [_exists(p)]
         return results
-    return os.path.exists(host(paths))
+    return _exists(paths)
 
 def isdir(path):
     return os.path.isdir(host(path))
@@ -107,7 +120,7 @@ def iswritable(path):
 def ispathwritable(path):
     path = host(path)
     while len(path) != 0:
-        if os.path.exists(path):
+        if exists(path):
             return iswritable(path)
         path = os.path.dirname(path)
     return False
@@ -135,33 +148,48 @@ def mkdir(path):
             except OSError as err:
                 raise error.general('cannot make directory: %s' % (path))
 
+def chdir(path):
+    os.chdir(host(path))
+
 def removeall(path):
     #
     # Perform the removal of the directory tree manually so we can
-    # make sure on Windows the files and correctly encoded to avoid
-    # the size limit.
+    # make sure on Windows the files are correctly encoded to avoid
+    # the file name size limit. On Windows the os.walk fails once we
+    # get to the max path length on Windows.
     #
-    path = host(path)
-    for root, dirs, files in os.walk(path, topdown = False):
-        for name in files:
-            file = host(os.path.join(root, name))
-            if not os.path.islink(file) and not os.access(file, os.W_OK):
-                os.chmod(file, stat.S_IWUSR)
-            os.unlink(file)
-        for name in dirs:
-            dir = host(os.path.join(root, name))
-            if os.path.islink(dir):
-                os.unlink(dir)
+    def _isdir(path):
+        hpath = host(path)
+        return os.path.isdir(hpath) and not os.path.islink(hpath)
+
+    def _remove_node(path):
+        hpath = host(path)
+        if not os.path.islink(hpath) and not os.access(hpath, os.W_OK):
+            os.chmod(hpath, stat.S_IWUSR)
+        if _isdir(path):
+            os.rmdir(hpath)
+        else:
+            os.unlink(hpath)
+
+    def _remove(path):
+        dirs = []
+        for name in listdir(path):
+            path_ = join(path, name)
+            hname = host(path_)
+            if _isdir(path_):
+                dirs += [name]
             else:
-                if not os.access(dir, os.W_OK):
-                    os.chmod(dir, stat.S_IWUSR)
-                os.rmdir(dir)
-    if not os.path.islink(path) and not os.access(path, os.W_OK):
-        os.chmod(path, stat.S_IWUSR)
-    if os.path.islink(path):
-        os.unlink(path)
-    else:
-        os.rmdir(path)
+                _remove_node(path_)
+        for name in dirs:
+            dir = join(path, name)
+            _remove(dir)
+            _remove_node(dir)
+
+    hpath = host(path)
+
+    if os.path.exists(hpath):
+        _remove(path)
+        _remove_node(path)
 
 def expand(name, paths):
     l = []
@@ -187,17 +215,17 @@ def copy_tree(src, dst):
     hsrc = host(src)
     hdst = host(dst)
 
-    if os.path.exists(hsrc):
-        names = os.listdir(hsrc)
+    if exists(hsrc):
+        names = listdir(hsrc)
     else:
         names = []
 
     if trace:
         print('path.copy_tree:')
-        print('   src: %s' % (src))
-        print('  hsrc: %s' % (hsrc))
-        print('   dst: %s' % (dst))
-        print('  hdst: %s' % (hdst))
+        print('   src: "%s"' % (src))
+        print('  hsrc: "%s"' % (hsrc))
+        print('   dst: "%s"' % (dst))
+        print('  hdst: "%s"' % (hdst))
         print(' names: %r' % (names))
 
     if not os.path.isdir(hdst):
@@ -215,7 +243,7 @@ def copy_tree(src, dst):
         try:
             if os.path.islink(srcname):
                 linkto = os.readlink(srcname)
-                if os.path.exists(dstname):
+                if exists(dstname):
                     if os.path.islink(dstname):
                         dstlinkto = os.readlink(dstname)
                         if linkto != dstlinkto:
@@ -231,7 +259,8 @@ def copy_tree(src, dst):
             elif os.path.isdir(srcname):
                 copy_tree(srcname, dstname)
             else:
-                    shutil.copy2(host(srcname), host(dstname))
+                shutil.copyfile(host(srcname), host(dstname))
+                shutil.copystat(host(srcname), host(dstname))
         except shutil.Error as err:
             raise error.general('copying tree (2): %s -> %s: %s' % \
                                 (hsrc, hdst, str(err)))
-- 
2.13.2



More information about the devel mailing list