]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- add initial support to revert XA changes in between two snapshots
authorOndrej Kozina <okozina@redhat.com>
Fri, 18 Jan 2013 16:29:49 +0000 (17:29 +0100)
committerOndrej Kozina <okozina@redhat.com>
Wed, 27 Feb 2013 16:24:56 +0000 (17:24 +0100)
snapper/File.cc
snapper/File.h
snapper/XAttributes.cc
snapper/XAttributes.h

index 113a94f0a7898c501d3ff922aedfef7a55e2f6b4..d0d75f6f5dde55f3051a74e345e8b04aa55dcdeb 100644 (file)
@@ -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;
 
index 439f12b6d1bb4e4384e3a9425e7bf3962e55a5fd..a1867280b2d4ba6ac38ec4b1736de29656ccff01 100644 (file)
@@ -29,6 +29,8 @@
 #include <string>
 #include <vector>
 
+#include <snapper/XAttributes.h>
+
 
 namespace snapper
 {
@@ -130,6 +132,8 @@ namespace snapper
 
        bool modifyAllTypes() const;
 
+        bool modifyXattributes() const;
+
        const FilePaths* file_paths;
 
        string name;
index 697ede1d8de0e4f605d22465bb01ee9320c3f57b..cfc42588649991e39efa5166a97bb14586b9235a 100644 (file)
 #include <attr/xattr.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <attr/xattr.h>
 #include <fcntl.h>
 #include <unistd.h>
 
+#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<xa_map_citer, bool> 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<xa_map_citer, bool> 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)
     {
index cbfe030de1cfce82f07e0b929d473513ad2d9676..a40c8e04ef396d4226444606781798614d0c04ad 100644 (file)
@@ -39,24 +39,49 @@ namespace snapper
        typedef vector<uint8_t> xa_value_t;
        typedef map<string, xa_value_t> xa_map_t;
        typedef pair<string, xa_value_t> xa_pair_t;
+        typedef pair<uint8_t, string> xa_cmp_pair_t;
+        typedef pair<bool, xa_value_t> xa_find_pair_t;
+        typedef map<uint8_t, string> xa_change_t;
+        // pair<name, mode>
+        //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&);
        };