Skip to content

Commit ecfecc2

Browse files
[3.9] bpo-41043: Escape literal part of the path for glob(). (GH-20994). (GH-21275)
(cherry picked from commit 9355868)
1 parent df59293 commit ecfecc2

File tree

24 files changed

+40
-30
lines changed

24 files changed

+40
-30
lines changed

Lib/distutils/command/build_py.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import os
66
import importlib.util
77
import sys
8-
from glob import glob
8+
import glob
99

1010
from distutils.core import Command
1111
from distutils.errors import *
@@ -125,7 +125,7 @@ def find_data_files(self, package, src_dir):
125125
files = []
126126
for pattern in globs:
127127
# Each pattern has to be converted to a platform-specific path
128-
filelist = glob(os.path.join(src_dir, convert_path(pattern)))
128+
filelist = glob.glob(os.path.join(glob.escape(src_dir), convert_path(pattern)))
129129
# Files that match more than one pattern are only added once
130130
files.extend([fn for fn in filelist if fn not in files
131131
and os.path.isfile(fn)])
@@ -216,7 +216,7 @@ def check_module(self, module, module_file):
216216

217217
def find_package_modules(self, package, package_dir):
218218
self.check_package(package, package_dir)
219-
module_files = glob(os.path.join(package_dir, "*.py"))
219+
module_files = glob.glob(os.path.join(glob.escape(package_dir), "*.py"))
220220
modules = []
221221
setup_script = os.path.abspath(self.distribution.script_name)
222222

Lib/idlelib/tree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def listicons(icondir=ICONDIR):
3838
"""Utility to display the available icons."""
3939
root = Tk()
4040
import glob
41-
list = glob.glob(os.path.join(icondir, "*.gif"))
41+
list = glob.glob(os.path.join(glob.escape(icondir), "*.gif"))
4242
list.sort()
4343
images = []
4444
row = column = 0

Lib/imghdr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def testall(list, recursive, toplevel):
152152
if recursive or toplevel:
153153
print('recursing down:')
154154
import glob
155-
names = glob.glob(os.path.join(filename, '*'))
155+
names = glob.glob(os.path.join(glob.escape(filename), '*'))
156156
testall(names, recursive, 0)
157157
else:
158158
print('*** directory (use -r) ***')

Lib/pdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ def _complete_location(self, text, line, begidx, endidx):
474474
except Exception:
475475
ret = []
476476
# Then, try to complete file names as well.
477-
globs = glob.glob(text + '*')
477+
globs = glob.glob(glob.escape(text) + '*')
478478
for fn in globs:
479479
if os.path.isdir(fn):
480480
ret.append(fn + '/')

Lib/sndhdr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def testall(list, recursive, toplevel):
241241
if recursive or toplevel:
242242
print('recursing down:')
243243
import glob
244-
names = glob.glob(os.path.join(filename, '*'))
244+
names = glob.glob(os.path.join(glob.escape(filename), '*'))
245245
testall(names, recursive, 0)
246246
else:
247247
print('*** directory (use -r) ***')

Lib/test/_test_multiprocessing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4259,7 +4259,7 @@ class _TestImportStar(unittest.TestCase):
42594259
def get_module_names(self):
42604260
import glob
42614261
folder = os.path.dirname(multiprocessing.__file__)
4262-
pattern = os.path.join(folder, '*.py')
4262+
pattern = os.path.join(glob.escape(folder), '*.py')
42634263
files = glob.glob(pattern)
42644264
modules = [os.path.splitext(os.path.split(f)[1])[0] for f in files]
42654265
modules = ['multiprocessing.' + m for m in modules]

Lib/test/libregrtest/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ def create_temp_dir(self):
603603
def cleanup(self):
604604
import glob
605605

606-
path = os.path.join(self.tmp_dir, 'test_python_*')
606+
path = os.path.join(glob.escape(self.tmp_dir), 'test_python_*')
607607
print("Cleanup %s directory" % self.tmp_dir)
608608
for name in glob.glob(path):
609609
if os.path.isdir(name):

Lib/test/support/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2353,7 +2353,7 @@ def _platform_specific(self):
23532353
dll,
23542354
os.path.join(dest_dir, os.path.basename(dll))
23552355
))
2356-
for runtime in glob.glob(os.path.join(src_dir, "vcruntime*.dll")):
2356+
for runtime in glob.glob(os.path.join(glob.escape(src_dir), "vcruntime*.dll")):
23572357
self._also_link.append((
23582358
runtime,
23592359
os.path.join(dest_dir, os.path.basename(runtime))

Lib/test/test_bz2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class BaseTest(unittest.TestCase):
6969
# simply use the bigger test data for all tests.
7070
test_size = 0
7171
BIG_TEXT = bytearray(128*1024)
72-
for fname in glob.glob(os.path.join(os.path.dirname(__file__), '*.py')):
72+
for fname in glob.glob(os.path.join(glob.escape(os.path.dirname(__file__)), '*.py')):
7373
with open(fname, 'rb') as fh:
7474
test_size += fh.readinto(memoryview(BIG_TEXT)[test_size:])
7575
if test_size > 128*1024:

Lib/test/test_crashers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from test.support.script_helper import assert_python_failure
1212

1313
CRASHER_DIR = os.path.join(os.path.dirname(__file__), "crashers")
14-
CRASHER_FILES = os.path.join(CRASHER_DIR, "*.py")
14+
CRASHER_FILES = os.path.join(glob.escape(CRASHER_DIR), "*.py")
1515

1616
infinite_loops = ["infinite_loop_re.py", "nasty_eq_vs_dict.py"]
1717

Lib/test/test_dbm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def dbm_iterator():
3333
def delete_files():
3434
# we don't know the precise name the underlying database uses
3535
# so we use glob to locate all names
36-
for f in glob.glob(_fname + "*"):
36+
for f in glob.glob(glob.escape(_fname) + "*"):
3737
test.support.unlink(f)
3838

3939

Lib/test/test_import/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ def test_dll_dependency_import(self):
485485
pyexe = os.path.join(tmp, os.path.basename(sys.executable))
486486
shutil.copy(sys.executable, pyexe)
487487
shutil.copy(dllname, tmp)
488-
for f in glob.glob(os.path.join(sys.prefix, "vcruntime*.dll")):
488+
for f in glob.glob(os.path.join(glob.escape(sys.prefix), "vcruntime*.dll")):
489489
shutil.copy(f, tmp)
490490

491491
shutil.copy(pydname, tmp2)

Lib/test/test_mailbox.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ def tearDown(self):
979979
super().tearDown()
980980
self._box.close()
981981
self._delete_recursively(self._path)
982-
for lock_remnant in glob.glob(self._path + '.*'):
982+
for lock_remnant in glob.glob(glob.escape(self._path) + '.*'):
983983
support.unlink(lock_remnant)
984984

985985
def assertMailboxEmpty(self):
@@ -1311,7 +1311,7 @@ def tearDown(self):
13111311
super().tearDown()
13121312
self._box.close()
13131313
self._delete_recursively(self._path)
1314-
for lock_remnant in glob.glob(self._path + '.*'):
1314+
for lock_remnant in glob.glob(glob.escape(self._path) + '.*'):
13151315
support.unlink(lock_remnant)
13161316

13171317
def test_labels(self):

Lib/test/test_regrtest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ def test_finds_expected_number_of_tests(self):
556556
args = ['-Wd', '-E', '-bb', '-m', 'test.regrtest', '--list-tests']
557557
output = self.run_python(args)
558558
rough_number_of_tests_found = len(output.splitlines())
559-
actual_testsuite_glob = os.path.join(os.path.dirname(__file__),
559+
actual_testsuite_glob = os.path.join(glob.escape(os.path.dirname(__file__)),
560560
'test*.py')
561561
rough_counted_test_py_files = len(glob.glob(actual_testsuite_glob))
562562
# We're not trying to duplicate test finding logic in here,

Lib/test/test_site.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ def test_startup_imports(self):
534534
# found in sys.path (see site.addpackage()). Skip the test if at least
535535
# one .pth file is found.
536536
for path in isolated_paths:
537-
pth_files = glob.glob(os.path.join(path, "*.pth"))
537+
pth_files = glob.glob(os.path.join(glob.escape(path), "*.pth"))
538538
if pth_files:
539539
self.skipTest(f"found {len(pth_files)} .pth files in: {path}")
540540

Lib/test/test_tokenize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1605,7 +1605,7 @@ def test_random_files(self):
16051605
import glob, random
16061606
fn = support.findfile("tokenize_tests.txt")
16071607
tempdir = os.path.dirname(fn) or os.curdir
1608-
testfiles = glob.glob(os.path.join(tempdir, "test*.py"))
1608+
testfiles = glob.glob(os.path.join(glob.escape(tempdir), "test*.py"))
16091609

16101610
# Tokenize is broken on test_pep3131.py because regular expressions are
16111611
# broken on the obscure unicode identifiers in it. *sigh*

Lib/test/test_unicode_file.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _do_single(self, filename):
4040
self._do_copyish(filename, filename)
4141
# Filename should appear in glob output
4242
self.assertTrue(
43-
os.path.abspath(filename)==os.path.abspath(glob.glob(filename)[0]))
43+
os.path.abspath(filename)==os.path.abspath(glob.glob(glob.escape(filename))[0]))
4444
# basename should appear in listdir.
4545
path, base = os.path.split(os.path.abspath(filename))
4646
file_list = os.listdir(path)

Lib/webbrowser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ def _find_grail_rc(self):
413413
tempdir = os.path.join(tempfile.gettempdir(),
414414
".grail-unix")
415415
user = pwd.getpwuid(os.getuid())[0]
416-
filename = os.path.join(tempdir, user + "-*")
416+
filename = os.path.join(glob.escape(tempdir), glob.escape(user) + "-*")
417417
maybes = glob.glob(filename)
418418
if not maybes:
419419
return None
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed the use of :func:`~glob.glob` in the stdlib: literal part of the path
2+
is now always correctly escaped.

Tools/c-analyzer/c_analyzer/common/files.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def walk_tree(root, *,
4141
def glob_tree(root, *,
4242
suffix=None,
4343
_glob=glob.iglob,
44+
_escape=glob.escape,
45+
_join=os.path.join,
4446
):
4547
"""Yield each file in the tree under the given directory name.
4648
@@ -51,9 +53,9 @@ def glob_tree(root, *,
5153
if not isinstance(suffix, str):
5254
raise ValueError('suffix must be a string')
5355

54-
for filename in _glob(f'{root}/*{suffix}'):
56+
for filename in _glob(_join(_escape(root), f'*{suffix}')):
5557
yield filename
56-
for filename in _glob(f'{root}/**/*{suffix}'):
58+
for filename in _glob(_join(_escape(root), f'**/*{suffix}')):
5759
yield filename
5860

5961

Tools/c-analyzer/check-c-globals.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
def find_capi_vars(root):
3838
capi_vars = {}
3939
for dirname in SOURCE_DIRS:
40-
for filename in glob.glob(os.path.join(ROOT_DIR, dirname, '**/*.[hc]'),
40+
for filename in glob.glob(os.path.join(
41+
glob.escape(os.path.join(ROOT_DIR, dirname)),
42+
'**/*.[hc]'),
4143
recursive=True):
4244
with open(filename) as file:
4345
for name in _find_capi_vars(file):

Tools/peg_generator/scripts/test_parse_directory.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
import time
88
import traceback
99
import tokenize
10+
<<<<<<< HEAD
1011
import _peg_parser
1112
from glob import glob
13+
=======
14+
from glob import glob, escape
15+
>>>>>>> 9355868458... bpo-41043: Escape literal part of the path for glob(). (GH-20994)
1216
from pathlib import PurePath
1317

1418
from typing import List, Optional, Any, Tuple
@@ -183,7 +187,7 @@ def parse_directory(
183187
trees = {} # Trees to compare (after everything else is done)
184188
total_seconds = 0
185189

186-
for file in sorted(glob(f"{directory}/**/*.py", recursive=True)):
190+
for file in sorted(glob(os.path.join(escape(directory), f"**/*.py"), recursive=True)):
187191
# Only attempt to parse Python files and files that are not excluded
188192
if any(PurePath(file).match(pattern) for pattern in excluded_files):
189193
continue

Tools/ssl/make_ssl_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def parse_error_codes(h_file, prefix, libcode):
3939
f = sys.stdout if use_stdout else open(outfile, "w")
4040
# mnemonic -> (library code, error prefix, header file)
4141
error_libraries = {}
42-
for error_header in glob.glob(os.path.join(openssl_inc, 'include/openssl/*err.h')):
42+
for error_header in glob.glob(os.path.join(glob.escape(openssl_inc), 'include/openssl/*err.h')):
4343
base = os.path.basename(error_header)
4444
if base in ('buffererr.h', 'objectserr.h', 'storeerr.h'):
4545
# Deprecated in 3.0.

setup.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import re
99
import sys
1010
import sysconfig
11-
from glob import glob
11+
from glob import glob, escape
1212

1313

1414
try:
@@ -401,7 +401,7 @@ def update_sources_depends(self):
401401

402402
# Python header files
403403
headers = [sysconfig.get_config_h_filename()]
404-
headers += glob(os.path.join(sysconfig.get_path('include'), "*.h"))
404+
headers += glob(os.path.join(escape(sysconfig.get_path('include')), "*.h"))
405405

406406
for ext in self.extensions:
407407
ext.sources = [ find_module_file(filename, moddirlist)
@@ -2433,7 +2433,7 @@ def detect_hash_builtins(self):
24332433

24342434
if "blake2" in configured:
24352435
blake2_deps = glob(
2436-
os.path.join(self.srcdir, 'Modules/_blake2/impl/*')
2436+
os.path.join(escape(self.srcdir), 'Modules/_blake2/impl/*')
24372437
)
24382438
blake2_deps.append('hashlib.h')
24392439
self.add(Extension(
@@ -2448,7 +2448,7 @@ def detect_hash_builtins(self):
24482448

24492449
if "sha3" in configured:
24502450
sha3_deps = glob(
2451-
os.path.join(self.srcdir, 'Modules/_sha3/kcp/*')
2451+
os.path.join(escape(self.srcdir), 'Modules/_sha3/kcp/*')
24522452
)
24532453
sha3_deps.append('hashlib.h')
24542454
self.add(Extension(

0 commit comments

Comments
 (0)