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
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: %s -> %s: %s' % \
(hsrc, hdst, str(err)))