This is an automated email from the ASF dual-hosted git repository.

not-in-ldap pushed a commit to branch valentindavid/local-cache-exec-leak-2
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 5f50d3bde19b43852eba724e72e4c581a0e85e9a
Author: Valentin David <[email protected]>
AuthorDate: Mon Feb 11 18:51:20 2019 +0100

    buildstream/_cas/cascache.py: Set 0644 rights to pulled files
    
    This was broken by 5ef19a0b31df84caed1e41719ef7ea5c6bd8a8bc.
---
 buildstream/_cas/cascache.py | 21 ++++++++++---
 tests/frontend/pull.py       | 72 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/buildstream/_cas/cascache.py b/buildstream/_cas/cascache.py
index 5a62518..7c7af40 100644
--- a/buildstream/_cas/cascache.py
+++ b/buildstream/_cas/cascache.py
@@ -374,9 +374,7 @@ class CASCache():
                     for chunk in iter(lambda: tmp.read(4096), b""):
                         h.update(chunk)
                 else:
-                    tmp = 
stack.enter_context(utils._tempnamedfile(dir=self.tmpdir))
-                    # Set mode bits to 0644
-                    os.chmod(tmp.name, stat.S_IRUSR | stat.S_IWUSR | 
stat.S_IRGRP | stat.S_IROTH)
+                    tmp = stack.enter_context(self._temporary_object())
 
                     if path:
                         with open(path, 'rb') as f:
@@ -825,6 +823,19 @@ class CASCache():
         for dirnode in directory.directories:
             yield from self._required_blobs(dirnode.digest)
 
+    # _temporary_object():
+    #
+    # Returns:
+    #     (file): A file object to a named temporary file.
+    #
+    # Create a named temporary file with 0o0644 access rights.
+    @contextlib.contextmanager
+    def _temporary_object(self):
+        with utils._tempnamedfile(dir=self.tmpdir) as f:
+            os.chmod(f.name,
+                     stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
+            yield f
+
     # _ensure_blob():
     #
     # Fetch and add blob if it's not already local.
@@ -842,7 +853,7 @@ class CASCache():
             # already in local repository
             return objpath
 
-        with utils._tempnamedfile(dir=self.tmpdir) as f:
+        with self._temporary_object() as f:
             remote._fetch_blob(digest, f)
 
             added_digest = self.add_object(path=f.name, link_directly=True)
@@ -852,7 +863,7 @@ class CASCache():
 
     def _batch_download_complete(self, batch):
         for digest, data in batch.send():
-            with utils._tempnamedfile(dir=self.tmpdir) as f:
+            with self._temporary_object() as f:
                 f.write(data)
                 f.flush()
 
diff --git a/tests/frontend/pull.py b/tests/frontend/pull.py
index 9579d9f..2555355 100644
--- a/tests/frontend/pull.py
+++ b/tests/frontend/pull.py
@@ -1,5 +1,6 @@
 import os
 import shutil
+import stat
 import pytest
 from buildstream.plugintestutils import cli
 from tests.testutils import create_artifact_share, generate_junction
@@ -462,3 +463,74 @@ def test_build_remote_option(caplog, cli, tmpdir, 
datafiles):
         assert shareproject.repo not in result.stderr
         assert shareuser.repo not in result.stderr
         assert sharecli.repo in result.stderr
+
+
[email protected](DATA_DIR)
+def test_pull_access_rights(caplog, cli, tmpdir, datafiles):
+    project = str(datafiles)
+    checkout = os.path.join(str(tmpdir), 'checkout')
+
+    # Work-around datafiles not preserving mode
+    os.chmod(os.path.join(project, 'files/bin-files/usr/bin/hello'), 0o0755)
+
+    # We need a big file that does not go into a batch to test a different
+    # code path
+    os.makedirs(os.path.join(project, 'files/dev-files/usr/share'), 
exist_ok=True)
+    with open(os.path.join(project, 'files/dev-files/usr/share/big-file'), 
'w') as f:
+        buf = ' ' * 4096
+        for _ in range(1024):
+            f.write(buf)
+
+    with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare')) as 
share:
+
+        cli.configure({
+            'artifacts': {'url': share.repo, 'push': True}
+        })
+        result = cli.run(project=project, args=['build', 'compose-all.bst'])
+        result.assert_success()
+
+        result = cli.run(project=project,
+                         args=['artifact', 'checkout',
+                               '--hardlinks', '--no-integrate',
+                               'compose-all.bst',
+                               '--directory', checkout])
+        result.assert_success()
+
+        st = os.lstat(os.path.join(checkout, 'usr/include/pony.h'))
+        assert stat.S_ISREG(st.st_mode)
+        assert stat.S_IMODE(st.st_mode) == 0o0644
+
+        st = os.lstat(os.path.join(checkout, 'usr/bin/hello'))
+        assert stat.S_ISREG(st.st_mode)
+        assert stat.S_IMODE(st.st_mode) == 0o0755
+
+        st = os.lstat(os.path.join(checkout, 'usr/share/big-file'))
+        assert stat.S_ISREG(st.st_mode)
+        assert stat.S_IMODE(st.st_mode) == 0o0644
+
+        shutil.rmtree(checkout)
+
+        artifacts = os.path.join(cli.directory, 'artifacts')
+        shutil.rmtree(artifacts)
+
+        result = cli.run(project=project, args=['artifact', 'pull', 
'compose-all.bst'])
+        result.assert_success()
+
+        result = cli.run(project=project,
+                         args=['artifact', 'checkout',
+                               '--hardlinks', '--no-integrate',
+                               'compose-all.bst',
+                               '--directory', checkout])
+        result.assert_success()
+
+        st = os.lstat(os.path.join(checkout, 'usr/include/pony.h'))
+        assert stat.S_ISREG(st.st_mode)
+        assert stat.S_IMODE(st.st_mode) == 0o0644
+
+        st = os.lstat(os.path.join(checkout, 'usr/bin/hello'))
+        assert stat.S_ISREG(st.st_mode)
+        assert stat.S_IMODE(st.st_mode) == 0o0755
+
+        st = os.lstat(os.path.join(checkout, 'usr/share/big-file'))
+        assert stat.S_ISREG(st.st_mode)
+        assert stat.S_IMODE(st.st_mode) == 0o0644

Reply via email to