diff options
Diffstat (limited to 'libbutl')
-rw-r--r-- | libbutl/buildfile | 2 | ||||
-rw-r--r-- | libbutl/builtin.cxx | 2 | ||||
-rw-r--r-- | libbutl/fdstream.cxx | 8 | ||||
-rw-r--r-- | libbutl/path.cxx | 27 | ||||
-rw-r--r-- | libbutl/path.hxx | 49 | ||||
-rw-r--r-- | libbutl/process.cxx | 20 | ||||
-rw-r--r-- | libbutl/utility.hxx | 2 |
7 files changed, 93 insertions, 17 deletions
diff --git a/libbutl/buildfile b/libbutl/buildfile index ba4ad96..bbecf43 100644 --- a/libbutl/buildfile +++ b/libbutl/buildfile @@ -76,7 +76,7 @@ switch $tclass, $tsys } if! $windows - cxx.libs += -lpthread + cxx.libs += -pthread # Include the generated version header into the distribution (so that we don't # pick up an installed one) and don't remove it when cleaning in src (so that diff --git a/libbutl/builtin.cxx b/libbutl/builtin.cxx index 2755bf1..a5861d4 100644 --- a/libbutl/builtin.cxx +++ b/libbutl/builtin.cxx @@ -243,7 +243,7 @@ namespace butl // completed using the current directory if it is relative. Fail if // std::system_error is thrown by the underlying function call. // - dir_path + static dir_path current_directory (const dir_path& wd, const function<error_record ()>& fail) { try diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index 07cb9f2..df5b531 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -1889,7 +1889,13 @@ namespace butl throw_system_ios_failure (e); if (t == FILE_TYPE_CHAR) // Terminal. - return true; + { + // One notable special file that has this type is nul (as returned by + // fdopen_null()). So tighten this case with the GetConsoleMode() call. + // + DWORD m; + return GetConsoleMode (h, &m) != 0; + } if (t != FILE_TYPE_PIPE) // Pipe still can be a terminal (see below). return false; diff --git a/libbutl/path.cxx b/libbutl/path.cxx index bd66f13..909971b 100644 --- a/libbutl/path.cxx +++ b/libbutl/path.cxx @@ -26,6 +26,8 @@ #include <atomic> #include <cstring> // strcpy() +#include <libbutl/ft/lang.hxx> // thread_local + #include <libbutl/utility.hxx> // throw_*_error() #include <libbutl/process.hxx> // process::current_id() @@ -55,10 +57,21 @@ namespace butl // char // + static +#ifdef __cpp_thread_local + thread_local +#else + __thread +#endif + const path_traits<char>::string_type* current_directory_ = nullptr; + template <> LIBBUTL_SYMEXPORT path_traits<char>::string_type path_traits<char>:: current_directory () { + if (const auto* twd = current_directory_) + return *twd; + #ifdef _WIN32 char cwd[_MAX_PATH]; if (_getcwd (cwd, _MAX_PATH) == 0) @@ -98,6 +111,20 @@ namespace butl #endif } + template <> + LIBBUTL_SYMEXPORT const path_traits<char>::string_type* path_traits<char>:: + thread_current_directory () + { + return current_directory_; + } + + template <> + LIBBUTL_SYMEXPORT void path_traits<char>:: + thread_current_directory (const string_type* twd) + { + current_directory_ = twd; + } + #ifndef _WIN32 static const small_vector<string, 4> tmp_vars ( {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}); diff --git a/libbutl/path.hxx b/libbutl/path.hxx index b10022a..7d8b862 100644 --- a/libbutl/path.hxx +++ b/libbutl/path.hxx @@ -451,11 +451,31 @@ namespace butl // Get/set current working directory. Throw std::system_error to report // underlying OS errors. // + // The curren_directory() accessor (as well as the relevant process + // startup functions) have a notion of a "thread working directory" which + // is implemented as a thread-specific override that can be added/removed + // with thread_current_directory() below. + // + // Note that the current_directory() modifier always sets the process-wide + // working directory. + // + // See also thread_env(). + // static string_type current_directory (); static void - current_directory (string_type const&); + current_directory (const string_type&); + + // Get/set thread working directory override. Note that the passed + // pointed-to string should be valid (and immutable) for as long as the + // override is in effect. + // + static const string_type* + thread_current_directory (); + + static void + thread_current_directory (const string_type*); // Return the user home directory. Throw std::system_error to report // underlying OS errors. @@ -890,7 +910,7 @@ namespace butl make_leaf (); // Return the path without the specified directory part. Returns empty - // path if the paths are the same. Throws invalid_path if the directory is + // path if the paths are the same. Throw invalid_path if the directory is // not a prefix of *this. Expects both paths to be normalized. // basic_path @@ -908,7 +928,7 @@ namespace butl make_directory (); // Return the directory part of the path without the specified leaf part. - // Throws invalid_path if the leaf is not a suffix of *this. Expects both + // Throw invalid_path if the leaf is not a suffix of *this. Expects both // paths to be normalized. // dir_type @@ -944,7 +964,7 @@ namespace butl extension_cstring () const; // Return a path relative to the specified path that is equivalent - // to *this. Throws invalid_path if a relative path cannot be derived + // to *this. Throw invalid_path if a relative path cannot be derived // (e.g., paths are on different drives on Windows). // basic_path @@ -1112,19 +1132,22 @@ namespace butl basic_path& canonicalize (char dir_sep = '\0'); - // Normalize the path and return *this. Normalization involves collapsing - // the '.' and '..' directories if possible, collapsing multiple - // directory separators, and converting all directory separators to the - // canonical form. If cur_empty is true then collapse relative paths - // representing the current directory (for example, '.', './', 'foo/..') - // to an empty path. Otherwise convert it to the canonical form (./ on - // POSIX systems). Note that a non-empty path cannot become an empty one - // in the latter case. + // Normalize the path and return *this. Throw invalid_path if the + // resulting path would be invalid (e.g., /tmp/../..). + // + // Normalization involves collapsing the '.' and '..' directories if + // possible, collapsing multiple directory separators, and converting all + // directory separators to the canonical form. If cur_empty is true then + // collapse relative paths representing the current directory (for + // example, '.', './', 'foo/..') to an empty path. Otherwise convert it + // to the canonical form (./ on POSIX systems). Note that a non-empty path + // cannot become an empty one in the latter case. // // If actual is true, then for case-insensitive filesystems obtain the // actual spelling of the path. Only an absolute path can be actualized. // If a path component does not exist, then its (and all subsequent) - // spelling is unchanged. This is a potentially expensive operation. + // spelling is unchanged. Throw system_error on all other underlying + // filesystem errors. Note that this is a potentially expensive operation. // Normally one can assume that "well-known" directories (current, home, // etc.) are returned in their actual spelling. // diff --git a/libbutl/process.cxx b/libbutl/process.cxx index e416807..1b8da98 100644 --- a/libbutl/process.cxx +++ b/libbutl/process.cxx @@ -262,7 +262,7 @@ namespace butl { // Note that there is a similar version for Win32. - typedef path::traits_type traits; + using traits = path::traits_type; size_t fn (strlen (f)); @@ -454,6 +454,15 @@ namespace butl else if (err == -2) in_efd.out = open_null (); + // If there is no user-supplied CWD and we have thread-specific override, + // use that instead of defaulting to the process-wide value. + // + if (cwd == nullptr || *cwd == '\0') + { + if (const string* twd = path::traits_type::thread_current_directory ()) + cwd = twd->c_str (); + } + const char* const* tevars (thread_env ()); // The posix_spawn()-based implementation. @@ -1392,6 +1401,15 @@ namespace butl throw process_error (m == nullptr ? last_error_msg () : m); }; + // If there is no user-supplied CWD and we have thread-specific override, + // use that instead of defaulting to the process-wide value. + // + if (cwd == nullptr || *cwd == '\0') + { + if (const string* twd = path::traits_type::thread_current_directory ()) + cwd = twd->c_str (); + } + // (Un)set the environment variables for the child process. // // Note that we can not do it incrementally, as for POSIX implementation. diff --git a/libbutl/utility.hxx b/libbutl/utility.hxx index 779a0aa..9eb052d 100644 --- a/libbutl/utility.hxx +++ b/libbutl/utility.hxx @@ -301,6 +301,8 @@ namespace butl // of overrides over the process environment (sets and unsets), the same as // for the process startup. // + // See also path_traits::thread_current_directory(). + // extern #ifdef __cpp_thread_local thread_local |