| 1 | diff --unified -r --new-file rsync-2.5.5.orig/Makefile.in rsync-2.5.5/Makefile.in |
| 2 | --- rsync-2.5.5.orig/Makefile.in Mon Mar 25 15:36:56 2002 |
| 3 | +++ rsync-2.5.5/Makefile.in Wed Apr 3 21:45:22 2002 |
| 4 | @@ -31,7 +31,7 @@ |
| 5 | zlib/zutil.o zlib/adler32.o |
| 6 | OBJS1=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 |
| 7 | OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o batch.o \ |
| 8 | - clientname.o |
| 9 | + clientname.o chmod.o |
| 10 | DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o |
| 11 | popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ |
| 12 | popt/popthelp.o popt/poptparse.o |
| 13 | diff --unified -r --new-file rsync-2.5.5.orig/chmod.c rsync-2.5.5/chmod.c |
| 14 | --- rsync-2.5.5.orig/chmod.c Thu Jan 1 10:00:00 1970 |
| 15 | +++ rsync-2.5.5/chmod.c Wed Apr 3 22:56:30 2002 |
| 16 | @@ -0,0 +1,134 @@ |
| 17 | +#include "rsync.h" |
| 18 | + |
| 19 | +struct chmod_mode_struct { |
| 20 | + int ModeAND; |
| 21 | + int ModeOR; |
| 22 | + char Xkeep; |
| 23 | + struct chmod_mode_struct *next; |
| 24 | +}; |
| 25 | + |
| 26 | +#define CHMOD_ADD 1 |
| 27 | +#define CHMOD_SUB 2 |
| 28 | +#define CHMOD_EQ 3 |
| 29 | + |
| 30 | +/* Parse a chmod-style argument, and break it down into one or more AND/OR |
| 31 | + pairs in a linked list. |
| 32 | + We use a state machine to walk through the options - states 1 and 3 |
| 33 | + before/including the operation (+, - or =), state 2 after the operation and |
| 34 | + state 4 if we hit an error. |
| 35 | +*/ |
| 36 | +struct chmod_mode_struct *parse_chmod (char *modestr) |
| 37 | +{ |
| 38 | + int state = 1; |
| 39 | + int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, Xkeep=0; |
| 40 | + struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL, *prev_mode = NULL; |
| 41 | + |
| 42 | + while (*modestr) { |
| 43 | + if (state!=2) { |
| 44 | + switch (*modestr) { |
| 45 | + case 'u' : where |= 0100; topbits |= 04000; break; |
| 46 | + case 'g' : where |= 0010; topbits |= 02000; break; |
| 47 | + case 'o' : where |= 0001; break; |
| 48 | + case 'a' : where |= 0111; break; |
| 49 | + case '+' : op = CHMOD_ADD; state=2; break; |
| 50 | + case '-' : op = CHMOD_SUB; state=2; break; |
| 51 | + case '=' : op = CHMOD_EQ; state=2; break; |
| 52 | + case ',' : break; |
| 53 | + default : state=4; /* Invalid Mode! */ |
| 54 | + } |
| 55 | + } else if (state==2) { |
| 56 | + switch (*modestr) { |
| 57 | + case 'r' : what |= 4; break; |
| 58 | + case 'w' : what |= 2; break; |
| 59 | + case 'X' : Xkeep = 1; |
| 60 | + case 'x' : what |= 1; break; |
| 61 | + case 's' : if (topbits) { |
| 62 | + topoct |= topbits; |
| 63 | + } else { |
| 64 | + topoct = 04000; |
| 65 | + } |
| 66 | + break; |
| 67 | + case 't' : topoct |= 01000; break; |
| 68 | + default : state=4; /* Invalid Mode! */ |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + if (state==4) { |
| 73 | + break; |
| 74 | + } |
| 75 | + |
| 76 | + modestr++; |
| 77 | + if (!*modestr || *modestr == ',') { |
| 78 | + prev_mode = curr_mode; |
| 79 | + curr_mode = malloc(sizeof(struct chmod_mode_struct)); |
| 80 | + if (prev_mode) { |
| 81 | + prev_mode->next = curr_mode; |
| 82 | + } else { |
| 83 | + first_mode = curr_mode; |
| 84 | + } |
| 85 | + curr_mode->next = NULL; |
| 86 | + |
| 87 | + switch (op) { |
| 88 | + case CHMOD_ADD: |
| 89 | + curr_mode->ModeAND = 07777; |
| 90 | + curr_mode->ModeOR = (where * what) + topoct; |
| 91 | + break; |
| 92 | + case CHMOD_SUB: |
| 93 | + curr_mode->ModeAND = 07777 - (where * what) - topoct; |
| 94 | + curr_mode->ModeOR = 0; |
| 95 | + break; |
| 96 | + case CHMOD_EQ: |
| 97 | + curr_mode->ModeAND = 07777 - (where * 7); |
| 98 | + curr_mode->ModeOR = where * what - topoct; |
| 99 | + break; |
| 100 | + } |
| 101 | + |
| 102 | + curr_mode->Xkeep = Xkeep; |
| 103 | + |
| 104 | + state=3; |
| 105 | + where = what = topoct = topbits = Xkeep = 0; |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + if (state==4) { |
| 110 | + free_chmod_mode(first_mode); |
| 111 | + first_mode=NULL; |
| 112 | + } |
| 113 | + return first_mode; |
| 114 | +} |
| 115 | + |
| 116 | + |
| 117 | +/* Takes an existing file permission and a list of AND/OR changes, and create a |
| 118 | + new permissions |
| 119 | +*/ |
| 120 | +int newmode (int oldmode, struct chmod_mode_struct *chmod_modes) |
| 121 | +{ |
| 122 | + int IsX = (oldmode & 0111); |
| 123 | + int NonPerm = oldmode - (oldmode & 07777); |
| 124 | + |
| 125 | + while (chmod_modes) { |
| 126 | + oldmode &= chmod_modes->ModeAND; |
| 127 | + if (chmod_modes->Xkeep && !IsX) { |
| 128 | + oldmode |= chmod_modes->ModeOR & (07777 - 0111); |
| 129 | + } else { |
| 130 | + oldmode |= chmod_modes->ModeOR; |
| 131 | + } |
| 132 | + chmod_modes = chmod_modes->next; |
| 133 | + } |
| 134 | + |
| 135 | + return (oldmode + NonPerm); |
| 136 | +} |
| 137 | + |
| 138 | +/* Free the linked list created by parse_chmod |
| 139 | +*/ |
| 140 | +int free_chmod_mode (struct chmod_mode_struct *chmod_modes) |
| 141 | +{ |
| 142 | + struct chmod_mode_struct *next; |
| 143 | + |
| 144 | + while (chmod_modes) { |
| 145 | + next = chmod_modes->next; |
| 146 | + free(chmod_modes); |
| 147 | + chmod_modes = next; |
| 148 | + } |
| 149 | + return 0; |
| 150 | +} |
| 151 | diff --unified -r --new-file rsync-2.5.5.orig/flist.c rsync-2.5.5/flist.c |
| 152 | --- rsync-2.5.5.orig/flist.c Fri Mar 15 08:20:20 2002 |
| 153 | +++ rsync-2.5.5/flist.c Wed Apr 3 21:54:42 2002 |
| 154 | @@ -36,6 +36,7 @@ |
| 155 | extern int verbose; |
| 156 | extern int do_progress; |
| 157 | extern int am_server; |
| 158 | +extern int am_sender; |
| 159 | extern int always_checksum; |
| 160 | |
| 161 | extern int cvs_exclude; |
| 162 | @@ -61,6 +62,8 @@ |
| 163 | extern int read_batch; |
| 164 | extern int write_batch; |
| 165 | |
| 166 | +extern struct chmod_mode_struct *chmod_modes; |
| 167 | + |
| 168 | static char topsrcname[MAXPATHLEN]; |
| 169 | |
| 170 | static struct exclude_struct **local_exclude_list; |
| 171 | @@ -715,6 +718,10 @@ |
| 172 | #ifdef HAVE_STRUCT_STAT_ST_RDEV |
| 173 | file->rdev = st.st_rdev; |
| 174 | #endif |
| 175 | + |
| 176 | + if (am_sender && chmod_modes && S_ISREG(st.st_mode)) { |
| 177 | + file->mode = newmode(file->mode, chmod_modes); |
| 178 | + } |
| 179 | |
| 180 | #if SUPPORT_LINKS |
| 181 | if (S_ISLNK(st.st_mode)) { |
| 182 | diff --unified -r --new-file rsync-2.5.5.orig/options.c rsync-2.5.5/options.c |
| 183 | --- rsync-2.5.5.orig/options.c Wed Mar 20 07:16:42 2002 |
| 184 | +++ rsync-2.5.5/options.c Wed Apr 3 22:24:46 2002 |
| 185 | @@ -112,6 +112,7 @@ |
| 186 | char *password_file = NULL; |
| 187 | char *rsync_path = RSYNC_PATH; |
| 188 | char *backup_dir = NULL; |
| 189 | +char *chmod_mode = NULL; |
| 190 | int rsync_port = RSYNC_PORT; |
| 191 | |
| 192 | int verbose = 0; |
| 193 | @@ -128,6 +129,7 @@ |
| 194 | * address, or a hostname. **/ |
| 195 | char *bind_address; |
| 196 | |
| 197 | +struct chmod_mode_struct *chmod_modes = NULL; |
| 198 | |
| 199 | static void print_rsync_version(enum logcode f) |
| 200 | { |
| 201 | @@ -220,6 +222,7 @@ |
| 202 | rprintf(F," -g, --group preserve group\n"); |
| 203 | rprintf(F," -D, --devices preserve devices (root only)\n"); |
| 204 | rprintf(F," -t, --times preserve times\n"); |
| 205 | + rprintf(F," --chmod=CHMOD change destination permissions\n"); |
| 206 | rprintf(F," -S, --sparse handle sparse files efficiently\n"); |
| 207 | rprintf(F," -n, --dry-run show what would have been transferred\n"); |
| 208 | rprintf(F," -W, --whole-file copy whole files, no incremental checks\n"); |
| 209 | @@ -285,7 +288,7 @@ |
| 210 | OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST, |
| 211 | OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS, |
| 212 | OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR, |
| 213 | - OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO, |
| 214 | + OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO, OPT_CHMOD, |
| 215 | OPT_NO_BLOCKING_IO, OPT_WHOLE_FILE, OPT_NO_WHOLE_FILE, |
| 216 | OPT_MODIFY_WINDOW, OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_IGNORE_EXISTING}; |
| 217 | |
| 218 | @@ -325,6 +328,7 @@ |
| 219 | {"perms", 'p', POPT_ARG_NONE, &preserve_perms , 0, 0, 0 }, |
| 220 | {"owner", 'o', POPT_ARG_NONE, &preserve_uid , 0, 0, 0 }, |
| 221 | {"group", 'g', POPT_ARG_NONE, &preserve_gid , 0, 0, 0 }, |
| 222 | + {"chmod", 0, POPT_ARG_STRING, &chmod_mode, OPT_CHMOD, 0, 0 }, |
| 223 | {"devices", 'D', POPT_ARG_NONE, &preserve_devices , 0, 0, 0 }, |
| 224 | {"times", 't', POPT_ARG_NONE, &preserve_times , 0, 0, 0 }, |
| 225 | {"checksum", 'c', POPT_ARG_NONE, &always_checksum , 0, 0, 0 }, |
| 226 | @@ -563,6 +567,15 @@ |
| 227 | read_batch = 1; |
| 228 | break; |
| 229 | |
| 230 | + case OPT_CHMOD: |
| 231 | + chmod_modes = parse_chmod(chmod_mode); |
| 232 | + if (!chmod_modes) { |
| 233 | + snprintf(err_buf,sizeof(err_buf), |
| 234 | + "Invalud argument passed to chmod\n"); |
| 235 | + rprintf(FERROR,"ERROR: Invalid argument passed to chmod\n"); |
| 236 | + return 0; |
| 237 | + } |
| 238 | + break; |
| 239 | default: |
| 240 | /* FIXME: If --daemon is specified, then errors for later |
| 241 | * parameters seem to disappear. */ |
| 242 | @@ -787,6 +800,11 @@ |
| 243 | */ |
| 244 | args[ac++] = "--compare-dest"; |
| 245 | args[ac++] = compare_dest; |
| 246 | + } |
| 247 | + |
| 248 | + if (chmod_mode && !am_sender) { |
| 249 | + args[ac++] = "--chmod"; |
| 250 | + args[ac++] = chmod_mode; |
| 251 | } |
| 252 | |
| 253 | *argc = ac; |
| 254 | diff --unified -r --new-file rsync-2.5.5.orig/proto.h rsync-2.5.5/proto.h |
| 255 | --- rsync-2.5.5.orig/proto.h Mon Mar 25 14:51:17 2002 |
| 256 | +++ rsync-2.5.5/proto.h Wed Apr 3 21:51:32 2002 |
| 257 | @@ -31,6 +31,9 @@ |
| 258 | void sum_init(void); |
| 259 | void sum_update(char *p,int len); |
| 260 | void sum_end(char *sum); |
| 261 | +struct chmod_mode_struct *parse_chmod (char *modestr); |
| 262 | +int newmode (int oldmode, struct chmod_mode_struct *chmod_modes); |
| 263 | +int free_chmod_mode (struct chmod_mode_struct *chmod_modes); |
| 264 | void _exit_cleanup(int code, const char *file, int line); |
| 265 | void cleanup_disable(void); |
| 266 | void cleanup_set(char *fnametmp, char *fname, struct file_struct *file, |
| 267 | diff --unified -r --new-file rsync-2.5.5.orig/rsync.yo rsync-2.5.5/rsync.yo |
| 268 | --- rsync-2.5.5.orig/rsync.yo Thu Feb 7 08:20:49 2002 |
| 269 | +++ rsync-2.5.5/rsync.yo Wed Apr 3 23:32:30 2002 |
| 270 | @@ -236,6 +236,7 @@ |
| 271 | -g, --group preserve group |
| 272 | -D, --devices preserve devices (root only) |
| 273 | -t, --times preserve times |
| 274 | + --chmod=CHMOD change destination permissions |
| 275 | -S, --sparse handle sparse files efficiently |
| 276 | -n, --dry-run show what would have been transferred |
| 277 | -W, --whole-file copy whole files, no incremental checks |
| 278 | @@ -440,6 +441,9 @@ |
| 279 | cause the next transfer to behave as if it used -I, and all files will have |
| 280 | their checksums compared and show up in log messages even if they haven't |
| 281 | changed. |
| 282 | + |
| 283 | +dit(bf(--chmod)) This options tells rsync to apply the listed "chmod" pattern |
| 284 | +to the permission of the files on the destination. |
| 285 | |
| 286 | dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers, |
| 287 | instead it will just report the actions it would have taken. |
| 288 | diff --unified -r --new-file rsync-2.5.5.orig/testsuite/chmod.test rsync-2.5.5/testsuite/chmod.test |
| 289 | --- rsync-2.5.5.orig/testsuite/chmod.test Thu Jan 1 10:00:00 1970 |
| 290 | +++ rsync-2.5.5/testsuite/chmod.test Wed Apr 3 23:23:36 2002 |
| 291 | @@ -0,0 +1,38 @@ |
| 292 | +#! /bin/sh |
| 293 | + |
| 294 | +# Copyright (C) 2002 by Martin Pool <mbp@samba.org> |
| 295 | + |
| 296 | +# This program is distributable under the terms of the GNU GPL (see |
| 297 | +# COPYING). |
| 298 | + |
| 299 | +# Test that the --chmod option functions correctly. |
| 300 | + |
| 301 | +. $srcdir/testsuite/rsync.fns |
| 302 | + |
| 303 | +set -x |
| 304 | + |
| 305 | +# Build some files |
| 306 | + |
| 307 | +fromdir="$scratchdir/from" |
| 308 | +todir="$scratchdir/to" |
| 309 | +checkdir="$scratchdir/check" |
| 310 | + |
| 311 | +mkdir "$fromdir" |
| 312 | +name1="$fromdir/name1" |
| 313 | +name2="$fromdir/name2" |
| 314 | +echo "This is the file" > "$name1" |
| 315 | +echo "This is the other file" > "$name2" |
| 316 | + |
| 317 | +chmod 4700 "$name1" || test_skipped "Can't chown" |
| 318 | + |
| 319 | +# Copy the files we've created over to another directory |
| 320 | +checkit "rsync -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir" |
| 321 | + |
| 322 | +# And then manually make the changes which should occur |
| 323 | +chmod ug-s,a+rX $checkdir/* |
| 324 | + |
| 325 | +checkit "rsync -avv --chmod ug-s,a+rX \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir" |
| 326 | + |
| 327 | +exit 0 |
| 328 | +# last [] may have failed but if we get here then we've won |
| 329 | + |