The ACL support has arrived! This version has a brand new protocol

that makes it incompatible with all prior versions.  A patch will be
provided to allow talking with older (patched) rsync versions.
This commit is contained in:
Wayne Davison
2007-03-11 00:13:34 +00:00
parent 085e2fd588
commit 1c3344a105
25 changed files with 5504 additions and 288 deletions

View File

@@ -26,15 +26,15 @@ VERSION=@VERSION@
.SUFFIXES:
.SUFFIXES: .c .o
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h smb_acls.h lib/pool_alloc.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
lib/permstring.o lib/pool_alloc.o @LIBOBJS@
lib/permstring.o lib/pool_alloc.o lib/sysacls.o @LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
util.o main.o checksum.o match.o syscall.o log.o backup.o
OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o \
fileio.o batch.o clientname.o chmod.o
fileio.o batch.o clientname.o chmod.o acls.o
OBJS3=progress.o pipe.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \

1085
acls.c Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,7 @@
extern int verbose;
extern int am_root;
extern int preserve_acls;
extern int preserve_devices;
extern int preserve_specials;
extern int preserve_links;
@@ -92,7 +93,8 @@ path
****************************************************************************/
static int make_bak_dir(char *fullpath)
{
STRUCT_STAT st;
statx sx;
struct file_struct *file;
char *rel = fullpath + backup_dir_len;
char *end = rel + strlen(rel);
char *p = end;
@@ -124,15 +126,25 @@ static int make_bak_dir(char *fullpath)
if (p >= rel) {
/* Try to transfer the directory settings of the
* actual dir that the files are coming from. */
if (do_stat(rel, &st) < 0) {
if (do_stat(rel, &sx.st) < 0) {
rsyserr(FERROR, errno,
"make_bak_dir stat %s failed",
full_fname(rel));
} else {
do_lchown(fullpath, st.st_uid, st.st_gid);
#ifdef HAVE_CHMOD
do_chmod(fullpath, st.st_mode);
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
#endif
if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
continue;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
get_acl(rel, &sx);
cache_acl(file, &sx);
free_acl(&sx);
}
#endif
set_file_attrs(fullpath, file, NULL, 0);
free(file);
}
}
*p = '/';
@@ -170,15 +182,18 @@ static int robust_move(const char *src, char *dst)
* We will move the file to be deleted into a parallel directory tree. */
static int keep_backup(const char *fname)
{
STRUCT_STAT st;
statx sx;
struct file_struct *file;
char *buf;
int kept = 0;
int ret_code;
/* return if no file to keep */
if (do_lstat(fname, &st) < 0)
if (do_lstat(fname, &sx.st) < 0)
return 1;
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
#endif
if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
return 1; /* the file could have disappeared */
@@ -188,6 +203,14 @@ static int keep_backup(const char *fname)
return 0;
}
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
get_acl(fname, &sx);
cache_acl(file, &sx);
free_acl(&sx);
}
#endif
/* Check to see if this is a device file, or link */
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|| (preserve_specials && IS_SPECIAL(file->mode))) {
@@ -259,7 +282,7 @@ static int keep_backup(const char *fname)
if (robust_move(fname, buf) != 0) {
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
full_fname(fname), buf);
} else if (st.st_nlink > 1) {
} else if (sx.st.st_nlink > 1) {
/* If someone has hard-linked the file into the backup
* dir, rename() might return success but do nothing! */
robust_unlink(fname); /* Just in case... */

View File

@@ -36,7 +36,8 @@
/* Our 64-bit numbers are sent in MSB-first order so that we can use
* the highest bits to indicate the number of bytes sent. */
#define NVAL2(b,m) ((UVAL(b,0)&~(m))<<8|UVAL(b,1))
#define NVAL1(b,m) (UVAL(b,0)&~(uint32)(m))
#define NVAL2(b,m) (NVAL1(b,m)<<8|UVAL(b,1))
#define NVAL3(b,m) (NVAL2(b,m)<<8|UVAL(b,2))
#define NVAL4(b,m) (NVAL3(b,m)<<8|UVAL(b,3))
#define NVAL5(b,m) ((int64)NVAL4(b,m)<<8|UVAL(b,4))

View File

@@ -41,6 +41,7 @@ extern int prune_empty_dirs;
extern int protocol_version;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_acls;
extern int preserve_hard_links;
extern int need_messages_from_generator;
extern int delete_mode, delete_before, delete_during, delete_after;
@@ -61,6 +62,8 @@ void setup_protocol(int f_out,int f_in)
preserve_uid = ++file_extra_cnt;
if (preserve_gid)
preserve_gid = ++file_extra_cnt;
if (preserve_acls && !am_sender)
preserve_acls = ++file_extra_cnt;
if (remote_protocol == 0) {
if (!read_batch)
@@ -108,6 +111,13 @@ void setup_protocol(int f_out,int f_in)
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (preserve_acls) {
rprintf(FERROR,
"--acls requires protocol 30 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
}
if (delete_mode && !(delete_before+delete_during+delete_after)) {

View File

@@ -542,6 +542,11 @@ if test x"$ac_cv_func_strcasecmp" = x"no"; then
AC_CHECK_LIB(resolv, strcasecmp)
fi
AC_CHECK_FUNCS(aclsort)
if test x"$ac_cv_func_aclsort" = x"no"; then
AC_CHECK_LIB(sec, aclsort)
fi
dnl At the moment we don't test for a broken memcmp(), because all we
dnl need to do is test for equality, not comparison, and it seems that
dnl every platform has a memcmp that can do at least that.
@@ -806,6 +811,76 @@ AC_SUBST(OBJ_RESTORE)
AC_SUBST(CC_SHOBJ_FLAG)
AC_SUBST(BUILD_POPT)
AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
AC_CHECK_FUNCS(_acl __acl _facl __facl)
#################################################
# check for ACL support
AC_MSG_CHECKING([whether to support ACLs])
AC_ARG_ENABLE(acl-support,
AC_HELP_STRING([--disable-acl-support],
[Turn off ACL support]))
if test x"$enable_acl_support" = x"no"; then
AC_MSG_RESULT(no)
else
AC_DEFINE(SUPPORT_ACLS, 1, [Define to 1 to add support for ACLs])
case "$host_os" in
*sysv5*)
AC_MSG_RESULT(Using UnixWare ACLs)
AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
;;
*solaris*|*cygwin*)
AC_MSG_RESULT(Using solaris ACLs)
AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
;;
*hpux*)
AC_MSG_RESULT(Using HPUX ACLs)
AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
;;
*irix*)
AC_MSG_RESULT(Using IRIX ACLs)
AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
;;
*aix*)
AC_MSG_RESULT(Using AIX ACLs)
AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
;;
*osf*)
AC_MSG_RESULT(Using Tru64 ACLs)
AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
LIBS="$LIBS -lpacl"
;;
*)
AC_MSG_RESULT(running tests:)
AC_CHECK_LIB(acl,acl_get_file)
AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
AC_TRY_LINK([#include <sys/types.h>
#include <sys/acl.h>],
[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
AC_MSG_CHECKING(ACL test results)
if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
AC_MSG_RESULT(Using posix ACLs)
AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
AC_TRY_LINK([#include <sys/types.h>
#include <sys/acl.h>],
[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
fi
else
AC_MSG_ERROR(Failed to find ACL support)
if test x"$enable_acl_support" != x"yes"; then
AC_DEFINE(SUPPORT_ACLS, 0)
fi
fi
;;
esac
fi
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
AC_OUTPUT

55
flist.c
View File

@@ -41,6 +41,7 @@ extern int filesfrom_fd;
extern int one_file_system;
extern int copy_dirlinks;
extern int keep_dirlinks;
extern int preserve_acls;
extern int preserve_links;
extern int preserve_hard_links;
extern int preserve_devices;
@@ -152,6 +153,8 @@ static void list_file_entry(struct file_struct *f)
permstring(permbuf, f->mode);
len = F_LENGTH(f);
/* TODO: indicate '+' if the entry has an ACL. */
#ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
@@ -464,13 +467,13 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
if (flags & XMIT_SAME_NAME)
write_byte(f, l1);
if (flags & XMIT_LONG_NAME)
write_int(f, l2);
write_abbrevint30(f, l2);
else
write_byte(f, l2);
write_buf(f, fname + l1, l2);
if (first_hlink_ndx >= 0) {
write_int(f, first_hlink_ndx);
write_abbrevint30(f, first_hlink_ndx);
goto the_end;
}
@@ -480,7 +483,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
if (!(flags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(mode));
if (preserve_uid && !(flags & XMIT_SAME_UID)) {
write_int(f, uid);
write_abbrevint30(f, uid);
if (flags & XMIT_USER_NAME_FOLLOWS) {
int len = strlen(user_name);
write_byte(f, len);
@@ -488,7 +491,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
}
}
if (preserve_gid && !(flags & XMIT_SAME_GID)) {
write_int(f, gid);
write_abbrevint30(f, gid);
if (flags & XMIT_GROUP_NAME_FOLLOWS) {
int len = strlen(group_name);
write_byte(f, len);
@@ -514,7 +517,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx)
if (preserve_links && S_ISLNK(mode)) {
const char *sl = F_SYMLINK(file);
int len = strlen(sl);
write_int(f, len);
write_abbrevint30(f, len);
write_buf(f, sl, len);
}
#endif
@@ -580,7 +583,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
l1 = read_byte(f);
if (flags & XMIT_LONG_NAME)
l2 = read_int(f);
l2 = read_abbrevint30(f);
else
l2 = read_byte(f);
@@ -619,7 +622,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
if (protocol_version >= 30
&& BITS_SETnUNSET(flags, XMIT_HLINKED, XMIT_HLINK_FIRST)) {
struct file_struct *first;
first_hlink_ndx = read_int(f);
first_hlink_ndx = read_abbrevint30(f);
if (first_hlink_ndx < 0 || first_hlink_ndx >= flist->count) {
rprintf(FERROR,
"hard-link reference out of range: %d (%d)\n",
@@ -657,14 +660,14 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
mode = tweak_mode(mode, chmod_modes);
if (preserve_uid && !(flags & XMIT_SAME_UID)) {
uid = (uid_t)read_int(f);
uid = (uid_t)read_abbrevint30(f);
if (flags & XMIT_USER_NAME_FOLLOWS)
uid = recv_user_name(f, uid);
else if (inc_recurse && am_root && !numeric_ids)
uid = match_uid(uid);
}
if (preserve_gid && !(flags & XMIT_SAME_GID)) {
gid = (gid_t)read_int(f);
gid = (gid_t)read_abbrevint30(f);
if (flags & XMIT_GROUP_NAME_FOLLOWS)
gid = recv_group_name(f, gid);
else if (inc_recurse && (!am_root || !numeric_ids))
@@ -693,7 +696,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
#ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(mode)) {
linkname_len = read_int(f) + 1; /* count the '\0' */
linkname_len = read_abbrevint30(f) + 1; /* count the '\0' */
if (linkname_len <= 0 || linkname_len > MAXPATHLEN) {
rprintf(FERROR, "overflow: linkname_len=%d\n",
linkname_len - 1);
@@ -714,6 +717,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
}
#endif
#ifdef SUPPORT_ACLS
/* We need one or two index int32s when we're preserving ACLs. */
if (preserve_acls)
extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN;
#endif
if (always_checksum && S_ISREG(mode))
extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
@@ -851,6 +860,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
read_buf(f, bp, checksum_len);
}
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(mode))
receive_acl(file, f);
#endif
if (S_ISREG(mode) || S_ISLNK(mode))
stats.total_size += file_length;
@@ -1122,6 +1136,9 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
int flags, int filter_flags)
{
struct file_struct *file;
#ifdef SUPPORT_ACLS
statx sx;
#endif
file = make_file(fname, flist, stp, flags, filter_flags);
if (!file)
@@ -1130,12 +1147,28 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
if (chmod_modes && !S_ISLNK(file->mode))
file->mode = tweak_mode(file->mode, chmod_modes);
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode) && f >= 0) {
sx.st.st_mode = file->mode;
sx.acc_acl = sx.def_acl = NULL;
if (get_acl(fname, &sx) < 0)
return NULL;
}
#endif
maybe_emit_filelist_progress(flist->count + flist_count_offset);
flist_expand(flist);
flist->files[flist->count++] = file;
if (f >= 0)
if (f >= 0) {
send_file_entry(f, file, flist->count - 1);
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
send_acl(&sx, f);
free_acl(&sx);
}
#endif
}
return file;
}

View File

@@ -35,6 +35,7 @@ extern int do_progress;
extern int relative_paths;
extern int implied_dirs;
extern int keep_dirlinks;
extern int preserve_acls;
extern int preserve_links;
extern int preserve_devices;
extern int preserve_specials;
@@ -89,6 +90,7 @@ extern int force_delete;
extern int one_file_system;
extern struct stats stats;
extern dev_t filesystem_dev;
extern mode_t orig_umask;
extern char *backup_dir;
extern char *backup_suffix;
extern int backup_suffix_len;
@@ -511,22 +513,31 @@ static void do_delete_pass(struct file_list *flist)
rprintf(FINFO, " \r");
}
int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st)
int unchanged_attrs(const char *fname, struct file_struct *file, statx *sxp)
{
if (preserve_perms && !BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS))
if (preserve_perms && !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
return 0;
if (am_root && preserve_uid && st->st_uid != F_UID(file))
if (am_root && preserve_uid && sxp->st.st_uid != F_UID(file))
return 0;
if (preserve_gid && F_GID(file) != GID_NONE && st->st_gid != F_GID(file))
if (preserve_gid && F_GID(file) != GID_NONE && sxp->st.st_gid != F_GID(file))
return 0;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
if (!ACL_READY(*sxp))
get_acl(fname, sxp);
if (set_acl(NULL, file, sxp) == 0)
return 0;
}
#endif
return 1;
}
void itemize(struct file_struct *file, int ndx, int statret,
STRUCT_STAT *st, int32 iflags, uchar fnamecmp_type,
void itemize(const char *fname, struct file_struct *file, int ndx, int statret,
statx *sxp, int32 iflags, uchar fnamecmp_type,
const char *xname)
{
if (statret >= 0) { /* A from-dest-dir statret can == 1! */
@@ -534,20 +545,28 @@ void itemize(struct file_struct *file, int ndx, int statret,
: S_ISDIR(file->mode) ? !omit_dir_times
: !S_ISLNK(file->mode);
if (S_ISREG(file->mode) && F_LENGTH(file) != st->st_size)
if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
iflags |= ITEM_REPORT_SIZE;
if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
&& !(iflags & ITEM_MATCHED)
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
|| (keep_time && cmp_time(file->modtime, st->st_mtime) != 0))
|| (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
iflags |= ITEM_REPORT_TIME;
if (!BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS))
if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
iflags |= ITEM_REPORT_PERMS;
if (preserve_uid && am_root && F_UID(file) != st->st_uid)
if (preserve_uid && am_root && F_UID(file) != sxp->st.st_uid)
iflags |= ITEM_REPORT_OWNER;
if (preserve_gid && F_GID(file) != GID_NONE
&& st->st_gid != F_GID(file))
&& sxp->st.st_gid != F_GID(file))
iflags |= ITEM_REPORT_GROUP;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
if (!ACL_READY(*sxp))
get_acl(fname, sxp);
if (set_acl(NULL, file, sxp) == 0)
iflags |= ITEM_REPORT_ACL;
}
#endif
} else
iflags |= ITEM_IS_NEW;
@@ -783,7 +802,7 @@ static int find_fuzzy(struct file_struct *file, struct file_list *dirlist)
* handling the file, -1 if no dest-linking occurred, or a non-negative
* value if we found an alternate basis file. */
static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
char *cmpbuf, STRUCT_STAT *stp, int itemizing,
char *cmpbuf, statx *sxp, int itemizing,
enum logcode code)
{
int best_match = -1;
@@ -792,7 +811,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
do {
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, stp, 0) < 0 || !S_ISREG(stp->st_mode))
if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
continue;
switch (match_level) {
case 0:
@@ -800,16 +819,16 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
match_level = 1;
/* FALL THROUGH */
case 1:
if (!unchanged_file(cmpbuf, file, stp))
if (!unchanged_file(cmpbuf, file, &sxp->st))
continue;
best_match = j;
match_level = 2;
/* FALL THROUGH */
case 2:
if (!unchanged_attrs(file, stp))
if (!unchanged_attrs(cmpbuf, file, sxp))
continue;
if (always_checksum > 0 && preserve_times
&& cmp_time(stp->st_mtime, file->modtime))
&& cmp_time(sxp->st.st_mtime, file->modtime))
continue;
best_match = j;
match_level = 3;
@@ -824,7 +843,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
if (j != best_match) {
j = best_match;
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, stp, 0) < 0)
if (link_stat(cmpbuf, &sxp->st, 0) < 0)
return -1;
}
@@ -834,16 +853,16 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
if (!hard_link_one(file, fname, cmpbuf, 1))
goto try_a_copy;
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, stp, itemizing, code, j);
finish_hard_link(file, fname, &sxp->st, itemizing, code, j);
if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) {
itemize(file, ndx, 1, stp,
itemize(fname, file, ndx, 1, sxp,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
0, "");
}
} else
#endif
if (itemizing)
itemize(file, ndx, 0, stp, 0, 0, NULL);
itemize(fname, file, ndx, 0, sxp, 0, 0, NULL);
if (verbose > 1 && maybe_ATTRS_REPORT)
rprintf(FCLIENT, "%s is uptodate\n", fname);
return -2;
@@ -861,7 +880,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
return -1;
}
if (itemizing)
itemize(file, ndx, 0, stp, ITEM_LOCAL_CHANGE, 0, NULL);
itemize(fname, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
set_file_attrs(fname, file, NULL, 0);
if (maybe_ATTRS_REPORT
&& ((!itemizing && verbose && match_level == 2)
@@ -872,7 +891,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
}
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, stp, itemizing, code, -1);
finish_hard_link(file, fname, &sxp->st, itemizing, code, -1);
#endif
return -2;
}
@@ -884,7 +903,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
* handling the file, or -1 if no dest-linking occurred, or a non-negative
* value if we found an alternate basis file. */
static int try_dests_non(struct file_struct *file, char *fname, int ndx,
char *cmpbuf, STRUCT_STAT *stp, int itemizing,
char *cmpbuf, statx *sxp, int itemizing,
enum logcode code)
{
char lnk[MAXPATHLEN];
@@ -917,24 +936,24 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
do {
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, stp, 0) < 0)
if (link_stat(cmpbuf, &sxp->st, 0) < 0)
continue;
switch (type) {
case TYPE_DIR:
if (!S_ISDIR(stp->st_mode))
if (!S_ISDIR(sxp->st.st_mode))
continue;
break;
case TYPE_SPECIAL:
if (!IS_SPECIAL(stp->st_mode))
if (!IS_SPECIAL(sxp->st.st_mode))
continue;
break;
case TYPE_DEVICE:
if (!IS_DEVICE(stp->st_mode))
if (!IS_DEVICE(sxp->st.st_mode))
continue;
break;
#ifdef SUPPORT_LINKS
case TYPE_SYMLINK:
if (!S_ISLNK(stp->st_mode))
if (!S_ISLNK(sxp->st.st_mode))
continue;
break;
#endif
@@ -949,7 +968,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
case TYPE_SPECIAL:
case TYPE_DEVICE:
devp = F_RDEV_P(file);
if (stp->st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
continue;
break;
#ifdef SUPPORT_LINKS
@@ -966,7 +985,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
match_level = 2;
best_match = j;
}
if (unchanged_attrs(file, stp)) {
if (unchanged_attrs(cmpbuf, file, sxp)) {
match_level = 3;
best_match = j;
break;
@@ -979,7 +998,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
if (j != best_match) {
j = best_match;
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, stp, 0) < 0)
if (link_stat(cmpbuf, &sxp->st, 0) < 0)
return -1;
}
@@ -1010,7 +1029,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
: ITEM_LOCAL_CHANGE
+ (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
char *lp = match_level == 3 ? "" : NULL;
itemize(file, ndx, 0, stp, chg + ITEM_MATCHED, 0, lp);
itemize(fname, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
}
if (verbose > 1 && maybe_ATTRS_REPORT) {
rprintf(FCLIENT, "%s%s is uptodate\n",
@@ -1023,6 +1042,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
}
static int phase = 0;
static int dflt_perms;
/* Acts on the indicated item in cur_flist whose name is fname. If a dir,
* make sure it exists, and has the right permissions/timestamp info. For
@@ -1043,7 +1063,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
static int need_fuzzy_dirlist = 0;
struct file_struct *fuzzy_file = NULL;
int fd = -1, f_copy = -1;
STRUCT_STAT st, real_st, partial_st;
statx sx, real_sx;
STRUCT_STAT partial_st;
struct file_struct *back_file = NULL;
int statret, real_ret, stat_errno;
char *fnamecmp, *partialptr, *backupptr = NULL;
@@ -1088,6 +1109,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
return;
}
}
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
#endif
if (dry_run > 1) {
if (fuzzy_dirlist) {
flist_free(fuzzy_dirlist);
@@ -1100,7 +1124,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
const char *dn = file->dirname ? file->dirname : ".";
if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
if (relative_paths && !implied_dirs
&& do_stat(dn, &st) < 0
&& do_stat(dn, &sx.st) < 0
&& create_directory_path(fname) < 0) {
rsyserr(FERROR, errno,
"recv_generator: mkdir %s failed",
@@ -1112,6 +1136,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
if (fuzzy_basis)
need_fuzzy_dirlist = 1;
#ifdef SUPPORT_ACLS
if (!preserve_perms)
dflt_perms = default_perms_for_dir(dn);
#endif
}
parent_dirname = dn;
@@ -1121,7 +1149,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
need_fuzzy_dirlist = 0;
}
statret = link_stat(fname, &st,
statret = link_stat(fname, &sx.st,
keep_dirlinks && S_ISDIR(file->mode));
stat_errno = errno;
}
@@ -1149,8 +1177,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
* file of that name and it is *not* a directory, then
* we need to delete it. If it doesn't exist, then
* (perhaps recursively) create it. */
if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (delete_item(fname, st.st_mode, "directory", del_opts) != 0)
if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
if (delete_item(fname, sx.st.st_mode, "directory", del_opts) != 0)
return;
statret = -1;
}
@@ -1159,18 +1187,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
dry_run++;
}
real_ret = statret;
real_st = st;
real_sx = sx;
if (new_root_dir) {
if (*fname == '.' && fname[1] == '\0')
statret = -1;
new_root_dir = 0;
}
if (!preserve_perms) { /* See comment in non-dir code below. */
file->mode = dest_mode(file->mode, st.st_mode,
statret == 0);
file->mode = dest_mode(file->mode, sx.st.st_mode,
dflt_perms, statret == 0);
}
if (statret != 0 && basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
if (j == -2) {
itemizing = 0;
@@ -1179,7 +1207,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
statret = 1;
}
if (itemizing && f_out != -1) {
itemize(file, ndx, statret, &st,
itemize(fname, file, ndx, statret, &sx,
statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
}
if (real_ret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
@@ -1193,38 +1221,39 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
"*** Skipping any contents from this failed directory ***\n");
missing_below = F_DEPTH(file);
file->flags |= FLAG_MISSING_DIR;
return;
goto cleanup;
}
}
if (set_file_attrs(fname, file, real_ret ? NULL : &real_st, 0)
if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, 0)
&& verbose && code != FNONE && f_out != -1)
rprintf(code, "%s/\n", fname);
if (real_ret != 0 && one_file_system)
real_st.st_dev = filesystem_dev;
real_sx.st.st_dev = filesystem_dev;
if (inc_recurse) {
if (one_file_system) {
uint32 *devp = F_DIRDEV_P(file);
DEV_MAJOR(devp) = major(real_st.st_dev);
DEV_MINOR(devp) = minor(real_st.st_dev);
DEV_MAJOR(devp) = major(real_sx.st.st_dev);
DEV_MINOR(devp) = minor(real_sx.st.st_dev);
}
}
else if (delete_during && f_out != -1 && !phase && dry_run < 2
&& (file->flags & FLAG_XFER_DIR))
delete_in_dir(cur_flist, fname, file, &real_st.st_dev);
return;
delete_in_dir(cur_flist, fname, file, &real_sx.st.st_dev);
goto cleanup;
}
/* If we're not preserving permissions, change the file-list's
* mode based on the local permissions and some heuristics. */
if (!preserve_perms) {
int exists = statret == 0 && !S_ISDIR(st.st_mode);
file->mode = dest_mode(file->mode, st.st_mode, exists);
int exists = statret == 0 && !S_ISDIR(sx.st.st_mode);
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
exists);
}
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_HLINK_NOT_FIRST(file)
&& hard_link_check(file, ndx, fname, statret, &st, itemizing, code))
return;
&& hard_link_check(file, ndx, fname, statret, &sx, itemizing, code))
goto cleanup;
#endif
if (preserve_links && S_ISLNK(file->mode)) {
@@ -1244,28 +1273,28 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
char lnk[MAXPATHLEN];
int len;
if (!S_ISLNK(st.st_mode))
if (!S_ISLNK(sx.st.st_mode))
statret = -1;
else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0
&& strncmp(lnk, sl, len) == 0 && sl[len] == '\0') {
/* The link is pointing to the right place. */
if (itemizing)
itemize(file, ndx, 0, &st, 0, 0, NULL);
set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, &st, itemizing, code, -1);
finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
#endif
if (remove_source_files == 1)
goto return_with_success;
return;
goto cleanup;
}
/* Not the right symlink (or not a symlink), so
* delete it. */
if (delete_item(fname, st.st_mode, "symlink", del_opts) != 0)
return;
if (delete_item(fname, sx.st.st_mode, "symlink", del_opts) != 0)
goto cleanup;
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
if (j == -2) {
#ifndef CAN_HARDLINK_SYMLINK
@@ -1274,7 +1303,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
} else
#endif
if (!copy_dest)
return;
goto cleanup;
itemizing = 0;
code = FNONE;
} else if (j >= 0)
@@ -1282,7 +1311,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_HLINK_NOT_LAST(file))
return;
goto cleanup;
#endif
if (do_symlink(sl, fname) != 0) {
rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
@@ -1290,7 +1319,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
} else {
set_file_attrs(fname, file, NULL, 0);
if (itemizing) {
itemize(file, ndx, statret, &st,
itemize(fname, file, ndx, statret, &sx,
ITEM_LOCAL_CHANGE, 0, NULL);
}
if (code != FNONE && verbose)
@@ -1306,7 +1335,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto return_with_success;
}
#endif
return;
goto cleanup;
}
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
@@ -1316,33 +1345,33 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (statret == 0) {
char *t;
if (IS_DEVICE(file->mode)) {
if (!IS_DEVICE(st.st_mode))
if (!IS_DEVICE(sx.st.st_mode))
statret = -1;
t = "device file";
} else {
if (!IS_SPECIAL(st.st_mode))
if (!IS_SPECIAL(sx.st.st_mode))
statret = -1;
t = "special file";
}
if (statret == 0
&& BITS_EQUAL(st.st_mode, file->mode, _S_IFMT)
&& st.st_rdev == rdev) {
&& BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
&& sx.st.st_rdev == rdev) {
/* The device or special file is identical. */
if (itemizing)
itemize(file, ndx, 0, &st, 0, 0, NULL);
set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, &st, itemizing, code, -1);
finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
#endif
if (remove_source_files == 1)
goto return_with_success;
return;
goto cleanup;
}
if (delete_item(fname, st.st_mode, t, del_opts) != 0)
return;
if (delete_item(fname, sx.st.st_mode, t, del_opts) != 0)
goto cleanup;
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
if (j == -2) {
#ifndef CAN_HARDLINK_SPECIAL
@@ -1351,7 +1380,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
} else
#endif
if (!copy_dest)
return;
goto cleanup;
itemizing = 0;
code = FNONE;
} else if (j >= 0)
@@ -1359,7 +1388,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_HLINK_NOT_LAST(file))
return;
goto cleanup;
#endif
if (verbose > 2) {
rprintf(FINFO, "mknod(%s, 0%o, [%ld,%ld])\n",
@@ -1372,7 +1401,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
} else {
set_file_attrs(fname, file, NULL, 0);
if (itemizing) {
itemize(file, ndx, statret, &st,
itemize(fname, file, ndx, statret, &sx,
ITEM_LOCAL_CHANGE, 0, NULL);
}
if (code != FNONE && verbose)
@@ -1384,14 +1413,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (remove_source_files == 1)
goto return_with_success;
}
return;
goto cleanup;
}
if (!S_ISREG(file->mode)) {
if (solo_file)
fname = f_name(file, NULL);
rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname);
return;
goto cleanup;
}
if (max_size > 0 && F_LENGTH(file) > max_size) {
@@ -1400,7 +1429,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fname = f_name(file, NULL);
rprintf(FINFO, "%s is over max-size\n", fname);
}
return;
goto cleanup;
}
if (min_size > 0 && F_LENGTH(file) < min_size) {
if (verbose > 1) {
@@ -1408,39 +1437,39 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fname = f_name(file, NULL);
rprintf(FINFO, "%s is under min-size\n", fname);
}
return;
goto cleanup;
}
if (ignore_existing > 0 && statret == 0) {
if (verbose > 1)
rprintf(FINFO, "%s exists\n", fname);
return;
goto cleanup;
}
if (update_only > 0 && statret == 0
&& cmp_time(st.st_mtime, file->modtime) > 0) {
&& cmp_time(sx.st.st_mtime, file->modtime) > 0) {
if (verbose > 1)
rprintf(FINFO, "%s is newer\n", fname);
return;
goto cleanup;
}
fnamecmp = fname;
fnamecmp_type = FNAMECMP_FNAME;
if (statret == 0 && !S_ISREG(st.st_mode)) {
if (delete_item(fname, st.st_mode, "regular file", del_opts) != 0)
return;
if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
if (delete_item(fname, sx.st.st_mode, "regular file", del_opts) != 0)
goto cleanup;
statret = -1;
stat_errno = ENOENT;
}
if (statret != 0 && basis_dir[0] != NULL) {
int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &st,
int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
if (j == -2) {
if (remove_source_files == 1)
goto return_with_success;
return;
goto cleanup;
}
if (j >= 0) {
fnamecmp = fnamecmpbuf;
@@ -1450,7 +1479,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
real_ret = statret;
real_st = st;
real_sx = sx;
if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
&& link_stat(partialptr, &partial_st, 0) == 0
@@ -1469,7 +1498,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
rprintf(FINFO, "fuzzy basis selected for %s: %s\n",
fname, fnamecmpbuf);
}
st.st_size = F_LENGTH(fuzzy_file);
sx.st.st_size = F_LENGTH(fuzzy_file);
statret = 0;
fnamecmp = fnamecmpbuf;
fnamecmp_type = FNAMECMP_FUZZY;
@@ -1479,45 +1508,45 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (statret != 0) {
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_HLINK_NOT_LAST(file))
return;
goto cleanup;
#endif
if (stat_errno == ENOENT)
goto notify_others;
rsyserr(FERROR, stat_errno, "recv_generator: failed to stat %s",
full_fname(fname));
return;
goto cleanup;
}
if (append_mode > 0 && st.st_size > F_LENGTH(file))
return;
if (append_mode > 0 && sx.st.st_size > F_LENGTH(file))
goto cleanup;
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
;
else if (fnamecmp_type == FNAMECMP_FUZZY)
;
else if (unchanged_file(fnamecmp, file, &st)) {
else if (unchanged_file(fnamecmp, file, &sx.st)) {
if (partialptr) {
do_unlink(partialptr);
handle_partial_dir(partialptr, PDIR_DELETE);
}
if (itemizing)
itemize(file, ndx, statret, &st, 0, 0, NULL);
set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, &st, itemizing, code, -1);
finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
#endif
if (remove_source_files != 1)
return;
goto cleanup;
return_with_success:
if (!dry_run)
send_msg_int(MSG_SUCCESS, ndx);
return;
goto cleanup;
}
prepare_to_open:
if (partialptr) {
st = partial_st;
sx.st = partial_st;
fnamecmp = partialptr;
fnamecmp_type = FNAMECMP_PARTIAL_DIR;
statret = 0;
@@ -1542,7 +1571,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
/* pretend the file didn't exist */
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_HLINK_NOT_LAST(file))
return;
goto cleanup;
#endif
statret = real_ret = -1;
goto notify_others;
@@ -1551,7 +1580,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
if (!(backupptr = get_backup_name(fname))) {
close(fd);
return;
goto cleanup;
}
if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
close(fd);
@@ -1562,7 +1591,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
full_fname(backupptr));
unmake_file(back_file);
close(fd);
return;
goto cleanup;
}
if ((f_copy = do_open(backupptr,
O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
@@ -1570,14 +1599,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
full_fname(backupptr));
unmake_file(back_file);
close(fd);
return;
goto cleanup;
}
fnamecmp_type = FNAMECMP_BACKUP;
}
if (verbose > 3) {
rprintf(FINFO, "gen mapped %s of size %.0f\n",
fnamecmp, (double)st.st_size);
fnamecmp, (double)sx.st.st_size);
}
if (verbose > 2)
@@ -1601,26 +1630,30 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
iflags |= ITEM_BASIS_TYPE_FOLLOWS;
if (fnamecmp_type == FNAMECMP_FUZZY)
iflags |= ITEM_XNAME_FOLLOWS;
itemize(file, -1, real_ret, &real_st, iflags, fnamecmp_type,
itemize(fnamecmp, file, -1, real_ret, &real_sx, iflags, fnamecmp_type,
fuzzy_file ? fuzzy_file->basename : NULL);
#ifdef SUPPORT_ACLS
if (preserve_acls)
free_acl(&real_sx);
#endif
}
if (!do_xfers) {
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, &st, itemizing, code, -1);
finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
#endif
return;
goto cleanup;
}
if (read_batch)
return;
goto cleanup;
if (statret != 0 || whole_file) {
write_sum_head(f_out, NULL);
return;
goto cleanup;
}
generate_and_send_sums(fd, st.st_size, f_out, f_copy);
generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy);
if (f_copy >= 0) {
close(f_copy);
@@ -1633,6 +1666,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
close(fd);
cleanup:
#ifdef SUPPORT_ACLS
if (preserve_acls)
free_acl(&sx);
#endif
return;
}
static void touch_up_dirs(struct file_list *flist, int ndx)
@@ -1803,6 +1843,8 @@ void generate_files(int f_out, const char *local_name)
* notice that and let us know via the redo pipe (or its closing). */
ignore_timeout = 1;
dflt_perms = (ACCESSPERMS & ~orig_umask);
do {
if (inc_recurse && delete_during && cur_flist->ndx_start) {
struct file_struct *fp = dir_flist->files[cur_flist->parent_ndx];

68
hlink.c
View File

@@ -26,6 +26,7 @@ extern int verbose;
extern int dry_run;
extern int do_xfers;
extern int link_dest;
extern int preserve_acls;
extern int make_backups;
extern int protocol_version;
extern int remove_source_files;
@@ -267,15 +268,15 @@ void match_hard_links(void)
}
static int maybe_hard_link(struct file_struct *file, int ndx,
const char *fname, int statret, STRUCT_STAT *stp,
const char *fname, int statret, statx *sxp,
const char *oldname, STRUCT_STAT *old_stp,
const char *realname, int itemizing, enum logcode code)
{
if (statret == 0) {
if (stp->st_dev == old_stp->st_dev
&& stp->st_ino == old_stp->st_ino) {
if (sxp->st.st_dev == old_stp->st_dev
&& sxp->st.st_ino == old_stp->st_ino) {
if (itemizing) {
itemize(file, ndx, statret, stp,
itemize(fname, file, ndx, statret, sxp,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
0, "");
}
@@ -296,7 +297,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
if (hard_link_one(file, fname, oldname, 0)) {
if (itemizing) {
itemize(file, ndx, statret, stp,
itemize(fname, file, ndx, statret, sxp,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
realname);
}
@@ -310,7 +311,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
/* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
* 0 = process the file, 1 = skip the file, -1 = error occurred. */
int hard_link_check(struct file_struct *file, int ndx, const char *fname,
int statret, STRUCT_STAT *stp, int itemizing,
int statret, statx *sxp, int itemizing,
enum logcode code)
{
STRUCT_STAT prev_st;
@@ -361,18 +362,20 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
if (statret < 0 && basis_dir[0] != NULL) {
/* If we match an alt-dest item, we don't output this as a change. */
char cmpbuf[MAXPATHLEN];
STRUCT_STAT alt_st;
statx alt_sx;
int j = 0;
#ifdef SUPPORT_ACLS
alt_sx.acc_acl = alt_sx.def_acl = NULL;
#endif
do {
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &alt_st, 0) < 0)
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
continue;
if (link_dest) {
if (prev_st.st_dev != alt_st.st_dev
|| prev_st.st_ino != alt_st.st_ino)
if (prev_st.st_dev != alt_sx.st.st_dev
|| prev_st.st_ino != alt_sx.st.st_ino)
continue;
statret = 1;
*stp = alt_st;
if (verbose < 2 || !stdout_format_has_i) {
itemizing = 0;
code = FNONE;
@@ -381,16 +384,32 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
}
break;
}
if (!unchanged_file(cmpbuf, file, &alt_st))
if (!unchanged_file(cmpbuf, file, &alt_sx.st))
continue;
statret = 1;
*stp = alt_st;
if (unchanged_attrs(file, &alt_st))
if (unchanged_attrs(cmpbuf, file, &alt_sx))
break;
} while (basis_dir[++j] != NULL);
if (statret == 1) {
sxp->st = alt_sx.st;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
if (!ACL_READY(*sxp))
get_acl(cmpbuf, sxp);
else {
sxp->acc_acl = alt_sx.acc_acl;
sxp->def_acl = alt_sx.def_acl;
}
}
#endif
}
#ifdef SUPPORT_ACLS
else if (preserve_acls)
free_acl(&alt_sx);
#endif
}
if (maybe_hard_link(file, ndx, fname, statret, stp, prev_name, &prev_st,
if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
realname, itemizing, code) < 0)
return -1;
@@ -425,7 +444,8 @@ void finish_hard_link(struct file_struct *file, const char *fname,
STRUCT_STAT *stp, int itemizing, enum logcode code,
int alt_dest)
{
STRUCT_STAT st, prev_st;
statx prev_sx;
STRUCT_STAT st;
char alt_name[MAXPATHLEN], *prev_name;
const char *our_name;
int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
@@ -449,14 +469,24 @@ void finish_hard_link(struct file_struct *file, const char *fname,
} else
our_name = fname;
#ifdef SUPPORT_ACLS
prev_sx.acc_acl = prev_sx.def_acl = NULL;
#endif
while ((ndx = prev_ndx) >= 0) {
int val;
file = FPTR(ndx);
file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
prev_ndx = F_HL_PREV(file);
prev_name = f_name(file, NULL);
prev_statret = link_stat(prev_name, &prev_st, 0);
if (maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_st,
our_name, stp, fname, itemizing, code) < 0)
prev_statret = link_stat(prev_name, &prev_sx.st, 0);
val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
our_name, stp, fname, itemizing, code);
#ifdef SUPPORT_ACLS
if (preserve_acls)
free_acl(&prev_sx);
#endif
if (val < 0)
continue;
if (remove_source_files == 1 && do_xfers)
send_msg_int(MSG_SUCCESS, ndx);

72
io.c
View File

@@ -100,10 +100,10 @@ static int active_filecnt = 0;
static OFF_T active_bytecnt = 0;
static char int_byte_cnt[64] = {
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* (00 - 3F)/4 */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* (40 - 7F)/4 */
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* (80 - BF)/4 */
5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 9, /* (C0 - FF)/4 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* (00 - 3F)/4 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* (40 - 7F)/4 */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* (80 - BF)/4 */
3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7, /* (C0 - FF)/4 */
};
static void readfd(int fd, char *buffer, size_t N);
@@ -998,6 +998,37 @@ unsigned short read_shortint(int f)
return (UVAL(b, 1) << 8) + UVAL(b, 0);
}
int32 read_abbrevint(int f)
{
int32 num;
char b[5];
int cnt;
readfd(f, b, 1);
cnt = int_byte_cnt[CVAL(b, 0) / 4];
if (cnt > 1)
readfd(f, b + 1, cnt - 1);
switch (cnt) {
case 1:
num = NVAL1(b, 0);
break;
case 2:
num = NVAL2(b, 0x80);
break;
case 3:
num = NVAL3(b, 0xC0);
break;
case 4:
num = NVAL4(b, 0xE0);
break;
case 5:
num = NVAL4(b+1, 0);
break;
default:
exit_cleanup(RERR_PROTOCOL); /* impossible... */
}
return num;
}
int32 read_int(int f)
{
char b[4];
@@ -1033,7 +1064,7 @@ int64 read_longint(int f)
} else {
int cnt;
readfd(f, b, 3);
cnt = int_byte_cnt[CVAL(b, 0) / 4];
cnt = int_byte_cnt[CVAL(b, 0) / 4] + 2;
#if SIZEOF_INT64 < 8
if (cnt > 5 || (cnt == 5 && (CVAL(b,0)&0x3F || CVAL(b,1)&0x80))) {
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
@@ -1373,6 +1404,37 @@ void write_shortint(int f, unsigned short x)
writefd(f, b, 2);
}
void write_abbrevint(int f, int32 x)
{
char b[5];
if ((uint32)x < ((uint32)1<<(1*8-1))) {
b[0] = (char)x;
writefd(f, b, 1);
} else if ((uint32)x < ((uint32)1<<(2*8-2))) {
b[0] = (char)(x >> 8) | 0x80;
b[1] = (char)x;
writefd(f, b, 2);
} else if ((uint32)x < ((uint32)1<<(3*8-3))) {
b[0] = (char)(x >> 16) | 0xC0;
b[1] = (char)(x >> 8);
b[2] = (char)x;
writefd(f, b, 3);
} else if ((uint32)x < ((uint32)1<<(4*8-4))) {
b[0] = (char)(x >> 24) | 0xE0;
b[1] = (char)(x >> 16);
b[2] = (char)(x >> 8);
b[3] = (char)x;
writefd(f, b, 4);
} else {
b[0] = 0xF0;
b[1] = (char)(x >> 24);
b[2] = (char)(x >> 16);
b[3] = (char)(x >> 8);
b[4] = (char)x;
writefd(f, b, 5);
}
}
void write_int(int f, int32 x)
{
char b[4];

3251
lib/sysacls.c Normal file
View File

File diff suppressed because it is too large Load Diff

40
lib/sysacls.h Normal file
View File

@@ -0,0 +1,40 @@
#ifdef SUPPORT_ACLS
#ifdef HAVE_SYS_ACL_H
#include <sys/acl.h>
#endif
#ifdef HAVE_ACL_LIBACL_H
#include <acl/libacl.h>
#endif
#include "smb_acls.h"
#define SMB_MALLOC(cnt) new_array(char, cnt)
#define SMB_MALLOC_P(obj) new_array(obj, 1)
#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt)
#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt)
#define slprintf snprintf
int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p);
void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d);
SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
SMB_ACL_T sys_acl_get_fd(int fd);
int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
int sys_acl_add_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
int sys_acl_get_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
char *sys_acl_to_text(SMB_ACL_T the_acl, ssize_t *plen);
SMB_ACL_T sys_acl_init(int count);
int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype);
int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry, void *qual);
int sys_acl_set_permset(SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset);
int sys_acl_valid(SMB_ACL_T theacl);
int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
int sys_acl_set_fd(int fd, SMB_ACL_T theacl);
int sys_acl_delete_def_file(const char *name);
int sys_acl_free_text(char *text);
int sys_acl_free_acl(SMB_ACL_T the_acl);
int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype);
#endif /* SUPPORT_ACLS */

6
log.c
View File

@@ -624,8 +624,10 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
c[8] = '.';
c[9] = '\0';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
c[11] = '\0';
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
char ch = iflags & ITEM_IS_NEW ? '+' : '?';

View File

@@ -46,6 +46,7 @@ int copy_dirlinks = 0;
int copy_links = 0;
int preserve_links = 0;
int preserve_hard_links = 0;
int preserve_acls = 0;
int preserve_perms = 0;
int preserve_executability = 0;
int preserve_devices = 0;
@@ -198,6 +199,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 *acls = "no ";
char const *links = "no ";
char const *ipv6 = "no ";
STRUCT_STAT *dumstat;
@@ -214,6 +216,10 @@ static void print_rsync_version(enum logcode f)
hardlinks = "";
#endif
#ifdef SUPPORT_ACLS
acls = "";
#endif
#ifdef SUPPORT_LINKS
links = "";
#endif
@@ -232,8 +238,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\n",
have_inplace);
rprintf(f, " %sappend, %sACLs\n",
have_inplace, acls);
#ifdef MAINTAINER_MODE
rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
@@ -279,7 +285,7 @@ void usage(enum logcode F)
rprintf(F," -q, --quiet suppress non-error messages\n");
rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n");
rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n");
rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H)\n");
rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H, -A)\n");
rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n");
rprintf(F," -r, --recursive recurse into directories\n");
rprintf(F," -R, --relative use relative path names\n");
@@ -301,6 +307,9 @@ void usage(enum logcode F)
rprintf(F," -p, --perms preserve permissions\n");
rprintf(F," -E, --executability preserve the file's executability\n");
rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n");
#ifdef SUPPORT_ACLS
rprintf(F," -A, --acls preserve ACLs (implies --perms)\n");
#endif
rprintf(F," -o, --owner preserve owner (super-user only)\n");
rprintf(F," -g, --group preserve group\n");
rprintf(F," --devices preserve device files (super-user only)\n");
@@ -421,6 +430,9 @@ static struct poptOption long_options[] = {
{"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
{"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
{"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 },
{"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
{"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
{"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
{"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
@@ -1092,6 +1104,24 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
usage(FINFO);
exit_cleanup(0);
case 'A':
#ifdef SUPPORT_ACLS
preserve_acls = 1;
preserve_perms = 1;
break;
#else
/* FIXME: this should probably be ignored with a
* warning and then countermeasures taken to
* restrict group and other access in the presence
* of any more restrictive ACLs, but this is safe
* for now */
snprintf(err_buf,sizeof(err_buf),
"ACLs are not supported on this %s\n",
am_server ? "server" : "client");
return 0;
#endif
default:
/* A large opt value means that set_refuse_options()
* turned this option off. */
@@ -1551,6 +1581,10 @@ void server_options(char **args,int *argc)
argstr[x++] = 'p';
else if (preserve_executability && am_sender)
argstr[x++] = 'E';
#ifdef SUPPORT_ACLS
if (preserve_acls)
argstr[x++] = 'A';
#endif
if (recurse)
argstr[x++] = 'r';
if (always_checksum)

View File

@@ -47,6 +47,7 @@ extern int keep_partial;
extern int checksum_seed;
extern int inplace;
extern int delay_updates;
extern mode_t orig_umask;
extern struct stats stats;
extern char *tmpdir;
extern char *partial_dir;
@@ -347,6 +348,10 @@ int recv_files(int f_in, char *local_name)
int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
enum logcode log_code = log_before_transfer ? FLOG : FINFO;
int max_phase = protocol_version >= 29 ? 2 : 1;
int dflt_perms = (ACCESSPERMS & ~orig_umask);
#ifdef SUPPORT_ACLS
const char *parent_dirname = "";
#endif
int ndx, recv_ok;
if (verbose > 2)
@@ -562,7 +567,16 @@ int recv_files(int f_in, char *local_name)
* mode based on the local permissions and some heuristics. */
if (!preserve_perms) {
int exists = fd1 != -1;
file->mode = dest_mode(file->mode, st.st_mode, exists);
#ifdef SUPPORT_ACLS
const char *dn = file->dirname ? file->dirname : ".";
if (parent_dirname != dn
&& strcmp(parent_dirname, dn) != 0) {
dflt_perms = default_perms_for_dir(dn);
parent_dirname = dn;
}
#endif
file->mode = dest_mode(file->mode, st.st_mode,
dflt_perms, exists);
}
/* We now check to see if we are writing the file "inplace" */

81
rsync.c
View File

@@ -31,6 +31,7 @@
extern int verbose;
extern int dry_run;
extern int preserve_acls;
extern int preserve_perms;
extern int preserve_executability;
extern int preserve_times;
@@ -49,7 +50,6 @@ extern int inplace;
extern int flist_eof;
extern int keep_dirlinks;
extern int make_backups;
extern mode_t orig_umask;
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern struct chmod_mode_struct *daemon_chmod_modes;
@@ -203,7 +203,8 @@ void free_sums(struct sum_struct *s)
/* This is only called when we aren't preserving permissions. Figure out what
* the permissions should be and return them merged back into the mode. */
mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists)
mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
int exists)
{
int new_mode;
/* If the file already exists, we'll return the local permissions,
@@ -220,56 +221,65 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists)
new_mode |= (new_mode & 0444) >> 2;
}
} else {
/* Apply the umask and turn off special permissions. */
new_mode = flist_mode & (~CHMOD_BITS | (ACCESSPERMS & ~orig_umask));
/* Apply destination default permissions and turn
* off special permissions. */
new_mode = flist_mode & (~CHMOD_BITS | dflt_perms);
}
return new_mode;
}
int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
int set_file_attrs(char *fname, struct file_struct *file, statx *sxp,
int flags)
{
int updated = 0;
STRUCT_STAT st2;
statx sx2;
int change_uid, change_gid;
mode_t new_mode = file->mode;
if (!st) {
if (!sxp) {
if (dry_run)
return 1;
if (link_stat(fname, &st2, 0) < 0) {
if (link_stat(fname, &sx2.st, 0) < 0) {
rsyserr(FERROR, errno, "stat %s failed",
full_fname(fname));
return 0;
}
st = &st2;
#ifdef SUPPORT_ACLS
sx2.acc_acl = sx2.def_acl = NULL;
#endif
if (!preserve_perms && S_ISDIR(new_mode)
&& st->st_mode & S_ISGID) {
&& sx2.st.st_mode & S_ISGID) {
/* We just created this directory and its setgid
* bit is on, so make sure it stays on. */
new_mode |= S_ISGID;
}
sxp = &sx2;
}
if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
get_acl(fname, sxp);
#endif
if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times))
flags |= ATTRS_SKIP_MTIME;
if (!(flags & ATTRS_SKIP_MTIME)
&& cmp_time(st->st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, st->st_mode);
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
if (ret < 0) {
rsyserr(FERROR, errno, "failed to set times on %s",
full_fname(fname));
return 0;
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
}
change_uid = am_root && preserve_uid && st->st_uid != F_UID(file);
change_uid = am_root && preserve_uid && sxp->st.st_uid != F_UID(file);
change_gid = preserve_gid && F_GID(file) != GID_NONE
&& st->st_gid != F_GID(file);
&& sxp->st.st_gid != F_GID(file);
#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
if (S_ISLNK(st->st_mode))
if (S_ISLNK(sxp->st.st_mode))
;
else
#endif
@@ -279,45 +289,57 @@ int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
rprintf(FINFO,
"set uid of %s from %ld to %ld\n",
fname,
(long)st->st_uid, (long)F_UID(file));
(long)sxp->st.st_uid, (long)F_UID(file));
}
if (change_gid) {
rprintf(FINFO,
"set gid of %s from %ld to %ld\n",
fname,
(long)st->st_gid, (long)F_GID(file));
(long)sxp->st.st_gid, (long)F_GID(file));
}
}
if (do_lchown(fname,
change_uid ? F_UID(file) : st->st_uid,
change_gid ? F_GID(file) : st->st_gid) != 0) {
change_uid ? F_UID(file) : sxp->st.st_uid,
change_gid ? F_GID(file) : sxp->st.st_gid) != 0) {
/* shouldn't have attempted to change uid or gid
* unless have the privilege */
rsyserr(FERROR, errno, "%s %s failed",
change_uid ? "chown" : "chgrp",
full_fname(fname));
return 0;
goto cleanup;
}
/* a lchown had been done - we have to re-stat if the
* destination had the setuid or setgid bits set due
* to the side effect of the chown call */
if (st->st_mode & (S_ISUID | S_ISGID)) {
link_stat(fname, st,
keep_dirlinks && S_ISDIR(st->st_mode));
if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
link_stat(fname, &sxp->st,
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
}
updated = 1;
}
if (daemon_chmod_modes && !S_ISLNK(new_mode))
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
#ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator
* will enable owner-writability using chmod, if necessary.
*
* If set_acl() changes permission bits in the process of setting
* an access ACL, it changes sxp->st.st_mode so we know whether we
* need to chmod(). */
if (preserve_acls && !S_ISLNK(new_mode) && set_acl(fname, file, sxp) == 0)
updated = 1;
#endif
#ifdef HAVE_CHMOD
if (!BITS_EQUAL(st->st_mode, new_mode, CHMOD_BITS)) {
if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
int ret = do_chmod(fname, new_mode);
if (ret < 0) {
rsyserr(FERROR, errno,
"failed to set permissions on %s",
full_fname(fname));
return 0;
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
@@ -330,6 +352,11 @@ int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
else
rprintf(FCLIENT, "%s is uptodate\n", fname);
}
cleanup:
#ifdef SUPPORT_ACLS
if (preserve_acls && sxp == &sx2)
free_acl(&sx2);
#endif
return updated;
}

47
rsync.h
View File

@@ -547,6 +547,10 @@ struct idev_node {
#define IN_LOOPBACKNET 127
#endif
#if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS
#define ACLS_NEED_MASK 1
#endif
#define GID_NONE ((gid_t)-1)
union file_extras {
@@ -566,6 +570,7 @@ struct file_struct {
extern int file_extra_cnt;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_acls;
#define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
#define EXTRA_LEN (sizeof (union file_extras))
@@ -598,10 +603,12 @@ extern int preserve_gid;
/* When the associated option is on, all entries will have these present: */
#define F_OWNER(f) REQ_EXTRA(f, preserve_uid)->unum
#define F_GROUP(f) REQ_EXTRA(f, preserve_gid)->unum
#define F_ACL(f) REQ_EXTRA(f, preserve_acls)->unum
/* These items are per-entry optional and mutally exclusive: */
#define F_HL_GNUM(f) OPT_EXTRA(f, LEN64_BUMP(f))->num
#define F_HL_PREV(f) OPT_EXTRA(f, LEN64_BUMP(f))->num
#define F_DEF_ACL(f) OPT_EXTRA(f, LEN64_BUMP(f))->unum
#define F_DIRDEV_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) + 2 - 1)->unum)
#define F_DIRNODE_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) + 3 - 1)->num)
@@ -753,6 +760,17 @@ struct stats {
struct chmod_mode_struct;
#define EMPTY_ITEM_LIST {NULL, 0, 0}
typedef struct {
void *items;
size_t count;
size_t malloced;
} item_list;
#define EXPAND_ITEM_LIST(lp, type, incr) \
(type*)expand_item_list(lp, sizeof (type), #type, incr)
#include "byteorder.h"
#include "lib/mdfour.h"
#include "lib/wildmatch.h"
@@ -771,6 +789,16 @@ struct chmod_mode_struct;
#define NORETURN __attribute__((__noreturn__))
#endif
typedef struct {
STRUCT_STAT st;
#ifdef SUPPORT_ACLS
struct rsync_acl *acc_acl; /* access ACL */
struct rsync_acl *def_acl; /* default ACL */
#endif
} statx;
#define ACL_READY(sx) ((sx).acc_acl != NULL)
#include "proto.h"
/* We have replacement versions of these if they're missing. */
@@ -977,7 +1005,7 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
#define MY_GID() getgid()
#endif
extern int verbose;
extern int verbose, protocol_version;
#ifndef HAVE_INET_NTOP
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
@@ -991,6 +1019,23 @@ int inet_pton(int af, const char *src, void *dst);
const char *get_panic_action(void);
#endif
static inline int32
read_abbrevint30(int f)
{
if (protocol_version < 30)
return read_int(f);
return read_abbrevint(f);
}
static inline void
write_abbrevint30(int f, int32 x)
{
if (protocol_version < 30)
write_int(f, x);
else
write_abbrevint(f, x);
}
static inline int
isDigit(const char *ptr)
{

View File

@@ -301,7 +301,7 @@ to the detailed description below for a complete description. verb(
-q, --quiet suppress non-error messages
--no-motd suppress daemon-mode MOTD (see caveat)
-c, --checksum skip based on checksum, not mod-time & size
-a, --archive archive mode; same as -rlptgoD (no -H)
-a, --archive archive mode; same as -rlptgoD (no -H, -A)
--no-OPTION turn off an implied OPTION (e.g. --no-D)
-r, --recursive recurse into directories
-R, --relative use relative path names
@@ -323,6 +323,7 @@ to the detailed description below for a complete description. verb(
-p, --perms preserve permissions
-E, --executability preserve executability
--chmod=CHMOD affect file and/or directory permissions
-A, --acls preserve ACLs (implies -p)
-o, --owner preserve owner (super-user only)
-g, --group preserve group
--devices preserve device files (super-user only)
@@ -771,7 +772,9 @@ quote(itemization(
permissions, though the bf(--executability) option might change just
the execute permission for the file.
it() New files get their "normal" permission bits set to the source
file's permissions masked with the receiving end's umask setting, and
file's permissions masked with the receiving directory's default
permissions (either the receiving process's umask, or the permissions
specified via the destination directory's default ACL), and
their special permission bits disabled except in the case where a new
directory inherits a setgid bit from its parent directory.
))
@@ -802,9 +805,11 @@ The preservation of the destination's setgid bit on newly-created
directories when bf(--perms) is off was added in rsync 2.6.7. Older rsync
versions erroneously preserved the three special permission bits for
newly-created files when bf(--perms) was off, while overriding the
destination's setgid bit setting on a newly-created directory. (Keep in
mind that it is the version of the receiving rsync that affects this
behavior.)
destination's setgid bit setting on a newly-created directory. Default ACL
observance was added to the ACL patch for rsync 2.6.7, so older (or
non-ACL-enabled) rsyncs use the umask even if default ACLs are present.
(Keep in mind that it is the version of the receiving rsync that affects
these behaviors.)
dit(bf(-E, --executability)) This option causes rsync to preserve the
executability (or non-executability) of regular files when bf(--perms) is
@@ -822,6 +827,10 @@ quote(itemization(
If bf(--perms) is enabled, this option is ignored.
dit(bf(-A, --acls)) This option causes rsync to update the destination
ACLs to be the same as the source ACLs. This nonstandard option only
works if the remote rsync also supports it. bf(--acls) implies bf(--perms).
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
@@ -1432,8 +1441,8 @@ if the receiving rsync is at least version 2.6.7 (you can use bf(-vv)
with older versions of rsync, but that also turns on the output of other
verbose messages).
The "%i" escape has a cryptic output that is 9 letters long. The general
format is like the string bf(YXcstpogz), where bf(Y) is replaced by the
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
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.
@@ -1482,7 +1491,11 @@ quote(itemization(
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(z) slot is reserved for future use.
it() The bf(u) slot is reserved for reporting update (access) time changes
(a feature that is not yet released).
it() The bf(a) means that the ACL information changed.
it() The bf(x) slot is reserved for reporting extended attribute changes
(a feature that is not yet released).
))
One other output is possible: when deleting files, the "%i" will output

281
smb_acls.h Normal file
View File

@@ -0,0 +1,281 @@
/*
Unix SMB/Netbios implementation.
Version 2.2.x
Portable SMB ACL interface
Copyright (C) Jeremy Allison 2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _SMB_ACLS_H
#define _SMB_ACLS_H
#if defined HAVE_POSIX_ACLS
/* This is an identity mapping (just remove the SMB_). */
#define SMB_ACL_TAG_T acl_tag_t
#define SMB_ACL_TYPE_T acl_type_t
#define SMB_ACL_PERMSET_T acl_permset_t
#define SMB_ACL_PERM_T acl_perm_t
#define SMB_ACL_READ ACL_READ
#define SMB_ACL_WRITE ACL_WRITE
#define SMB_ACL_EXECUTE ACL_EXECUTE
/* Types of ACLs. */
#define SMB_ACL_USER ACL_USER
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
#define SMB_ACL_GROUP ACL_GROUP
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
#define SMB_ACL_OTHER ACL_OTHER
#define SMB_ACL_MASK ACL_MASK
#define SMB_ACL_T acl_t
#define SMB_ACL_ENTRY_T acl_entry_t
#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
#elif defined HAVE_TRU64_ACLS
/* This is for DEC/Compaq Tru64 UNIX */
#define SMB_ACL_TAG_T acl_tag_t
#define SMB_ACL_TYPE_T acl_type_t
#define SMB_ACL_PERMSET_T acl_permset_t
#define SMB_ACL_PERM_T acl_perm_t
#define SMB_ACL_READ ACL_READ
#define SMB_ACL_WRITE ACL_WRITE
#define SMB_ACL_EXECUTE ACL_EXECUTE
/* Types of ACLs. */
#define SMB_ACL_USER ACL_USER
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
#define SMB_ACL_GROUP ACL_GROUP
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
#define SMB_ACL_OTHER ACL_OTHER
#define SMB_ACL_MASK ACL_MASK
#define SMB_ACL_T acl_t
#define SMB_ACL_ENTRY_T acl_entry_t
#define SMB_ACL_FIRST_ENTRY 0
#define SMB_ACL_NEXT_ENTRY 1
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS
/*
* Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
* Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
*/
/* SVR4.2 ES/MP ACLs */
typedef int SMB_ACL_TAG_T;
typedef int SMB_ACL_TYPE_T;
typedef ushort *SMB_ACL_PERMSET_T;
typedef ushort SMB_ACL_PERM_T;
#define SMB_ACL_READ 4
#define SMB_ACL_WRITE 2
#define SMB_ACL_EXECUTE 1
/* Types of ACLs. */
#define SMB_ACL_USER USER
#define SMB_ACL_USER_OBJ USER_OBJ
#define SMB_ACL_GROUP GROUP
#define SMB_ACL_GROUP_OBJ GROUP_OBJ
#define SMB_ACL_OTHER OTHER_OBJ
#define SMB_ACL_MASK CLASS_OBJ
typedef struct SMB_ACL_T {
int size;
int count;
int next;
struct acl acl[1];
} *SMB_ACL_T;
typedef struct acl *SMB_ACL_ENTRY_T;
#define SMB_ACL_FIRST_ENTRY 0
#define SMB_ACL_NEXT_ENTRY 1
#define SMB_ACL_TYPE_ACCESS 0
#define SMB_ACL_TYPE_DEFAULT 1
#ifdef __CYGWIN__
#define SMB_ACL_LOSES_SPECIAL_MODE_BITS
#endif
#elif defined HAVE_HPUX_ACLS
/*
* Based on the Solaris & UnixWare code.
*/
#undef GROUP
#include <sys/aclv.h>
/* SVR4.2 ES/MP ACLs */
typedef int SMB_ACL_TAG_T;
typedef int SMB_ACL_TYPE_T;
typedef ushort *SMB_ACL_PERMSET_T;
typedef ushort SMB_ACL_PERM_T;
#define SMB_ACL_READ 4
#define SMB_ACL_WRITE 2
#define SMB_ACL_EXECUTE 1
/* Types of ACLs. */
#define SMB_ACL_USER USER
#define SMB_ACL_USER_OBJ USER_OBJ
#define SMB_ACL_GROUP GROUP
#define SMB_ACL_GROUP_OBJ GROUP_OBJ
#define SMB_ACL_OTHER OTHER_OBJ
#define SMB_ACL_MASK CLASS_OBJ
typedef struct SMB_ACL_T {
int size;
int count;
int next;
struct acl acl[1];
} *SMB_ACL_T;
typedef struct acl *SMB_ACL_ENTRY_T;
#define SMB_ACL_FIRST_ENTRY 0
#define SMB_ACL_NEXT_ENTRY 1
#define SMB_ACL_TYPE_ACCESS 0
#define SMB_ACL_TYPE_DEFAULT 1
#elif defined HAVE_IRIX_ACLS
#define SMB_ACL_TAG_T acl_tag_t
#define SMB_ACL_TYPE_T acl_type_t
#define SMB_ACL_PERMSET_T acl_permset_t
#define SMB_ACL_PERM_T acl_perm_t
#define SMB_ACL_READ ACL_READ
#define SMB_ACL_WRITE ACL_WRITE
#define SMB_ACL_EXECUTE ACL_EXECUTE
/* Types of ACLs. */
#define SMB_ACL_USER ACL_USER
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
#define SMB_ACL_GROUP ACL_GROUP
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
#define SMB_ACL_OTHER ACL_OTHER_OBJ
#define SMB_ACL_MASK ACL_MASK
typedef struct SMB_ACL_T {
int next;
BOOL freeaclp;
struct acl *aclp;
} *SMB_ACL_T;
#define SMB_ACL_ENTRY_T acl_entry_t
#define SMB_ACL_FIRST_ENTRY 0
#define SMB_ACL_NEXT_ENTRY 1
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
#elif defined HAVE_AIX_ACLS
/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
#include "/usr/include/acl.h"
typedef uint *SMB_ACL_PERMSET_T;
struct acl_entry_link{
struct acl_entry_link *prevp;
struct new_acl_entry *entryp;
struct acl_entry_link *nextp;
int count;
};
struct new_acl_entry{
unsigned short ace_len;
unsigned short ace_type;
unsigned int ace_access;
struct ace_id ace_id[1];
};
#define SMB_ACL_ENTRY_T struct new_acl_entry*
#define SMB_ACL_T struct acl_entry_link*
#define SMB_ACL_TAG_T unsigned short
#define SMB_ACL_TYPE_T int
#define SMB_ACL_PERM_T uint
#define SMB_ACL_READ S_IRUSR
#define SMB_ACL_WRITE S_IWUSR
#define SMB_ACL_EXECUTE S_IXUSR
/* Types of ACLs. */
#define SMB_ACL_USER ACEID_USER
#define SMB_ACL_USER_OBJ 3
#define SMB_ACL_GROUP ACEID_GROUP
#define SMB_ACL_GROUP_OBJ 4
#define SMB_ACL_OTHER 5
#define SMB_ACL_MASK 6
#define SMB_ACL_FIRST_ENTRY 1
#define SMB_ACL_NEXT_ENTRY 2
#define SMB_ACL_TYPE_ACCESS 0
#define SMB_ACL_TYPE_DEFAULT 1
#else /* No ACLs. */
/* No ACLS - fake it. */
#define SMB_ACL_TAG_T int
#define SMB_ACL_TYPE_T int
#define SMB_ACL_PERMSET_T mode_t
#define SMB_ACL_PERM_T mode_t
#define SMB_ACL_READ S_IRUSR
#define SMB_ACL_WRITE S_IWUSR
#define SMB_ACL_EXECUTE S_IXUSR
/* Types of ACLs. */
#define SMB_ACL_USER 0
#define SMB_ACL_USER_OBJ 1
#define SMB_ACL_GROUP 2
#define SMB_ACL_GROUP_OBJ 3
#define SMB_ACL_OTHER 4
#define SMB_ACL_MASK 5
typedef struct SMB_ACL_T {
int dummy;
} *SMB_ACL_T;
typedef struct SMB_ACL_ENTRY_T {
int dummy;
} *SMB_ACL_ENTRY_T;
#define SMB_ACL_FIRST_ENTRY 0
#define SMB_ACL_NEXT_ENTRY 1
#define SMB_ACL_TYPE_ACCESS 0
#define SMB_ACL_TYPE_DEFAULT 1
#endif /* No ACLs. */
#endif /* _SMB_ACLS_H */

39
testsuite/acls.test Normal file
View File

@@ -0,0 +1,39 @@
#! /bin/sh
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test that rsync handles basic ACL preservation.
. $srcdir/testsuite/rsync.fns
$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
case "$RSYNC" in
*protocol=29*) test_skipped "ACLs require protocol 30" ;;
esac
case "$setfacl_nodef" in
true) test_skipped "I don't know how to use your setfacl command" ;;
esac
makepath "$fromdir/foo"
echo something >"$fromdir/file1"
echo else >"$fromdir/file2"
files='foo file1 file2'
setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled"
setfacl -m u:0:5 "$fromdir/file1"
setfacl -m u:0:5 "$fromdir/file2"
$RSYNC -avvA "$fromdir/" "$todir/"
cd "$fromdir"
getfacl $files >"$scratchdir/acls.txt"
cd "$todir"
getfacl $files | diff $diffopt "$scratchdir/acls.txt" -
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -0,0 +1,70 @@
#! /bin/sh
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test that rsync obeys default ACLs. -- Matt McCutchen
. $srcdir/testsuite/rsync.fns
$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
case "$RSYNC" in
*protocol=29*) test_skipped "ACLs require protocol 30" ;;
esac
case "$setfacl_nodef" in
true) test_skipped "I don't know how to use your setfacl command" ;;
*-k*) opts='-dm u::7,g::5,o:5' ;;
*) opts='-m d:u::7,d:g::5,d:o:5' ;;
esac
setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled"
# Call as: testit <dirname> <default-acl> <file-expected> <program-expected>
testit() {
todir="$scratchdir/$1"
mkdir "$todir"
$setfacl_nodef "$todir"
if [ "$2" ]; then
case "$setfacl_nodef" in
*-k*) opts="-dm $2" ;;
*) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`"
esac
setfacl $opts "$todir"
fi
# Make sure we obey ACLs when creating a directory to hold multiple transferred files,
# even though the directory itself is outside the transfer
$RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/"
check_perms "$todir/to" $4 "Target $1"
check_perms "$todir/to/dir" $4 "Target $1"
check_perms "$todir/to/file" $3 "Target $1"
check_perms "$todir/to/program" $4 "Target $1"
# Make sure get_local_name doesn't mess us up when transferring only one file
$RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile"
check_perms "$todir/to/anotherfile" $3 "Target $1"
# Make sure we obey default ACLs when not transferring a regular file
$RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/"
check_perms "$todir/to/anotherdir" $4 "Target $1"
}
mkdir "$scratchdir/dir"
echo "File!" >"$scratchdir/file"
echo "#!/bin/sh" >"$scratchdir/program"
chmod 777 "$scratchdir/dir"
chmod 666 "$scratchdir/file"
chmod 777 "$scratchdir/program"
# Test some target directories
umask 0077
testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx
testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x
testit da750 u::7,g::5,o:0 rw-r----- rwxr-x---
testit da770mask u::7,u:0:7,g::0,m:7,o:0 rw-rw---- rwxrwx---
testit noda1 '' rw------- rwx------
umask 0000
testit noda2 '' rw-rw-rw- rwxrwxrwx
umask 0022
testit noda3 '' rw-r--r-- rwxr-xr-x
# Hooray
exit 0

View File

@@ -42,14 +42,14 @@ touch -r "$fromdir/block" "$fromdir/block2"
$RSYNC -ai "$fromdir/block" "$todir/block2" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cD+++++++ block
cD+++++++++ block
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
$RSYNC -ai "$fromdir/block2" "$todir/block" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cD+++++++ block2
cD+++++++++ block2
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
@@ -58,7 +58,7 @@ sleep 1
$RSYNC -Di "$fromdir/block3" "$todir/block" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cD..T.... block3
cD..T...... block3
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
@@ -66,15 +66,15 @@ $RSYNC -aiHvv "$fromdir/" "$todir/" \
| tee "$outfile"
filter_outfile
cat <<EOT >"$chkfile"
.d..t.... ./
cD..t.... block
cD block2
cD+++++++ block3
hD+++++++ block2.5 => block3
cD+++++++ char
cD+++++++ char2
cD+++++++ char3
cS+++++++ fifo
.d..t...... ./
cD..t...... block
cD block2
cD+++++++++ block3
hD+++++++++ block2.5 => block3
cD+++++++++ char
cD+++++++++ char2
cD+++++++++ char3
cS+++++++++ fifo
EOT
if test ! -b "$fromdir/block2.5"; then
sed -e '/block2\.5/d' \
@@ -94,15 +94,15 @@ if test -b "$fromdir/block2.5"; then
$RSYNC -aii --link-dest="$todir" "$fromdir/" "$chkdir/" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cd ./
hD block
hD block2
hD block2.5
hD block3
hD char
hD char2
hD char3
hS fifo
cd ./
hD block
hD block2
hD block2.5
hD block3
hD char
hD char2
hD char3
hS fifo
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
fi

View File

@@ -47,16 +47,16 @@ rm -f "$to2dir" "$to2dir.test"
$RSYNC -iplr "$fromdir/" "$todir/" \
| tee "$outfile"
sed -e "$sed_cmd" <<EOT >"$chkfile"
cd+++++++ ./
cd+++++++ bar/
cd+++++++ foo/_P30_
cd+++++++ bar/baz/
>f+++++++ bar/baz/rsync
cd+++++++ foo/_P29_
>f+++++++ foo/config1
>f+++++++ foo/config2
>f+++++++ foo/extra
cL+++++++ foo/sym -> ../bar/baz/rsync
cd+++++++++ ./
cd+++++++++ bar/
cd+++++++++ foo/_P30_
cd+++++++++ bar/baz/
>f+++++++++ bar/baz/rsync
cd+++++++++ foo/_P29_
>f+++++++++ foo/config1
>f+++++++++ foo/config2
>f+++++++++ foo/extra
cL+++++++++ foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
@@ -68,10 +68,10 @@ chmod 601 "$fromdir/foo/config2"
$RSYNC -iplrH "$fromdir/" "$todir/" \
| tee "$outfile"
sed -e "$sed_cmd" <<EOT >"$chkfile"
>f..T.... bar/baz/rsync
>f..T.... foo/config1
>f.sTp... foo/config2
hf..T.... foo/extra => foo/config1
>f..T...... bar/baz/rsync
>f..T...... foo/config1
>f.sTp..... foo/config2
hf..T...... foo/extra => foo/config1
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
@@ -88,12 +88,12 @@ chmod 777 "$todir/bar/baz/rsync"
$RSYNC -iplrtc "$fromdir/" "$todir/" \
| tee "$outfile"
sed -e "$sed_cmd" <<EOT >"$chkfile"
.d..t.... foo/_P30_
.f..tp... bar/baz/rsync
.d..t.... foo/_P29_
.f..t.... foo/config1
>fcstp... foo/config2
cL..T.... foo/sym -> ../bar/baz/rsync
.d..t...... foo/_P30_
.f..tp..... bar/baz/rsync
.d..t...... foo/_P29_
.f..t...... foo/config1
>fcstp..... foo/config2
cL..T...... foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
@@ -118,15 +118,15 @@ $RSYNC -ivvplrtH "$fromdir/" "$todir/" \
| tee "$outfile"
filter_outfile
sed -e "$sed_cmd" <<EOT >"$chkfile"
.d ./
.d bar/
.d bar/baz/
.f...p... bar/baz/rsync
.d foo/
.f foo/config1
>f..t.... foo/config2
hf foo/extra
.L foo/sym -> ../bar/baz/rsync
.d ./
.d bar/
.d bar/baz/
.f...p..... bar/baz/rsync
.d foo/
.f foo/config1
>f..t...... foo/config2
hf foo/extra
.L foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed"
@@ -145,8 +145,8 @@ touch "$todir/foo/config2"
$RSYNC -iplrtH "$fromdir/" "$todir/" \
| tee "$outfile"
sed -e "$sed_cmd" <<EOT >"$chkfile"
.f...p... foo/config1
>f..t.... foo/config2
.f...p..... foo/config1
>f..t...... foo/config2
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed"
@@ -154,15 +154,15 @@ $RSYNC -ivvplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
filter_outfile
sed -e "$sed_cmd" <<EOT >"$chkfile"
cd ./
cd bar/
cd bar/baz/
cf bar/baz/rsync
cd foo/
cf foo/config1
cf foo/config2
hf foo/extra => foo/config1
cL foo/sym -> ../bar/baz/rsync
cd ./
cd bar/
cd bar/baz/
cf bar/baz/rsync
cd foo/
cf foo/config1
cf foo/config2
hf foo/extra => foo/config1
cL foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
@@ -170,7 +170,7 @@ rm -rf "$to2dir"
$RSYNC -iplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
sed -e "$sed_cmd" <<EOT >"$chkfile"
hf foo/extra => foo/config1
hf foo/extra => foo/config1
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
@@ -196,15 +196,15 @@ $RSYNC -ivvplrtH --link-dest="$todir" "$fromdir/" "$to2dir/" \
| tee "$outfile"
filter_outfile
sed -e "$sed_cmd" <<EOT >"$chkfile"
cd ./
cd bar/
cd bar/baz/
hf bar/baz/rsync
cd foo/
hf foo/config1
hf foo/config2
hf foo/extra => foo/config1
$L foo/sym -> ../bar/baz/rsync
cd ./
cd bar/
cd bar/baz/
hf bar/baz/rsync
cd foo/
hf foo/config1
hf foo/config2
hf foo/extra => foo/config1
$L foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
@@ -244,15 +244,15 @@ $RSYNC -ivvplrtH --compare-dest="$todir" "$fromdir/" "$to2dir/" \
| tee "$outfile"
filter_outfile
sed -e "$sed_cmd" <<EOT >"$chkfile"
cd ./
cd bar/
cd bar/baz/
.f bar/baz/rsync
cd foo/
.f foo/config1
.f foo/config2
.f foo/extra
.L foo/sym -> ../bar/baz/rsync
cd ./
cd bar/
cd bar/baz/
.f bar/baz/rsync
cd foo/
.f foo/config1
.f foo/config2
.f foo/extra
.L foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"

View File

@@ -35,6 +35,7 @@ extern int verbose;
extern int am_root;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_acls;
extern int numeric_ids;
struct idlist {
@@ -271,7 +272,7 @@ void send_uid_list(int f)
{
struct idlist *list;
if (preserve_uid) {
if (preserve_uid || preserve_acls) {
int len;
/* we send sequences of uid/byte-length/name */
for (list = uidlist; list; list = list->next) {
@@ -288,7 +289,7 @@ void send_uid_list(int f)
write_int(f, 0);
}
if (preserve_gid) {
if (preserve_gid || preserve_acls) {
int len;
for (list = gidlist; list; list = list->next) {
if (!list->name)
@@ -328,18 +329,28 @@ void recv_uid_list(int f, struct file_list *flist)
{
int id, i;
if (preserve_uid && !numeric_ids) {
if ((preserve_uid || preserve_acls) && !numeric_ids) {
/* read the uid list */
while ((id = read_int(f)) != 0)
recv_user_name(f, (uid_t)id);
}
if (preserve_gid && !numeric_ids) {
if ((preserve_gid || preserve_acls) && !numeric_ids) {
/* read the gid list */
while ((id = read_int(f)) != 0)
recv_group_name(f, (gid_t)id);
}
#ifdef SUPPORT_ACLS
if (preserve_acls && !numeric_ids) {
id_t *id;
while ((id = next_acl_uid(flist)) != NULL)
*id = match_uid(*id);
while ((id = next_acl_gid(flist)) != NULL)
*id = match_gid(*id);
}
#endif
/* Now convert all the uids/gids from sender values to our values. */
if (am_root && preserve_uid && !numeric_ids) {
for (i = 0; i < flist->count; i++)

28
util.c
View File

@@ -1466,3 +1466,31 @@ int bitbag_next_bit(struct bitbag *bb, int after)
return -1;
}
void *expand_item_list(item_list *lp, size_t item_size,
const char *desc, int incr)
{
/* First time through, 0 <= 0, so list is expanded. */
if (lp->malloced <= lp->count) {
void *new_ptr;
size_t new_size = lp->malloced;
if (incr < 0)
new_size -= incr; /* increase slowly */
else if (new_size < (size_t)incr)
new_size += incr;
else
new_size *= 2;
new_ptr = realloc_array(lp->items, char, new_size * item_size);
if (verbose >= 4) {
rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",
who_am_i(), desc, (double)new_size * item_size,
new_ptr == lp->items ? " not" : "");
}
if (!new_ptr)
out_of_memory("expand_item_list");
lp->items = new_ptr;
lp->malloced = new_size;
}
return (char*)lp->items + (lp->count++ * item_size);
}