aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-04-22 12:52:55 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-04-22 12:52:55 +0000
commit6bad5399dddddeed9c49ebc420d482eb8ea4cb42 (patch)
tree567cb774b1e0ebaf09bd8b194885ccc7d3fdeef4
parent7bca36310de46b08f3148faca204a8ba834117fe (diff)
downloadpaludis-6bad5399dddddeed9c49ebc420d482eb8ea4cb42.tar.gz
paludis-6bad5399dddddeed9c49ebc420d482eb8ea4cb42.tar.xz
Preserve extended attributes, where supported
-rw-r--r--NEWS2
-rw-r--r--configure.ac22
-rw-r--r--paludis/merger.cc97
-rw-r--r--paludis/merger.hh1
-rw-r--r--paludis/merger.se1
-rw-r--r--paludis/ndbam_merger.cc4
-rw-r--r--paludis/repositories/e/vdb_merger.cc4
7 files changed, 129 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 368f4c0..4d2ab15 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ trunk/:
Portage-compatible configuration files without caring about Portage
compatibility.
+ * Extended attributes are now preserved when merging, where supported.
+
0.26.0_pre3:
* reconcilio no longer accepts the --verbose switch; verbose display is
now turned on unconditionally.
diff --git a/configure.ac b/configure.ac
index 0b87d1e..1047d59 100644
--- a/configure.ac
+++ b/configure.ac
@@ -473,6 +473,28 @@ AC_CHECK_FUNCS([lchflags])
AM_CONDITIONAL(HAVE_LCHFLAGS, test x$ac_cv_func_lchflags = xyes)
dnl }}}
+dnl {{{ check for listxattrf etc
+AC_MSG_CHECKING([for f*xattr function family])
+AC_COMPILE_IFELSE([
+#include <sys/types.h>
+#include <attr/xattr.h>
+
+int main(int, char **)
+{
+ flistxattr(0, 0, 0);
+ fgetxattr(0, 0, 0, 0);
+ fsetxattr(0, 0, 0, 0, 0);
+}
+],
+ [AC_MSG_RESULT([yes])
+ HAVE_XATTRS=yes],
+ [AC_MSG_RESULT([no])
+ HAVE_XATTRS=])
+if test "x$HAVE_XATTRS" = "xyes"; then
+ AC_DEFINE([HAVE_XATTRS], [1], [Have xattrs support])
+fi
+dnl }}}
+
dnl {{{ check for canonicalize_file_name function
AC_CHECK_FUNCS([canonicalize_file_name])
AM_CONDITIONAL(HAVE_CANONICALIZE_FILE_NAME, test x$ac_cv_func_canonicalize_file_name = xyes)
diff --git a/paludis/merger.cc b/paludis/merger.cc
index c77eab8..f78e101 100644
--- a/paludis/merger.cc
+++ b/paludis/merger.cc
@@ -35,6 +35,11 @@
#include <cstring>
#include <list>
+#include "config.h"
+#ifdef HAVE_XATTRS
+# include <attr/xattr.h>
+#endif
+
using namespace paludis;
#include <paludis/merger-se.cc>
@@ -721,6 +726,7 @@ Merger::install_file(const FSEntry & src, const FSEntry & dst_dir, const std::st
/* set*id bits */
if (0 != ::fchmod(output_fd, src_perms))
throw MergerError("Cannot fchmod '" + stringify(dst) + "': " + stringify(::strerror(errno)));
+ try_to_copy_xattrs(src, output_fd, result);
char buf[4096];
ssize_t count;
@@ -910,11 +916,18 @@ Merger::install_dir(const FSEntry & src, const FSEntry & dst_dir)
{
Log::get_instance()->message("merger.dir.rename_failed", ll_debug, lc_context) <<
"rename failed. Falling back to recursive copy.";
+
dst.mkdir(mode);
+ FDHolder dst_fd(::open(stringify(dst).c_str(), O_RDONLY | O_DIRECTORY));
+ if (-1 == dst_fd)
+ throw MergerError("Could not get an FD for the directory '"
+ + stringify(dst) + "' that we just created: " + stringify(::strerror(errno)));
if (! _params[k::no_chown()])
- dst.chown(dest_uid, dest_gid);
+ ::fchown(dst_fd, dest_uid, dest_gid);
/* pick up set*id bits */
- dst.chmod(mode);
+ ::fchmod(dst_fd, mode);
+ try_to_copy_xattrs(src, dst_fd, result);
+ ::close(dst_fd);
}
if (0 != _params[k::environment()]->perform_hook(extend_hook(
@@ -1089,3 +1102,83 @@ Merger::extend_hook(const Hook & h)
("IMAGE", stringify(_params[k::image()]));
}
+#ifdef HAVE_XATTRS
+
+void
+Merger::try_to_copy_xattrs(const FSEntry & src, int dst_fd, MergeStatusFlags & flags)
+{
+ FDHolder src_fd(::open(stringify(src).c_str(), O_RDONLY));
+
+ ssize_t list_sz(flistxattr(src_fd, 0, 0));
+ if (-1 == list_sz)
+ {
+ if (ENOTSUP != errno)
+ Log::get_instance()->message("merger.xattrs.failure", ll_warning, lc_context) <<
+ "Got error '" << ::strerror(errno) << "' when trying to find extended attributes size for '" << src << "'";
+ return;
+ }
+
+ tr1::shared_ptr<char> list_holder(static_cast<char *>(::operator new(list_sz)));
+ list_sz = flistxattr(src_fd, list_holder.get(), list_sz);
+ if (-1 == list_sz)
+ {
+ Log::get_instance()->message("merger.xattrs.failure", ll_warning, lc_context) <<
+ "Got error '" << ::strerror(errno) << "' when trying to find extended attributes for '" << src << "'";
+ return;
+ }
+
+ for (int offset(0) ; list_sz > 0 ; )
+ {
+ std::string key(list_holder.get() + offset);
+ do
+ {
+ ssize_t value_sz(fgetxattr(src_fd, key.c_str(), 0, 0));
+ if (-1 == value_sz)
+ {
+ Log::get_instance()->message("merger.xattrs.failure", ll_warning, lc_context) <<
+ "Got error '" << ::strerror(errno) << "' when trying to read size of extended attribute '" <<
+ key << "' for '" << src << "'";
+ break;
+ }
+
+ tr1::shared_ptr<char> value_holder(static_cast<char *>(::operator new(value_sz)));
+ value_sz = fgetxattr(src_fd, key.c_str(), value_holder.get(), value_sz);
+ if (-1 == value_sz)
+ {
+ Log::get_instance()->message("merger.xattrs.failure", ll_warning, lc_context) <<
+ "Got error '" << ::strerror(errno) << "' when trying to read extended attribute '" <<
+ key << "' for '" << src << "'";
+ }
+
+ if (-1 == fsetxattr(dst_fd, key.c_str(), value_holder.get(), value_sz, 0))
+ {
+ if (ENOTSUP == errno)
+ {
+ Log::get_instance()->message("merger.xattrs.failure", ll_warning, lc_context) <<
+ "Could not copy extended attributes from source file '" << src << "'";
+ return;
+ }
+ else
+ Log::get_instance()->message("merger.xattrs.failure", ll_warning, lc_context) <<
+ "Got error '" << ::strerror(errno) << "' when trying to set extended attribute '" <<
+ key << "' taken from source file '" << src << "'";
+ }
+
+ flags += msi_xattr;
+
+ } while (false);
+
+ list_sz -= (key.length() + 1);
+ offset += (key.length() + 1);
+ }
+}
+
+#else
+
+void
+Merger::try_to_copy_xattrs(const FSEntry &, int, MergeStatusFlags &)
+{
+}
+
+#endif
+
diff --git a/paludis/merger.hh b/paludis/merger.hh
index 6477cd7..808b189 100644
--- a/paludis/merger.hh
+++ b/paludis/merger.hh
@@ -84,6 +84,7 @@ namespace paludis
void record_renamed_dir_recursive(const FSEntry &);
void relabel_dir_recursive(const FSEntry &, const FSEntry &);
void rewrite_symlink_as_needed(const FSEntry &, const FSEntry &);
+ void try_to_copy_xattrs(const FSEntry &, int, MergeStatusFlags &);
bool symlink_needs_rewriting(const FSEntry & sym);
protected:
diff --git a/paludis/merger.se b/paludis/merger.se
index 9f7b904..766455d 100644
--- a/paludis/merger.se
+++ b/paludis/merger.se
@@ -11,6 +11,7 @@ make_enum_MergeStatusFlag()
key msi_used_existing "We used the existing entry (e.g. dir over dir)"
key msi_fixed_ownership "We fixed owner or group from the reduced id"
key msi_setid_bits "The source file had set*id bits"
+ key msi_xattr "The source file had xattr bits"
key msi_as_hardlink "We detected a hardlink and merged it as such"
doxygen_comment << "END"
diff --git a/paludis/ndbam_merger.cc b/paludis/ndbam_merger.cc
index 898e1fd..b3b59f0 100644
--- a/paludis/ndbam_merger.cc
+++ b/paludis/ndbam_merger.cc
@@ -311,6 +311,10 @@ NDBAMMerger::make_arrows(const MergeStatusFlags & flags) const
result[2] = '*';
continue;
+ case msi_xattr:
+ result[2] = '+';
+ continue;
+
case last_msi:
break;
}
diff --git a/paludis/repositories/e/vdb_merger.cc b/paludis/repositories/e/vdb_merger.cc
index 0a9a722..c3f8a50 100644
--- a/paludis/repositories/e/vdb_merger.cc
+++ b/paludis/repositories/e/vdb_merger.cc
@@ -344,6 +344,10 @@ VDBMerger::make_arrows(const MergeStatusFlags & flags) const
result[2] = '*';
continue;
+ case msi_xattr:
+ result[2] = '+';
+ continue;
+
case last_msi:
break;
}