zipremove 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {zipremove-0.2.0/src/zipremove.egg-info → zipremove-0.3.0}/PKG-INFO +8 -1
- {zipremove-0.2.0 → zipremove-0.3.0}/README.md +6 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/setup.cfg +2 -1
- {zipremove-0.2.0 → zipremove-0.3.0}/src/zipremove/__init__.py +17 -8
- {zipremove-0.2.0 → zipremove-0.3.0/src/zipremove.egg-info}/PKG-INFO +8 -1
- {zipremove-0.2.0 → zipremove-0.3.0}/tests/test_zipfile.py +40 -32
- {zipremove-0.2.0 → zipremove-0.3.0}/tests/test_zipfile64.py +36 -2
- {zipremove-0.2.0 → zipremove-0.3.0}/LICENSE.txt +0 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/pyproject.toml +0 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/setup.py +0 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/src/zipremove.egg-info/SOURCES.txt +0 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/src/zipremove.egg-info/dependency_links.txt +0 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/src/zipremove.egg-info/requires.txt +0 -0
- {zipremove-0.2.0 → zipremove-0.3.0}/src/zipremove.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipremove
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Extend `zipfile` with `remove`-related functionalities
|
|
5
5
|
Home-page: https://github.com/danny0838/zipremove
|
|
6
6
|
Author: Danny Lin
|
|
@@ -10,6 +10,7 @@ Classifier: Development Status :: 4 - Beta
|
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Topic :: System :: Archiving :: Compression
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -31,6 +32,12 @@ Requires-Dist: flake8-isort>=6.0; extra == "dev"
|
|
|
31
32
|
Requires-Dist: isort>=5.5; extra == "dev"
|
|
32
33
|
Dynamic: license-file
|
|
33
34
|
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+
[](https://pepy.tech/project/zipremove)
|
|
40
|
+
|
|
34
41
|
This package extends `zipfile` with `remove`-related functionalities.
|
|
35
42
|
|
|
36
43
|
## API
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
[](https://pepy.tech/project/zipremove)
|
|
6
|
+
|
|
1
7
|
This package extends `zipfile` with `remove`-related functionalities.
|
|
2
8
|
|
|
3
9
|
## API
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = zipremove
|
|
3
|
-
version = 0.
|
|
3
|
+
version = 0.3.0
|
|
4
4
|
author = Danny Lin
|
|
5
5
|
author_email = danny0838@gmail.com
|
|
6
6
|
url = https://github.com/danny0838/zipremove
|
|
@@ -13,6 +13,7 @@ classifiers =
|
|
|
13
13
|
Intended Audience :: Developers
|
|
14
14
|
Topic :: System :: Archiving :: Compression
|
|
15
15
|
Programming Language :: Python :: 3
|
|
16
|
+
Programming Language :: Python :: 3 :: Only
|
|
16
17
|
Programming Language :: Python :: 3.9
|
|
17
18
|
Programming Language :: Python :: 3.10
|
|
18
19
|
Programming Language :: Python :: 3.11
|
|
@@ -3,7 +3,9 @@ import io
|
|
|
3
3
|
import os
|
|
4
4
|
import struct
|
|
5
5
|
from zipfile import *
|
|
6
|
-
from zipfile import
|
|
6
|
+
from zipfile import __all__ # noqa: F401
|
|
7
|
+
from zipfile import _get_compressor # noqa: F401
|
|
8
|
+
from zipfile import (
|
|
7
9
|
_DD_SIGNATURE,
|
|
8
10
|
_FH_COMPRESSED_SIZE,
|
|
9
11
|
_FH_COMPRESSION_METHOD,
|
|
@@ -13,8 +15,6 @@ from zipfile import ( # noqa: F401
|
|
|
13
15
|
_FH_GENERAL_PURPOSE_FLAG_BITS,
|
|
14
16
|
_FH_SIGNATURE,
|
|
15
17
|
_FH_UNCOMPRESSED_SIZE,
|
|
16
|
-
LZMADecompressor,
|
|
17
|
-
_get_compressor,
|
|
18
18
|
_get_decompressor,
|
|
19
19
|
crc32,
|
|
20
20
|
sizeFileHeader,
|
|
@@ -49,6 +49,20 @@ except ImportError:
|
|
|
49
49
|
filename = filename.replace(os.altsep, "/")
|
|
50
50
|
return filename
|
|
51
51
|
|
|
52
|
+
try:
|
|
53
|
+
import zipfile
|
|
54
|
+
zipfile.LZMADecompressor().unused_data
|
|
55
|
+
except AttributeError:
|
|
56
|
+
# polyfill to support LZMADecompressor().unused_data
|
|
57
|
+
class LZMADecompressor(zipfile.LZMADecompressor):
|
|
58
|
+
@property
|
|
59
|
+
def unused_data(self):
|
|
60
|
+
try:
|
|
61
|
+
return self._decomp.unused_data
|
|
62
|
+
except AttributeError:
|
|
63
|
+
return b''
|
|
64
|
+
zipfile.LZMADecompressor = LZMADecompressor
|
|
65
|
+
|
|
52
66
|
|
|
53
67
|
class _ZipRepacker:
|
|
54
68
|
"""Class for ZipFile repacking."""
|
|
@@ -471,11 +485,6 @@ class _ZipRepacker:
|
|
|
471
485
|
if decompressor is None:
|
|
472
486
|
return False
|
|
473
487
|
|
|
474
|
-
# Current LZMADecompressor is unreliable since it's `.eof` is usually
|
|
475
|
-
# not set as expected.
|
|
476
|
-
if isinstance(decompressor, LZMADecompressor):
|
|
477
|
-
return False
|
|
478
|
-
|
|
479
488
|
dd_fmt = '<LQQ' if zip64 else '<LLL'
|
|
480
489
|
dd_size = struct.calcsize(dd_fmt)
|
|
481
490
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipremove
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Extend `zipfile` with `remove`-related functionalities
|
|
5
5
|
Home-page: https://github.com/danny0838/zipremove
|
|
6
6
|
Author: Danny Lin
|
|
@@ -10,6 +10,7 @@ Classifier: Development Status :: 4 - Beta
|
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Topic :: System :: Archiving :: Compression
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -31,6 +32,12 @@ Requires-Dist: flake8-isort>=6.0; extra == "dev"
|
|
|
31
32
|
Requires-Dist: isort>=5.5; extra == "dev"
|
|
32
33
|
Dynamic: license-file
|
|
33
34
|
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+
[](https://pepy.tech/project/zipremove)
|
|
40
|
+
|
|
34
41
|
This package extends `zipfile` with `remove`-related functionalities.
|
|
35
42
|
|
|
36
43
|
## API
|
|
@@ -1623,50 +1623,51 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1623
1623
|
|
|
1624
1624
|
def test_scan_data_descriptor(self):
|
|
1625
1625
|
repacker = zipfile._ZipRepacker()
|
|
1626
|
+
SIG = zipfile._DD_SIGNATURE
|
|
1626
1627
|
|
|
1627
1628
|
# basic
|
|
1628
|
-
bytes_ = b'
|
|
1629
|
+
bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
|
|
1629
1630
|
self.assertEqual(
|
|
1630
1631
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1631
1632
|
(0x4ff4f23f, 5, 5, 16),
|
|
1632
1633
|
)
|
|
1633
1634
|
|
|
1634
1635
|
# return None if no signature
|
|
1635
|
-
bytes_ = b'dummy
|
|
1636
|
+
bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1636
1637
|
self.assertEqual(
|
|
1637
1638
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1638
1639
|
None,
|
|
1639
1640
|
)
|
|
1640
1641
|
|
|
1641
1642
|
# return None if not unpackable
|
|
1642
|
-
bytes_ =
|
|
1643
|
+
bytes_ = struct.pack('<L', SIG)
|
|
1643
1644
|
self.assertEqual(
|
|
1644
1645
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1645
1646
|
None,
|
|
1646
1647
|
)
|
|
1647
1648
|
|
|
1648
1649
|
# return None if compressed size not match
|
|
1649
|
-
bytes_ = b'
|
|
1650
|
+
bytes_ = b'dumm' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
|
|
1650
1651
|
self.assertEqual(
|
|
1651
1652
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1652
1653
|
None,
|
|
1653
1654
|
)
|
|
1654
1655
|
|
|
1655
1656
|
# zip64
|
|
1656
|
-
bytes_ = b'
|
|
1657
|
+
bytes_ = b'dummy' + struct.pack('<2L2Q', SIG, 0x4ff4f23f, 5, 5)
|
|
1657
1658
|
self.assertEqual(
|
|
1658
1659
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), True),
|
|
1659
1660
|
(0x4ff4f23f, 5, 5, 24),
|
|
1660
1661
|
)
|
|
1661
1662
|
|
|
1662
1663
|
# offset
|
|
1663
|
-
bytes_ = b'
|
|
1664
|
+
bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
|
|
1664
1665
|
self.assertEqual(
|
|
1665
1666
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 1, len(bytes_), False),
|
|
1666
1667
|
None,
|
|
1667
1668
|
)
|
|
1668
1669
|
|
|
1669
|
-
bytes_ = b'
|
|
1670
|
+
bytes_ = b'123dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
|
|
1670
1671
|
self.assertEqual(
|
|
1671
1672
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1672
1673
|
None,
|
|
@@ -1677,13 +1678,13 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1677
1678
|
)
|
|
1678
1679
|
|
|
1679
1680
|
# end_offset
|
|
1680
|
-
bytes_ = b'
|
|
1681
|
+
bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
|
|
1681
1682
|
self.assertEqual(
|
|
1682
1683
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_) - 1, False),
|
|
1683
1684
|
None,
|
|
1684
1685
|
)
|
|
1685
1686
|
|
|
1686
|
-
bytes_ = b'
|
|
1687
|
+
bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5) + b'123'
|
|
1687
1688
|
self.assertEqual(
|
|
1688
1689
|
repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_) - 3, False),
|
|
1689
1690
|
(0x4ff4f23f, 5, 5, 16),
|
|
@@ -1693,34 +1694,34 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1693
1694
|
repacker = zipfile._ZipRepacker()
|
|
1694
1695
|
|
|
1695
1696
|
# basic
|
|
1696
|
-
bytes_ = b'dummy
|
|
1697
|
+
bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1697
1698
|
self.assertEqual(
|
|
1698
1699
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1699
1700
|
(0x4ff4f23f, 5, 5, 12),
|
|
1700
1701
|
)
|
|
1701
1702
|
|
|
1702
1703
|
# return None if compressed size not match
|
|
1703
|
-
bytes_ = b'dumm
|
|
1704
|
+
bytes_ = b'dumm' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1704
1705
|
self.assertEqual(
|
|
1705
1706
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1706
1707
|
None,
|
|
1707
1708
|
)
|
|
1708
1709
|
|
|
1709
1710
|
# zip64
|
|
1710
|
-
bytes_ = b'dummy
|
|
1711
|
+
bytes_ = b'dummy' + struct.pack('<L2Q', 0x4ff4f23f, 5, 5)
|
|
1711
1712
|
self.assertEqual(
|
|
1712
1713
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), True),
|
|
1713
1714
|
(0x4ff4f23f, 5, 5, 20),
|
|
1714
1715
|
)
|
|
1715
1716
|
|
|
1716
1717
|
# offset
|
|
1717
|
-
bytes_ = b'dummy
|
|
1718
|
+
bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1718
1719
|
self.assertEqual(
|
|
1719
1720
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 1, len(bytes_), False),
|
|
1720
1721
|
None,
|
|
1721
1722
|
)
|
|
1722
1723
|
|
|
1723
|
-
bytes_ = b'123dummy
|
|
1724
|
+
bytes_ = b'123dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1724
1725
|
self.assertEqual(
|
|
1725
1726
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False),
|
|
1726
1727
|
None,
|
|
@@ -1731,20 +1732,20 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1731
1732
|
)
|
|
1732
1733
|
|
|
1733
1734
|
# end_offset
|
|
1734
|
-
bytes_ = b'dummy
|
|
1735
|
+
bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1735
1736
|
self.assertEqual(
|
|
1736
1737
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_) - 1, False),
|
|
1737
1738
|
None,
|
|
1738
1739
|
)
|
|
1739
1740
|
|
|
1740
|
-
bytes_ = b'dummy
|
|
1741
|
+
bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5) + b'123'
|
|
1741
1742
|
self.assertEqual(
|
|
1742
1743
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_) - 3, False),
|
|
1743
1744
|
(0x4ff4f23f, 5, 5, 12),
|
|
1744
1745
|
)
|
|
1745
1746
|
|
|
1746
1747
|
# chunk_size
|
|
1747
|
-
bytes_ = b'dummy
|
|
1748
|
+
bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
|
|
1748
1749
|
self.assertEqual(
|
|
1749
1750
|
repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False, 12),
|
|
1750
1751
|
(0x4ff4f23f, 5, 5, 12),
|
|
@@ -1767,7 +1768,7 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1767
1768
|
|
|
1768
1769
|
@requires_lzma()
|
|
1769
1770
|
def test_scan_data_descriptor_no_sig_by_decompression_lzma(self):
|
|
1770
|
-
self.
|
|
1771
|
+
self._test_scan_data_descriptor_no_sig_by_decompression(zipfile.ZIP_LZMA)
|
|
1771
1772
|
|
|
1772
1773
|
@requires_zstd()
|
|
1773
1774
|
def test_scan_data_descriptor_no_sig_by_decompression_zstd(self):
|
|
@@ -1782,27 +1783,34 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1782
1783
|
|
|
1783
1784
|
compressor = zipfile._get_compressor(method)
|
|
1784
1785
|
|
|
1785
|
-
|
|
1786
|
+
raw_bytes = b'dummy'
|
|
1787
|
+
raw_len = len(raw_bytes)
|
|
1788
|
+
comp_bytes = compressor.compress(raw_bytes)
|
|
1786
1789
|
comp_bytes += compressor.flush()
|
|
1787
1790
|
comp_len = len(comp_bytes)
|
|
1788
1791
|
|
|
1789
1792
|
# basic
|
|
1790
|
-
bytes_ = comp_bytes +
|
|
1793
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
|
|
1791
1794
|
self.assertEqual(
|
|
1792
1795
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1793
1796
|
io.BytesIO(bytes_), 0, len(bytes_), False, method),
|
|
1794
|
-
(0x4ff4f23f, comp_len,
|
|
1797
|
+
(0x4ff4f23f, comp_len, raw_len, 12),
|
|
1795
1798
|
)
|
|
1796
1799
|
|
|
1797
1800
|
# return None if insufficient data length
|
|
1798
|
-
bytes_ =
|
|
1801
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
|
|
1799
1802
|
self.assertEqual(
|
|
1800
1803
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1801
1804
|
io.BytesIO(bytes_), 0, len(bytes_) - 1, False, method),
|
|
1802
1805
|
None,
|
|
1803
1806
|
)
|
|
1804
1807
|
|
|
1805
|
-
bytes_ =
|
|
1808
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)[:-1]
|
|
1809
|
+
self.assertEqual(
|
|
1810
|
+
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1811
|
+
io.BytesIO(bytes_), 0, len(bytes_), False, method),
|
|
1812
|
+
None,
|
|
1813
|
+
)
|
|
1806
1814
|
self.assertEqual(
|
|
1807
1815
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1808
1816
|
io.BytesIO(bytes_), 0, len(bytes_) + 1, False, method),
|
|
@@ -1810,7 +1818,7 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1810
1818
|
)
|
|
1811
1819
|
|
|
1812
1820
|
# return None if compressed size not match
|
|
1813
|
-
bytes_ = comp_bytes +
|
|
1821
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len - 1, raw_len)
|
|
1814
1822
|
self.assertEqual(
|
|
1815
1823
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1816
1824
|
io.BytesIO(bytes_), 0, len(bytes_), False, method),
|
|
@@ -1818,41 +1826,41 @@ class ZipRepackerTests(unittest.TestCase):
|
|
|
1818
1826
|
)
|
|
1819
1827
|
|
|
1820
1828
|
# zip64
|
|
1821
|
-
bytes_ = comp_bytes +
|
|
1829
|
+
bytes_ = comp_bytes + struct.pack('<L2Q', 0x4ff4f23f, comp_len, raw_len)
|
|
1822
1830
|
self.assertEqual(
|
|
1823
1831
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1824
1832
|
io.BytesIO(bytes_), 0, len(bytes_), True, method),
|
|
1825
|
-
(0x4ff4f23f, comp_len,
|
|
1833
|
+
(0x4ff4f23f, comp_len, raw_len, 20),
|
|
1826
1834
|
)
|
|
1827
1835
|
|
|
1828
1836
|
# offset
|
|
1829
|
-
bytes_ = comp_bytes +
|
|
1837
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
|
|
1830
1838
|
self.assertEqual(
|
|
1831
1839
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1832
1840
|
io.BytesIO(bytes_), 1, len(bytes_), False, method),
|
|
1833
1841
|
None,
|
|
1834
1842
|
)
|
|
1835
1843
|
|
|
1836
|
-
bytes_ = b'123' + comp_bytes +
|
|
1844
|
+
bytes_ = b'123' + comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
|
|
1837
1845
|
self.assertEqual(
|
|
1838
1846
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1839
1847
|
io.BytesIO(bytes_), 3, len(bytes_), False, method),
|
|
1840
|
-
(0x4ff4f23f, comp_len,
|
|
1848
|
+
(0x4ff4f23f, comp_len, raw_len, 12),
|
|
1841
1849
|
)
|
|
1842
1850
|
|
|
1843
1851
|
# end_offset
|
|
1844
|
-
bytes_ = comp_bytes +
|
|
1852
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
|
|
1845
1853
|
self.assertEqual(
|
|
1846
1854
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1847
1855
|
io.BytesIO(bytes_), 0, len(bytes_) - 2, False, method),
|
|
1848
1856
|
None,
|
|
1849
1857
|
)
|
|
1850
1858
|
|
|
1851
|
-
bytes_ = comp_bytes +
|
|
1859
|
+
bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len) + b'123'
|
|
1852
1860
|
self.assertEqual(
|
|
1853
1861
|
repacker._scan_data_descriptor_no_sig_by_decompression(
|
|
1854
1862
|
io.BytesIO(bytes_), 0, len(bytes_) - 2, False, method),
|
|
1855
|
-
(0x4ff4f23f, comp_len,
|
|
1863
|
+
(0x4ff4f23f, comp_len, raw_len, 12),
|
|
1856
1864
|
)
|
|
1857
1865
|
|
|
1858
1866
|
def _test_scan_data_descriptor_no_sig_by_decompression_invalid(self, method):
|
|
@@ -13,10 +13,10 @@ from .test_zipfile import struct_pack_no_dd_sig
|
|
|
13
13
|
|
|
14
14
|
# polyfills
|
|
15
15
|
try:
|
|
16
|
-
from test.test_zipfile.test_core import Unseekable
|
|
16
|
+
from test.test_zipfile.test_core import Unseekable, requires_zlib
|
|
17
17
|
except ImportError:
|
|
18
18
|
# polyfill for Python < 3.12
|
|
19
|
-
from test.test_zipfile import Unseekable
|
|
19
|
+
from test.test_zipfile import Unseekable, requires_zlib
|
|
20
20
|
|
|
21
21
|
ENABLED_RESOURCES = set(os.environ.get("TEST_RESOURCES", "").split(","))
|
|
22
22
|
|
|
@@ -172,5 +172,39 @@ class TestRepack(unittest.TestCase):
|
|
|
172
172
|
zh.repack()
|
|
173
173
|
self.assertIsNone(zh.testzip())
|
|
174
174
|
|
|
175
|
+
@requires_zlib()
|
|
176
|
+
def test_strip_removed_large_file_with_dd_no_sig_by_decompression(self):
|
|
177
|
+
"""Should scan for the data descriptor (without signature) of a removed
|
|
178
|
+
large file without causing a memory issue."""
|
|
179
|
+
# Try the temp file. If we do TESTFN2, then it hogs
|
|
180
|
+
# gigabytes of disk space for the duration of the test.
|
|
181
|
+
with TemporaryFile() as f:
|
|
182
|
+
tracemalloc.start()
|
|
183
|
+
self._test_strip_removed_large_file_with_dd_no_sig_by_decompression(
|
|
184
|
+
f, zipfile.ZIP_DEFLATED)
|
|
185
|
+
self.assertFalse(f.closed)
|
|
186
|
+
current, peak = tracemalloc.get_traced_memory()
|
|
187
|
+
tracemalloc.stop()
|
|
188
|
+
self.assertLess(peak, self.allowed_memory)
|
|
189
|
+
|
|
190
|
+
def _test_strip_removed_large_file_with_dd_no_sig_by_decompression(self, f, method):
|
|
191
|
+
file = 'file.txt'
|
|
192
|
+
file1 = 'largefile.txt'
|
|
193
|
+
data = b'Sed ut perspiciatis unde omnis iste natus error sit voluptatem'
|
|
194
|
+
with mock.patch('zipfile.struct.pack', side_effect=struct_pack_no_dd_sig):
|
|
195
|
+
with zipfile.ZipFile(Unseekable(f), 'w', compression=method) as zh:
|
|
196
|
+
with zh.open(file1, 'w', force_zip64=True) as fh:
|
|
197
|
+
self._write_large_file(fh)
|
|
198
|
+
zh.writestr(file, data)
|
|
199
|
+
|
|
200
|
+
with zipfile.ZipFile(f, 'a') as zh:
|
|
201
|
+
# make sure data descriptor bit is really set (by making zip file unseekable)
|
|
202
|
+
for zi in zh.infolist():
|
|
203
|
+
self.assertTrue(zi.flag_bits & 8, f'data descriptor flag not set: {zi.filename}')
|
|
204
|
+
|
|
205
|
+
zh.remove(file1)
|
|
206
|
+
zh.repack()
|
|
207
|
+
self.assertIsNone(zh.testzip())
|
|
208
|
+
|
|
175
209
|
if __name__ == "__main__":
|
|
176
210
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|