From: Ondrej Kozina Date: Fri, 18 Jan 2013 16:29:49 +0000 (+0100) Subject: - add initial support to revert XA changes in between two snapshots X-Git-Tag: v0.1.3~18^2~48 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=3e59fe171d3fe30577239d01d9ecd92d468b8daf;p=thirdparty%2Fsnapper.git - add initial support to revert XA changes in between two snapshots --- diff --git a/snapper/File.cc b/snapper/File.cc index 113a94f0..d0d75f6f 100644 --- a/snapper/File.cc +++ b/snapper/File.cc @@ -524,6 +524,42 @@ namespace snapper return true; } + bool + File::modifyXattributes() const + { + + int src_fd = open(getAbsolutePath(LOC_PRE).c_str(), O_RDONLY | O_CLOEXEC); + if (src_fd < 0) + { + y2err("open failed errno:" << errno << " (" << stringerror(errno) << ")"); + return false; + } + + int dest_fd = open(getAbsolutePath(LOC_SYSTEM).c_str(), O_RDWR | O_CLOEXEC); + if (dest_fd < 0) + { + y2err("open failed errno:" << errno << " (" << stringerror(errno) << ")"); + close(src_fd); + return false; + } + + bool ret_val; + + try { + XAttributes xa_src(src_fd), xa_dest(dest_fd); + + xa_dest.generateXaComparison(xa_src); + ret_val = xa_dest.serializeTo(dest_fd); + } + catch (IOErrorException ioe) { + ret_val = false; + } + + close(src_fd); + close(dest_fd); + + return ret_val; + } bool File::doUndo() @@ -548,6 +584,13 @@ namespace snapper error = true; } + // NOTE: XATTR flasg must not be set w/ CREATED or DELETED flag + if (getPreToPostStatus() & XATTRS) + { + if (!modifyXattributes()) + error = true; + } + pre_to_system_status = (unsigned int) -1; post_to_system_status = (unsigned int) -1; diff --git a/snapper/File.h b/snapper/File.h index 439f12b6..a1867280 100644 --- a/snapper/File.h +++ b/snapper/File.h @@ -29,6 +29,8 @@ #include #include +#include + namespace snapper { @@ -130,6 +132,8 @@ namespace snapper bool modifyAllTypes() const; + bool modifyXattributes() const; + const FilePaths* file_paths; string name; diff --git a/snapper/XAttributes.cc b/snapper/XAttributes.cc index 697ede1d..cfc42588 100644 --- a/snapper/XAttributes.cc +++ b/snapper/XAttributes.cc @@ -24,110 +24,277 @@ #include #include #include +#include #include #include +#include "snapper/AppUtil.h" #include "snapper/Exception.h" +#include "snapper/Log.h" namespace snapper { XAttributes::XAttributes() { xamap = new xa_map_t; + xachmap = NULL; } XAttributes::XAttributes(int fd) { - // TODO: change to debug - std::cout << "starting XattrsContainer(int)" << std::endl; + y2deb("entering Xattributes(int fd) constructor"); ssize_t size = flistxattr(fd, NULL, 0); if (size < 0) { - std::cerr << "errno: " << errno << std::endl; + y2err("Couldn't get xattributes names-list size: " << stringerror(errno)); throw IOErrorException(); } // +1 to cover size == 0 char *names = new char[size + 1]; + names[size] = '\0'; + y2deb("XAttributes names-list size is: " << size); + size = flistxattr(fd, names, size); if (size < 0) { - std::cerr << "errno: " << errno << std::endl; + y2err("Couldn't get xattributes names-list: " << stringerror(errno)); throw IOErrorException(); } - // TODO: change to debug - std::cout << "names list size is: " << size << std::endl; - - int pos = 0; - xamap = new xa_map_t; + + int pos = 0; while (pos < size) { string name = string(names + pos); - // step beyond separating '\0' char + // move beyond separating '\0' char pos += name.length() + 1; ssize_t v_size = fgetxattr(fd, name.c_str(), NULL, 0); if (v_size < 0) { - std::cerr << "fgetxattr(0) failed w/ errno: " << errno << std::endl; + y2err("Couldn't get a xattribute value size for the xattribute name '" << name << "': " << stringerror(errno)); throw IOErrorException(); } + + y2deb("XAttribute value size for xattribute name: '" << name << "' is " << size); uint8_t *buffer = new uint8_t[v_size]; - v_size = fgetxattr(fd, name.c_str(), buffer, v_size); + v_size = fgetxattr(fd, name.c_str(), (void *)buffer, v_size); if (v_size < 0) { - std::cerr << "fgetxattr(" << v_size << ") failed w/ errno: " << errno << std::endl; + y2err("Coudln't get xattrbitue value for the xattrbite name '" << name << "': "); throw IOErrorException(); } xa_value_t xa_value(buffer, buffer + v_size); - std::cout << "array size: " << v_size << ", xavalue size: " << xa_value.size() << std::endl; - xamap->insert(xa_pair_t(name, xa_value)); delete[] buffer; } delete[] names; + + xachmap = NULL; } XAttributes::XAttributes(const XAttributes &xa) { - std::cout << "starting copy constructor XattrsContainer(const XattrsContainer&)" << std::endl; + y2deb("Starting copy constructor XAttribute(const XAttribute&)"); xamap = new xa_map_t(*(xa.xamap)); + + if (xa.xachmap) + xachmap = new xa_change_t(*(xa.xachmap)); } XAttributes::~XAttributes() { delete xamap; + delete xachmap; + } + + xa_find_pair_t + XAttributes::find(const string &xa_name) const + { + xa_map_citer cit = xamap->find(xa_name); + if (cit != xamap->end()) + { + return xa_find_pair_t(true, cit->second); + } + + return xa_find_pair_t(false, xa_value_t()); + } + + void + XAttributes::insert(const xa_pair_t &p) + { + pair ret = xamap->insert(p); + if (!ret.second) + y2war("Couldn't insert pair xa_name==" << p.first << ":xa_value==" << p.second); + + } + + void + XAttributes::generateXaComparison(const XAttributes &src_xa) + { + xa_change_t *change_map = new xa_change_t(); + + delete this->xachmap; + + if (*this == src_xa) + { + this->xachmap = change_map; + + return; + } + + xa_map_citer src_cit = src_xa.xamap->begin(); + xa_map_iter it = this->xamap->begin(); + + while (src_cit != src_xa.xamap->end() && it != this->xamap->end()) + { + if (src_cit->first == it->first) + { + if (src_cit->second != it->second) + { + (*change_map)[XA_REPLACE] = src_cit->first; + (*this->xamap)[src_cit->first] = src_cit->second; + } + src_cit++; + it++; + } + else if (src_cit->first < it->first) + { + (*change_map)[XA_CREATE] = src_cit->first; + it = this->xamap->insert(xa_pair_t(src_cit->first, src_cit->second)).first; + + src_cit++; + } + else + { + (*change_map)[XA_DELETE] = src_cit->first; + it = this->xamap->erase(it); + } + } + + while (src_cit != src_xa.xamap->end()) + { + (*change_map)[XA_CREATE] = src_cit->first; + it = this->xamap->insert(xa_pair_t(src_cit->first, src_cit->second)).first; + + src_cit++; + } + + while (it != this->xamap->end()) + { + (*change_map)[XA_DELETE] = it->first; + it = this->xamap->erase(it); + } + + this->xachmap = change_map; + } + + bool + XAttributes::serializeTo(int dest_fd) + { + if (!this->xachmap) + { + y2war("Missing change map!"); + return false; + } + + xa_change_citer cit = this->xachmap->begin(); + + while(cit != this->xachmap->end()) + { + switch (cit->first) + { + case XA_DELETE: + y2deb("delete xattribute: " << cit->second); + if (fremovexattr(dest_fd, cit->second.c_str())) + { + y2err("Couldn't remove xattribute '" << cit->second << "': " << stringerror(errno)); + return false; + } + break; + + case XA_REPLACE: + { + y2deb("replace xattribute: " << cit->second); + xa_find_pair_t fnd = find(cit->second); + if (!fnd.first || fnd.second.empty()) + { + y2war("Internal error: Couldn't find xattribute '" << cit->second << "'"); + return false; + } + y2deb("new value: '" << fnd.second << "'"); + if (fsetxattr(dest_fd, cit->second.c_str(), &fnd.second.front(), fnd.second.size(), XATTR_REPLACE)) + { + y2err("Couldn't replace xattribute '" << cit->second << "' by new value: " << stringerror(errno)); + return false; + } + } + break; + + case XA_CREATE: + { + y2deb("create xattribute: " << cit->second); + xa_find_pair_t fnd = find(cit->second); + if (!fnd.first || fnd.second.empty()) + { + y2war("Internal error: Couldn't find xattribute '" << cit->second << "'"); + return false; + } + y2deb("new value: '" << fnd.second << "'"); + if (fsetxattr(dest_fd, cit->second.c_str(), &fnd.second.front(), fnd.second.size(), XATTR_CREATE)) + { + y2err("Couldn't create xattribute '" << cit->second << "': " << stringerror(errno)); + return false; + } + } + break; + + default: + y2err("Internal Error in XAttributes()"); + return false; + } + cit++; + } + return true; } XAttributes& XAttributes::operator=(const XAttributes &xa) { + y2deb("Entering XAttribute::operator=()"); if (this != &xa) { - std::cout << "This is assignment operator XattrsContainer::operator=()" << std::endl; delete this->xamap; - this->xamap = new xa_map_t(*(xa.xamap)); + + delete this->xachmap; + this->xachmap = NULL; + + if (xa.xachmap) + { + this->xachmap = new xa_change_t(*(xa.xachmap)); + } } return *this; } bool - XAttributes::operator==(const XAttributes &xa) + XAttributes::operator==(const XAttributes& xa) const { - std::cout << "operator==" << std::endl; - return *(this->xamap) == *(xa.xamap); + y2deb("Entering XAttribute::operator==()"); + // do not care about change map. the content is xamap only + return (this == &xa) ? true : (*(this->xamap) == *(xa.xamap)); } ostream& @@ -141,26 +308,15 @@ namespace snapper return out; } - out << "XA container includes:" << std::endl; - while (it != xa.xamap->end()) { - out << "xa name: " << it->first << ", xa value: " << it->second << std::endl; + out << "xa_name: " << it->first << ", xa_value: " << it->second << std::endl; it++; } return out; } - void - XAttributes::insert(const xa_pair_t &p) - { - pair ret = xamap->insert(p); - if (!ret.second) - std::cerr << "couldn't insert '" << p.first << ":" << "'" << p.second << "'" << std::endl; - - } - ostream& operator<<(ostream &out, const xa_value_t &xavalue) { diff --git a/snapper/XAttributes.h b/snapper/XAttributes.h index cbfe030d..a40c8e04 100644 --- a/snapper/XAttributes.h +++ b/snapper/XAttributes.h @@ -39,24 +39,49 @@ namespace snapper typedef vector xa_value_t; typedef map xa_map_t; typedef pair xa_pair_t; + typedef pair xa_cmp_pair_t; + typedef pair xa_find_pair_t; + typedef map xa_change_t; + // pair + //i.e: + // name=acl, mode="create,delete,replace" + // create - whole new XA + // delete - remove XA + // replace - change in xa_value + typedef xa_map_t::iterator xa_map_iter; typedef xa_map_t::const_iterator xa_map_citer; + typedef xa_change_t::const_iterator xa_change_citer; + + // this is ordered on purpose! + // we can possibly avoid allocating new fs block if xattrs fits + // into 100 bytes (ext2,3,4) + // so, first remove/change and create later + enum XaCompareFlags { + XA_DELETE = 0, + XA_REPLACE, + XA_CREATE + }; class XAttributes { private: - xa_map_t *xamap; + xa_map_t *xamap; + xa_change_t *xachmap; public: XAttributes(); XAttributes(int); XAttributes(const XAttributes&); ~XAttributes(); - XAttributes& operator=(const XAttributes&); - bool operator==(const XAttributes&); + xa_find_pair_t find(const string&) const; + void insert(const xa_pair_t&); + void generateXaComparison(const XAttributes&); + bool serializeTo(int); - void insert(const xa_pair_t&); + XAttributes& operator=(const XAttributes&); + bool operator==(const XAttributes&) const; friend ostream& operator<<(ostream&, const XAttributes&); };