# # # patch "key_store.hh" # from [8912c391c7e6ea8a925ffb9cd8c9f5b3859bd139] # to [6dd1c25123305d42dfbf957f6ee872fae601e96b] # # patch "paths.cc" # from [c17f38dc8d335bba640982d366d6d464a20cb042] # to [1d28eaaea93d0c9142de1406ce80f542bf86b0cf] # # patch "paths.hh" # from [80931173a8567a2f0dffd3d0551d929540bd33a9] # to [2d99b30b4c38f21a427376bd2625e65d7e17577a] # # patch "roster.cc" # from [95bc8ab68e236204ace5928a48d42fe31bd0f5c1] # to [5b403512edb2c165b2a1e27a10e8074471fdfbe7] # ============================================================ --- key_store.hh 8912c391c7e6ea8a925ffb9cd8c9f5b3859bd139 +++ key_store.hh 6dd1c25123305d42dfbf957f6ee872fae601e96b @@ -1,7 +1,8 @@ #ifndef __KEY_STORE_H__ #define __KEY_STORE_H__ #include +#include #include "vocab.hh" #include "paths.hh" ============================================================ --- paths.cc c17f38dc8d335bba640982d366d6d464a20cb042 +++ paths.cc 1d28eaaea93d0c9142de1406ce80f542bf86b0cf @@ -405,78 +405,6 @@ bool bookkeeping_path::internal_string_i // normalized, relative, paths. /////////////////////////////////////////////////////////////////////////// -// This function takes a vector of path components and joins them into a -// single file_path. This is the inverse to file_path::split. It takes a -// vector of the form: -// -// ["", p[0], p[1], ..., p[n]] -// -// and constructs the path: -// -// p[0]/p[1]/.../p[n] -// -file_path::file_path(split_path const & sp) -{ - split_path::const_iterator i = sp.begin(); - I(i != sp.end()); - I(i->empty()); - string tmp; - bool start = true; - size_t size = 0; - for (++i; i != sp.end(); ++i) - { - size = size + 1 + (*i)().length(); - } - tmp.reserve(size); - i = sp.begin(); - for (++i; i != sp.end(); ++i) - { - I(!i->empty()); - if (!start) - tmp += "/"; - tmp += (*i)(); - if (start) - start = false; - } - I(!in_bookkeeping_dir(tmp)); - data = utf8(tmp); -} - -// -// this takes a path of the form -// -// "p[0]/p[1]/.../p[n-1]/p[n]" -// -// and fills in a vector of paths corresponding to p[0] ... p[n]. This is the -// inverse to the file_path::file_path(split_path) constructor. -// -// The first entry in this vector is always the null component, "". This path -// is the root of the tree. So we actually output a vector like: -// ["", p[0], p[1], ..., p[n]] -// with n+1 members. -void -file_path::split(split_path & sp) const -{ - sp.clear(); - sp.push_back(path_component()); - if (empty()) - return; - string::size_type start, stop; - start = 0; - string const & s = data(); - while (1) - { - stop = s.find('/', start); - if (stop == string::npos) - { - sp.push_back(path_component(s, start)); - break; - } - sp.push_back(path_component(s, start, stop - start)); - start = stop + 1; - } -} - // this peels off the last component of any path and returns it. // the last component of a path with no slashes in it is the complete path. // the last component of a path referring to the root directory is an @@ -508,7 +436,6 @@ file_path::dirname() const return file_path(s, 0, sep); } - // count the number of /-separated components of the path. unsigned int file_path::depth() const @@ -557,22 +484,7 @@ operator <<(ostream & o, any_path const return o; } -ostream & -operator <<(ostream & o, split_path const & sp) -{ - file_path tmp(sp); - return o << tmp; -} - template <> -void dump(split_path const & sp, string & out) -{ - ostringstream oss; - oss << sp << '\n'; - out = oss.str(); -} - -template <> void dump(file_path const & p, string & out) { ostringstream oss; @@ -987,15 +899,6 @@ UNIT_TEST(paths, file_path_internal) file_path fp = file_path_internal(*c); UNIT_TEST_CHECK(fp.as_internal() == *c); UNIT_TEST_CHECK(file_path_internal(fp.as_internal()) == fp); - split_path split_test; - fp.split(split_test); - UNIT_TEST_CHECK(!split_test.empty()); - file_path fp2(split_test); - UNIT_TEST_CHECK(fp == fp2); - UNIT_TEST_CHECK(split_test[0].empty()); - for (split_path::const_iterator - i = split_test.begin() + 1; i != split_test.end(); ++i) - UNIT_TEST_CHECK(!i->empty()); } } @@ -1012,15 +915,6 @@ static void check_fp_normalizes_to(char // we compare after to the external form too, since as far as we know // relative normalized posix paths are always good win32 paths too UNIT_TEST_CHECK(fp.as_external() == after); - split_path split_test; - fp.split(split_test); - UNIT_TEST_CHECK(!split_test.empty()); - file_path fp2(split_test); - UNIT_TEST_CHECK(fp == fp2); - UNIT_TEST_CHECK(split_test[0].empty()); - for (split_path::const_iterator - i = split_test.begin() + 1; i != split_test.end(); ++i) - UNIT_TEST_CHECK(!i->empty()); } UNIT_TEST(paths, file_path_external_null_prefix) @@ -1184,94 +1078,6 @@ UNIT_TEST(paths, file_path_external_pref initial_rel_path.unset(); } -UNIT_TEST(paths, split_join) -{ - file_path fp1 = file_path_internal("foo/bar/baz"); - file_path fp2 = file_path_internal("bar/baz/foo"); - split_path split1, split2; - fp1.split(split1); - fp2.split(split2); - UNIT_TEST_CHECK(fp1 == file_path(split1)); - UNIT_TEST_CHECK(fp2 == file_path(split2)); - UNIT_TEST_CHECK(!(fp1 == file_path(split2))); - UNIT_TEST_CHECK(!(fp2 == file_path(split1))); - UNIT_TEST_CHECK(split1.size() == 4); - UNIT_TEST_CHECK(split2.size() == 4); - UNIT_TEST_CHECK(split1[1] != split1[2]); - UNIT_TEST_CHECK(split1[1] != split1[3]); - UNIT_TEST_CHECK(split1[2] != split1[3]); - UNIT_TEST_CHECK(split1[0].empty() - && !split1[1].empty() - && !split1[2].empty() - && !split1[3].empty()); - UNIT_TEST_CHECK(split1[1] == split2[3]); - UNIT_TEST_CHECK(split1[2] == split2[1]); - UNIT_TEST_CHECK(split1[3] == split2[2]); - - file_path fp3 = file_path_internal(""); - split_path split3; - fp3.split(split3); - UNIT_TEST_CHECK(split3.size() == 1 && split3[0].empty()); - - // empty split_path is invalid - split_path split4; - // this comparison tricks the compiler into not completely eliminating this - // code as dead... - UNIT_TEST_CHECK_THROW(file_path(split4) == file_path(), logic_error); - split4.push_back(path_component()); - UNIT_TEST_CHECK(file_path(split4) == file_path()); - - // split_path without null first item is invalid - split4.clear(); - split4.push_back(split1[1]); - // this comparison tricks the compiler into not completely eliminating this - // code as dead... - UNIT_TEST_CHECK_THROW(file_path(split4) == file_path(), logic_error); - - // split_path with non-first item item null is invalid - split4.clear(); - split4.push_back(path_component()); - split4.push_back(split1[0]); - split4.push_back(path_component()); - // this comparison tricks the compiler into not completely eliminating this - // code as dead... - UNIT_TEST_CHECK_THROW(file_path(split4) == file_path(), logic_error); - - // Make sure that we can't use joining to create a path into the bookkeeping - // dir - { - split_path split_mt1, split_mt2; - file_path_internal("foo/_MTN").split(split_mt1); - UNIT_TEST_CHECK(split_mt1.size() == 3); - I(split_mt1[2] == bookkeeping_root_component); - split_mt2.push_back(path_component()); - split_mt2.push_back(split_mt1[2]); - // split_mt2 now contains the component "_MTN" - UNIT_TEST_CHECK_THROW(file_path(split_mt2) == file_path(), logic_error); - split_mt2.push_back(split_mt1[1]); - // split_mt2 now contains the components "_MTN", "foo" in that order - // this comparison tricks the compiler into not completely eliminating this - // code as dead... - UNIT_TEST_CHECK_THROW(file_path(split_mt2) == file_path(), logic_error); - } - // and make sure it fails for the klugy security cases -- see comments on - // in_bookkeeping_dir - { - split_path split_mt1, split_mt2; - file_path_internal("foo/_mTn").split(split_mt1); - UNIT_TEST_CHECK(split_mt1.size() == 3); - split_mt2.push_back(path_component()); - split_mt2.push_back(split_mt1[2]); - // split_mt2 now contains the component "_mTn" - UNIT_TEST_CHECK_THROW(file_path(split_mt2) == file_path(), logic_error); - split_mt2.push_back(split_mt1[1]); - // split_mt2 now contains the components "_mTn", "foo" in that order - // this comparison tricks the compiler into not completely eliminating this - // code as dead... - UNIT_TEST_CHECK_THROW(file_path(split_mt2) == file_path(), logic_error); - } -} - UNIT_TEST(paths, basename) { struct t @@ -1563,10 +1369,6 @@ static void test_path_less_than(string c MM(right); file_path left_fp = file_path_internal(left); file_path right_fp = file_path_internal(right); - split_path left_sp, right_sp; - left_fp.split(left_sp); - right_fp.split(right_sp); - I(left_sp < right_sp); I(left_fp < right_fp); } @@ -1576,10 +1378,6 @@ static void test_path_equal(string const MM(right); file_path left_fp = file_path_internal(left); file_path right_fp = file_path_internal(right); - split_path left_sp, right_sp; - left_fp.split(left_sp); - right_fp.split(right_sp); - I(left_sp == right_sp); I(left_fp == right_fp); } ============================================================ --- paths.hh 80931173a8567a2f0dffd3d0551d929540bd33a9 +++ paths.hh 2d99b30b4c38f21a427376bd2625e65d7e17577a @@ -98,19 +98,19 @@ #include #include -#include #include "vocab.hh" +class any_path; +class file_path; +class roster_t; + // A path_component is one component of a path. It is always utf8, may not // contain either kind of slash, and may not be a magic directory entry ("." // or "..") It _may_ be the empty string, but you only get that if you ask // for the basename of the root directory. It resembles, but is not, a // vocab type. -class any_path; -class file_path; - class path_component { public: @@ -147,13 +147,6 @@ template <> void dump(path_component con std::ostream & operator<<(std::ostream &, path_component const &); template <> void dump(path_component const &, std::string &); -// There is also one "not really a path" type, 'split_path'. This is a vector -// of path_component's, and semantically equivalent to a file_path -- -// file_path's can be split into split_path's, and split_path's can be joined -// into file_path's. - -typedef std::vector split_path; - // It's possible this will become a proper virtual interface in the future, // but since the implementation is exactly the same in all cases, there isn't // much point ATM... @@ -180,22 +173,15 @@ std::ostream & operator<<(std::ostream & }; std::ostream & operator<<(std::ostream & o, any_path const & a); -std::ostream & operator<<(std::ostream & o, split_path const & s); -template <> void dump(split_path const & sp, std::string & out); - class file_path : public any_path { public: file_path() {} // join a file_path out of pieces - explicit file_path(split_path const & sp); - file_path operator /(path_component const & to_append) const; file_path operator /(file_path const & to_append) const; - void split(split_path & sp) const; - // these functions could be defined on any_path but are only needed // for file_path, and not defining them for system_path gets us out // of nailing down the semantics near the absolute root. @@ -269,6 +255,9 @@ private: { data = utf8(path.substr(start, stop)); } + + // roster_t::get_name is allowed to use the private substring constructor. + friend class roster_t; }; // these are the public file_path constructors ============================================================ --- roster.cc 95bc8ab68e236204ace5928a48d42fe31bd0f5c1 +++ roster.cc 5b403512edb2c165b2a1e27a10e8074471fdfbe7 @@ -130,14 +130,6 @@ namespace // // - there is no file_path or path_component corresponding to the_null_node. // - // - the split_path corresponding to the_null_node is [], the empty vector. - // - // - the split_path corresponding to the root node is [""], the 1-element - // vector containing an empty path component. This is the only valid - // one-element split_path. - // - // - the split_path corresponding to foo/bar is ["", "foo", "bar"]. - // // We do this in order to support the notion of moving the root directory // around, or applying attributes to the root directory. Note that the // only supported way to move the root is with the 'pivot_root' operation, @@ -648,16 +640,40 @@ roster_t::get_name(node_id nid, file_pat void roster_t::get_name(node_id nid, file_path & p) const { - split_path sp; I(!null_node(nid)); - while (!null_node(nid)) + + stack sp; + size_t size = 0; + + while (nid != root_dir->self) { node_t n = get_node(nid); - sp.push_back(n->name); + sp.push(n->name); + size += n->name().length() + 1; nid = n->parent; } - reverse(sp.begin(), sp.end()); - p = file_path(sp); + + if (size == 0) + { + p.clear(); + return; + } + + I(!bookkeeping_path::internal_string_is_bookkeeping_path(utf8(sp.top()()))); + + string tmp; + tmp.reserve(size); + + for (;;) + { + tmp += sp.top()(); + sp.pop(); + if (sp.empty()) + break; + tmp += "/"; + } + + p = file_path(tmp, 0, string::npos); // short circuit constructor } @@ -2982,9 +2998,7 @@ path_component new_component(randomizer path_component new_component(randomizer & rng) { - split_path pieces; - file_path_internal(new_word(rng)).split(pieces); - return pieces.back(); + return path_component(new_word(rng)); } @@ -2998,24 +3012,33 @@ attr_key pick_attr(attr_map_t const & at return random_element(attrs, rng)->first; } -bool parent_of(split_path const & p, - split_path const & c) +bool parent_of(file_path const & p, + file_path const & c) { bool is_parent = false; - if (p.size() <= c.size()) + // the null path is the parent of all paths. + if (p.depth() == 0) + is_parent = true; + + else if (p.depth() <= c.depth()) { - split_path::const_iterator c_anchor = - search(c.begin(), c.end(), - p.begin(), p.end()); + string const & ci = c.as_internal(); + string const & pi = p.as_internal(); + + string::const_iterator c_anchor = + search(ci.begin(), ci.end(), + pi.begin(), pi.end()); - is_parent = (c_anchor == c.begin()); + is_parent = (c_anchor == ci.begin() && (ci.size() == pi.size() + || *(ci.begin() + pi.size()) + == '/')); } // L(FL("path '%s' is%s parent of '%s'") - // % file_path(p) + // % p // % (is_parent ? "" : " not") - // % file_path(c)); + // % c); return is_parent; } @@ -3027,10 +3050,8 @@ void perform_random_action(roster_t & r, while (c.empty()) { node_t n = random_element(r.all_nodes(), rng)->second; - split_path pth; - file_path fp; - r.get_name(n->self, fp); - fp.split(pth); + file_path pth; + r.get_name(n->self, pth); // L(FL("considering acting on '%s'") % file_path(pth)); switch (rng.uniform(7)) @@ -3039,24 +3060,23 @@ void perform_random_action(roster_t & r, case 0: case 1: case 2: - if (is_file_t(n) || (pth.size() > 1 && rng.flip())) + if (is_file_t(n) || (pth.depth() > 1 && rng.flip())) // Add a sibling of an existing entry. - pth[pth.size() - 1] = new_component(rng); + pth = pth.dirname() / new_component(rng); else // Add a child of an existing entry. - pth.push_back(new_component(rng)); + pth = pth / new_component(rng); if (rng.flip()) { // L(FL("adding dir '%s'") % file_path(pth)); - safe_insert(c.dirs_added, file_path(pth)); + safe_insert(c.dirs_added, pth); } else { // L(FL("adding file '%s'") % file_path(pth)); - safe_insert(c.files_added, make_pair(file_path(pth), - new_ident(rng))); + safe_insert(c.files_added, make_pair(pth, new_ident(rng))); } break; @@ -3065,30 +3085,27 @@ void perform_random_action(roster_t & r, { // L(FL("altering content of file '%s'") % file_path(pth)); safe_insert(c.deltas_applied, - make_pair - (file_path(pth), - make_pair(downcast_to_file_t(n)->content, - new_ident(rng)))); + make_pair(pth, + make_pair(downcast_to_file_t(n)->content, + new_ident(rng)))); } break; case 4: { node_t n2 = random_element(r.all_nodes(), rng)->second; - file_path fp2; - split_path pth2; - r.get_name(n2->self, fp2); - fp2.split(pth2); - if (n == n2) continue; - if (is_file_t(n2) || (pth2.size() > 1 && rng.flip())) + file_path pth2; + r.get_name(n2->self, pth2); + + if (is_file_t(n2) || (pth2.depth() > 1 && rng.flip())) { // L(FL("renaming to a sibling of an existing entry '%s'") // % file_path(pth2)); // Move to a sibling of an existing entry. - pth2[pth2.size() - 1] = new_component(rng); + pth2 = pth2.dirname() / new_component(rng); } else @@ -3096,15 +3113,14 @@ void perform_random_action(roster_t & r, // L(FL("renaming to a child of an existing entry '%s'") // % file_path(pth2)); // Move to a child of an existing entry. - pth2.push_back(new_component(rng)); + pth2 = pth2 / new_component(rng); } if (!parent_of(pth, pth2)) { // L(FL("renaming '%s' -> '%s") // % file_path(pth) % file_path(pth2)); - safe_insert(c.nodes_renamed, make_pair(file_path(pth), - file_path(pth2))); + safe_insert(c.nodes_renamed, make_pair(pth, pth2)); } } break; @@ -3115,7 +3131,7 @@ void perform_random_action(roster_t & r, && r.all_nodes().size() > 1) // do not delete the root { // L(FL("deleting '%s'") % file_path(pth)); - safe_insert(c.nodes_deleted, file_path(pth)); + safe_insert(c.nodes_deleted, pth); } break; @@ -3128,14 +3144,13 @@ void perform_random_action(roster_t & r, if (rng.flip()) { // L(FL("clearing attr on '%s'") % file_path(pth)); - safe_insert(c.attrs_cleared, make_pair(file_path(pth), k)); + safe_insert(c.attrs_cleared, make_pair(pth, k)); } else { // L(FL("changing attr on '%s'\n") % file_path(pth)); safe_insert(c.attrs_set, - make_pair(make_pair(file_path(pth), k), - new_word(rng))); + make_pair(make_pair(pth, k), new_word(rng))); } } else @@ -3143,15 +3158,14 @@ void perform_random_action(roster_t & r, // L(FL("setting previously set attr on '%s'") // % file_path(pth)); safe_insert(c.attrs_set, - make_pair(make_pair(file_path(pth), k), - new_word(rng))); + make_pair(make_pair(pth, k), new_word(rng))); } } else { // L(FL("setting attr on '%s'") % file_path(pth)); safe_insert(c.attrs_set, - make_pair(make_pair(file_path(pth), new_word(rng)), + make_pair(make_pair(pth, new_word(rng)), new_word(rng))); } break; @@ -4829,21 +4843,19 @@ create_random_unification_task(roster_t right_nid = right_er->create_file_node(fid); } - split_path pth; - file_path fp; - left.get_name(left_n->self, fp); - I(right.has_node(fp)); - fp.split(pth); + file_path pth; + left.get_name(left_n->self, pth); + I(right.has_node(pth)); - if (is_file_t(left_n) || (pth.size() > 1 && rng.flip())) + if (is_file_t(left_n) || (pth.depth() > 1 && rng.flip())) // Add a sibling of an existing entry. - pth[pth.size() - 1] = new_component(rng); + pth = pth.dirname() / new_component(rng); else // Add a child of an existing entry. - pth.push_back(new_component(rng)); + pth = pth / new_component(rng); - left_er->attach_node(left_nid, file_path(pth)); - right_er->attach_node(right_nid, file_path(pth)); + left_er->attach_node(left_nid, pth); + right_er->attach_node(right_nid, pth); } }