Rsync 2.6.9pre2 tries to read ACLs of nonexistent files

Matt McCutchen hashproduct+rsync at gmail.com
Sat Oct 21 20:27:17 GMT 2006


Dear rsync people,

Today I tried to back up my computer using rsnapshot with the RPM
version of rsync-acl 2.6.9pre1 that I built.  I tried twice, and both
times, rsync encountered some kind of assertion failure.  I was trying
to reproduce the crash with rsync-acl 2.6.9pre2 and noticed a
different bug (described below); when I have a chance, I will go back
and investigate the crash further.

Rsync 2.6.9pre2 produced the following errors:

/home/matt/rsync/rsync-acl/rsync -aAPx --del --numeric-ids --relative \
    --delete-excluded --exclude=media/external-disk/snapshots \
    --link-dest=/media/external-disk/snapshots/occasional.0/mattlaptop/ /. \
    /media/external-disk/snapshots/.sync/mattlaptop/
[...]
/etc/
rsync: get_acl: sys_acl_get_file(etc/adjtime, SMB_ACL_TYPE_ACCESS): No
such file or directory (2)
/etc/adjtime
          46 100%    0.00kB/s    0:00:00 (xfer#1, to-check=283360/283617)
rsync: get_acl: sys_acl_get_file(etc/group, SMB_ACL_TYPE_ACCESS): No
such file or directory (2)
/etc/group
         582 100%  568.36kB/s    0:00:00 (xfer#2, to-check=283334/283617)
[...]

I reran the command with / as the current directory and the same thing
happened, but /etc/adjtime definitely exists, so the errors must have
come from the receiver.  It looks like the receiver tried to read each
file's ACL before it actually created the file.

I think I have tracked down the problem.  In lines 1392-1393, the
generator reads the old ACL of a destination file about to be
overwritten so it knows whether to itemize an ACL change:

		if (preserve_acls && real_ret == 0)
			get_acl(fname, &real_sx);

Presumably real_ret is zero if and only if the destination file
actually exists.  However, back in lines 1210-1226, the generator sets
real_ret to 0 if a basis file is found, even though the destination
file does not exist:

	if (statret != 0 && basis_dir[0] != NULL) {
		int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
				      itemizing, maybe_ATTRS_REPORT, code);
		if (j == -2) {
			if (remove_source_files == 1)
				goto return_with_success;
			goto cleanup;
		}
		if (j >= 0) {
			fnamecmp = fnamecmpbuf;
			fnamecmp_type = j;
			statret = 0;
		}
	}

	real_ret = statret;
	real_sx = sx;

A few lines later, rsync checks for a fuzzy basis file; if it finds
one, it sets statret = 0, and that change does /not/ propagate to
real_ret.  Thus, I'm guessing real_ret and real_sx should actually
have been set /before/ the basis directories are checked.

Matt


More information about the rsync mailing list