From e7b033d7b38bc55f934521b5f35060b43a8b0526 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 30 Nov 2016 11:47:27 +0300 Subject: Make path::normalize() to preserve ./, invalidate paths starting with \, / on Windows --- butl/buildfile | 1 + butl/path | 8 ++++++-- butl/path.txx | 26 +++++++++++++++++++------- butl/process.cxx | 28 +++++++++++++++++++++------- 4 files changed, 47 insertions(+), 16 deletions(-) (limited to 'butl') diff --git a/butl/buildfile b/butl/buildfile index 5c5aae3..6e259c8 100644 --- a/butl/buildfile +++ b/butl/buildfile @@ -21,6 +21,7 @@ lib{butl}: \ {hxx txx }{ prefix-map } \ {hxx ixx cxx}{ process } \ {hxx cxx}{ sha256 } \ +{hxx }{ small-vector } \ {hxx txx }{ string-table } \ {hxx cxx}{ timestamp } \ {hxx cxx}{ triplet } \ diff --git a/butl/path b/butl/path index 2a32c70..2e243ff 100644 --- a/butl/path +++ b/butl/path @@ -808,7 +808,11 @@ namespace butl // 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. + // 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. @@ -818,7 +822,7 @@ namespace butl // etc.) are returned in their actual spelling. // basic_path& - normalize (bool actual = false); + normalize (bool actual = false, bool cur_empty = false); // Make the path absolute using the current directory unless it is already // absolute. Return *this. diff --git a/butl/path.txx b/butl/path.txx index 5bcaea0..0cdaf5b 100644 --- a/butl/path.txx +++ b/butl/path.txx @@ -147,7 +147,7 @@ namespace butl template basic_path& basic_path:: - normalize (bool actual) + normalize (bool actual, bool cur_empty) { if (empty ()) return *this; @@ -273,12 +273,24 @@ namespace butl p += traits::directory_separator; } - if (tsep && (!p.empty () || abs)) // Distinguish "/"-empty and "."-empty. + if (tsep) { if (p.empty ()) { - p += traits::directory_separator; - ts = -1; + // Distinguish "/"-empty and "."-empty. + // + if (abs) + { + p += traits::directory_separator; + ts = -1; + } + else if (!cur_empty) // Collapse to canonical current directory. + { + p = "."; + ts = 1; // Canonical separator is always first. + } + else // Collapse to empty path. + ts = 0; } else ts = 1; // Canonical separator is always first. @@ -313,11 +325,11 @@ namespace butl #ifdef _WIN32 // We do not support any special Windows path name notations like in C:abc, - // \\?\c:\abc, \\server\abc and \\?\UNC\server\abc (more about them at - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx). + // /, \, /abc, \abc, \\?\c:\abc, \\server\abc and \\?\UNC\server\abc (more + // about them in "Naming Files, Paths, and Namespaces" MSDN article). // if ((n > 2 && s[1] == ':' && s[2] != '\\' && s[2] != '/') || - (n > 1 && s[0] == '\\' && s[1] == '\\')) + (n > 0 && (s[0] == '\\' || s[0] == '/'))) { if (exact) return data_type (); diff --git a/butl/process.cxx b/butl/process.cxx index c75cfbd..cf4b26d 100644 --- a/butl/process.cxx +++ b/butl/process.cxx @@ -171,7 +171,7 @@ namespace butl ep = path (move (s)); // Move back into result. if (norm) - ep.normalize (); //@@ NORM + ep.normalize (); return exists (ep.string ().c_str ()); }; @@ -212,10 +212,17 @@ namespace butl e = strchr (b, traits::path_separator); // Empty path (i.e., a double colon or a colon at the beginning or end - // of PATH) means search in the current dirrectory. + // of PATH) means search in the current dirrectory. Silently skip + // invalid paths. // - if (search (b, e != nullptr ? e - b : strlen (b))) - return r; + try + { + if (search (b, e != nullptr ? e - b : strlen (b))) + return r; + } + catch (const invalid_path&) + { + } } // If we were given a fallback, try that. @@ -575,10 +582,17 @@ namespace butl e = strchr (b, traits::path_separator); // Empty path (i.e., a double colon or a colon at the beginning or end - // of PATH) means search in the current dirrectory. + // of PATH) means search in the current dirrectory. Silently skip + // invalid paths. // - if (search (b, e != nullptr ? e - b : strlen (b))) - return r; + try + { + if (search (b, e != nullptr ? e - b : strlen (b))) + return r; + } + catch (const invalid_path&) + { + } } // Finally, if we were given a fallback, try that. This case is similar to -- cgit v1.1