Retaining permission of VNF package files

Python zipfile module changes permission of the zip file
contents to 644 incorrectly while extracting zip file.

This is because of the bug present in the python zipfile module:
https://bugs.python.org/issue15795

This patch will resolve this issue and retain the permission of
files.

Co-Authored-By: Shanu Pandit <shanu.pandit@india.nec.com>
Co-Authored-By: Sheel Rana <ranasheel2000@gmail.com>

Closes-Bug: #1923540
Change-Id: I71aad5f879e6df21f679187283957c59b73e0643
This commit is contained in:
Sheel Rana 2021-05-12 04:44:49 +09:00
parent a98cd4eaa9
commit 89b3b65c7c
2 changed files with 44 additions and 1 deletions

View File

@ -521,7 +521,7 @@ def _validate_hash(algorithm, hash_code, csar, artifact_path):
def extract_csar_zip_file(file_path, extract_path):
try:
with zipfile.ZipFile(file_path, 'r') as zf:
with PreserveZipFilePermissions(file_path, 'r') as zf:
zf.extractall(extract_path)
except (RuntimeError, zipfile.BadZipfile) as exp:
with excutils.save_and_reraise_exception():
@ -573,3 +573,25 @@ def delete_csar_data(package_uuid):
msg = _('Failed to delete csar folder: '
'%(csar_path)s, Error: %(exc)s')
LOG.warning(msg, {'csar_path': csar_path, 'exc': exc_message})
class PreserveZipFilePermissions(zipfile.ZipFile):
"""Patched _extract_member function of zipFile.
zipfile.ZipFile.extractall function internally calls
_extract_member function.
Here _extract_member function is patched to retain the
file permissions using member.external_attr >> 16.
Note: First 16 bits of external_attr store permission details.
"""
def _extract_member(self, member, targetpath, pwd):
if not isinstance(member, zipfile.ZipInfo):
member = self.getinfo(member)
targetpath = super()._extract_member(member, targetpath, pwd)
attr = member.external_attr >> 16
if attr != 0:
os.chmod(targetpath, attr)
return targetpath

View File

@ -464,3 +464,24 @@ class TestCSARUtils(testtools.TestCase):
self.assertEqual(flavours[0]['sw_images'][1]['min_disk'], 2000000000)
self.assertEqual(flavours[0]['sw_images'][1]['size'], 2000000000)
self.assertEqual(flavours[0]['sw_images'][1]['min_ram'], 8590458880)
def test_extract_csar_zip_file_for_file_permissions(self):
dir_location = tempfile.mkdtemp()
file_obj = tempfile.NamedTemporaryFile(dir=dir_location)
file_path = file_obj.name
file_name = file_path.split("/")[3]
os.chmod(file_path, 0o755)
self.addCleanup(shutil.rmtree, dir_location)
initial_cwd = os.getcwd()
os.chdir(dir_location)
zip_file_path = dir_location + '/' + "test_extract_csar_zip_file.zip"
with zipfile.ZipFile(zip_file_path, 'w') as zip:
zip.write(file_name)
self.assertEqual(True, os.path.exists(zip_file_path))
zip_extract_path = dir_location + "/zip_extract"
extract_file_path = zip_extract_path + "/" + file_name
os.chdir(initial_cwd)
csar_utils.extract_csar_zip_file(zip_file_path, zip_extract_path)
status = os.stat(extract_file_path)
permission = oct(status.st_mode)[-3:]
self.assertEqual('755', permission)