Skip to content
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

bpo-41043: Escape literal part of the path for glob(). #20994

Merged
merged 1 commit into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Lib/distutils/command/build_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import os
import importlib.util
import sys
from glob import glob
import glob

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

def find_package_modules(self, package, package_dir):
self.check_package(package, package_dir)
module_files = glob(os.path.join(package_dir, "*.py"))
module_files = glob.glob(os.path.join(glob.escape(package_dir), "*.py"))
modules = []
setup_script = os.path.abspath(self.distribution.script_name)

Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def listicons(icondir=ICONDIR):
"""Utility to display the available icons."""
root = Tk()
import glob
list = glob.glob(os.path.join(icondir, "*.gif"))
list = glob.glob(os.path.join(glob.escape(icondir), "*.gif"))
list.sort()
images = []
row = column = 0
Expand Down
2 changes: 1 addition & 1 deletion Lib/imghdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def testall(list, recursive, toplevel):
if recursive or toplevel:
print('recursing down:')
import glob
names = glob.glob(os.path.join(filename, '*'))
names = glob.glob(os.path.join(glob.escape(filename), '*'))
testall(names, recursive, 0)
else:
print('*** directory (use -r) ***')
Expand Down
2 changes: 1 addition & 1 deletion Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ def _complete_location(self, text, line, begidx, endidx):
except Exception:
ret = []
# Then, try to complete file names as well.
globs = glob.glob(text + '*')
globs = glob.glob(glob.escape(text) + '*')
for fn in globs:
if os.path.isdir(fn):
ret.append(fn + '/')
Expand Down
2 changes: 1 addition & 1 deletion Lib/sndhdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def testall(list, recursive, toplevel):
if recursive or toplevel:
print('recursing down:')
import glob
names = glob.glob(os.path.join(filename, '*'))
names = glob.glob(os.path.join(glob.escape(filename), '*'))
testall(names, recursive, 0)
else:
print('*** directory (use -r) ***')
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4260,7 +4260,7 @@ class _TestImportStar(unittest.TestCase):
def get_module_names(self):
import glob
folder = os.path.dirname(multiprocessing.__file__)
pattern = os.path.join(folder, '*.py')
pattern = os.path.join(glob.escape(folder), '*.py')
files = glob.glob(pattern)
modules = [os.path.splitext(os.path.split(f)[1])[0] for f in files]
modules = ['multiprocessing.' + m for m in modules]
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/libregrtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ def create_temp_dir(self):
def cleanup(self):
import glob

path = os.path.join(self.tmp_dir, 'test_python_*')
path = os.path.join(glob.escape(self.tmp_dir), 'test_python_*')
print("Cleanup %s directory" % self.tmp_dir)
for name in glob.glob(path):
if os.path.isdir(name):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,7 @@ def _platform_specific(self):
dll,
os.path.join(dest_dir, os.path.basename(dll))
))
for runtime in glob.glob(os.path.join(src_dir, "vcruntime*.dll")):
for runtime in glob.glob(os.path.join(glob.escape(src_dir), "vcruntime*.dll")):
self._also_link.append((
runtime,
os.path.join(dest_dir, os.path.basename(runtime))
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_bz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class BaseTest(unittest.TestCase):
# simply use the bigger test data for all tests.
test_size = 0
BIG_TEXT = bytearray(128*1024)
for fname in glob.glob(os.path.join(os.path.dirname(__file__), '*.py')):
for fname in glob.glob(os.path.join(glob.escape(os.path.dirname(__file__)), '*.py')):
with open(fname, 'rb') as fh:
test_size += fh.readinto(memoryview(BIG_TEXT)[test_size:])
if test_size > 128*1024:
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_crashers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from test.support.script_helper import assert_python_failure

CRASHER_DIR = os.path.join(os.path.dirname(__file__), "crashers")
CRASHER_FILES = os.path.join(CRASHER_DIR, "*.py")
CRASHER_FILES = os.path.join(glob.escape(CRASHER_DIR), "*.py")

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

Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_dbm.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def dbm_iterator():
def delete_files():
# we don't know the precise name the underlying database uses
# so we use glob to locate all names
for f in glob.glob(_fname + "*"):
for f in glob.glob(glob.escape(_fname) + "*"):
test.support.unlink(f)


Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ def test_dll_dependency_import(self):
pyexe = os.path.join(tmp, os.path.basename(sys.executable))
shutil.copy(sys.executable, pyexe)
shutil.copy(dllname, tmp)
for f in glob.glob(os.path.join(sys.prefix, "vcruntime*.dll")):
for f in glob.glob(os.path.join(glob.escape(sys.prefix), "vcruntime*.dll")):
shutil.copy(f, tmp)

shutil.copy(pydname, tmp2)
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ def tearDown(self):
super().tearDown()
self._box.close()
self._delete_recursively(self._path)
for lock_remnant in glob.glob(self._path + '.*'):
for lock_remnant in glob.glob(glob.escape(self._path) + '.*'):
support.unlink(lock_remnant)

def assertMailboxEmpty(self):
Expand Down Expand Up @@ -1311,7 +1311,7 @@ def tearDown(self):
super().tearDown()
self._box.close()
self._delete_recursively(self._path)
for lock_remnant in glob.glob(self._path + '.*'):
for lock_remnant in glob.glob(glob.escape(self._path) + '.*'):
support.unlink(lock_remnant)

def test_labels(self):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ def test_finds_expected_number_of_tests(self):
args = ['-Wd', '-E', '-bb', '-m', 'test.regrtest', '--list-tests']
output = self.run_python(args)
rough_number_of_tests_found = len(output.splitlines())
actual_testsuite_glob = os.path.join(os.path.dirname(__file__),
actual_testsuite_glob = os.path.join(glob.escape(os.path.dirname(__file__)),
'test*.py')
rough_counted_test_py_files = len(glob.glob(actual_testsuite_glob))
# We're not trying to duplicate test finding logic in here,
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ def test_startup_imports(self):
# found in sys.path (see site.addpackage()). Skip the test if at least
# one .pth file is found.
for path in isolated_paths:
pth_files = glob.glob(os.path.join(path, "*.pth"))
pth_files = glob.glob(os.path.join(glob.escape(path), "*.pth"))
if pth_files:
self.skipTest(f"found {len(pth_files)} .pth files in: {path}")

Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_tokenize.py
Original file line number Diff line number Diff line change
Expand Up @@ -1605,7 +1605,7 @@ def test_random_files(self):
import glob, random
fn = support.findfile("tokenize_tests.txt")
tempdir = os.path.dirname(fn) or os.curdir
testfiles = glob.glob(os.path.join(tempdir, "test*.py"))
testfiles = glob.glob(os.path.join(glob.escape(tempdir), "test*.py"))

# Tokenize is broken on test_pep3131.py because regular expressions are
# broken on the obscure unicode identifiers in it. *sigh*
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_unicode_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _do_single(self, filename):
self._do_copyish(filename, filename)
# Filename should appear in glob output
self.assertTrue(
os.path.abspath(filename)==os.path.abspath(glob.glob(filename)[0]))
os.path.abspath(filename)==os.path.abspath(glob.glob(glob.escape(filename))[0]))
# basename should appear in listdir.
path, base = os.path.split(os.path.abspath(filename))
file_list = os.listdir(path)
Expand Down
2 changes: 1 addition & 1 deletion Lib/webbrowser.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ def _find_grail_rc(self):
tempdir = os.path.join(tempfile.gettempdir(),
".grail-unix")
user = pwd.getpwuid(os.getuid())[0]
filename = os.path.join(tempdir, user + "-*")
filename = os.path.join(glob.escape(tempdir), glob.escape(user) + "-*")
maybes = glob.glob(filename)
if not maybes:
return None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed the use of :func:`~glob.glob` in the stdlib: literal part of the path
is now always correctly escaped.
6 changes: 4 additions & 2 deletions Tools/c-analyzer/c_analyzer/common/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def walk_tree(root, *,
def glob_tree(root, *,
suffix=None,
_glob=glob.iglob,
_escape=glob.escape,
_join=os.path.join,
):
"""Yield each file in the tree under the given directory name.

Expand All @@ -51,9 +53,9 @@ def glob_tree(root, *,
if not isinstance(suffix, str):
raise ValueError('suffix must be a string')

for filename in _glob(f'{root}/*{suffix}'):
for filename in _glob(_join(_escape(root), f'*{suffix}')):
yield filename
for filename in _glob(f'{root}/**/*{suffix}'):
for filename in _glob(_join(_escape(root), f'**/*{suffix}')):
yield filename


Expand Down
4 changes: 3 additions & 1 deletion Tools/c-analyzer/check-c-globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
def find_capi_vars(root):
capi_vars = {}
for dirname in SOURCE_DIRS:
for filename in glob.glob(os.path.join(ROOT_DIR, dirname, '**/*.[hc]'),
for filename in glob.glob(os.path.join(
glob.escape(os.path.join(ROOT_DIR, dirname)),
'**/*.[hc]'),
recursive=True):
with open(filename) as file:
for name in _find_capi_vars(file):
Expand Down
4 changes: 2 additions & 2 deletions Tools/peg_generator/scripts/test_parse_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import time
import traceback
import tokenize
from glob import glob
from glob import glob, escape
from pathlib import PurePath

from typing import List, Optional, Any, Tuple
Expand Down Expand Up @@ -109,7 +109,7 @@ def parse_directory(directory: str, verbose: bool, excluded_files: List[str], sh
files = []
total_seconds = 0

for file in sorted(glob(f"{directory}/**/*.py", recursive=True)):
for file in sorted(glob(os.path.join(escape(directory), f"**/*.py"), recursive=True)):
# Only attempt to parse Python files and files that are not excluded
if any(PurePath(file).match(pattern) for pattern in excluded_files):
continue
Expand Down
2 changes: 1 addition & 1 deletion Tools/ssl/make_ssl_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def parse_error_codes(h_file, prefix, libcode):
f = sys.stdout if use_stdout else open(outfile, "w")
# mnemonic -> (library code, error prefix, header file)
error_libraries = {}
for error_header in glob.glob(os.path.join(openssl_inc, 'include/openssl/*err.h')):
for error_header in glob.glob(os.path.join(glob.escape(openssl_inc), 'include/openssl/*err.h')):
base = os.path.basename(error_header)
if base in ('buffererr.h', 'objectserr.h', 'storeerr.h'):
# Deprecated in 3.0.
Expand Down
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import re
import sys
import sysconfig
from glob import glob
from glob import glob, escape


try:
Expand Down Expand Up @@ -401,7 +401,7 @@ def update_sources_depends(self):

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

for ext in self.extensions:
ext.sources = [ find_module_file(filename, moddirlist)
Expand Down Expand Up @@ -2431,7 +2431,7 @@ def detect_hash_builtins(self):

if "blake2" in configured:
blake2_deps = glob(
os.path.join(self.srcdir, 'Modules/_blake2/impl/*')
os.path.join(escape(self.srcdir), 'Modules/_blake2/impl/*')
)
blake2_deps.append('hashlib.h')
self.add(Extension(
Expand All @@ -2446,7 +2446,7 @@ def detect_hash_builtins(self):

if "sha3" in configured:
sha3_deps = glob(
os.path.join(self.srcdir, 'Modules/_sha3/kcp/*')
os.path.join(escape(self.srcdir), 'Modules/_sha3/kcp/*')
)
sha3_deps.append('hashlib.h')
self.add(Extension(
Expand Down