#include "snapper/Exception.h"
#include "snapper/Log.h"
+#include <boost/scoped_array.hpp>
+#include <boost/scoped_ptr.hpp>
+
namespace snapper
{
- XAttributes::XAttributes()
- {
- xamap = new xa_map_t;
- xachmap = NULL;
- }
-
XAttributes::XAttributes(int fd)
{
y2deb("entering Xattributes(int fd) constructor");
}
// +1 to cover size == 0
- char *names = new char[size + 1];
+ boost::scoped_array<char> names(new char[size + 1]);
names[size] = '\0';
y2deb("XAttributes names-list size is: " << size);
- size = flistxattr(fd, names, size);
+ size = flistxattr(fd, names.get(), size);
if (size < 0)
{
y2err("Couldn't get xattributes names-list: " << stringerror(errno));
throw IOErrorException();
}
-
- xamap = new xa_map_t;
int pos = 0;
while (pos < size)
{
- string name = string(names + pos);
+ string name = string(names.get() + pos);
// move beyond separating '\0' char
pos += name.length() + 1;
ssize_t v_size = fgetxattr(fd, name.c_str(), NULL, 0);
if (v_size < 0)
{
- y2err("Couldn't get a xattribute value size for the xattribute name '" << name << "': " << stringerror(errno));
+ 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 " << v_size);
- uint8_t *buffer = new uint8_t[v_size];
+ boost::scoped_array<uint8_t> buffer(v_size ? new uint8_t[v_size] : NULL);
- v_size = fgetxattr(fd, name.c_str(), (void *)buffer, v_size);
+ v_size = fgetxattr(fd, name.c_str(), (void *)buffer.get(), v_size);
if (v_size < 0)
{
y2err("Coudln't get xattrbitue value for the xattrbite name '" << name << "': ");
throw IOErrorException();
}
- xa_value_t xa_value(buffer, buffer + v_size);
-
- xamap->insert(xa_pair_t(name, xa_value));
-
- delete[] buffer;
+ 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!");
+ // TODO: possible XAException candidate
+ throw IOErrorException();
+ }
}
-
- delete[] names;
-
- xachmap = NULL;
}
XAttributes::XAttributes(const XAttributes &xa)
{
y2deb("Starting copy constructor XAttribute(const XAttribute&)");
- xamap = new xa_map_t(*(xa.xamap));
-
- if (xa.xachmap)
- xachmap = new xa_change_t(*(xa.xachmap));
+ xamap = xa.xamap;
}
- 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())
+ 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();
- (*change_map)[XA_DELETE] = xa_name_vec_t();
- (*change_map)[XA_REPLACE] = xa_name_vec_t();
- (*change_map)[XA_CREATE] = xa_name_vec_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].push_back(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].push_back(src_cit->first);
- it = this->xamap->insert(xa_pair_t(src_cit->first, src_cit->second)).first;
-
- src_cit++;
- }
- else
- {
- (*change_map)[XA_DELETE].push_back(it->first);
- xa_map_iter tmp = it++;
- this->xamap->erase(tmp);
- }
- }
-
- while (src_cit != src_xa.xamap->end())
- {
- (*change_map)[XA_CREATE].push_back(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].push_back(it->first);
- xa_map_iter tmp = it++;
- it = this->xamap->erase(tmp);
- }
-
- this->xachmap = change_map;
- }
bool
- XAttributes::serializeTo(int dest_fd)
+ XAttributes::serializeModificationsTo(int dest_fd, const XAModification &xa_mods) const
{
- if (!this->xachmap)
+ if (this != xa_mods.getDestination())
{
- y2war("Missing change map!");
return false;
+ // TODO: throw exception: invalid request
}
- xa_change_citer cit = this->xachmap->begin();
-
- while(cit != this->xachmap->end())
+ for (xa_mod_citer cit = xa_mods.cbegin(); cit != xa_mods.cend(); cit++)
{
- xa_name_vec_citer name_cit = cit->second.begin();
-
- switch (cit->first)
+ for (xa_name_vec_citer name_cit = cit->second.begin(); name_cit != cit->second.end(); name_cit++)
{
- case XA_DELETE:
- while (name_cit != cit->second.end())
- {
+ switch (cit->first)
+ {
+ case XA_DELETE:
y2deb("delete xattribute: " << *name_cit);
if (fremovexattr(dest_fd, (*name_cit).c_str()))
{
y2err("Couldn't remove xattribute '" << *name_cit << "': " << stringerror(errno));
return false;
}
- name_cit++;
- }
- break;
+ break;
- case XA_REPLACE:
- while (name_cit != cit->second.end())
- {
+ case XA_REPLACE:
y2deb("replace xattribute: " << *name_cit);
- xa_find_pair_t fnd = find(*name_cit);
- if (!fnd.first)
{
- y2err("Internal error: Couldn't find xattribute '" << *name_cit << "'");
- return false;
- }
- if (fnd.second.empty())
- {
- y2deb("new value for xattribute '" << *name_cit << "' is empty!");
- if (fsetxattr(dest_fd, (*name_cit).c_str(), NULL, 0, XATTR_REPLACE))
+ xa_find_pair_t fnd = find(*name_cit);
+ if (!fnd.first)
{
- y2err("Couldn't replace xattribute '" << *name_cit << "' by new (empty) value: " << stringerror(errno));
+ y2err("Internal error: Couldn't find xattribute '" << *name_cit << "'");
return false;
}
- }
- else
- {
- y2deb("new value: '" << fnd.second << "'");
- if (fsetxattr(dest_fd, (*name_cit).c_str(), &fnd.second.front(), fnd.second.size(), XATTR_REPLACE))
+ if (fnd.second.empty())
{
- y2err("Couldn't replace xattribute by new value: " << stringerror(errno));
- return false;
+ y2deb("new value for xattribute '" << *name_cit << "' is empty!");
+ if (fsetxattr(dest_fd, (*name_cit).c_str(), NULL, 0, XATTR_REPLACE))
+ {
+ y2err("Couldn't replace xattribute '" << *name_cit << "' by new (empty) value: " << stringerror(errno));
+ return false;
+ }
+ }
+ else
+ {
+ y2deb("new value: '" << fnd.second << "'");
+ if (fsetxattr(dest_fd, (*name_cit).c_str(), &fnd.second.front(), fnd.second.size(), XATTR_REPLACE))
+ {
+ y2err("Couldn't replace xattribute by new value: " << stringerror(errno));
+ return false;
+ }
}
}
- name_cit++;
- }
- break;
+ break;
- case XA_CREATE:
- while (name_cit != cit->second.end())
- {
+ case XA_CREATE:
y2deb("create xattribute: " << *name_cit);
- xa_find_pair_t fnd = find(*name_cit);
- if (!fnd.first)
{
- y2err("Internal error: Couldn't find xattribute '" << *name_cit << "'");
- return false;
- }
- if (fnd.second.empty())
- {
- y2deb("new value for xattribute '" << *name_cit << "' is empty!");
- if (fsetxattr(dest_fd, (*name_cit).c_str(), NULL, 0, XATTR_CREATE))
+ xa_find_pair_t fnd = find(*name_cit);
+ if (!fnd.first)
{
- y2err("Couldn't create xattribute '" << *name_cit << "' by new (empty) value: " << stringerror(errno));
+ y2err("Internal error: Couldn't find xattribute '" << *name_cit << "'");
return false;
}
- }
- else
- {
- y2deb("new value: '" << fnd.second << "'");
- if (fsetxattr(dest_fd, (*name_cit).c_str(), &fnd.second.front(), fnd.second.size(), XATTR_CREATE))
+ if (fnd.second.empty())
{
- y2err("Couldn't create xattribute '" << *name_cit << "': " << stringerror(errno));
- return false;
+ y2deb("new value for xattribute '" << *name_cit << "' is empty!");
+ if (fsetxattr(dest_fd, (*name_cit).c_str(), NULL, 0, XATTR_CREATE))
+ {
+ y2err("Couldn't create xattribute '" << *name_cit << "' by new (empty) value: " << stringerror(errno));
+ return false;
+ }
+ }
+ else
+ {
+ y2deb("new value: '" << fnd.second << "'");
+ if (fsetxattr(dest_fd, (*name_cit).c_str(), &fnd.second.front(), fnd.second.size(), XATTR_CREATE))
+ {
+ y2err("Couldn't create xattribute '" << *name_cit << "': " << stringerror(errno));
+ return false;
+ }
}
}
- name_cit++;
- }
- break;
+ break;
- default:
- y2err("Internal Error in XAttributes()");
- return false;
+ default:
+ y2err("Internal Error in XAttributes()");
+ return false;
+ }
}
- cit++;
}
return true;
}
y2deb("Entering XAttribute::operator=()");
if (this != &xa)
{
- 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));
- }
+ this->xamap = xa.xamap;
}
return *this;
XAttributes::operator==(const XAttributes& xa) const
{
y2deb("Entering XAttribute::operator==()");
- // do not care about change map. the content is xamap only
- return (this == &xa) ? true : (*(this->xamap) == *(xa.xamap));
+ return (this == &xa) ? true : (this->xamap == xa.xamap);
}
ostream&
operator<<(ostream &out, const XAttributes &xa)
{
- xa_map_citer it = xa.xamap->begin();
+ xa_map_citer cit = xa.cbegin();
- if (it == xa.xamap->end())
+ if (cit == xa.cend())
out << "(XA container is empty)";
- while (it != xa.xamap->end())
- {
- out << "xa_name: " << it->first << ", xa_value: " << it->second << std::endl;
- it++;
- }
-
- if (xa.xachmap)
- {
- out << "change content: " << std::endl << *xa.xachmap;
- }
+ for (; cit != xa.cend(); cit++)
+ out << "xa_name: " << cit->first << ", xa_value: " << cit->second << std::endl;
return out;
}
}
ostream&
- operator<<(ostream &out, const xa_change_t &xa_change)
+ operator<<(ostream &out, const xa_modification_t &xa_change)
{
- xa_change_citer cit = xa_change.begin();
-
- while (cit != xa_change.end())
+ if (xa_change.find(XA_DELETE)->second.empty() &&
+ xa_change.find(XA_REPLACE)->second.empty() &&
+ xa_change.find(XA_CREATE)->second.empty()
+ )
+ out << "(xa_modification_t is empty)";
+ else
{
- xa_name_vec_citer name_cit = cit->second.begin();
- switch (cit->first)
+ for (xa_mod_citer cit = xa_change.begin(); cit != xa_change.end(); cit++)
{
- case XA_DELETE:
- out << "XA_DELETE";
- break;
- case XA_REPLACE:
- out << "XA_REPLACE";
- break;
- case XA_CREATE:
- out << "XA_CREATE";
- break;
- default:
- out << "unknown";
+ switch (cit->first)
+ {
+ case XA_DELETE:
+ out << "XA_DELETE:";
+ break;
+ case XA_REPLACE:
+ out << "XA_REPLACE:";
+ break;
+ case XA_CREATE:
+ out << "XA_CREATE:";
+ break;
+ default:
+ out << "(!!!unknown!!!)";
+ }
+ for (xa_name_vec_citer name_cit = cit->second.begin(); name_cit != cit->second.end(); name_cit++)
+ out << *name_cit << ',' << std::endl;
}
- out << " mark:" << std::endl;
- while (name_cit != cit->second.end())
- out << *name_cit++ << std::endl;
- cit++;
}
return out;
}
+
+ XAModification::XAModification()
+ {
+ xamodmap[XA_DELETE] = xa_name_vec_t();
+ xamodmap[XA_REPLACE] = xa_name_vec_t();
+ xamodmap[XA_CREATE] = xa_name_vec_t();
+
+ p_xa_dest = NULL;
+ }
+
+ XAModification::XAModification(const XAttributes &src_xa, XAttributes &dest_xa)
+ {
+ xamodmap[XA_DELETE] = xa_name_vec_t();
+ xamodmap[XA_REPLACE] = xa_name_vec_t();
+ xamodmap[XA_CREATE] = xa_name_vec_t();
+
+ xa_map_citer src_cit = src_xa.xamap.begin();
+
+ boost::scoped_ptr<xa_map_t> p_xamap(new xa_map_t(dest_xa.xamap));
+
+ xa_map_iter it = p_xamap->begin();
+
+ while (src_cit != src_xa.xamap.end() && it != p_xamap->end())
+ {
+ y2deb("this src_xa_name: " << src_cit->first);
+ y2deb("this dest_xa_name: " << it->first);
+
+ if (src_cit->first == it->first)
+ {
+ y2deb("names matched");
+ if (src_cit->second != it->second)
+ {
+ y2deb("create XA_REPLACE event");
+ xamodmap[XA_REPLACE].push_back(src_cit->first);
+ (*p_xamap)[it->first] = src_cit->second;
+ }
+ src_cit++;
+ it++;
+ }
+ else if (src_cit->first < it->first)
+ {
+ y2deb("src name < dest name");
+ xamodmap[XA_CREATE].push_back(src_cit->first);
+ it = p_xamap->insert(xa_pair_t(src_cit->first, src_cit->second)).first;
+ if (it != p_xamap->end())
+ y2deb("next dest name is " << it->first);
+
+ src_cit++;
+ }
+ else
+ {
+ y2deb("src name > dest name");
+ xamodmap[XA_DELETE].push_back(it->first);
+ xa_map_iter tmp = it++;
+ p_xamap->erase(tmp);
+ if (it != p_xamap->end())
+ y2deb("next dest name is " << it->first);
+ }
+ }
+
+ if (it != p_xamap->end())
+ {
+ xa_map_iter tmp = it;
+ while (tmp != p_xamap->end())
+ {
+ xamodmap[XA_DELETE].push_back(tmp->first);
+ tmp++;
+ }
+ p_xamap->erase(it, p_xamap->end());
+ }
+
+ while (src_cit != src_xa.xamap.end())
+ {
+ xamodmap[XA_CREATE].push_back(src_cit->first);
+ if (!p_xamap->insert(xa_pair_t(src_cit->first, src_cit->second)).second)
+ {
+ // TODO: throw XA error
+ y2war("Internal error: XA w/ name: '" << src_cit->first << "' already exists");
+ }
+
+ src_cit++;
+ }
+
+ // TODO: how to do atomic change in a sane way?
+ dest_xa.xamap = *p_xamap;
+ this->p_xa_dest = &dest_xa;
+ }
+
+ ostream&
+ operator<<(ostream &out, const XAModification &xa_mod)
+ {
+ return out << xa_mod;
+ }
}
\ No newline at end of file
using std::ostream;
using std::vector;
+ class XAModification;
+ class XAttributes;
+
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 vector<string> xa_name_vec_t;
// create - whole new XA
// delete - remove XA
// replace - change in xa_value
- typedef map<uint8_t, xa_name_vec_t> xa_change_t;
+ typedef map<uint8_t, xa_name_vec_t> xa_modification_t;
// iterators
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;
+ typedef xa_modification_t::const_iterator xa_mod_citer;
typedef xa_name_vec_t::const_iterator xa_name_vec_citer;
class XAttributes
{
private:
- xa_map_t *xamap;
- xa_change_t *xachmap;
- public:
- XAttributes();
- XAttributes(int);
- XAttributes(const XAttributes&);
- ~XAttributes();
-
- xa_find_pair_t find(const string&) const;
- void insert(const xa_pair_t&);
- void generateXaComparison(const XAttributes&);
- bool serializeTo(int);
-
- XAttributes& operator=(const XAttributes&);
- bool operator==(const XAttributes&) const;
-
- friend ostream& operator<<(ostream&, const XAttributes&);
+ xa_map_t xamap;
+ public:
+ XAttributes(int);
+ XAttributes(const XAttributes&);
+
+ xa_map_citer cbegin() const { return xamap.begin(); }
+ xa_map_citer cend() const { return xamap.end(); }
+ xa_find_pair_t find(const string&) const;
+ // this method is not const! (it changes xamap to reflect new state)!
+ bool serializeModificationsTo(int, const XAModification&) const;
+
+ XAttributes& operator=(const XAttributes&);
+ bool operator==(const XAttributes&) const;
+
+ // XAModification is able to atomically modify xamap atribute
+ friend class XAModification;
};
+ class XAModification
+ {
+ private:
+ xa_modification_t xamodmap;
+ const XAttributes *p_xa_dest;
+ public:
+ XAModification();
+ XAModification(const XAttributes&, XAttributes&);
+
+ xa_mod_citer cbegin() const { return xamodmap.begin(); };
+ xa_mod_citer cend() const { return xamodmap.end(); };
+ const XAttributes* getDestination() const { return p_xa_dest; }
+ };
+
+ ostream& operator<<(ostream&, const XAModification&);
+ ostream& operator<<(ostream&, const XAttributes&);
ostream& operator<<(ostream&, const xa_value_t&);
- ostream& operator<<(ostream&, const xa_change_t&);
+ ostream& operator<<(ostream&, const xa_modification_t&);
}
#endif