xref: /dragonfly/bin/cpdup/hcproto.c (revision 335b9e93)
1 /*
2  * HCPROTO.C
3  *
4  * This module implements a simple remote control protocol
5  *
6  * $DragonFly: src/bin/cpdup/hcproto.c,v 1.8 2008/11/11 04:36:00 dillon Exp $
7  */
8 
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
12 
13 static int hc_decode_stat(hctransaction_t trans, struct stat *, struct HCHead *);
14 static int hc_decode_stat_item(struct stat *st, struct HCLeaf *item);
15 static int rc_encode_stat(hctransaction_t trans, struct stat *);
16 
17 static int rc_hello(hctransaction_t trans, struct HCHead *);
18 static int rc_stat(hctransaction_t trans, struct HCHead *);
19 static int rc_lstat(hctransaction_t trans, struct HCHead *);
20 static int rc_opendir(hctransaction_t trans, struct HCHead *);
21 static int rc_readdir(hctransaction_t trans, struct HCHead *);
22 static int rc_closedir(hctransaction_t trans, struct HCHead *);
23 static int rc_scandir(hctransaction_t trans, struct HCHead *);
24 static int rc_open(hctransaction_t trans, struct HCHead *);
25 static int rc_close(hctransaction_t trans, struct HCHead *);
26 static int rc_read(hctransaction_t trans, struct HCHead *);
27 static int rc_readfile(hctransaction_t trans, struct HCHead *);
28 static int rc_write(hctransaction_t trans, struct HCHead *);
29 static int rc_remove(hctransaction_t trans, struct HCHead *);
30 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
31 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
32 static int rc_chown(hctransaction_t trans, struct HCHead *);
33 static int rc_lchown(hctransaction_t trans, struct HCHead *);
34 static int rc_chmod(hctransaction_t trans, struct HCHead *);
35 static int rc_mknod(hctransaction_t trans, struct HCHead *);
36 static int rc_link(hctransaction_t trans, struct HCHead *);
37 #ifdef _ST_FLAGS_PRESENT_
38 static int rc_chflags(hctransaction_t trans, struct HCHead *);
39 #endif
40 static int rc_readlink(hctransaction_t trans, struct HCHead *);
41 static int rc_umask(hctransaction_t trans, struct HCHead *);
42 static int rc_symlink(hctransaction_t trans, struct HCHead *);
43 static int rc_rename(hctransaction_t trans, struct HCHead *);
44 static int rc_utimes(hctransaction_t trans, struct HCHead *);
45 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
46 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
47 
48 static int getmygroups(gid_t **gidlist);
49 
50 static int silentwarning(int *, const char *, ...) __printflike(2, 3);
51 
52 static struct HCDesc HCDispatchTable[] = {
53     { HC_HELLO,		rc_hello },
54     { HC_STAT,		rc_stat },
55     { HC_LSTAT,		rc_lstat },
56     { HC_OPENDIR,	rc_opendir },
57     { HC_READDIR,	rc_readdir },
58     { HC_CLOSEDIR,	rc_closedir },
59     { HC_OPEN,		rc_open },
60     { HC_CLOSE,		rc_close },
61     { HC_READ,		rc_read },
62     { HC_WRITE,		rc_write },
63     { HC_REMOVE,	rc_remove },
64     { HC_MKDIR,		rc_mkdir },
65     { HC_RMDIR,		rc_rmdir },
66     { HC_CHOWN,		rc_chown },
67     { HC_LCHOWN,	rc_lchown },
68     { HC_CHMOD,		rc_chmod },
69     { HC_MKNOD,		rc_mknod },
70     { HC_LINK,		rc_link },
71 #ifdef _ST_FLAGS_PRESENT_
72     { HC_CHFLAGS,	rc_chflags },
73 #endif
74     { HC_READLINK,	rc_readlink },
75     { HC_UMASK,		rc_umask },
76     { HC_SYMLINK,	rc_symlink },
77     { HC_RENAME,	rc_rename },
78     { HC_UTIMES,	rc_utimes },
79     { HC_GETEUID,	rc_geteuid },
80     { HC_GETGROUPS,	rc_getgroups },
81     { HC_SCANDIR,	rc_scandir },
82     { HC_READFILE,	rc_readfile },
83 };
84 
85 static int chown_warning;
86 #ifdef _ST_FLAGS_PRESENT_
87 static int chflags_warning;
88 #endif
89 
90 /*
91  * If not running as root generate a silent warning and return no error.
92  *
93  * If running as root return an error.
94  */
95 static int
96 silentwarning(int *didwarn, const char *ctl, ...)
97 {
98     va_list va;
99 
100     if (DstRootPrivs)
101 	return(-1);
102     if (*didwarn == 0 && QuietOpt == 0) {
103 	*didwarn = 1;
104 	fprintf(stderr, "WARNING: Not running as root, ");
105 	va_start(va, ctl);
106 	vfprintf(stderr, ctl, va);
107 	va_end(va);
108     }
109     return(0);
110 }
111 
112 int
113 hc_connect(struct HostConf *hc, int readonly)
114 {
115     if (hcc_connect(hc, readonly) < 0) {
116 	fprintf(stderr, "Unable to connect to %s\n", hc->host);
117 	return(-1);
118     }
119     return(hc_hello(hc));
120 }
121 
122 void
123 hc_slave(int fdin, int fdout)
124 {
125     hcc_slave(fdin, fdout, HCDispatchTable,
126 	      sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
127 }
128 
129 /*
130  * A HELLO RPC is sent on the initial connect.
131  */
132 int
133 hc_hello(struct HostConf *hc)
134 {
135     struct HCHead *head;
136     struct HCLeaf *item;
137     hctransaction_t trans;
138     char hostbuf[256];
139     int error;
140 
141     bzero(hostbuf, sizeof(hostbuf));
142     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
143 	return(-1);
144     if (hostbuf[0] == 0)
145 	hostbuf[0] = '?';
146 
147     trans = hcc_start_command(hc, HC_HELLO);
148     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
149     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
150     if (UseCpFile)
151 	hcc_leaf_string(trans, LC_PATH1, UseCpFile);
152     if ((head = hcc_finish_command(trans)) == NULL) {
153 	fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
154 		hc->host);
155 	return(-1);
156     }
157 
158     if (head->error) {
159 	fprintf(stderr, "Connected to %s but remote returned error %d\n",
160 		hc->host, head->error);
161 	return(-1);
162     }
163 
164     error = -1;
165     FOR_EACH_ITEM(item, trans, head) {
166 	switch(item->leafid) {
167 	case LC_HELLOSTR:
168 	    if (QuietOpt == 0)
169 		fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
170 	    error = 0;
171 	    break;
172 	case LC_VERSION:
173 	    hc->version = HCC_INT32(item);
174 	    break;
175 	}
176     }
177     if (hc->version < HCPROTO_VERSION_COMPAT) {
178 	fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
179 		hc->host);
180 	error = -1;
181     } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
182 	fprintf(stderr,
183 		"WARNING: Remote cpdup at %s has a lower version,\n"
184 		"expect reduced speed and/or functionality\n", hc->host);
185     }
186     if (error < 0)
187 	fprintf(stderr, "Handshake failed with %s\n", hc->host);
188     return (error);
189 }
190 
191 static int
192 rc_hello(hctransaction_t trans, struct HCHead *head)
193 {
194     struct HCLeaf *item;
195     char hostbuf[256];
196 
197     FOR_EACH_ITEM(item, trans, head) {
198 	if (item->leafid == LC_PATH1)
199 	    UseCpFile = strdup(HCC_STRING(item));
200     }
201 
202     bzero(hostbuf, sizeof(hostbuf));
203     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
204 	return(-1);
205     if (hostbuf[0] == 0)
206 	hostbuf[0] = '?';
207 
208     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
209     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
210     return(0);
211 }
212 
213 /*
214  * STAT, LSTAT
215  */
216 int
217 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
218 {
219     struct HCHead *head;
220     hctransaction_t trans;
221 
222     if (hc == NULL || hc->host == NULL)
223 	return(stat(path, st));
224 
225     trans = hcc_start_command(hc, HC_STAT);
226     hcc_leaf_string(trans, LC_PATH1, path);
227     if ((head = hcc_finish_command(trans)) == NULL)
228 	return(-1);
229     if (head->error)
230 	return(-1);
231     return(hc_decode_stat(trans, st, head));
232 }
233 
234 int
235 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
236 {
237     struct HCHead *head;
238     hctransaction_t trans;
239 
240     if (hc == NULL || hc->host == NULL)
241 	return(lstat(path, st));
242 
243     trans = hcc_start_command(hc, HC_LSTAT);
244     hcc_leaf_string(trans, LC_PATH1, path);
245     if ((head = hcc_finish_command(trans)) == NULL)
246 	return(-1);
247     if (head->error)
248 	return(-1);
249     return(hc_decode_stat(trans, st, head));
250 }
251 
252 static int
253 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
254 {
255     struct HCLeaf *item;
256 
257     bzero(st, sizeof(*st));
258     FOR_EACH_ITEM(item, trans, head)
259 	hc_decode_stat_item(st, item);
260     return(0);
261 }
262 
263 static int
264 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
265 {
266     switch(item->leafid) {
267     case LC_DEV:
268 	st->st_dev = HCC_INT32(item);
269 	break;
270     case LC_INO:
271 	st->st_ino = HCC_INT64(item);
272 	break;
273     case LC_MODE:
274 	st->st_mode = HCC_INT32(item);
275 	break;
276     case LC_NLINK:
277 	st->st_nlink = HCC_INT32(item);
278 	break;
279     case LC_UID:
280 	st->st_uid = HCC_INT32(item);
281 	break;
282     case LC_GID:
283 	st->st_gid = HCC_INT32(item);
284 	break;
285     case LC_RDEV:
286 	st->st_rdev = HCC_INT32(item);
287 	break;
288     case LC_ATIME:
289 	st->st_atime = (time_t)HCC_INT64(item);
290 	break;
291     case LC_MTIME:
292 	st->st_mtime = (time_t)HCC_INT64(item);
293 	break;
294     case LC_CTIME:
295 	st->st_ctime = (time_t)HCC_INT64(item);
296 	break;
297 #if defined(st_atime)  /* A macro, so very likely on modern POSIX */
298     case LC_ATIMENSEC:
299 	st->st_atim.tv_nsec = HCC_INT32(item);
300 	break;
301     case LC_MTIMENSEC:
302 	st->st_mtim.tv_nsec = HCC_INT32(item);
303 	break;
304     case LC_CTIMENSEC:
305 	st->st_ctim.tv_nsec = HCC_INT32(item);
306 	break;
307 #endif
308     case LC_FILESIZE:
309 	st->st_size = HCC_INT64(item);
310 	break;
311     case LC_FILEBLKS:
312 	st->st_blocks = HCC_INT64(item);
313 	break;
314     case LC_BLKSIZE:
315 	st->st_blksize = HCC_INT32(item);
316 	break;
317 #ifdef _ST_FSMID_PRESENT_
318     case LC_FSMID:
319 	st->st_fsmid = HCC_INT64(item);
320 	break;
321 #endif
322 #ifdef _ST_FLAGS_PRESENT_
323     case LC_FILEFLAGS:
324 	st->st_flags = (uint32_t)HCC_INT64(item);
325 	break;
326 #endif
327     }
328     return(0);
329 }
330 
331 static int
332 rc_stat(hctransaction_t trans, struct HCHead *head)
333 {
334     struct HCLeaf *item;
335     struct stat st;
336     const char *path = NULL;
337 
338     FOR_EACH_ITEM(item, trans, head) {
339 	if (item->leafid == LC_PATH1)
340 	    path = HCC_STRING(item);
341     }
342     if (path == NULL)
343 	return(-2);
344     if (stat(path, &st) < 0)
345 	return(-1);
346     return (rc_encode_stat(trans, &st));
347 }
348 
349 static int
350 rc_lstat(hctransaction_t trans, struct HCHead *head)
351 {
352     struct HCLeaf *item;
353     struct stat st;
354     const char *path = NULL;
355 
356     FOR_EACH_ITEM(item, trans, head) {
357 	if (item->leafid == LC_PATH1)
358 	    path = HCC_STRING(item);
359     }
360     if (path == NULL)
361 	return(-2);
362     if (lstat(path, &st) < 0)
363 	return(-1);
364     return (rc_encode_stat(trans, &st));
365 }
366 
367 /*
368  * Encode all entries of a stat structure.
369  *
370  * CAUTION:  If you add any more entries here, be sure to
371  *           increase the STAT_MAX_NUM_ENTRIES value!
372  */
373 #define STAT_MAX_NUM_ENTRIES 18
374 static int
375 rc_encode_stat(hctransaction_t trans, struct stat *st)
376 {
377     hcc_leaf_int32(trans, LC_DEV, st->st_dev);
378     hcc_leaf_int64(trans, LC_INO, st->st_ino);
379     hcc_leaf_int32(trans, LC_MODE, st->st_mode);
380     hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
381     hcc_leaf_int32(trans, LC_UID, st->st_uid);
382     hcc_leaf_int32(trans, LC_GID, st->st_gid);
383     hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
384     hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
385     hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
386     hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
387 #if defined(st_atime)
388     hcc_leaf_int32(trans, LC_ATIMENSEC, st->st_atim.tv_nsec);
389     hcc_leaf_int32(trans, LC_MTIMENSEC, st->st_mtim.tv_nsec);
390     hcc_leaf_int32(trans, LC_CTIMENSEC, st->st_ctim.tv_nsec);
391 #endif
392     hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
393     hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
394     hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
395 #ifdef _ST_FSMID_PRESENT_
396     hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
397 #endif
398 #ifdef _ST_FLAGS_PRESENT_
399     hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
400 #endif
401     return(0);
402 }
403 
404 /*
405  * OPENDIR
406  */
407 DIR *
408 hc_opendir(struct HostConf *hc, const char *path)
409 {
410     hctransaction_t trans;
411     struct HCHead *head;
412 
413     if (hc == NULL || hc->host == NULL)
414 	return(opendir(path));
415 
416     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
417 	struct HCLeaf *item;
418 	struct HCDirEntry *den;
419 	intptr_t desc = 0;
420 
421 	trans = hcc_start_command(hc, HC_OPENDIR);
422 	hcc_leaf_string(trans, LC_PATH1, path);
423 	if ((head = hcc_finish_command(trans)) == NULL)
424 	    return (NULL);
425 	if (head->error)
426 	    return (NULL);
427 	FOR_EACH_ITEM(item, trans, head) {
428 	    if (item->leafid == LC_DESCRIPTOR)
429 		desc = HCC_INT32(item);
430 	}
431 	if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
432 	    fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
433 		(intmax_t)desc);
434 	    return (NULL);
435 	}
436 	den = malloc(sizeof(*den));
437 	hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
438 	return ((void *)desc);
439     }
440 
441     /* hc->version >= 4: use HC_SCANDIR */
442     trans = hcc_start_command(hc, HC_SCANDIR);
443     hcc_leaf_string(trans, LC_PATH1, path);
444     if ((head = hcc_finish_command(trans)) == NULL || head->error)
445 	return (NULL);
446     return ((void *)head);
447 }
448 
449 static int
450 rc_opendir(hctransaction_t trans, struct HCHead *head)
451 {
452     struct HCLeaf *item;
453     const char *path = NULL;
454     DIR *dir;
455     int desc;
456 
457     FOR_EACH_ITEM(item, trans, head) {
458 	if (item->leafid == LC_PATH1)
459 	    path = HCC_STRING(item);
460     }
461     if (path == NULL)
462 	return(-2);
463     if ((dir = opendir(path)) == NULL) {
464 	head->error = errno;
465     } else {
466 	desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
467 	hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
468     }
469     return(0);
470 }
471 
472 /*
473  * READDIR
474  */
475 struct HCDirEntry *
476 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
477 {
478     int stat_ok = 0;
479     struct HCHead *head;
480     struct HCLeaf *item;
481     static struct HCDirEntry denbuf;
482 
483     *statpp = NULL;
484     if (hc == NULL || hc->host == NULL) {
485 	struct dirent *sysden;
486 
487 	if ((sysden = readdir(dir)) == NULL)
488 	    return (NULL);
489 	strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
490 	return (&denbuf);
491     }
492 
493     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
494 	hctransaction_t trans;
495 	struct HCDirEntry *den;
496 
497 	trans = hcc_start_command(hc, HC_READDIR);
498 	hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
499 	if ((head = hcc_finish_command(trans)) == NULL)
500 	    return (NULL);
501 	if (head->error)
502 	    return (NULL);	/* XXX errno */
503 	den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
504 	if (den == NULL)
505 	    return (NULL);	/* XXX errno */
506 	den->d_name[0] = 0;
507 	FOR_EACH_ITEM(item, trans, head) {
508 	    if (item->leafid == LC_PATH1)
509 		strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
510 	}
511 	return (den->d_name[0] ? den : NULL);
512     }
513 
514     /* hc->version >= 4: using HC_SCANDIR */
515     denbuf.d_name[0] = 0;
516     head = (void *)dir;
517     *statpp = malloc(sizeof(struct stat));
518     bzero(*statpp, sizeof(struct stat));
519     while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
520 	if (item->leafid == LC_PATH1) {  /* this must be the last item */
521 	    strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
522 	    break;
523 	} else {
524 	    stat_ok = 1;
525 	    hc_decode_stat_item(*statpp, item);
526 	}
527     }
528     if (!stat_ok) {
529 	free(*statpp);
530 	*statpp = NULL;
531     }
532     if (hc->trans.state == HCT_FAIL)
533 	return NULL;
534     return (denbuf.d_name[0] ? &denbuf : NULL);
535 }
536 
537 static int
538 rc_readdir(hctransaction_t trans, struct HCHead *head)
539 {
540     struct HCLeaf *item;
541     struct dirent *den;
542     DIR *dir = NULL;
543 
544     FOR_EACH_ITEM(item, trans, head) {
545 	if (item->leafid == LC_DESCRIPTOR)
546 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
547     }
548     if (dir == NULL)
549 	return(-2);
550     if ((den = readdir(dir)) != NULL)
551 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
552     return(0);
553 }
554 
555 /*
556  * CLOSEDIR
557  *
558  * XXX cpdup needs to check error code to avoid truncated dirs?
559  */
560 int
561 hc_closedir(struct HostConf *hc, DIR *dir)
562 {
563     struct HCHead *head;
564 
565     if (hc == NULL || hc->host == NULL)
566 	return(closedir(dir));
567 
568     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
569 	hctransaction_t trans;
570 	struct dirent *den;
571 
572 	if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
573 	    free(den);
574 	    hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
575 	    trans = hcc_start_command(hc, HC_CLOSEDIR);
576 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
577 	    if ((head = hcc_finish_command(trans)) == NULL)
578 		return (-1);
579 	    if (head->error)
580 		return (-1);		/* XXX errno */
581 	    return (0);
582 	} else {
583 	    /* errno */
584 	    return(-1);
585 	}
586     }
587 
588     /* hc->version >= 4: using HC_SCANDIR */
589     head = (void *)dir;
590     /* skip any remaining items if the directory is closed prematurely */
591     while (hcc_nextchaineditem(hc, head) != NULL)
592 	/*nothing*/ ;
593     if (hc->trans.state == HCT_FAIL || head->error)
594 	return (-1);
595     return (0);
596 }
597 
598 static int
599 rc_closedir(hctransaction_t trans, struct HCHead *head)
600 {
601     struct HCLeaf *item;
602     DIR *dir = NULL;
603 
604     FOR_EACH_ITEM(item, trans, head) {
605 	if (item->leafid == LC_DESCRIPTOR) {
606 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
607 	    if (dir != NULL) {
608 		    hcc_set_descriptor(trans->hc, HCC_INT32(item),
609 				       NULL, HC_DESC_DIR);
610 	    }
611 	}
612     }
613     if (dir == NULL)
614 	return(-2);
615     return(closedir(dir));
616 }
617 
618 /*
619  * SCANDIR
620  */
621 static int
622 rc_scandir(hctransaction_t trans, struct HCHead *head)
623 {
624     struct HCLeaf *item;
625     const char *path = NULL;
626     struct dirent *den;
627     DIR *dir;
628     char *fpath;
629     struct stat st;
630 
631     FOR_EACH_ITEM(item, trans, head) {
632 	if (item->leafid == LC_PATH1)
633 	    path = HCC_STRING(item);
634     }
635     if (path == NULL)
636 	return (-2);
637     if ((dir = opendir(path)) == NULL)
638 	return (-1);
639     while ((den = readdir(dir)) != NULL) {
640 	if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
641 		(den->d_name[1] == '.' && den->d_name[2] == '\0')))
642 	    continue;	/* skip "." and ".." */
643 	/*
644 	 * Check if there's enough space left in the current packet.
645 	 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
646 	 * one is a string, so we use strlen() + 1 (terminating zero).
647 	 * The remaining ones are numbers; we assume sizeof(int64_t) so
648 	 * we're on the safe side.
649 	 */
650 	if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
651 		(STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
652 		strlen(den->d_name) + 1)) {
653 	    closedir(dir);
654 	    return (-1);
655 	}
656 	fpath = mprintf("%s/%s", path, den->d_name);
657 	if (lstat(fpath, &st) == 0)
658 	    rc_encode_stat(trans, &st);
659 	/* The name must be the last item! */
660 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
661 	free(fpath);
662     }
663     return (closedir(dir));
664 }
665 
666 /*
667  * OPEN
668  */
669 int
670 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
671 {
672     hctransaction_t trans;
673     struct HCHead *head;
674     struct HCLeaf *item;
675     int *fdp;
676     int desc = 0;
677     int nflags;
678 
679     if (NotForRealOpt && (flags & O_CREAT))
680 	return(0x7FFFFFFF);
681 
682     if (hc == NULL || hc->host == NULL) {
683 #ifdef O_LARGEFILE
684 	flags |= O_LARGEFILE;
685 #endif
686 	return(open(path, flags, mode));
687     }
688 
689     if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
690 	trans = hcc_start_command(hc, HC_READFILE);
691 	hcc_leaf_string(trans, LC_PATH1, path);
692 	if ((head = hcc_finish_command(trans)) == NULL || head->error)
693 	    return (-1);
694 	head->magic = 0; /* used to indicate offset within buffer */
695 	return (1); /* dummy */
696     }
697 
698     nflags = flags & XO_NATIVEMASK;
699     if (flags & O_CREAT)
700 	nflags |= XO_CREAT;
701     if (flags & O_EXCL)
702 	nflags |= XO_EXCL;
703     if (flags & O_TRUNC)
704 	nflags |= XO_TRUNC;
705 
706     trans = hcc_start_command(hc, HC_OPEN);
707     hcc_leaf_string(trans, LC_PATH1, path);
708     hcc_leaf_int32(trans, LC_OFLAGS, nflags);
709     hcc_leaf_int32(trans, LC_MODE, mode);
710 
711     if ((head = hcc_finish_command(trans)) == NULL)
712 	return(-1);
713     if (head->error)
714 	return(-1);
715     FOR_EACH_ITEM(item, trans, head) {
716 	if (item->leafid == LC_DESCRIPTOR)
717 	    desc = HCC_INT32(item);
718     }
719     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
720 	fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
721 		desc);
722 	return(-1);
723     }
724     fdp = malloc(sizeof(int));
725     *fdp = desc;	/* really just a dummy */
726     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
727     return(desc);
728 }
729 
730 static int
731 rc_open(hctransaction_t trans, struct HCHead *head)
732 {
733     struct HCLeaf *item;
734     const char *path = NULL;
735     int nflags = 0;
736     int flags;
737     mode_t mode = 0666;
738     int desc;
739     int *fdp;
740     int fd;
741 
742     FOR_EACH_ITEM(item, trans, head) {
743 	switch(item->leafid) {
744 	case LC_PATH1:
745 	    path = HCC_STRING(item);
746 	    break;
747 	case LC_OFLAGS:
748 	    nflags = HCC_INT32(item);
749 	    break;
750 	case LC_MODE:
751 	    mode = HCC_INT32(item);
752 	    break;
753 	}
754     }
755     if (path == NULL)
756 	return(-2);
757 
758     flags = nflags & XO_NATIVEMASK;
759     if (nflags & XO_CREAT)
760 	flags |= O_CREAT;
761     if (nflags & XO_EXCL)
762 	flags |= O_EXCL;
763     if (nflags & XO_TRUNC)
764 	flags |= O_TRUNC;
765 
766     if (ReadOnlyOpt) {
767 	if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
768 	    head->error = EACCES;
769 	    return (0);
770 	}
771 	flags |= O_RDONLY;
772     }
773 
774 #ifdef O_LARGEFILE
775     flags |= O_LARGEFILE;
776 #endif
777     if ((fd = open(path, flags, mode)) < 0)
778 	return(-1);
779     fdp = malloc(sizeof(int));
780     *fdp = fd;
781     desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
782     hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
783     return(0);
784 }
785 
786 /*
787  * CLOSE
788  */
789 int
790 hc_close(struct HostConf *hc, int fd)
791 {
792     hctransaction_t trans;
793     struct HCHead *head;
794     int *fdp;
795 
796     if (NotForRealOpt && fd == 0x7FFFFFFF)
797 	return(0);
798     if (hc == NULL || hc->host == NULL)
799 	return(close(fd));
800 
801     if (fd == 1 && hc->version >= 4) {	/* using HC_READFILE */
802 	head = (void *)hc->trans.rbuf;
803 	/* skip any remaining items if the file is closed prematurely */
804 	while (hcc_nextchaineditem(hc, head) != NULL)
805 	    /*nothing*/ ;
806 	if (hc->trans.state == HCT_FAIL || head->error)
807 	    return (-1);
808 	return (0);
809     }
810 
811     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
812     if (fdp) {
813 	free(fdp);
814 	hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
815 
816 	trans = hcc_start_command(hc, HC_CLOSE);
817 	hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
818 	if ((head = hcc_finish_command(trans)) == NULL)
819 	    return(-1);
820 	if (head->error)
821 	    return(-1);
822 	return(0);
823     } else {
824 	return(-1);
825     }
826 }
827 
828 static int
829 rc_close(hctransaction_t trans, struct HCHead *head)
830 {
831     struct HCLeaf *item;
832     int *fdp = NULL;
833     int fd;
834     int desc = -1;
835 
836     FOR_EACH_ITEM(item, trans, head) {
837 	if (item->leafid == LC_DESCRIPTOR)
838 	    desc = HCC_INT32(item);
839     }
840     if (desc < 0)
841 	return(-2);
842     if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
843 	return(-2);
844     fd = *fdp;
845     free(fdp);
846     hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
847     return(close(fd));
848 }
849 
850 static int
851 getiolimit(void)
852 {
853     return(32768);
854 }
855 
856 /*
857  * READ
858  */
859 ssize_t
860 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
861 {
862     hctransaction_t trans;
863     struct HCHead *head;
864     struct HCLeaf *item;
865     int *fdp;
866     int offset;
867     int r = 0;
868     int x = 0;
869 
870     if (hc == NULL || hc->host == NULL)
871 	return(read(fd, buf, bytes));
872 
873     if (fd == 1 && hc->version >= 4) {	/* using HC_READFILE */
874 	head = (void *)hc->trans.rbuf;
875 	while (bytes) {
876 	    if ((offset = head->magic) != 0) {
877 		item = hcc_currentchaineditem(hc, head);
878 	    } else {
879 		item = hcc_nextchaineditem(hc, head);
880 	    }
881 	    if (item == NULL) {
882 		if (hc->trans.state == HCT_FAIL)
883 			r = -1;
884 		return (r);
885 	    }
886 	    if (item->leafid != LC_DATA)
887 		return (-1);
888 	    x = item->bytes - sizeof(*item) - offset;
889 	    if (x > (int)bytes) {
890 		x = (int)bytes;
891 		head->magic += x;  /* leave bytes in the buffer */
892 	    }
893 	    else
894 		head->magic = 0;  /* all bytes used up */
895 	    bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
896 	    buf = (char *)buf + x;
897 	    bytes -= (size_t)x;
898 	    r += x;
899 	}
900 	return (r);
901     }
902 
903     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
904     if (fdp) {
905 	while (bytes) {
906 	    size_t limit = getiolimit();
907 	    int n = (bytes > limit) ? limit : bytes;
908 
909 	    trans = hcc_start_command(hc, HC_READ);
910 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
911 	    hcc_leaf_int32(trans, LC_BYTES, n);
912 	    if ((head = hcc_finish_command(trans)) == NULL)
913 		return(-1);
914 	    if (head->error)
915 		return(-1);
916 	    FOR_EACH_ITEM(item, trans, head) {
917 		if (item->leafid == LC_DATA) {
918 		    x = item->bytes - sizeof(*item);
919 		    if (x > (int)bytes)
920 			x = (int)bytes;
921 		    bcopy(HCC_BINARYDATA(item), buf, x);
922 		    buf = (char *)buf + x;
923 		    bytes -= (size_t)x;
924 		    r += x;
925 		}
926 	    }
927 	    if (x < n)
928 		break;
929 	}
930 	return(r);
931     } else {
932 	return(-1);
933     }
934 }
935 
936 static int
937 rc_read(hctransaction_t trans, struct HCHead *head)
938 {
939     struct HCLeaf *item;
940     int *fdp = NULL;
941     char buf[32768];
942     int bytes = -1;
943     int n;
944 
945     FOR_EACH_ITEM(item, trans, head) {
946 	switch(item->leafid) {
947 	case LC_DESCRIPTOR:
948 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
949 	    break;
950 	case LC_BYTES:
951 	    bytes = HCC_INT32(item);
952 	    break;
953 	}
954     }
955     if (fdp == NULL)
956 	return(-2);
957     if (bytes < 0 || bytes > 32768)
958 	return(-2);
959     n = read(*fdp, buf, bytes);
960     if (n < 0)
961 	return(-1);
962     hcc_leaf_data(trans, LC_DATA, buf, n);
963     return(0);
964 }
965 
966 /*
967  * READFILE
968  */
969 static int
970 rc_readfile(hctransaction_t trans, struct HCHead *head)
971 {
972     struct HCLeaf *item;
973     const char *path = NULL;
974     char buf[32768];
975     int n;
976     int fd;
977 
978     FOR_EACH_ITEM(item, trans, head) {
979 	if (item->leafid == LC_PATH1)
980 	    path = HCC_STRING(item);
981     }
982     if (path == NULL)
983 	return (-2);
984     if ((fd = open(path, O_RDONLY)) < 0)
985 	return(-1);
986     while ((n = read(fd, buf, 32768)) >= 0) {
987 	if (!hcc_check_space(trans, head, 1, n)) {
988 	    close(fd);
989 	    return (-1);
990 	}
991 	hcc_leaf_data(trans, LC_DATA, buf, n);
992 	if (n == 0)
993 		break;
994     }
995     if (n < 0) {
996 	close(fd);
997 	return (-1);
998     }
999     return (close(fd));
1000 }
1001 
1002 /*
1003  * WRITE
1004  */
1005 ssize_t
1006 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
1007 {
1008     hctransaction_t trans;
1009     struct HCHead *head;
1010     struct HCLeaf *item;
1011     int *fdp;
1012     int r;
1013 
1014     if (NotForRealOpt)
1015 	return(bytes);
1016 
1017     if (hc == NULL || hc->host == NULL)
1018 	return(write(fd, buf, bytes));
1019 
1020     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1021     if (fdp) {
1022 	r = 0;
1023 	while (bytes) {
1024 	    size_t limit = getiolimit();
1025 	    int n = (bytes > limit) ? limit : bytes;
1026 	    int x = 0;
1027 
1028 	    trans = hcc_start_command(hc, HC_WRITE);
1029 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1030 	    hcc_leaf_data(trans, LC_DATA, buf, n);
1031 	    if ((head = hcc_finish_command(trans)) == NULL)
1032 		return(-1);
1033 	    if (head->error)
1034 		return(-1);
1035 	    FOR_EACH_ITEM(item, trans, head) {
1036 		if (item->leafid == LC_BYTES)
1037 		    x = HCC_INT32(item);
1038 	    }
1039 	    if (x < 0 || x > n)
1040 		return(-1);
1041 	    r += x;
1042 	    buf = (const char *)buf + x;
1043 	    bytes -= x;
1044 	    if (x < n)
1045 		break;
1046 	}
1047 	return(r);
1048     } else {
1049 	return(-1);
1050     }
1051 }
1052 
1053 static int
1054 rc_write(hctransaction_t trans, struct HCHead *head)
1055 {
1056     struct HCLeaf *item;
1057     int *fdp = NULL;
1058     void *buf = NULL;
1059     int n = -1;
1060 
1061     FOR_EACH_ITEM(item, trans, head) {
1062 	switch(item->leafid) {
1063 	case LC_DESCRIPTOR:
1064 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1065 	    break;
1066 	case LC_DATA:
1067 	    buf = HCC_BINARYDATA(item);
1068 	    n = item->bytes - sizeof(*item);
1069 	    break;
1070 	}
1071     }
1072     if (ReadOnlyOpt) {
1073 	head->error = EACCES;
1074 	return (0);
1075     }
1076     if (fdp == NULL)
1077 	return(-2);
1078     if (n < 0 || n > 32768)
1079 	return(-2);
1080     n = write(*fdp, buf, n);
1081     if (n < 0)
1082 	return (-1);
1083     hcc_leaf_int32(trans, LC_BYTES, n);
1084     return(0);
1085 }
1086 
1087 /*
1088  * REMOVE
1089  *
1090  * NOTE: This function returns -errno if an error occured.
1091  */
1092 int
1093 hc_remove(struct HostConf *hc, const char *path)
1094 {
1095     hctransaction_t trans;
1096     struct HCHead *head;
1097     int res;
1098 
1099     if (NotForRealOpt)
1100 	return(0);
1101     if (hc == NULL || hc->host == NULL) {
1102 	res = remove(path);
1103 	if (res < 0)
1104 		res = -errno;
1105 	return(res);
1106     }
1107 
1108     trans = hcc_start_command(hc, HC_REMOVE);
1109     hcc_leaf_string(trans, LC_PATH1, path);
1110     if ((head = hcc_finish_command(trans)) == NULL)
1111 	return(-EIO);
1112     if (head->error)
1113 	return(-(int)head->error);
1114     return(0);
1115 }
1116 
1117 static int
1118 rc_remove(hctransaction_t trans, struct HCHead *head)
1119 {
1120     struct HCLeaf *item;
1121     const char *path = NULL;
1122 
1123     FOR_EACH_ITEM(item, trans, head) {
1124 	if (item->leafid == LC_PATH1)
1125 	    path = HCC_STRING(item);
1126     }
1127     if (path == NULL)
1128 	return(-2);
1129     if (ReadOnlyOpt) {
1130 	head->error = EACCES;
1131 	return (0);
1132     }
1133     return(remove(path));
1134 }
1135 
1136 /*
1137  * MKDIR
1138  */
1139 int
1140 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1141 {
1142     hctransaction_t trans;
1143     struct HCHead *head;
1144 
1145     if (NotForRealOpt)
1146 	return(0);
1147     if (hc == NULL || hc->host == NULL)
1148 	return(mkdir(path, mode));
1149 
1150     trans = hcc_start_command(hc, HC_MKDIR);
1151     hcc_leaf_string(trans, LC_PATH1, path);
1152     hcc_leaf_int32(trans, LC_MODE, mode);
1153     if ((head = hcc_finish_command(trans)) == NULL)
1154 	return(-1);
1155     if (head->error)
1156 	return(-1);
1157     return(0);
1158 }
1159 
1160 static int
1161 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1162 {
1163     struct HCLeaf *item;
1164     const char *path = NULL;
1165     mode_t mode = 0777;
1166 
1167     FOR_EACH_ITEM(item, trans, head) {
1168 	switch(item->leafid) {
1169 	case LC_PATH1:
1170 	    path = HCC_STRING(item);
1171 	    break;
1172 	case LC_MODE:
1173 	    mode = HCC_INT32(item);
1174 	    break;
1175 	}
1176     }
1177     if (ReadOnlyOpt) {
1178 	head->error = EACCES;
1179 	return (0);
1180     }
1181     if (path == NULL)
1182 	return(-2);
1183     return(mkdir(path, mode));
1184 }
1185 
1186 /*
1187  * RMDIR
1188  */
1189 int
1190 hc_rmdir(struct HostConf *hc, const char *path)
1191 {
1192     hctransaction_t trans;
1193     struct HCHead *head;
1194 
1195     if (NotForRealOpt)
1196 	return(0);
1197     if (hc == NULL || hc->host == NULL)
1198 	return(rmdir(path));
1199 
1200     trans = hcc_start_command(hc, HC_RMDIR);
1201     hcc_leaf_string(trans, LC_PATH1, path);
1202     if ((head = hcc_finish_command(trans)) == NULL)
1203 	return(-1);
1204     if (head->error)
1205 	return(-1);
1206     return(0);
1207 }
1208 
1209 static int
1210 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1211 {
1212     struct HCLeaf *item;
1213     const char *path = NULL;
1214 
1215     FOR_EACH_ITEM(item, trans, head) {
1216 	if (item->leafid == LC_PATH1)
1217 	    path = HCC_STRING(item);
1218     }
1219     if (ReadOnlyOpt) {
1220 	head->error = EACCES;
1221 	return (0);
1222     }
1223     if (path == NULL)
1224 	return(-2);
1225     return(rmdir(path));
1226 }
1227 
1228 /*
1229  * CHOWN
1230  *
1231  * Almost silently ignore chowns that fail if we are not root.
1232  */
1233 int
1234 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1235 {
1236     hctransaction_t trans;
1237     struct HCHead *head;
1238     int rc;
1239 
1240     if (NotForRealOpt)
1241 	return(0);
1242     if (!DstRootPrivs)
1243 	owner = -1;
1244 
1245     if (hc == NULL || hc->host == NULL) {
1246 	rc = chown(path, owner, group);
1247 	if (rc < 0)
1248 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1249 	return(rc);
1250     }
1251 
1252     trans = hcc_start_command(hc, HC_CHOWN);
1253     hcc_leaf_string(trans, LC_PATH1, path);
1254     hcc_leaf_int32(trans, LC_UID, owner);
1255     hcc_leaf_int32(trans, LC_GID, group);
1256     if ((head = hcc_finish_command(trans)) == NULL)
1257 	return(-1);
1258     if (head->error)
1259 	return(-1);
1260     return(0);
1261 }
1262 
1263 static int
1264 rc_chown(hctransaction_t trans, struct HCHead *head)
1265 {
1266     struct HCLeaf *item;
1267     const char *path = NULL;
1268     uid_t uid = (uid_t)-1;
1269     gid_t gid = (gid_t)-1;
1270     int rc;
1271 
1272     FOR_EACH_ITEM(item, trans, head) {
1273 	switch(item->leafid) {
1274 	case LC_PATH1:
1275 	    path = HCC_STRING(item);
1276 	    break;
1277 	case LC_UID:
1278 	    uid = HCC_INT32(item);
1279 	    break;
1280 	case LC_GID:
1281 	    gid = HCC_INT32(item);
1282 	    break;
1283 	}
1284     }
1285     if (ReadOnlyOpt) {
1286 	head->error = EACCES;
1287 	return (0);
1288     }
1289     if (path == NULL)
1290 	return(-2);
1291     rc = chown(path, uid, gid);
1292     if (rc < 0)
1293 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1294     return(rc);
1295 }
1296 
1297 /*
1298  * LCHOWN
1299  */
1300 int
1301 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1302 {
1303     hctransaction_t trans;
1304     struct HCHead *head;
1305     int rc;
1306 
1307     if (NotForRealOpt)
1308 	return(0);
1309     if (!DstRootPrivs)
1310 	owner = -1;
1311 
1312     if (hc == NULL || hc->host == NULL) {
1313 	rc = lchown(path, owner, group);
1314 	if (rc < 0)
1315 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1316 	return(rc);
1317     }
1318 
1319     trans = hcc_start_command(hc, HC_LCHOWN);
1320     hcc_leaf_string(trans, LC_PATH1, path);
1321     hcc_leaf_int32(trans, LC_UID, owner);
1322     hcc_leaf_int32(trans, LC_GID, group);
1323     if ((head = hcc_finish_command(trans)) == NULL)
1324 	return(-1);
1325     if (head->error)
1326 	return(-1);
1327     return(0);
1328 }
1329 
1330 static int
1331 rc_lchown(hctransaction_t trans, struct HCHead *head)
1332 {
1333     struct HCLeaf *item;
1334     const char *path = NULL;
1335     uid_t uid = (uid_t)-1;
1336     gid_t gid = (gid_t)-1;
1337     int rc;
1338 
1339     FOR_EACH_ITEM(item, trans, head) {
1340 	switch(item->leafid) {
1341 	case LC_PATH1:
1342 	    path = HCC_STRING(item);
1343 	    break;
1344 	case LC_UID:
1345 	    uid = HCC_INT32(item);
1346 	    break;
1347 	case LC_GID:
1348 	    gid = HCC_INT32(item);
1349 	    break;
1350 	}
1351     }
1352     if (ReadOnlyOpt) {
1353 	head->error = EACCES;
1354 	return (0);
1355     }
1356     if (path == NULL)
1357 	return(-2);
1358     rc = lchown(path, uid, gid);
1359     if (rc < 0)
1360 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1361     return(rc);
1362 }
1363 
1364 /*
1365  * CHMOD
1366  */
1367 int
1368 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1369 {
1370     hctransaction_t trans;
1371     struct HCHead *head;
1372 
1373     if (NotForRealOpt)
1374 	return(0);
1375     if (hc == NULL || hc->host == NULL)
1376 	return(chmod(path, mode));
1377 
1378     trans = hcc_start_command(hc, HC_CHMOD);
1379     hcc_leaf_string(trans, LC_PATH1, path);
1380     hcc_leaf_int32(trans, LC_MODE, mode);
1381     if ((head = hcc_finish_command(trans)) == NULL)
1382 	return(-1);
1383     if (head->error)
1384 	return(-1);
1385     return(0);
1386 }
1387 
1388 static int
1389 rc_chmod(hctransaction_t trans, struct HCHead *head)
1390 {
1391     struct HCLeaf *item;
1392     const char *path = NULL;
1393     mode_t mode = 0666;
1394 
1395     FOR_EACH_ITEM(item, trans, head) {
1396 	switch(item->leafid) {
1397 	case LC_PATH1:
1398 	    path = HCC_STRING(item);
1399 	    break;
1400 	case LC_MODE:
1401 	    mode = HCC_INT32(item);
1402 	    break;
1403 	}
1404     }
1405     if (ReadOnlyOpt) {
1406 	head->error = EACCES;
1407 	return (0);
1408     }
1409     if (path == NULL)
1410 	return(-2);
1411     return(chmod(path, mode));
1412 }
1413 
1414 /*
1415  * MKNOD
1416  */
1417 int
1418 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1419 {
1420     hctransaction_t trans;
1421     struct HCHead *head;
1422 
1423     if (NotForRealOpt)
1424 	return(0);
1425     if (!DstRootPrivs) {
1426 	/* mknod() requires root privs, so don't bother. */
1427 	errno = EPERM;
1428 	return (-1);
1429     }
1430 
1431     if (hc == NULL || hc->host == NULL)
1432 	return(mknod(path, mode, rdev));
1433 
1434     trans = hcc_start_command(hc, HC_MKNOD);
1435     hcc_leaf_string(trans, LC_PATH1, path);
1436     hcc_leaf_int32(trans, LC_MODE, mode);
1437     hcc_leaf_int32(trans, LC_RDEV, rdev);
1438     if ((head = hcc_finish_command(trans)) == NULL)
1439 	return(-1);
1440     if (head->error)
1441 	return(-1);
1442     return(0);
1443 }
1444 
1445 static int
1446 rc_mknod(hctransaction_t trans, struct HCHead *head)
1447 {
1448     struct HCLeaf *item;
1449     const char *path = NULL;
1450     mode_t mode = 0666;
1451     dev_t rdev = 0;
1452 
1453     FOR_EACH_ITEM(item, trans, head) {
1454 	switch(item->leafid) {
1455 	case LC_PATH1:
1456 	    path = HCC_STRING(item);
1457 	    break;
1458 	case LC_MODE:
1459 	    mode = HCC_INT32(item);
1460 	    break;
1461 	case LC_RDEV:
1462 	    rdev = HCC_INT32(item);
1463 	    break;
1464 	}
1465     }
1466     if (ReadOnlyOpt) {
1467 	head->error = EACCES;
1468 	return (0);
1469     }
1470     if (path == NULL)
1471 	return(-2);
1472     return(mknod(path, mode, rdev));
1473 }
1474 
1475 /*
1476  * LINK
1477  */
1478 int
1479 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1480 {
1481     hctransaction_t trans;
1482     struct HCHead *head;
1483 
1484     if (NotForRealOpt)
1485 	return(0);
1486     if (hc == NULL || hc->host == NULL)
1487 	return(link(name1, name2));
1488 
1489     trans = hcc_start_command(hc, HC_LINK);
1490     hcc_leaf_string(trans, LC_PATH1, name1);
1491     hcc_leaf_string(trans, LC_PATH2, name2);
1492     if ((head = hcc_finish_command(trans)) == NULL)
1493 	return(-1);
1494     if (head->error)
1495 	return(-1);
1496     return(0);
1497 }
1498 
1499 static int
1500 rc_link(hctransaction_t trans, struct HCHead *head)
1501 {
1502     struct HCLeaf *item;
1503     const char *name1 = NULL;
1504     const char *name2 = NULL;
1505 
1506     FOR_EACH_ITEM(item, trans, head) {
1507 	switch(item->leafid) {
1508 	case LC_PATH1:
1509 	    name1 = HCC_STRING(item);
1510 	    break;
1511 	case LC_PATH2:
1512 	    name2 = HCC_STRING(item);
1513 	    break;
1514 	}
1515     }
1516     if (ReadOnlyOpt) {
1517 	head->error = EACCES;
1518 	return (-0);
1519     }
1520     if (name1 == NULL || name2 == NULL)
1521 	return(-2);
1522     return(link(name1, name2));
1523 }
1524 
1525 #ifdef _ST_FLAGS_PRESENT_
1526 /*
1527  * CHFLAGS
1528  */
1529 int
1530 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1531 {
1532     hctransaction_t trans;
1533     struct HCHead *head;
1534     int rc;
1535 
1536     if (NotForRealOpt)
1537 	return(0);
1538     if (!DstRootPrivs)
1539 	flags &= UF_SETTABLE;
1540 
1541     if (hc == NULL || hc->host == NULL) {
1542 	if ((rc = chflags(path, flags)) < 0)
1543 	    rc = silentwarning(&chflags_warning, "file flags may differ\n");
1544 	return (rc);
1545     }
1546 
1547     trans = hcc_start_command(hc, HC_CHFLAGS);
1548     hcc_leaf_string(trans, LC_PATH1, path);
1549     hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1550     if ((head = hcc_finish_command(trans)) == NULL)
1551 	return(-1);
1552     if (head->error)
1553 	return(-1);
1554     return(0);
1555 }
1556 
1557 static int
1558 rc_chflags(hctransaction_t trans, struct HCHead *head)
1559 {
1560     struct HCLeaf *item;
1561     const char *path = NULL;
1562     u_long flags = 0;
1563     int rc;
1564 
1565     FOR_EACH_ITEM(item, trans, head) {
1566 	switch(item->leafid) {
1567 	case LC_PATH1:
1568 	    path = HCC_STRING(item);
1569 	    break;
1570 	case LC_FILEFLAGS:
1571 	    flags = (u_long)HCC_INT64(item);
1572 	    break;
1573 	}
1574     }
1575     if (ReadOnlyOpt) {
1576 	head->error = EACCES;
1577 	return (0);
1578     }
1579     if (path == NULL)
1580 	return(-2);
1581     if ((rc = chflags(path, flags)) < 0)
1582 	rc = silentwarning(&chflags_warning, "file flags may differ\n");
1583     return(rc);
1584 }
1585 
1586 #endif
1587 
1588 /*
1589  * READLINK
1590  */
1591 int
1592 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1593 {
1594     hctransaction_t trans;
1595     struct HCHead *head;
1596     struct HCLeaf *item;
1597     int r;
1598 
1599     if (hc == NULL || hc->host == NULL)
1600 	return(readlink(path, buf, bufsiz));
1601 
1602     trans = hcc_start_command(hc, HC_READLINK);
1603     hcc_leaf_string(trans, LC_PATH1, path);
1604     if ((head = hcc_finish_command(trans)) == NULL)
1605 	return(-1);
1606     if (head->error)
1607 	return(-1);
1608 
1609     r = 0;
1610     FOR_EACH_ITEM(item, trans, head) {
1611 	if (item->leafid == LC_DATA) {
1612 	    r = item->bytes - sizeof(*item);
1613 	    if (r < 0)
1614 		r = 0;
1615 	    if (r > bufsiz)
1616 		r = bufsiz;
1617 	    bcopy(HCC_BINARYDATA(item), buf, r);
1618 	}
1619     }
1620     return(r);
1621 }
1622 
1623 static int
1624 rc_readlink(hctransaction_t trans, struct HCHead *head)
1625 {
1626     struct HCLeaf *item;
1627     const char *path = NULL;
1628     char buf[1024];
1629     int r;
1630 
1631     FOR_EACH_ITEM(item, trans, head) {
1632 	if (item->leafid == LC_PATH1)
1633 	    path = HCC_STRING(item);
1634     }
1635     if (path == NULL)
1636 	return(-2);
1637     r = readlink(path, buf, sizeof(buf));
1638     if (r < 0)
1639 	return(-1);
1640     hcc_leaf_data(trans, LC_DATA, buf, r);
1641     return(0);
1642 }
1643 
1644 /*
1645  * UMASK
1646  */
1647 mode_t
1648 hc_umask(struct HostConf *hc, mode_t numask)
1649 {
1650     hctransaction_t trans;
1651     struct HCHead *head;
1652     struct HCLeaf *item;
1653 
1654     if (NotForRealOpt)
1655 	return(umask(numask));
1656     if (hc == NULL || hc->host == NULL)
1657 	return(umask(numask));
1658 
1659     trans = hcc_start_command(hc, HC_UMASK);
1660     hcc_leaf_int32(trans, LC_MODE, numask);
1661     if ((head = hcc_finish_command(trans)) == NULL)
1662 	return((mode_t)-1);
1663     if (head->error)
1664 	return((mode_t)-1);
1665 
1666     numask = (mode_t) ~0666U;
1667     FOR_EACH_ITEM(item, trans, head) {
1668 	if (item->leafid == LC_MODE)
1669 	    numask = HCC_INT32(item);
1670     }
1671     return(numask);
1672 }
1673 
1674 static int
1675 rc_umask(hctransaction_t trans, struct HCHead *head)
1676 {
1677     struct HCLeaf *item;
1678     mode_t numask = (mode_t) ~0666U;
1679 
1680     FOR_EACH_ITEM(item, trans, head) {
1681 	if (item->leafid == LC_MODE)
1682 	    numask = HCC_INT32(item);
1683     }
1684     numask = umask(numask);
1685     hcc_leaf_int32(trans, LC_MODE, numask);
1686     return(0);
1687 }
1688 
1689 /*
1690  * SYMLINK
1691  */
1692 int
1693 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1694 {
1695     hctransaction_t trans;
1696     struct HCHead *head;
1697 
1698     if (NotForRealOpt)
1699 	return(0);
1700     if (hc == NULL || hc->host == NULL)
1701 	return(symlink(name1, name2));
1702 
1703     trans = hcc_start_command(hc, HC_SYMLINK);
1704     hcc_leaf_string(trans, LC_PATH1, name1);
1705     hcc_leaf_string(trans, LC_PATH2, name2);
1706     if ((head = hcc_finish_command(trans)) == NULL)
1707 	return(-1);
1708     if (head->error)
1709 	return(-1);
1710     return(0);
1711 }
1712 
1713 static int
1714 rc_symlink(hctransaction_t trans, struct HCHead *head)
1715 {
1716     struct HCLeaf *item;
1717     const char *name1 = NULL;
1718     const char *name2 = NULL;
1719 
1720     FOR_EACH_ITEM(item, trans, head) {
1721 	switch(item->leafid) {
1722 	case LC_PATH1:
1723 	    name1 = HCC_STRING(item);
1724 	    break;
1725 	case LC_PATH2:
1726 	    name2 = HCC_STRING(item);
1727 	    break;
1728 	}
1729     }
1730     if (ReadOnlyOpt) {
1731 	head->error = EACCES;
1732 	return (0);
1733     }
1734     if (name1 == NULL || name2 == NULL)
1735 	return(-2);
1736     return(symlink(name1, name2));
1737 }
1738 
1739 /*
1740  * RENAME
1741  */
1742 int
1743 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1744 {
1745     hctransaction_t trans;
1746     struct HCHead *head;
1747 
1748     if (NotForRealOpt)
1749 	return(0);
1750     if (hc == NULL || hc->host == NULL)
1751 	return(rename(name1, name2));
1752 
1753     trans = hcc_start_command(hc, HC_RENAME);
1754     hcc_leaf_string(trans, LC_PATH1, name1);
1755     hcc_leaf_string(trans, LC_PATH2, name2);
1756     if ((head = hcc_finish_command(trans)) == NULL)
1757 	return(-1);
1758     if (head->error)
1759 	return(-1);
1760     return(0);
1761 }
1762 
1763 static int
1764 rc_rename(hctransaction_t trans, struct HCHead *head)
1765 {
1766     struct HCLeaf *item;
1767     const char *name1 = NULL;
1768     const char *name2 = NULL;
1769 
1770     FOR_EACH_ITEM(item, trans, head) {
1771 	switch(item->leafid) {
1772 	case LC_PATH1:
1773 	    name1 = HCC_STRING(item);
1774 	    break;
1775 	case LC_PATH2:
1776 	    name2 = HCC_STRING(item);
1777 	    break;
1778 	}
1779     }
1780     if (ReadOnlyOpt) {
1781 	head->error = EACCES;
1782 	return (0);
1783     }
1784     if (name1 == NULL || name2 == NULL)
1785 	return(-2);
1786     return(rename(name1, name2));
1787 }
1788 
1789 /*
1790  * UTIMES
1791  */
1792 int
1793 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1794 {
1795     hctransaction_t trans;
1796     struct HCHead *head;
1797 
1798     if (NotForRealOpt)
1799 	return(0);
1800     if (hc == NULL || hc->host == NULL)
1801 	return(utimes(path, times));
1802 
1803     trans = hcc_start_command(hc, HC_UTIMES);
1804     hcc_leaf_string(trans, LC_PATH1, path);
1805     hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1806     hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1807 #if defined(st_atime)
1808     hcc_leaf_int32(trans, LC_ATIMENSEC, times[0].tv_usec * 1000);
1809     hcc_leaf_int32(trans, LC_MTIMENSEC, times[1].tv_usec * 1000);
1810 #endif
1811     if ((head = hcc_finish_command(trans)) == NULL)
1812 	return(-1);
1813     if (head->error)
1814 	return(-1);
1815     return(0);
1816 }
1817 
1818 static int
1819 rc_utimes(hctransaction_t trans, struct HCHead *head)
1820 {
1821     struct HCLeaf *item;
1822     struct timeval times[2];
1823     const char *path;
1824 
1825     bzero(times, sizeof(times));
1826     path = NULL;
1827 
1828     FOR_EACH_ITEM(item, trans, head) {
1829 	switch(item->leafid) {
1830 	case LC_PATH1:
1831 	    path = HCC_STRING(item);
1832 	    break;
1833 	case LC_ATIME:
1834 	    times[0].tv_sec = HCC_INT64(item);
1835 	    break;
1836 	case LC_MTIME:
1837 	    times[1].tv_sec = HCC_INT64(item);
1838 	    break;
1839 #if defined(st_atimespec) || defined(_STATBUF_ST_NSEC)
1840 	case LC_ATIMENSEC:
1841 	    times[0].tv_usec = HCC_INT32(item) / 1000;
1842 	    break;
1843 	case LC_MTIMENSEC:
1844 	    times[1].tv_usec = HCC_INT32(item) / 1000;
1845 	    break;
1846 #endif
1847 	}
1848     }
1849     if (ReadOnlyOpt) {
1850 	head->error = EACCES;
1851 	return (0);
1852     }
1853     if (path == NULL)
1854 	return(-2);
1855     return(utimes(path, times));
1856 }
1857 
1858 uid_t
1859 hc_geteuid(struct HostConf *hc)
1860 {
1861     hctransaction_t trans;
1862     struct HCHead *head;
1863     struct HCLeaf *item;
1864 
1865     if (hc == NULL || hc->host == NULL)
1866 	return (geteuid());
1867 
1868     if (hc->version < 3) {
1869 	fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1870 	/* Return 0 on error, so the caller assumes root privileges. */
1871 	return (0);
1872     }
1873 
1874     trans = hcc_start_command(hc, HC_GETEUID);
1875     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1876 	return(0);
1877     FOR_EACH_ITEM(item, trans, head) {
1878 	if (item->leafid == LC_UID)
1879 	    return (HCC_INT32(item));
1880     }
1881     return(0); /* shouldn't happen */
1882 }
1883 
1884 static int
1885 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1886 {
1887     hcc_leaf_int32(trans, LC_UID, geteuid());
1888     return (0);
1889 }
1890 
1891 static int
1892 getmygroups(gid_t **gidlist)
1893 {
1894     int count;
1895 
1896     if ((count = getgroups(0, *gidlist)) > 0) {
1897 	if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1898 	    if ((count = getgroups(count, *gidlist)) <= 0)
1899 		free(*gidlist);
1900 	}
1901 	else
1902 	    count = -1;
1903     }
1904     else
1905 	*gidlist = NULL;
1906     return (count);
1907 }
1908 
1909 int
1910 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1911 {
1912     int count, i;
1913     hctransaction_t trans;
1914     struct HCHead *head;
1915     struct HCLeaf *item;
1916 
1917     if (hc == NULL || hc->host == NULL)
1918 	return (getmygroups(gidlist));
1919 
1920     i = 0;
1921     count = 0;
1922     *gidlist = NULL;
1923 
1924     if (hc->version < 3) {
1925 	fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1926 	return (-1);
1927     }
1928 
1929     trans = hcc_start_command(hc, HC_GETGROUPS);
1930     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1931 	return(-1);
1932     FOR_EACH_ITEM(item, trans, head) {
1933 	switch(item->leafid) {
1934 	case LC_COUNT:
1935 	    count = HCC_INT32(item);
1936 	    if (*gidlist != NULL) { /* protocol error */
1937 		free(*gidlist);
1938 		*gidlist = NULL;
1939 		return (-1);
1940 	    }
1941 	    if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1942 		return (-1);
1943 	    break;
1944 	case LC_GID:
1945 	    if (*gidlist == NULL || i >= count) { /* protocol error */
1946 		if (*gidlist != NULL)
1947 		    free(*gidlist);
1948 		*gidlist = NULL;
1949 		return (-1);
1950 	    }
1951 	    (*gidlist)[i++] = HCC_INT32(item);
1952 	    break;
1953 	}
1954     }
1955     return (count);
1956 }
1957 
1958 static int
1959 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1960 {
1961     int count, i;
1962     gid_t *gidlist;
1963 
1964     if ((count = getmygroups(&gidlist)) < 0)
1965 	return (-1);
1966     hcc_leaf_int32(trans, LC_COUNT, count);
1967     for (i = 0; i < count; i++)
1968 	hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1969     if (gidlist != NULL)
1970 	free(gidlist);
1971     return (0);
1972 }
1973