1 After applying this patch and running configure, you MUST run this
7 --- orig/Makefile.in 2005-07-07 23:11:07
8 +++ Makefile.in 2004-07-03 20:13:41
9 @@ -33,7 +33,7 @@ ZLIBOBJ=zlib/deflate.o zlib/inffast.o zl
10 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
11 main.o checksum.o match.o syscall.o log.o backup.o
12 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
13 - fileio.o batch.o clientname.o
14 + fileio.o batch.o clientname.o chmod.o
15 OBJS3=progress.o pipe.o
16 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
17 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
18 --- orig/chmod.c 2005-07-09 16:09:14
19 +++ chmod.c 2005-07-09 16:09:14
23 +extern int orig_umask;
25 +#define FLAG_X_KEEP (1<<0)
26 +#define FLAG_DIRS_ONLY (1<<1)
27 +#define FLAG_FILES_ONLY (1<<2)
29 +struct chmod_mode_struct {
30 + struct chmod_mode_struct *next;
31 + int ModeAND, ModeOR;
39 +#define STATE_ERROR 0
40 +#define STATE_1ST_HALF 1
41 +#define STATE_2ND_HALF 2
43 +/* Parse a chmod-style argument, and break it down into one or more AND/OR
44 + * pairs in a linked list. We use a state machine to walk through the
46 +struct chmod_mode_struct *parse_chmod(char *modestr)
48 + int state = STATE_1ST_HALF;
49 + int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
50 + struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
53 + while (state != STATE_ERROR) {
54 + if (!*modestr || *modestr == ',') {
58 + state = STATE_ERROR;
61 + prev_mode = curr_mode;
62 + curr_mode = new_array(struct chmod_mode_struct, 1);
64 + prev_mode->next = curr_mode;
66 + first_mode = curr_mode;
67 + curr_mode->next = NULL;
70 + bits = where * what;
73 + bits = (where * what) & ~orig_umask;
78 + curr_mode->ModeAND = 07777;
79 + curr_mode->ModeOR = bits + topoct;
82 + curr_mode->ModeAND = 07777 - bits - topoct;
83 + curr_mode->ModeOR = 0;
86 + curr_mode->ModeAND = 07777 - (where * 7) - (topoct ? topbits : 0);
87 + curr_mode->ModeOR = bits + topoct;
91 + curr_mode->flags = flags;
97 + state = STATE_1ST_HALF;
98 + where = what = op = topoct = topbits = flags = 0;
101 + if (state != STATE_2ND_HALF) {
102 + switch (*modestr) {
104 + if (flags & FLAG_FILES_ONLY)
105 + state = STATE_ERROR;
106 + flags |= FLAG_DIRS_ONLY;
109 + if (flags & FLAG_DIRS_ONLY)
110 + state = STATE_ERROR;
111 + flags |= FLAG_FILES_ONLY;
129 + state = STATE_2ND_HALF;
133 + state = STATE_2ND_HALF;
137 + state = STATE_2ND_HALF;
140 + state = STATE_ERROR;
144 + switch (*modestr) {
152 + flags |= FLAG_X_KEEP;
167 + state = STATE_ERROR;
174 + if (state == STATE_ERROR) {
175 + free_chmod_mode(first_mode);
182 +/* Takes an existing file permission and a list of AND/OR changes, and
183 + * create a new permissions. */
184 +int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
186 + int IsX = mode & 0111;
187 + int NonPerm = mode & ~07777;
189 + for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
190 + if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
192 + if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
194 + mode &= chmod_modes->ModeAND;
195 + if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
196 + mode |= chmod_modes->ModeOR & ~0111;
198 + mode |= chmod_modes->ModeOR;
201 + return mode | NonPerm;
204 +/* Free the linked list created by parse_chmod. */
205 +int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
207 + struct chmod_mode_struct *next;
209 + while (chmod_modes) {
210 + next = chmod_modes->next;
212 + chmod_modes = next;
216 --- orig/flist.c 2005-08-17 06:45:07
217 +++ flist.c 2004-09-18 01:51:11
218 @@ -62,6 +62,8 @@ extern struct file_list *the_file_list;
220 extern char curr_dir[MAXPATHLEN];
222 +extern struct chmod_mode_struct *chmod_modes;
224 extern struct filter_list_struct filter_list;
225 extern struct filter_list_struct server_filter_list;
227 @@ -883,7 +885,10 @@ skip_filters:
229 file->modtime = st.st_mtime;
230 file->length = st.st_size;
231 - file->mode = st.st_mode;
232 + if (chmod_modes && am_sender && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)))
233 + file->mode = tweak_mode(st.st_mode, chmod_modes);
235 + file->mode = st.st_mode;
236 file->uid = st.st_uid;
237 file->gid = st.st_gid;
239 --- orig/options.c 2005-08-27 21:11:26
240 +++ options.c 2005-08-27 21:18:52
241 @@ -141,6 +141,7 @@ char *log_format = NULL;
242 char *password_file = NULL;
243 char *rsync_path = RSYNC_PATH;
244 char *backup_dir = NULL;
245 +char *chmod_mode = NULL;
246 char backup_dir_buf[MAXPATHLEN];
248 int compare_dest = 0;
249 @@ -160,6 +161,8 @@ int list_only = 0;
250 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
251 char *batch_name = NULL;
253 +struct chmod_mode_struct *chmod_modes = NULL;
255 static int daemon_opt; /* sets am_daemon after option error-reporting */
256 static int F_option_cnt = 0;
257 static int modify_window_set;
258 @@ -289,6 +292,7 @@ void usage(enum logcode F)
259 rprintf(F," -D, --devices preserve devices (root only)\n");
260 rprintf(F," -t, --times preserve times\n");
261 rprintf(F," -O, --omit-dir-times omit directories when preserving times\n");
262 + rprintf(F," --chmod=CHMOD change destination permissions\n");
263 rprintf(F," -S, --sparse handle sparse files efficiently\n");
264 rprintf(F," -n, --dry-run show what would have been transferred\n");
265 rprintf(F," -W, --whole-file copy files whole (without rsync algorithm)\n");
266 @@ -411,6 +415,7 @@ static struct poptOption long_options[]
267 {"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
268 {"no-R", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
269 {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
270 + {"chmod", 0, POPT_ARG_STRING, &chmod_mode, 0, 0, 0 },
271 {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
272 {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
273 {"one-file-system", 'x', POPT_ARG_NONE, &one_file_system, 0, 0, 0 },
274 @@ -1122,6 +1127,13 @@ int parse_arguments(int *argc, const cha
275 if (make_backups && !backup_dir)
278 + if (chmod_mode && !(chmod_modes = parse_chmod(chmod_mode))) {
279 + snprintf(err_buf, sizeof err_buf,
280 + "Invalid argument passed to chmod\n");
281 + rprintf(FERROR, "ERROR: %s", err_buf);
286 if (log_format_has(log_format, 'i'))
287 log_format_has_i = 1;
288 @@ -1507,6 +1519,11 @@ void server_options(char **args,int *arg
292 + if (chmod_mode && !am_sender) {
293 + args[ac++] = "--chmod";
294 + args[ac++] = chmod_mode;
297 if (files_from && (!am_sender || filesfrom_host)) {
298 if (filesfrom_host) {
299 args[ac++] = "--files-from";
300 --- orig/rsync.yo 2005-08-27 21:05:12
301 +++ rsync.yo 2005-01-24 01:48:43
302 @@ -323,6 +323,7 @@ to the detailed description below for a
303 -D, --devices preserve devices (root only)
304 -t, --times preserve times
305 -O, --omit-dir-times omit directories when preserving times
306 + --chmod=CHMOD change destination permissions
307 -S, --sparse handle sparse files efficiently
308 -n, --dry-run show what would have been transferred
309 -W, --whole-file copy files whole (without rsync algorithm)
310 @@ -695,6 +696,14 @@ it is preserving modification times (see
311 the directories on the receiving side, it is a good idea to use bf(-O).
312 This option is inferred if you use bf(--backup) without bf(--backup-dir).
314 +dit(bf(--chmod)) This options tells rsync to apply the listed "chmod" pattern
315 +to the permission of the files on the destination. In addition to the normal
316 +parsing rules specified in the chmod manpage, you can specify an item that
317 +should only apply to a directory by prefixing it with a 'D', or specify an
318 +item that should only apply to a file by prefixing it with a 'F'. For example:
320 +quote(--chmod=Dg+s,ug+w,Fo-w,+X)
322 dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
323 instead it will just report the actions it would have taken.
325 --- orig/testsuite/chmod-option.test 2005-07-09 15:49:59
326 +++ testsuite/chmod-option.test 2005-07-09 15:49:59
330 +# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
332 +# This program is distributable under the terms of the GNU GPL (see
335 +# Test that the --chmod option functions correctly.
337 +. $srcdir/testsuite/rsync.fns
343 +fromdir="$scratchdir/from"
344 +todir="$scratchdir/to"
345 +checkdir="$scratchdir/check"
348 +name1="$fromdir/name1"
349 +name2="$fromdir/name2"
350 +dir1="$fromdir/dir1"
351 +dir2="$fromdir/dir2"
352 +echo "This is the file" > "$name1"
353 +echo "This is the other file" > "$name2"
354 +mkdir "$dir1" "$dir2"
356 +chmod 4700 "$name1" || test_skipped "Can't chmod"
360 +# Copy the files we've created over to another directory
361 +checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
363 +# And then manually make the changes which should occur
365 +chmod ug-s,a+rX "$checkdir"/*
366 +chmod +w "$checkdir" "$checkdir"/dir*
368 +checkit "$RSYNC -avv --chmod ug-s,a+rX,D+w \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir"
370 +# The script would have aborted on error, so getting here means we've won.