|
4 | 4 | import math |
5 | 5 |
|
6 | 6 | from . import ffi |
| 7 | +from .exception import ArchiveError |
7 | 8 |
|
8 | 9 |
|
9 | 10 | class FileType(IntEnum): |
@@ -86,12 +87,12 @@ def modify(self, header_codec=None, **attributes): |
86 | 87 | rdev (int | Tuple[int, int]): device number, if the file is a device |
87 | 88 | rdevmajor (int): major part of the device number |
88 | 89 | 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 |
95 | 96 | """ |
96 | 97 | if header_codec: |
97 | 98 | self.header_codec = header_codec |
@@ -440,79 +441,93 @@ def rdevminor(self, value): |
440 | 441 | ffi.entry_set_rdevminor(self._entry_p, value) |
441 | 442 |
|
442 | 443 | @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') |
445 | 446 |
|
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) |
449 | 450 |
|
450 | 451 | @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') |
453 | 454 |
|
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) |
457 | 458 |
|
458 | 459 | @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') |
461 | 462 |
|
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) |
465 | 466 |
|
466 | 467 | @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') |
469 | 470 |
|
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) |
473 | 474 |
|
474 | 475 | @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') |
477 | 478 |
|
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) |
481 | 482 |
|
482 | 483 | @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') |
485 | 486 |
|
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) |
489 | 490 |
|
490 | | - def _digest(self, digest_type): |
| 491 | + def get_stored_digest(self, algorithm_name): |
| 492 | + algorithm = ffi.DIGEST_ALGORITHMS[algorithm_name] |
491 | 493 | 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) |
495 | 495 | 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 | + ) |
503 | 515 | 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 | + ) |
510 | 521 | 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 |
516 | 531 |
|
517 | 532 |
|
518 | 533 | class ConsumedArchiveEntry(ArchiveEntry): |
|
0 commit comments