1 After applying this patch and running configure, you MUST run this
7 --- orig/Makefile.in 2004-08-13 07:18:58
8 +++ Makefile.in 2004-07-03 20:13:41
9 @@ -34,7 +34,7 @@ ZLIBOBJ=zlib/deflate.o zlib/infblock.o z
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 2004-06-18 17:22:08
19 +++ chmod.c 2004-06-18 17:22:08
23 +#define FLAG_X_KEEP (1<<0)
24 +#define FLAG_DIRS_ONLY (1<<1)
25 +#define FLAG_FILES_ONLY (1<<2)
27 +struct chmod_mode_struct {
28 + struct chmod_mode_struct *next;
29 + int ModeAND, ModeOR;
37 +#define STATE_ERROR 0
38 +#define STATE_1ST_HALF 1
39 +#define STATE_2ND_HALF 2
41 +/* Parse a chmod-style argument, and break it down into one or more AND/OR
42 + * pairs in a linked list. We use a state machine to walk through the
44 +struct chmod_mode_struct *parse_chmod(char *modestr)
46 + int state = STATE_1ST_HALF;
47 + int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
48 + struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
51 + while (state != STATE_ERROR) {
52 + if (!*modestr || *modestr == ',') {
54 + state = STATE_ERROR;
57 + prev_mode = curr_mode;
58 + curr_mode = new_array(struct chmod_mode_struct, 1);
60 + prev_mode->next = curr_mode;
62 + first_mode = curr_mode;
63 + curr_mode->next = NULL;
67 + curr_mode->ModeAND = 07777;
68 + curr_mode->ModeOR = (where * what) + topoct;
71 + curr_mode->ModeAND = 07777 - (where * what) - topoct;
72 + curr_mode->ModeOR = 0;
75 + curr_mode->ModeAND = 07777 - (where * 7);
76 + curr_mode->ModeOR = where * what - topoct;
80 + curr_mode->flags = flags;
86 + state = STATE_1ST_HALF;
87 + where = what = op = topoct = topbits = flags = 0;
90 + if (state != STATE_2ND_HALF) {
93 + if (flags & FLAG_FILES_ONLY)
94 + state = STATE_ERROR;
95 + flags |= FLAG_DIRS_ONLY;
98 + if (flags & FLAG_DIRS_ONLY)
99 + state = STATE_ERROR;
100 + flags |= FLAG_FILES_ONLY;
118 + state = STATE_2ND_HALF;
122 + state = STATE_2ND_HALF;
126 + state = STATE_2ND_HALF;
129 + state = STATE_ERROR;
133 + switch (*modestr) {
141 + flags |= FLAG_X_KEEP;
156 + state = STATE_ERROR;
163 + if (state == STATE_ERROR) {
164 + free_chmod_mode(first_mode);
171 +/* Takes an existing file permission and a list of AND/OR changes, and
172 + * create a new permissions. */
173 +int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
175 + int IsX = mode & 0111;
176 + int NonPerm = mode & ~07777;
178 + for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
179 + if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
181 + if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
183 + mode &= chmod_modes->ModeAND;
184 + if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
185 + mode |= chmod_modes->ModeOR & ~0111;
187 + mode |= chmod_modes->ModeOR;
190 + return mode | NonPerm;
193 +/* Free the linked list created by parse_chmod. */
194 +int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
196 + struct chmod_mode_struct *next;
198 + while (chmod_modes) {
199 + next = chmod_modes->next;
201 + chmod_modes = next;
205 --- orig/flist.c 2004-08-12 18:34:38
206 +++ flist.c 2004-07-03 20:13:41
207 @@ -33,6 +33,7 @@ extern int verbose;
208 extern int do_progress;
210 extern int am_server;
211 +extern int am_sender;
212 extern int am_daemon;
213 extern int always_checksum;
214 extern int module_id;
215 @@ -64,6 +65,8 @@ extern int delete_excluded;
216 extern int orig_umask;
217 extern int list_only;
219 +extern struct chmod_mode_struct *chmod_modes;
221 extern struct exclude_list_struct exclude_list;
222 extern struct exclude_list_struct server_exclude_list;
223 extern struct exclude_list_struct local_exclude_list;
224 @@ -867,7 +870,10 @@ skip_excludes:
226 file->modtime = st.st_mtime;
227 file->length = st.st_size;
228 - file->mode = st.st_mode;
229 + if (chmod_modes && am_sender && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)))
230 + file->mode = tweak_mode(st.st_mode, chmod_modes);
232 + file->mode = st.st_mode;
233 file->uid = st.st_uid;
234 file->gid = st.st_gid;
236 --- orig/options.c 2004-08-12 18:34:38
237 +++ options.c 2004-07-03 20:13:41
238 @@ -126,6 +126,7 @@ char *log_format = NULL;
239 char *password_file = NULL;
240 char *rsync_path = RSYNC_PATH;
241 char *backup_dir = NULL;
242 +char *chmod_mode = NULL;
243 char backup_dir_buf[MAXPATHLEN];
244 int rsync_port = RSYNC_PORT;
246 @@ -138,6 +139,8 @@ int list_only = 0;
247 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
248 char *batch_name = NULL;
250 +struct chmod_mode_struct *chmod_modes = NULL;
252 static int daemon_opt; /* sets am_daemon after option error-reporting */
253 static int modify_window_set;
255 @@ -253,6 +256,7 @@ void usage(enum logcode F)
256 rprintf(F," -g, --group preserve group\n");
257 rprintf(F," -D, --devices preserve devices (root only)\n");
258 rprintf(F," -t, --times preserve times\n");
259 + rprintf(F," --chmod=CHMOD change destination permissions\n");
260 rprintf(F," -S, --sparse handle sparse files efficiently\n");
261 rprintf(F," -n, --dry-run show what would have been transferred\n");
262 rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
263 @@ -360,6 +364,7 @@ static struct poptOption long_options[]
264 {"perms", 'p', POPT_ARG_NONE, &preserve_perms, 0, 0, 0 },
265 {"owner", 'o', POPT_ARG_NONE, &preserve_uid, 0, 0, 0 },
266 {"group", 'g', POPT_ARG_NONE, &preserve_gid, 0, 0, 0 },
267 + {"chmod", 0, POPT_ARG_STRING, &chmod_mode, 0, 0, 0 },
268 {"devices", 'D', POPT_ARG_NONE, &preserve_devices, 0, 0, 0 },
269 {"times", 't', POPT_ARG_NONE, &preserve_times, 0, 0, 0 },
270 {"checksum", 'c', POPT_ARG_NONE, &always_checksum, 0, 0, 0 },
271 @@ -808,6 +813,13 @@ int parse_arguments(int *argc, const cha
275 + if (chmod_mode && !(chmod_modes = parse_chmod(chmod_mode))) {
276 + snprintf(err_buf, sizeof err_buf,
277 + "Invalid argument passed to chmod\n");
278 + rprintf(FERROR, "ERROR: %s", err_buf);
282 if (do_progress && !verbose)
285 @@ -1078,6 +1090,11 @@ void server_options(char **args,int *arg
286 args[ac++] = compare_dest;
289 + if (chmod_mode && !am_sender) {
290 + args[ac++] = "--chmod";
291 + args[ac++] = chmod_mode;
294 if (files_from && (!am_sender || remote_filesfrom_file)) {
295 if (remote_filesfrom_file) {
296 args[ac++] = "--files-from";
297 --- orig/rsync.yo 2004-08-13 07:18:59
298 +++ rsync.yo 2004-07-03 20:13:41
299 @@ -330,6 +330,7 @@ verb(
300 -g, --group preserve group
301 -D, --devices preserve devices (root only)
302 -t, --times preserve times
303 + --chmod=CHMOD change destination permissions
304 -S, --sparse handle sparse files efficiently
305 -n, --dry-run show what would have been transferred
306 -W, --whole-file copy whole files, no incremental checks
307 @@ -603,6 +604,14 @@ cause the next transfer to behave as if
308 updated (though the rsync algorithm will make the update fairly efficient
309 if the files haven't actually changed, you're much better off using -t).
311 +dit(bf(--chmod)) This options tells rsync to apply the listed "chmod" pattern
312 +to the permission of the files on the destination. In addition to the normal
313 +parsing rules specified in the chmod manpage, you can specify an item that
314 +should only apply to a directory by prefixing it with a 'D', or specify an
315 +item that should only apply to a file by prefixing it with a 'F'. For example:
317 +quote(--chmod=Dg+s,ug+w,Fo-w,+X)
319 dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
320 instead it will just report the actions it would have taken.
322 --- orig/testsuite/chmod-option.test 2004-06-18 17:22:09
323 +++ testsuite/chmod-option.test 2004-06-18 17:22:09
327 +# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
329 +# This program is distributable under the terms of the GNU GPL (see
332 +# Test that the --chmod option functions correctly.
334 +. $srcdir/testsuite/rsync.fns
340 +fromdir="$scratchdir/from"
341 +todir="$scratchdir/to"
342 +checkdir="$scratchdir/check"
345 +name1="$fromdir/name1"
346 +name2="$fromdir/name2"
347 +dir1="$fromdir/dir1"
348 +dir2="$fromdir/dir2"
349 +echo "This is the file" > "$name1"
350 +echo "This is the other file" > "$name2"
351 +mkdir "$dir1" "$dir2"
353 +chmod 4700 "$name1" || test_skipped "Can't chmod"
357 +# Copy the files we've created over to another directory
358 +checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
360 +# And then manually make the changes which should occur
361 +chmod ug-s,a+rX "$checkdir"/*
362 +chmod g+w "$checkdir" "$checkdir"/dir*
364 +checkit "$RSYNC -avv --chmod ug-s,a+rX,Dg+w \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir"
366 +# The script would have aborted on error, so getting here means we've won.