From 5e274066e3ec199dd56d81f43db6ea276b6da019 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 17 Oct 2019 21:15:43 +0200 Subject: [PATCH] Always return absolute path in path_get_cdpath Fixes #6220 --- CHANGELOG.md | 1 + src/path.cpp | 11 ++++++----- src/path.h | 3 +-- tests/checks/cd.fish | 13 +++++++++++++ 4 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 tests/checks/cd.fish diff --git a/CHANGELOG.md b/CHANGELOG.md index 18a38f334..59403745c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - The null command (`:`) now always exits successfully, rather than passing through the previous exit status (#6022). - `jobs --last` returns 0 to indicate success when a job is found (#6104). - `commandline -p` and `commandline -j` now split on `&&` and `||` in addition to `;` and `&` (#6214) +- `fish` now correctly handles CDPATH entries that starts with `..` (#6220) ### Syntax changes and new commands - Brace expansion now only takes place if the braces include a "," or a variable expansion, meaning common commands such as `git reset HEAD@{0}` do not require escaping (#5869). diff --git a/src/path.cpp b/src/path.cpp index 802fccf80..2532b13f6 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -161,8 +161,7 @@ maybe_t path_get_cdpath(const wcstring &dir, const wcstring &wd, const environment_t &env_vars) { int err = ENOENT; if (dir.empty()) return none(); - - assert(wd.empty() || wd.back() == L'/'); + assert(!wd.empty() && wd.back() == L'/'); wcstring_list_t paths; if (dir.at(0) == L'/') { // Absolute path. @@ -181,14 +180,16 @@ maybe_t path_get_cdpath(const wcstring &dir, const wcstring &wd, cdpathsv.push_back(L"."); for (wcstring next_path : cdpathsv) { if (next_path.empty()) next_path = L"."; - if (next_path == L"." && !wd.empty()) { + if (next_path == L".") { // next_path is just '.', and we have a working directory, so use the wd instead. next_path = wd; } - // If next_path starts with ./ we need to replace the . with the wd. - if (string_prefixes_string(L"./", next_path) && !wd.empty()) { + // We want to return an absolute path (see issue 6220) + if (string_prefixes_string(L"./", next_path)) { next_path = next_path.replace(0, 2, wd); + } else if (string_prefixes_string(L"../", next_path) || next_path == L"..") { + next_path = next_path.insert(0, wd); } expand_tilde(next_path, env_vars); diff --git a/src/path.h b/src/path.h index a6074df48..cc62576a0 100644 --- a/src/path.h +++ b/src/path.h @@ -58,8 +58,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars); /// are found, it is undefined which error status will be returned. /// /// \param dir The name of the directory. -/// \param out_or_NULL If non-NULL, return the path to the resolved directory -/// \param wd The working directory. The working directory should have a slash appended at the end. +/// \param wd The working directory. The working directory must end with a slash. /// \param vars The environment variables to use (for the CDPATH variable) /// \return the command, or none() if it could not be found. maybe_t path_get_cdpath(const wcstring &dir, const wcstring &wd, diff --git a/tests/checks/cd.fish b/tests/checks/cd.fish new file mode 100644 index 000000000..7be303541 --- /dev/null +++ b/tests/checks/cd.fish @@ -0,0 +1,13 @@ +# RUN: %fish %s +set -l tmp (mktemp -d) +cd $tmp +# resolve CDPATH (issue 6220) +begin + mkdir -p x + # CHECK: /{{.*}}/x + cd x; pwd + + # CHECK: /{{.*}}/x + set -lx CDPATH ..; cd x; pwd +end +rm -rf $tmp