#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&
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)
{
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&);
};