From: Ondrej Kozina Date: Wed, 6 Feb 2013 18:37:06 +0000 (+0100) Subject: - partial work on dealing with extended attributes and symbolic links X-Git-Tag: v0.1.3~18^2~29 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=3b8cb2a2022726e04ac09477a90a80360efbcfef;p=thirdparty%2Fsnapper.git - partial work on dealing with extended attributes and symbolic links --- diff --git a/snapper/XAttributes.cc b/snapper/XAttributes.cc index 940cc270..bd737dec 100644 --- a/snapper/XAttributes.cc +++ b/snapper/XAttributes.cc @@ -36,6 +36,55 @@ namespace snapper { + struct XAModification::LinkSetHelper { + const string *plink; + LinkSetHelper(const string &link) : plink(&link) {} + + int operator()(const string&, const xa_value_t&, int); + }; + + int + XAModification::LinkSetHelper::operator()(const string &name, const xa_value_t &value, int flags) + { + // TODO: add logging + if (value.empty()) + return lsetxattr(plink->c_str(), name.c_str(), NULL, 0, flags); + else + return lsetxattr(plink->c_str(), name.c_str(), (void *) &value.front(), value.size(), flags); + } + + struct XAModification::LinkRmHelper { + const string *plink; + LinkRmHelper(const string &link) : plink(&link) {} + + int operator()(const string &name) { return lremovexattr(plink->c_str(), name.c_str()); } + }; + + struct XAModification::FileSetHelper { + const int fd; + FileSetHelper(int fd) : fd(fd) {} + + int operator()(const string&, const xa_value_t&, int); + }; + + int + XAModification::FileSetHelper::operator()(const string &name, const xa_value_t &value, int flags) + { + // TODO: add logging + if (value.empty()) + return fsetxattr(fd, name.c_str(), NULL, 0, flags); + else + return fsetxattr(fd, name.c_str(), (void *) &value.front(), value.size(), flags); + } + + struct XAModification::FileRmHelper { + const int fd; + FileRmHelper(int fd) : fd(fd) {} + + int operator()(const string &name) { return fremovexattr(fd, name.c_str()); } + }; + + XAttributes::XAttributes(int fd) { y2deb("entering Xattributes(int fd) constructor"); @@ -93,10 +142,68 @@ 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&)"); xamap = xa.xamap; + type = xa.type; } XAttributes& @@ -106,6 +213,7 @@ namespace snapper if (this != &xa) { this->xamap = xa.xamap; + type = xa.type; } return *this; @@ -115,6 +223,7 @@ namespace snapper XAttributes::operator==(const XAttributes& xa) const { y2deb("Entering XAttribute::operator==()"); + // TODO: what about file type? return (this == &xa) ? true : (this->xamap == xa.xamap); } @@ -186,6 +295,9 @@ namespace snapper XAModification::XAModification(const snapper::XAttributes& src_xa, const snapper::XAttributes& dest_xa) { + if (src_xa.getType() != dest_xa.getType()) + throw XAttributesException(); + xamodmap[XA_DELETE] = xa_mod_vec_t(); xamodmap[XA_REPLACE] = xa_mod_vec_t(); xamodmap[XA_CREATE] = xa_mod_vec_t(); @@ -250,11 +362,8 @@ namespace snapper } bool - XAModification::serializeTo(int dest_fd) const + XAModification::serializeTo(xattr_set_cb_t set_xattr, xattr_rm_cb_t rm_xattr) const { - if (this->isEmpty()) - return true; - for (xa_mod_citer cit = this->cbegin(); cit != this->cend(); cit++) { for (xa_mod_vec_citer mod_cit = cit->second.begin(); mod_cit != cit->second.end(); mod_cit++) @@ -263,7 +372,7 @@ namespace snapper { case XA_DELETE: y2deb("delete xattribute: " << mod_cit->first); - if (fremovexattr(dest_fd, mod_cit->first.c_str())) + if (rm_xattr(mod_cit->first)) { y2err("Couldn't remove xattribute '" << mod_cit->first << "': " << stringerror(errno)); return false; @@ -273,47 +382,22 @@ namespace snapper case XA_REPLACE: y2deb("replace xattribute: " << mod_cit->first); - 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)) - { - y2err("Couldn't replace xattribute '" << mod_cit->first << "' by new (empty) value: " << stringerror(errno)); - return false; - } - } - else + if (set_xattr(mod_cit->first, mod_cit->second, XATTR_REPLACE)) { - 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)) - { - 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); - return false; - } + y2err("Couldn't replace xattribute '" << mod_cit->first << "'"); + y2deb("replace value was: " << mod_cit->second); + return false; } break; case XA_CREATE: y2deb("create xattribute: " << mod_cit->first); - 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)) - { - y2err("Couldn't create xattribute '" << mod_cit->first << "' with new (empty) value: " << stringerror(errno)); - return false; - } - } - else + + if (set_xattr(mod_cit->first, mod_cit->second, XATTR_CREATE)) { - 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)) - { - 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); - return false; - } + y2err("Couldn't create xattribute '" << mod_cit->first << "'"); + y2deb("new value was: " << mod_cit->second); + return false; } break; @@ -326,6 +410,31 @@ namespace snapper return true; } + bool + XAModification::serializeToFd(int dest_fd) const + { + if (this->isEmpty()) + return true; + + xattr_rm_cb_t rm_cb = FileRmHelper(dest_fd); + xattr_set_cb_t set_cb = FileSetHelper(dest_fd); + + return serializeTo(set_cb, rm_cb); + } + + + bool + XAModification::serializeToLink(const string &link) const + { + if (this->isEmpty()) + return true; + + xattr_rm_cb_t rm_cb = LinkRmHelper(link); + xattr_set_cb_t set_cb = LinkSetHelper(link); + + return serializeTo(set_cb, rm_cb); + } + ostream& operator<<(ostream &out, const XAModification &xa_mod) { diff --git a/snapper/XAttributes.h b/snapper/XAttributes.h index ef2411a0..00e9d376 100644 --- a/snapper/XAttributes.h +++ b/snapper/XAttributes.h @@ -25,8 +25,10 @@ #include #include #include +#include #include +#include namespace snapper { @@ -66,16 +68,24 @@ namespace snapper typedef xa_modification_t::const_iterator xa_mod_citer; typedef xa_mod_vec_t::const_iterator xa_mod_vec_citer; + typedef std::function xattr_set_cb_t; + typedef std::function xattr_rm_cb_t; + class XAttributes { private: xa_map_t xamap; + mode_t type; public: + /* constructor for all but link types */ XAttributes(int); + /* constructor for links */ + XAttributes(const string&); XAttributes(const XAttributes&); xa_map_citer cbegin() const { return xamap.begin(); } xa_map_citer cend() const { return xamap.end(); } + mode_t getType() const { return type; } XAttributes& operator=(const XAttributes&); bool operator==(const XAttributes&) const; @@ -86,12 +96,20 @@ namespace snapper private: xa_modification_t xamodmap; const xa_mod_vec_t& operator[](const uint8_t) const; + + struct LinkSetHelper; + struct LinkRmHelper; + struct FileSetHelper; + struct FileRmHelper; + + bool serializeTo(xattr_set_cb_t, xattr_rm_cb_t) const; public: XAModification(); XAModification(const XAttributes&, const XAttributes&); bool isEmpty() const; - bool serializeTo(int) const; + bool serializeToFd(int) const; + bool serializeToLink(const string&) const; xa_mod_citer cbegin() const { return xamodmap.begin(); }; xa_mod_citer cend() const { return xamodmap.end(); };