summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin David <valentin.david@codethink.co.uk>2018-11-13 21:24:20 +0100
committerValentin David <valentin.david@codethink.co.uk>2019-01-04 17:09:37 +0100
commit4bd6b9bb0a0f5af8893761e48d79f949cadf40fa (patch)
treeb92593b8cf9c48acdf434d599eb0f69c4d848533
parent96fc33105c3a14b24fcc4157ae576e21a9ea1070 (diff)
downloadbuildstream-valentindavid/link_files_sort_resolved.tar.gz
Fix issue with absolute symbolic links in copy_files/link_filesvalentindavid/link_files_sort_resolved
When paths given by caller for copy_files/link_files used absolute symbolic links, sorting the paths required to resolve links within the sysroot.
-rw-r--r--buildstream/utils.py46
-rw-r--r--tests/integration/compose-symlinks.py17
-rw-r--r--tests/integration/project/elements/compose-symlinks/a-foo-symlink.bst11
-rw-r--r--tests/integration/project/elements/compose-symlinks/compose-absolute-symlink.bst14
-rw-r--r--tests/integration/project/elements/compose-symlinks/foo-dir.bst11
-rw-r--r--tests/integration/project/elements/compose-symlinks/integration-move-dir.bst14
6 files changed, 111 insertions, 2 deletions
diff --git a/buildstream/utils.py b/buildstream/utils.py
index ae5da34d7..fc496154e 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 bf279fa6f..c72d81866 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 000000000..3beff338a
--- /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 000000000..7111cb4c7
--- /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 000000000..e9206cd32
--- /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 000000000..851f03fa9
--- /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