Added the dparam.diff patch.
[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
f9df736a 13@@ -70,6 +70,7 @@ extern int need_unsorted_flist;
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
bc3fcf1d 21@@ -764,7 +765,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 }
bc3fcf1d 30@@ -776,7 +777,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 }
7f0bf1cb 39@@ -2188,8 +2189,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);
118@@ -1997,6 +2021,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
ab5ffac0 149@@ -1608,6 +1610,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.
cc3e685d
WD
197diff --git a/uidlist.c b/uidlist.c
198--- a/uidlist.c
199+++ b/uidlist.c
c82285d5
WD
200@@ -24,6 +24,7 @@
201 * are special. */
202
203 #include "rsync.h"
204+#include "ifuncs.h"
205 #include "io.h"
206
207 extern int verbose;
208@@ -32,6 +33,8 @@ extern int preserve_uid;
4122278d
WD
209 extern int preserve_gid;
210 extern int preserve_acls;
211 extern int numeric_ids;
409bd73e
WD
212+extern char *usermap;
213+extern char *groupmap;
4122278d 214
6a189d36
WD
215 #ifdef HAVE_GETGROUPS
216 # ifndef GETGROUPS_T
c82285d5 217@@ -41,6 +44,9 @@ extern int numeric_ids;
6a189d36
WD
218
219 #define GID_NONE ((gid_t)-1)
220
221+#define NFLAGS_WILD_NAME_MATCH (1<<0)
222+#define NFLAGS_NAME_MATCH (1<<1)
223+
4122278d
WD
224 struct idlist {
225 struct idlist *next;
4c15e800 226 const char *name;
c82285d5 227@@ -48,8 +54,8 @@ struct idlist {
6a189d36 228 uint16 flags;
4122278d
WD
229 };
230
231-static struct idlist *uidlist;
232-static struct idlist *gidlist;
233+static struct idlist *uidlist, *uidmap;
234+static struct idlist *gidlist, *gidmap;
235
4c15e800 236 static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
6a189d36 237 id_t id2, uint16 flags)
4c15e800 238@@ -84,22 +90,6 @@ static const char *gid_to_name(gid_t gid)
9405aad3
WD
239 return NULL;
240 }
241
85096e5e 242-static uid_t map_uid(uid_t id, const char *name)
9405aad3
WD
243-{
244- uid_t uid;
245- if (id != 0 && name_to_uid(name, &uid))
246- return uid;
247- return id;
248-}
249-
85096e5e 250-static gid_t map_gid(gid_t id, const char *name)
9405aad3
WD
251-{
252- gid_t gid;
253- if (id != 0 && name_to_gid(name, &gid))
254- return gid;
255- return id;
256-}
257-
258 static int is_in_group(gid_t gid)
259 {
260 #ifdef HAVE_GETGROUPS
ab5ffac0 261@@ -159,34 +149,53 @@ static int is_in_group(gid_t gid)
9405aad3
WD
262 #endif
263 }
264
265-/* Add a uid to the list of uids. Only called on receiving side. */
85096e5e 266-static struct idlist *recv_add_uid(uid_t id, const char *name)
9405aad3 267+/* Add a uid/gid to its list of ids. Only called on receiving side. */
ab5ffac0
WD
268+static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap,
269+ id_t id, const char *name)
4122278d
WD
270 {
271- uid_t id2 = name ? map_uid(id, name) : id;
272 struct idlist *node;
ab5ffac0 273+ int flag;
6a189d36 274+ id_t id2;
409bd73e 275
6a189d36 276- node = add_to_list(&uidlist, id, name, id2, 0);
409bd73e
WD
277+ if (!name)
278+ name = "";
4122278d 279
9405aad3 280- if (verbose > 3) {
6a189d36
WD
281- rprintf(FINFO, "uid %u(%s) maps to %u\n",
282- (unsigned)id, name ? name : "", (unsigned)id2);
ab5ffac0 283+ for (node = idmap; node; node = node->next) {
6a189d36 284+ if (node->flags & NFLAGS_WILD_NAME_MATCH) {
409bd73e
WD
285+ if (!wildmatch(node->name, name))
286+ continue;
6a189d36 287+ } else if (node->flags & NFLAGS_NAME_MATCH) {
409bd73e
WD
288+ if (strcmp(node->name, name) != 0)
289+ continue;
ab5ffac0
WD
290+ } else if (node->name) {
291+ if (id < node->id || id > (unsigned long)node->name)
292+ continue;
6a189d36 293+ } else {
9405aad3 294+ if (node->id != id)
409bd73e 295+ continue;
4122278d 296+ }
409bd73e 297+ break;
9405aad3 298 }
409bd73e
WD
299+ if (node)
300+ id2 = node->id2;
9405aad3 301+ else if (*name && id) {
ab5ffac0 302+ if (idmap == uidmap) {
9405aad3 303+ uid_t uid;
6a189d36 304+ id2 = name_to_uid(name, &uid) ? uid : id;
9405aad3
WD
305+ } else {
306+ gid_t gid;
6a189d36 307+ id2 = name_to_gid(name, &gid) ? gid : id;
9405aad3
WD
308+ }
309+ } else
409bd73e 310+ id2 = id;
4122278d 311
6a189d36 312- return node;
9405aad3
WD
313-}
314-
315-/* Add a gid to the list of gids. Only called on receiving side. */
85096e5e 316-static struct idlist *recv_add_gid(gid_t id, const char *name)
9405aad3
WD
317-{
318- gid_t id2 = name ? map_gid(id, name) : id;
319- struct idlist *node;
320-
6a189d36
WD
321- node = add_to_list(&gidlist, id, name, id2,
322- !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
ab5ffac0
WD
323+ flag = idmap == gidmap && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0;
324+ node = add_to_list(idlist_ptr, id, *name ? name : NULL, id2, flag);
409bd73e
WD
325
326 if (verbose > 3) {
6a189d36
WD
327- rprintf(FINFO, "gid %u(%s) maps to %u\n",
328- (unsigned)id, name ? name : "", (unsigned)id2);
329+ rprintf(FINFO, "%sid %u(%s) maps to %u\n",
ab5ffac0 330+ idmap == uidmap ? "u" : "g",
6a189d36 331+ (unsigned)id, name, (unsigned)id2);
409bd73e
WD
332 }
333
6a189d36 334 return node;
ab5ffac0 335@@ -195,12 +204,9 @@ static struct idlist *recv_add_gid(gid_t id, const char *name)
409bd73e
WD
336 /* this function is a definate candidate for a faster algorithm */
337 uid_t match_uid(uid_t uid)
338 {
339- static uid_t last_in, last_out;
340+ static uid_t last_in = -1, last_out = -1;
4122278d
WD
341 struct idlist *list;
342
343- if (uid == 0)
344- return 0;
345-
346 if (uid == last_in)
347 return last_out;
348
ab5ffac0 349@@ -208,10 +214,13 @@ uid_t match_uid(uid_t uid)
6a189d36
WD
350
351 for (list = uidlist; list; list = list->next) {
352 if (list->id == uid)
353- return last_out = list->id2;
354+ break;
409bd73e 355 }
4122278d 356
409bd73e 357- return last_out = uid;
6a189d36 358+ if (!list)
ab5ffac0 359+ list = recv_add_id(&uidlist, uidmap, uid, NULL);
6a189d36
WD
360+
361+ return last_out = list->id2;
409bd73e 362 }
4122278d 363
6a189d36 364 gid_t match_gid(gid_t gid, uint16 *flags_ptr)
ab5ffac0 365@@ -227,7 +236,7 @@ gid_t match_gid(gid_t gid, uint16 *flags_ptr)
761f1b71
WD
366 break;
367 }
368 if (!list)
8f1c03c8 369- list = recv_add_gid(gid, NULL);
ab5ffac0 370+ list = recv_add_id(&gidlist, gidmap, gid, NULL);
761f1b71 371 last = list;
9405aad3
WD
372 }
373
ab5ffac0 374@@ -320,7 +329,7 @@ uid_t recv_user_name(int f, uid_t uid)
85096e5e
WD
375 free(name);
376 name = NULL;
377 }
6a189d36 378- node = recv_add_uid(uid, name); /* node keeps name's memory */
ab5ffac0 379+ node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */
6a189d36 380 return node->id2;
9405aad3
WD
381 }
382
ab5ffac0 383@@ -336,7 +345,7 @@ gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
85096e5e
WD
384 free(name);
385 name = NULL;
386 }
6a189d36 387- node = recv_add_gid(gid, name); /* node keeps name's memory */
ab5ffac0 388+ node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */
6a189d36
WD
389 if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
390 *flags_ptr |= FLAG_SKIP_GROUP;
391 return node->id2;
ab5ffac0 392@@ -363,17 +372,103 @@ void recv_id_list(int f, struct file_list *flist)
4122278d 393
409bd73e
WD
394 /* Now convert all the uids/gids from sender values to our values. */
395 #ifdef SUPPORT_ACLS
396- if (preserve_acls && !numeric_ids)
6a189d36 397+ if (preserve_acls && (!numeric_ids || usermap || groupmap))
409bd73e
WD
398 match_acl_ids();
399 #endif
400- if (am_root && preserve_uid && !numeric_ids) {
401+ if (am_root && preserve_uid && (!numeric_ids || usermap)) {
9c85142a 402 for (i = 0; i < flist->used; i++)
6a189d36 403 F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
409bd73e
WD
404 }
405- if (preserve_gid && (!am_root || !numeric_ids)) {
406+ if (preserve_gid && (!am_root || !numeric_ids || groupmap)) {
9c85142a 407 for (i = 0; i < flist->used; i++) {
6a189d36
WD
408 F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
409 &flist->files[i]->flags);
410 }
4122278d
WD
411 }
412 }
413+
414+void parse_name_map(char *map, int usernames)
415+{
9405aad3
WD
416+ struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap;
417+ struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist;
ab5ffac0
WD
418+ char *colon, *end, *name, *cp = map + strlen(map);
419+ id_t id1;
6a189d36 420+ uint16 flags;
4122278d 421+
ab5ffac0 422+ /* Parse the list in reverse, so the order in the struct is right. */
4122278d
WD
423+ while (1) {
424+ end = cp;
425+ while (cp > map && cp[-1] != ',') cp--;
426+ if (!(colon = strchr(cp, ':'))) {
427+ rprintf(FERROR, "No colon found in --%smap: %s\n",
428+ usernames ? "user" : "group", cp);
429+ exit_cleanup(RERR_SYNTAX);
430+ }
ab5ffac0
WD
431+ if (!colon[1]) {
432+ rprintf(FERROR, "No name found after colon --%smap: %s\n",
433+ usernames ? "user" : "group", cp);
434+ exit_cleanup(RERR_SYNTAX);
435+ }
4122278d
WD
436+ *colon = '\0';
437+
438+ if (isDigit(cp)) {
ab5ffac0
WD
439+ char *dash = strchr(cp, '-');
440+ if (strspn(cp, "0123456789-") != (size_t)(colon - cp)
441+ || (dash && (!dash[1] || strchr(dash+1, '-')))) {
4122278d
WD
442+ bad_number:
443+ rprintf(FERROR, "Invalid number in --%smap: %s\n",
444+ usernames ? "user" : "group", cp);
445+ exit_cleanup(RERR_SYNTAX);
446+ }
ab5ffac0
WD
447+ if (dash)
448+ name = (char *)atol(dash+1);
449+ else
450+ name = (char *)0;
6a189d36 451+ flags = 0;
ab5ffac0 452+ id1 = atol(cp);
6a189d36
WD
453+ } else if (strpbrk(cp, "*[?")) {
454+ flags = NFLAGS_WILD_NAME_MATCH;
ab5ffac0 455+ name = cp;
6a189d36
WD
456+ id1 = 0;
457+ } else {
458+ flags = NFLAGS_NAME_MATCH;
ab5ffac0 459+ name = cp;
6a189d36
WD
460+ id1 = 0;
461+ }
4122278d
WD
462+
463+ if (isDigit(colon+1)) {
464+ if (strspn(colon+1, "0123456789") != (size_t)(end - colon - 1)) {
465+ cp = colon+1;
466+ goto bad_number;
467+ }
ab5ffac0
WD
468+ add_to_list(idmap_ptr, id1, name, atol(colon+1), flags);
469+ } else if (usernames) {
470+ uid_t uid;
471+ if (name_to_uid(colon+1, &uid))
472+ add_to_list(idmap_ptr, id1, name, uid, flags);
473+ else {
474+ rprintf(FERROR,
475+ "Unknown --usermap name on receiver: %s\n",
476+ colon+1);
477+ }
4122278d 478+ } else {
ab5ffac0
WD
479+ gid_t gid;
480+ if (name_to_gid(colon+1, &gid))
481+ add_to_list(idmap_ptr, id1, name, gid, flags);
482+ else {
483+ rprintf(FERROR,
484+ "Unknown --groupmap name on receiver: %s\n",
485+ colon+1);
4122278d
WD
486+ }
487+ }
488+
4122278d
WD
489+ if (cp == map)
490+ break;
491+
492+ *--cp = '\0'; /* replace comma */
493+ }
409bd73e 494+
85096e5e 495+ /* The 0 user/group doesn't get its name sent, so add it explicitly. */
ab5ffac0 496+ recv_add_id(idlist_ptr, *idmap_ptr, 0,
85096e5e 497+ numeric_ids ? NULL : usernames ? uid_to_name(0) : gid_to_name(0));
4122278d 498+}