--- /dev/null
+/*
+ * Copyright (c) [2014] 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 <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "snapper/Acls.h"
+#include "snapper/AppUtil.h"
+#include "snapper/Exception.h"
+#include "snapper/Log.h"
+
+namespace snapper
+{
+ bool
+ is_acl_signature(const std::string& name)
+ {
+ for (std::vector<string>::const_iterator cit = _acl_signatures.begin(); cit != _acl_signatures.end(); cit++)
+ {
+ if (name == *cit)
+ return true;
+ }
+ return false;
+ }
+
+ Acls::Acls(const string& path)
+ : allowed_types(0x0), acl_access(NULL), acl_default(NULL)
+ {
+ struct stat buf;
+
+ int fd = ::open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_NONBLOCK | O_NOATIME |
+ O_CLOEXEC);
+ if (fd < 0)
+ {
+ if (errno == ELOOP)
+ {
+ y2deb("can't read ACLs from symlink '" << path << "' itself");
+ return;
+ }
+
+ if (stat(path.c_str(), &buf) < 0)
+ {
+ y2err("stat failed errno: " << errno << " (" << stringerror(errno) << ")");
+ throw AclException();
+ }
+ }
+ else
+ {
+ if (fstat(fd, &buf) < 0)
+ {
+ y2err("fstat failed errno: " << errno << " (" << stringerror(errno) << ")");
+ ::close(fd);
+ throw AclException();
+ }
+
+ acl_access = acl_get_fd(fd);
+ if (!acl_access)
+ {
+ y2err("acl_get_fd failed errno: " << errno << " (" << stringerror(errno) << ")");
+ ::close(fd);
+ throw AclException();
+ }
+
+ ::close(fd);
+ allowed_types = ACL_TYPE_ACCESS;
+ }
+
+ allowed_types |= (S_ISDIR(buf.st_mode)) ? ACL_TYPE_DEFAULT : 0x0;
+
+ // in case open failed for some reason
+ if (!(allowed_types & ACL_TYPE_ACCESS))
+ {
+ allowed_types |= ACL_TYPE_ACCESS;
+ acl_access = acl_get_file(path.c_str(), ACL_TYPE_ACCESS);
+ if (!acl_access)
+ {
+ y2err("acl_get_file failed errno: " << errno << " (" << stringerror(errno) << ")");
+ throw AclException();
+ }
+ }
+
+ // ACL_TYPE_DEFAULT can't be read from fd
+ if (allowed_types & ACL_TYPE_DEFAULT)
+ {
+ acl_default = acl_get_file(path.c_str(), ACL_TYPE_DEFAULT);
+ if (!acl_default)
+ {
+ y2err("acl_get_file failed errno: " << errno << " (" << stringerror(errno) << ")");
+ if (acl_free(acl_access))
+ {
+ y2err("acl_free failed errno: " << errno << " (" << stringerror(errno) << ")");
+ }
+
+ throw AclException();
+ }
+ }
+ }
+
+
+ Acls::~Acls()
+ {
+ if (acl_access)
+ acl_free(acl_access);
+ if (acl_default)
+ acl_free(acl_default);
+ }
+
+
+ void
+ Acls::serializeTo(const string& path) const
+ {
+ if (empty())
+ return;
+
+ if (acl_set_file(path.c_str(), ACL_TYPE_ACCESS, acl_access))
+ {
+ y2err("acl_set_file failed errno: " << errno << " (" << stringerror(errno) << ")");
+ throw AclException();
+ }
+
+ if (get_acl_types() & ACL_TYPE_DEFAULT)
+ {
+ if (acl_set_file(path.c_str(), ACL_TYPE_DEFAULT, acl_default))
+ {
+ y2err("acl_set_file failed errno: " << errno << " (" << stringerror(errno) << ")");
+ throw AclException();
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2014] 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_ACLS_H
+#define SNAPPER_ACLS_H
+
+#include <string>
+#include <vector>
+#include <sys/acl.h>
+
+#include <boost/assign/list_of.hpp>
+
+#ifndef ENABLE_ACL_SIGNATURES
+#define ENABLE_ACL_SIGNATURES ("system.posix_acl_access") \
+ ("system.posix_acl_default") \
+ ("trusted.SGI_ACL_FILE") \
+ ("trusted.SGI_ACL_DEFAULT")
+#endif
+
+namespace snapper
+{
+ using std::string;
+
+ const std::vector<string> _acl_signatures = boost::assign::list_of ENABLE_ACL_SIGNATURES;
+
+ bool is_acl_signature(const string& name);
+
+ class Acls
+ {
+ public:
+
+ Acls(const string& path);
+ ~Acls();
+
+ acl_type_t get_acl_types() const { return allowed_types; }
+ bool empty() const { return allowed_types == 0x0; }
+ void serializeTo(const string& path) const;
+
+ private:
+
+ acl_type_t allowed_types;
+ acl_t acl_access;
+ acl_t acl_default;
+ };
+
+}
+#endif //SNAPPER_ACLS_H
#include "snapper/Snapper.h"
#include "snapper/SnapperTmpl.h"
#include "snapper/SnapperDefines.h"
+#include "snapper/Acls.h"
namespace snapper
if (status & CREATED) status = CREATED;
if (status & DELETED) status = DELETED;
- if (status & (CONTENT | PERMISSIONS | USER | GROUP | XATTRS))
+ if (status & (CONTENT | PERMISSIONS | USER | GROUP | XATTRS | ACL))
{
// TODO check for content sometimes not required
- status &= ~(CONTENT | PERMISSIONS | USER | GROUP | XATTRS);
+ status &= ~(CONTENT | PERMISSIONS | USER | GROUP | XATTRS | ACL);
string dirname = snapper::dirname(name);
string basename = snapper::basename(name);
else
{
node->status &= ~(CREATED | DELETED);
- node->status |= CONTENT | PERMISSIONS | USER | GROUP | XATTRS;
+ node->status |= CONTENT | PERMISSIONS | USER | GROUP | XATTRS | ACL;
}
}
else
{
node->status &= ~(CREATED | DELETED);
- node->status |= CONTENT | PERMISSIONS | USER | GROUP | XATTRS;
+ node->status |= CONTENT | PERMISSIONS | USER | GROUP | XATTRS | ACL;
}
merge(processor, &it->second, from, to, x);
else
{
node->status &= ~(CREATED | DELETED);
- node->status |= CONTENT | PERMISSIONS | USER | GROUP | XATTRS;
+ node->status |= CONTENT | PERMISSIONS | USER | GROUP | XATTRS | ACL;
}
merge(processor, &it->second, from, to, x);
tree_node* node = processor->files.insert(path);
node->status |= XATTRS;
+
+ if (is_acl_signature(name))
+ {
+ #ifdef DEBUG_PROCESS
+ y2deb("adding acl flag, signature:'" << name << "'");
+ #endif
+ node->status |= ACL;
+ }
#endif
return 0;
tree_node* node = processor->files.insert(path);
node->status |= XATTRS;
+
+ if (is_acl_signature(name))
+ {
+ #ifdef DEBUG_PROCESS
+ y2deb("adding acl flag, signature:'" << name << "'");
+ #endif
+ node->status |= ACL;
+ }
#endif
return 0;
#include "snapper/Compare.h"
#include "snapper/Exception.h"
#include "snapper/XAttributes.h"
+#include "snapper/Acls.h"
namespace snapper
#ifdef ENABLE_XATTRS
if (file1.xaSupported() && file2.xaSupported())
{
- if (!cmpFilesXattrs(file1, file2))
- {
- status |= XATTRS;
- }
+ status |= cmpFilesXattrs(file1, file2);
}
#endif
}
- bool
+ unsigned int
cmpFilesXattrs(const SFile& file1, const SFile& file2)
{
try
{
XAttributes xa(file1);
XAttributes xb(file2);
- return xa == xb;
+
+ if (xa == xb)
+ {
+ return 0;
+ }
+ else
+ {
+ unsigned int status = XATTRS;
+
+ CompareAcls acl_a(xa);
+ CompareAcls acl_b(xb);
+
+ status |= (acl_a == acl_b) ? 0 : ACL;
+
+ return status;
+ }
}
catch (const XAttributesException& e)
{
- y2err("extended attributes compare failed");
- return false;
+ y2err("extended attributes or ACL compare failed");
+ return (XATTRS | ACL);
}
}
void
cmpDirs(const SDir& dir1, const SDir& dir2, cmpdirs_cb_t cb);
- bool
+ /* Compares the two files extended attributes and ACLs.
+ Returns 0 or XATTRS or (XATTRS | ACL) */
+ unsigned int
cmpFilesXattrs(const SFile&, const SFile&);
}
#include "snapper/Compare.h"
#include "snapper/Exception.h"
#include "snapper/XAttributes.h"
+#include "snapper/Acls.h"
namespace snapper
XAModification xa_mod(xa_src, xa_dest);
y2deb("xa_modmap(xa_dest) object: " << xa_mod);
+ xa_mod.filterOutAcls();
+
xaCreated = xa_mod.getXaCreateNum();
xaDeleted = xa_mod.getXaDeleteNum();
xaReplaced = xa_mod.getXaReplaceNum();
return ret_val;
}
+
+ bool
+ File::modifyAcls()
+ {
+ bool ret_val;
+
+ try
+ {
+ Acls acl(getAbsolutePath(LOC_PRE));
+ acl.serializeTo(getAbsolutePath(LOC_SYSTEM));
+
+ ret_val = true;
+ }
+ catch (const SnapperException& e)
+ {
+ ret_val = false;
+ }
+
+ return ret_val;
+ }
+
+
XAUndoStatistic& operator+=(XAUndoStatistic &out, const XAUndoStatistic &src)
{
out.numCreate += src.numCreate;
if (!modifyXattributes())
error = true;
}
+
+ if (getPreToPostStatus() & (ACL | TYPE | DELETED))
+ {
+ if (!modifyAcls())
+ error = true;
+ }
#endif
pre_to_system_status = (unsigned int) -1;
ret += status & PERMISSIONS ? "p" : ".";
ret += status & USER ? "u" : ".";
ret += status & GROUP ? "g" : ".";
- ret += status & XATTRS ? "x" : ".";
+ ret += status & XATTRS ? "x" : ".";
+ ret += status & ACL ? "a" : ".";
return ret;
}
}
if (str.length() >= 5)
- {
- if (str[4] == 'x')
- ret |= XATTRS;
- }
+ {
+ if (str[4] == 'x')
+ ret |= XATTRS;
+ }
+
+ if (str.length() >= 6)
+ {
+ if (str[5] == 'a')
+ ret |= ACL;
+ }
return ret;
}
enum StatusFlags
{
CREATED = 1, DELETED = 2, TYPE = 4, CONTENT = 8, PERMISSIONS = 16, USER = 32,
- GROUP = 64, XATTRS = 128
+ GROUP = 64, XATTRS = 128, ACL = 256
};
enum Cmp
bool undo;
bool modifyXattributes();
+ bool modifyAcls();
unsigned int xaCreated;
unsigned int xaDeleted;
SystemCmd.cc SystemCmd.h \
AsciiFile.cc AsciiFile.h \
Regex.cc Regex.h \
+ Acls.cc Acls.h \
Exception.h \
SnapperTmpl.h \
SnapperTypes.h \
SnapperDefines.h \
- Version.h \
- $(TMP_XA)
+ Version.h
if ENABLE_BTRFS
/*
- * Copyright (c) [2013] Red Hat, Inc.
+ * Copyright (c) [2013-2014] Red Hat, Inc.
*
* All Rights Reserved.
*
#include <errno.h>
#include <iomanip>
#include <boost/scoped_array.hpp>
+#include <algorithm>
#include "snapper/AppUtil.h"
#include "snapper/Exception.h"
#include "snapper/Log.h"
#include "snapper/XAttributes.h"
+#include "snapper/Acls.h"
namespace snapper
{
+ struct FilterAclsHelper
+ {
+ FilterAclsHelper(const vector<string>& acl_sigs)
+ : acl_sigs(acl_sigs) {}
+
+ bool operator()(const xa_pair_t& pair)
+ {
+ for (vector<string>::const_iterator cit = acl_sigs.begin(); cit != acl_sigs.end(); cit++)
+ if (pair.first == *cit)
+ return true;
+ return false;
+ }
+
+ bool operator()(const string& name)
+ {
+ for (vector<string>::const_iterator cit = acl_sigs.begin(); cit != acl_sigs.end(); cit++)
+ if (name == *cit)
+ return true;
+ return false;
+ }
+
+ const vector<string>& acl_sigs;
+ };
+
+
+ struct InsertAclsHelper
+ {
+ InsertAclsHelper(xa_map_t& xamap, const vector<string>& acl_sigs)
+ : map(xamap), acl_sigs(acl_sigs) {}
+ void operator()(const xa_pair_t& xapair)
+ {
+ for (vector<string>::const_iterator cit = acl_sigs.begin(); cit != acl_sigs.end(); cit++)
+ {
+ if (*cit == xapair.first)
+ {
+ map.insert(xapair);
+ break;
+ }
+ }
+ }
+
+ xa_map_t& map;
+ const vector<string>& acl_sigs;
+ };
+
XAttributes::XAttributes(const string &path)
{
// move beyond separating '\0' char
pos += name.length() + 1;
+
ssize_t v_size = lgetxattr(path.c_str(), name.c_str(), NULL, 0);
if (v_size < 0)
{
return (this == &xa) ? true : (this->xamap == xa.xamap);
}
+
ostream&
operator<<(ostream &out, const XAttributes &xa)
{
return out;
}
+
ostream&
operator<<(ostream &out, const xa_value_t &xavalue)
{
y2deb("adding create operation for " << src_cit->first);
create_vec.push_back(xa_pair_t(src_cit->first, src_cit->second));
}
+
}
+
bool
XAModification::empty() const
{
return create_vec.empty() && delete_vec.empty() && replace_vec.empty();
}
+
bool
XAModification::serializeTo(const string &dest) const
{
return true;
}
+
unsigned int
XAModification::getXaCreateNum() const
{
return create_vec.size();
}
+
unsigned int
XAModification::getXaDeleteNum() const
{
return delete_vec.size();
}
+
unsigned int
XAModification::getXaReplaceNum() const
{
return replace_vec.size();
}
+
void
XAModification::printTo(ostream& out, bool diff) const
{
}
}
+
void
XAModification::dumpDiffReport(ostream& out) const
{
printTo(out, true);
}
+
ostream&
operator<<(ostream &out, const XAModification &xa_mod)
{
xa_mod.printTo(out, false);
return out;
}
+
+
+ CompareAcls::CompareAcls(const XAttributes& xa)
+ {
+ std::for_each(xa.cbegin(), xa.cend(), InsertAclsHelper(xamap, _acl_signatures));
+ }
+
+
+ bool
+ CompareAcls::operator==(const CompareAcls& acls) const
+ {
+ return (this == &acls) ? true : (this->xamap == acls.xamap);
+ }
+
+
+ void
+ XAModification::filterOutAcls()
+ {
+ FilterAclsHelper fhelper(_acl_signatures);
+
+ create_vec.erase(std::remove_if(create_vec.begin(), create_vec.end(), fhelper),
+ create_vec.end());
+ delete_vec.erase(std::remove_if(delete_vec.begin(), delete_vec.end(), fhelper),
+ delete_vec.end());
+ replace_vec.erase(std::remove_if(replace_vec.begin(), replace_vec.end(), fhelper),
+ replace_vec.end());
+ }
+
}
/*
- * Copyright (c) [2013] Red Hat, Inc.
+ * Copyright (c) [2013-2014] Red Hat, Inc.
*
* All Rights Reserved.
*
XAModification(const XAttributes&, const XAttributes&);
bool empty() const;
+ void filterOutAcls();
bool serializeTo(const string&) const;
unsigned int getXaCreateNum() const;
ostream& operator<<(ostream&, const XAttributes&);
ostream& operator<<(ostream&, const xa_value_t&);
+
+ class CompareAcls
+ {
+ private:
+ xa_map_t xamap;
+ public:
+ CompareAcls(const XAttributes& xa);
+
+ bool operator==(const CompareAcls&) const;
+ };
}
LDADD = ../snapper/libsnapper.la
if HAVE_XATTRS
-TMP_XATST = xattrs1 xattrs2 xattrs3
+TMP_XATST = xattrs1 xattrs2 xattrs3 xattrs4
endif
noinst_SCRIPTS = run-all
xattrs1_SOURCES = xattrs1.cc xattrs_utils.cc xattrs_utils.h common.h common.cc
xattrs2_SOURCES = xattrs2.cc xattrs_utils.cc xattrs_utils.h common.h common.cc
xattrs3_SOURCES = xattrs3.cc xattrs_utils.cc xattrs_utils.h common.h common.cc
+xattrs4_SOURCES = xattrs4.cc xattrs_utils.cc xattrs_utils.h common.h common.cc
EXTRA_DIST = $(noinst_SCRIPTS)
test -x xattrs1 && run xattrs1
test -x xattrs2 && run xattrs2
test -x xattrs3 && run xattrs3
+test -x xattrs4 && run xattrs4
check_undo_statistics(0, 1, 0);
- check_xa_undo_statistics(2, 1, 1);
+ // do not count ACLs
+ check_xa_undo_statistics(1, 1, 1);
check_undo_errors(0, 0, 0);
--- /dev/null
+
+#include "common.h"
+
+using namespace std;
+
+int
+main()
+{
+ setup();
+
+ run_command("touch file1");
+ run_command("mkdir dir1");
+ run_command("mkdir no_default");
+ run_command("setfacl -b file1");
+ run_command("setfacl -k dir1");
+ run_command("setfacl -k no_default");
+ run_command("setfacl -m u:nobody:rw file1");
+ run_command("setfacl -d -m u:nobody:w dir1");
+
+ first_snapshot();
+
+ run_command("setfacl -b file1");
+ run_command("setfacl -k dir1");
+
+ second_snapshot();
+
+ undo();
+
+ check_undo_statistics(0, 2, 0);
+
+ // do not count ACLs
+ check_xa_undo_statistics(0, 0, 0);
+
+ check_undo_errors(0, 0, 0);
+
+ check_first();
+
+ cleanup();
+
+ exit(EXIT_SUCCESS);
+}