Merge branch 'feature/UpdateRarfile' into dev

This commit is contained in:
JackDandy 2024-06-07 16:45:37 +01:00
commit b623ffae4d
2 changed files with 47 additions and 13 deletions

View file

@ -12,6 +12,7 @@
* Update imdbpie 5.6.4 (f695e87) to 5.6.5 (f8ed7a0)
* Update profilehooks module 1.12.1 (c3fc078) to 1.13.0.dev0 (99f8a31)
* Update pytz 2023.3/2023c (488d3eb) to 2024.1/2024a (3680953)
* Update Rarfile 4.1a1 (8a72967) to 4.2 (db1df33)
* Update Requests library 2.31.0 (8812812) to 2.32.3 (0e322af)
* Update Tornado Web Server 6.4 (b3f2a4b) to 6.4.1 (2a0e1d1)
* Update urllib3 2.0.7 (56f01e0) to 2.2.1 (54d6edf)

View file

@ -1,6 +1,6 @@
# rarfile.py
#
# Copyright (c) 2005-2020 Marko Kreen <markokr@gmail.com>
# Copyright (c) 2005-2024 Marko Kreen <markokr@gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@ -92,7 +92,7 @@ class AES_CBC_Decrypt:
self.decrypt = ciph.decryptor().update
__version__ = "4.1"
__version__ = "4.2"
# export only interesting items
__all__ = ["get_rar_version", "is_rarfile", "is_rarfile_sfx", "RarInfo", "RarFile", "RarExtFile"]
@ -210,6 +210,9 @@ RAR_M3 = 0x33 #: Compression level `-m3`.
RAR_M4 = 0x34 #: Compression level `-m4`.
RAR_M5 = 0x35 #: Compression level `-m5` - Maximum compression.
RAR_MAX_PASSWORD = 127 #: Max number of utf-16 chars in passwords.
RAR_MAX_KDF_SHIFT = 24 #: Max power-of-2 for KDF count
#
# RAR5 constants
#
@ -739,6 +742,13 @@ class RarFile:
"""
return self._file_parser.needs_password()
def is_solid(self):
"""Returns True if archive uses solid compression.
.. versionadded:: 4.2
"""
return self._file_parser.is_solid()
def namelist(self):
"""Return list of filenames in archive.
"""
@ -1030,6 +1040,14 @@ class CommonParser:
self._sfx_offset = sfx_offset
self._part_only = part_only
def is_solid(self):
"""Returns True if archive uses solid compression.
"""
if self._main:
if self._main.flags & RAR_MAIN_SOLID:
return True
return False
def has_header_encryption(self):
"""Returns True if headers are encrypted
"""
@ -1167,7 +1185,9 @@ class CommonParser:
if not self._password:
break
elif h.type == RAR_BLOCK_ENDARC:
more_vols = (h.flags & RAR_ENDARC_NEXT_VOLUME) > 0
# use flag, but also allow RAR 2.x logic below to trigger
if h.flags & RAR_ENDARC_NEXT_VOLUME:
more_vols = True
endarc = True
if raise_need_first_vol and (h.flags & RAR_ENDARC_VOLNR) > 0:
raise NeedFirstVolume(
@ -1810,10 +1830,10 @@ class RAR5Parser(CommonParser):
def _gen_key(self, kdf_count, salt):
if self._last_aes256_key[:2] == (kdf_count, salt):
return self._last_aes256_key[2]
if kdf_count > 24:
if kdf_count > RAR_MAX_KDF_SHIFT:
raise BadRarFile("Too large kdf_count")
pwd = self._get_utf8_password()
key = pbkdf2_hmac("sha256", pwd, salt, 1 << kdf_count)
key = rar5_s2k(pwd, salt, 1 << kdf_count)
self._last_aes256_key = (kdf_count, salt, key)
return key
@ -1978,6 +1998,8 @@ class RAR5Parser(CommonParser):
def _check_password(self, check_value, kdf_count_shift, salt):
if len(check_value) != RAR5_PW_CHECK_SIZE + RAR5_PW_SUM_SIZE:
return
if kdf_count_shift > RAR_MAX_KDF_SHIFT:
raise BadRarFile("Too large kdf_count")
hdr_check = check_value[:RAR5_PW_CHECK_SIZE]
hdr_sum = check_value[RAR5_PW_CHECK_SIZE:]
@ -1987,7 +2009,7 @@ class RAR5Parser(CommonParser):
kdf_count = (1 << kdf_count_shift) + 32
pwd = self._get_utf8_password()
pwd_hash = pbkdf2_hmac("sha256", pwd, salt, kdf_count)
pwd_hash = rar5_s2k(pwd, salt, kdf_count)
pwd_check = bytearray(RAR5_PW_CHECK_SIZE)
len_mask = RAR5_PW_CHECK_SIZE - 1
@ -2341,8 +2363,8 @@ class RarExtFile(io.RawIOBase):
"""Seek in data.
On uncompressed files, the seeking works by actual
seeks so it's fast. On compresses files its slow
- forward seeking happends by reading ahead,
seeks so it's fast. On compressed files its slow
- forward seeking happens by reading ahead,
backwards by re-opening and decompressing from the start.
"""
@ -3044,12 +3066,23 @@ def is_filelike(obj):
return True
def rar5_s2k(pwd, salt, kdf_count):
"""String-to-key hash for RAR5.
"""
if not isinstance(pwd, str):
pwd = pwd.decode("utf8")
wstr = pwd.encode("utf-16le")[:RAR_MAX_PASSWORD*2]
ustr = wstr.decode("utf-16le").encode("utf8")
return pbkdf2_hmac("sha256", ustr, salt, kdf_count)
def rar3_s2k(pwd, salt):
"""String-to-key hash for RAR3.
"""
if not isinstance(pwd, str):
pwd = pwd.decode("utf8")
seed = bytearray(pwd.encode("utf-16le") + salt)
wstr = pwd.encode("utf-16le")[:RAR_MAX_PASSWORD*2]
seed = bytearray(wstr + salt)
h = Rar3Sha1(rarbug=True)
iv = b""
for i in range(16):
@ -3114,7 +3147,7 @@ def rar3_decompress(vers, meth, data, declen=0, flags=0, crc=0, pwd=None, salt=N
def sanitize_filename(fname, pathsep, is_win32):
"""Simulate unrar sanitization.
"""Make filename safe for write access.
"""
if is_win32:
if len(fname) > 1 and fname[1] == ":":
@ -3186,12 +3219,12 @@ def parse_dos_time(stamp):
class nsdatetime(datetime):
"""Datetime that carries nanoseconds.
Arithmetic not supported, will lose nanoseconds.
Arithmetic operations will lose nanoseconds.
.. versionadded:: 4.0
"""
__slots__ = ("nanosecond",)
nanosecond: int #: Number of nanoseconds, 0 <= nanosecond < 999999999
nanosecond: int #: Number of nanoseconds, 0 <= nanosecond <= 999999999
def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
microsecond=0, tzinfo=None, *, fold=0, nanosecond=0):
@ -3393,7 +3426,7 @@ class ToolSetup:
UNRAR_CONFIG = {
"open_cmd": ("UNRAR_TOOL", "p", "-inul"),
"check_cmd": ("UNRAR_TOOL", "-inul"),
"check_cmd": ("UNRAR_TOOL", "-inul", "-?"),
"password": "-p",
"no_password": ("-p-",),
# map return code to exception class, codes from rar.txt