From 286a46e8b4b24042fa822c9a4dba6389361fd639 Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Thu, 26 May 2016 16:40:50 -0700 Subject: [PATCH] Python2.4's zipfile library cannot handle zip 64bit extensions which are needed for > 64K files (#3754) Fallback to unzip if zipfile fails and hope that unzip can deal with it (sites have an easier time upgrading the unzip utility than all of python). https://bugs.python.org/issue3997 Fixes #3560 --- lib/ansible/modules/files/unarchive.py | 64 ++++++++++++++++++++------ 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/lib/ansible/modules/files/unarchive.py b/lib/ansible/modules/files/unarchive.py index d2d7b97a52..9b7d3f85d4 100644 --- a/lib/ansible/modules/files/unarchive.py +++ b/lib/ansible/modules/files/unarchive.py @@ -123,7 +123,7 @@ import grp import datetime import time import binascii -from zipfile import ZipFile +from zipfile import ZipFile, BadZipfile import tarfile import subprocess @@ -174,17 +174,41 @@ class ZipArchive(object): # mode += 2**(9+j) return ( mode & ~umask ) + def _legacy_file_list(self, force_refresh=False): + unzip_bin = self.module.get_bin_path('unzip') + if not unzip_bin: + raise UnarchiveError('Python Zipfile cannot read %s and unzip not found' % self.src) + + rc, out, err = self.module.run_command([unzip_bin, '-v', self.src]) + if rc: + raise UnarchiveError('Neither python zipfile nor unzip can read %s' % self.src) + + for line in out.splitlines()[3:-2]: + fields = line.split(None, 7) + self._files_in_archive.append(fields[7]) + self._infodict[fields[7]] = long(fields[6]) + def _crc32(self, path): if self._infodict: return self._infodict[path] - archive = ZipFile(self.src) try: - for item in archive.infolist(): - self._infodict[item.filename] = long(item.CRC) - except: - archive.close() - raise UnarchiveError('Unable to list files in the archive') + archive = ZipFile(self.src) + except BadZipfile: + e = get_exception() + if e.args[0].lower().startswith('bad magic number'): + # Python2.4 can't handle zipfiles with > 64K files. Try using + # /usr/bin/unzip instead + self._legacy_file_list() + else: + raise + else: + try: + for item in archive.infolist(): + self._infodict[item.filename] = long(item.CRC) + except: + archive.close() + raise UnarchiveError('Unable to list files in the archive') return self._infodict[path] @@ -194,16 +218,26 @@ class ZipArchive(object): return self._files_in_archive self._files_in_archive = [] - archive = ZipFile(self.src) try: - for member in archive.namelist(): - if member not in self.excludes: - self._files_in_archive.append(member) - except: - archive.close() - raise UnarchiveError('Unable to list files in the archive') + archive = ZipFile(self.src) + except BadZipfile: + e = get_exception() + if e.args[0].lower().startswith('bad magic number'): + # Python2.4 can't handle zipfiles with > 64K files. Try using + # /usr/bin/unzip instead + self._legacy_file_list(force_refresh) + else: + raise + else: + try: + for member in archive.namelist(): + if member not in self.excludes: + self._files_in_archive.append(member) + except: + archive.close() + raise UnarchiveError('Unable to list files in the archive') - archive.close() + archive.close() return self._files_in_archive def is_unarchived(self):