From fac84c7eda5b28af36c3139bb565659a9ed80aec Mon Sep 17 00:00:00 2001 From: Stewart Miles Date: Mon, 7 Oct 2024 07:30:52 -0700 Subject: [PATCH] Do not use the absolute path to cache wheel extensions. (#226) Wheel names can be long and paths to mounted wheels can be long. Previously `util.path_to_cache_dir()` was unconditionally building cache paths using the absolute path of the cache directory joined with the absolute path to a wheel being mounted. This makes it very easy to generate in huge paths that exceed the maximum path length (MAX_PATH) on Windows machines without the [registry change](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry) to support long paths. A user-wide shared location for cached data is potentially easy enough to poison with incorrect extensions, so using the absolute path of a wheel being mounted to cache extensions doesn't seem to add any more protection and results in very long hard to read paths that can exceed Windows path limits in out of the box installations. Fixes #224 --- distlib/util.py | 8 ++++---- distlib/wheel.py | 2 +- tests/test_util.py | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/distlib/util.py b/distlib/util.py index aa76a97..0d5bd7a 100644 --- a/distlib/util.py +++ b/distlib/util.py @@ -789,7 +789,7 @@ def get_cache_base(suffix=None): return os.path.join(result, suffix) -def path_to_cache_dir(path): +def path_to_cache_dir(path, use_abspath=True): """ Convert an absolute path to a directory name for use in a cache. @@ -799,7 +799,7 @@ def path_to_cache_dir(path): #. Any occurrence of ``os.sep`` is replaced with ``'--'``. #. ``'.cache'`` is appended. """ - d, p = os.path.splitdrive(os.path.abspath(path)) + d, p = os.path.splitdrive(os.path.abspath(path) if use_abspath else path) if d: d = d.replace(':', '---') p = p.replace(os.sep, '--') @@ -981,11 +981,11 @@ def __init__(self, base): logger.warning('Directory \'%s\' is not private', base) self.base = os.path.abspath(os.path.normpath(base)) - def prefix_to_dir(self, prefix): + def prefix_to_dir(self, prefix, use_abspath=True): """ Converts a resource prefix to a directory name in the cache. """ - return path_to_cache_dir(prefix) + return path_to_cache_dir(prefix, use_abspath=use_abspath) def clear(self): """ diff --git a/distlib/wheel.py b/distlib/wheel.py index 0034276..e04a515 100644 --- a/distlib/wheel.py +++ b/distlib/wheel.py @@ -752,7 +752,7 @@ def _get_extensions(self): wf = wrapper(bf) extensions = json.load(wf) cache = self._get_dylib_cache() - prefix = cache.prefix_to_dir(pathname) + prefix = cache.prefix_to_dir(self.filename, use_abspath=False) cache_base = os.path.join(cache.base, prefix) if not os.path.isdir(cache_base): os.makedirs(cache_base) diff --git a/tests/test_util.py b/tests/test_util.py index 936e05e..ee28574 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -99,6 +99,11 @@ def test_cache_base(self): @unittest.skipIf(os.name != 'posix', 'Test is only valid for POSIX') def test_path_to_cache_dir_posix(self): self.assertEqual(path_to_cache_dir('/home/user/some-file.zip'), '--home--user--some-file.zip.cache') + self.assertEqual(path_to_cache_dir('path/to/some-file.zip'), + os.path.splitext(path_to_cache_dir(os.path.dirname(HERE)))[0] + + '--path--to--some-file.zip.cache') + self.assertEqual(path_to_cache_dir('path/to/some-file.zip', use_abspath=False), + 'path--to--some-file.zip.cache') @unittest.skipIf(os.name != 'nt', 'Test is only valid for Windows') def test_path_to_cache_dir_nt(self):