- Added Matt's changes to lookup directory-default ACLs.
authorWayne Davison <wayned@samba.org>
Tue, 31 Jan 2006 03:35:20 +0000 (03:35 +0000)
committerWayne Davison <wayned@samba.org>
Tue, 31 Jan 2006 03:35:20 +0000 (03:35 +0000)
- Fixed failing hunks.

acls.diff

index 5171116..1faaaa9 100644 (file)
--- a/acls.diff
+++ b/acls.diff
@@ -11,6 +11,10 @@ from a disk that doesn't support ACLs.  This should be changed to silently
 notice that no ACLs are available to copy.  Of course, trying to write out
 ACLs to a non-ACL-supporting disk should complain.
 
+TODO:  we need to cache the return from default_mode_for_dir_acl() so that
+it only gets re-called when the destination directory changes (and does not
+get called if dry_run > 1).
+
 --- orig/Makefile.in   2006-01-14 08:14:29
 +++ Makefile.in        2005-11-07 04:31:05
 @@ -25,15 +25,15 @@ VERSION=@VERSION@
@@ -32,9 +36,9 @@ ACLs to a non-ACL-supporting disk should complain.
  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 \
---- orig/acls.c        2005-07-29 02:48:46
-+++ acls.c     2005-07-29 02:48:46
-@@ -0,0 +1,1130 @@
+--- orig/acls.c        2006-01-31 03:29:49
++++ acls.c     2006-01-31 03:29:49
+@@ -0,0 +1,1204 @@
 +/* -*- c-file-style: "linux" -*-
 +   Copyright (C) Andrew Tridgell 1996
 +   Copyright (C) Paul Mackerras 1996
@@ -64,6 +68,7 @@ ACLs to a non-ACL-supporting disk should complain.
 +extern int preserve_acls;
 +extern int am_root;
 +extern int dry_run;
++extern int orig_umask;
 +
 +typedef struct {
 +      id_t id;
@@ -941,7 +946,7 @@ ACLs to a non-ACL-supporting disk should complain.
 +      return ret;
 +}
 +
-+/* Stuff for redirecting calls to set_acl() from set_perms()
++/* Stuff for redirecting calls to set_acl() from set_file_attrs()
 + * for keep_backup(). */
 +static const struct file_struct *backup_orig_file = NULL;
 +static const char null_string[] = "";
@@ -1164,10 +1169,83 @@ ACLs to a non-ACL-supporting disk should complain.
 +      set_acl_id(gid);
 +}
 +
++static int mode_splice(int mode, int newbits, int where) {
++      return (mode & ~(7 << where)) | (newbits << where);
++}
++
++int default_mode_for_dir_acl(const char *dir)
++{
++      rsync_acl racl;
++      SMB_ACL_T sacl;
++      BOOL ok, saw_mask = False;
++      mode_t mode;
++      size_t i;
++
++      if (dir == NULL)
++              dir = ".";
++      mode = ACCESSPERMS & ~orig_umask;
++      /* Read the directory's default ACL.  If it has none, this will successfully return an empty ACL. */
++      sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT);
++      if (sacl == NULL) {
++              /* Couldn't get an ACL.  Darn. */
++              switch (errno) {
++              case ENOTSUP:
++                      /* ACLs are disabled.  We could yell at the user to turn them on, but... */
++                      break;
++              case ENOENT:
++                      if (dry_run) {
++                              /* We're doing a dry run, so the containing directory
++                               * wasn't actually created.  Don't worry about it. */
++                              break;
++                      }
++                      /* Otherwise fall through. */
++              default:
++                      rprintf(FERROR, "default_mode_for_dir_acl: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
++                              dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
++              }
++              return mode;
++      }
++
++      /* Convert it. */
++      ok = unpack_smb_acl(&racl, sacl);
++      sys_acl_free_acl(sacl);
++      if (!ok) {
++              rprintf(FERROR, "default_mode_for_dir_acl: unpack_smb_acl failed, falling back on umask\n");
++              return mode;
++      }
++
++      /* Look at each default ACL entry and possibly modify three bits of `mode' accordingly.
++       * If there's "no" default ACL, there will be zero entries and the umask-based mode is unchanged. */
++      for (i = 0; i < racl.count; i++) {
++              switch (racl.races[i].tag_type) {
++              case SMB_ACL_USER_OBJ:
++                      mode = mode_splice(mode, racl.races[i].access, 6);
++                      break;
++              case SMB_ACL_GROUP_OBJ:
++                      if (!saw_mask)
++                              mode = mode_splice(mode, racl.races[i].access, 3);
++                      break;
++              case SMB_ACL_MASK:
++                      saw_mask = True;
++                      mode = mode_splice(mode, racl.races[i].access, 3);
++                      break;
++              case SMB_ACL_OTHER:
++                      mode = mode_splice(mode, racl.races[i].access, 0);
++                      break;
++              default:
++                      break;
++              }
++      }
++      rsync_acl_free(&racl);
++      if (verbose > 2)
++              rprintf(FINFO, "got ACL-based default mode %o for directory %s\n", mode, dir);
++      return mode;
++}
++
 +#endif /* SUPPORT_ACLS */
---- orig/backup.c      2006-01-20 21:12:21
+--- orig/backup.c      2006-01-30 07:18:27
 +++ backup.c   2004-10-06 00:13:09
-@@ -134,6 +134,7 @@ static int make_bak_dir(char *fullpath)
+@@ -135,6 +135,7 @@ static int make_bak_dir(char *fullpath)
                        } else {
                                do_lchown(fullpath, st.st_uid, st.st_gid);
                                do_chmod(fullpath, st.st_mode);
@@ -1175,19 +1253,19 @@ ACLs to a non-ACL-supporting disk should complain.
                        }
                }
                *p = '/';
-@@ -186,6 +187,8 @@ static int keep_backup(char *fname)
+@@ -188,6 +189,8 @@ static int keep_backup(char *fname)
        if (!(buf = get_backup_name(fname)))
                return 0;
  
 +      PUSH_KEEP_BACKUP_ACL(file, fname, buf);
 +
        /* Check to see if this is a device file, or link */
-       if (IS_DEVICE(file->mode) && am_root && preserve_devices) {
-               do_unlink(buf);
-@@ -260,6 +263,7 @@ static int keep_backup(char *fname)
+       if ((am_root && preserve_devices && IS_DEVICE(file->mode))
+        || (preserve_specials && IS_SPECIAL(file->mode))) {
+@@ -263,6 +266,7 @@ static int keep_backup(char *fname)
                }
        }
-       set_perms(buf, file, NULL, 0);
+       set_file_attrs(buf, file, NULL, 0);
 +      CLEANUP_KEEP_BACKUP_ACL();
        free(file);
  
@@ -1284,9 +1362,9 @@ ACLs to a non-ACL-supporting disk should complain.
  AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
  AC_OUTPUT
  
---- orig/flist.c       2006-01-22 21:04:41
-+++ flist.c    2006-01-21 08:04:42
-@@ -970,6 +970,8 @@ static struct file_struct *send_file_nam
+--- orig/flist.c       2006-01-31 02:30:18
++++ flist.c    2006-01-31 02:37:33
+@@ -967,6 +967,8 @@ static struct file_struct *send_file_nam
                         f == -2 ? SERVER_FILTERS : ALL_FILTERS);
        if (!file)
                return NULL;
@@ -1295,7 +1373,7 @@ ACLs to a non-ACL-supporting disk should complain.
  
        if (chmod_modes && !S_ISLNK(file->mode))
                file->mode = tweak_mode(file->mode, chmod_modes);
-@@ -981,6 +983,10 @@ static struct file_struct *send_file_nam
+@@ -978,6 +980,10 @@ static struct file_struct *send_file_nam
        if (file->basename[0]) {
                flist->files[flist->count++] = file;
                send_file_entry(file, f);
@@ -1306,7 +1384,7 @@ ACLs to a non-ACL-supporting disk should complain.
        }
        return file;
  }
-@@ -1371,6 +1377,8 @@ struct file_list *recv_file_list(int f)
+@@ -1366,6 +1372,8 @@ struct file_list *recv_file_list(int f)
                        flags |= read_byte(f) << 8;
                file = receive_file_entry(flist, flags, f);
  
@@ -1315,19 +1393,29 @@ ACLs to a non-ACL-supporting disk should complain.
                if (S_ISREG(file->mode))
                        stats.total_size += file->length;
  
-@@ -1393,6 +1401,8 @@ struct file_list *recv_file_list(int f)
+@@ -1388,6 +1396,8 @@ struct file_list *recv_file_list(int f)
  
        clean_flist(flist, relative_paths, 1);
  
 +      SORT_FILE_ACL_INDEX_LISTS();
 +
        if (f >= 0) {
-               /* Now send the uid/gid list. This was introduced in
-                * protocol version 15 */
---- orig/generator.c   2006-01-22 21:04:41
-+++ generator.c        2006-01-14 08:17:25
-@@ -893,6 +893,10 @@ static void recv_generator(char *fname, 
-               if (set_perms(fname, file, statret ? NULL : &st, 0)
+               recv_uid_list(f, flist);
+--- orig/generator.c   2006-01-31 02:30:18
++++ generator.c        2006-01-31 02:35:44
+@@ -860,7 +860,8 @@ static void recv_generator(char *fname, 
+       if (!preserve_perms) {
+               int exists = statret == 0
+                         && S_ISDIR(st.st_mode) == S_ISDIR(file->mode);
+-              file->mode = dest_mode(file->mode, st.st_mode, exists);
++              file->mode = dest_mode(file->mode, st.st_mode, exists,
++                                     file->dirname);
+       }
+       if (S_ISDIR(file->mode)) {
+@@ -894,6 +895,10 @@ static void recv_generator(char *fname, 
+               if (set_file_attrs(fname, file, statret ? NULL : &st, 0)
                    && verbose && code && f_out != -1)
                        rprintf(code, "%s/\n", fname);
 +#ifdef SUPPORT_ACLS
@@ -4624,17 +4712,17 @@ ACLs to a non-ACL-supporting disk should complain.
    next;
  }
  
---- orig/options.c     2006-01-23 18:48:23
-+++ options.c  2005-08-27 21:15:29
+--- orig/options.c     2006-01-31 03:11:30
++++ options.c  2006-01-31 03:11:18
 @@ -44,6 +44,7 @@ int keep_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;
- int preserve_uid = 0;
-@@ -189,6 +190,7 @@ static void print_rsync_version(enum log
+@@ -193,6 +194,7 @@ static void print_rsync_version(enum log
        char const *got_socketpair = "no ";
        char const *have_inplace = "no ";
        char const *hardlinks = "no ";
@@ -4642,7 +4730,7 @@ ACLs to a non-ACL-supporting disk should complain.
        char const *links = "no ";
        char const *ipv6 = "no ";
        STRUCT_STAT *dumstat;
-@@ -205,6 +207,10 @@ static void print_rsync_version(enum log
+@@ -209,6 +211,10 @@ static void print_rsync_version(enum log
        hardlinks = "";
  #endif
  
@@ -4653,7 +4741,7 @@ ACLs to a non-ACL-supporting disk should complain.
  #ifdef SUPPORT_LINKS
        links = "";
  #endif
-@@ -218,9 +224,9 @@ static void print_rsync_version(enum log
+@@ -222,9 +228,9 @@ static void print_rsync_version(enum log
        rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n");
        rprintf(f, "<http://rsync.samba.org/>\n");
        rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
@@ -4665,25 +4753,25 @@ ACLs to a non-ACL-supporting disk should complain.
  
        /* Note that this field may not have type ino_t.  It depends
         * on the complicated interaction between largefile feature
-@@ -288,6 +294,7 @@ void usage(enum logcode F)
-   rprintf(F," -H, --hard-links            preserve hard links\n");
+@@ -293,6 +299,7 @@ void usage(enum logcode F)
    rprintf(F," -K, --keep-dirlinks         treat symlinked dir on receiver as dir\n");
    rprintf(F," -p, --perms                 preserve permissions\n");
+   rprintf(F," -E, --executability         preserve the file's executability\n");
 +  rprintf(F," -A, --acls                  preserve ACLs (implies --perms)\n");
-   rprintf(F," -o, --owner                 preserve owner (root only)\n");
+   rprintf(F,"     --chmod=CHMOD           change destination permissions\n");
+   rprintf(F," -o, --owner                 preserve owner (super-user only)\n");
    rprintf(F," -g, --group                 preserve group\n");
-   rprintf(F," -D, --devices               preserve devices (root only)\n");
-@@ -397,6 +404,9 @@ static struct poptOption long_options[] 
-   {"perms",           'p', POPT_ARG_VAL,    &preserve_perms, 1, 0, 0 },
+@@ -409,6 +416,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 },
-@@ -1027,6 +1037,24 @@ int parse_arguments(int *argc, const cha
+@@ -1057,6 +1067,24 @@ int parse_arguments(int *argc, const cha
                        usage(FINFO);
                        exit_cleanup(0);
  
@@ -4708,7 +4796,7 @@ ACLs to a non-ACL-supporting disk should complain.
                default:
                        /* A large opt value means that set_refuse_options()
                         * turned this option off. */
-@@ -1460,6 +1488,8 @@ void server_options(char **args,int *arg
+@@ -1497,6 +1525,8 @@ void server_options(char **args,int *arg
  
        if (preserve_hard_links)
                argstr[x++] = 'H';
@@ -4717,9 +4805,43 @@ ACLs to a non-ACL-supporting disk should complain.
        if (preserve_uid)
                argstr[x++] = 'o';
        if (preserve_gid)
---- orig/rsync.c       2006-01-14 08:14:31
-+++ rsync.c    2004-07-03 20:11:58
-@@ -139,6 +139,14 @@ int set_perms(char *fname,struct file_st
+--- orig/receiver.c    2006-01-31 02:30:18
++++ receiver.c 2006-01-31 02:36:26
+@@ -607,7 +607,8 @@ int recv_files(int f_in, struct file_lis
+                * 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);
++                      file->mode = dest_mode(file->mode, st.st_mode, exists,
++                                             file->dirname);
+               }
+               /* We now check to see if we are writing file "inplace" */
+--- orig/rsync.c       2006-01-31 02:30:18
++++ rsync.c    2006-01-31 02:33:51
+@@ -53,7 +53,7 @@ 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 dest_mode, int exists)
++mode_t dest_mode(mode_t flist_mode, mode_t dest_mode, int exists, const char *dirname)
+ {
+       /* If the file already exists we'll return the local permissions,
+        * possibly tweaked by the --executability option. */
+@@ -67,8 +67,10 @@ mode_t dest_mode(mode_t flist_mode, mode
+                       else if (!(dest_mode & 0111))
+                               dest_mode |= (dest_mode & 0444) >> 2;
+               }
+-      } else
+-              dest_mode = flist_mode & ~orig_umask;
++      } else {
++              dest_mode = ((flist_mode & CHMOD_BITS)
++                        & DEFAULT_MODE_FOR_DIR(dirname)) | S_IWUSR;
++      }
+       return (flist_mode & ~CHMOD_BITS) | (dest_mode & CHMOD_BITS);
+ }
+@@ -161,6 +163,14 @@ int set_file_attrs(char *fname, struct f
        }
  #endif
  
@@ -4731,12 +4853,12 @@ ACLs to a non-ACL-supporting disk should complain.
 +                      updated = 1;
 +      }
 +
-       if (verbose > 1 && flags & PERMS_REPORT) {
+       if (verbose > 1 && flags & ATTRS_REPORT) {
                enum logcode code = daemon_log_format_has_i || dry_run
                                  ? FCLIENT : FINFO;
---- orig/rsync.h       2006-01-21 21:02:30
-+++ rsync.h    2005-07-29 02:25:55
-@@ -647,6 +647,44 @@ struct stats {
+--- orig/rsync.h       2006-01-30 20:39:09
++++ rsync.h    2006-01-23 21:24:53
+@@ -648,6 +648,46 @@ struct chmod_mode_struct;
  #include "lib/permstring.h"
  #include "lib/addrinfo.h"
  
@@ -4764,6 +4886,7 @@ ACLs to a non-ACL-supporting disk should complain.
 +                                      push_keep_backup_acl(file, orig, dest)
 +#define CLEANUP_KEEP_BACKUP_ACL()             cleanup_keep_backup_acl()
 +#define DUP_ACL(orig, dest, mode)             dup_acl(orig, dest, mode)
++#define DEFAULT_MODE_FOR_DIR(dir)             default_mode_for_dir_acl(dir)
 +#else /* SUPPORT_ACLS */
 +#define MAKE_ACL(file, fname)                 1 /* checked return value */
 +#define SEND_ACL(file, f)
@@ -4775,34 +4898,71 @@ ACLs to a non-ACL-supporting disk should complain.
 +#define PUSH_KEEP_BACKUP_ACL(file, orig, dest)
 +#define CLEANUP_KEEP_BACKUP_ACL()
 +#define DUP_ACL(src, orig, mode)              1 /* checked return value */
++#define DEFAULT_MODE_FOR_DIR(dir)             (ACCESSPERMS & ~orig_umask)
 +#endif /* SUPPORT_ACLS */
 +#include "smb_acls.h"
 +
  #include "proto.h"
  
  /* We have replacement versions of these if they're missing. */
---- orig/rsync.yo      2006-01-22 21:04:42
-+++ rsync.yo   2004-07-03 20:11:58
-@@ -316,6 +316,7 @@ to the detailed description below for a 
-  -H, --hard-links            preserve hard links
+--- orig/rsync.yo      2006-01-31 03:05:44
++++ rsync.yo   2006-01-31 03:14:05
+@@ -317,6 +317,7 @@ to the detailed description below for a 
   -K, --keep-dirlinks         treat symlinked dir on receiver as dir
   -p, --perms                 preserve permissions
-+ -A, --acls                  preserve ACLs (implies -p) [local option]
-  -o, --owner                 preserve owner (root only)
+  -E, --executability         preserve executability
++ -A, --acls                  preserve ACLs (implies -p) [non-standard]
+      --chmod=CHMOD           change destination permissions
+  -o, --owner                 preserve owner (super-user only)
   -g, --group                 preserve group
-  -D, --devices               preserve devices (root only)
-@@ -681,6 +682,11 @@ based on the source file's permissions, 
- umask setting
- (which is the same behavior as other file-copy utilities, such as cp).
+@@ -691,14 +692,23 @@ quote(itemize(
+   permissions, though the bf(--executability) option might change just
+   the execute permission for the file.
+   it() Each new file gets its permissions set based on the source file's
+-  permissions, but masked by the receiving end's umask setting (including
++  permissions, but masked by the receiving end's destination-default
++  permissions (which is either based on the ACL of the destination
++  directory, if available, or the receiving end's umask setting) and
++  includes
+   the stripping of the three special permission bits).
++  Hint: Using bf(--chmod=ugo=rwX) without bf(--perms) will cause new
++  files to get all the destination-default permissions.
+ ))
+   
+ Thus, when bf(--perms) and bf(--executability) are both disabled,
+ rsync's behavior is the same as that of other file-copy utilities,
+ such as bf(cp)(1) and bf(tar)(1).
++This version of rsync observes default ACLs; patched versions of rsync only
++applied the umask, and could thus set wrong permissions in the presence of
++default ACLs.
++
+ dit(bf(-E, --executability)) This option causes rsync to preserve the
+ executability (or non-executability) of regular files when bf(--perms) is
+ not enabled.  A regular file is considered to be executable if at least one
+@@ -713,6 +723,10 @@ quote(itemize(
+ 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
+--- orig/runtests.sh   2005-08-17 06:45:08
++++ runtests.sh        2006-01-23 21:24:53
+@@ -195,6 +195,9 @@ export scratchdir suitedir
+ prep_scratch() {
+     [ -d "$scratchdir" ] && rm -rf "$scratchdir"
+     mkdir "$scratchdir"
++    # Get rid of default ACLs and directory setgid because they confuse some tests.
++    setfacl -k "$scratchdir" || true
++    chmod g-s "$scratchdir"
+     return 0
+ }
  
-+dit(bf(-A, --acls)) This option causes rsync to update the remote
-+ACLs to be the same as the local ACLs.  This will work only if the
-+remote machine's rsync supports this option also. This is a non-standard
-+option.
-+
- dit(bf(-o, --owner)) This option causes rsync to set the owner of the
- destination file to be the same as the source file.  On most systems,
- only the super-user can set file ownership.  By default, the preservation
 --- orig/smb_acls.h    2004-06-30 00:04:07
 +++ smb_acls.h 2004-06-30 00:04:07
 @@ -0,0 +1,277 @@
@@ -5083,8 +5243,62 @@ ACLs to a non-ACL-supporting disk should complain.
 +
 +#endif /* No ACLs. */
 +#endif /* _SMB_ACLS_H */
---- orig/uidlist.c     2005-11-10 16:58:36
-+++ uidlist.c  2004-07-03 20:11:58
+--- orig/testsuite/default-acls-obey.test      2005-10-15 16:08:45
++++ testsuite/default-acls-obey.test   2005-10-15 16:08:45
+@@ -0,0 +1,51 @@
++#! /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
++
++set -x
++
++$RSYNC --help | grep -q "ACLs" || test_skipped "Rsync is configured without ACL support"
++setfacl -dm u::rwx,g::---,o::--- "$scratchdir" || test_skipped "Your filesystem has ACLs disabled"
++
++echo "File!" >"$scratchdir/file"
++echo "#!/bin/bash" >"$scratchdir/program"
++chmod 666 "$scratchdir/file"
++chmod 777 "$scratchdir/program"
++
++# Call as: testit <dirname> <default-acl> <file-expected> <program-expected>
++function testit {
++    todir="$scratchdir/$1"
++    mkdir "$todir"
++    setfacl -k "$todir"
++    chmod g-s "$todir" ### Don't let directory setgid interfere
++    [ "$2" ] && setfacl -dm "$2" "$todir"
++    # 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/file" "$scratchdir/program" "$todir/to/"
++    [ `stat --format=%a "$todir/to"` == $4 ] || test_fail "Target $1: to should have $4 permissions"
++    [ `stat --format=%a "$todir/to/file"` == $3 ] || test_fail "Target $1: to/file should have $3 permissions"
++    [ `stat --format=%a "$todir/to/program"` == $4 ] || test_fail "Target $1: to/program should have $4 permissions"
++    # Make sure get_local_name doesn't mess us up when transferring only one file
++    $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile"
++    [ `stat --format=%a "$todir/to/anotherfile"` == $3 ] || test_fail "Target $1: to/anotherfile should have $3 permissions"
++}
++
++# Test some target directories
++umask 0077
++testit da777 u::rwx,g::rwx,o::rwx 666 777
++testit da775 u::rwx,g::rwx,o::r-x 664 775
++testit da750 u::rwx,g::r-x,o::--- 640 750
++testit da770mask u::rwx,g::---,m::rwx,o::--- 660 770
++testit noda1 '' 600 700
++umask 0000
++testit noda2 '' 666 777
++umask 0022
++testit noda3 '' 644 755
++
++# Hooray
++exit 0
+--- orig/uidlist.c     2006-01-25 17:15:13
++++ uidlist.c  2006-01-25 17:45:21
 @@ -34,6 +34,7 @@
  extern int verbose;
  extern int preserve_uid;
@@ -5145,6 +5359,6 @@ ACLs to a non-ACL-supporting disk should complain.
 +      }
 +#endif /* SUPPORT_ACLS */
 +
-       /* now convert the uid/gid of all files in the list to the mapped
-        * uid/gid */
+       /* 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++)