summaryrefslogtreecommitdiff
path: root/src/buildstream/storage
diff options
context:
space:
mode:
authorWilliam Salmon <will.salmon@codethink.co.uk>2019-05-30 13:37:02 +0100
committerWilliam Salmon <will.salmon@codethink.co.uk>2019-07-25 13:57:18 +0100
commit455323471868f653b0a305b9dc7d2a2dde2b9753 (patch)
tree5cb88185c362f183714a83e60de87020d1ab41b4 /src/buildstream/storage
parent43505dfd6da8b6eb3f4d4e544f3cdc0e2a31a947 (diff)
downloadbuildstream-455323471868f653b0a305b9dc7d2a2dde2b9753.tar.gz
Fix descend can not follow symlinks
Diffstat (limited to 'src/buildstream/storage')
-rw-r--r--src/buildstream/storage/_casbaseddirectory.py51
-rw-r--r--src/buildstream/storage/_filebaseddirectory.py6
-rw-r--r--src/buildstream/storage/directory.py2
3 files changed, 53 insertions, 6 deletions
diff --git a/src/buildstream/storage/_casbaseddirectory.py b/src/buildstream/storage/_casbaseddirectory.py
index 7bd9ceea0..424b7ef63 100644
--- a/src/buildstream/storage/_casbaseddirectory.py
+++ b/src/buildstream/storage/_casbaseddirectory.py
@@ -159,7 +159,15 @@ class CasBasedDirectory(Directory):
self.__invalidate_digest()
- def descend(self, *paths, create=False):
+ def find_root(self):
+ """ Finds the root of this directory tree by following 'parent' until there is
+ no parent. """
+ if self.parent:
+ return self.parent.find_root()
+ else:
+ return self
+
+ def descend(self, *paths, create=False, follow_symlinks=False):
"""Descend one or more levels of directory hierarchy and return a new
Directory object for that directory.
@@ -177,6 +185,7 @@ class CasBasedDirectory(Directory):
"""
current_dir = self
+ paths = list(paths)
for path in paths:
# Skip empty path segments
@@ -184,20 +193,37 @@ class CasBasedDirectory(Directory):
continue
entry = current_dir.index.get(path)
+
if entry:
if entry.type == _FileType.DIRECTORY:
current_dir = entry.get_directory(current_dir)
+ elif follow_symlinks and entry.type == _FileType.SYMLINK:
+ linklocation = entry.target
+ newpaths = linklocation.split(os.path.sep)
+ if os.path.isabs(linklocation):
+ current_dir = current_dir.find_root().descend(*newpaths, follow_symlinks=True)
+ else:
+ current_dir = current_dir.descend(*newpaths, follow_symlinks=True)
else:
error = "Cannot descend into {}, which is a '{}' in the directory {}"
raise VirtualDirectoryError(error.format(path,
current_dir.index[path].type,
- current_dir))
+ current_dir),
+ reason="not-a-directory")
else:
- if create:
+ if path == '.':
+ continue
+ elif path == '..':
+ if current_dir.parent is not None:
+ current_dir = current_dir.parent
+ # In POSIX /.. == / so just stay at the root dir
+ continue
+ elif create:
current_dir = current_dir._add_directory(path)
else:
error = "'{}' not found in {}"
- raise VirtualDirectoryError(error.format(path, str(current_dir)))
+ raise VirtualDirectoryError(error.format(path, str(current_dir)),
+ reason="directory-not-found")
return current_dir
@@ -618,6 +644,23 @@ class CasBasedDirectory(Directory):
return self.__digest
+ def _exists(self, *path, follow_symlinks=False):
+ try:
+ subdir = self.descend(*path[:-1], follow_symlinks=follow_symlinks)
+ target = subdir.index.get(path[-1])
+ if target is not None:
+ if target.type == _FileType.REGULAR_FILE:
+ return True
+ elif follow_symlinks and target.type == _FileType.SYMLINK:
+ linklocation = target.target
+ newpath = linklocation.split(os.path.sep)
+ if os.path.isabs(linklocation):
+ return subdir.find_root()._exists(*newpath, follow_symlinks=True)
+ return subdir._exists(*newpath, follow_symlinks=True)
+ return False
+ except VirtualDirectoryError:
+ return False
+
def __invalidate_digest(self):
if self.__digest:
self.__digest = None
diff --git a/src/buildstream/storage/_filebaseddirectory.py b/src/buildstream/storage/_filebaseddirectory.py
index 8c55819c9..a083f6507 100644
--- a/src/buildstream/storage/_filebaseddirectory.py
+++ b/src/buildstream/storage/_filebaseddirectory.py
@@ -37,6 +37,7 @@ from .. import utils
from ..utils import link_files, copy_files, list_relative_paths, _get_link_mtime, BST_ARBITRARY_TIMESTAMP
from ..utils import _set_deterministic_user, _set_deterministic_mtime
from ..utils import FileListResult
+from .._exceptions import ImplError
# FileBasedDirectory intentionally doesn't call its superclass constuctor,
# which is meant to be unimplemented.
@@ -47,9 +48,12 @@ class FileBasedDirectory(Directory):
def __init__(self, external_directory=None):
self.external_directory = external_directory
- def descend(self, *paths, create=False):
+ def descend(self, *paths, create=False, follow_symlinks=False):
""" See superclass Directory for arguments """
+ if follow_symlinks:
+ ImplError("FileBasedDirectory.Decend dose not implement follow_symlinks=True")
+
current_dir = self
for path in paths:
diff --git a/src/buildstream/storage/directory.py b/src/buildstream/storage/directory.py
index c9906b058..d32ac0063 100644
--- a/src/buildstream/storage/directory.py
+++ b/src/buildstream/storage/directory.py
@@ -52,7 +52,7 @@ class Directory():
def __init__(self, external_directory=None):
raise NotImplementedError()
- def descend(self, *paths, create=False):
+ def descend(self, *paths, create=False, follow_symlinks=False):
"""Descend one or more levels of directory hierarchy and return a new
Directory object for that directory.