diff --git a/picard/ui/options/renaming.py b/picard/ui/options/renaming.py index 0df1acbbf..3d6deac18 100644 --- a/picard/ui/options/renaming.py +++ b/picard/ui/options/renaming.py @@ -46,7 +46,7 @@ from picard.config import ( ) from picard.const.sys import IS_WIN from picard.script import ScriptParser -from picard.util.filenaming import system_supports_long_paths +from picard.util import system_supports_long_paths from picard.ui.options import ( OptionsCheckError, diff --git a/picard/util/__init__.py b/picard/util/__init__.py index a986c2f25..57752c392 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -72,6 +72,9 @@ from picard.const.sys import ( ) +if IS_WIN: + import winreg + # Windows path length constraints: # the entire path's length WIN_MAX_FILEPATH_LEN = 259 @@ -175,12 +178,32 @@ def decode_filename(filename): return filename.decode(_io_encoding) +def system_supports_long_paths(): + if not IS_WIN: + return True + else: + try: + # Use cached value + return system_supports_long_paths._supported + except AttributeError: + pass + try: + with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, + r"SYSTEM\CurrentControlSet\Control\FileSystem") as key: + system_supports_long_paths._supported = winreg.QueryValueEx(key, "LongPathsEnabled")[0] == 1 + return system_supports_long_paths._supported + except OSError: + log.info('Failed reading LongPathsEnabled from registry') + return False + + def normpath(path): path = os.path.normpath(path) # If the path is longer than 259 characters on Windows, prepend the \\?\ # prefix. This enables access to long paths using the Windows API. See # https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation - if IS_WIN and len(path) > WIN_MAX_FILEPATH_LEN and not path.startswith(WIN_LONGPATH_PREFIX): + if (IS_WIN and len(path) > WIN_MAX_FILEPATH_LEN and not system_supports_long_paths() + and not path.startswith(WIN_LONGPATH_PREFIX)): path = WIN_LONGPATH_PREFIX + path try: path = os.path.realpath(path) diff --git a/picard/util/filenaming.py b/picard/util/filenaming.py index 5b2241793..a35ff4d4b 100644 --- a/picard/util/filenaming.py +++ b/picard/util/filenaming.py @@ -54,7 +54,6 @@ from picard.util import ( win32api = None if IS_WIN: - import winreg try: import win32api # isort:skip import pywintypes @@ -150,25 +149,6 @@ def _shorten_to_bytes_length(text, length): # noqa: E302 return "" -def system_supports_long_paths(): - if not IS_WIN: - return True - else: - try: - # Use cached value - return system_supports_long_paths._supported - except AttributeError: - pass - try: - with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, - r"SYSTEM\CurrentControlSet\Control\FileSystem") as key: - system_supports_long_paths._supported = winreg.QueryValueEx(key, "LongPathsEnabled")[0] == 1 - return system_supports_long_paths._supported - except OSError: - log.info('Failed reading LongPathsEnabled from registry') - return False - - class ShortenMode(IntEnum): BYTES = 0 UTF16 = 1 diff --git a/test/test_utils.py b/test/test_utils.py index 508385752..3571e12f0 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -37,7 +37,10 @@ import re import subprocess # nosec: B404 from tempfile import NamedTemporaryFile import unittest -from unittest.mock import Mock +from unittest.mock import ( + Mock, + patch, +) from test.picardtestcase import PicardTestCase @@ -722,7 +725,9 @@ class NormpathTest(PicardTestCase): self.assertEqual('C:\\Bar.baz', normpath('C:/Foo/../Bar.baz')) @unittest.skipUnless(IS_WIN, "windows test") - def test_normpath_windows_longpath(self): + @patch.object(util, 'system_supports_long_paths') + def test_normpath_windows_longpath(self, mock_system_supports_long_paths): + mock_system_supports_long_paths.return_value = False path = 'C:\\foo\\' + (252 * 'a') self.assertEqual(path, normpath(path)) path += 'a'