From 455323471868f653b0a305b9dc7d2a2dde2b9753 Mon Sep 17 00:00:00 2001 From: William Salmon Date: Thu, 30 May 2019 13:37:02 +0100 Subject: Fix descend can not follow symlinks --- src/buildstream/storage/_casbaseddirectory.py | 51 ++++++++++++++++++++++++-- src/buildstream/storage/_filebaseddirectory.py | 6 ++- src/buildstream/storage/directory.py | 2 +- 3 files changed, 53 insertions(+), 6 deletions(-) (limited to 'src/buildstream/storage') 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. -- cgit v1.2.1