# # patch "ChangeLog" # from [3d9a978cdfca1f476c03b7ce196a3be0a3dc2bd3] # to [cc4161041cb4085a188729e806c1ee5d905934ae] # # patch "paths.cc" # from [f62a77b3ed9c5da9a101f825dd5951c517e836e3] # to [ca3c2e0bff67faea75076ba1e12bf2c1abd6d1df] # # patch "unix/fs.cc" # from [f662e2ce8ffda78997c89c83c583add594d99462] # to [9f93398a3edcfc1d2246c26627c9ebf1cd72f2c6] # ======================================================================== --- ChangeLog 3d9a978cdfca1f476c03b7ce196a3be0a3dc2bd3 +++ ChangeLog cc4161041cb4085a188729e806c1ee5d905934ae @@ -1,5 +1,9 @@ 2005-08-25 Nathaniel Smith + * paths.cc, unix/fs.cc: Many, many fixes and some new tests too. + +2005-08-25 Nathaniel Smith + * paths.cc (struct access_tracker): Doh, initializer should set 'initialized'... (test_file_path_internal): It's valid for a split file ======================================================================== --- paths.cc f62a77b3ed9c5da9a101f825dd5951c517e836e3 +++ paths.cc ca3c2e0bff67faea75076ba1e12bf2c1abd6d1df @@ -117,7 +117,8 @@ // empty path is fine if (path.empty()) return true; - // : in second position => absolute path on windows + // could use is_absolute_somewhere, but this is the only part of it that + // wouldn't be redundant if (path.size() > 1 && path[1] == ':') return false; // first scan for completely illegal bytes @@ -156,10 +157,20 @@ data = path; break; case external: - fs::path tmp(initial_rel_path.get().as_internal()); - tmp /= fs::path(path, fs::native); - tmp = tmp.normalize(); + fs::path tmp; + try + { + tmp = fs::path(initial_rel_path.get().as_internal()); + tmp /= fs::path(path); + tmp = tmp.normalize(); + } + catch (std::exception & e) + { + N(false, F("path '%s' is invalid") % path); + } data = utf8(tmp.string()); + N(fully_normalized_path(data()), F("path '%s' is invalid") % data); + N(!in_bookkeeping_dir(data()), F("path '%s' is in bookkeeping dir") % data); } I(fully_normalized_path(data())); I(!in_bookkeeping_dir(data())); @@ -287,9 +298,40 @@ // this code's speed does not matter much /////////////////////////////////////////////////////////////////////////// +static bool +is_absolute_here(std::string const & path) +{ + if (path.empty()) + return false; + if (path[0] == '/') + return true; +#ifdef _WIN32 + if (path[0] == '\\') + return true; + if (path.size() > 1 && path[1] == ':') + return true; +#endif + return false; +} + +static inline bool +is_absolute_somewhere(std::string const & path) +{ + if (path.empty()) + return false; + if (path[0] == '/') + return true; + if (path[0] == '\\') + return true; + if (path.size() > 1 && path[1] == ':') + return true; + return false; +} + file_path file_path::operator /(std::string const & to_append) const { + I(!is_absolute_somewhere(to_append)); if (empty()) return file_path_internal(to_append); else @@ -299,16 +341,16 @@ bookkeeping_path bookkeeping_path::operator /(std::string const & to_append) const { - if (empty()) - return bookkeeping_path(to_append); - else - return bookkeeping_path(data() + "/" + to_append); + I(!is_absolute_somewhere(to_append)); + I(!empty()); + return bookkeeping_path(data() + "/" + to_append); } system_path system_path::operator /(std::string const & to_append) const { I(!empty()); + I(!is_absolute_here(to_append)); return system_path(data() + "/" + to_append); } @@ -316,32 +358,17 @@ // system_path /////////////////////////////////////////////////////////////////////////// -static bool -is_absolute(std::string const & path) -{ - if (path.empty()) - return false; - if (path[0] == '/') - return true; -#ifdef _WIN32 - if (path[0] == '\\') - return true; - if (path.size() > 1 && path[1] == ':') - return true; -#endif - return false; -} - system_path::system_path(any_path const & other) { - I(!is_absolute(other.as_internal())); + I(!is_absolute_here(other.as_internal())); data = (working_root.get() / other.as_internal()).as_internal(); } static inline std::string const_system_path(utf8 const & path) { + N(!path().empty(), F("invalid path ''")); std::string expanded = tilde_expand(path)(); - if (is_absolute(expanded)) + if (is_absolute_here(expanded)) return expanded; else return (initial_abs_path.get() / expanded).as_internal(); @@ -456,9 +483,11 @@ "c:foo", "c:/foo", 0 }; + initial_rel_path.unset(); initial_rel_path.set(file_path(), true); for (char const ** c = baddies; *c; ++c) BOOST_CHECK_THROW(file_path_internal(*c), std::logic_error); + initial_rel_path.unset(); initial_rel_path.set(file_path_internal("blah/blah/blah"), true); for (char const ** c = baddies; *c; ++c) BOOST_CHECK_THROW(file_path_internal(*c), std::logic_error); @@ -473,10 +502,12 @@ ".foo/bar", "..foo/bar", "MTfoo/bar", + "foo:bar", 0 }; for (int i = 0; i < 2; ++i) { + initial_rel_path.unset(); initial_rel_path.set(i ? file_path() : file_path_internal("blah/blah/blah"), true); @@ -489,6 +520,7 @@ fp.split(split_test); file_path fp2(split_test); BOOST_CHECK(fp == fp2); + BOOST_CHECK(!split_test.empty()); if (split_test.size() > 1) for (std::vector::const_iterator i = split_test.begin(); i != split_test.end(); ++i) @@ -511,13 +543,16 @@ fp.split(split_test); file_path fp2(split_test); BOOST_CHECK(fp == fp2); - for (std::vector::const_iterator i = split_test.begin(); - i != split_test.end(); ++i) - BOOST_CHECK(!null_name(*i)); + BOOST_CHECK(!split_test.empty()); + if (split_test.size() > 1) + for (std::vector::const_iterator i = split_test.begin(); + i != split_test.end(); ++i) + BOOST_CHECK(!null_name(*i)); } static void test_file_path_external_no_prefix() { + initial_rel_path.unset(); initial_rel_path.set(file_path(), true); char const * baddies[] = {"/foo", @@ -545,6 +580,7 @@ check_fp_normalizes_to(".foo/bar", ".foo/bar"); check_fp_normalizes_to("..foo/bar", "..foo/bar"); check_fp_normalizes_to(".", ""); + check_fp_normalizes_to("foo:bar", "foo:bar"); check_fp_normalizes_to("foo//bar", "foo/bar"); check_fp_normalizes_to("foo/../bar", "bar"); @@ -558,6 +594,7 @@ static void test_file_path_external_prefix_a_b() { + initial_rel_path.unset(); initial_rel_path.set(file_path_internal("a/b"), true); char const * baddies[] = {"/foo", @@ -571,7 +608,10 @@ "", 0 }; for (char const ** c = baddies; *c; ++c) - BOOST_CHECK_THROW(file_path_external(utf8(*c)), informative_failure); + { + L(F("test_file_path_external_prefix_a_b: trying baddie: %s") % *c); + BOOST_CHECK_THROW(file_path_external(utf8(*c)), informative_failure); + } check_fp_normalizes_to("foo", "a/b/foo"); check_fp_normalizes_to("a", "a/b/a"); @@ -583,6 +623,7 @@ check_fp_normalizes_to(".foo/bar", "a/b/.foo/bar"); check_fp_normalizes_to("..foo/bar", "a/b/..foo/bar"); check_fp_normalizes_to(".", "a/b"); + check_fp_normalizes_to("foo:bar", "a/b/foo:bar"); // things that would have been bad without the initial_rel_path: check_fp_normalizes_to("foo//bar", "a/b/foo/bar"); check_fp_normalizes_to("foo/../bar", "a/b/bar"); @@ -644,6 +685,7 @@ static void check_bk_normalizes_to(char * before, char * after) { bookkeeping_path bp(bookkeeping_root / before); + L(F("normalizing %s to %s (got %s)") % before % after % bp); BOOST_CHECK(bp.as_external() == after); BOOST_CHECK(bookkeeping_path(bp.as_internal()).as_internal() == bp.as_internal()); } @@ -667,13 +709,15 @@ for (char const ** c = baddies; *c; ++c) { + L(F("test_bookkeeping_path baddie: trying '%s'") % *c); BOOST_CHECK_THROW(bookkeeping_path(std::string(*c)), std::logic_error); BOOST_CHECK_THROW(bookkeeping_root / std::string(*c), std::logic_error); } BOOST_CHECK_THROW(bookkeeping_path(std::string("foo/bar")), std::logic_error); BOOST_CHECK_THROW(bookkeeping_path(std::string("a")), std::logic_error); - check_bk_normalizes_to("a", "MT/foo"); + check_bk_normalizes_to("a", "MT/a"); + check_bk_normalizes_to("a:b", "MT/a:b"); check_bk_normalizes_to("foo", "MT/foo"); check_bk_normalizes_to("foo/bar", "MT/foo/bar"); check_bk_normalizes_to("foo/bar/baz", "MT/foo/bar/baz"); @@ -682,12 +726,14 @@ static void check_system_normalizes_to(char * before, char * after) { system_path sp(before); + L(F("normalizing '%s' to '%s' (got '%s')") % before % after % sp); BOOST_CHECK(sp.as_external() == after); BOOST_CHECK(system_path(sp.as_internal()).as_internal() == sp.as_internal()); } static void test_system_path() { + initial_abs_path.unset(); initial_abs_path.set(system_path("/a/b"), true); BOOST_CHECK_THROW(system_path(""), informative_failure); @@ -695,16 +741,17 @@ check_system_normalizes_to("foo", "/a/b/foo"); check_system_normalizes_to("foo/bar", "/a/b/foo/bar"); check_system_normalizes_to("/foo/bar", "/foo/bar"); - check_system_normalizes_to("//foo/bar", "/foo/bar"); + check_system_normalizes_to("//foo/bar", "//foo/bar"); #ifdef _WIN32 check_system_normalizes_to("c:foo", "c:foo"); check_system_normalizes_to("c:/foo", "c:/foo"); check_system_normalizes_to("c:\\foo", "c:\\foo"); #else - check_system_normalizes_to("c:foo", "a/b/c:foo"); - check_system_normalizes_to("c:/foo", "a/b/c:/foo"); - check_system_normalizes_to("c:\\foo", "a/b/c:\\foo"); + check_system_normalizes_to("c:foo", "/a/b/c:foo"); + check_system_normalizes_to("c:/foo", "/a/b/c:/foo"); + check_system_normalizes_to("c:\\foo", "/a/b/c:\\foo"); #endif + check_system_normalizes_to("foo:bar", "/a/b/foo:bar"); // can't do particularly interesting checking of tilde expansion, but at // least we can check that it's doing _something_... std::string tilde_expanded = system_path("~/foo").as_external(); @@ -722,7 +769,9 @@ // finally, make sure that the copy-from-any_path constructor works right // in particular, it should interpret the paths it gets as being relative to // the project root, not the initial path + working_root.unset(); working_root.set(system_path("/working/root"), true); + initial_rel_path.unset(); initial_rel_path.set(file_path_internal("rel/initial"), true); BOOST_CHECK(system_path(system_path("foo/bar")).as_internal() == "/a/b/foo/bar"); @@ -731,8 +780,12 @@ == "/working/root/foo/bar"); BOOST_CHECK(system_path(file_path_external(std::string("foo/bar"))).as_external() == "/working/root/rel/initial/foo/bar"); + BOOST_CHECK(system_path(file_path()).as_external() + == "/working/root/"); BOOST_CHECK(system_path(bookkeeping_path("MT/foo/bar")).as_internal() == "/working/root/MT/foo/bar"); + BOOST_CHECK(system_path(bookkeeping_root).as_internal() + == "/working/root/MT"); initial_abs_path.unset(); working_root.unset(); ======================================================================== --- unix/fs.cc f662e2ce8ffda78997c89c83c583add594d99462 +++ unix/fs.cc 9f93398a3edcfc1d2246c26627c9ebf1cd72f2c6 @@ -48,6 +48,8 @@ utf8 tilde_expand(utf8 const & in) { + if (in().empty() || in()[0] != '~') + return in; fs::path tmp(in(), fs::native); fs::path::iterator i = tmp.begin(); if (i != tmp.end())