From 76d0e43140e83602ecca0073f2ee5515c3a9613b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 27 Oct 2010 02:53:42 +0200 Subject: 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. --- src/Makefile.am | 3 ++- src/patch.c | 9 ++++---- src/util.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/util.h | 4 ++-- 4 files changed, 76 insertions(+), 10 deletions(-) (limited to 'src') 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 #include +#ifdef USE_XATTR +# include +# include +# include +# 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) -- cgit v1.2.1