]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- partial work on dealing with extended attributes and symbolic links
authorOndrej Kozina <okozina@redhat.com>
Wed, 6 Feb 2013 18:37:06 +0000 (19:37 +0100)
committerOndrej Kozina <okozina@redhat.com>
Wed, 27 Feb 2013 16:30:10 +0000 (17:30 +0100)
snapper/XAttributes.cc
snapper/XAttributes.h

index 940cc270d281f87b62e60bb11e1da84dcc5722a7..bd737dec35bb3cbb04690e1a171d5e1896da3777 100644 (file)
 
 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<char> 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<uint8_t> 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)
     {
index ef2411a0f58c0325cccd2b07d9ad690362328f88..00e9d376f23adbb205cab12f5c8af9a7d1b3eb87 100644 (file)
 #include <vector>
 #include <string>
 #include <iostream>
+#include <functional>
 
 #include <stdint.h>
+#include <sys/types.h>
 
 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<int(const string&, const xa_value_t&, int)> xattr_set_cb_t;
+        typedef std::function<int(const string&)> 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(); };