From 26c810d8217be660be9927bbc99f550228faaf49 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Tue, 31 Jan 2006 19:45:18 +0000 Subject: [PATCH] Cache the destination-default permissions for each destination directory rather than computing it anew for each file. Also silenced some error output in the tests if setfacl isn't found. --- acls.diff | 194 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 142 insertions(+), 52 deletions(-) diff --git a/acls.diff b/acls.diff index 1faaaa9..bdd795c 100644 --- a/acls.diff +++ b/acls.diff @@ -11,10 +11,6 @@ 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@ @@ -36,9 +32,9 @@ get called if dry_run > 1). 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 2006-01-31 03:29:49 -+++ acls.c 2006-01-31 03:29:49 -@@ -0,0 +1,1204 @@ +--- orig/acls.c 2006-01-31 19:25:53 ++++ acls.c 2006-01-31 19:25:53 +@@ -0,0 +1,1202 @@ +/* -*- c-file-style: "linux" -*- + Copyright (C) Andrew Tridgell 1996 + Copyright (C) Paul Mackerras 1996 @@ -1169,21 +1165,19 @@ get called if dry_run > 1). + set_acl_id(gid); +} + -+static int mode_splice(int mode, int newbits, int where) { -+ return (mode & ~(7 << where)) | (newbits << where); -+} ++#define PERMS_SPLICE(perms,newbits,where) (((perms) & ~(7 << (where))) | ((newbits) << (where))) + -+int default_mode_for_dir_acl(const char *dir) ++int default_perms_for_dir(const char *dir) +{ + rsync_acl racl; + SMB_ACL_T sacl; + BOOL ok, saw_mask = False; -+ mode_t mode; + size_t i; ++ int perms; + + if (dir == NULL) + dir = "."; -+ mode = ACCESSPERMS & ~orig_umask; ++ perms = 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) { @@ -1200,37 +1194,37 @@ get called if dry_run > 1). + } + /* Otherwise fall through. */ + default: -+ rprintf(FERROR, "default_mode_for_dir_acl: sys_acl_get_file(%s, %s): %s, falling back on umask\n", ++ rprintf(FERROR, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n", + dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno)); + } -+ return mode; ++ return perms; + } + + /* 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; ++ rprintf(FERROR, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n"); ++ return perms; + } + -+ /* 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. */ ++ /* Look at each default ACL entry and possibly modify three bits of `perms' accordingly. ++ * If there's "no" default ACL, there will be zero entries and the umask-based perms 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); ++ perms = PERMS_SPLICE(perms, racl.races[i].access, 6); + break; + case SMB_ACL_GROUP_OBJ: + if (!saw_mask) -+ mode = mode_splice(mode, racl.races[i].access, 3); ++ perms = PERMS_SPLICE(perms, racl.races[i].access, 3); + break; + case SMB_ACL_MASK: + saw_mask = True; -+ mode = mode_splice(mode, racl.races[i].access, 3); ++ perms = PERMS_SPLICE(perms, racl.races[i].access, 3); + break; + case SMB_ACL_OTHER: -+ mode = mode_splice(mode, racl.races[i].access, 0); ++ perms = PERMS_SPLICE(perms, racl.races[i].access, 0); + break; + default: + break; @@ -1238,8 +1232,8 @@ get called if dry_run > 1). + } + rsync_acl_free(&racl); + if (verbose > 2) -+ rprintf(FINFO, "got ACL-based default mode %o for directory %s\n", mode, dir); -+ return mode; ++ rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir); ++ return perms; +} + +#endif /* SUPPORT_ACLS */ @@ -1402,19 +1396,84 @@ get called if dry_run > 1). if (f >= 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, +--- orig/generator.c 2006-01-31 18:59:39 ++++ generator.c 2006-01-31 19:36:04 +@@ -42,6 +42,7 @@ extern int preserve_specials; + extern int preserve_hard_links; + extern int preserve_perms; + extern int preserve_executability; ++extern int preserve_acls; + extern int preserve_uid; + extern int preserve_gid; + extern int preserve_times; +@@ -756,6 +757,7 @@ static int try_dests_non(struct file_str + } + + static int phase = 0; ++static int dflt_perms; + + /* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir, + * make sure it exists, and has the right permissions/timestamp info. For +@@ -772,7 +774,7 @@ static void recv_generator(char *fname, + enum logcode code, int f_out) + { + static int missing_below = -1, excluded_below = -1; +- static char *fuzzy_dirname = ""; ++ static char *parent_dirname = ""; + static struct file_list *fuzzy_dirlist = NULL; + struct file_struct *fuzzy_file = NULL; + int fd = -1, f_copy = -1; +@@ -791,12 +793,12 @@ static void recv_generator(char *fname, + if (fuzzy_dirlist) { + flist_free(fuzzy_dirlist); + fuzzy_dirlist = NULL; +- fuzzy_dirname = ""; + } + if (missing_below >= 0) { + dry_run--; + missing_below = -1; + } ++ parent_dirname = ""; + return; + } + +@@ -831,15 +833,20 @@ static void recv_generator(char *fname, + statret = -1; + stat_errno = ENOENT; + } else { +- if (fuzzy_basis && S_ISREG(file->mode)) { ++ if ((fuzzy_basis || preserve_acls) && S_ISREG(file->mode)) { + char *dn = file->dirname ? file->dirname : "."; +- if (fuzzy_dirname != dn +- && strcmp(fuzzy_dirname, dn) != 0) { ++ if (parent_dirname != dn ++ && strcmp(parent_dirname, dn) != 0) { + if (fuzzy_dirlist) + flist_free(fuzzy_dirlist); +- fuzzy_dirlist = get_dirlist(dn, -1, 1); ++ if (fuzzy_basis) ++ fuzzy_dirlist = get_dirlist(dn, -1, 1); ++#ifdef SUPPORT_ACLS ++ if (preserve_acls) ++ dflt_perms = default_perms_for_dir(dn); ++#endif + } +- fuzzy_dirname = dn; ++ parent_dirname = dn; + } + + statret = link_stat(fname, &st, +@@ -861,7 +868,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); ++ file->mode = dest_mode(file->mode, st.st_mode, dflt_perms, ++ exists); } if (S_ISDIR(file->mode)) { -@@ -894,6 +895,10 @@ static void recv_generator(char *fname, +@@ -895,6 +903,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); @@ -1425,6 +1484,15 @@ get called if dry_run > 1). if (delete_during && f_out != -1 && !phase && dry_run < 2 && (file->flags & FLAG_DEL_HERE)) delete_in_dir(the_file_list, fname, file, &st); +@@ -1330,6 +1342,8 @@ void generate_files(int f_out, struct fi + * notice that and let us know via the redo pipe (or its closing). */ + ignore_timeout = 1; + ++ dflt_perms = (ACCESSPERMS & ~orig_umask); ++ + for (i = 0; i < flist->count; i++) { + struct file_struct *file = flist->files[i]; + --- orig/lib/sysacls.c 2005-05-16 23:27:53 +++ lib/sysacls.c 2005-05-16 23:27:53 @@ -0,0 +1,3242 @@ @@ -4806,42 +4874,66 @@ get called if dry_run > 1). argstr[x++] = 'o'; if (preserve_gid) --- 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 ++++ receiver.c 2006-01-31 19:36:48 +@@ -37,6 +37,7 @@ extern int relative_paths; + extern int keep_dirlinks; + extern int preserve_hard_links; + extern int preserve_perms; ++extern int preserve_acls; + extern int io_error; + extern int basis_dir_cnt; + extern int make_backups; +@@ -410,6 +411,8 @@ int recv_files(int f_in, struct file_lis + int itemizing = am_daemon ? daemon_log_format_has_i + : !am_server && log_format_has_i; + int max_phase = protocol_version >= 29 ? 2 : 1; ++ int dflt_perms = (ACCESSPERMS & ~orig_umask); ++ char *parent_dirname = ""; + int i, recv_ok; + + if (verbose > 2) +@@ -607,7 +610,18 @@ 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); ++#ifdef SUPPORT_ACLS ++ if (preserve_acls) { ++ 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 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) ++++ rsync.c 2006-01-31 19:35:44 +@@ -53,7 +53,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 dest_mode, int exists) -+mode_t dest_mode(mode_t flist_mode, mode_t dest_mode, int exists, const char *dirname) ++mode_t dest_mode(mode_t flist_mode, mode_t dest_mode, int dflt_perms, ++ int exists) { /* 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)) +@@ -68,7 +69,7 @@ mode_t dest_mode(mode_t flist_mode, mode dest_mode |= (dest_mode & 0444) >> 2; } -- } else + } else - dest_mode = flist_mode & ~orig_umask; -+ } else { -+ dest_mode = ((flist_mode & CHMOD_BITS) -+ & DEFAULT_MODE_FOR_DIR(dirname)) | S_IWUSR; -+ } ++ dest_mode = ((flist_mode & CHMOD_BITS) & dflt_perms) | S_IWUSR; return (flist_mode & ~CHMOD_BITS) | (dest_mode & CHMOD_BITS); } -@@ -161,6 +163,14 @@ int set_file_attrs(char *fname, struct f +@@ -161,6 +162,14 @@ int set_file_attrs(char *fname, struct f } #endif @@ -4857,8 +4949,8 @@ get called if dry_run > 1). enum logcode code = daemon_log_format_has_i || dry_run ? FCLIENT : FINFO; --- 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; ++++ rsync.h 2006-01-31 19:27:00 +@@ -648,6 +648,44 @@ struct chmod_mode_struct; #include "lib/permstring.h" #include "lib/addrinfo.h" @@ -4886,7 +4978,6 @@ get called if dry_run > 1). + 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) @@ -4898,7 +4989,6 @@ get called if dry_run > 1). +#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" + @@ -4952,13 +5042,13 @@ get called if dry_run > 1). 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 ++++ runtests.sh 2006-01-31 19:09:40 @@ -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 ++ setfacl -k "$scratchdir" 2>/dev/null || true + chmod g-s "$scratchdir" return 0 } -- 2.34.1