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@
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
+extern int preserve_acls;
+extern int am_root;
+extern int dry_run;
++extern int orig_umask;
+
+typedef struct {
+ id_t id;
+ 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[] = "";
+ 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);
}
}
*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);
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;
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);
}
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);
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
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 ";
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
#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, "
/* 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);
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';
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
+ 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"
+ 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)
+#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 @@
+
+#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;
+ }
+#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++)