Skip to content

Commit 8a0ec1d

Browse files
committed
more rewording and refactoring
1 parent 99f9eff commit 8a0ec1d

2 files changed

Lines changed: 99 additions & 81 deletions

File tree

libarchive/entry.py

Lines changed: 73 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import math
55

66
from . import ffi
7+
from .exception import ArchiveError
78

89

910
class FileType(IntEnum):
@@ -86,12 +87,12 @@ def modify(self, header_codec=None, **attributes):
8687
rdev (int | Tuple[int, int]): device number, if the file is a device
8788
rdevmajor (int): major part of the device number
8889
rdevminor (int): minor part of the device number
89-
md5digest (bytes): MD5 digest
90-
rmd160digest (bytes): RMD160 digest
91-
sha1digest (bytes): SHA1 digest
92-
sha256digest (bytes): SHA256 digest
93-
sha384digest (bytes): SHA384 digest
94-
sha512digest (bytes): SHA512 digest
90+
md5 (bytes): MD5 digest
91+
rmd160 (bytes): RMD160 digest
92+
sha1 (bytes): SHA1 digest
93+
sha256 (bytes): SHA256 digest
94+
sha384 (bytes): SHA384 digest
95+
sha512 (bytes): SHA512 digest
9596
"""
9697
if header_codec:
9798
self.header_codec = header_codec
@@ -440,79 +441,93 @@ def rdevminor(self, value):
440441
ffi.entry_set_rdevminor(self._entry_p, value)
441442

442443
@property
443-
def md5digest(self):
444-
return self._digest(ffi.ARCHIVE_ENTRY_DIGEST_MD5)
444+
def md5(self):
445+
return self.get_stored_digest('md5')
445446

446-
@md5digest.setter
447-
def md5digest(self, value):
448-
self._set_digest(ffi.ARCHIVE_ENTRY_DIGEST_MD5, value)
447+
@md5.setter
448+
def md5(self, value):
449+
self.set_stored_digest('md5', value)
449450

450451
@property
451-
def rmd160digest(self):
452-
return self._digest(ffi.ARCHIVE_ENTRY_DIGEST_RMD160)
452+
def rmd160(self):
453+
return self.get_stored_digest('rmd160')
453454

454-
@rmd160digest.setter
455-
def rmd160digest(self, value):
456-
self._set_digest(ffi.ARCHIVE_ENTRY_DIGEST_RMD160, value)
455+
@rmd160.setter
456+
def rmd160(self, value):
457+
self.set_stored_digest('rmd160', value)
457458

458459
@property
459-
def sha1digest(self):
460-
return self._digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA1)
460+
def sha1(self):
461+
return self.get_stored_digest('sha1')
461462

462-
@sha1digest.setter
463-
def sha1digest(self, value):
464-
self._set_digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA1, value)
463+
@sha1.setter
464+
def sha1(self, value):
465+
self.set_stored_digest('sha1', value)
465466

466467
@property
467-
def sha256digest(self):
468-
return self._digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA256)
468+
def sha256(self):
469+
return self.get_stored_digest('sha256')
469470

470-
@sha256digest.setter
471-
def sha256digest(self, value):
472-
self._set_digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA256, value)
471+
@sha256.setter
472+
def sha256(self, value):
473+
self.set_stored_digest('sha256', value)
473474

474475
@property
475-
def sha384digest(self):
476-
return self._digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA384)
476+
def sha384(self):
477+
return self.get_stored_digest('sha384')
477478

478-
@sha384digest.setter
479-
def sha384digest(self, value):
480-
self._set_digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA384, value)
479+
@sha384.setter
480+
def sha384(self, value):
481+
self.set_stored_digest('sha384', value)
481482

482483
@property
483-
def sha512digest(self):
484-
return self._digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA512)
484+
def sha512(self):
485+
return self.get_stored_digest('sha512')
485486

486-
@sha512digest.setter
487-
def sha512digest(self, value):
488-
self._set_digest(ffi.ARCHIVE_ENTRY_DIGEST_SHA512, value)
487+
@sha512.setter
488+
def sha512(self, value):
489+
self.set_stored_digest('sha512', value)
489490

490-
def _digest(self, digest_type):
491+
def get_stored_digest(self, algorithm_name):
492+
algorithm = ffi.DIGEST_ALGORITHMS[algorithm_name]
491493
try:
492-
ptr = ffi.entry_digest(self._entry_p, digest_type)
493-
if ptr:
494-
return bytes(ptr[:ffi._DIGEST_LENGTHS[digest_type - 1]])
494+
ptr = ffi.entry_digest(self._entry_p, algorithm.libarchive_id)
495495
except AttributeError:
496-
raise NotImplementedError(f"the libarchive being used (version "
497-
f"{ffi.version_number()} path "
498-
f"{ffi.libarchive_path}) doesn't "
499-
f"support read-only digest APIs")
500-
return None
501-
502-
def _set_digest(self, digest_type, value):
496+
raise NotImplementedError(
497+
f"the libarchive being used (version {ffi.version_number()}, path "
498+
f"{ffi.libarchive_path}) doesn't support reading entry digests"
499+
) from None
500+
except ArchiveError:
501+
raise NotImplementedError(
502+
f"the libarchive being used (version {ffi.version_number()}, path "
503+
f"{ffi.libarchive_path}) doesn't support {algorithm_name} digests"
504+
) from None
505+
return bytes(ptr[:algorithm.bytes_length])
506+
507+
def set_stored_digest(self, algorithm_name, value):
508+
algorithm = ffi.DIGEST_ALGORITHMS[algorithm_name]
509+
expected_length = algorithm.bytes_length
510+
if len(value) != expected_length:
511+
raise ValueError(
512+
f"invalid input digest: expected {expected_length} bytes, "
513+
f"got {len(value)}"
514+
)
503515
try:
504-
digest_length = ffi._DIGEST_LENGTHS[digest_type - 1]
505-
if len(value) != digest_length:
506-
raise ValueError(f"Invalid input digest Expected {digest_length} "
507-
f"bytes. Got {len(value)}.")
508-
buffer = (digest_length * ffi.c_ubyte)(*value)
509-
ffi.entry_set_digest(self._entry_p, digest_type, buffer)
516+
retcode = ffi.entry_set_digest(
517+
self._entry_p,
518+
algorithm.libarchive_id,
519+
(expected_length * ffi.c_ubyte)(*value)
520+
)
510521
except AttributeError:
511-
raise NotImplementedError(f"the libarchive being used (version "
512-
f"{ffi.version_number()} path "
513-
f"{ffi.libarchive_path}) doesn't support "
514-
f"writable digest APIs")
515-
return None
522+
raise NotImplementedError(
523+
f"the libarchive being used (version {ffi.version_number()}, path "
524+
f"{ffi.libarchive_path}) doesn't support writing entry digests"
525+
) from None
526+
if retcode < 0:
527+
raise NotImplementedError(
528+
f"the libarchive being used (version {ffi.version_number()}, path "
529+
f"{ffi.libarchive_path}) doesn't support {algorithm_name} digests"
530+
) from None
516531

517532

518533
class ConsumedArchiveEntry(ArchiveEntry):

libarchive/ffi.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -366,38 +366,41 @@ def get_write_filter_function(filter_name):
366366
f"path {libarchive_path}) doesn't support encryption"
367367
)
368368

369-
# archive digest API
370-
try:
371-
ffi('entry_digest', [c_archive_entry_p, c_int], POINTER(c_ubyte))
372-
373-
ARCHIVE_ENTRY_DIGEST_MD5 = 1
374-
ARCHIVE_ENTRY_DIGEST_RMD160 = 2
375-
ARCHIVE_ENTRY_DIGEST_SHA1 = 3
376-
ARCHIVE_ENTRY_DIGEST_SHA256 = 4
377-
ARCHIVE_ENTRY_DIGEST_SHA384 = 5
378-
ARCHIVE_ENTRY_DIGEST_SHA512 = 6
379-
380-
_DIGEST_LENGTHS = [
381-
16, # MD5
382-
20, # RMD160
383-
20, # SHA1
384-
32, # SHA256
385-
48, # SHA384
386-
64, # SHA512
387-
]
388369

370+
# archive entry digests (a.k.a. hashes)
371+
372+
class DigestAlgorithm:
373+
__slots__ = ('name', 'libarchive_id', 'bytes_length')
374+
375+
def __init__(self, name, libarchive_id, bytes_length):
376+
self.name = name
377+
self.libarchive_id = libarchive_id
378+
self.bytes_length = bytes_length
379+
380+
381+
DIGEST_ALGORITHMS = {
382+
'md5': DigestAlgorithm('md5', libarchive_id=1, bytes_length=16),
383+
'rmd160': DigestAlgorithm('rmd160', libarchive_id=2, bytes_length=20),
384+
'sha1': DigestAlgorithm('sha1', libarchive_id=3, bytes_length=20),
385+
'sha256': DigestAlgorithm('sha256', libarchive_id=4, bytes_length=32),
386+
'sha384': DigestAlgorithm('sha384', libarchive_id=5, bytes_length=48),
387+
'sha512': DigestAlgorithm('sha512', libarchive_id=6, bytes_length=64),
388+
}
389+
390+
try:
391+
ffi('entry_digest', [c_archive_entry_p, c_int], POINTER(c_ubyte), check_null)
389392
except AttributeError:
390393
logger.info(
391394
f"the libarchive being used (version {version_number()}, "
392-
f"path {libarchive_path}) doesn't support read-only message digest API"
395+
f"path {libarchive_path}) doesn't support reading entry digests"
393396
)
394397

395398
try:
396399
ffi('entry_set_digest',
397-
[ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_ubyte)],
398-
ctypes.c_int)
400+
[c_archive_entry_p, c_int, POINTER(c_ubyte)],
401+
c_int, check_int)
399402
except AttributeError:
400403
logger.info(
401404
f"the libarchive being used (version {version_number()}, "
402-
f"path {libarchive_path}) doesn't support mutable message digest API"
405+
f"path {libarchive_path}) doesn't support modifying entry digests"
403406
)

0 commit comments

Comments
 (0)