You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by gi...@apache.org on 2020/12/29 13:24:49 UTC

[buildstream] 02/02: Fix issue with absolute symbolic links in copy_files/link_files

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

github-bot pushed a commit to branch valentindavid/link_files_sort_resolved
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 4bd6b9bb0a0f5af8893761e48d79f949cadf40fa
Author: Valentin David <va...@codethink.co.uk>
AuthorDate: Tue Nov 13 21:24:20 2018 +0100

    Fix issue with absolute symbolic links in copy_files/link_files
    
    When paths given by caller for copy_files/link_files used absolute
    symbolic links, sorting the paths required to resolve links within the
    sysroot.
---
 buildstream/utils.py                               | 46 +++++++++++++++++++++-
 tests/integration/compose-symlinks.py              | 17 ++++++++
 .../elements/compose-symlinks/a-foo-symlink.bst    | 11 ++++++
 .../compose-symlinks/compose-absolute-symlink.bst  | 14 +++++++
 .../project/elements/compose-symlinks/foo-dir.bst  | 11 ++++++
 .../compose-symlinks/integration-move-dir.bst      | 14 +++++++
 6 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/buildstream/utils.py b/buildstream/utils.py
index ae5da34..fc49615 100644
--- a/buildstream/utils.py
+++ b/buildstream/utils.py
@@ -787,6 +787,48 @@ def _ensure_real_directory(root, destpath):
     return destpath_resolved
 
 
+@functools.lru_cache(maxsize=1)
+def _symloop_max():
+    if hasattr(os, 'sysconf'):
+        try:
+            ret = os.sysconf('_SC_SYMLOOP_MAX')
+            if ret != -1:
+                return ret
+        except ValueError:
+            pass
+    return 8
+
+
+@functools.lru_cache(maxsize=64)
+def _sysroot_realpath(path, sysroot):
+    assert not os.path.isabs(path)
+    assert os.path.isabs(sysroot)
+
+    loop_count = _symloop_max()
+    while True:
+        full_path = os.path.join(sysroot, path)
+        st = os.lstat(full_path)
+        mode = st.st_mode
+        if not stat.S_ISLNK(mode):
+            break
+        loop_count = loop_count - 1
+        if loop_count < 0:
+            raise UtilError("Symlink loop detected: {}".format(os.path.join(sysroot, path)))
+        link_path = os.readlink(full_path)
+        if not os.path.isabs(link_path):
+            link_path = os.path.join('/', os.path.dirname(path), link_path)
+        path = os.path.relpath(os.path.normpath(link_path), '/')
+
+    parent = os.path.dirname(path)
+    if parent != '':
+        parent = _sysroot_realpath(parent, sysroot)
+        full_parent = os.path.join(sysroot, parent)
+        if not os.path.isdir(full_parent):
+            raise UtilError("Path is not a directory: {}".format(full_parent))
+
+    return os.path.join(parent, os.path.basename(path))
+
+
 # _process_list()
 #
 # Internal helper for copying/moving/linking file lists
@@ -817,10 +859,10 @@ def _process_list(srcdir, destdir, filelist, actionfunc, result,
     # those directories.
     if not presorted:
         resolved = []
+        _sysroot_realpath.cache_clear()
         for f in filelist:
             dirname = os.path.dirname(f)
-            dirname = os.path.realpath(os.path.join(srcdir, dirname))
-            dirname = os.path.relpath(dirname, srcdir)
+            dirname = _sysroot_realpath(dirname, srcdir)
             if dirname == '.':
                 resolved.append(os.path.basename(f))
             else:
diff --git a/tests/integration/compose-symlinks.py b/tests/integration/compose-symlinks.py
index bf279fa..c72d818 100644
--- a/tests/integration/compose-symlinks.py
+++ b/tests/integration/compose-symlinks.py
@@ -7,6 +7,7 @@ from buildstream import _yaml
 
 from tests.testutils import cli_integration as cli
 from tests.testutils.integration import walk_dir
+from tests.testutils.site import IS_LINUX, HAVE_BWRAP
 
 
 pytestmark = pytest.mark.integration
@@ -41,3 +42,19 @@ def test_compose_symlinks(cli, tmpdir, datafiles):
 
     assert set(walk_dir(checkout)) == set(['/sbin', '/usr', '/usr/sbin',
                                            '/usr/sbin/init', '/usr/sbin/dummy'])
+
+
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.skipif(not IS_LINUX or not HAVE_BWRAP, reason='Only available on linux with bubblewrap')
+def test_compose_absolute_symlinks(cli, tmpdir, datafiles):
+    project = str(datafiles)
+    checkout = os.path.join(cli.directory, 'checkout')
+    element_path = os.path.join(project, 'elements')
+
+    result = cli.run(project=project, args=['build', 'compose-symlinks/compose-absolute-symlink.bst'])
+    result.assert_success()
+
+    result = cli.run(project=project, args=['checkout', 'compose-symlinks/compose-absolute-symlink.bst', checkout])
+    result.assert_success()
+
+    assert os.readlink(os.path.join(checkout, 'foo')) == 'test/foo'
diff --git a/tests/integration/project/elements/compose-symlinks/a-foo-symlink.bst b/tests/integration/project/elements/compose-symlinks/a-foo-symlink.bst
new file mode 100644
index 0000000..3beff33
--- /dev/null
+++ b/tests/integration/project/elements/compose-symlinks/a-foo-symlink.bst
@@ -0,0 +1,11 @@
+kind: script
+
+depends:
+- filename: base.bst
+  type: build
+
+config:
+  commands:
+  - |
+    mkdir -p "%{install-root}/bar"
+    ln -s "/bar" "%{install-root}/foo"
diff --git a/tests/integration/project/elements/compose-symlinks/compose-absolute-symlink.bst b/tests/integration/project/elements/compose-symlinks/compose-absolute-symlink.bst
new file mode 100644
index 0000000..7111cb4
--- /dev/null
+++ b/tests/integration/project/elements/compose-symlinks/compose-absolute-symlink.bst
@@ -0,0 +1,14 @@
+kind: compose
+
+depends:
+- filename: compose-symlinks/foo-dir.bst
+  type: build
+- filename: compose-symlinks/a-foo-symlink.bst
+  type: build
+- filename: compose-symlinks/integration-move-dir.bst
+  type: build
+
+config:
+  include-orphans: true
+  exclude:
+    - dummy
diff --git a/tests/integration/project/elements/compose-symlinks/foo-dir.bst b/tests/integration/project/elements/compose-symlinks/foo-dir.bst
new file mode 100644
index 0000000..e9206cd
--- /dev/null
+++ b/tests/integration/project/elements/compose-symlinks/foo-dir.bst
@@ -0,0 +1,11 @@
+kind: script
+
+depends:
+- filename: base.bst
+  type: build
+
+config:
+  commands:
+  - |
+    mkdir -p "%{install-root}/foo"
+    echo test >"%{install-root}/foo/foo.txt"
diff --git a/tests/integration/project/elements/compose-symlinks/integration-move-dir.bst b/tests/integration/project/elements/compose-symlinks/integration-move-dir.bst
new file mode 100644
index 0000000..851f03f
--- /dev/null
+++ b/tests/integration/project/elements/compose-symlinks/integration-move-dir.bst
@@ -0,0 +1,14 @@
+kind: stack
+
+depends:
+- filename: base.bst
+
+public:
+  bst:
+    integration-commands:
+    - |
+      mkdir test
+      mv foo test/
+      mv bar test/
+      ln -s /test/foo /foo
+      ln -s /test/bar /bar