From ae0e285185e79e45885ceda89bc5a4d758f2f75f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 16 Nov 2021 12:35:28 +0200 Subject: Ignore (with warning) directory symlink cycles in bootstrap dist --- libbuild2/dist/operation.cxx | 47 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) (limited to 'libbuild2') diff --git a/libbuild2/dist/operation.cxx b/libbuild2/dist/operation.cxx index 7a85119..a799cfc 100644 --- a/libbuild2/dist/operation.cxx +++ b/libbuild2/dist/operation.cxx @@ -105,13 +105,25 @@ namespace build2 // Recursively traverse an src_root subdirectory entering/collecting the // contained files and file symlinks as the file targets and skipping // entries that start with a dot. Follow directory symlinks (preserving - // their names) and fail on dangling symlinks. + // their names) and fail on dangling symlinks. Also detect directory + // symlink cycles. // + struct subdir + { + const subdir* prev; + const dir_path& dir; + }; + static void - add_subdir (const scope& rs, const dir_path& sd, action_targets& files) + add_subdir (const scope& rs, + const dir_path& sd, + action_targets& files, + const subdir* prev = nullptr) { dir_path d (rs.src_path () / sd); + const subdir next {prev, d}; + try { for (const dir_entry& e: dir_iterator (d, false /* ignore_dangling */)) @@ -122,7 +134,36 @@ namespace build2 try { if (e.type () == entry_type::directory) // Can throw. - add_subdir (rs, sd / path_cast (n), files); + { + // If this is a symlink, check that it doesn't cause a cycle. + // + if (e.ltype () == entry_type::symlink) + { + // Note that the resulting path will be absolute and + // normalized. + // + dir_path ld (d / path_cast (n)); + dir_path td (path_cast (followsymlink (ld))); + + const subdir* s (&next); + for (; s != nullptr; s = s->prev) + { + if (s->dir == td) + { + if (verb) + warn << "directory cycle caused by symlink " << ld << + info << "symlink target " << td; + + break; + } + } + + if (s != nullptr) + break; + } + + add_subdir (rs, sd / path_cast (n), files, &next); + } else files.push_back (add_target (rs, sd / n, true, true)); } -- cgit v1.1