From: Ondrej Kozina Date: Mon, 18 Feb 2013 12:29:04 +0000 (+0100) Subject: - simplify XA comparison (use only syscalls prefixed with 'l' to deal with links) X-Git-Tag: v0.1.3~18^2~27 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=c1f7bcb684bcb529b2f1041e0423cde35cb34fb3;p=thirdparty%2Fsnapper.git - simplify XA comparison (use only syscalls prefixed with 'l' to deal with links) --- diff --git a/client/snapper.cc b/client/snapper.cc index 8cf627bd..f55eb00e 100644 --- a/client/snapper.cc +++ b/client/snapper.cc @@ -1125,19 +1125,8 @@ help_xa_diff() void print_xa_diff(const string loc_pre, const string loc_post) { - int src_fd = open(loc_pre.c_str(), O_RDONLY | O_NOATIME | O_NOFOLLOW); - if (src_fd < 0) - cerr << "Can't open " << loc_pre << stringerror(errno) << endl; - - int dest_fd = open(loc_post.c_str(), O_RDONLY | O_NOATIME | O_NOFOLLOW); - if (dest_fd < 0) - { - close(src_fd); - cerr << "Can't open " << loc_post << stringerror(errno) << endl; - } - try { - XAModification xa_mod = XAModification(XAttributes(src_fd), XAttributes(dest_fd)); + XAModification xa_mod = XAModification(XAttributes(loc_pre), XAttributes(loc_post)); if (xa_mod.isEmpty()) y2deb("XA Modification object is empty!"); cout << "extended attributes diff:" << endl << "--- " << loc_pre << endl << "+++ " << loc_post << endl << xa_mod; diff --git a/snapper/Compare.cc b/snapper/Compare.cc index 0f405491..8c48ead4 100644 --- a/snapper/Compare.cc +++ b/snapper/Compare.cc @@ -202,6 +202,20 @@ namespace snapper { if (!cmpFilesContent(file1, stat1, file2, stat2)) status |= CONTENT; + +#ifdef ENABLE_XATTRS + /* TODO: think about this. Do you want to report + * XA modification in case the compared files differ + * in their types file A: link, file B: directory + */ + if (file1.xaSupported() && file2.xaSupported()) + { + if (!cmpFilesXattrs(file1, stat1, file2, stat2)) + { + status |= XATTRS; + } + } +#endif } if ((stat1.st_mode ^ stat2.st_mode) & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | @@ -220,18 +234,6 @@ namespace snapper status |= GROUP; } -#ifdef ENABLE_XATTRS - if (file1.xaSupported() && file2.xaSupported()) - { - // TODO: think about how XATTRS are related to - // to other status changes... - if (!cmpFilesXattrs(file1, file2)) - { - status |= XATTRS; - } - } -#endif - return status; } @@ -471,19 +473,41 @@ namespace snapper #ifdef ENABLE_XATTRS bool - cmpFilesXattrs(const SFile& file1, const SFile& file2) + cmpFilesXattrs(const SFile& file1, const struct stat& stat1, const SFile& file2, const struct stat& stat2) + { + if ((stat1.st_mode & S_IFMT) != (stat2.st_mode & S_IFMT)) + throw LogicErrorException(); + + bool retval; + + try + { + XAttributes xa(file1.fullname(true)), xb(file2.fullname(true)); + retval = (xa == xb); + } + catch (XAttributesException xae) + { + y2err("extended attributes compare failed"); + retval = false; + } + + return retval; + } + +/* + bool cmpFilesXattrsLnk(const SFile& file1, const SFile& file2) { - int fd1 = file1.open(O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC); + int fd1 = file1.open(O_RDONLY | O_NOATIME | O_CLOEXEC); if (fd1 < 0) { - y2err("open failed path:" << file1.fullname() << " errno:" << errno); + y2err("Can't open link: " << file1.fullname() << " w/ error: " << stringerror(errno)); throw IOErrorException(); } - int fd2 = file2.open(O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC); + int fd2 = file2.open(O_RDONLY | O_NOATIME | O_CLOEXEC); if (fd2 < 0) { - y2err("open failed path:" << file2.fullname() << " errno:" << errno); + y2err("Can't open link:" << file2.fullname() << " w/ error: " << stringerror(errno)); close(fd1); throw IOErrorException(); } @@ -497,6 +521,7 @@ namespace snapper } catch (XAttributesException xae) { + y2err("extended attributes compare failed"); retval = false; } close(fd1); @@ -504,5 +529,6 @@ namespace snapper return retval; } +*/ #endif } diff --git a/snapper/Compare.h b/snapper/Compare.h index b88c4302..f831b219 100644 --- a/snapper/Compare.h +++ b/snapper/Compare.h @@ -50,7 +50,7 @@ namespace snapper #ifdef ENABLE_XATTRS bool - cmpFilesXattrs(const SFile&, const SFile&); + cmpFilesXattrs(const SFile&, const struct stat&, const SFile&, const struct stat&); #endif } diff --git a/snapper/File.cc b/snapper/File.cc index ff30d2fc..d5e916ae 100644 --- a/snapper/File.cc +++ b/snapper/File.cc @@ -526,18 +526,17 @@ namespace snapper } #ifdef ENABLE_XATTRS - bool - File::modifyXattributes() const +/* bool + File::modifyXattributesReg() const { - - int src_fd = open(getAbsolutePath(LOC_PRE).c_str(), O_RDONLY | O_CLOEXEC); + int src_fd = open(getAbsolutePath(LOC_PRE).c_str(), O_RDONLY | O_NOFOLLOW | 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); + int dest_fd = open(getAbsolutePath(LOC_SYSTEM).c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC); if (dest_fd < 0) { y2err("open failed errno:" << errno << " (" << stringerror(errno) << ")"); @@ -557,7 +556,7 @@ namespace snapper XAModification xa_mod(xa_src, xa_dest); y2deb("xa_modmap(xa_dest) object: " << xa_mod); - ret_val = xa_mod.serializeTo(dest_fd); + ret_val = xa_mod.serializeToFd(dest_fd); } catch (XAttributesException xae) { ret_val = false; @@ -568,6 +567,49 @@ namespace snapper return ret_val; } + + bool + File::modifyXattributesLink() const + { + bool ret_val; + + try { + XAttributes xa_src(getAbsolutePath(LOC_PRE)), xa_dest(getAbsolutePath(LOC_SYSTEM)); + y2deb("xa_src object: " << xa_src << std::endl << "xa_dest object: " << xa_dest); + + XAModification xa_mod(xa_src, xa_dest); + y2deb("xa_modmap(xa_dest) object: " << xa_mod); + + ret_val = xa_mod.serializeToLink(getAbsolutePath(LOC_SYSTEM)); + } + catch (XAttributesException xae) { + ret_val = false; + } + + return ret_val; + } +*/ + bool + File::modifyXattributes() const + { + bool ret_val; + + try { + XAttributes xa_src(getAbsolutePath(LOC_PRE)), xa_dest(getAbsolutePath(LOC_SYSTEM)); + y2deb("xa_src object: " << xa_src << std::endl << "xa_dest object: " << xa_dest); + + XAModification xa_mod(xa_src, xa_dest); + y2deb("xa_modmap(xa_dest) object: " << xa_mod); + + ret_val = xa_mod.serializeTo(getAbsolutePath(LOC_SYSTEM)); + } + catch (XAttributesException xae) { + ret_val = false; + } + + return ret_val; + } + #endif bool @@ -594,8 +636,12 @@ namespace snapper } #ifdef ENABLE_XATTRS - // NOTE: XATTR flasg must not be set w/ CREATED or DELETED flag - if (getPreToPostStatus() & XATTRS) + /* + * xattributes have to be transfered as well + * if we'are about to create new type during + * undo! + */ + if (getPreToPostStatus() & (XATTRS | TYPE | DELETED)) { if (!modifyXattributes()) error = true; diff --git a/snapper/XAttributes.cc b/snapper/XAttributes.cc index 940cc270..211707df 100644 --- a/snapper/XAttributes.cc +++ b/snapper/XAttributes.cc @@ -36,6 +36,7 @@ namespace snapper { + /* TODO: candidate for removal */ XAttributes::XAttributes(int fd) { y2deb("entering Xattributes(int fd) constructor"); @@ -93,6 +94,63 @@ namespace snapper } } + XAttributes::XAttributes(const string &linkpath) + { + y2deb("entering Xattributes(string link) constructor"); + ssize_t size = llistxattr(linkpath.c_str(), NULL, 0); + if (size < 0) + { + y2err("Couldn't get xattributes names-list size. link: " << linkpath << ", error: " << stringerror(errno)); + throw XAttributesException(); + } + + // +1 to cover size == 0 + boost::scoped_array names(new char[size + 1]); + names[size] = '\0'; + + y2deb("XAttributes names-list size is: " << size); + + size = llistxattr(linkpath.c_str(), names.get(), size); + if (size < 0) + { + y2err("Couldn't get xattributes names-list. link: " << linkpath << ", error: " << stringerror(errno)); + throw XAttributesException(); + } + + int pos = 0; + + while (pos < size) + { + string name = string(names.get() + pos); + // move beyond separating '\0' char + pos += name.length() + 1; + + ssize_t v_size = lgetxattr(linkpath.c_str(), name.c_str(), NULL, 0); + if (v_size < 0) + { + y2err("Couldn't get a xattribute value size for the xattribute name '" << name << "': " << stringerror(errno)); + throw XAttributesException(); + } + + y2deb("XAttribute value size for xattribute name: '" << name << "' is " << v_size); + + boost::scoped_array buffer(v_size ? new uint8_t[v_size] : NULL); + + v_size = lgetxattr(linkpath.c_str(), name.c_str(), (void *)buffer.get(), v_size); + if (v_size < 0) + { + y2err("Coudln't get xattrbitue value for the xattrbite name '" << name << "': "); + throw XAttributesException(); + } + + if (!xamap.insert(xa_pair_t(name, xa_value_t(buffer.get(), buffer.get() + v_size))).second) + { + y2err("Duplicite extended attribute name in source file!"); + throw XAttributesException(); + } + } + } + XAttributes::XAttributes(const XAttributes &xa) { y2deb("Starting copy constructor XAttribute(const XAttribute&)"); @@ -250,7 +308,7 @@ namespace snapper } bool - XAModification::serializeTo(int dest_fd) const + XAModification::serializeTo(const string &dest) const { if (this->isEmpty()) return true; @@ -263,7 +321,7 @@ namespace snapper { case XA_DELETE: y2deb("delete xattribute: " << mod_cit->first); - if (fremovexattr(dest_fd, mod_cit->first.c_str())) + if (lremovexattr(dest.c_str(), mod_cit->first.c_str())) { y2err("Couldn't remove xattribute '" << mod_cit->first << "': " << stringerror(errno)); return false; @@ -276,7 +334,7 @@ namespace snapper if (mod_cit->second.empty()) { y2deb("new value for xattribute '" << mod_cit->first << "' is empty!"); - if (fsetxattr(dest_fd, mod_cit->first.c_str(), NULL, 0, XATTR_REPLACE)) + if (lsetxattr(dest.c_str(), mod_cit->first.c_str(), NULL, 0, XATTR_REPLACE)) { y2err("Couldn't replace xattribute '" << mod_cit->first << "' by new (empty) value: " << stringerror(errno)); return false; @@ -285,7 +343,7 @@ namespace snapper else { y2deb("new value for xattribute '" << mod_cit->first << "': " << mod_cit->second); - if (fsetxattr(dest_fd, mod_cit->first.c_str(), &mod_cit->second.front(), mod_cit->second.size(), XATTR_REPLACE)) + if (lsetxattr(dest.c_str(), mod_cit->first.c_str(), &mod_cit->second.front(), mod_cit->second.size(), XATTR_REPLACE)) { y2err("Couldn't replace xattribute '" << mod_cit->first << "' by new (non-empty) value: " << stringerror(errno)); y2deb("new XA value size: " << mod_cit->second.size() << ". The value: " << mod_cit->second); @@ -299,7 +357,7 @@ namespace snapper if (mod_cit->second.empty()) { y2deb("new value for xattribute '" << mod_cit->first << "' is empty!"); - if (fsetxattr(dest_fd, mod_cit->first.c_str(), NULL, 0, XATTR_CREATE)) + if (lsetxattr(dest.c_str(), mod_cit->first.c_str(), NULL, 0, XATTR_CREATE)) { y2err("Couldn't create xattribute '" << mod_cit->first << "' with new (empty) value: " << stringerror(errno)); return false; @@ -308,7 +366,7 @@ namespace snapper else { y2deb("new value for xattribute '" << mod_cit->first << "': " << mod_cit->second); - if (fsetxattr(dest_fd, mod_cit->first.c_str(), &mod_cit->second.front(), mod_cit->second.size(), XATTR_CREATE)) + if (lsetxattr(dest.c_str(), mod_cit->first.c_str(), &mod_cit->second.front(), mod_cit->second.size(), XATTR_CREATE)) { y2err("Couldn't create xattribute '" << mod_cit->first << "' with new (non-empty) value: " << stringerror(errno)); y2deb("new XA value size: " << mod_cit->second.size() << ". The value: " << mod_cit->second); diff --git a/snapper/XAttributes.h b/snapper/XAttributes.h index ef2411a0..9319aeb4 100644 --- a/snapper/XAttributes.h +++ b/snapper/XAttributes.h @@ -46,7 +46,7 @@ namespace snapper // this is ordered on purpose! // we can possibly avoid allocating new fs block if xattrs fits - // into 100 bytes (ext2,3,4) + // into 100 bytes (ext4) // so, first remove/change and create later enum XaCompareFlags { XA_DELETE = 0, @@ -72,6 +72,7 @@ namespace snapper xa_map_t xamap; public: XAttributes(int); + XAttributes(const string&); XAttributes(const XAttributes&); xa_map_citer cbegin() const { return xamap.begin(); } @@ -91,7 +92,7 @@ namespace snapper XAModification(const XAttributes&, const XAttributes&); bool isEmpty() const; - bool serializeTo(int) const; + bool serializeTo(const string&) const; xa_mod_citer cbegin() const { return xamodmap.begin(); }; xa_mod_citer cend() const { return xamodmap.end(); };