diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-02-12 09:08:32 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-02-12 09:08:32 +0200 |
commit | e4a63cd55c6347dd24938ec8a1ef203409be058e (patch) | |
tree | 56d41e47355067685fa9590b8f3d6fac18d05af6 | |
parent | d2c8cfc1f02b40d3fef5414e5830dd6f1fc20fe9 (diff) |
Add path::realize(), which on POSIX calls realpath(3)
-rw-r--r-- | butl/path | 80 | ||||
-rw-r--r-- | butl/path.cxx | 37 | ||||
-rw-r--r-- | butl/path.ixx | 13 |
3 files changed, 94 insertions, 36 deletions
@@ -14,6 +14,33 @@ namespace butl { + class invalid_path_base: std::exception + { + public: + virtual char const* + what () const throw (); + }; + + template <typename C> + class invalid_basic_path: public invalid_path_base + { + public: + typedef std::basic_string<C> string_type; + + invalid_basic_path (C const* p): path_ (p) {} + invalid_basic_path (string_type const& p): path_ (p) {} + ~invalid_basic_path () throw () {} + + string_type const& + path () const + { + return path_; + } + + private: + string_type path_; + }; + template <typename C> struct path_traits { @@ -123,8 +150,8 @@ namespace butl return ln < rn ? -1 : (ln > rn ? 1 : 0); } - // Get/set current working directory. Throw std::system_error - // to report the underlying OS errors. + // Get/set current working directory. Throw std::system_error to report + // the underlying OS errors. // static string_type current (); @@ -132,6 +159,15 @@ namespace butl static void current (string_type const&); + // Make the path real (by calling realpath(3)). Throw invalid_basic_path + // if the path is invalid (e.g., some components do not exist) and + // std::system_error to report other underlying OS errors. + // +#ifndef _WIN32 + static void + realize (string_type&); +#endif + private: #ifdef _WIN32 static C @@ -179,35 +215,6 @@ namespace butl typedef basic_path<wchar_t, dir_path_kind<wchar_t>> dir_wpath; typedef invalid_basic_path<wchar_t> invalid_wpath; - // - // - class invalid_path_base: std::exception - { - public: - virtual char const* - what () const throw (); - }; - - template <typename C> - class invalid_basic_path: public invalid_path_base - { - public: - typedef std::basic_string<C> string_type; - - invalid_basic_path (C const* p): path_ (p) {} - invalid_basic_path (string_type const& p): path_ (p) {} - ~invalid_basic_path () throw () {} - - string_type const& - path () const - { - return path_; - } - - private: - string_type path_; - }; - template <typename C> class path_data { @@ -477,17 +484,24 @@ namespace butl // Normalize the path. This includes collapsing the '.' and '..' // directories if possible, collapsing multiple directory // separators, and converting all directory separators to the - // canonical form. Returns *this. + // canonical form. Return *this. // basic_path& normalize (); // Make the path absolute using the current directory unless - // it is already absolute. + // it is already absolute. Return *this. // basic_path& complete (); + // Make the path real, that is, absolute, normalized, and with resolved + // symlinks. On POSIX systems this is accomplished with the call to + // realpath(3). On Windows -- complete() and normalize(). Return *this. + // + basic_path& + realize (); + public: basic_path& operator/= (basic_path const&); diff --git a/butl/path.cxx b/butl/path.cxx index 5b68749..3e82190 100644 --- a/butl/path.cxx +++ b/butl/path.cxx @@ -6,14 +6,15 @@ #ifdef _WIN32 # include <stdlib.h> // _MAX_PATH -# include <direct.h> // _[w]getcwd, _[w]chdir +# include <direct.h> // _[w]getcwd(), _[w]chdir() #else # include <errno.h> // EINVAL -# include <stdlib.h> // mbstowcs, wcstombs +# include <stdlib.h> // mbstowcs(), wcstombs(), realpath() # include <limits.h> // PATH_MAX -# include <unistd.h> // getcwd, chdir +# include <unistd.h> // getcwd(), chdir() #endif +#include <cassert> #include <system_error> #ifndef _WIN32 @@ -68,6 +69,27 @@ namespace butl #endif } +#ifndef _WIN32 + template <> + void path_traits<char>:: + realize (string_type& s) + { + char r[PATH_MAX]; + if (realpath (s.c_str (), r) == nullptr) + { + // @@ If there were a message in invalid_basic_path, we could have said + // what exactly is wrong with the path. + // + if (errno == EACCES || errno == ENOENT || errno == ENOTDIR) + throw invalid_basic_path<char> (s); + else + throw system_error (errno, system_category ()); + } + + s = r; + } +#endif + // // wchar_t // @@ -112,4 +134,13 @@ namespace butl throw system_error (errno, system_category ()); #endif } + +#ifndef _WIN32 + template <> + void path_traits<wchar_t>:: + realize (string_type&) + { + assert (false); // Implement if/when needed. + } +#endif } diff --git a/butl/path.ixx b/butl/path.ixx index c072075..f933bd3 100644 --- a/butl/path.ixx +++ b/butl/path.ixx @@ -177,6 +177,19 @@ namespace butl } template <typename C, typename K> + inline basic_path<C, K>& basic_path<C, K>:: + realize () + { +#ifdef _WIN32 + complete (); + normalize (); +#else + traits::realize (this->path_); +#endif + return *this; + } + + template <typename C, typename K> inline typename basic_path<C, K>::dir_type basic_path<C, K>:: root_directory () const { |