--- /dev/null
+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-18 01:49:33
++++ 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;
+ }
+
+@@ -934,10 +942,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);
+ }