summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin David <valentin.david@codethink.co.uk>2018-08-07 16:22:26 +0200
committerTristan Van Berkom <tristan.van.berkom@gmail.com>2018-08-12 05:57:44 +0000
commite8a3297b3d0d0652a91ee84b335e8d41545dbb7b (patch)
treeec97178d41951def68d0c21a4daaebd4f2a0d3b9
parent465909ddc6d39822f7669d554f3033e497b6f762 (diff)
downloadbuildstream-e8a3297b3d0d0652a91ee84b335e8d41545dbb7b.tar.gz
buildstream/plugins/sources/zip.py: Fix non-determism in staging.
Staging could end-up with file with different rights depending on the umask. The extracted files need to get their access rights fixed.
-rw-r--r--buildstream/plugins/sources/zip.py32
1 files changed, 30 insertions, 2 deletions
diff --git a/buildstream/plugins/sources/zip.py b/buildstream/plugins/sources/zip.py
index 9b47d7f78..d3ce0f16d 100644
--- a/buildstream/plugins/sources/zip.py
+++ b/buildstream/plugins/sources/zip.py
@@ -49,10 +49,17 @@ zip - stage files from zip archives
# To extract the root of the archive directly, this can be set
# to an empty string.
base-dir: '*'
+
+.. attention::
+
+ File permissions are not preserved. All extracted directories have
+ permissions 0755 and all extracted files have permissions 0644.
+
"""
import os
import zipfile
+import stat
from buildstream import SourceError
from buildstream import utils
@@ -74,6 +81,9 @@ class ZipSource(DownloadableFileSource):
return super().get_unique_key() + [self.base_dir]
def stage(self, directory):
+ exec_rights = (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) & ~(stat.S_IWGRP | stat.S_IWOTH)
+ noexec_rights = exec_rights & ~(stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+
try:
with zipfile.ZipFile(self._get_mirror_file()) as archive:
base_dir = None
@@ -81,9 +91,27 @@ class ZipSource(DownloadableFileSource):
base_dir = self._find_base_dir(archive, self.base_dir)
if base_dir:
- archive.extractall(path=directory, members=self._extract_members(archive, base_dir))
+ members = self._extract_members(archive, base_dir)
else:
- archive.extractall(path=directory)
+ members = archive.namelist()
+
+ for member in members:
+ written = archive.extract(member, path=directory)
+
+ # zipfile.extract might create missing directories
+ rel = os.path.relpath(written, start=directory)
+ assert not os.path.isabs(rel)
+ rel = os.path.dirname(rel)
+ while rel:
+ os.chmod(os.path.join(directory, rel), exec_rights)
+ rel = os.path.dirname(rel)
+
+ if os.path.islink(written):
+ pass
+ elif os.path.isdir(written):
+ os.chmod(written, exec_rights)
+ else:
+ os.chmod(written, noexec_rights)
except (zipfile.BadZipFile, zipfile.LargeZipFile, OSError) as e:
raise SourceError("{}: Error staging source: {}".format(self, e)) from e