#include "snapper/File.h"
#include "snapper/Compare.h"
#include "snapper/Exception.h"
+#include "snapper/XAttributes.h"
namespace snapper
cmpFiles(const SFile& file1, const struct stat& stat1, const SFile& file2,
const struct stat& stat2)
{
- unsigned int status = 0;
+ unsigned int status = 0;
+
+ /*
+ * NOTE:
+ *
+ * if both ctimes are in match, files should be same
+ * ctime can be altered only by some debugfs tool and
+ * on umounted fs (ext2,3,4...). So this should be safe
+ * unless root or CAP_SYS_ADMIN played with low-level fs
+ * utilities
+ */
+ if ((stat1.st_ctime == stat2.st_ctime))
+ return status;
if ((stat1.st_mode & S_IFMT) != (stat2.st_mode & S_IFMT))
{
status |= GROUP;
}
- return status;
+ // TODO: decide what to do w/ i.e. file1.xaSupported()
+ // and !file2.xaSupported() at the same time
+ if (file1.xaSupported() && file2.xaSupported())
+ {
+ if (!cmpFilesXattrs(file1, file2))
+ {
+ status |= XATTRS;
+ }
+ }
+
+ return status;
}
y2mil("stopwatch " << stopwatch << " for comparing directories");
}
+ bool
+ cmpFilesXattrs(const SFile& file1, const SFile& file2)
+ {
+ int fd1 = file1.open(O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC);
+ if (fd1 < 0)
+ {
+ y2err("open failed path:" << file1.fullname() << " errno:" << errno);
+ throw IOErrorException();
+ }
+
+ int fd2 = file2.open(O_RDONLY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC);
+ if (fd1 < 0)
+ {
+ y2err("open failed path:" << file2.fullname() << " errno:" << errno);
+ throw IOErrorException();
+ }
+
+ XAttributes xa(fd1), xb(fd2);
+ close(fd1);
+ close(fd2);
+ return (xa == xb);
+ }
}
void
cmpDirs(const SDir& dir1, const SDir& dir2, cmpdirs_cb_t cb);
+ bool
+ cmpFilesXattrs(const SFile&, const SFile&);
+
}
ret += status & USER ? "u" : ".";
ret += status & GROUP ? "g" : ".";
+ ret += status & XATTRS ? "x" : ".";
+
return ret;
}
ret |= GROUP;
}
+ if (str.length() >= 5)
+ {
+ if (str[4] == 'x')
+ ret |= XATTRS;
+ }
+
return ret;
}
enum StatusFlags
{
CREATED = 1, DELETED = 2, TYPE = 4, CONTENT = 8, PERMISSIONS = 16, USER = 32,
- GROUP = 64
+ GROUP = 64, XATTRS = 128
};
enum Cmp
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/xattr.h>
#include <fcntl.h>
#include <stddef.h>
#include <dirent.h>
y2err("not a directory path:" << base_path);
throw IOErrorException();
}
+
+ setXaStatus();
}
close(dirfd);
throw IOErrorException();
}
+
+ setXaStatus();
}
SDir::SDir(const SDir& dir)
- : base_path(dir.base_path), path(dir.path)
+ : base_path(dir.base_path), path(dir.path), xastatus(dir.xastatus)
{
dirfd = dup(dir.dirfd);
if (dirfd == -1)
{
if (this != &dir)
{
+ xastatus = dir.xastatus;
::close(dirfd);
dirfd = dup(dir.dirfd);
if (dirfd == -1)
return -1;
}
+ bool
+ SDir::xaSupported(void) const
+ {
+ return (xastatus == XA_SUPPORTED);
+ }
+
+ void
+ SDir::setXaStatus(void)
+ {
+ xastatus = XA_UNKNOWN;
+
+ ssize_t ret = flistxattr(dirfd, NULL, 0);
+ if (ret < 0)
+ {
+ if (errno == ENOTSUP)
+ {
+ xastatus = XA_UNSUPPORTED;
+ }
+ else
+ {
+ y2err("Couldn't get extended attributes status for " << base_path << "/" << path << stringerror(errno));
+ throw IOErrorException();
+ }
+ }
+ else
+ {
+ xastatus = XA_SUPPORTED;
+ }
+ }
SFile::SFile(const SDir& dir, const string& name)
: dir(dir), name(name)
return dir.readlink(name, buf);
}
+ bool
+ SFile::xaSupported(void) const
+ {
+ return dir.xaSupported();
+ }
}
{
using std::string;
using std::vector;
-
+
+ enum XaAttrsStatus {
+ XA_UNKNOWN,
+ XA_UNSUPPORTED,
+ XA_SUPPORTED
+ };
class SDir
{
int rename(const string& oldname, const string& newname) const;
int mktemp(string& name) const;
+ bool xaSupported() const;
private:
+ void setXaStatus();
const string base_path;
const string path;
int dirfd;
+ int xastatus;
};
int stat(struct stat* buf, int flags) const;
int open(int flags) const;
int readlink(string& buf) const;
-
+ bool xaSupported() const;
private:
const SDir& dir;
SystemCmd.cc SystemCmd.h \
AsciiFile.cc AsciiFile.h \
Regex.cc Regex.h \
+ XAttributes.cc Xattributes.h \
Exception.h \
SnapperTmpl.h \
SnapperTypes.h \
--- /dev/null
+/*
+ * Copyright (c) [2013] Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "XAttributes.h"
+
+#include <cstdio>
+#include <attr/xattr.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "snapper/Exception.h"
+
+namespace snapper
+{
+ XAttributes::XAttributes()
+ {
+ xamap = new xa_map_t;
+ }
+
+ XAttributes::XAttributes(int fd)
+ {
+ // TODO: change to debug
+ std::cout << "starting XattrsContainer(int)" << std::endl;
+ ssize_t size = flistxattr(fd, NULL, 0);
+ if (size < 0)
+ {
+ std::cerr << "errno: " << errno << std::endl;
+ throw IOErrorException();
+ }
+
+ // +1 to cover size == 0
+ char *names = new char[size + 1];
+
+ size = flistxattr(fd, names, size);
+ if (size < 0)
+ {
+ std::cerr << "errno: " << errno << std::endl;
+ throw IOErrorException();
+ }
+
+ // TODO: change to debug
+ std::cout << "names list size is: " << size << std::endl;
+
+ int pos = 0;
+
+ xamap = new xa_map_t;
+
+ while (pos < size)
+ {
+ string name = string(names + pos);
+ // step 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;
+ throw IOErrorException();
+ }
+
+ uint8_t *buffer = new uint8_t[v_size];
+
+ v_size = fgetxattr(fd, name.c_str(), buffer, v_size);
+ if (v_size < 0)
+ {
+ std::cerr << "fgetxattr(" << v_size << ") failed w/ errno: " << errno << std::endl;
+ 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;
+ }
+
+ XAttributes::XAttributes(const XAttributes &xa)
+ {
+ std::cout << "starting copy constructor XattrsContainer(const XattrsContainer&)" << std::endl;
+ xamap = new xa_map_t(*(xa.xamap));
+ }
+
+ XAttributes::~XAttributes()
+ {
+ delete xamap;
+ }
+
+ XAttributes&
+ XAttributes::operator=(const XAttributes &xa)
+ {
+ if (this != &xa)
+ {
+ std::cout << "This is assignment operator XattrsContainer::operator=()" << std::endl;
+ delete this->xamap;
+
+ this->xamap = new xa_map_t(*(xa.xamap));
+ }
+
+ return *this;
+ }
+
+ bool
+ XAttributes::operator==(const XAttributes &xa)
+ {
+ std::cout << "operator==" << std::endl;
+ return *(this->xamap) == *(xa.xamap);
+ }
+
+ ostream&
+ operator<<(ostream &out, const XAttributes &xa)
+ {
+ xa_map_citer it = xa.xamap->begin();
+
+ if (it == xa.xamap->end())
+ {
+ out << "(XA container is empty)";
+ return out;
+ }
+
+ out << "XA container includes:" << std::endl;
+
+ while (it != xa.xamap->end())
+ {
+ 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)
+ {
+ char tmp[4];
+
+ for (xa_value_t::const_iterator cit = xavalue.begin(); cit != xavalue.end(); cit++)
+ {
+ sprintf(tmp, "%d", *cit);
+ out << tmp << ":";
+ }
+
+ return out;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) [2013] Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef SNAPPER_XATTRIBUTES_H
+#define SNAPPER_XATTRIBUTES_H
+
+#include <map>
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include <stdint.h>
+
+namespace snapper
+{
+ using std::map;
+ using std::string;
+ using std::pair;
+ using std::ostream;
+ using std::vector;
+
+ 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 xa_map_t::iterator xa_map_iter;
+ typedef xa_map_t::const_iterator xa_map_citer;
+
+ class XAttributes
+ {
+ private:
+ xa_map_t *xamap;
+ public:
+ XAttributes();
+ XAttributes(int);
+ XAttributes(const XAttributes&);
+ ~XAttributes();
+
+ XAttributes& operator=(const XAttributes&);
+ bool operator==(const XAttributes&);
+
+ void insert(const xa_pair_t&);
+
+ friend ostream& operator<<(ostream&, const XAttributes&);
+ };
+
+ ostream& operator<<(ostream&, const xa_value_t&);
+}
+
+#endif