The patches for 3.0.4pre2.
[rsync/rsync-patches.git] / usermap.diff
CommitLineData
409bd73e
WD
1This adds a --usermap and a --groupmap option. See the man page for
2more details.
4122278d 3
409bd73e
WD
4To use this patch, run these commands for a successful build:
5
6 patch -p1 <patches/usermap.diff
7 ./configure (optional if already run)
8 make
4122278d 9
cc3e685d
WD
10diff --git a/flist.c b/flist.c
11--- a/flist.c
12+++ b/flist.c
ae306a29 13@@ -71,6 +71,7 @@ extern int sender_symlink_iconv;
d4dd2dd5 14 extern int unsort_ndx;
4122278d 15 extern struct stats stats;
c8a8b4a7 16 extern char *filesfrom_host;
d4dd2dd5 17+extern char *usermap, *groupmap;
4122278d 18
d4dd2dd5
WD
19 extern char curr_dir[MAXPATHLEN];
20
ae306a29 21@@ -767,7 +768,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
409bd73e 22 uid = (uid_t)read_varint(f);
6a189d36 23 if (xflags & XMIT_USER_NAME_FOLLOWS)
409bd73e
WD
24 uid = recv_user_name(f, uid);
25- else if (inc_recurse && am_root && !numeric_ids)
f62e6e48 26+ else if (inc_recurse && am_root && (!numeric_ids || usermap))
409bd73e
WD
27 uid = match_uid(uid);
28 }
29 }
ae306a29 30@@ -779,7 +780,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
761f1b71 31 gid_flags = 0;
6a189d36 32 if (xflags & XMIT_GROUP_NAME_FOLLOWS)
761f1b71 33 gid = recv_group_name(f, gid, &gid_flags);
409bd73e 34- else if (inc_recurse && (!am_root || !numeric_ids))
f62e6e48 35+ else if (inc_recurse && (!am_root || !numeric_ids || groupmap))
761f1b71 36 gid = match_gid(gid, &gid_flags);
409bd73e
WD
37 }
38 }
ae306a29 39@@ -2264,8 +2265,13 @@ struct file_list *recv_file_list(int f)
4122278d
WD
40 int dstart, flags;
41 int64 start_read;
42
43- if (!first_flist)
44+ if (!first_flist) {
45 rprintf(FLOG, "receiving file list\n");
46+ if (usermap)
47+ parse_name_map(usermap, 1);
48+ if (groupmap)
49+ parse_name_map(groupmap, 0);
50+ }
51 if (show_filelist_p())
52 start_filelist_progress("receiving file list");
53 else if (inc_recurse && verbose && !am_server && !first_flist)
cc3e685d
WD
54diff --git a/options.c b/options.c
55--- a/options.c
56+++ b/options.c
c0c7984e 57@@ -167,6 +167,8 @@ char *rsync_path = RSYNC_PATH;
4122278d
WD
58 char *backup_dir = NULL;
59 char backup_dir_buf[MAXPATHLEN];
60 char *sockopts = NULL;
61+char *usermap = NULL;
62+char *groupmap = NULL;
63 int rsync_port = 0;
64 int compare_dest = 0;
65 int copy_dest = 0;
c0c7984e 66@@ -384,6 +386,8 @@ void usage(enum logcode F)
4122278d
WD
67 rprintf(F," --delay-updates put all updated files into place at transfer's end\n");
68 rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n");
69 rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
70+ rprintf(F," --usermap=STRING custom username mapping\n");
71+ rprintf(F," --groupmap=STRING custom groupname mapping\n");
cc3e685d
WD
72 rprintf(F," --timeout=SECONDS set I/O timeout in seconds\n");
73 rprintf(F," --contimeout=SECONDS set daemon connection timeout in seconds\n");
4122278d 74 rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n");
ab5ffac0
WD
75@@ -446,7 +450,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
76 OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
77 OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
78 OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
79- OPT_NO_D, OPT_APPEND, OPT_NO_ICONV,
80+ OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_USERMAP, OPT_GROUPMAP,
81 OPT_SERVER, OPT_REFUSED_BASE = 9000};
82
83 static struct poptOption long_options[] = {
c0c7984e 84@@ -622,6 +626,8 @@ static struct poptOption long_options[] = {
c8a8b4a7 85 {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
6cbbe66d
WD
86 {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 },
87 {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 },
ab5ffac0
WD
88+ {"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 },
89+ {"groupmap", 0, POPT_ARG_STRING, 0, OPT_GROUPMAP, 0, 0 },
4122278d 90 {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
6cbbe66d 91 {"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 },
cc3e685d 92 {"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 },
ab5ffac0
WD
93@@ -1228,6 +1234,24 @@ int parse_arguments(int *argc_p, const char ***argv_p)
94 }
95 break;
96
97+ case OPT_USERMAP:
98+ if (usermap) {
99+ snprintf(err_buf, sizeof err_buf,
100+ "You can only specify --usermap once.\n");
101+ return 0;
102+ }
103+ usermap = (char *)poptGetOptArg(pc);
104+ break;
105+
106+ case OPT_GROUPMAP:
107+ if (groupmap) {
108+ snprintf(err_buf, sizeof err_buf,
109+ "You can only specify --groupmap once.\n");
110+ return 0;
111+ }
112+ groupmap = (char *)poptGetOptArg(pc);
113+ break;
114+
115 case OPT_HELP:
116 usage(FINFO);
117 exit_cleanup(0);
ae306a29 118@@ -2005,6 +2029,18 @@ void server_options(char **args, int *argc_p)
d4dd2dd5 119 args[ac++] = "--use-qsort";
4122278d
WD
120
121 if (am_sender) {
122+ if (usermap) {
f62e6e48 123+ if (asprintf(&arg, "--usermap=%s", usermap) < 0)
4122278d
WD
124+ goto oom;
125+ args[ac++] = arg;
126+ }
127+
128+ if (groupmap) {
f62e6e48 129+ if (asprintf(&arg, "--groupmap=%s", groupmap) < 0)
4122278d
WD
130+ goto oom;
131+ args[ac++] = arg;
132+ }
133+
134 if (ignore_existing)
135 args[ac++] = "--ignore-existing";
136
cc3e685d
WD
137diff --git a/rsync.yo b/rsync.yo
138--- a/rsync.yo
139+++ b/rsync.yo
140@@ -378,6 +378,8 @@ to the detailed description below for a complete description. verb(
4122278d
WD
141 --delay-updates put all updated files into place at end
142 -m, --prune-empty-dirs prune empty directory chains from file-list
143 --numeric-ids don't map uid/gid values by user/group name
144+ --usermap=STRING custom username mapping
145+ --groupmap=STRING custom groupname mapping
cc3e685d
WD
146 --timeout=SECONDS set I/O timeout in seconds
147 --contimeout=SECONDS set daemon connection timeout in seconds
4122278d 148 -I, --ignore-times don't skip files that match size and time
ae306a29 149@@ -1620,6 +1622,47 @@ from the source system is used instead. See also the comments on the
4122278d
WD
150 the chroot setting affects rsync's ability to look up the names of the
151 users and groups and what you can do about it.
152
153+dit(bf(--usermap=STRING, --groupmap=STRING)) These options allow you to
409bd73e
WD
154+specify users and groups that should be mapped to other values by the
155+receiving side. The bf(STRING) is one or more bf(FROM):bf(TO) pairs of
156+values separated by commas. Any matching bf(FROM) value from the sender is
157+replaced with a bf(TO) value from the receiver. You may specify usernames
158+or user IDs for the bf(FROM) and bf(TO) values, and the bf(FROM) value may
159+also be a wild-card string, which will be matched against the sender's
ab5ffac0
WD
160+names (wild-cards do NOT match against ID numbers, though see below for
161+why a '*' matches everything). You may instead specify a range of ID
162+numbers via an inclusive range: LOW-HIGH. For example:
409bd73e 163+
ab5ffac0 164+verb( --usermap=0-99:nobody,wayne:admin,*:normal --groupmap=usr:1,1:usr)
409bd73e 165+
ab5ffac0
WD
166+The first match in the list is the one that is used. You should specify
167+all your user mappings using a single bf(--usermap) option, and/or all
168+your group mappings using a single bf(--groupmap) option.
4122278d 169+
9405aad3 170+Note that the sender's name for the 0 user and group are not transmitted
409bd73e 171+to the receiver, so you should either match these values using a 0, or use
ab5ffac0
WD
172+the names in effect on the receiving side (typically "root"). All other
173+bf(FROM) names match those in use on the sending side. All bf(TO) names
174+match those in use on the receiving side.
4122278d 175+
ab5ffac0 176+Any IDs that do not have a name on the sending side are treated as having an
9405aad3 177+empty name for the purpose of matching. This allows them to be matched via
ab5ffac0 178+a "*" or using an empty name. For instance:
9405aad3
WD
179+
180+verb( --usermap=:nobody --groupmap=*:nobody)
181+
182+When the bf(--numeric-ids) option is used,the sender does not send any
ab5ffac0 183+names, so all the IDs are treated as having an empty name. This means that
9405aad3
WD
184+you will need to specify numeric bf(FROM) values if you want to map these
185+nameless IDs to different values.
4122278d 186+
409bd73e
WD
187+For the bf(--usermap) option to have any effect, the bf(-o) (bf(--owner))
188+option must be used (or implied), and the receiver will need to be running
9405aad3 189+as a super-user (see also the bf(--fake-super) option). For the bf(--groupmap)
409bd73e
WD
190+option to have any effect, the bf(-g) (bf(--groups)) option must be used
191+(or implied), and the receiver will need to have permissions to set that
192+group.
4122278d
WD
193+
194 dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum I/O
195 timeout in seconds. If no data is transferred for the specified time
196 then rsync will exit. The default is 0, which means no timeout.
ae306a29
WD
197diff --git a/support/mapfrom b/support/mapfrom
198new file mode 100755
199--- /dev/null
200+++ b/support/mapfrom
201@@ -0,0 +1,5 @@
202+#!/usr/bin/perl
203+while (<>) {
204+ push @_, "$2:$1" if /^(\w+):[^:]+:(\d+)/;
205+}
206+print join(',', @_), "\n";
207diff --git a/support/mapto b/support/mapto
208new file mode 100755
209--- /dev/null
210+++ b/support/mapto
211@@ -0,0 +1,5 @@
212+#!/usr/bin/perl
213+while (<>) {
214+ push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/;
215+}
216+print join(',', @_), "\n";
cc3e685d
WD
217diff --git a/uidlist.c b/uidlist.c
218--- a/uidlist.c
219+++ b/uidlist.c
c82285d5
WD
220@@ -24,6 +24,7 @@
221 * are special. */
222
223 #include "rsync.h"
224+#include "ifuncs.h"
225 #include "io.h"
226
227 extern int verbose;
228@@ -32,6 +33,8 @@ extern int preserve_uid;
4122278d
WD
229 extern int preserve_gid;
230 extern int preserve_acls;
231 extern int numeric_ids;
409bd73e
WD
232+extern char *usermap;
233+extern char *groupmap;
4122278d 234
6a189d36
WD
235 #ifdef HAVE_GETGROUPS
236 # ifndef GETGROUPS_T
c82285d5 237@@ -41,6 +44,9 @@ extern int numeric_ids;
6a189d36
WD
238
239 #define GID_NONE ((gid_t)-1)
240
241+#define NFLAGS_WILD_NAME_MATCH (1<<0)
242+#define NFLAGS_NAME_MATCH (1<<1)
243+
4122278d
WD
244 struct idlist {
245 struct idlist *next;
4c15e800 246 const char *name;
c82285d5 247@@ -48,8 +54,8 @@ struct idlist {
6a189d36 248 uint16 flags;
4122278d
WD
249 };
250
251-static struct idlist *uidlist;
252-static struct idlist *gidlist;
253+static struct idlist *uidlist, *uidmap;
254+static struct idlist *gidlist, *gidmap;
255
4c15e800 256 static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
6a189d36 257 id_t id2, uint16 flags)
4c15e800 258@@ -84,22 +90,6 @@ static const char *gid_to_name(gid_t gid)
9405aad3
WD
259 return NULL;
260 }
261
85096e5e 262-static uid_t map_uid(uid_t id, const char *name)
9405aad3
WD
263-{
264- uid_t uid;
265- if (id != 0 && name_to_uid(name, &uid))
266- return uid;
267- return id;
268-}
269-
85096e5e 270-static gid_t map_gid(gid_t id, const char *name)
9405aad3
WD
271-{
272- gid_t gid;
273- if (id != 0 && name_to_gid(name, &gid))
274- return gid;
275- return id;
276-}
277-
278 static int is_in_group(gid_t gid)
279 {
280 #ifdef HAVE_GETGROUPS
ab5ffac0 281@@ -159,34 +149,53 @@ static int is_in_group(gid_t gid)
9405aad3
WD
282 #endif
283 }
284
285-/* Add a uid to the list of uids. Only called on receiving side. */
85096e5e 286-static struct idlist *recv_add_uid(uid_t id, const char *name)
9405aad3 287+/* Add a uid/gid to its list of ids. Only called on receiving side. */
ab5ffac0
WD
288+static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap,
289+ id_t id, const char *name)
4122278d
WD
290 {
291- uid_t id2 = name ? map_uid(id, name) : id;
292 struct idlist *node;
ab5ffac0 293+ int flag;
6a189d36 294+ id_t id2;
409bd73e 295
6a189d36 296- node = add_to_list(&uidlist, id, name, id2, 0);
409bd73e
WD
297+ if (!name)
298+ name = "";
4122278d 299
9405aad3 300- if (verbose > 3) {
6a189d36
WD
301- rprintf(FINFO, "uid %u(%s) maps to %u\n",
302- (unsigned)id, name ? name : "", (unsigned)id2);
ab5ffac0 303+ for (node = idmap; node; node = node->next) {
6a189d36 304+ if (node->flags & NFLAGS_WILD_NAME_MATCH) {
409bd73e
WD
305+ if (!wildmatch(node->name, name))
306+ continue;
6a189d36 307+ } else if (node->flags & NFLAGS_NAME_MATCH) {
409bd73e
WD
308+ if (strcmp(node->name, name) != 0)
309+ continue;
ab5ffac0
WD
310+ } else if (node->name) {
311+ if (id < node->id || id > (unsigned long)node->name)
312+ continue;
6a189d36 313+ } else {
9405aad3 314+ if (node->id != id)
409bd73e 315+ continue;
4122278d 316+ }
409bd73e 317+ break;
9405aad3 318 }
409bd73e
WD
319+ if (node)
320+ id2 = node->id2;
9405aad3 321+ else if (*name && id) {
ab5ffac0 322+ if (idmap == uidmap) {
9405aad3 323+ uid_t uid;
6a189d36 324+ id2 = name_to_uid(name, &uid) ? uid : id;
9405aad3
WD
325+ } else {
326+ gid_t gid;
6a189d36 327+ id2 = name_to_gid(name, &gid) ? gid : id;
9405aad3
WD
328+ }
329+ } else
409bd73e 330+ id2 = id;
4122278d 331
6a189d36 332- return node;
9405aad3
WD
333-}
334-
335-/* Add a gid to the list of gids. Only called on receiving side. */
85096e5e 336-static struct idlist *recv_add_gid(gid_t id, const char *name)
9405aad3
WD
337-{
338- gid_t id2 = name ? map_gid(id, name) : id;
339- struct idlist *node;
340-
6a189d36
WD
341- node = add_to_list(&gidlist, id, name, id2,
342- !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
ab5ffac0
WD
343+ flag = idmap == gidmap && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0;
344+ node = add_to_list(idlist_ptr, id, *name ? name : NULL, id2, flag);
409bd73e
WD
345
346 if (verbose > 3) {
6a189d36
WD
347- rprintf(FINFO, "gid %u(%s) maps to %u\n",
348- (unsigned)id, name ? name : "", (unsigned)id2);
349+ rprintf(FINFO, "%sid %u(%s) maps to %u\n",
ab5ffac0 350+ idmap == uidmap ? "u" : "g",
6a189d36 351+ (unsigned)id, name, (unsigned)id2);
409bd73e
WD
352 }
353
6a189d36 354 return node;
ab5ffac0 355@@ -195,12 +204,9 @@ static struct idlist *recv_add_gid(gid_t id, const char *name)
409bd73e
WD
356 /* this function is a definate candidate for a faster algorithm */
357 uid_t match_uid(uid_t uid)
358 {
359- static uid_t last_in, last_out;
360+ static uid_t last_in = -1, last_out = -1;
4122278d
WD
361 struct idlist *list;
362
363- if (uid == 0)
364- return 0;
365-
366 if (uid == last_in)
367 return last_out;
368
ab5ffac0 369@@ -208,10 +214,13 @@ uid_t match_uid(uid_t uid)
6a189d36
WD
370
371 for (list = uidlist; list; list = list->next) {
372 if (list->id == uid)
373- return last_out = list->id2;
374+ break;
409bd73e 375 }
4122278d 376
409bd73e 377- return last_out = uid;
6a189d36 378+ if (!list)
ab5ffac0 379+ list = recv_add_id(&uidlist, uidmap, uid, NULL);
6a189d36
WD
380+
381+ return last_out = list->id2;
409bd73e 382 }
4122278d 383
6a189d36 384 gid_t match_gid(gid_t gid, uint16 *flags_ptr)
ab5ffac0 385@@ -227,7 +236,7 @@ gid_t match_gid(gid_t gid, uint16 *flags_ptr)
761f1b71
WD
386 break;
387 }
388 if (!list)
8f1c03c8 389- list = recv_add_gid(gid, NULL);
ab5ffac0 390+ list = recv_add_id(&gidlist, gidmap, gid, NULL);
761f1b71 391 last = list;
9405aad3
WD
392 }
393
ab5ffac0 394@@ -320,7 +329,7 @@ uid_t recv_user_name(int f, uid_t uid)
85096e5e
WD
395 free(name);
396 name = NULL;
397 }
6a189d36 398- node = recv_add_uid(uid, name); /* node keeps name's memory */
ab5ffac0 399+ node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */
6a189d36 400 return node->id2;
9405aad3
WD
401 }
402
ab5ffac0 403@@ -336,7 +345,7 @@ gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
85096e5e
WD
404 free(name);
405 name = NULL;
406 }
6a189d36 407- node = recv_add_gid(gid, name); /* node keeps name's memory */
ab5ffac0 408+ node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */
6a189d36
WD
409 if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
410 *flags_ptr |= FLAG_SKIP_GROUP;
411 return node->id2;
ab5ffac0 412@@ -363,17 +372,103 @@ void recv_id_list(int f, struct file_list *flist)
4122278d 413
409bd73e
WD
414 /* Now convert all the uids/gids from sender values to our values. */
415 #ifdef SUPPORT_ACLS
416- if (preserve_acls && !numeric_ids)
6a189d36 417+ if (preserve_acls && (!numeric_ids || usermap || groupmap))
409bd73e
WD
418 match_acl_ids();
419 #endif
420- if (am_root && preserve_uid && !numeric_ids) {
421+ if (am_root && preserve_uid && (!numeric_ids || usermap)) {
9c85142a 422 for (i = 0; i < flist->used; i++)
6a189d36 423 F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
409bd73e
WD
424 }
425- if (preserve_gid && (!am_root || !numeric_ids)) {
426+ if (preserve_gid && (!am_root || !numeric_ids || groupmap)) {
9c85142a 427 for (i = 0; i < flist->used; i++) {
6a189d36
WD
428 F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
429 &flist->files[i]->flags);
430 }
4122278d
WD
431 }
432 }
433+
434+void parse_name_map(char *map, int usernames)
435+{
9405aad3
WD
436+ struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap;
437+ struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist;
ab5ffac0
WD
438+ char *colon, *end, *name, *cp = map + strlen(map);
439+ id_t id1;
6a189d36 440+ uint16 flags;
4122278d 441+
ab5ffac0 442+ /* Parse the list in reverse, so the order in the struct is right. */
4122278d
WD
443+ while (1) {
444+ end = cp;
445+ while (cp > map && cp[-1] != ',') cp--;
446+ if (!(colon = strchr(cp, ':'))) {
447+ rprintf(FERROR, "No colon found in --%smap: %s\n",
448+ usernames ? "user" : "group", cp);
449+ exit_cleanup(RERR_SYNTAX);
450+ }
ab5ffac0
WD
451+ if (!colon[1]) {
452+ rprintf(FERROR, "No name found after colon --%smap: %s\n",
453+ usernames ? "user" : "group", cp);
454+ exit_cleanup(RERR_SYNTAX);
455+ }
4122278d
WD
456+ *colon = '\0';
457+
458+ if (isDigit(cp)) {
ab5ffac0
WD
459+ char *dash = strchr(cp, '-');
460+ if (strspn(cp, "0123456789-") != (size_t)(colon - cp)
461+ || (dash && (!dash[1] || strchr(dash+1, '-')))) {
4122278d
WD
462+ bad_number:
463+ rprintf(FERROR, "Invalid number in --%smap: %s\n",
464+ usernames ? "user" : "group", cp);
465+ exit_cleanup(RERR_SYNTAX);
466+ }
ab5ffac0
WD
467+ if (dash)
468+ name = (char *)atol(dash+1);
469+ else
470+ name = (char *)0;
6a189d36 471+ flags = 0;
ab5ffac0 472+ id1 = atol(cp);
6a189d36
WD
473+ } else if (strpbrk(cp, "*[?")) {
474+ flags = NFLAGS_WILD_NAME_MATCH;
ab5ffac0 475+ name = cp;
6a189d36
WD
476+ id1 = 0;
477+ } else {
478+ flags = NFLAGS_NAME_MATCH;
ab5ffac0 479+ name = cp;
6a189d36
WD
480+ id1 = 0;
481+ }
4122278d
WD
482+
483+ if (isDigit(colon+1)) {
484+ if (strspn(colon+1, "0123456789") != (size_t)(end - colon - 1)) {
485+ cp = colon+1;
486+ goto bad_number;
487+ }
ab5ffac0
WD
488+ add_to_list(idmap_ptr, id1, name, atol(colon+1), flags);
489+ } else if (usernames) {
490+ uid_t uid;
491+ if (name_to_uid(colon+1, &uid))
492+ add_to_list(idmap_ptr, id1, name, uid, flags);
493+ else {
494+ rprintf(FERROR,
495+ "Unknown --usermap name on receiver: %s\n",
496+ colon+1);
497+ }
4122278d 498+ } else {
ab5ffac0
WD
499+ gid_t gid;
500+ if (name_to_gid(colon+1, &gid))
501+ add_to_list(idmap_ptr, id1, name, gid, flags);
502+ else {
503+ rprintf(FERROR,
504+ "Unknown --groupmap name on receiver: %s\n",
505+ colon+1);
4122278d
WD
506+ }
507+ }
508+
4122278d
WD
509+ if (cp == map)
510+ break;
511+
512+ *--cp = '\0'; /* replace comma */
513+ }
409bd73e 514+
85096e5e 515+ /* The 0 user/group doesn't get its name sent, so add it explicitly. */
ab5ffac0 516+ recv_add_id(idlist_ptr, *idmap_ptr, 0,
85096e5e 517+ numeric_ids ? NULL : usernames ? uid_to_name(0) : gid_to_name(0));
4122278d 518+}