From 31611b920a307d6c1909270ff8ec850c17625b04 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Mon, 20 Mar 2006 23:54:26 +0000 Subject: [PATCH] A new version of an old patch by Rolf Grossmann. --- flags.diff | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 flags.diff diff --git a/flags.diff b/flags.diff new file mode 100644 index 0000000..a885d7e --- /dev/null +++ b/flags.diff @@ -0,0 +1,372 @@ +This patch provides --flags, which preserves the st_flags field. +Modified from a patch that was written by Rolf Grossmann: + + http://www.progtech.net/rsync.flags-patch + +--- old/configure.in ++++ new/configure.in +@@ -494,7 +494,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strd + memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \ + strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ + setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \ +- strerror putenv iconv_open locale_charset nl_langinfo \ ++ chflags strerror putenv iconv_open locale_charset nl_langinfo \ + sigaction sigprocmask) + + AC_CHECK_FUNCS(getpgrp tcgetpgrp) +--- old/flist.c ++++ new/flist.c +@@ -48,6 +48,7 @@ extern int preserve_links; + extern int preserve_hard_links; + extern int preserve_devices; + extern int preserve_specials; ++extern int preserve_flags; + extern int preserve_uid; + extern int preserve_gid; + extern int relative_paths; +@@ -312,6 +313,9 @@ static void send_file_entry(struct file_ + unsigned short flags; + static time_t modtime; + static mode_t mode; ++#ifdef SUPPORT_FLAGS ++ static uint32 fileflags; ++#endif + static int64 dev; + static dev_t rdev; + static uint32 rdev_major; +@@ -344,6 +348,12 @@ static void send_file_entry(struct file_ + flags |= XMIT_SAME_MODE; + else + mode = file->mode; ++#ifdef SUPPORT_FLAGS ++ if (file->fileflags == fileflags) ++ flags |= XMIT_SAME_FLAGS; ++ else ++ fileflags = file->fileflags; ++#endif + if ((preserve_devices && IS_DEVICE(mode)) + || (preserve_specials && IS_SPECIAL(mode))) { + if (protocol_version < 28) { +@@ -427,6 +437,10 @@ static void send_file_entry(struct file_ + write_int(f, modtime); + if (!(flags & XMIT_SAME_MODE)) + write_int(f, to_wire_mode(mode)); ++#ifdef SUPPORT_FLAGS ++ if (preserve_flags && !(flags & XMIT_SAME_FLAGS)) ++ write_int(f, (int)fileflags); ++#endif + if (preserve_uid && !(flags & XMIT_SAME_UID)) { + if (!numeric_ids) + add_uid(uid); +@@ -496,6 +510,9 @@ static struct file_struct *receive_file_ + { + static time_t modtime; + static mode_t mode; ++#ifdef SUPPORT_FLAGS ++ static uint32 fileflags; ++#endif + static int64 dev; + static dev_t rdev; + static uint32 rdev_major; +@@ -569,9 +586,12 @@ static struct file_struct *receive_file_ + modtime = (time_t)read_int(f); + if (!(flags & XMIT_SAME_MODE)) + mode = from_wire_mode(read_int(f)); +- + if (chmod_modes && !S_ISLNK(mode)) + mode = tweak_mode(mode, chmod_modes); ++#ifdef SUPPORT_FLAGS ++ if (preserve_flags && !(flags & XMIT_SAME_FLAGS)) ++ fileflags = (uint32)read_int(f); ++#endif + + if (preserve_uid && !(flags & XMIT_SAME_UID)) + uid = (uid_t)read_int(f); +@@ -622,6 +642,9 @@ static struct file_struct *receive_file_ + file->modtime = modtime; + file->length = file_length; + file->mode = mode; ++#ifdef SUPPORT_FLAGS ++ file->fileflags = fileflags; ++#endif + file->uid = uid; + file->gid = gid; + +@@ -874,6 +897,9 @@ struct file_struct *make_file(char *fnam + file->modtime = st.st_mtime; + file->length = st.st_size; + file->mode = st.st_mode; ++#ifdef SUPPORT_FLAGS ++ file->fileflags = st.st_flags; ++#endif + file->uid = st.st_uid; + file->gid = st.st_gid; + +--- old/generator.c ++++ new/generator.c +@@ -126,6 +126,9 @@ static int delete_item(char *fname, int + if (!S_ISDIR(mode)) { + if (max_delete && ++deletion_count > max_delete) + return 0; ++#ifdef SUPPORT_FLAGS ++ make_mutable(fname); ++#endif + if (make_backups && (backup_dir || !is_backup_file(fname))) + ok = make_backup(fname); + else +@@ -150,10 +153,17 @@ static int delete_item(char *fname, int + ok = 0; + errno = ENOTEMPTY; + } else if (make_backups && !backup_dir && !is_backup_file(fname) +- && !(flags & DEL_FORCE_RECURSE)) ++ && !(flags & DEL_FORCE_RECURSE)) { ++#ifdef SUPPORT_FLAGS ++ make_mutable(fname); ++#endif + ok = make_backup(fname); +- else ++ } else { ++#ifdef SUPPORT_FLAGS ++ make_mutable(fname); ++#endif + ok = do_rmdir(fname) == 0; ++ } + if (ok) { + if (!(flags & DEL_TERSE)) + log_delete(fname, mode); +--- old/options.c ++++ new/options.c +@@ -46,6 +46,7 @@ int copy_links = 0; + int preserve_links = 0; + int preserve_hard_links = 0; + int preserve_perms = 0; ++int preserve_flags = 0; + int preserve_executability = 0; + int preserve_devices = 0; + int preserve_specials = 0; +@@ -196,6 +197,7 @@ static void print_rsync_version(enum log + char const *hardlinks = "no "; + char const *links = "no "; + char const *ipv6 = "no "; ++ char const *flags = "no "; + STRUCT_STAT *dumstat; + + #ifdef HAVE_SOCKETPAIR +@@ -218,6 +220,10 @@ static void print_rsync_version(enum log + ipv6 = ""; + #endif + ++#ifdef SUPPORT_FLAGS ++ flags = ""; ++#endif ++ + rprintf(f, "%s version %s protocol version %d\n", + RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION); + rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n"); +@@ -230,9 +236,9 @@ static void print_rsync_version(enum log + /* Note that this field may not have type ino_t. It depends + * on the complicated interaction between largefile feature + * macros. */ +- rprintf(f, " %sinplace, %sIPv6, " ++ rprintf(f, " %sinplace, %sIPv6, %sfile flags, " + "%d-bit system inums, %d-bit internal inums\n", +- have_inplace, ipv6, ++ have_inplace, ipv6, flags, + (int) (sizeof dumstat->st_ino * 8), + (int) (sizeof (int64) * 8)); + #ifdef MAINTAINER_MODE +@@ -294,6 +300,7 @@ void usage(enum logcode F) + rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); + rprintf(F," -H, --hard-links preserve hard links\n"); + rprintf(F," -p, --perms preserve permissions\n"); ++ rprintf(F," --flags preserve file flags\n"); + rprintf(F," -E, --executability preserve the file's executability\n"); + rprintf(F," --chmod=CHMOD change destination permissions\n"); + rprintf(F," -o, --owner preserve owner (super-user only)\n"); +@@ -409,6 +416,8 @@ static struct poptOption long_options[] + {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 }, + {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, + {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, ++ {"flags", 0, POPT_ARG_VAL, &preserve_flags, 1, 0, 0 }, ++ {"no-flags", 0, POPT_ARG_VAL, &preserve_flags, 0, 0, 0 }, + {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, + {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, + {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, +@@ -1107,6 +1116,15 @@ int parse_arguments(int *argc, const cha + } + #endif + ++#ifndef SUPPORT_FLAGS ++ if (preserve_flags) { ++ snprintf(err_buf, sizeof err_buf, ++ "file flags are not supported on this %s\n", ++ am_server ? "server" : "client"); ++ return 0; ++ } ++#endif ++ + if (write_batch && read_batch) { + snprintf(err_buf, sizeof err_buf, + "--write-batch and --read-batch can not be used together\n"); +@@ -1562,6 +1580,9 @@ void server_options(char **args,int *arg + if (xfer_dirs && !recurse && delete_mode && am_sender) + args[ac++] = "--no-r"; + ++ if (preserve_flags) ++ args[ac++] = "--flags"; ++ + if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) { + if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0) + goto oom; +--- old/rsync.c ++++ new/rsync.c +@@ -34,6 +34,7 @@ extern int verbose; + extern int dry_run; + extern int daemon_log_format_has_i; + extern int preserve_perms; ++extern int preserve_flags; + extern int preserve_executability; + extern int preserve_times; + extern int omit_dir_times; +@@ -217,6 +218,19 @@ int set_file_attrs(char *fname, struct f + } + #endif + ++#ifdef SUPPORT_FLAGS ++ if (preserve_flags && !S_ISLNK(st->st_mode) ++ && st->st_flags != file->fileflags) { ++ if (do_chflags(fname, file->fileflags) != 0) { ++ rsyserr(FERROR, errno, ++ "failed to set file flags on %s", ++ full_fname(fname)); ++ return 0; ++ } ++ updated = 1; ++ } ++#endif ++ + if (verbose > 1 && flags & ATTRS_REPORT) { + enum logcode code = daemon_log_format_has_i || dry_run + ? FCLIENT : FINFO; +@@ -252,6 +266,10 @@ void finish_transfer(char *fname, char * + { + int ret; + ++#ifdef SUPPORT_FLAGS ++ make_mutable(fname); /* XXX */ ++#endif ++ + if (inplace) { + if (verbose > 2) + rprintf(FINFO, "finishing %s\n", fname); +@@ -305,3 +323,27 @@ const char *who_am_i(void) + return am_server ? "server" : "client"; + return am_sender ? "sender" : am_generator ? "generator" : "receiver"; + } ++ ++#ifdef SUPPORT_FLAGS ++/* remove immutable flags from an object, so it can be altered/removed. */ ++void make_mutable(char *fname) ++{ ++#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | UF_NOUNLINK | SF_IMMUTABLE | SF_APPEND | SF_NOUNLINK) ++ STRUCT_STAT stb; ++ int failed; ++ ++ if (dry_run) ++ return; ++ ++ /* XXX get rid of this extra stat() */ ++#ifdef SUPPORT_LINKS ++ failed = do_lstat(fname, &stb); ++#else ++ failed = do_stat(fname, &stb); ++#endif ++ if (failed) ++ return; ++ if (stb.st_flags & NOCHANGEBITS) ++ do_chflags(fname, stb.st_flags & ~NOCHANGEBITS); ++} ++#endif +--- old/rsync.h ++++ new/rsync.h +@@ -54,6 +54,7 @@ + #define XMIT_HAS_IDEV_DATA (1<<9) + #define XMIT_SAME_DEV (1<<10) + #define XMIT_RDEV_MINOR_IS_SMALL (1<<11) ++#define XMIT_SAME_FLAGS (1<<12) + + /* These flags are used in the live flist data. */ + +@@ -519,6 +520,9 @@ struct file_struct { + struct hlink *links; + } link_u; + time_t modtime; ++#ifdef SUPPORT_FLAGS ++ uint32 fileflags; ++#endif + uid_t uid; + gid_t gid; + mode_t mode; +@@ -702,6 +706,9 @@ extern int errno; + #ifdef HAVE_LINK + #define SUPPORT_HARD_LINKS 1 + #endif ++#ifdef HAVE_CHFLAGS ++#define SUPPORT_FLAGS 1 ++#endif + + #ifdef HAVE_SIGACTION + #define SIGACTION(n,h) sigact.sa_handler=(h), sigaction((n),&sigact,NULL) +--- old/rsync.yo ++++ new/rsync.yo +@@ -322,6 +322,7 @@ to the detailed description below for a + -p, --perms preserve permissions + -E, --executability preserve executability + --chmod=CHMOD change destination permissions ++ --flags preserve file flags + -o, --owner preserve owner (super-user only) + -g, --group preserve group + --devices preserve device files (super-user only) +@@ -498,7 +499,9 @@ specified, in which case bf(-r) is not i + + Note that bf(-a) bf(does not preserve hardlinks), because + finding multiply-linked files is expensive. You must separately +-specify bf(-H). ++specify bf(-H). Note also that for compatibility, bf(-a) ++currently bf(does not include --flags) (see there) to include preserving ++change file flags (if supported by the OS). + + dit(--no-OPTION) You may turn off one or more implied options by prefixing + the option name with "no-". Not all options may be prefixed with a "no-": +@@ -793,6 +796,13 @@ quote(itemize( + + If bf(--perms) is enabled, this option is ignored. + ++dit(bf(--flags)) This option causes rsync to update the change file flags ++to be the same as the source file, if your OS supports the chflags(2) ++system call. In any case, an attempt is made to remove flags that would ++prevent a file to be altered. Some flags can only be altered by the ++super-user and can only be unset below a certain secure-level (usually ++single-user mode). ++ + dit(bf(--chmod)) This option tells rsync to apply one or more + comma-separated "chmod" strings to the permission of the files in the + transfer. The resulting value is treated as though it was the permissions +--- old/syscall.c ++++ new/syscall.c +@@ -155,6 +155,15 @@ int do_chmod(const char *path, mode_t mo + } + #endif + ++#ifdef SUPPORT_FLAGS ++int do_chflags(const char *path, u_long flags) ++{ ++ if (dry_run) return 0; ++ RETURN_ERROR_IF_RO_OR_LO; ++ return chflags(path, flags); ++} ++#endif ++ + int do_rename(const char *fname1, const char *fname2) + { + if (dry_run) return 0; -- 2.34.1