From 34466f10506fd57836e89cffda7738c3008321b1 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sun, 15 Mar 2020 17:03:49 +0300 Subject: Fix mkanylink() to complete relative target against link directory when create hardlink or copy --- libbutl/builtin.cxx | 4 ++-- libbutl/command.cxx | 2 +- libbutl/command.mxx | 2 +- libbutl/filesystem.cxx | 20 ++++++++++++++++---- libbutl/filesystem.mxx | 4 +++- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/libbutl/builtin.cxx b/libbutl/builtin.cxx index f1b6b63..9efa697 100644 --- a/libbutl/builtin.cxx +++ b/libbutl/builtin.cxx @@ -277,7 +277,7 @@ namespace butl } // Return the current working directory if wd is empty and wd otherwise, - // completed against the current directory if it is relative. Fail if + // completed using the current directory if it is relative. Fail if // std::system_error is thrown by the underlying function call. // dir_path @@ -779,7 +779,7 @@ namespace butl assert (link.absolute () && link.normalized ()); // Determine the target type, fail if the target doesn't exist. Note that - // to do that we need to complete a relative target path against the link + // to do that we need to complete a relative target path using the link // directory making the target path absolute. // const path& atp (target.relative () diff --git a/libbutl/command.cxx b/libbutl/command.cxx index 8dcfd05..bb5287c 100644 --- a/libbutl/command.cxx +++ b/libbutl/command.cxx @@ -137,7 +137,7 @@ namespace butl // Sort the remaining command line elements into the arguments and // redirects, performing the substitutions. Complete relative redirects - // against CWD and use the rightmost redirect. + // using CWD and use the rightmost redirect. // vector args; diff --git a/libbutl/command.mxx b/libbutl/command.mxx index b215817..02c8eb8 100644 --- a/libbutl/command.mxx +++ b/libbutl/command.mxx @@ -55,7 +55,7 @@ LIBBUTL_MODEXPORT namespace butl // possible substitutions (so the redirect character cannot be the result of // a substitution; see below). // - // The relative redirect file paths are completed against the command + // The relative redirect file paths are completed using the command // current working directory. Note that if it is altered via the process // environment, then the new value is used. // diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx index fa36ed3..4698ed9 100644 --- a/libbutl/filesystem.cxx +++ b/libbutl/filesystem.cxx @@ -1453,9 +1453,11 @@ namespace butl { using error = pair; + const path& tp (rel ? target.relative (link.directory ()) : target); + try { - mksymlink (rel ? target.relative (link.directory ()) : target, link); + mksymlink (tp, link); return entry_type::symlink; } catch (system_error& e) @@ -1469,9 +1471,19 @@ namespace butl if (c == ENOSYS || // Not implemented. c == EPERM) // Not supported by the filesystem(s). { + // Note that for hardlinking/copying we need to complete a relative + // target using the link directory. + // + const path& ctp (tp.relative () ? link.directory () / tp : tp); + try { - mkhardlink (target, link); + // The target can be a symlink (or a symlink chain) with a + // relative target that, unless the (final) symlink and the + // hardlink are in the same directory, will result in a dangling + // link. + // + mkhardlink (followsymlink (ctp), link); return entry_type::other; } catch (system_error& e) @@ -1485,7 +1497,7 @@ namespace butl { try { - cpfile (target, link); + cpfile (ctp, link); return entry_type::regular; } catch (system_error& e) @@ -2416,7 +2428,7 @@ namespace butl recursive_dir_iterator (recursive_dir_iterator&&) = default; // Return false if no more entries left. Otherwise save the next entry path - // and return true. The path is relative against the directory being + // and return true. The path is relative to the directory being // traversed and contains a trailing separator for sub-directories. Throw // std::system_error in case of a failure (insufficient permissions, // dangling symlink encountered, etc). diff --git a/libbutl/filesystem.mxx b/libbutl/filesystem.mxx index a445b70..94ed366 100644 --- a/libbutl/filesystem.mxx +++ b/libbutl/filesystem.mxx @@ -362,7 +362,9 @@ LIBBUTL_MODEXPORT namespace butl // no directories, only files), whichever is possible in that order. If // `relative` is true, then make the symlink target relative to the link // directory (note: it is the caller's responsibility to make sure this is - // possible). + // possible). Otherwise, assume a relative target to be relative to the + // link directory and complete it accordingly when create a hardlink or a + // copy. // // On success, return the type of entry created: `regular` for copy, // `symlink` for symlink, and `other` for hardlink. On failure, throw a -- cgit v1.1