This patch implements an idiom where two -o options cause rsync to try to set the owner information even if we're not running as UID 0. Similarly, two -g options cause rsync to try to set all groups, even if they weren't returned by getgroups(). E.g.: rsync -avoogg host:/from/ /to/ --- orig/compat.c 2004-07-21 23:59:35 +++ compat.c 2004-09-09 01:59:08 @@ -28,8 +28,11 @@ int remote_protocol = 0; extern int verbose; +extern int am_root; extern int am_server; extern int am_sender; +extern int preserve_uid; +extern int preserve_gid; extern int read_batch; extern int checksum_seed; extern int protocol_version; @@ -81,4 +84,11 @@ void setup_protocol(int f_out,int f_in) } else { checksum_seed = read_int(f_in); } + + if (am_root) { + if (preserve_uid) + preserve_uid = 2; + if (preserve_gid) + preserve_gid = 2; + } } --- orig/options.c 2004-09-23 17:42:07 +++ options.c 2004-09-09 01:59:08 @@ -358,8 +358,8 @@ static struct poptOption long_options[] {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 }, {"copy-unsafe-links", 0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 }, {"perms", 'p', POPT_ARG_NONE, &preserve_perms, 0, 0, 0 }, - {"owner", 'o', POPT_ARG_NONE, &preserve_uid, 0, 0, 0 }, - {"group", 'g', POPT_ARG_NONE, &preserve_gid, 0, 0, 0 }, + {"owner", 'o', POPT_ARG_NONE, 0, 'o', 0, 0 }, + {"group", 'g', POPT_ARG_NONE, 0, 'g', 0, 0 }, {"devices", 'D', POPT_ARG_NONE, &preserve_devices, 0, 0, 0 }, {"times", 't', POPT_ARG_NONE, &preserve_times, 0, 0, 0 }, {"checksum", 'c', POPT_ARG_NONE, &always_checksum, 0, 0, 0 }, @@ -568,6 +568,14 @@ int parse_arguments(int *argc, const cha usage(FINFO); exit_cleanup(0); + case 'o': + preserve_uid++; + break; + + case 'g': + preserve_gid++; + break; + case 'v': verbose++; break; @@ -707,8 +715,8 @@ int parse_arguments(int *argc, const cha #endif preserve_perms = 1; preserve_times = 1; - preserve_gid = 1; - preserve_uid = 1; + preserve_uid |= 1; + preserve_gid |= 1; preserve_devices = 1; } @@ -942,10 +950,16 @@ void server_options(char **args,int *arg if (preserve_hard_links) argstr[x++] = 'H'; - if (preserve_uid) + if (preserve_uid) { argstr[x++] = 'o'; - if (preserve_gid) + if (preserve_uid > 1) + argstr[x++] = 'o'; + } + if (preserve_gid) { argstr[x++] = 'g'; + if (preserve_gid > 1) + argstr[x++] = 'g'; + } if (preserve_devices) argstr[x++] = 'D'; if (preserve_times) --- orig/rsync.c 2004-09-07 21:45:30 +++ rsync.c 2004-09-09 01:59:08 @@ -25,7 +25,6 @@ extern int verbose; extern int dry_run; extern int preserve_times; -extern int am_root; extern int am_sender; extern int am_generator; extern int preserve_uid; @@ -158,7 +157,7 @@ int set_perms(char *fname,struct file_st updated = 1; } - change_uid = am_root && preserve_uid && st->st_uid != file->uid; + change_uid = preserve_uid > 1 && st->st_uid != file->uid; change_gid = preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid; if (change_uid || change_gid) { --- orig/uidlist.c 2004-04-29 19:37:25 +++ uidlist.c 2004-09-09 01:59:08 @@ -35,7 +35,6 @@ extern int verbose; extern int preserve_uid; extern int preserve_gid; extern int numeric_ids; -extern int am_root; struct idlist { struct idlist *next; @@ -177,7 +176,7 @@ static struct idlist *recv_add_gid(int i int id2 = name ? map_gid(id, name) : id; struct idlist *node; - if (!am_root && !is_in_group(id2)) + if (preserve_gid < 2 && !is_in_group(id2)) id2 = GID_NONE; node = add_to_list(&gidlist, id, name, id2); @@ -339,11 +338,11 @@ void recv_uid_list(int f, struct file_li /* now convert the uid/gid of all files in the list to the mapped * uid/gid */ - if (am_root && preserve_uid && !numeric_ids) { + if (preserve_uid > 1 && !numeric_ids) { for (i = 0; i < flist->count; i++) flist->files[i]->uid = match_uid(flist->files[i]->uid); } - if (preserve_gid && (!am_root || !numeric_ids)) { + if (preserve_gid && (preserve_gid < 2 || !numeric_ids)) { for (i = 0; i < flist->count; i++) flist->files[i]->gid = match_gid(flist->files[i]->gid); }