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.
 
 
 
 
 

115 lines
3.1 KiB

  1. import os
  2. from libarchive import is_archive, Entry, SeekableArchive
  3. from tarfile import DEFAULT_FORMAT, USTAR_FORMAT, GNU_FORMAT, PAX_FORMAT, \
  4. ENCODING
  5. from tarfile import REGTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, CHRTYPE, BLKTYPE
  6. FORMAT_CONVERSION = {
  7. USTAR_FORMAT: 'tar',
  8. GNU_FORMAT: 'gnu',
  9. PAX_FORMAT: 'pax',
  10. }
  11. def is_tarfile(filename):
  12. return is_archive(filename, formats=('tar', 'gnu', 'pax'))
  13. def open(**kwargs):
  14. return TarFile(**kwargs)
  15. class TarInfo(Entry):
  16. def __init__(self, name):
  17. super(TarInfo, self).__init__(pathname=name)
  18. fromtarfile = Entry.from_archive
  19. def get_name(self):
  20. return self.pathname
  21. def set_name(self, value):
  22. self.pathname = value
  23. name = property(get_name, set_name)
  24. @property
  25. def get_type(self):
  26. for attr, type in (
  27. ('isdir', DIRTYPE), ('isfile', REGTYPE), ('issym', SYMTYPE),
  28. ('isfifo', FIFOTYPE), ('ischr', CHRTYPE), ('isblk', BLKTYPE),
  29. ):
  30. if getattr(self, attr)():
  31. return type
  32. def _get_missing(self):
  33. raise NotImplemented()
  34. def _set_missing(self, value):
  35. raise NotImplemented()
  36. pax_headers = property(_get_missing, _set_missing)
  37. class TarFile(SeekableArchive):
  38. getmember = SeekableArchive.getentry
  39. list = SeekableArchive.printlist
  40. extract = SeekableArchive.readpath
  41. extractfile = SeekableArchive.readstream
  42. def __init__(self, name=None, mode='r', fileobj=None,
  43. format=DEFAULT_FORMAT, tarinfo=TarInfo, encoding=ENCODING):
  44. if name:
  45. f = name
  46. elif fileobj:
  47. f = fileobj
  48. try:
  49. format = FORMAT_CONVERSION.get(format)
  50. except KeyError:
  51. raise Exception('Invalid tar format: %s' % format)
  52. super(TarFile, self).__init__(f, mode=mode, format=format,
  53. entry_class=tarinfo, encoding=encoding)
  54. def getmembers(self):
  55. return list(self)
  56. def getnames(self):
  57. return list(self.iterpaths)
  58. def __next__(self):
  59. raise NotImplementedError
  60. pass # TODO: how to do this?
  61. def extract(self, member, path=None):
  62. if path is None:
  63. path = os.getcwd()
  64. if isinstance(member, str):
  65. f = os.path.join(path, member)
  66. else:
  67. f = os.path.join(path, member.pathname)
  68. return self.readpath(member, f)
  69. def add(self, name, arcname, recursive=True, exclude=None, filter=None):
  70. pass # TODO: implement this.
  71. def addfile(self, tarinfo, fileobj):
  72. return self.writepath(fileobj, tarinfo)
  73. def gettarinfo(self, name=None, arcname=None, fileobj=None):
  74. if name:
  75. f = name
  76. elif fileobj:
  77. f = fileobj
  78. entry = self.entry_class.from_file(f)
  79. if arcname:
  80. entry.pathname = arcname
  81. return entry
  82. def _get_missing(self):
  83. raise NotImplemented()
  84. def _set_missing(self, value):
  85. raise NotImplemented()
  86. pax_headers = property(_get_missing, _set_missing)