Skip to content

Commit

Permalink
Catch exception in threading extraction
Browse files Browse the repository at this point in the history
Signed-off-by: Hiroshi Miura <miurahr@linux.com>
  • Loading branch information
miurahr committed Jan 20, 2021
1 parent d2e1638 commit 438bba4
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 28 deletions.
70 changes: 42 additions & 28 deletions py7zr/py7zr.py
Expand Up @@ -965,49 +965,63 @@ def extract(self, fp: BinaryIO, parallel: bool, q=None) -> None:
filename = getattr(fp, 'name', None)
self.extract_single(open(filename, 'rb'), empty_files, 0, 0, q)
extract_threads = []
exc_q = queue.Queue() # type: queue.Queue
for i in range(numfolders):
p = threading.Thread(target=self.extract_single,
args=(filename, folders[i].files,
self.src_start + positions[i], self.src_start + positions[i + 1], q))
self.src_start + positions[i], self.src_start + positions[i + 1],
q, exc_q))
p.start()
extract_threads.append((p))
extract_threads.append(p)
for p in extract_threads:
p.join()
if exc_q.empty():
pass
else:
(exc_type, exc_val, exc_tb) = exc_q.get()
raise exc_type(exc_val).with_traceback(exc_tb)
else:
empty_files = [f for f in self.files if f.emptystream]
self.extract_single(fp, empty_files, 0, 0, q)

def extract_single(self, fp: Union[BinaryIO, str], files, src_start: int, src_end: int,
q: Optional[queue.Queue]) -> None:
q: Optional[queue.Queue], exc_q: Optional[queue.Queue] = None) -> None:
"""Single thread extractor that takes file lists in single 7zip folder."""
if files is None:
return
if isinstance(fp, str):
fp = open(fp, 'rb')
fp.seek(src_start)
for f in files:
if q is not None:
q.put(('s', str(f.filename), str(f.compressed) if f.compressed is not None else '0'))
fileish = self.target_filepath.get(f.id, None)
if fileish is not None:
fileish.parent.mkdir(parents=True, exist_ok=True)
with fileish.open(mode='wb') as ofp:
if not f.emptystream:
# extract to file
try:
if isinstance(fp, str):
fp = open(fp, 'rb')
fp.seek(src_start)
for f in files:
if q is not None:
q.put(('s', str(f.filename), str(f.compressed) if f.compressed is not None else '0'))
fileish = self.target_filepath.get(f.id, None)
if fileish is not None:
fileish.parent.mkdir(parents=True, exist_ok=True)
with fileish.open(mode='wb') as ofp:
if not f.emptystream:
# extract to file
crc32 = self.decompress(fp, f.folder, ofp, f.uncompressed, f.compressed, src_end)
ofp.seek(0)
if f.crc32 is not None and crc32 != f.crc32:
raise CrcError("{}".format(f.filename))
else:
pass # just create empty file
elif not f.emptystream:
# read and bin off a data but check crc
with NullIO() as ofp:
crc32 = self.decompress(fp, f.folder, ofp, f.uncompressed, f.compressed, src_end)
ofp.seek(0)
if f.crc32 is not None and crc32 != f.crc32:
raise CrcError("{}".format(f.filename))
else:
pass # just create empty file
elif not f.emptystream:
# read and bin off a data but check crc
with NullIO() as ofp:
crc32 = self.decompress(fp, f.folder, ofp, f.uncompressed, f.compressed, src_end)
if f.crc32 is not None and crc32 != f.crc32:
raise CrcError("{}".format(f.filename))
if q is not None:
q.put(('e', str(f.filename), str(f.uncompressed)))
if f.crc32 is not None and crc32 != f.crc32:
raise CrcError("{}".format(f.filename))
if q is not None:
q.put(('e', str(f.filename), str(f.uncompressed)))
except Exception as e:
if exc_q is None:
raise e
else:
exc_tuple = sys.exc_info()
exc_q.put(exc_tuple)

def decompress(self, fp: BinaryIO, folder, fq: IO[Any],
size: int, compressed_size: Optional[int], src_end: int) -> int:
Expand Down
Binary file added tests/data/issue_218.7z
Binary file not shown.
7 changes: 7 additions & 0 deletions tests/test_extract.py
Expand Up @@ -462,3 +462,10 @@ def test_extract_lzma_bcj_ppc(tmp_path):
def test_extract_lzma_bcj_sparc(tmp_path):
with py7zr.SevenZipFile(testdata_path.joinpath('lzma_bcj_sparc.7z').open(mode='rb')) as ar:
ar.extractall(tmp_path)


@pytest.mark.files
def test_extract_multi_exception(tmp_path):
with pytest.raises(py7zr.exceptions.UnsupportedCompressionMethodError):
with py7zr.SevenZipFile(testdata_path.joinpath('issue_218.7z').open(mode='rb')) as ar:
ar.extractall(tmp_path)

0 comments on commit 438bba4

Please sign in to comment.