diff options
| author | jvoisin | 2019-04-27 22:33:54 +0200 |
|---|---|---|
| committer | jvoisin | 2019-04-27 22:48:40 +0200 |
| commit | a7ebb587e19ce1177a7ef067e2da74e4964ff19e (patch) | |
| tree | 63d140b6748243dbef4e8bff191ed48f40e069d4 /libmat2 | |
| parent | 14a4cddb8b0d68aa90facf8452a09c81125d8570 (diff) | |
Handle weird permissions in tar archives
Diffstat (limited to 'libmat2')
| -rw-r--r-- | libmat2/archive.py | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/libmat2/archive.py b/libmat2/archive.py index 7aa5cb9..969bbd8 100644 --- a/libmat2/archive.py +++ b/libmat2/archive.py | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | import abc | 1 | import abc |
| 2 | import stat | ||
| 2 | import zipfile | 3 | import zipfile |
| 3 | import datetime | 4 | import datetime |
| 4 | import tarfile | 5 | import tarfile |
| @@ -104,6 +105,12 @@ class ArchiveBasedAbstractParser(abstract.AbstractParser): | |||
| 104 | full_path: str): | 105 | full_path: str): |
| 105 | """Add the file at full_path to the archive, via the given member.""" | 106 | """Add the file at full_path to the archive, via the given member.""" |
| 106 | 107 | ||
| 108 | @staticmethod | ||
| 109 | def _set_member_permissions(member: ArchiveMember, permissions: int) -> ArchiveMember: | ||
| 110 | """Set the permission of the archive member.""" | ||
| 111 | # pylint: disable=unused-argument | ||
| 112 | return member | ||
| 113 | |||
| 107 | def get_meta(self) -> Dict[str, Union[str, dict]]: | 114 | def get_meta(self) -> Dict[str, Union[str, dict]]: |
| 108 | meta = dict() # type: Dict[str, Union[str, dict]] | 115 | meta = dict() # type: Dict[str, Union[str, dict]] |
| 109 | 116 | ||
| @@ -120,6 +127,7 @@ class ArchiveBasedAbstractParser(abstract.AbstractParser): | |||
| 120 | 127 | ||
| 121 | zin.extract(member=item, path=temp_folder) | 128 | zin.extract(member=item, path=temp_folder) |
| 122 | full_path = os.path.join(temp_folder, member_name) | 129 | full_path = os.path.join(temp_folder, member_name) |
| 130 | os.chmod(full_path, stat.S_IRUSR) | ||
| 123 | 131 | ||
| 124 | specific_meta = self._specific_get_meta(full_path, member_name) | 132 | specific_meta = self._specific_get_meta(full_path, member_name) |
| 125 | local_meta = {**local_meta, **specific_meta} | 133 | local_meta = {**local_meta, **specific_meta} |
| @@ -164,6 +172,9 @@ class ArchiveBasedAbstractParser(abstract.AbstractParser): | |||
| 164 | zin.extract(member=item, path=temp_folder) | 172 | zin.extract(member=item, path=temp_folder) |
| 165 | full_path = os.path.join(temp_folder, member_name) | 173 | full_path = os.path.join(temp_folder, member_name) |
| 166 | 174 | ||
| 175 | original_permissions = os.stat(full_path).st_mode | ||
| 176 | os.chmod(full_path, original_permissions | stat.S_IWUSR | stat.S_IRUSR) | ||
| 177 | |||
| 167 | if self._specific_cleanup(full_path) is False: | 178 | if self._specific_cleanup(full_path) is False: |
| 168 | logging.warning("Something went wrong during deep cleaning of %s", | 179 | logging.warning("Something went wrong during deep cleaning of %s", |
| 169 | member_name) | 180 | member_name) |
| @@ -202,6 +213,7 @@ class ArchiveBasedAbstractParser(abstract.AbstractParser): | |||
| 202 | os.rename(member_parser.output_filename, full_path) | 213 | os.rename(member_parser.output_filename, full_path) |
| 203 | 214 | ||
| 204 | zinfo = self.member_class(member_name) # type: ignore | 215 | zinfo = self.member_class(member_name) # type: ignore |
| 216 | zinfo = self._set_member_permissions(zinfo, original_permissions) | ||
| 205 | clean_zinfo = self._clean_member(zinfo) | 217 | clean_zinfo = self._clean_member(zinfo) |
| 206 | self._add_file_to_archive(zout, clean_zinfo, full_path) | 218 | self._add_file_to_archive(zout, clean_zinfo, full_path) |
| 207 | 219 | ||
| @@ -216,11 +228,11 @@ class TarParser(ArchiveBasedAbstractParser): | |||
| 216 | mimetypes = {'application/x-tar'} | 228 | mimetypes = {'application/x-tar'} |
| 217 | def __init__(self, filename): | 229 | def __init__(self, filename): |
| 218 | super().__init__(filename) | 230 | super().__init__(filename) |
| 219 | # yes, it's tarfile.TarFile.open and not tarfile.TarFile, | 231 | # yes, it's tarfile.open and not tarfile.TarFile, |
| 220 | # as stated in the documentation: | 232 | # as stated in the documentation: |
| 221 | # https://docs.python.org/3/library/tarfile.html#tarfile.TarFile | 233 | # https://docs.python.org/3/library/tarfile.html#tarfile.TarFile |
| 222 | # This is required to support compressed archives. | 234 | # This is required to support compressed archives. |
| 223 | self.archive_class = tarfile.TarFile.open | 235 | self.archive_class = tarfile.open |
| 224 | self.member_class = tarfile.TarInfo | 236 | self.member_class = tarfile.TarInfo |
| 225 | 237 | ||
| 226 | def is_archive_valid(self): | 238 | def is_archive_valid(self): |
| @@ -239,7 +251,7 @@ class TarParser(ArchiveBasedAbstractParser): | |||
| 239 | assert isinstance(member, tarfile.TarInfo) # please mypy | 251 | assert isinstance(member, tarfile.TarInfo) # please mypy |
| 240 | metadata = {} | 252 | metadata = {} |
| 241 | if member.mtime != 0: | 253 | if member.mtime != 0: |
| 242 | metadata['mtime'] = datetime.datetime.fromtimestamp(member.mtime) | 254 | metadata['mtime'] = str(datetime.datetime.fromtimestamp(member.mtime)) |
| 243 | if member.uid != 0: | 255 | if member.uid != 0: |
| 244 | metadata['uid'] = str(member.uid) | 256 | metadata['uid'] = str(member.uid) |
| 245 | if member.gid != 0: | 257 | if member.gid != 0: |
| @@ -267,6 +279,12 @@ class TarParser(ArchiveBasedAbstractParser): | |||
| 267 | assert isinstance(member, tarfile.TarInfo) # please mypy | 279 | assert isinstance(member, tarfile.TarInfo) # please mypy |
| 268 | return member.name | 280 | return member.name |
| 269 | 281 | ||
| 282 | @staticmethod | ||
| 283 | def _set_member_permissions(member: ArchiveMember, permissions: int) -> ArchiveMember: | ||
| 284 | assert isinstance(member, tarfile.TarInfo) # please mypy | ||
| 285 | member.mode = permissions | ||
| 286 | return member | ||
| 287 | |||
| 270 | 288 | ||
| 271 | class TarGzParser(TarParser): | 289 | class TarGzParser(TarParser): |
| 272 | compression = ':gz' | 290 | compression = ':gz' |
