summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2010-10-27 02:53:42 +0200
committerAndreas Gruenbacher <agruen@suse.de>2010-10-27 02:53:42 +0200
commit76d0e43140e83602ecca0073f2ee5515c3a9613b (patch)
treed00898bcd03371cde4b75d3f3b9a150e37efd973 /src
parent28113637f563534c5b4e1a462c39069b837d31d9 (diff)
downloadpatch-76d0e43140e83602ecca0073f2ee5515c3a9613b.tar.gz
Preserve extended attributes of patched files when possible
* src/patch.c (main): Set all file attributes of the temporary output file before renaming it over the final output file (possibly replacing the input file). Pass the input file name to set_file_attributes(). * src/util.c (set_file_attributes): When enabled (USE_XATTR), also copy extended attributes including attributes which define permissions. (copy_attr_error, copy_attr_quote, copy_attr_free, copy_attr_check, copy_attr): Helper functions for copying extended attributes. * m4/xattr.m4 (gl_FUNC_XATTR): Import from coreutils. * src/Makefile.am (patch_LDADD): Add $(LIB_XATTR) here. * bootstrap.conf: Use the gnulib verror module.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/patch.c9
-rw-r--r--src/util.c70
-rw-r--r--src/util.h4
4 files changed, 76 insertions, 10 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c1a1f9c..c119cfb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,7 +31,8 @@ patch_SOURCES = \
version.h
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib
-patch_LDADD = $(LDADD) $(top_builddir)/lib/libpatch.a $(LIB_CLOCK_GETTIME)
+patch_LDADD = $(LDADD) $(top_builddir)/lib/libpatch.a $(LIB_CLOCK_GETTIME) \
+ $(LIB_XATTR)
if ENABLE_MERGE
patch_SOURCES += merge.c
diff --git a/src/patch.c b/src/patch.c
index 6d37581..77be499 100644
--- a/src/patch.c
+++ b/src/patch.c
@@ -476,9 +476,6 @@ main (int argc, char **argv)
mode_t mode = file_type |
((new_mode ? new_mode : instat.st_mode) & S_IRWXUGO);
- move_file (TMPOUTNAME, &TMPOUTNAME_needs_removal, &outst,
- outname, mode, backup);
-
if ((set_time | set_utc) && new_time.tv_sec != -1)
{
struct timespec old_time = pch_timestamp (reverse);
@@ -500,7 +497,11 @@ main (int argc, char **argv)
}
if (! inerrno)
- set_file_attributes (outname, attr, &instat, mode, &new_time);
+ set_file_attributes (TMPOUTNAME, attr, inname, &instat,
+ mode, &new_time);
+
+ move_file (TMPOUTNAME, &TMPOUTNAME_needs_removal, &outst,
+ outname, mode, backup);
if (pch_rename ())
{
diff --git a/src/util.c b/src/util.c
index 22b19d0..2f9c2f6 100644
--- a/src/util.c
+++ b/src/util.c
@@ -42,6 +42,13 @@
#include <full-write.h>
#include <tempname.h>
+#ifdef USE_XATTR
+# include <attr/error_context.h>
+# include <attr/libattr.h>
+# include <stdarg.h>
+# include "verror.h"
+#endif
+
static void makedirs (char const *);
typedef struct
@@ -123,9 +130,64 @@ contains_slash (const char *s)
return false;
}
+#ifdef USE_XATTR
+
+static void
+copy_attr_error (struct error_context *ctx, char const *fmt, ...)
+{
+ int err = errno;
+ va_list ap;
+
+ /* use verror module to print error message */
+ va_start (ap, fmt);
+ verror (0, err, fmt, ap);
+ va_end (ap);
+}
+
+static char const *
+copy_attr_quote (struct error_context *ctx, char const *str)
+{
+ return quotearg (str);
+}
+
+static void
+copy_attr_free (struct error_context *ctx, char const *str)
+{
+}
+
+static int
+copy_attr_check (const char *name, struct error_context *ctx)
+{
+ int action = attr_copy_action (name, ctx);
+ return action == 0 || action == ATTR_ACTION_PERMISSIONS;
+}
+
+static int
+copy_attr (char const *src_path, char const *dst_path)
+{
+ struct error_context ctx =
+ {
+ .error = copy_attr_error,
+ .quote = copy_attr_quote,
+ .quote_free = copy_attr_free
+ };
+ return attr_copy_file (src_path, dst_path, copy_attr_check, &ctx);
+}
+
+#else /* USE_XATTR */
+
+static int
+copy_attr (char const *src_path, char const *dst_path)
+{
+ return 0;
+}
+
+#endif
+
void
set_file_attributes (char const *to, enum file_attributes attr,
- struct stat *st, mode_t mode, struct timespec *new_time)
+ char const *from, struct stat *st, mode_t mode,
+ struct timespec *new_time)
{
if (attr & FA_TIMES)
{
@@ -170,6 +232,9 @@ set_file_attributes (char const *to, enum file_attributes attr,
S_ISLNK (st->st_mode) ? "symbolic link" : "file",
quotearg (to));
}
+ if (copy_attr (from, to))
+ fatal_exit (0);
+ /* FIXME: There may be other attributes to preserve. */
if (attr & FA_MODE)
{
#if 0 && defined HAVE_LCHMOD
@@ -184,7 +249,6 @@ set_file_attributes (char const *to, enum file_attributes attr,
S_ISLNK (st->st_mode) ? "symbolic link" : "file",
quotearg (to));
}
- /* FIXME: There may be other attributes to preserve. */
}
static void
@@ -196,7 +260,7 @@ create_backup_copy (char const *from, char const *to, struct stat *st,
to_dir_known_to_exist);
if (remember_backup)
insert_file (&backup_st);
- set_file_attributes (to, FA_TIMES | FA_IDS | FA_MODE, st, st->st_mode, NULL);
+ set_file_attributes (to, FA_TIMES | FA_IDS | FA_MODE, from, st, st->st_mode, NULL);
}
void
diff --git a/src/util.h b/src/util.h
index 521d098..6ab09f0 100644
--- a/src/util.h
+++ b/src/util.h
@@ -70,8 +70,8 @@ enum file_attributes {
FA_MODE = 4
};
-void set_file_attributes (char const *, enum file_attributes, struct stat *,
- mode_t, struct timespec *);
+void set_file_attributes (char const *, enum file_attributes, char const *,
+ struct stat *, mode_t, struct timespec *);
static inline char const *
skip_spaces (char const *str)