The Samba-Bugzilla – Attachment 6298 Details for
Bug 8019
Various improvements to the fileflags patch
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Several changes to the fileflags.diff patch
fileflags_bombich.diff (text/plain), 42.60 KB, created by
Mike Bombich
on 2011-03-16 22:15:15 UTC
(
hide
)
Description:
Several changes to the fileflags.diff patch
Filename:
MIME Type:
Creator:
Mike Bombich
Created:
2011-03-16 22:15:15 UTC
Size:
42.60 KB
patch
obsolete
>This patch provides --fileflags, which preserves the st_flags stat() field. >Modified from a patch that was written by Rolf Grossmann. > >To use this patch, run these commands for a successful build: > > patch -p1 <patches/fileflags.diff > ./prepare-source > ./configure > make > >diff -Naur a/Makefile.in b/Makefile.in >--- a/Makefile.in 2011-03-16 13:25:12.000000000 -0500 >+++ b/Makefile.in 2011-03-16 14:35:30.000000000 -0500 >@@ -42,7 +42,7 @@ > popt/popthelp.o popt/poptparse.o > OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@ > >-TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@ >+TLS_OBJ = tls.o syscall.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@ > > # Programs we must have to run the test cases > CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \ >@@ -107,7 +107,7 @@ > getfsdev$(EXEEXT): getfsdev.o > $(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS) > >-TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o >+TRIMSLASH_OBJ = trimslash.o syscall.o t_stub.o lib/compat.o lib/snprintf.o > trimslash$(EXEEXT): $(TRIMSLASH_OBJ) > $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS) > >diff -Naur a/compat.c b/compat.c >--- a/compat.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/compat.c 2011-03-16 14:35:30.000000000 -0500 >@@ -43,9 +43,11 @@ > extern int basis_dir_cnt; > extern int prune_empty_dirs; > extern int protocol_version; >+extern int force_change; > extern int protect_args; > extern int preserve_uid; > extern int preserve_gid; >+extern int preserve_fileflags; > extern int preserve_acls; > extern int preserve_xattrs; > extern int need_messages_from_generator; >@@ -63,7 +65,7 @@ > #endif > > /* These index values are for the file-list's extra-attribute array. */ >-int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; >+int uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx; > > int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ > int sender_symlink_iconv = 0; /* sender should convert symlink content */ >@@ -140,6 +142,8 @@ > uid_ndx = ++file_extra_cnt; > if (preserve_gid) > gid_ndx = ++file_extra_cnt; >+ if (preserve_fileflags || (force_change && !am_sender)) >+ fileflags_ndx = ++file_extra_cnt; > if (preserve_acls && !am_sender) > acls_ndx = ++file_extra_cnt; > if (preserve_xattrs) >diff -Naur a/configure.ac b/configure.ac >--- a/configure.ac 2011-03-16 13:25:12.000000000 -0500 >+++ b/configure.ac 2011-03-16 14:35:30.000000000 -0500 >@@ -567,6 +567,7 @@ > AC_FUNC_ALLOCA > AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ > fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ >+ chflags \ > memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ > strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ > setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \ >diff -Naur a/flist.c b/flist.c >--- a/flist.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/flist.c 2011-03-16 14:45:29.000000000 -0500 >@@ -51,6 +51,7 @@ > extern int preserve_hard_links; > extern int preserve_devices; > extern int preserve_specials; >+extern int preserve_fileflags; > extern int delete_during; > extern int eol_nulls; > extern int relative_paths; >@@ -394,6 +395,9 @@ > { > static time_t modtime; > static mode_t mode; >+#ifdef SUPPORT_FILEFLAGS >+ static uint32 fileflags; >+#endif > #ifdef SUPPORT_HARD_LINKS > static int64 dev; > #endif >@@ -423,6 +427,16 @@ > xflags |= XMIT_SAME_MODE; > else > mode = file->mode; >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags) { >+ if (F_FFLAGS(file) == fileflags) >+ xflags |= XMIT_SAME_FLAGS; >+ else >+ fileflags = F_FFLAGS(file); >+ } else { >+ fileflags = 0; >+ } >+#endif > > if (preserve_devices && IS_DEVICE(mode)) { > if (protocol_version < 28) { >@@ -547,6 +561,10 @@ > } > if (!(xflags & XMIT_SAME_MODE)) > write_int(f, to_wire_mode(mode)); >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags && !(xflags & XMIT_SAME_FLAGS)) >+ write_int(f, (int)fileflags); >+#endif > if (preserve_uid && !(xflags & XMIT_SAME_UID)) { > if (protocol_version < 30) > write_int(f, uid); >@@ -634,6 +652,9 @@ > { > static int64 modtime; > static mode_t mode; >+#ifdef SUPPORT_FILEFLAGS >+ static uint32 fileflags; >+#endif > #ifdef SUPPORT_HARD_LINKS > static int64 dev; > #endif >@@ -731,6 +752,12 @@ > file_length = F_LENGTH(first); > modtime = first->modtime; > mode = first->mode; >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags) >+ fileflags = F_FFLAGS(first); >+ else >+ fileflags = 0; >+#endif > if (preserve_uid) > uid = F_OWNER(first); > if (preserve_gid) >@@ -768,6 +795,12 @@ > > if (chmod_modes && !S_ISLNK(mode)) > mode = tweak_mode(mode, chmod_modes); >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags && !(xflags & XMIT_SAME_FLAGS)) >+ fileflags = (uint32)read_int(f); >+ else if (!preserve_fileflags) >+ fileflags = 0; >+#endif > > if (preserve_uid && !(xflags & XMIT_SAME_UID)) { > if (protocol_version < 30) >@@ -909,6 +942,12 @@ > } > #endif > file->mode = mode; >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags) >+ F_FFLAGS(file) = fileflags; >+ else >+ F_FFLAGS(file) = 0; >+#endif > if (preserve_uid) > F_OWNER(file) = uid; > if (preserve_gid) { >@@ -1283,6 +1322,10 @@ > } > #endif > file->mode = st.st_mode; >+#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE >+ if (fileflags_ndx) >+ F_FFLAGS(file) = st.st_flags; >+#endif > if (preserve_uid) > F_OWNER(file) = st.st_uid; > if (preserve_gid) >@@ -1430,6 +1473,8 @@ > if (preserve_xattrs) { > sx.st.st_mode = file->mode; > sx.xattr = NULL; >+ if (preserve_fileflags) >+ sx.st.st_flags = F_FFLAGS(file); > if (get_xattr(fname, &sx) < 0) { > io_error |= IOERR_GENERAL; > return NULL; >diff -Naur a/generator.c b/generator.c >--- a/generator.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/generator.c 2011-03-16 14:35:30.000000000 -0500 >@@ -42,8 +42,10 @@ > extern int preserve_specials; > extern int preserve_hard_links; > extern int preserve_executability; >+extern int preserve_fileflags; > extern int preserve_perms; > extern int preserve_times; >+extern int force_change; > extern int delete_mode; > extern int delete_before; > extern int delete_during; >@@ -164,11 +166,18 @@ > } > > if (flags & DEL_NO_UID_WRITE) >- do_chmod(fbuf, mode | S_IWUSR); >+ do_chmod(fbuf, mode | S_IWUSR, NO_FFLAGS); > > if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { > /* This only happens on the first call to delete_item() since > * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change) { >+ STRUCT_STAT st; >+ if (x_lstat(fbuf, &st, NULL) == 0) >+ make_mutable(fbuf, st.st_mode, st.st_flags, force_change); >+ } >+#endif > ignore_perishable = 1; > /* If DEL_RECURSE is not set, this just reports emptiness. */ > ret = delete_dir_contents(fbuf, flags); >@@ -285,8 +294,12 @@ > } > > strlcpy(p, fp->basename, remainder); >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change) >+ make_mutable(fname, fp->mode, F_FFLAGS(fp), force_change); >+#endif > if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) >- do_chmod(fname, fp->mode | S_IWUSR); >+ do_chmod(fname, fp->mode | S_IWUSR, NO_FFLAGS); > /* Save stack by recursing to ourself directly. */ > if (S_ISDIR(fp->mode)) { > if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) >@@ -647,6 +660,10 @@ > return 0; > if (perms_differ(file, sxp)) > return 0; >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags && sxp->st.st_flags != F_FFLAGS(file)) >+ return 0; >+#endif > if (ownership_differs(file, sxp)) > return 0; > #ifdef SUPPORT_ACLS >@@ -698,6 +715,11 @@ > if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) > && sxp->st.st_gid != (gid_t)F_GROUP(file)) > iflags |= ITEM_REPORT_GROUP; >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags && !S_ISLNK(file->mode) >+ && sxp->st.st_flags != F_FFLAGS(file)) >+ iflags |= ITEM_REPORT_FFLAGS; >+#endif > #ifdef SUPPORT_ACLS > if (preserve_acls && !S_ISLNK(file->mode)) { > if (!ACL_READY(*sxp)) >@@ -1491,6 +1513,10 @@ > file->mode = dest_mode(file->mode, sx.st.st_mode, > dflt_perms, statret == 0); > } >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && !preserve_fileflags) >+ F_FFLAGS(file) = sx.st.st_flags; >+#endif > if (statret != 0 && basis_dir[0] != NULL) { > int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, > itemizing, code); >@@ -1533,10 +1559,15 @@ > /* We need to ensure that the dirs in the transfer have writable > * permissions during the time we are putting files within them. > * This is then fixed after the transfer is done. */ >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && F_FFLAGS(file) & force_change >+ && make_mutable(fname, file->mode, F_FFLAGS(file), force_change)) >+ need_retouch_dir_perms = 1; >+#endif > #ifdef HAVE_CHMOD > if (!am_root && !(file->mode & S_IWUSR) && dir_tweaking) { > mode_t mode = file->mode | S_IWUSR; >- if (do_chmod(fname, mode) < 0) { >+ if (do_chmod(fname, mode, 0) < 0) { > rsyserr(FERROR_XFER, errno, > "failed to modify permissions on %s", > full_fname(fname)); >@@ -1571,6 +1602,10 @@ > file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, > exists); > } >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && !preserve_fileflags) >+ F_FFLAGS(file) = sx.st.st_flags; >+#endif > > #ifdef SUPPORT_HARD_LINKS > if (preserve_hard_links && F_HLINK_NOT_FIRST(file) >@@ -2114,13 +2149,17 @@ > continue; > fname = f_name(file, NULL); > if (fix_dir_perms) >- do_chmod(fname, file->mode); >+ do_chmod(fname, file->mode, 0); > if (need_retouch_dir_times) { > STRUCT_STAT st; > if (link_stat(fname, &st, 0) == 0 > && cmp_time(st.st_mtime, file->modtime) != 0) >- set_modtime(fname, file->modtime, file->mode); >+ set_modtime(fname, file->modtime, file->mode, 0); > } >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && F_FFLAGS(file) & force_change) >+ undo_make_mutable(fname, F_FFLAGS(file)); >+#endif > if (counter >= loopchk_limit) { > if (allowed_lull) > maybe_send_keepalive(); >diff -Naur a/log.c b/log.c >--- a/log.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/log.c 2011-03-16 14:35:30.000000000 -0500 >@@ -658,7 +658,7 @@ > c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; > c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; > c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; >- c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u'; >+ c[8] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f'; > c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; > c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; > c[11] = '\0'; >diff -Naur a/options.c b/options.c >--- a/options.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/options.c 2011-03-16 14:35:30.000000000 -0500 >@@ -53,6 +53,7 @@ > int preserve_acls = 0; > int preserve_xattrs = 0; > int preserve_perms = 0; >+int preserve_fileflags = 0; > int preserve_executability = 0; > int preserve_devices = 0; > int preserve_specials = 0; >@@ -84,6 +85,7 @@ > int numeric_ids = 0; > int allow_8bit_chars = 0; > int force_delete = 0; >+int force_change = 0; > int io_timeout = 0; > int prune_empty_dirs = 0; > int use_qsort = 0; >@@ -223,6 +225,7 @@ > char const *links = "no "; > char const *iconv = "no "; > char const *ipv6 = "no "; >+ char const *fileflags = "no "; > STRUCT_STAT *dumstat; > > #if SUBPROTOCOL_VERSION != 0 >@@ -256,6 +259,9 @@ > #ifdef CAN_SET_SYMLINK_TIMES > symtimes = ""; > #endif >+#ifdef SUPPORT_FILEFLAGS >+ fileflags = ""; >+#endif > > rprintf(f, "%s version %s protocol version %d%s\n", > RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); >@@ -269,8 +275,8 @@ > (int)(sizeof (int64) * 8)); > rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", > got_socketpair, hardlinks, links, ipv6, have_inplace); >- rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes\n", >- have_inplace, acls, xattrs, iconv, symtimes); >+ rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sfile-flags\n", >+ have_inplace, acls, xattrs, iconv, symtimes, fileflags); > > #ifdef MAINTAINER_MODE > rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); >@@ -337,6 +343,9 @@ > 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"); >+#ifdef SUPPORT_FILEFLAGS >+ rprintf(F," --fileflags preserve file-flags (aka chflags)\n"); >+#endif > rprintf(F," -E, --executability preserve the file's executability\n"); > rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n"); > #ifdef SUPPORT_ACLS >@@ -374,7 +383,12 @@ > rprintf(F," --delete-after receiver deletes after transfer, not during\n"); > rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); > rprintf(F," --ignore-errors delete even if there are I/O errors\n"); >- rprintf(F," --force force deletion of directories even if not empty\n"); >+ rprintf(F," --force-delete force deletion of directories even if not empty\n"); >+#ifdef SUPPORT_FORCE_CHANGE >+ rprintf(F," --force-change affect user-/system-immutable files/dirs\n"); >+ rprintf(F," --force-uchange affect user-immutable files/dirs\n"); >+ rprintf(F," --force-schange affect system-immutable files/dirs\n"); >+#endif > rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); > rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); > rprintf(F," --min-size=SIZE don't transfer any file smaller than SIZE\n"); >@@ -479,6 +493,10 @@ > {"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 }, >+#ifdef SUPPORT_FILEFLAGS >+ {"fileflags", 0, POPT_ARG_VAL, &preserve_fileflags, 1, 0, 0 }, >+ {"no-fileflags", 0, POPT_ARG_VAL, &preserve_fileflags, 0, 0, 0 }, >+#endif > {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, > {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 }, > {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, >@@ -557,6 +575,14 @@ > {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 }, > {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, > {"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 }, >+ {"force-delete", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, >+ {"no-force-delete", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 }, >+#ifdef SUPPORT_FORCE_CHANGE >+ {"force-change", 0, POPT_ARG_VAL, &force_change, ALL_IMMUTABLE, 0, 0 }, >+ {"no-force-change", 0, POPT_ARG_VAL, &force_change, 0, 0, 0 }, >+ {"force-uchange", 0, POPT_ARG_VAL, &force_change, USR_IMMUTABLE, 0, 0 }, >+ {"force-schange", 0, POPT_ARG_VAL, &force_change, SYS_IMMUTABLE, 0, 0 }, >+#endif > {"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 }, > {"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 }, > {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 }, >@@ -1879,6 +1905,9 @@ > if (xfer_dirs && !recurse && delete_mode && am_sender) > args[ac++] = "--no-r"; > >+ if (preserve_fileflags) >+ args[ac++] = "--fileflags"; >+ > if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) { > if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0) > goto oom; >@@ -1966,6 +1995,16 @@ > args[ac++] = "--delete-excluded"; > if (force_delete) > args[ac++] = "--force"; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change) { >+ if (force_change == ALL_IMMUTABLE) >+ args[ac++] = "--force-change"; >+ else if (force_change == USR_IMMUTABLE) >+ args[ac++] = "--force-uchange"; >+ else if (force_change == SYS_IMMUTABLE) >+ args[ac++] = "--force-schange"; >+ } >+#endif > if (write_batch < 0) > args[ac++] = "--only-write-batch=X"; > if (am_root > 1) >diff -Naur a/rsync.c b/rsync.c >--- a/rsync.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/rsync.c 2011-03-16 15:09:34.000000000 -0500 >@@ -31,7 +31,9 @@ > extern int dry_run; > extern int preserve_acls; > extern int preserve_xattrs; >+extern int force_change; > extern int preserve_perms; >+extern int preserve_fileflags; > extern int preserve_executability; > extern int preserve_times; > extern int am_root; >@@ -374,6 +376,41 @@ > return new_mode; > } > >+#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE >+/* Set a file's st_flags. */ >+static int set_fileflags(const char *fname, uint32 fileflags) >+{ >+ if (do_chflags(fname, fileflags) != 0) { >+ rsyserr(FERROR_XFER, errno, >+ "failed to set file flags (%d) on %s", fileflags, >+ full_fname(fname)); >+ return 0; >+ } >+ >+ return 1; >+} >+ >+/* Remove immutable flags from an object, so it can be altered/removed. */ >+int make_mutable(const char *fname, mode_t mode, uint32 fileflags, uint32 iflags) >+{ >+ if (S_ISLNK(mode) || !(fileflags & iflags)) >+ return 0; >+ if (!set_fileflags(fname, fileflags & ~iflags)) >+ return -1; >+ return 1; >+} >+ >+/* Undo a prior make_mutable() call that returned a 1. */ >+int undo_make_mutable(const char *fname, uint32 fileflags) >+{ >+ if (!set_fileflags(fname, fileflags)) { >+ rsyserr(FINFO, errno, "failed to relock %s", full_fname(fname)); >+ return -1; >+ } >+ return 1; >+} >+#endif >+ > int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, > const char *fnamecmp, int flags) > { >@@ -382,6 +419,7 @@ > int change_uid, change_gid; > mode_t new_mode = file->mode; > int inherit; >+ int became_mutable = 0; > > if (!sxp) { > if (dry_run) >@@ -411,6 +449,11 @@ > if (daemon_chmod_modes && !S_ISLNK(new_mode)) > new_mode = tweak_mode(new_mode, daemon_chmod_modes); > >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change) >+ became_mutable = make_mutable(fname, sxp->st.st_mode, sxp->st.st_flags, force_change) > 0; >+#endif >+ > #ifdef SUPPORT_ACLS > if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp)) > get_acl(fname, sxp); >@@ -429,7 +472,7 @@ > flags |= ATTRS_SKIP_MTIME; > if (!(flags & ATTRS_SKIP_MTIME) > && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { >- int ret = set_modtime(fname, file->modtime, sxp->st.st_mode); >+ int ret = set_modtime(fname, file->modtime, sxp->st.st_mode, ST_FLAGS(sxp->st)); > if (ret < 0) { > rsyserr(FERROR_XFER, errno, "failed to set times on %s", > full_fname(fname)); >@@ -465,7 +508,7 @@ > if (am_root >= 0) { > uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid; > gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid; >- if (do_lchown(fname, uid, gid) != 0) { >+ if (do_lchown(fname, uid, gid, sxp->st.st_mode, ST_FLAGS(sxp->st)) != 0) { > /* We shouldn't have attempted to change uid > * or gid unless have the privilege. */ > rsyserr(FERROR_XFER, errno, "%s %s failed", >@@ -503,7 +546,7 @@ > > #ifdef HAVE_CHMOD > if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) { >- int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode); >+ int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode, ST_FLAGS(sxp->st)); > if (ret < 0) { > rsyserr(FERROR_XFER, errno, > "failed to set permissions on %s", >@@ -515,6 +558,24 @@ > } > #endif > >+#ifdef SUPPORT_FORCE_CHANGE >+ if (became_mutable) >+ undo_make_mutable(fname, sxp->st.st_flags); >+#endif >+ >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags && !S_ISLNK(sxp->st.st_mode) >+ && sxp->st.st_flags != F_FFLAGS(file)) { >+ uint32 fileflags = F_FFLAGS(file); >+ if (flags & ATTRS_DELAY_IMMUTABLE) >+ fileflags &= ~ALL_IMMUTABLE; >+ if (sxp->st.st_flags != fileflags >+ && !set_fileflags(fname, fileflags)) >+ goto cleanup; >+ updated = 1; >+ } >+#endif >+ > if (verbose > 1 && flags & ATTRS_REPORT) { > if (updated) > rprintf(FCLIENT, "%s\n", fname); >@@ -578,7 +639,8 @@ > > /* Change permissions before putting the file into place. */ > set_file_attrs(fnametmp, file, NULL, fnamecmp, >- ok_to_set_time ? 0 : ATTRS_SKIP_MTIME); >+ ATTRS_DELAY_IMMUTABLE >+ | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME)); > > /* move tmp file over real file */ > if (verbose > 2) >@@ -597,6 +659,10 @@ > } > if (ret == 0) { > /* The file was moved into place (not copied), so it's done. */ >+#ifdef SUPPORT_FILEFLAGS >+ if (preserve_fileflags && F_FFLAGS(file) & ALL_IMMUTABLE) >+ set_fileflags(fname, F_FFLAGS(file)); >+#endif > return 1; > } > /* The file was copied, so tweak the perms of the copied file. If it >diff -Naur a/rsync.h b/rsync.h >--- a/rsync.h 2011-03-16 13:25:12.000000000 -0500 >+++ b/rsync.h 2011-03-16 14:35:30.000000000 -0500 >@@ -61,6 +61,7 @@ > #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */ > #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */ > #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */ >+#define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */ > > /* These flags are used in the live flist data. */ > >@@ -160,6 +161,7 @@ > > #define ATTRS_REPORT (1<<0) > #define ATTRS_SKIP_MTIME (1<<1) >+#define ATTRS_DELAY_IMMUTABLE (1<<2) > > #define FULL_FLUSH 1 > #define NORMAL_FLUSH 0 >@@ -186,6 +188,7 @@ > #define ITEM_REPORT_GROUP (1<<6) > #define ITEM_REPORT_ACL (1<<7) > #define ITEM_REPORT_XATTR (1<<8) >+#define ITEM_REPORT_FFLAGS (1<<9) > #define ITEM_BASIS_TYPE_FOLLOWS (1<<11) > #define ITEM_XNAME_FOLLOWS (1<<12) > #define ITEM_IS_NEW (1<<13) >@@ -482,6 +485,28 @@ > #endif > #endif > >+#define NO_FFLAGS ((uint32)-1) >+ >+#ifdef HAVE_CHFLAGS >+#define SUPPORT_FILEFLAGS 1 >+#define SUPPORT_FORCE_CHANGE 1 >+#endif >+ >+#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE >+#ifndef UF_NOUNLINK >+#define UF_NOUNLINK 0 >+#endif >+#ifndef SF_NOUNLINK >+#define SF_NOUNLINK 0 >+#endif >+#define USR_IMMUTABLE (UF_IMMUTABLE|UF_NOUNLINK|UF_APPEND) >+#define SYS_IMMUTABLE (SF_IMMUTABLE|SF_NOUNLINK|SF_APPEND) >+#define ALL_IMMUTABLE (USR_IMMUTABLE|SYS_IMMUTABLE) >+#define ST_FLAGS(st) (st.st_flags) >+#else >+#define ST_FLAGS(st) NO_FFLAGS >+#endif >+ > /* Find a variable that is either exactly 32-bits or longer. > * If some code depends on 32-bit truncation, it will need to > * take special action in a "#if SIZEOF_INT32 > 4" section. */ >@@ -652,6 +677,7 @@ > extern int inc_recurse; > extern int uid_ndx; > extern int gid_ndx; >+extern int fileflags_ndx; > extern int acls_ndx; > extern int xattrs_ndx; > >@@ -689,6 +715,11 @@ > /* When the associated option is on, all entries will have these present: */ > #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum > #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum >+#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE >+#define F_FFLAGS(f) REQ_EXTRA(f, fileflags_ndx)->unum >+#else >+#define F_FFLAGS(f) NO_FFLAGS >+#endif > #define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num > #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num > #define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num >diff -Naur a/rsync.yo b/rsync.yo >--- a/rsync.yo 2011-03-16 13:25:12.000000000 -0500 >+++ b/rsync.yo 2011-03-16 14:35:30.000000000 -0500 >@@ -342,6 +342,7 @@ > -K, --keep-dirlinks treat symlinked dir on receiver as dir > -H, --hard-links preserve hard links > -p, --perms preserve permissions >+ --fileflags preserve file-flags (aka chflags) > -E, --executability preserve executability > --chmod=CHMOD affect file and/or directory permissions > -A, --acls preserve ACLs (implies -p) >@@ -373,7 +374,10 @@ > --delete-after receiver deletes after transfer, not before > --delete-excluded also delete excluded files from dest dirs > --ignore-errors delete even if there are I/O errors >- --force force deletion of dirs even if not empty >+ --force-delete force deletion of dirs even if not empty >+ --force-change affect user/system immutable files/dirs >+ --force-uchange affect user-immutable files/dirs >+ --force-schange affect system-immutable files/dirs > --max-delete=NUM don't delete more than NUM files > --max-size=SIZE don't transfer any file larger than SIZE > --min-size=SIZE don't transfer any file smaller than SIZE >@@ -547,7 +551,8 @@ > > 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 backward compatibility, bf(-a) >+currently does bf(not) imply the bf(--fileflags) option. > > 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-": >@@ -827,7 +832,7 @@ > Without this option, if the sending side has replaced a directory with a > symlink to a directory, the receiving side will delete anything that is in > the way of the new symlink, including a directory hierarchy (as long as >-bf(--force) or bf(--delete) is in effect). >+bf(--force-delete) or bf(--delete) is in effect). > > See also bf(--keep-dirlinks) for an analogous option for the receiving > side. >@@ -990,6 +995,29 @@ > used by bf(--fake-super)) unless you repeat the option (e.g. -XX). This > "copy all xattrs" mode cannot be used with bf(--fake-super). > >+dit(bf(--fileflags)) This option causes rsync to update the file-flags to be >+the same as the source files and directories (if your OS supports the >+bf(chflags)(2) system call). Some flags can only be altered by the super-user >+and some might only be unset below a certain secure-level (usually single-user >+mode). It will not make files alterable that are set to immutable on the >+receiver. To do that, see bf(--force-change), bf(--force-uchange), and >+bf(--force-schange). >+ >+dit(bf(--force-change)) This option causes rsync to disable both user-immutable >+and system-immutable flags on files and directories that are being updated or >+deleted on the receiving side. This option overrides bf(--force-uchange) and >+bf(--force-schange). >+ >+dit(bf(--force-uchange)) This option causes rsync to disable user-immutable >+flags on files and directories that are being updated or deleted on the >+receiving side. It does not try to affect system flags. This option overrides >+bf(--force-change) and bf(--force-schange). >+ >+dit(bf(--force-schange)) This option causes rsync to disable system-immutable >+flags on files and directories that are being updated or deleted on the >+receiving side. It does not try to affect user flags. This option overrides >+bf(--force-change) and bf(--force-schange). >+ > 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 were the permissions >@@ -1260,12 +1288,13 @@ > dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files > even when there are I/O errors. > >-dit(bf(--force)) This option tells rsync to delete a non-empty directory >+dit(bf(--force-delete)) This option tells rsync to delete a non-empty directory > when it is to be replaced by a non-directory. This is only relevant if > deletions are not active (see bf(--delete) for details). > >-Note for older rsync versions: bf(--force) used to still be required when >-using bf(--delete-after), and it used to be non-functional unless the >+This option can be abbreviated bf(--force) for backward compatibility. >+Note that some older rsync versions used to still require bf(--force) >+when using bf(--delete-after), and it used to be non-functional unless the > bf(--recursive) option was also enabled. > > dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM >@@ -1753,7 +1782,7 @@ > verbose messages). > > The "%i" escape has a cryptic output that is 11 letters long. The general >-format is like the string bf(YXcstpoguax), where bf(Y) is replaced by the >+format is like the string bf(YXcstpogfax), where bf(Y) is replaced by the > type of update being done, bf(X) is replaced by the file-type, and the > other letters represent attributes that may be output if they are being > modified. >@@ -1809,7 +1838,7 @@ > sender's value (requires bf(--owner) and super-user privileges). > it() A bf(g) means the group is different and is being updated to the > sender's value (requires bf(--group) and the authority to set the group). >- it() The bf(u) slot is reserved for future use. >+ it() The bf(f) means that the fileflags information changed. > it() The bf(a) means that the ACL information changed. > it() The bf(x) means that the extended attribute information changed. > )) >diff -Naur a/syscall.c b/syscall.c >--- a/syscall.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/syscall.c 2011-03-16 16:17:33.000000000 -0500 >@@ -29,10 +29,14 @@ > #include <sys/attr.h> > #endif > >+/* For dirname() */ >+#include <libgen.h> >+ > extern int dry_run; > extern int am_root; > extern int read_only; > extern int list_only; >+extern int force_change; > extern int preserve_perms; > extern int preserve_executability; > >@@ -50,33 +54,136 @@ > { > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; >- return unlink(fname); >+ if (unlink(fname) == 0) >+ return 0; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT st, pst; >+ char *parent; >+ int became_mutable; >+ int saved_errno = errno; >+ >+ if (x_lstat(fname, &st, NULL) == 0) { >+ became_mutable = make_mutable(fname, st.st_mode, st.st_flags, force_change) > 0; >+ if (became_mutable && unlink(fname) == 0) >+ return 0; >+ >+ if ((parent = (char *)dirname((char *)fname)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ if (unlink(fname) == 0) { >+ undo_make_mutable(parent, pst.st_flags); >+ return 0; >+ } else { >+ undo_make_mutable(parent, pst.st_flags); >+ if (became_mutable) >+ undo_make_mutable(fname, st.st_flags); >+ } >+ } >+ } >+ } >+ errno = saved_errno; >+ } >+#endif >+ return -1; > } > > int do_symlink(const char *fname1, const char *fname2) > { >+ int ret; > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; >- return symlink(fname1, fname2); >+ ret = symlink(fname1, fname2); >+ >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT pst; >+ char *parent; >+ int saved_errno = errno; >+ >+ /* Attempt to make the parent directory mutable */ >+ if ((parent = (char *)dirname((char *)fname2)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ if (symlink(fname1, fname2) == 0) { >+ undo_make_mutable(parent, pst.st_flags); >+ return 0; >+ } else >+ undo_make_mutable(parent, pst.st_flags); >+ } >+ errno = saved_errno; >+ } >+ } >+#endif >+ >+ return ret; > } > > #ifdef HAVE_LINK > int do_link(const char *fname1, const char *fname2) > { >+ int ret; > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; >- return link(fname1, fname2); >+ ret = link(fname1, fname2); >+ >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT pst; >+ char *parent; >+ int saved_errno = errno; >+ >+ /* Attempt to make the parent directory mutable */ >+ if ((parent = (char *)dirname((char *)fname2)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ if (link(fname1, fname2) == 0) { >+ undo_make_mutable(parent, pst.st_flags); >+ return 0; >+ } else >+ undo_make_mutable(parent, pst.st_flags); >+ } >+ errno = saved_errno; >+ } >+ } >+#endif >+ >+ return ret; > } > #endif > >-int do_lchown(const char *path, uid_t owner, gid_t group) >+int do_lchown(const char *path, uid_t owner, gid_t group, mode_t mode, uint32 fileflags) > { > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; > #ifndef HAVE_LCHOWN > #define lchown chown > #endif >- return lchown(path, owner, group); >+ if (lchown(path, owner, group) == 0) >+ return 0; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && (errno == EPERM || errno == EACCES)) { >+ int saved_errno = errno; >+ if (fileflags == NO_FFLAGS) { >+ STRUCT_STAT st; >+ if (x_lstat(path, &st, NULL) == 0) { >+ mode = st.st_mode; >+ fileflags = st.st_flags; >+ } >+ } >+ if (fileflags != NO_FFLAGS >+ && make_mutable(path, mode, fileflags, force_change) > 0) { >+ int ret = lchown(path, owner, group); >+ undo_make_mutable(path, fileflags); >+ if (ret == 0) >+ return 0; >+ } >+ errno = saved_errno; >+ } >+#else >+ mode = fileflags = 0; /* avoid compiler warning */ >+#endif >+ return -1; > } > > int do_mknod(const char *pathname, mode_t mode, dev_t dev) >@@ -116,7 +223,7 @@ > return -1; > close(sock); > #ifdef HAVE_CHMOD >- return do_chmod(pathname, mode); >+ return do_chmod(pathname, mode, 0); > #else > return 0; > #endif >@@ -133,21 +240,74 @@ > { > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; >- return rmdir(pathname); >+ if (rmdir(pathname) == 0) >+ return 0; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT st, pst; >+ char *parent; >+ int became_mutable; >+ int saved_errno = errno; >+ >+ if (x_lstat(pathname, &st, NULL) == 0) { >+ became_mutable = make_mutable(pathname, st.st_mode, st.st_flags, force_change); >+ if (became_mutable >= 0) { /* even if this item is not immutable, the parent may be */ >+ if (rmdir(pathname) == 0) >+ return 0; >+ else { >+ /* Attempt to make the parent directory mutable */ >+ if ((parent = (char *)dirname((char *)pathname)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ if (rmdir(pathname) == 0) { >+ undo_make_mutable(parent, pst.st_flags); >+ return 0; >+ } else >+ undo_make_mutable(parent, pst.st_flags); >+ } >+ } >+ } >+ if (became_mutable) >+ undo_make_mutable(pathname, st.st_flags); >+ } >+ } >+ errno = saved_errno; >+ } >+#endif >+ return -1; > } > > int do_open(const char *pathname, int flags, mode_t mode) > { >+ int fd; > if (flags != O_RDONLY) { > RETURN_ERROR_IF(dry_run, 0); > RETURN_ERROR_IF_RO_OR_LO; > } > >- return open(pathname, flags | O_BINARY, mode); >+ fd = open(pathname, flags | O_BINARY, mode); >+#ifdef SUPPORT_FORCE_CHANGE >+ if (fd == -1 && force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT pst; >+ char *parent; >+ int saved_errno = errno; >+ >+ /* Attempt to make the parent directory mutable */ >+ if ((parent = (char *)dirname((char *)pathname)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ fd = open(pathname, flags | O_BINARY, mode); >+ undo_make_mutable(parent, pst.st_flags); >+ } >+ errno = saved_errno; >+ } >+ } >+#endif >+ return fd; > } > > #ifdef HAVE_CHMOD >-int do_chmod(const char *path, mode_t mode) >+int do_chmod(const char *path, mode_t mode, uint32 fileflags) > { > int code; > if (dry_run) return 0; >@@ -170,17 +330,120 @@ > } else > code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ > #endif /* !HAVE_LCHMOD */ >+#ifdef SUPPORT_FORCE_CHANGE >+ if (code < 0 && force_change && (errno == EPERM || errno == EACCES) && !S_ISLNK(mode)) { >+ int saved_errno = errno; >+ if (fileflags == NO_FFLAGS) { >+ STRUCT_STAT st; >+ if (x_lstat(path, &st, NULL) == 0) >+ fileflags = st.st_flags; >+ } >+ if (fileflags != NO_FFLAGS >+ && make_mutable(path, mode, fileflags, force_change) > 0) { >+#ifdef HAVE_LCHMOD >+ code = lchmod(path, mode & CHMOD_BITS); >+#else >+ code = chmod(path, mode & CHMOD_BITS); >+#endif >+ undo_make_mutable(path, fileflags); >+ if (code == 0) >+ return 0; >+ } >+ errno = saved_errno; >+ } >+#else >+ fileflags = 0; /* avoid compiler warning */ >+#endif > if (code != 0 && (preserve_perms || preserve_executability)) > return code; > return 0; > } > #endif > >+#ifdef HAVE_CHFLAGS >+int do_chflags(const char *path, uint32 fileflags) >+{ >+ if (dry_run) return 0; >+ RETURN_ERROR_IF_RO_OR_LO; >+ return chflags(path, fileflags); >+} >+#endif >+ > int do_rename(const char *fname1, const char *fname2) > { > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; >- return rename(fname1, fname2); >+ if (rename(fname1, fname2) == 0) >+ return 0; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT st1, st2, pst1, pst2; >+ int became_mutable = 0, p1_mutable = 0, p2_mutable = 0; >+ char *dirtmp, p1[MAXPATHLEN], p2[MAXPATHLEN]; >+ int saved_errno = errno; >+ >+ if (x_lstat(fname1, &st1, NULL) != 0) >+ goto failed; >+ became_mutable = make_mutable(fname1, st1.st_mode, st1.st_flags, force_change) > 0; >+ if (became_mutable && rename(fname1, fname2) == 0) >+ goto success; >+ if (x_lstat(fname2, &st2, NULL) == 0 >+ && make_mutable(fname2, st2.st_mode, st2.st_flags, force_change) > 0) { >+ if (rename(fname1, fname2) == 0) >+ goto success; >+ } >+ >+ /* Now try making the parent directories mutable */ >+ if ((dirtmp = (char *)dirname((char *)fname1)) == NULL) >+ goto failed; >+ strncpy(p1, dirtmp, MAXPATHLEN); >+ >+ if (x_lstat(p1, &pst1, NULL) != 0) >+ goto failed; >+ >+ p1_mutable = make_mutable(p1, pst1.st_mode, pst1.st_flags, force_change) > 0; >+ if (p1_mutable && rename(fname1, fname2) == 0) >+ goto success; >+ >+ if ((dirtmp = (char *)dirname((char *)fname2)) == NULL) >+ goto failed; >+ strncpy(p2, dirtmp, MAXPATHLEN); >+ >+ if (strcmp(p1, p2) != 0) { >+ if (x_lstat(p2, &pst2, NULL) != 0) >+ goto failed; >+ >+ p2_mutable = make_mutable(p2, pst2.st_mode, pst2.st_flags, force_change) > 0; >+ if (p2_mutable && rename(fname1, fname2) == 0) >+ goto success; >+ >+ } >+ >+ failed: >+ errno = saved_errno; >+ if (became_mutable) { >+ undo_make_mutable(fname1, st1.st_flags); >+ undo_make_mutable(fname2, st2.st_flags); >+ } >+ if (p1_mutable) >+ undo_make_mutable(p1, pst1.st_flags); >+ if (p2_mutable) >+ undo_make_mutable(p2, pst2.st_flags); >+ return -1; >+ >+ success: >+ if (became_mutable) /* Yes, use fname2 and st1! */ >+ undo_make_mutable(fname2, st1.st_flags); >+ if (p1_mutable) >+ undo_make_mutable(p1, pst1.st_flags); >+ if (p2_mutable) >+ undo_make_mutable(p2, pst2.st_flags); >+ return 0; >+ >+ >+ } >+#endif >+ return -1; > } > > #ifdef HAVE_FTRUNCATE >@@ -219,10 +482,34 @@ > > int do_mkdir(char *fname, mode_t mode) > { >+ int ret; > if (dry_run) return 0; > RETURN_ERROR_IF_RO_OR_LO; > trim_trailing_slashes(fname); >- return mkdir(fname, mode); >+ ret = mkdir(fname, mode); >+ >+#ifdef SUPPORT_FORCE_CHANGE >+ if (ret != 0 && force_change && (errno == EPERM || errno == EACCES)) { >+ STRUCT_STAT pst; >+ char *parent; >+ int saved_errno = errno; >+ >+ /* Attempt to make the parent directory mutable */ >+ if ((parent = (char *)dirname(fname)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ if (mkdir(fname, mode) == 0) { >+ undo_make_mutable(parent, pst.st_flags); >+ return 0; >+ } else >+ undo_make_mutable(parent, pst.st_flags); >+ } >+ errno = saved_errno; >+ } >+ } >+#endif >+ >+ return ret; > } > > /* like mkstemp but forces permissions */ >@@ -235,6 +522,21 @@ > #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64) > { > int fd = mkstemp(template); >+#ifdef SUPPORT_FORCE_CHANGE >+ int saved_errno = errno; >+ if (fd == -1) { >+ STRUCT_STAT pst; >+ char *parent; >+ if ((parent = (char *)dirname(template)) != NULL >+ && x_lstat(parent, &pst, NULL) == 0) { >+ if (force_change && make_mutable(parent, pst.st_mode, pst.st_flags, force_change) > 0) { >+ fd = mkstemp(template); >+ undo_make_mutable(parent, pst.st_flags); >+ } >+ } >+ } >+ errno = saved_errno; >+#endif > if (fd == -1) > return -1; > if (fchmod(fd, perms) != 0 && preserve_perms) { >diff -Naur a/t_stub.c b/t_stub.c >--- a/t_stub.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/t_stub.c 2011-03-16 14:35:30.000000000 -0500 >@@ -26,6 +26,7 @@ > int relative_paths = 0; > int human_readable = 0; > int module_dirlen = 0; >+int force_change = 0; > int preserve_times = 0; > int preserve_xattrs = 0; > mode_t orig_umask = 002; >@@ -90,3 +91,23 @@ > { > return "tester"; > } >+ >+#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE >+ int make_mutable(UNUSED(const char *fname), UNUSED(mode_t mode), UNUSED(uint32 fileflags), UNUSED(uint32 iflags)) >+{ >+ return 0; >+} >+ >+/* Undo a prior make_mutable() call that returned a 1. */ >+ int undo_make_mutable(UNUSED(const char *fname), UNUSED(uint32 fileflags)) >+{ >+ return 0; >+} >+#endif >+ >+#ifdef SUPPORT_XATTRS >+ int x_lstat(UNUSED(const char *fname), UNUSED(STRUCT_STAT *fst), UNUSED(STRUCT_STAT *xst)) >+{ >+ return -1; >+} >+#endif >diff -Naur a/util.c b/util.c >--- a/util.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/util.c 2011-03-16 14:35:30.000000000 -0500 >@@ -30,6 +30,7 @@ > extern int relative_paths; > extern int preserve_times; > extern int human_readable; >+extern int force_change; > extern int preserve_xattrs; > extern char *module_dir; > extern unsigned int module_dirlen; >@@ -124,9 +125,34 @@ > exit_cleanup(RERR_MALLOC); > } > >+#ifdef SUPPORT_FORCE_CHANGE >+static int try_a_force_change(const char *fname, time_t modtime, mode_t mode, uint32 fileflags) >+{ >+ if (fileflags == NO_FFLAGS) { >+ STRUCT_STAT st; >+ if (x_lstat(fname, &st, NULL) == 0) >+ fileflags = st.st_flags; >+ } >+ >+ if (fileflags != NO_FFLAGS && make_mutable(fname, mode, fileflags, force_change) > 0) { >+ int ret, save_force_change = force_change; >+ >+ force_change = 0; /* Make certain we can't come back here. */ >+ ret = set_modtime(fname, modtime, mode, fileflags); >+ force_change = save_force_change; >+ >+ undo_make_mutable(fname, fileflags); >+ } >+ >+ errno = EPERM; >+ >+ return -1; >+} >+#endif >+ > /* This returns 0 for success, 1 for a symlink if symlink time-setting > * is not possible, or -1 for any other error. */ >-int set_modtime(const char *fname, time_t modtime, mode_t mode) >+int set_modtime(const char *fname, time_t modtime, mode_t mode, uint32 fileflags) > { > static int switch_step = 0; > >@@ -141,6 +167,11 @@ > #include "case_N.h" > if (do_utimensat(fname, modtime, 0) == 0) > break; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && errno == EPERM >+ && try_a_force_change(fname, modtime, mode, fileflags) == 0) >+ break; >+#endif > if (errno != ENOSYS) > return -1; > switch_step++; >@@ -151,6 +182,11 @@ > #include "case_N.h" > if (do_lutimes(fname, modtime, 0) == 0) > break; >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && errno == EPERM >+ && try_a_force_change(fname, modtime, mode, fileflags) == 0) >+ break; >+#endif > if (errno != ENOSYS) > return -1; > switch_step++; >@@ -174,6 +210,13 @@ > if (do_utime(fname, modtime, 0) == 0) > break; > #endif >+#ifdef SUPPORT_FORCE_CHANGE >+ if (force_change && errno == EPERM >+ && try_a_force_change(fname, modtime, mode, fileflags) == 0) >+ break; >+#else >+ fileflags = 0; /* avoid compiler warning */ >+#endif > > return -1; > } >diff -Naur a/xattrs.c b/xattrs.c >--- a/xattrs.c 2011-03-16 13:25:12.000000000 -0500 >+++ b/xattrs.c 2011-03-16 14:35:30.000000000 -0500 >@@ -1041,7 +1041,7 @@ > mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS) > | (S_ISDIR(fst.st_mode) ? 0700 : 0600); > if (fst.st_mode != mode) >- do_chmod(fname, mode); >+ do_chmod(fname, mode, ST_FLAGS(fst)); > if (!IS_DEVICE(fst.st_mode)) > fst.st_rdev = 0; /* just in case */ >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 8019
: 6298