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