Commit 1ed56a05 authored by Wayne Davison's avatar Wayne Davison

Extended the protocol-30 info-passing code at startup, and use it to

tell the client if the server can set the times on a symlink (both
the server->client byte and the client->server use of -e).  Make use
of this info to allow the proper output of the 't' flag when rsync
can set the time on a symlink (and we're talking protocol >= 30).
Added output of "[no] symtimes" info in the --version message.
Fixed the itemize.test so that it works when rsync believes that it
can set the time of a symlink, but it can't really do it.
parent 28fb6365
......@@ -48,7 +48,7 @@ extern int preserve_acls;
extern int preserve_xattrs;
extern int need_messages_from_generator;
extern int delete_mode, delete_before, delete_during, delete_after;
extern char *shell_cmd; /* contains VER.SUB string if client is a pre-release */
extern char *shell_cmd;
extern char *partial_dir;
extern char *dest_option;
extern char *files_from;
......@@ -62,10 +62,17 @@ extern iconv_t ic_send, ic_recv;
/* These index values are for the file-list's extra-attribute array. */
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
#ifdef ICONV_OPTION
int filesfrom_convert = 0;
#endif
#define CF_INC_RECURSE (1<<0)
#define CF_SYMLINK_TIMES (1<<1)
static const char *client_info;
/* The server makes sure that if either side only supports a pre-release
* version of a protocol, that both sides must speak a compatible version
* of that protocol for it to be advertised as available. */
......@@ -79,8 +86,9 @@ static void check_sub_protocol(void)
int our_sub = 0;
#endif
if (!shell_cmd || !(dot = strchr(shell_cmd, '.'))
|| !(their_protocol = atoi(shell_cmd))
/* client_info starts with VER.SUB string if client is a pre-release. */
if (!(their_protocol = atoi(client_info))
|| !(dot = strchr(client_info, '.'))
|| !(their_sub = atoi(dot+1))) {
#if SUBPROTOCOL_VERSION != 0
if (our_sub)
......@@ -103,6 +111,8 @@ static void check_sub_protocol(void)
void set_allow_inc_recurse(void)
{
client_info = shell_cmd ? shell_cmd : "";
if (!recurse || use_qsort)
allow_inc_recurse = 0;
else if (!am_sender
......@@ -110,7 +120,7 @@ void set_allow_inc_recurse(void)
|| delay_updates || prune_empty_dirs))
allow_inc_recurse = 0;
else if (am_server && !local_server
&& (!shell_cmd || strchr(shell_cmd, 'i') == NULL))
&& (strchr(client_info, 'i') == NULL))
allow_inc_recurse = 0;
}
......@@ -233,12 +243,26 @@ void setup_protocol(int f_out,int f_in)
exit_cleanup(RERR_PROTOCOL);
}
} else if (protocol_version >= 30) {
/* The inc_recurse var MUST be set to 0 or 1. */
int compat_flags;
if (am_server) {
inc_recurse = allow_inc_recurse ? 1 : 0;
write_byte(f_out, inc_recurse);
compat_flags = allow_inc_recurse ? CF_INC_RECURSE : 0;
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
compat_flags |= CF_SYMLINK_TIMES;
#endif
write_byte(f_out, compat_flags);
} else
inc_recurse = read_byte(f_in) ? 1 : 0;
compat_flags = read_byte(f_in);
/* The inc_recurse var MUST be set to 0 or 1. */
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0;
if (am_sender) {
receiver_symlink_times = am_server
? strchr(client_info, 'L') != NULL
: !!(compat_flags & CF_SYMLINK_TIMES);
}
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
else
receiver_symlink_times = 1;
#endif
if (inc_recurse && !allow_inc_recurse) {
/* This should only be able to happen in a batch. */
fprintf(stderr,
......
......@@ -27,6 +27,7 @@ extern int dry_run;
extern int do_xfers;
extern int stdout_format_has_i;
extern int logfile_format_has_i;
extern int receiver_symlink_times;
extern int am_root;
extern int am_server;
extern int am_daemon;
......@@ -553,7 +554,7 @@ static void do_delete_pass(void)
int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
{
#ifndef HAVE_LUTIMES
#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
if (S_ISLNK(file->mode)) {
;
} else
......@@ -599,8 +600,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
{
if (statret >= 0) { /* A from-dest-dir statret can == 1! */
int keep_time = !preserve_times ? 0
: S_ISDIR(file->mode) ? preserve_times > 1
: !S_ISLNK(file->mode);
: S_ISDIR(file->mode) ? preserve_times > 1 :
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
(receiver_symlink_times && !(file->flags & FLAG_TIME_FAILED)) ||
#endif
!S_ISLNK(file->mode);
if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
iflags |= ITEM_REPORT_SIZE;
......
......@@ -41,6 +41,7 @@ extern int stdout_format_has_i;
extern int stdout_format_has_o_or_i;
extern int logfile_format_has_i;
extern int logfile_format_has_o_or_i;
extern int receiver_symlink_times;
extern mode_t orig_umask;
extern char *auth_user;
extern char *stdout_format;
......@@ -638,7 +639,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
c[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
: !preserve_times || S_ISLNK(file->mode) ? 'T' : 't';
: !preserve_times || (!receiver_symlink_times && S_ISLNK(file->mode))
? 'T' : 't';
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
......
......@@ -218,6 +218,7 @@ static void print_rsync_version(enum logcode f)
char const *got_socketpair = "no ";
char const *have_inplace = "no ";
char const *hardlinks = "no ";
char const *symtimes = "no ";
char const *acls = "no ";
char const *xattrs = "no ";
char const *links = "no ";
......@@ -252,6 +253,9 @@ static void print_rsync_version(enum logcode f)
#ifdef ICONV_OPTION
iconv = "";
#endif
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
symtimes = "";
#endif
rprintf(f, "%s version %s protocol version %d%s\n",
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
......@@ -265,8 +269,8 @@ static void print_rsync_version(enum logcode f)
(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\n",
have_inplace, acls, xattrs, iconv);
rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes\n",
have_inplace, acls, xattrs, iconv, symtimes);
#ifdef MAINTAINER_MODE
rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
......@@ -1777,24 +1781,24 @@ void server_options(char **args, int *argc_p)
argstr[x++] = 'z';
/* We make use of the -e option to let the server know about any
* pre-release protocol version && our allow_inc_recurse status. */
set_allow_inc_recurse();
* pre-release protocol version && some behavior flags. */
argstr[x++] = 'e';
#if SUBPROTOCOL_VERSION != 0
if (protocol_version == PROTOCOL_VERSION) {
x += snprintf(argstr+x, sizeof argstr - x,
"e%d.%d%s", PROTOCOL_VERSION, SUBPROTOCOL_VERSION,
allow_inc_recurse ? "i" : "");
"%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
} else
#endif
if (allow_inc_recurse) {
argstr[x++] = 'e';
argstr[x++] = '.';
set_allow_inc_recurse();
if (allow_inc_recurse)
argstr[x++] = 'i';
}
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
argstr[x++] = 'L';
#endif
argstr[x] = '\0';
if (x != 1)
args[ac++] = argstr;
args[ac++] = argstr;
#ifdef ICONV_OPTION
if (iconv_opt) {
......
......@@ -399,6 +399,8 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
else
file->flags |= FLAG_TIME_FAILED;
}
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
......
......@@ -77,6 +77,7 @@
#define FLAG_HLINK_DONE (1<<8) /* receiver/generator (checked on all types) */
#define FLAG_LENGTH64 (1<<9) /* sender/receiver/generator */
#define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */
#define FLAG_TIME_FAILED (1<<11)/* generator */
/* These flags are passed to functions but not stored. */
......@@ -93,7 +94,7 @@
/* This is used when working on a new protocol version in CVS, and should
* be a new non-zero value for each CVS change that affects the protocol.
* It must ALWAYS be 0 when the protocol goes final! */
#define SUBPROTOCOL_VERSION 16
#define SUBPROTOCOL_VERSION 17
/* We refuse to interoperate with versions that are not in this range.
* Note that we assume we'll work with later versions: the onus is on
......
......@@ -1681,8 +1681,8 @@ quote(itemization(
it() A bf(t) means the modification time is different and is being updated
to the sender's value (requires bf(--times)). An alternate value of bf(T)
means that the modification time will be set to the transfer time, which happens
anytime a symlink is transferred, or when a regular file or device is
transferred without bf(--times).
when a file/symlink/device is updated without bf(--times) and when a
symlink is changed and the receiver can't set its time.
it() A bf(p) means the permissions are different and are being updated to
the sender's value (requires bf(--perms)).
it() An bf(o) means the owner is different and is being updated to the
......
......@@ -27,13 +27,26 @@ umask 022
ln "$fromdir/foo/config1" "$fromdir/foo/extra"
# Check if the OS can hard-link symlinks or not
ln -s no-such-dir "$to2dir"
if ln "$to2dir" "$to2dir.test" 2>/dev/null; then
if ln "$fromdir/foo/sym" "$to2dir" 2>/dev/null; then
L=hL
else
L=cL
fi
rm -f "$to2dir" "$to2dir.test"
rm -f "$to2dir"
# Check if rsync can preserve time on symlinks
case "$RSYNC" in
*protocol=2*)
T=.T
;;
*)
if $RSYNC --version | grep ", symtimes" >/dev/null; then
T=.t
else
T=.T
fi
;;
esac
$RSYNC -iplr "$fromdir/" "$todir/" \
| tee "$outfile"
......@@ -82,7 +95,7 @@ cat <<EOT >"$chkfile"
.d..t...... foo/
.f..t...... foo/config1
>fcstp..... foo/config2
cL..T...... foo/sym -> ../bar/baz/rsync
cL.$T...... foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
......@@ -142,6 +155,21 @@ diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed"
$RSYNC -ivvplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
filter_outfile
case `tail -1 "$outfile"` in
cL..t*)
sym_dots='..t......'
L_sym_dots='cL..t......'
is_uptodate='-> ../bar/baz/rsync'
echo "cL$sym_dots foo/sym $is_uptodate" >"$chkfile.extra"
L=cL
;;
*)
sym_dots=' '
L_sym_dots='.L '
is_uptodate='is uptodate'
touch "$chkfile.extra"
;;
esac
cat <<EOT >"$chkfile"
cd ./
cd bar/
......@@ -151,14 +179,14 @@ cd foo/
cf foo/config1
cf foo/config2
hf foo/extra => foo/config1
cL foo/sym -> ../bar/baz/rsync
cL$sym_dots foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
rm -rf "$to2dir"
$RSYNC -iplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cat - "$chkfile.extra" <<EOT >"$chkfile"
hf foo/extra => foo/config1
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
......@@ -176,7 +204,7 @@ foo/ is uptodate
foo/config1 is uptodate
foo/config2 is uptodate
foo/extra => foo/config1
foo/sym is uptodate
foo/sym $is_uptodate
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 10 failed"
......@@ -193,21 +221,21 @@ cd foo/
hf foo/config1
hf foo/config2
hf foo/extra => foo/config1
$L foo/sym -> ../bar/baz/rsync
$L$sym_dots foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
rm -rf "$to2dir"
$RSYNC -iplrtH --dry-run --link-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cat - "$chkfile.extra" <<EOT >"$chkfile"
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 12 failed"
rm -rf "$to2dir"
$RSYNC -iplrtH --link-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cat - "$chkfile.extra" <<EOT >"$chkfile"
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 13 failed"
......@@ -224,7 +252,7 @@ foo/ is uptodate
foo/config1 is uptodate
foo/config2 is uptodate
foo/extra is uptodate
foo/sym is uptodate
foo/sym $is_uptodate
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 14 failed"
......@@ -241,14 +269,14 @@ cd foo/
.f foo/config1
.f foo/config2
.f foo/extra
.L foo/sym -> ../bar/baz/rsync
$L_sym_dots foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"
rm -rf "$to2dir"
$RSYNC -iplrtH --compare-dest="$todir" "$fromdir/" "$to2dir/" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cat - "$chkfile.extra" <<EOT >"$chkfile"
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 16 failed"
......@@ -265,7 +293,7 @@ foo/ is uptodate
foo/config1 is uptodate
foo/config2 is uptodate
foo/extra is uptodate
foo/sym is uptodate
foo/sym $is_uptodate
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 17 failed"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment