You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

141 lines
4.5 KiB

  1. import os, time
  2. from libarchive import is_archive, Entry, SeekableArchive, _libarchive
  3. from zipfile import ZIP_STORED, ZIP_DEFLATED
  4. def is_zipfile(filename):
  5. return is_archive(filename, formats=('zip',))
  6. class ZipEntry(Entry):
  7. def __init__(self, *args, **kwargs):
  8. super(ZipEntry, self).__init__(*args, **kwargs)
  9. def get_filename(self):
  10. return self.pathname
  11. def set_filename(self, value):
  12. self.pathname = value
  13. filename = property(get_filename, set_filename)
  14. def get_file_size(self):
  15. return self.size
  16. def set_file_size(self, value):
  17. assert isinstance(value, int), 'Please provide size as int or long.'
  18. self.size = value
  19. file_size = property(get_file_size, set_file_size)
  20. def get_date_time(self):
  21. return time.localtime(self.mtime)[0:6]
  22. def set_date_time(self, value):
  23. assert isinstance(value, tuple), 'mtime should be tuple (year, month, day, hour, minute, second).'
  24. assert len(value) == 6, 'mtime should be tuple (year, month, day, hour, minute, second).'
  25. self.mtime = time.mktime(value + (0, 0, 0))
  26. date_time = property(get_date_time, set_date_time)
  27. header_offset = Entry.header_position
  28. def _get_missing(self):
  29. raise NotImplemented()
  30. def _set_missing(self, value):
  31. raise NotImplemented()
  32. compress_type = property(_get_missing, _set_missing)
  33. comment = property(_get_missing, _set_missing)
  34. extra = property(_get_missing, _set_missing)
  35. create_system = property(_get_missing, _set_missing)
  36. create_version = property(_get_missing, _set_missing)
  37. extract_version = property(_get_missing, _set_missing)
  38. reserved = property(_get_missing, _set_missing)
  39. flag_bits = property(_get_missing, _set_missing)
  40. volume = property(_get_missing, _set_missing)
  41. internal_attr = property(_get_missing, _set_missing)
  42. external_attr = property(_get_missing, _set_missing)
  43. CRC = property(_get_missing, _set_missing)
  44. compress_size = property(_get_missing, _set_missing)
  45. # encryption is one of (traditional = zipcrypt, aes128, aes256)
  46. class ZipFile(SeekableArchive):
  47. def __init__(self, f, mode='r', compression=ZIP_DEFLATED, allowZip64=False, password=None,
  48. encryption=None):
  49. self.compression = compression
  50. self.encryption = encryption
  51. super(ZipFile, self).__init__(
  52. f, mode=mode, format='zip', entry_class=ZipEntry, encoding='CP437', password=password
  53. )
  54. getinfo = SeekableArchive.getentry
  55. def set_initial_options(self):
  56. if self.mode == 'w' and self.compression == ZIP_STORED:
  57. # Disable compression for writing.
  58. _libarchive.archive_write_set_format_option(self._a, "zip", "compression", "store")
  59. if self.mode == 'w' and self.password:
  60. if not self.encryption:
  61. self.encryption = "traditional"
  62. _libarchive.archive_write_set_format_option(self._a, "zip", "encryption", self.encryption)
  63. def namelist(self):
  64. return list(self.iterpaths())
  65. def infolist(self):
  66. return list(self)
  67. def open(self, name, mode, pwd=None):
  68. if mode == 'r':
  69. if pwd:
  70. self.add_passphrase(pwd)
  71. return self.readstream(name)
  72. else:
  73. return self.writestream(name)
  74. def extract(self, name, path=None, pwd=None):
  75. if pwd:
  76. self.add_passphrase(pwd)
  77. if not path:
  78. path = os.getcwd()
  79. return self.readpath(name, os.path.join(path, name))
  80. def extractall(self, path, names=None, pwd=None):
  81. if pwd:
  82. self.add_passphrase(pwd)
  83. if not names:
  84. names = self.namelist()
  85. if names:
  86. for name in names:
  87. self.extract(name, path)
  88. def read(self, name, pwd=None):
  89. if pwd:
  90. self.add_passphrase(pwd)
  91. return super(ZipFile, self).read(name)
  92. def writestr(self, member, data, compress_type=None):
  93. if compress_type != self.compression and not (compress_type is None):
  94. raise Exception('Cannot change compression type for individual entries.')
  95. return self.write(member, data)
  96. def setpassword(self, pwd):
  97. return self.set_passphrase(pwd)
  98. def testzip(self):
  99. raise NotImplemented()
  100. def _get_missing(self):
  101. raise NotImplemented()
  102. def _set_missing(self, value):
  103. raise NotImplemented()
  104. comment = property(_get_missing, _set_missing)