Skip to content

Commit f818ad2

Browse files
GitHKAndrei Neagu
authored andcommitted
🚑️ Added escaping for 7zip paths (#7049)
Co-authored-by: Andrei Neagu <[email protected]>
1 parent 821aa5c commit f818ad2

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

packages/service-library/src/servicelib/archiving_utils/_interface_7zip.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import os
55
import re
6+
import shlex
67
from collections.abc import Awaitable, Callable
78
from contextlib import AsyncExitStack
89
from pathlib import Path
@@ -214,7 +215,7 @@ async def archive_dir(
214215
"-mta=off", # Don't store file access time
215216
]
216217
)
217-
command = f"{_7ZIP_EXECUTABLE} {options} {destination} {dir_to_compress}/*"
218+
command = f"{_7ZIP_EXECUTABLE} {options} {shlex.quote(f'{destination}')} {shlex.quote(f'{dir_to_compress}')}/*"
218219

219220
folder_size_bytes = sum(
220221
file.stat().st_size for file in iter_files_to_compress(dir_to_compress)
@@ -295,7 +296,7 @@ async def unarchive_dir(
295296
# get archive information
296297
archive_info_parser = _7ZipArchiveInfoParser()
297298
list_output = await _run_cli_command(
298-
f"{_7ZIP_EXECUTABLE} l {archive_to_extract}",
299+
f"{_7ZIP_EXECUTABLE} l {shlex.quote(f'{archive_to_extract}')}",
299300
output_handler=archive_info_parser.parse_chunk,
300301
)
301302
file_names_in_archive = _extract_file_names_from_archive(list_output)
@@ -330,7 +331,7 @@ async def _decompressed_bytes(byte_progress: NonNegativeInt) -> None:
330331
]
331332
)
332333
await _run_cli_command(
333-
f"{_7ZIP_EXECUTABLE} {options} {archive_to_extract} -o{destination_folder}",
334+
f"{_7ZIP_EXECUTABLE} {options} {shlex.quote(f'{archive_to_extract}')} -o{shlex.quote(f'{destination_folder}')}",
334335
output_handler=_7ZipProgressParser(_decompressed_bytes).parse_chunk,
335336
)
336337

packages/service-library/tests/archiving_utils/test_archiving__interface_7zip.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from pathlib import Path
66

77
import pytest
8+
from helpers import print_tree
89
from pydantic import NonNegativeInt
910
from servicelib.archiving_utils._interface_7zip import (
1011
_7ZipProgressParser,
@@ -61,12 +62,19 @@ async def _progress_handler(byte_progress: NonNegativeInt) -> None:
6162
assert sum(detected_entries) == expected_size
6263

6364

65+
def _assert_same_folder_content(f1: Path, f2: Path) -> None:
66+
in_f1 = {x.relative_to(f1) for x in f1.rglob("*")}
67+
in_f2 = {x.relative_to(f2) for x in f2.rglob("*")}
68+
assert in_f1 == in_f2
69+
70+
6471
@pytest.mark.parametrize("compress", [True, False])
6572
async def test_archive_unarchive(
6673
mixed_file_types: Path, archive_path: Path, unpacked_archive: Path, compress: bool
6774
):
6875
await archive_dir(mixed_file_types, archive_path, compress=compress)
6976
await unarchive_dir(archive_path, unpacked_archive)
77+
_assert_same_folder_content(mixed_file_types, unpacked_archive)
7078

7179

7280
@pytest.fixture
@@ -82,6 +90,7 @@ async def test_archive_unarchive_empty_folder(
8290
):
8391
await archive_dir(empty_folder, archive_path, compress=compress)
8492
await unarchive_dir(archive_path, unpacked_archive)
93+
_assert_same_folder_content(empty_folder, unpacked_archive)
8594

8695

8796
@pytest.mark.parametrize(
@@ -102,3 +111,27 @@ def test__extract_file_names_from_archive(
102111
archive_list_stdout_path.read_text()
103112
files = _extract_file_names_from_archive(archive_list_stdout_path.read_text())
104113
assert len(files) == expected_file_count
114+
115+
116+
@pytest.mark.parametrize("compress", [True, False])
117+
async def test_archive_unarchive_with_names_with_spaces(tmp_path: Path, compress: bool):
118+
to_archive_path = tmp_path / "'source of files!a ads now strange'"
119+
to_archive_path.mkdir(parents=True, exist_ok=True)
120+
assert to_archive_path.exists()
121+
122+
# generate some content
123+
for i in range(10):
124+
(to_archive_path / f"f{i}.txt").write_text("*" * i)
125+
print_tree(to_archive_path)
126+
127+
archive_path = tmp_path / "archived version herre!)!(/£)!'"
128+
assert not archive_path.exists()
129+
130+
extracted_to_path = tmp_path / "this is where i want them to be extracted to''''"
131+
extracted_to_path.mkdir(parents=True, exist_ok=True)
132+
assert extracted_to_path.exists()
133+
134+
# source and destination all with spaces
135+
await archive_dir(to_archive_path, archive_path, compress=compress)
136+
await unarchive_dir(archive_path, extracted_to_path)
137+
_assert_same_folder_content(to_archive_path, extracted_to_path)

0 commit comments

Comments
 (0)