sb: Fix long path support in the copy_tree and removeall path support.

This change lets the LM32 target build on Windows which has temporary
install paths greated 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.
This commit is contained in:
Chris Johns 2017-06-07 15:00:13 +10:00
parent 2433c4bd5f
commit 78c152453b

View File

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