From 1ea07ffe0d2d4fbcb9ca5e85eed81450af1fd22f Mon Sep 17 00:00:00 2001 From: Parker Loflin Date: Thu, 5 Nov 2026 16:46:46 -0500 Subject: [PATCH] Make the isal.igzip command refuse to overwrite its input file main() opens the output with "wb" before it reads the input, which truncates the input when both are the same file. With -f -o data data the command replaced data with an empty gzip file and exited with status 0. --- CHANGELOG.rst | 7 +++++++ src/isal/igzip.py | 5 +++++ tests/test_igzip.py | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d65c0609..08dfb182 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,13 @@ Changelog .. This document is user facing. Please word the changes in such a way .. that users understand how the changes affect the new version. +version 1.10.0-dev +------------------ ++ Fix ``python -m isal.igzip`` replacing the input file with empty output and + exiting with status 0 when the output file is the input file, as in + ``-f -o data data``. It exits with an error now. + + version 1.9.1 ----------------- + Fix BrokenPipeError when piping ``python -m isal.igzip`` into ``head``, diff --git a/src/isal/igzip.py b/src/isal/igzip.py index b18af11c..47b53f96 100644 --- a/src/isal/igzip.py +++ b/src/isal/igzip.py @@ -350,6 +350,11 @@ def main(): if extension != ".gz" and not args.stdout: sys.exit(f"filename doesn't end in .gz: {args.file!r}. " f"Cannot determine output filename.") + # Opening the output for writing would empty the input before it is read. + if (args.file is not None and out_filepath is not None + and os.path.exists(args.file) and os.path.exists(out_filepath) + and os.path.samefile(args.file, out_filepath)): + sys.exit(f"{args.file!r} and {out_filepath!r} are the same file") if out_filepath is not None and not args.force: if os.path.exists(out_filepath): yes_or_no = input(f"{out_filepath} already exists; " diff --git a/tests/test_igzip.py b/tests/test_igzip.py index 457f13f6..f34edb1d 100644 --- a/tests/test_igzip.py +++ b/tests/test_igzip.py @@ -355,6 +355,29 @@ def test_compress_infile_out_file_force(monkeypatch, tmp_path, capsysbinary): assert out == b'' +@pytest.mark.parametrize("args", [ + ['-f', '-o', 'test', 'test'], + ['-f', '-o', os.path.join('.', 'test'), 'test'], + ['-o', 'test', 'test'], # Refused before the overwrite prompt. + ['-d', '-f', '-o', 'test.gz', 'test.gz'], +]) +def test_infile_out_file_same_file(monkeypatch, tmp_path, capsysbinary, args): + monkeypatch.chdir(tmp_path) + test = tmp_path / "test" + test.write_bytes(DATA) + test_gz = tmp_path / "test.gz" + test_gz.write_bytes(COMPRESSED_DATA) + monkeypatch.setattr(sys, "argv", ['', *args]) + monkeypatch.setattr(sys, "stdin", io.TextIOWrapper(io.BytesIO(b"y"))) + with pytest.raises(SystemExit) as error: + igzip.main() + assert error.match("are the same file") + assert test.read_bytes() == DATA + assert test_gz.read_bytes() == COMPRESSED_DATA + out, err = capsysbinary.readouterr() + assert out == b'' + + def test_compress_infile_out_file_prompt(monkeypatch, tmp_path, capsysbinary): test = tmp_path / "test" test.write_bytes(DATA)