-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-37412: Fix os.getcwd() for long path on Windows #14424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
import subprocess | ||
import sys | ||
import sysconfig | ||
import tempfile | ||
import threading | ||
import time | ||
import unittest | ||
|
@@ -87,6 +88,60 @@ def test_getcwd(self): | |
cwd = os.getcwd() | ||
self.assertIsInstance(cwd, str) | ||
|
||
def test_getcwd_long_path(self): | ||
# bpo-37412: On Linux, PATH_MAX is usually around 4096 bytes. On | ||
# Windows, MAX_PATH is defined as 260 characters, but the universal | ||
# naming convention (UNC) allows longer paths. Internally, the os | ||
# module uses MAXPATHLEN which is at least 1024. | ||
# | ||
# Use a directory name of 200 characters to fit into Windows MAX_PATH | ||
# limit. | ||
# | ||
# On Windows, the test can stop when trying to create a path longer | ||
# than MAX_PATH if long paths support is disabled: | ||
# see RtlAreLongPathsEnabled(). | ||
min_len = 2000 # characters | ||
dirlen = 200 # characters | ||
dirname = 'python_test_dir_' | ||
dirname = dirname + ('a' * (dirlen - len(dirname))) | ||
|
||
with tempfile.TemporaryDirectory() as tmpdir: | ||
with support.change_cwd(tmpdir): | ||
path = tmpdir | ||
expected = path | ||
|
||
while True: | ||
cwd = os.getcwd() | ||
self.assertEqual(cwd, expected) | ||
|
||
need = min_len - (len(cwd) + len(os.path.sep)) | ||
if need <= 0: | ||
break | ||
if len(dirname) > need and need > 0: | ||
dirname = dirname[:need] | ||
|
||
path = os.path.join(path, dirname) | ||
try: | ||
os.mkdir(path) | ||
# On Windows, chdir() can fail | ||
# even if mkdir() succeeded | ||
os.chdir(path) | ||
except FileNotFoundError: | ||
# On Windows, catch ERROR_PATH_NOT_FOUND (3) and | ||
# ERROR_FILENAME_EXCED_RANGE (206) errors | ||
# ("The filename or extension is too long") | ||
break | ||
except OSError as exc: | ||
if exc.errno == errno.ENAMETOOLONG: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CRT in Windows doesn't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I modified my PR to catch also FileNotFoundError. The test stops on such error: we reached the maximum path length. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
"if exc.errno == errno.ENAMETOOLONG:" is for Linux ;-) |
||
break | ||
else: | ||
raise | ||
|
||
expected = path | ||
|
||
if support.verbose: | ||
print(f"Tested current directory length: {len(cwd)}") | ||
|
||
def test_getcwdb(self): | ||
cwd = os.getcwdb() | ||
self.assertIsInstance(cwd, bytes) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, UNC paths have the same length limit as DOS drive paths. "\\?\" paths remove the limit because they bypass normalization, but these are not UNC paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum. I rephased the comment in a more generic way.
"On Windows, MAX_PATH is defined as 260 characters, but Windows supports longer path if longer paths support is enabled."