Fix for window very-long-filename support. NFC (#1646)
We have a function called `fix_potentially_long_windows_pathname` which
is used when unzipping archives under windows.
Without this the unzip process will fail if the total filename length
ever exceeds 256. This change adds a test for installing deep in the
filesystem (where pathnames exceed 256) and fixes a bug in this code
which was causing the test to fail.
The fact that this code had this bug for god-known-how-long means I
think nobody was depending on it, so we could probably just remove it,
but fixing for now and adding a test.
diff --git a/emsdk.py b/emsdk.py
index 64d2714..f527860 100644
--- a/emsdk.py
+++ b/emsdk.py
@@ -574,14 +574,13 @@
unzip_to_dir = dest_dir
if common_subdir:
- debug_print(f'common_subdir: {common_subdir}')
unzip_to_dir = os.path.join(os.path.dirname(dest_dir), 'unzip_temp')
# Now do the actual decompress.
- target_dir = fix_potentially_long_windows_pathname(unzip_to_dir)
+ unzip_to_dir = fix_potentially_long_windows_pathname(unzip_to_dir)
for member in zf.infolist():
- zf.extract(member, target_dir)
- dst_filename = os.path.join(unzip_to_dir, member.filename)
+ zf.extract(member, unzip_to_dir)
+ dst_filename = os.path.join(unzip_to_dir, os.path.normpath(member.filename))
# See: https://stackoverflow.com/questions/42326428/zipfile-in-python-file-permission
unix_attributes = member.external_attr >> 16
diff --git a/test/test.py b/test/test.py
index a1b871c..47602fb 100755
--- a/test/test.py
+++ b/test/test.py
@@ -32,6 +32,12 @@
return [x]
+def copy_emsdk_to(targetdir):
+ for filename in os.listdir('.'):
+ if not filename.startswith('.') and not os.path.isdir(filename):
+ shutil.copy2(filename, os.path.join(targetdir, filename))
+
+
def check_call(cmd, **kwargs):
if type(cmd) is not list:
cmd = cmd.split()
@@ -79,6 +85,16 @@
return name
+def get_longest_path_in_dir(dirname):
+ longest = ''
+ for root, _dirs, files in os.walk(dirname):
+ for f in files:
+ fullname = os.path.join(root, f)
+ if len(fullname) > len(longest):
+ longest = fullname
+ return longest
+
+
# Set up
TAGS = json.loads(open('emscripten-releases-tags.json').read())
@@ -137,6 +153,46 @@
run_emsdk('install latest')
run_emsdk('activate latest')
+ def test_extrememly_long_filenames(self):
+ # We have special support for filenames longer than 256 on windows. This
+ # test installs emsdk in path that exceeds this limit in order to test
+ # this handling.
+ longpath = os.path.abspath('very_long_filename_indeed')
+
+ additional = 140 - len(longpath)
+ longpath += 'x' * additional
+ if os.path.exists(longpath):
+ # shutil.rmtree requires the special long path prefix
+ longpath_with_prefix = '\\\\?\\' + longpath
+ assert os.path.exists(longpath_with_prefix)
+ shutil.rmtree(longpath_with_prefix)
+
+ os.makedirs(longpath)
+ copy_emsdk_to(longpath)
+
+ emsdk = os.path.join(longpath, 'emsdk')
+ if WINDOWS:
+ emsdk += '.bat'
+ self.assertTrue(os.path.exists(emsdk))
+
+ check_call([emsdk, 'install', 'latest'])
+ check_call([emsdk, 'activate', 'latest'])
+
+ # Check that emcc exists in the expected location
+ emcc = os.path.join(longpath, 'upstream', 'emscripten', 'emcc')
+ if WINDOWS:
+ emcc += '.bat'
+ print(emcc)
+ self.assertTrue(os.path.exists(emcc))
+
+ # Find the longest installed path and assert this is longer than 256
+ longest_path = get_longest_path_in_dir(longpath)
+ print(f'longest ({len(longest_path)}: {longest_path})')
+ self.assertGreater(len(longest_path), 256)
+
+ # Finally make sure we can actaully compile something
+ check_call([emcc, 'hello_world.c'])
+
def test_unknown_arch(self):
env = os.environ.copy()
env['EMSDK_ARCH'] = 'mips'
@@ -236,9 +292,7 @@
print('test non-git update')
temp_dir = tempfile.mkdtemp()
- for filename in os.listdir('.'):
- if not filename.startswith('.') and not os.path.isdir(filename):
- shutil.copy2(filename, os.path.join(temp_dir, filename))
+ copy_emsdk_to(temp_dir)
olddir = os.getcwd()
try: