diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2011-03-17 11:48:54 -0700 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2011-03-17 11:48:54 -0700 |
commit | eb9f5718d412022015bb65eb08c30785c79e79e6 (patch) | |
tree | be0b6a9de27965e39c44c5c8a88adf9caa13abf8 /src/cstore/unionfs | |
parent | cda3f423c311fd30e8cc24e2de67d99baf352b2a (diff) | |
download | vyatta-cfg-eb9f5718d412022015bb65eb08c30785c79e79e6.tar.gz vyatta-cfg-eb9f5718d412022015bb65eb08c30785c79e79e6.zip |
add config path abstraction and high-level caching
* part of the config backend cleanup/optimization work.
* improves the performance of "load" (w/o commit) by ~55% and "show" by ~15%.
Diffstat (limited to 'src/cstore/unionfs')
-rw-r--r-- | src/cstore/unionfs/cstore-unionfs.cpp | 407 | ||||
-rw-r--r-- | src/cstore/unionfs/cstore-unionfs.hpp | 117 | ||||
-rw-r--r-- | src/cstore/unionfs/fspath.hpp | 92 |
3 files changed, 376 insertions, 240 deletions
diff --git a/src/cstore/unionfs/cstore-unionfs.cpp b/src/cstore/unionfs/cstore-unionfs.cpp index b59ddd3..f926540 100644 --- a/src/cstore/unionfs/cstore-unionfs.cpp +++ b/src/cstore/unionfs/cstore-unionfs.cpp @@ -26,7 +26,8 @@ #include <cli_cstore.h> #include <cstore/unionfs/cstore-unionfs.hpp> -using namespace cstore; +namespace cstore { // begin namespace cstore +namespace unionfs { // begin namespace unionfs ////// constants // environment vars defining root dirs @@ -205,7 +206,8 @@ UnionfsCstore::UnionfsCstore(bool use_edit_level) * starts with '/', so only append it if it is at least two chars * (i.e., it is not "/"). */ - tmpl_path /= val; + FsPath tlvl(val); + tmpl_path /= tlvl; } } _init_fs_escape_chars(); @@ -239,11 +241,11 @@ UnionfsCstore::UnionfsCstore(const string& sid, string& env) string declr = " declare -x -r "; // readonly vars env += " umask 002; {"; - env += (declr + C_ENV_ACTIVE_ROOT + "=" + active_root.file_string()); - env += (declr + C_ENV_CHANGE_ROOT + "=" + change_root.file_string() + ";"); - env += (declr + C_ENV_WORK_ROOT + "=" + work_root.file_string() + ";"); - env += (declr + C_ENV_TMP_ROOT + "=" + tmp_root.file_string() + ";"); - env += (declr + C_ENV_TMPL_ROOT + "=" + tmpl_root.file_string() + ";"); + env += (declr + C_ENV_ACTIVE_ROOT + "=" + active_root.path_cstr()); + env += (declr + C_ENV_CHANGE_ROOT + "=" + change_root.path_cstr() + ";"); + env += (declr + C_ENV_WORK_ROOT + "=" + work_root.path_cstr() + ";"); + env += (declr + C_ENV_TMP_ROOT + "=" + tmp_root.path_cstr() + ";"); + env += (declr + C_ENV_TMPL_ROOT + "=" + tmpl_root.path_cstr() + ";"); env += " } >&/dev/null || true"; // set up path strings using level vars @@ -254,7 +256,8 @@ UnionfsCstore::UnionfsCstore(const string& sid, string& env) } if ((val = getenv(C_ENV_TMPL_LEVEL.c_str())) && val[0] && val[1]) { // see comment in the other constructor - tmpl_path /= val; + FsPath tlvl(val); + tmpl_path /= tlvl; } _init_fs_escape_chars(); @@ -269,14 +272,14 @@ UnionfsCstore::~UnionfsCstore() bool UnionfsCstore::markSessionUnsaved() { - b_fs::path marker = work_root / C_MARKER_UNSAVED; - if (path_exists(marker.file_string().c_str())) { + FsPath marker = work_root; + marker.push(C_MARKER_UNSAVED); + if (path_exists(marker)) { // already marked. treat as success. return true; } - if (!create_file(marker.file_string())) { - output_internal("failed to mark unsaved [%s]\n", - marker.file_string().c_str()); + if (!create_file(marker)) { + output_internal("failed to mark unsaved [%s]\n", marker.path_cstr()); return false; } return true; @@ -285,16 +288,16 @@ UnionfsCstore::markSessionUnsaved() bool UnionfsCstore::unmarkSessionUnsaved() { - b_fs::path marker = work_root / C_MARKER_UNSAVED; - if (!path_exists(marker.file_string().c_str())) { + FsPath marker = work_root; + marker.push(C_MARKER_UNSAVED); + if (!path_exists(marker)) { // not marked. treat as success. return true; } try { - b_fs::remove(marker); + b_fs::remove(marker.path_cstr()); } catch (...) { - output_internal("failed to unmark unsaved [%s]\n", - marker.file_string().c_str()); + output_internal("failed to unmark unsaved [%s]\n", marker.path_cstr()); return false; } return true; @@ -303,15 +306,17 @@ UnionfsCstore::unmarkSessionUnsaved() bool UnionfsCstore::sessionUnsaved() { - b_fs::path marker = work_root / C_MARKER_UNSAVED; - return path_exists(marker.file_string().c_str()); + FsPath marker = work_root; + marker.push(C_MARKER_UNSAVED); + return path_exists(marker); } bool UnionfsCstore::sessionChanged() { - b_fs::path marker = work_root / C_MARKER_CHANGED; - return path_exists(marker.file_string().c_str()); + FsPath marker = work_root; + marker.push(C_MARKER_CHANGED); + return path_exists(marker); } /* set up the session associated with this object. @@ -321,15 +326,15 @@ UnionfsCstore::sessionChanged() bool UnionfsCstore::setupSession() { - if (!path_exists(work_root.file_string().c_str())) { + if (!path_exists(work_root)) { // session doesn't exist. create dirs. try { - b_fs::create_directories(work_root); - b_fs::create_directories(change_root); - b_fs::create_directories(tmp_root); - if (!path_exists(active_root.file_string().c_str())) { + b_fs::create_directories(work_root.path_cstr()); + b_fs::create_directories(change_root.path_cstr()); + b_fs::create_directories(tmp_root.path_cstr()); + if (!path_exists(active_root)) { // this should only be needed on boot - b_fs::create_directories(active_root); + b_fs::create_directories(active_root.path_cstr()); } } catch (...) { output_internal("setup session failed to create session directories\n"); @@ -337,17 +342,20 @@ UnionfsCstore::setupSession() } // union mount - string mopts = ("dirs=" + change_root.file_string() + "=rw:" - + active_root.file_string() + "=ro"); - if (mount("unionfs", work_root.file_string().c_str(), "unionfs", 0, + string mopts = "dirs="; + mopts += change_root.path_cstr(); + mopts += "=rw:"; + mopts += active_root.path_cstr(); + mopts += "=ro"; + if (mount("unionfs", work_root.path_cstr(), "unionfs", 0, mopts.c_str()) != 0) { output_internal("setup session mount failed [%s][%s]\n", - strerror(errno), work_root.file_string().c_str()); + strerror(errno), work_root.path_cstr()); return false; } - } else if (!path_is_directory(work_root.file_string().c_str())) { + } else if (!path_is_directory(work_root)) { output_internal("setup session not dir [%s]\n", - work_root.file_string().c_str()); + work_root.path_cstr()); return false; } return true; @@ -361,10 +369,9 @@ bool UnionfsCstore::teardownSession() { // check if session exists - string wstr = work_root.file_string(); + string wstr = work_root.path_cstr(); if (wstr.empty() || wstr.find(C_DEF_WORK_PREFIX) != 0 - || !path_exists(work_root.file_string().c_str()) - || !path_is_directory(work_root.file_string().c_str())) { + || !path_exists(work_root) || !path_is_directory(work_root)) { // no session output_internal("teardown invalid session [%s]\n", wstr.c_str()); return false; @@ -380,9 +387,9 @@ UnionfsCstore::teardownSession() // remove session directories bool ret = false; try { - if (b_fs::remove_all(work_root) != 0 - && b_fs::remove_all(change_root) != 0 - && b_fs::remove_all(tmp_root) != 0) { + if (b_fs::remove_all(work_root.path_cstr()) != 0 + && b_fs::remove_all(change_root.path_cstr()) != 0 + && b_fs::remove_all(tmp_root.path_cstr()) != 0) { ret = true; } } catch (...) { @@ -400,10 +407,9 @@ UnionfsCstore::teardownSession() bool UnionfsCstore::inSession() { - string wstr = work_root.file_string(); + string wstr = work_root.path_cstr(); return (!wstr.empty() && wstr.find(C_DEF_WORK_PREFIX) == 0 - && path_exists(work_root.file_string().c_str()) - && path_is_directory(work_root.file_string().c_str())); + && path_exists(work_root) && path_is_directory(work_root)); } @@ -414,11 +420,11 @@ UnionfsCstore::inSession() bool UnionfsCstore::tmpl_node_exists() { - return (path_exists(tmpl_path.file_string().c_str()) - && path_is_directory(tmpl_path.file_string().c_str())); + return (path_exists(tmpl_path) && path_is_directory(tmpl_path)); } -typedef Cstore::MapT<string, tr1::shared_ptr<vtw_def> > ParsedTmplCacheT; +typedef Cstore::MapT<FsPath, tr1::shared_ptr<vtw_def>, FsPathHash> + ParsedTmplCacheT; static ParsedTmplCacheT _parsed_tmpl_cache; /* parse template at current tmpl_path and return an allocated Ctemplate @@ -427,14 +433,14 @@ static ParsedTmplCacheT _parsed_tmpl_cache; Ctemplate * UnionfsCstore::tmpl_parse() { - b_fs::path tp = tmpl_path / C_DEF_NAME; - if (!path_exists(tp.file_string().c_str()) - || !path_is_regular(tp.file_string().c_str())) { + FsPath tp = tmpl_path; + tp.push(C_DEF_NAME); + if (!path_exists(tp) || !path_is_regular(tp)) { // invalid return 0; } - ParsedTmplCacheT::iterator p = _parsed_tmpl_cache.find(tp.file_string()); + ParsedTmplCacheT::iterator p = _parsed_tmpl_cache.find(tp); if (p != _parsed_tmpl_cache.end()) { // found in cache return (new Ctemplate(p->second)); @@ -443,9 +449,9 @@ UnionfsCstore::tmpl_parse() // new template => parse tr1::shared_ptr<vtw_def> def(new vtw_def); vtw_def *_def = def.get(); - if (_def && parse_def(_def, tp.file_string().c_str(), 0) == 0) { + if (_def && parse_def(_def, tp.path_cstr(), 0) == 0) { // succes => cache and return - _parsed_tmpl_cache[tp.file_string()] = def; + _parsed_tmpl_cache[tp] = def; return (new Ctemplate(def)); } return 0; @@ -454,9 +460,8 @@ UnionfsCstore::tmpl_parse() bool UnionfsCstore::cfg_node_exists(bool active_cfg) { - b_fs::path p = (active_cfg ? get_active_path() : get_work_path()); - return (path_exists(p.file_string().c_str()) - && path_is_directory(p.file_string().c_str())); + FsPath p = (active_cfg ? get_active_path() : get_work_path()); + return (path_exists(p) && path_is_directory(p)); } bool @@ -464,7 +469,7 @@ UnionfsCstore::add_node() { bool ret = true; try { - if (!b_fs::create_directory(get_work_path())) { + if (!b_fs::create_directory(get_work_path().path_cstr())) { // already exists. shouldn't call this function. ret = false; } @@ -473,7 +478,7 @@ UnionfsCstore::add_node() } if (!ret) { output_internal("failed to add node [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); } return ret; } @@ -481,15 +486,15 @@ UnionfsCstore::add_node() bool UnionfsCstore::remove_node() { - if (!path_exists(get_work_path().file_string().c_str()) - || !path_is_directory(get_work_path().file_string().c_str())) { + if (!path_exists(get_work_path()) + || !path_is_directory(get_work_path())) { output_internal("remove non-existent node [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } bool ret = false; try { - if (b_fs::remove_all(get_work_path()) != 0) { + if (b_fs::remove_all(get_work_path().path_cstr()) != 0) { ret = true; } } catch (...) { @@ -497,7 +502,7 @@ UnionfsCstore::remove_node() } if (!ret) { output_internal("failed to remove node [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); } return ret; } @@ -506,7 +511,7 @@ void UnionfsCstore::get_all_child_node_names_impl(vector<string>& cnodes, bool active_cfg) { - b_fs::path p = (active_cfg ? get_active_path() : get_work_path()); + FsPath p = (active_cfg ? get_active_path() : get_work_path()); get_all_child_dir_names(p, cnodes); /* XXX special cases to emulate original perl API behavior. @@ -530,8 +535,8 @@ UnionfsCstore::get_all_child_node_names_impl(vector<string>& cnodes, bool UnionfsCstore::read_value_vec(vector<string>& vvec, bool active_cfg) { - b_fs::path vpath = (active_cfg ? get_active_path() : get_work_path()); - vpath /= C_VAL_NAME; + FsPath vpath = (active_cfg ? get_active_path() : get_work_path()); + vpath.push(C_VAL_NAME); string ostr; if (!read_whole_file(vpath, ostr)) { @@ -564,14 +569,13 @@ UnionfsCstore::read_value_vec(vector<string>& vvec, bool active_cfg) bool UnionfsCstore::write_value_vec(const vector<string>& vvec, bool active_cfg) { - b_fs::path wp = (active_cfg ? get_active_path() : get_work_path()); - wp /= C_VAL_NAME; + FsPath wp = (active_cfg ? get_active_path() : get_work_path()); + wp.push(C_VAL_NAME); - if (path_exists(wp.file_string().c_str()) - && !path_is_regular(wp.file_string().c_str())) { + if (path_exists(wp) && !path_is_regular(wp)) { // not a file output_internal("failed to write node value (file) [%s]\n", - wp.file_string().c_str()); + wp.path_cstr()); return false; } @@ -584,9 +588,9 @@ UnionfsCstore::write_value_vec(const vector<string>& vvec, bool active_cfg) ostr += vvec[i]; } - if (!write_file(wp.file_string().c_str(), ostr)) { + if (!write_file(wp, ostr)) { output_internal("failed to write node value (write) [%s]\n", - wp.file_string().c_str()); + wp.path_cstr()); return false; } @@ -594,16 +598,16 @@ UnionfsCstore::write_value_vec(const vector<string>& vvec, bool active_cfg) } bool -UnionfsCstore::rename_child_node(const string& oname, const string& nname) +UnionfsCstore::rename_child_node(const char *oname, const char *nname) { - b_fs::path opath = get_work_path() / oname; - b_fs::path npath = get_work_path() / nname; - if (!path_exists(opath.file_string().c_str()) - || !path_is_directory(opath.file_string().c_str()) - || path_exists(npath.file_string().c_str())) { + FsPath opath = get_work_path(); + opath.push(oname); + FsPath npath = get_work_path(); + npath.push(nname); + if (!path_exists(opath) || !path_is_directory(opath) + || path_exists(npath)) { output_internal("cannot rename node [%s,%s,%s]\n", - get_work_path().file_string().c_str(), - oname.c_str(), nname.c_str()); + get_work_path().path_cstr(), oname, nname); return false; } bool ret = true; @@ -614,39 +618,37 @@ UnionfsCstore::rename_child_node(const string& oname, const string& nname) * do it the hard way. */ recursive_copy_dir(opath, npath); - if (b_fs::remove_all(opath) == 0) { + if (b_fs::remove_all(opath.path_cstr()) == 0) { ret = false; } } catch (...) { ret = false; } if (!ret) { - output_internal("failed to rename node [%s,%s]\n", - opath.file_string().c_str(), - npath.file_string().c_str()); + output_internal("failed to rename node [%s,%s]\n", opath.path_cstr(), + npath.path_cstr()); } return ret; } bool -UnionfsCstore::copy_child_node(const string& oname, const string& nname) +UnionfsCstore::copy_child_node(const char *oname, const char *nname) { - b_fs::path opath = get_work_path() / oname; - b_fs::path npath = get_work_path() / nname; - if (!path_exists(opath.file_string().c_str()) - || !path_is_directory(opath.file_string().c_str()) - || path_exists(npath.file_string().c_str())) { + FsPath opath = get_work_path(); + opath.push(oname); + FsPath npath = get_work_path(); + npath.push(nname); + if (!path_exists(opath) || !path_is_directory(opath) + || path_exists(npath)) { output_internal("cannot copy node [%s,%s,%s]\n", - get_work_path().file_string().c_str(), - oname.c_str(), nname.c_str()); + get_work_path().path_cstr(), oname, nname); return false; } try { recursive_copy_dir(opath, npath); } catch (...) { output_internal("failed to copy node [%s,%s,%s]\n", - get_work_path().file_string().c_str(), - oname.c_str(), nname.c_str()); + get_work_path().path_cstr(), oname, nname); return false; } return true; @@ -655,14 +657,15 @@ UnionfsCstore::copy_child_node(const string& oname, const string& nname) bool UnionfsCstore::mark_display_default() { - b_fs::path marker = get_work_path() / C_MARKER_DEF_VALUE; - if (path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEF_VALUE); + if (path_exists(marker)) { // already marked. treat as success. return true; } - if (!create_file(marker.file_string())) { + if (!create_file(marker)) { output_internal("failed to mark default [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -671,16 +674,17 @@ UnionfsCstore::mark_display_default() bool UnionfsCstore::unmark_display_default() { - b_fs::path marker = get_work_path() / C_MARKER_DEF_VALUE; - if (!path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEF_VALUE); + if (!path_exists(marker)) { // not marked. treat as success. return true; } try { - b_fs::remove(marker); + b_fs::remove(marker.path_cstr()); } catch (...) { output_internal("failed to unmark default [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -689,30 +693,31 @@ UnionfsCstore::unmark_display_default() bool UnionfsCstore::marked_display_default(bool active_cfg) { - b_fs::path marker = (active_cfg ? get_active_path() : get_work_path()) - / C_MARKER_DEF_VALUE; - return path_exists(marker.file_string().c_str()); + FsPath marker = (active_cfg ? get_active_path() : get_work_path()); + marker.push(C_MARKER_DEF_VALUE); + return path_exists(marker); } bool UnionfsCstore::marked_deactivated(bool active_cfg) { - b_fs::path p = (active_cfg ? get_active_path() : get_work_path()); - b_fs::path marker = p / C_MARKER_DEACTIVATE; - return path_exists(marker.file_string().c_str()); + FsPath marker = (active_cfg ? get_active_path() : get_work_path()); + marker.push(C_MARKER_DEACTIVATE); + return path_exists(marker); } bool UnionfsCstore::mark_deactivated() { - b_fs::path marker = get_work_path() / C_MARKER_DEACTIVATE; - if (path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEACTIVATE); + if (path_exists(marker)) { // already marked. treat as success. return true; } - if (!create_file(marker.file_string())) { + if (!create_file(marker)) { output_internal("failed to mark deactivated [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -721,16 +726,17 @@ UnionfsCstore::mark_deactivated() bool UnionfsCstore::unmark_deactivated() { - b_fs::path marker = get_work_path() / C_MARKER_DEACTIVATE; - if (!path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEACTIVATE); + if (!path_exists(marker)) { // not deactivated. treat as success. return true; } try { - b_fs::remove(marker); + b_fs::remove(marker.path_cstr()); } catch (...) { output_internal("failed to unmark deactivated [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -742,20 +748,21 @@ UnionfsCstore::unmark_deactivated_descendants() bool ret = false; do { // sanity check - if (!path_is_directory(get_work_path().file_string().c_str())) { + if (!path_is_directory(get_work_path())) { break; } try { vector<b_fs::path> markers; - b_fs::recursive_directory_iterator di(get_work_path()); + b_fs::recursive_directory_iterator di(get_work_path().path_cstr()); for (; di != b_fs::recursive_directory_iterator(); ++di) { if (!path_is_regular(di->path().file_string().c_str()) || di->path().filename() != C_MARKER_DEACTIVATE) { // not marker continue; } - if (di->path().parent_path() == get_work_path()) { + const char *ppath = di->path().parent_path().file_string().c_str(); + if (strcmp(ppath, get_work_path().path_cstr()) == 0) { // don't unmark the node itself continue; } @@ -771,7 +778,7 @@ UnionfsCstore::unmark_deactivated_descendants() } while (0); if (!ret) { output_internal("failed to unmark deactivated descendants [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); } return ret; } @@ -780,29 +787,27 @@ UnionfsCstore::unmark_deactivated_descendants() bool UnionfsCstore::mark_changed_with_ancestors() { - b_fs::path opath = mutable_cfg_path; // use a copy + FsPath opath = mutable_cfg_path; // use a copy bool done = false; while (!done) { - b_fs::path marker = work_root; + FsPath marker = work_root; if (opath.has_parent_path()) { marker /= opath; pop_path(opath); } else { done = true; } - if (!path_exists(marker.file_string().c_str()) - || !path_is_directory(marker.file_string().c_str())) { + if (!path_exists(marker) || !path_is_directory(marker)) { // don't do anything if the node is not there continue; } - marker /= C_MARKER_CHANGED; - if (path_exists(marker.file_string().c_str())) { + marker.push(C_MARKER_CHANGED); + if (path_exists(marker)) { // reached a node already marked => done break; } - if (!create_file(marker.file_string())) { - output_internal("failed to mark changed [%s]\n", - marker.file_string().c_str()); + if (!create_file(marker)) { + output_internal("failed to mark changed [%s]\n", marker.path_cstr()); return false; } } @@ -817,7 +822,7 @@ UnionfsCstore::unmark_changed_with_descendants() { try { vector<b_fs::path> markers; - b_fs::recursive_directory_iterator di(get_work_path()); + b_fs::recursive_directory_iterator di(get_work_path().path_cstr()); for (; di != b_fs::recursive_directory_iterator(); ++di) { if (!path_is_regular(di->path().file_string().c_str()) || di->path().filename() != C_MARKER_CHANGED) { @@ -831,7 +836,7 @@ UnionfsCstore::unmark_changed_with_descendants() } } catch (...) { output_internal("failed to unmark changed with descendants [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -841,15 +846,15 @@ UnionfsCstore::unmark_changed_with_descendants() bool UnionfsCstore::remove_comment() { - b_fs::path cfile = get_work_path() / C_COMMENT_FILE; - if (!path_exists(cfile.file_string().c_str())) { + FsPath cfile = get_work_path(); + cfile.push(C_COMMENT_FILE); + if (!path_exists(cfile)) { return false; } try { - b_fs::remove(cfile); + b_fs::remove(cfile.path_cstr()); } catch (...) { - output_internal("failed to remove comment [%s]\n", - cfile.file_string().c_str()); + output_internal("failed to remove comment [%s]\n", cfile.path_cstr()); return false; } return true; @@ -859,8 +864,9 @@ UnionfsCstore::remove_comment() bool UnionfsCstore::set_comment(const string& comment) { - b_fs::path cfile = get_work_path() / C_COMMENT_FILE; - return write_file(cfile.file_string(), comment); + FsPath cfile = get_work_path(); + cfile.push(C_COMMENT_FILE); + return write_file(cfile, comment); } // discard all changes in working config @@ -875,7 +881,7 @@ UnionfsCstore::discard_changes(unsigned long long& num_removed) vector<b_fs::path> directories; try { // iterate through all entries in change root - b_fs::directory_iterator di(change_root); + b_fs::directory_iterator di(change_root.path_cstr()); for (; di != b_fs::directory_iterator(); ++di) { if (path_is_directory(di->path().file_string().c_str())) { directories.push_back(di->path()); @@ -894,8 +900,7 @@ UnionfsCstore::discard_changes(unsigned long long& num_removed) num_removed += b_fs::remove_all(directories[i]); } } catch (...) { - output_internal("discard failed [%s]\n", - change_root.file_string().c_str()); + output_internal("discard failed [%s]\n", change_root.path_cstr()); ret = false; } @@ -911,8 +916,8 @@ UnionfsCstore::discard_changes(unsigned long long& num_removed) bool UnionfsCstore::get_comment(string& comment, bool active_cfg) { - b_fs::path cfile = (active_cfg ? get_active_path() : get_work_path()); - cfile /= C_COMMENT_FILE; + FsPath cfile = (active_cfg ? get_active_path() : get_work_path()); + cfile.push(C_COMMENT_FILE); return read_whole_file(cfile, comment); } @@ -920,8 +925,9 @@ UnionfsCstore::get_comment(string& comment, bool active_cfg) bool UnionfsCstore::cfg_node_changed() { - b_fs::path marker = get_work_path() / C_MARKER_CHANGED; - return path_exists(marker.file_string().c_str()); + FsPath marker = get_work_path(); + marker.push(C_MARKER_CHANGED); + return path_exists(marker); } /* XXX currently "committed marking" is done inside commit. @@ -934,14 +940,17 @@ UnionfsCstore::cfg_node_changed() * be only one operation on the path). */ bool -UnionfsCstore::marked_committed(const Ctemplate *def, bool is_set) +UnionfsCstore::marked_committed(const tr1::shared_ptr<Ctemplate>& def, + bool is_set) { - b_fs::path cpath = mutable_cfg_path; - string com_str = cpath.file_string() + "/"; + FsPath cpath = mutable_cfg_path; + string com_str = cpath.path_cstr(); + com_str += "/"; if (def->isLeafValue()) { // path includes leaf value. construct the right string. - string val = _unescape_path_name(cpath.filename()); - cpath = cpath.parent_path(); + string val; + cpath.pop(val); + val = _unescape_path_name(val); /* XXX current commit implementation escapes value strings for * single-value nodes but not for multi-value nodes for some * reason. the following match current behavior. @@ -949,14 +958,17 @@ UnionfsCstore::marked_committed(const Ctemplate *def, bool is_set) if (!def->isMulti()) { val = _escape_path_name(val); } - com_str = cpath.file_string() + "/value:" + val; + com_str = cpath.path_cstr(); + com_str += "/value:"; + com_str += val; } com_str = (is_set ? "+ " : "- ") + com_str; return committed_marker_exists(com_str); } bool -UnionfsCstore::validate_val_impl(const Ctemplate *def, char *value) +UnionfsCstore::validate_val_impl(const tr1::shared_ptr<Ctemplate>& def, + char *value) { /* XXX filesystem paths/accesses are completely embedded in var ref lib. * for now, treat the lib as a unionfs-specific implementation. @@ -971,16 +983,23 @@ UnionfsCstore::validate_val_impl(const Ctemplate *def, char *value) } void -UnionfsCstore::get_edit_level(vector<string>& pcomps) { - b_fs::path opath = mutable_cfg_path; // use a copy +UnionfsCstore::get_edit_level(Cpath& pcomps) { + FsPath opath = mutable_cfg_path; // use a copy + vector<string> tmp; while (opath.has_parent_path()) { - pcomps.insert(pcomps.begin(), pop_path(opath)); + string last; + pop_path(opath, last); + tmp.push_back(last); + } + while (tmp.size() > 0) { + pcomps.push(tmp.back()); + tmp.pop_back(); } } string UnionfsCstore::cfg_path_to_str() { - string cpath = mutable_cfg_path.file_string(); + string cpath = mutable_cfg_path.path_cstr(); if (cpath.length() == 0) { cpath = "/"; } @@ -990,8 +1009,8 @@ UnionfsCstore::cfg_path_to_str() { string UnionfsCstore::tmpl_path_to_str() { // return only the mutable part - string tpath = tmpl_path.file_string(); - tpath.erase(0, tmpl_root.file_string().length()); + string tpath = tmpl_path.path_cstr(); + tpath.erase(0, tmpl_root.length()); if (tpath.length() == 0) { tpath = "/"; } @@ -1001,33 +1020,35 @@ UnionfsCstore::tmpl_path_to_str() { ////// private functions void -UnionfsCstore::push_path(b_fs::path& old_path, const string& new_comp) +UnionfsCstore::push_path(FsPath& old_path, const char *new_comp) { string comp = _escape_path_name(new_comp); - old_path /= comp; + old_path.push(comp); } -string -UnionfsCstore::pop_path(b_fs::path& path) +void +UnionfsCstore::pop_path(FsPath& path) { - string ret = _unescape_path_name(path.filename()); - /* note: contrary to documentation, remove_filename() does not remove - * trailing slash. - */ - path = path.parent_path(); - return ret; + path.pop(); } void -UnionfsCstore::get_all_child_dir_names(b_fs::path root, vector<string>& nodes) +UnionfsCstore::pop_path(FsPath& path, string& last) { - if (!path_exists(root.file_string().c_str()) - || !path_is_directory(root.file_string().c_str())) { + path.pop(last); + last = _unescape_path_name(last); +} + +void +UnionfsCstore::get_all_child_dir_names(const FsPath& root, + vector<string>& nodes) +{ + if (!path_exists(root) || !path_is_directory(root)) { // not a valid root. nop. return; } try { - b_fs::directory_iterator di(root); + b_fs::directory_iterator di(root.path_cstr()); for (; di != b_fs::directory_iterator(); ++di) { // must be directory if (!path_is_directory(di->path().file_string().c_str())) { @@ -1047,7 +1068,7 @@ UnionfsCstore::get_all_child_dir_names(b_fs::path root, vector<string>& nodes) } bool -UnionfsCstore::write_file(const string& file, const string& data) +UnionfsCstore::write_file(const FsPath& file, const string& data) { if (data.size() > C_UNIONFS_MAX_FILE_SIZE) { output_internal("write_file too large\n"); @@ -1055,13 +1076,14 @@ UnionfsCstore::write_file(const string& file, const string& data) } try { // make sure the path exists - b_fs::path fpath(file); - b_fs::create_directories(fpath.parent_path()); + FsPath ppath(file); + ppath.pop(); + b_fs::create_directories(ppath.path_cstr()); // write the file ofstream fout; fout.exceptions(ofstream::failbit | ofstream::badbit); - fout.open(file.c_str(), ios_base::out | ios_base::trunc); + fout.open(file.path_cstr(), ios_base::out | ios_base::trunc); fout << data; fout.close(); } catch (...) { @@ -1071,23 +1093,22 @@ UnionfsCstore::write_file(const string& file, const string& data) } bool -UnionfsCstore::read_whole_file(const b_fs::path& fpath, string& data) +UnionfsCstore::read_whole_file(const FsPath& fpath, string& data) { /* must exist, be a regular file, and smaller than limit (we're going * to read the whole thing). */ - if (!path_exists(fpath.file_string().c_str()) - || !path_is_regular(fpath.file_string().c_str())) { + if (!path_exists(fpath) || !path_is_regular(fpath)) { return false; } try { - if (b_fs::file_size(fpath) > C_UNIONFS_MAX_FILE_SIZE) { + if (b_fs::file_size(fpath.path_cstr()) > C_UNIONFS_MAX_FILE_SIZE) { output_internal("read_whole_file too large\n"); return false; } stringbuf sbuf; - ifstream fin(fpath.file_string().c_str()); + ifstream fin(fpath.path_cstr()); fin >> &sbuf; fin.close(); /* note: if file contains just a newline => (eof() && fail()) @@ -1132,22 +1153,21 @@ UnionfsCstore::committed_marker_exists(const string& marker) * will throw exception (from b_fs) if fail. */ void -UnionfsCstore::recursive_copy_dir(const b_fs::path& src, const b_fs::path& dst) +UnionfsCstore::recursive_copy_dir(const FsPath& src, const FsPath& dst) { - string src_str = src.file_string(); - string dst_str = dst.file_string(); - b_fs::create_directory(dst); + string src_str = src.path_cstr(); + string dst_str = dst.path_cstr(); + b_fs::create_directory(dst.path_cstr()); - b_fs::recursive_directory_iterator di(src); + b_fs::recursive_directory_iterator di(src_str); for (; di != b_fs::recursive_directory_iterator(); ++di) { - b_fs::path opath = di->path(); - string nname = opath.file_string(); + const char *oname = di->path().file_string().c_str(); + string nname = oname; nname.replace(0, src_str.length(), dst_str); - b_fs::path npath = nname; - if (path_is_directory(opath.file_string().c_str())) { - b_fs::create_directory(npath); + if (path_is_directory(oname)) { + b_fs::create_directory(nname); } else { - b_fs::copy_file(opath, npath); + b_fs::copy_file(oname, nname); } } } @@ -1182,3 +1202,6 @@ UnionfsCstore::path_is_regular(const char *path) return b_fs::is_regular(result); } +} // end namespace unionfs +} // end namespace cstore + diff --git a/src/cstore/unionfs/cstore-unionfs.hpp b/src/cstore/unionfs/cstore-unionfs.hpp index 53c6396..afb65a6 100644 --- a/src/cstore/unionfs/cstore-unionfs.hpp +++ b/src/cstore/unionfs/cstore-unionfs.hpp @@ -28,8 +28,10 @@ #include <cli_cstore.h> #include <cstore/cstore.hpp> +#include <cstore/unionfs/fspath.hpp> namespace cstore { // begin namespace cstore +namespace unionfs { // begin namespace unionfs namespace b_fs = boost::filesystem; namespace b_s = boost::system; @@ -80,21 +82,19 @@ private: static const size_t C_UNIONFS_MAX_FILE_SIZE = 262144; // root dirs (constant) - b_fs::path work_root; // working root (union) - b_fs::path active_root; // active root (readonly part of union) - b_fs::path change_root; // change root (r/w part of union) - b_fs::path tmp_root; // temp root - b_fs::path tmpl_root; // template root + FsPath work_root; // working root (union) + FsPath active_root; // active root (readonly part of union) + FsPath change_root; // change root (r/w part of union) + FsPath tmp_root; // temp root + FsPath tmpl_root; // template root // path buffers - b_fs::path mutable_cfg_path; // mutable part of config path - b_fs::path tmpl_path; // whole template path - Cstore::MapT<const void *, pair<b_fs::path, b_fs::path> > saved_paths; - // saved mutable part of cfg path and whole template path + FsPath mutable_cfg_path; // mutable part of config path + FsPath tmpl_path; // whole template path ////// virtual functions defined in base class // begin path modifiers - void push_tmpl_path(const string& new_comp) { + void push_tmpl_path(const char *new_comp) { push_path(tmpl_path, new_comp); }; void push_tmpl_path_tag() { @@ -105,18 +105,24 @@ private: * however, since current C_TAG_NAME doesn't contain any escape * sequences, this cannot happen for now. */ - tmpl_path /= C_TAG_NAME; + tmpl_path.push(C_TAG_NAME); }; - string pop_tmpl_path() { - return pop_path(tmpl_path); + void pop_tmpl_path() { + pop_path(tmpl_path); }; - void push_cfg_path(const string& new_comp) { + void pop_tmpl_path(string& last) { + pop_path(tmpl_path, last); + }; + void push_cfg_path(const char *new_comp) { push_path(mutable_cfg_path, new_comp); }; - string pop_cfg_path() { - return pop_path(mutable_cfg_path); + void pop_cfg_path() { + pop_path(mutable_cfg_path); + }; + void pop_cfg_path(string& last) { + pop_path(mutable_cfg_path, last); }; - void append_cfg_path(const vector<string>& path_comps) { + void append_cfg_path(const Cpath& path_comps) { for (size_t i = 0; i < path_comps.size(); i++) { push_cfg_path(path_comps[i]); } @@ -125,27 +131,31 @@ private: tmpl_path = tmpl_root; mutable_cfg_path = ""; }; - void save_paths(const void *handle = NULL) { - pair<b_fs::path, b_fs::path> p; - p.first = mutable_cfg_path; - p.second = tmpl_path; - saved_paths[handle] = p; - }; - void restore_paths(const void *handle = NULL) { - Cstore::MapT<const void *, pair<b_fs::path, b_fs::path> >::iterator it - = saved_paths.find(handle); - if (it == saved_paths.end()) { - exit_internal("restore_paths: handle not found\n"); - } - pair<b_fs::path, b_fs::path> p = it->second; - mutable_cfg_path = p.first; - tmpl_path = p.second; + + class UnionfsSavePaths : public SavePaths { + public: + UnionfsSavePaths(UnionfsCstore *cs) + : cstore(cs), cpath(cs->mutable_cfg_path), tpath(cs->tmpl_path) {}; + + ~UnionfsSavePaths() { + cstore->mutable_cfg_path = cpath; + cstore->tmpl_path = tpath; + }; + + private: + UnionfsCstore *cstore; + FsPath cpath; + FsPath tpath; }; + auto_ptr<SavePaths> create_save_paths() { + return auto_ptr<SavePaths>(new UnionfsSavePaths(this)); + }; + bool cfg_path_at_root() { return (!mutable_cfg_path.has_parent_path()); }; bool tmpl_path_at_root() { - return (tmpl_path.file_string() == tmpl_root.file_string()); + return (tmpl_path == tmpl_root); }; // end path modifiers @@ -161,8 +171,8 @@ private: get_all_child_dir_names(tmpl_path, cnodes); }; bool write_value_vec(const vector<string>& vvec, bool active_cfg); - bool rename_child_node(const string& oname, const string& nname); - bool copy_child_node(const string& oname, const string& nname); + bool rename_child_node(const char *oname, const char *nname); + bool copy_child_node(const char *oname, const char *nname); bool mark_display_default(); bool unmark_display_default(); bool mark_deactivated(); @@ -185,10 +195,10 @@ private: bool marked_display_default(bool active_cfg); // observers during commit operation - bool marked_committed(const Ctemplate *def, bool is_set); + bool marked_committed(const tr1::shared_ptr<Ctemplate>& def, bool is_set); // these operate on both current tmpl and work paths - bool validate_val_impl(const Ctemplate *def, char *value); + bool validate_val_impl(const tr1::shared_ptr<Ctemplate>& def, char *value); // observers for "edit/tmpl levels" (for "edit"-related operations). // note that these should be moved to base class in the future. @@ -198,7 +208,7 @@ private: string get_tmpl_level_path() { return tmpl_path_to_str(); }; - void get_edit_level(vector<string>& path_comps); + void get_edit_level(Cpath& path_comps); bool edit_level_at_root() { return cfg_path_at_root(); }; @@ -208,19 +218,20 @@ private: string tmpl_path_to_str(); ////// private functions - b_fs::path get_work_path() { return (work_root / mutable_cfg_path); }; - b_fs::path get_active_path() { return (active_root / mutable_cfg_path); }; - b_fs::path get_change_path() { return (change_root / mutable_cfg_path); }; - void push_path(b_fs::path& old_path, const string& new_comp); - string pop_path(b_fs::path& path); - void get_all_child_dir_names(b_fs::path root, vector<string>& nodes); - bool write_file(const string& file, const string& data); - bool create_file(const string& file) { + FsPath get_work_path() { return (work_root / mutable_cfg_path); }; + FsPath get_active_path() { return (active_root / mutable_cfg_path); }; + FsPath get_change_path() { return (change_root / mutable_cfg_path); }; + void push_path(FsPath& old_path, const char *new_comp); + void pop_path(FsPath& path); + void pop_path(FsPath& path, string& last); + void get_all_child_dir_names(const FsPath& root, vector<string>& nodes); + bool write_file(const FsPath& file, const string& data); + bool create_file(const FsPath& file) { return write_file(file, ""); }; - bool read_whole_file(const b_fs::path& file, string& data); + bool read_whole_file(const FsPath& file, string& data); bool committed_marker_exists(const string& marker); - void recursive_copy_dir(const b_fs::path& src, const b_fs::path& dst); + void recursive_copy_dir(const FsPath& src, const FsPath& dst); // boost fs operations wrappers bool b_fs_get_file_status(const char *path, b_fs::file_status& fs) { @@ -229,10 +240,20 @@ private: return (!ec); }; bool path_exists(const char *path); + bool path_exists(const FsPath& path) { + return path_exists(path.path_cstr()); + }; bool path_is_directory(const char *path); + bool path_is_directory(const FsPath& path) { + return path_is_directory(path.path_cstr()); + }; bool path_is_regular(const char *path); + bool path_is_regular(const FsPath& path) { + return path_is_regular(path.path_cstr()); + }; }; +} // end namespace unionfs } // end namespace cstore #endif /* _CSTORE_UNIONFS_H_ */ diff --git a/src/cstore/unionfs/fspath.hpp b/src/cstore/unionfs/fspath.hpp new file mode 100644 index 0000000..35985ed --- /dev/null +++ b/src/cstore/unionfs/fspath.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 Vyatta, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _FSPATH_HPP_ +#define _FSPATH_HPP_ +#include <string> + +#include <cstore/svector.hpp> + +namespace cstore { // begin namespace cstore +namespace unionfs { // begin namespace unionfs + +class FsPath { +public: + FsPath() : _data() {}; + explicit FsPath(const char *full_path) : _data() { operator=(full_path); }; + explicit FsPath(const std::string& full_path) : _data() { + operator=(full_path); + }; + FsPath(const FsPath& p) : _data() { operator=(p); }; + ~FsPath() {}; + + void push(const char *comp) { _data.push_back(comp); }; + void push(const std::string& comp) { _data.push_back(comp.c_str()); }; + void pop() { _data.pop_back(); }; + void pop(std::string& last) { _data.pop_back(last); }; + + FsPath& operator=(const char *full_path) { + _data = full_path; + return *this; + }; + FsPath& operator=(const std::string& full_path) { + _data = full_path; + return *this; + }; + FsPath& operator=(const FsPath& p) { + _data = p._data; + return *this; + }; + FsPath& operator/=(const FsPath& p) { + _data /= p._data; + return *this; + } + FsPath operator/(const FsPath& rhs) { + FsPath lhs(*this); + lhs /= rhs; + return lhs; + }; + + bool operator==(const FsPath& rhs) const { + return (_data == rhs._data); + }; + + size_t length() const { return _data.length(); }; + bool has_parent_path() const { return (_data.size() > 0); }; + const char *path_cstr() const { return _data.get_cstr(); }; + size_t hash() const { return _data.hash(); }; + +private: + struct FsPathParams { + static const char separator = '/'; + static const size_t static_num_elems = 24; + static const size_t static_buf_len = 256; + }; + + cstore::svector<FsPathParams> _data; +}; + +struct FsPathHash { + inline size_t operator()(const FsPath& p) const { + return p.hash(); + }; +}; + +} // end namespace unionfs +} // end namespace cstore + +#endif /* _FSPATH_HPP_ */ + |