Hello,
are there any other opinions about the suggested patch?
It adds an option "--dirs-update", which handles directories in a similar way
as "--update" handles files. We face a certain situation where this is useful.
Suggestions to improve the patch are welcome.
Arvid
Am Montag, 20. Januar 2014, 16:44:02 schrieb Arvid Requate:
> Hello,
>
> thanks for your comments. Attached you may find a git patch based on the
> master branch. The patch adds a new rsync option which helps in our use
> case of replicating Samba 4 sysvol directories. In this specific case
> fACLs, xattrs and modification timestamps of subfolders of the target can
> get modified by Windows client tools in between subsequent rsync runs. If
> this happens, they should not be overwritten to avoid inconsistencies and
> client side error messages.
>
> To achive this, the patch implements an option "--dirs-update" to let rsync
> skip changes to directories in case the target directory has a more recent
> modification timestamp than the source directory *and* the direct content of
> the directories is the same. This option can be regarded as complementary
> to the existing option "--update", which does pretty much the same for
> files. The patch also provides a script for the testsuite.
>
> Maybe the patch is also useful for others. If it doesn't inflict any
> collateral damage on the general behaviour of rsync (e.g. the incremental
> recursion), maybe it would be worthwile to submit it as an enhancement bug
> to the bugzilla. Any opinions about this or suggestions for imrovement?
>
> On 16.01.2014 01:31:38, Matthias Schniedermeyer wrote:
> > - rsync doesn't determine if atime/mtime is bigger/smaller, it only
> > determines if they are identical or not.
>
> From looking at the function cmp_time in util.c and its use in generator.c I
> obtained the impression that time ordering is explicitely considered. My
> patch makes use of this function. Also the description of the option
> "--update" in the manual page ("skip files that are newer") seems to
> support this impression.
>
> I'm aware of the unidirectional nature of rsync you pointed out. We use
> rsync to let two machines pull the content of a certain directory tree and
> let them take turns at that. Modification time ordering is essential for
> this. Since Samba doesn't implement DFS replication yet we have to rely on
> this.
>
> Cheers,
> Arvid
--
Dr. Arvid Requate
Open Source Software Engineer
Univention GmbH
be open.
Mary-Somerville-Str.1
28359 Bremen
Tel. : +49 421 22232-52
Fax : +49 421 22232-99
requ...@univention.de
http://www.univention.de
Geschäftsführer: Peter H. Ganten
HRB 20755 Amtsgericht Bremen
Steuer-Nr.: 71-597-02876
>From c7ea18e917e2324f495fce1e2259f614da71fded Mon Sep 17 00:00:00 2001
From: Arvid Requate <requ...@univention.de>
Date: Fri, 17 Jan 2014 03:03:33 +0100
Subject: [PATCH] Additional option --dirs-update
---
generator.c | 18 ++++++
options.c | 3 +
rsync.h | 1 +
rsync.yo | 7 +++
testsuite/dirs-update.test | 125 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 154 insertions(+), 0 deletions(-)
create mode 100644 testsuite/dirs-update.test
diff --git a/generator.c b/generator.c
index 0f77481..6554cfd 100644
--- a/generator.c
+++ b/generator.c
@@ -54,6 +54,7 @@ extern int ignore_errors;
extern int remove_source_files;
extern int delay_updates;
extern int update_only;
+extern int dirs_update_only;
extern int human_readable;
extern int ignore_existing;
extern int ignore_non_existing;
@@ -1372,6 +1373,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
dry_missing_dir = file;
file->flags |= FLAG_MISSING_DIR;
}
+
+ if (dirs_update_only > 0 && statret == 0
+ && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
+ if (INFO_GTE(SKIP, 1))
+ rprintf(FINFO, "%s is newer\n", fname);
+ file->flags |= FLAG_DONT_TOUCH_UP;
+ goto cleanup;
+ }
+
init_stat_x(&real_sx);
real_sx.st = sx.st;
real_ret = statret;
@@ -2019,6 +2029,14 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
if (!S_ISDIR(file->mode)
|| (!implied_dirs && file->flags & FLAG_IMPLIED_DIR))
continue;
+ if (S_ISDIR(file->mode) && file->flags & FLAG_DONT_TOUCH_UP) {
+ fname = f_name(file, NULL);
+ if (INFO_GTE(SKIP, 3)) {
+ rprintf(FINFO, "skipping touch_up_dirs: %s (%d)\n",
+ NS(fname), i);
+ }
+ continue;
+ }
if (DEBUG_GTE(TIME, 2)) {
fname = f_name(file, NULL);
rprintf(FINFO, "touch_up_dirs: %s (%d)\n",
diff --git a/options.c b/options.c
index cc2c1ef..1b142cf 100644
--- a/options.c
+++ b/options.c
@@ -60,6 +60,7 @@ int preserve_uid = 0;
int preserve_gid = 0;
int preserve_times = 0;
int update_only = 0;
+int dirs_update_only = 0;
int cvs_exclude = 0;
int dry_run = 0;
int do_xfers = 1;
@@ -680,6 +681,7 @@ void usage(enum logcode F)
rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n");
rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
rprintf(F," -u, --update skip files that are newer on the receiver\n");
+ rprintf(F," --dirs-update skip dirs that are newer on the receiver\n");
rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n");
rprintf(F," --append append data onto shorter files\n");
rprintf(F," --append-verify like --append, but with old data in file checksum\n");
@@ -914,6 +916,7 @@ static struct poptOption long_options[] = {
{"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
{"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
{"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
+ {"dirs-update", 0, POPT_ARG_NONE, &dirs_update_only, 0, 0, 0 },
{"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 },
{"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 },
{"ignore-existing", 0, POPT_ARG_NONE, &ignore_existing, 0, 0, 0 },
diff --git a/rsync.h b/rsync.h
index b2869d0..858b8ab 100644
--- a/rsync.h
+++ b/rsync.h
@@ -83,6 +83,7 @@
#define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */
#define FLAG_TIME_FAILED (1<<11)/* generator */
#define FLAG_MOD_NSEC (1<<12) /* sender/receiver/generator */
+#define FLAG_DONT_TOUCH_UP (1<<13)/* generator */
/* These flags are passed to functions but not stored. */
diff --git a/rsync.yo b/rsync.yo
index a84b7bf..d2f4bc1 100644
--- a/rsync.yo
+++ b/rsync.yo
@@ -346,6 +346,7 @@ to the detailed description below for a complete description. verb(
--backup-dir=DIR make backups into hierarchy based in DIR
--suffix=SUFFIX backup suffix (default ~ w/o --backup-dir)
-u, --update skip files that are newer on the receiver
+ --dirs-update skip dirs that are newer on the receiver
--inplace update destination files in-place
--append append data onto shorter files
--append-verify --append w/old data in file checksum
@@ -800,6 +801,12 @@ This option is a transfer rule, not an exclude, so it doesn't affect the
data that goes into the file-lists, and thus it doesn't affect deletions.
It just limits the files that the receiver requests to be transferred.
+dit(bf(--dirs-update)) This forces rsync to skip modification of the status
+of directories (i.e. ownership, posix permissions, fACLs, extended attributes)
+which exist on the destination and have a modified time that is newer than
+the source directory. The directory content will be considered for replication
+anyway.
+
dit(bf(--inplace)) This option changes how rsync transfers a file when
its data needs to be updated: instead of the default method of creating
a new copy of the file and moving it into place when it is complete, rsync
diff --git a/testsuite/dirs-update.test b/testsuite/dirs-update.test
new file mode 100644
index 0000000..0cc855e
--- /dev/null
+++ b/testsuite/dirs-update.test
@@ -0,0 +1,125 @@
+#! /bin/sh
+
+# This program is distributable under the terms of the GNU GPL (see
+# COPYING).
+
+# Test that rsync handles dirctory ACL preservation.
+
+. $srcdir/testsuite/rsync.fns
+set -x
+
+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
+
+makepath "$fromdir/sub1"
+makepath "$fromdir/sub2"
+makepath "$fromdir/sub3"
+
+dst_preferred_files='. sub1 sub3'
+src_preferred_files='sub2 sub1/file1 sub2/file2'
+
+case "$setfacl_nodef" in
+true)
+ if ! chmod --help 2>&1 | fgrep +a >/dev/null; then
+ test_skipped "I don't know how to use setfacl or chmod for ACLs"
+ fi
+ chmod +a "root allow read,write,execute" "$fromdir/sub1" || test_skipped "Your filesystem has ACLs disabled"
+ chmod +a "admin allow read" "$fromdir/sub1"
+ chmod +a "daemon allow read,write" "$fromdir/sub1"
+
+ chmod +a "root allow read,write,execute" "$fromdir/sub2"
+ chmod +a "admin allow read" "$fromdir/sub2"
+ chmod +a "daemon allow read,write" "$fromdir/sub2"
+
+ chmod +a "root allow read,write,execute" "$fromdir/sub3"
+ chmod +a "admin allow read" "$fromdir/sub3"
+ chmod +a "daemon allow read,write" "$fromdir/sub3"
+
+ see_acls() {
+ ls -le "${@}"
+ }
+ ;;
+*)
+ setfacl -m u:0:7 "$fromdir/sub1" || test_skipped "Your filesystem has ACLs disabled"
+ setfacl -m g:1:5 "$fromdir/sub1"
+ setfacl -m g:2:1 "$fromdir/sub1"
+ setfacl -m g:0:7 "$fromdir/sub1"
+ setfacl -m u:2:1 "$fromdir/sub1"
+ setfacl -m u:1:5 "$fromdir/sub1"
+
+ setfacl -m u:0:7 "$fromdir/sub2"
+ setfacl -m g:1:5 "$fromdir/sub2"
+ setfacl -m g:2:1 "$fromdir/sub2"
+ setfacl -m g:0:7 "$fromdir/sub2"
+ setfacl -m u:2:1 "$fromdir/sub2"
+ setfacl -m u:1:5 "$fromdir/sub2"
+
+ setfacl -m u:0:7 "$fromdir/sub3"
+ setfacl -m g:1:5 "$fromdir/sub3"
+ setfacl -m g:2:1 "$fromdir/sub3"
+ setfacl -m g:0:7 "$fromdir/sub3"
+ setfacl -m u:2:1 "$fromdir/sub3"
+ setfacl -m u:1:5 "$fromdir/sub3"
+
+ see_acls() {
+ getfacl "${@}"
+ }
+ ;;
+esac
+
+$RSYNC -avvA "$fromdir/" "$todir"
+
+## add file1 to $fromdir/sub1
+echo else >"$fromdir/sub1/file1"
+
+sleep 1 ## wait a bit for timestamp difference
+
+## change $todir and $todir/sub*
+case "$setfacl_nodef" in
+true)
+ if ! chmod --help 2>&1 | fgrep +a >/dev/null; then
+ test_skipped "I don't know how to use setfacl or chmod for ACLs"
+ fi
+ chmod +a "nobody allow read,execute" "$todir"
+ chmod +a "nobody allow read,execute" "$todir/sub1"
+ chmod +a "nobody allow read,execute" "$todir/sub2"
+ chmod +a "nobody allow read,execute" "$todir/sub3"
+ ;;
+*)
+ setfacl -m u:65534:5 "$todir"
+ setfacl -m u:65534:5 "$todir/sub1"
+ setfacl -m u:65534:5 "$todir/sub2"
+ setfacl -m u:65534:5 "$todir/sub3"
+ ;;
+esac
+
+sleep 1 ## wait a bit for timestamp difference
+
+## update mtime of $todir and $todir/sub*
+chown guest "$todir"
+chown guest "$todir/sub1"
+chown guest "$todir/sub2"
+chown guest "$todir/sub3"
+touch "$todir"
+touch "$todir/sub1"
+touch "$todir/sub2"
+touch "$todir/sub3"
+
+sleep 1 ## wait a bit for timestamp difference
+
+## add file2 to $fromdir/sub2, this causes the mtime of sub2 to be updated
+echo else >"$fromdir/sub2/file2"
+
+cd "$todir"
+see_acls $dst_preferred_files >"$scratchdir/dst_preferred_acls.txt"
+
+cd "$fromdir"
+see_acls $src_preferred_files >"$scratchdir/src_preferred_acls.txt"
+
+$RSYNC -avvA --update --dirs-update "$fromdir/" "$todir/"
+
+cd "$todir"
+see_acls $dst_preferred_files | diff $diffopt "$scratchdir/dst_preferred_acls.txt" -
+see_acls $src_preferred_files | diff $diffopt "$scratchdir/src_preferred_acls.txt" -
+
+# The script would have aborted on error, so getting here means we've won.
+exit 0
--
1.7.2.5
--
Please use reply-all for most replies to avoid omitting the mailing list.
To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html