void
print_xa_diff(const string loc_pre, const string loc_post)
{
- int src_fd = open(loc_pre.c_str(), O_RDONLY | O_NOATIME | O_NOFOLLOW);
- if (src_fd < 0)
- cerr << "Can't open " << loc_pre << stringerror(errno) << endl;
-
- int dest_fd = open(loc_post.c_str(), O_RDONLY | O_NOATIME | O_NOFOLLOW);
- if (dest_fd < 0)
- {
- close(src_fd);
- cerr << "Can't open " << loc_post << stringerror(errno) << endl;
- }
-
try {
- XAModification xa_mod = XAModification(XAttributes(src_fd), XAttributes(dest_fd));
+ XAModification xa_mod = XAModification(XAttributes(loc_pre), XAttributes(loc_post));
if (xa_mod.isEmpty())
y2deb("XA Modification object is empty!");
cout << "extended attributes diff:" << endl << "--- " << loc_pre << endl << "+++ " << loc_post << endl << xa_mod;
{
if (!cmpFilesContent(file1, stat1, file2, stat2))
status |= CONTENT;
+
+#ifdef ENABLE_XATTRS
+ /* TODO: think about this. Do you want to report
+ * XA modification in case the compared files differ
+ * in their types file A: link, file B: directory
+ */
+ if (file1.xaSupported() && file2.xaSupported())
+ {
+ if (!cmpFilesXattrs(file1, stat1, file2, stat2))
+ {
+ status |= XATTRS;
+ }
+ }
+#endif
}
if ((stat1.st_mode ^ stat2.st_mode) & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID |
status |= GROUP;
}
-#ifdef ENABLE_XATTRS
- if (file1.xaSupported() && file2.xaSupported())
- {
- // TODO: think about how XATTRS are related to
- // to other status changes...
- if (!cmpFilesXattrs(file1, file2))
- {
- status |= XATTRS;
- }
- }
-#endif
-
return status;
}
#ifdef ENABLE_XATTRS
bool
- cmpFilesXattrs(const SFile& file1, const SFile& file2)
+ cmpFilesXattrs(const SFile& file1, const struct stat& stat1, const SFile& file2, const struct stat& stat2)
+ {
+ if ((stat1.st_mode & S_IFMT) != (stat2.st_mode & S_IFMT))
+ throw LogicErrorException();
+
+ bool retval;
+
+ try
+ {
+ XAttributes xa(file1.fullname(true)), xb(file2.fullname(true));
+ retval = (xa == xb);
+ }
+ catch (XAttributesException xae)
+ {
+ y2err("extended attributes compare failed");
+ retval = false;
+ }
+
+ return retval;
+ }
+
+/*
+ bool cmpFilesXattrsLnk(const SFile& file1, const SFile& file2)
{
- int fd1 = file1.open(O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC);
+ int fd1 = file1.open(O_RDONLY | O_NOATIME | O_CLOEXEC);
if (fd1 < 0)
{
- y2err("open failed path:" << file1.fullname() << " errno:" << errno);
+ y2err("Can't open link: " << file1.fullname() << " w/ error: " << stringerror(errno));
throw IOErrorException();
}
- int fd2 = file2.open(O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC);
+ int fd2 = file2.open(O_RDONLY | O_NOATIME | O_CLOEXEC);
if (fd2 < 0)
{
- y2err("open failed path:" << file2.fullname() << " errno:" << errno);
+ y2err("Can't open link:" << file2.fullname() << " w/ error: " << stringerror(errno));
close(fd1);
throw IOErrorException();
}
}
catch (XAttributesException xae)
{
+ y2err("extended attributes compare failed");
retval = false;
}
close(fd1);
return retval;
}
+*/
#endif
}
#ifdef ENABLE_XATTRS
bool
- cmpFilesXattrs(const SFile&, const SFile&);
+ cmpFilesXattrs(const SFile&, const struct stat&, const SFile&, const struct stat&);
#endif
}
}
#ifdef ENABLE_XATTRS
- bool
- File::modifyXattributes() const
+/* bool
+ File::modifyXattributesReg() const
{
-
- int src_fd = open(getAbsolutePath(LOC_PRE).c_str(), O_RDONLY | O_CLOEXEC);
+ int src_fd = open(getAbsolutePath(LOC_PRE).c_str(), O_RDONLY | O_NOFOLLOW | 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);
+ int dest_fd = open(getAbsolutePath(LOC_SYSTEM).c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC);
if (dest_fd < 0)
{
y2err("open failed errno:" << errno << " (" << stringerror(errno) << ")");
XAModification xa_mod(xa_src, xa_dest);
y2deb("xa_modmap(xa_dest) object: " << xa_mod);
- ret_val = xa_mod.serializeTo(dest_fd);
+ ret_val = xa_mod.serializeToFd(dest_fd);
}
catch (XAttributesException xae) {
ret_val = false;
return ret_val;
}
+
+ bool
+ File::modifyXattributesLink() const
+ {
+ bool ret_val;
+
+ try {
+ XAttributes xa_src(getAbsolutePath(LOC_PRE)), xa_dest(getAbsolutePath(LOC_SYSTEM));
+ y2deb("xa_src object: " << xa_src << std::endl << "xa_dest object: " << xa_dest);
+
+ XAModification xa_mod(xa_src, xa_dest);
+ y2deb("xa_modmap(xa_dest) object: " << xa_mod);
+
+ ret_val = xa_mod.serializeToLink(getAbsolutePath(LOC_SYSTEM));
+ }
+ catch (XAttributesException xae) {
+ ret_val = false;
+ }
+
+ return ret_val;
+ }
+*/
+ bool
+ File::modifyXattributes() const
+ {
+ bool ret_val;
+
+ try {
+ XAttributes xa_src(getAbsolutePath(LOC_PRE)), xa_dest(getAbsolutePath(LOC_SYSTEM));
+ y2deb("xa_src object: " << xa_src << std::endl << "xa_dest object: " << xa_dest);
+
+ XAModification xa_mod(xa_src, xa_dest);
+ y2deb("xa_modmap(xa_dest) object: " << xa_mod);
+
+ ret_val = xa_mod.serializeTo(getAbsolutePath(LOC_SYSTEM));
+ }
+ catch (XAttributesException xae) {
+ ret_val = false;
+ }
+
+ return ret_val;
+ }
+
#endif
bool
}
#ifdef ENABLE_XATTRS
- // NOTE: XATTR flasg must not be set w/ CREATED or DELETED flag
- if (getPreToPostStatus() & XATTRS)
+ /*
+ * xattributes have to be transfered as well
+ * if we'are about to create new type during
+ * undo!
+ */
+ if (getPreToPostStatus() & (XATTRS | TYPE | DELETED))
{
if (!modifyXattributes())
error = true;
namespace snapper
{
+ /* TODO: candidate for removal */
XAttributes::XAttributes(int fd)
{
y2deb("entering Xattributes(int fd) constructor");
}
}
+ 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&)");
}
bool
- XAModification::serializeTo(int dest_fd) const
+ XAModification::serializeTo(const string &dest) const
{
if (this->isEmpty())
return true;
{
case XA_DELETE:
y2deb("delete xattribute: " << mod_cit->first);
- if (fremovexattr(dest_fd, mod_cit->first.c_str()))
+ if (lremovexattr(dest.c_str(), mod_cit->first.c_str()))
{
y2err("Couldn't remove xattribute '" << mod_cit->first << "': " << stringerror(errno));
return false;
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))
+ if (lsetxattr(dest.c_str(), 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
{
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))
+ if (lsetxattr(dest.c_str(), 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);
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))
+ if (lsetxattr(dest.c_str(), 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
{
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))
+ if (lsetxattr(dest.c_str(), 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);
// this is ordered on purpose!
// we can possibly avoid allocating new fs block if xattrs fits
- // into 100 bytes (ext2,3,4)
+ // into 100 bytes (ext4)
// so, first remove/change and create later
enum XaCompareFlags {
XA_DELETE = 0,
xa_map_t xamap;
public:
XAttributes(int);
+ XAttributes(const string&);
XAttributes(const XAttributes&);
xa_map_citer cbegin() const { return xamap.begin(); }
XAModification(const XAttributes&, const XAttributes&);
bool isEmpty() const;
- bool serializeTo(int) const;
+ bool serializeTo(const string&) const;
xa_mod_citer cbegin() const { return xamodmap.begin(); };
xa_mod_citer cend() const { return xamodmap.end(); };