aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-02-12 09:08:32 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-02-12 09:08:32 +0200
commite4a63cd55c6347dd24938ec8a1ef203409be058e (patch)
tree56d41e47355067685fa9590b8f3d6fac18d05af6
parentd2c8cfc1f02b40d3fef5414e5830dd6f1fc20fe9 (diff)
Add path::realize(), which on POSIX calls realpath(3)
-rw-r--r--butl/path80
-rw-r--r--butl/path.cxx37
-rw-r--r--butl/path.ixx13
3 files changed, 94 insertions, 36 deletions
diff --git a/butl/path b/butl/path
index c600e04..1fdc8b6 100644
--- a/butl/path
+++ b/butl/path
@@ -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
{