xref: /dragonfly/bin/cpdup/hcproto.c (revision 5dfd06ac)
1 /*
2  * HCPROTO.C
3  *
4  * This module implements a simple remote control protocol
5  *
6  * $DragonFly: src/bin/cpdup/hcproto.c,v 1.1 2006/08/13 20:51:40 dillon Exp $
7  */
8 
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <dirent.h>
17 #include <errno.h>
18 
19 #include "hclink.h"
20 #include "hcproto.h"
21 
22 static int hc_decode_stat(struct stat *, struct HCHead *);
23 static int rc_encode_stat(struct HostConf *, struct stat *);
24 
25 static int rc_hello(struct HostConf *, struct HCHead *);
26 static int rc_stat(struct HostConf *, struct HCHead *);
27 static int rc_lstat(struct HostConf *, struct HCHead *);
28 static int rc_opendir(struct HostConf *, struct HCHead *);
29 static int rc_readdir(struct HostConf *, struct HCHead *);
30 static int rc_closedir(struct HostConf *, struct HCHead *);
31 static int rc_open(struct HostConf *, struct HCHead *);
32 static int rc_close(struct HostConf *, struct HCHead *);
33 static int rc_read(struct HostConf *, struct HCHead *);
34 static int rc_write(struct HostConf *, struct HCHead *);
35 static int rc_remove(struct HostConf *, struct HCHead *);
36 static int rc_mkdir(struct HostConf *, struct HCHead *);
37 static int rc_rmdir(struct HostConf *, struct HCHead *);
38 static int rc_chown(struct HostConf *, struct HCHead *);
39 static int rc_lchown(struct HostConf *, struct HCHead *);
40 static int rc_chmod(struct HostConf *, struct HCHead *);
41 static int rc_link(struct HostConf *, struct HCHead *);
42 #ifdef _ST_FLAGS_PRESENT_
43 static int rc_chflags(struct HostConf *, struct HCHead *);
44 #endif
45 static int rc_readlink(struct HostConf *, struct HCHead *);
46 static int rc_umask(struct HostConf *, struct HCHead *);
47 static int rc_symlink(struct HostConf *, struct HCHead *);
48 static int rc_rename(struct HostConf *, struct HCHead *);
49 static int rc_utimes(struct HostConf *, struct HCHead *);
50 
51 struct HCDesc HCDispatchTable[] = {
52     { HC_HELLO,		rc_hello },
53     { HC_STAT,		rc_stat },
54     { HC_LSTAT,		rc_lstat },
55     { HC_OPENDIR,	rc_opendir },
56     { HC_READDIR,	rc_readdir },
57     { HC_CLOSEDIR,	rc_closedir },
58     { HC_OPEN,		rc_open },
59     { HC_CLOSE,		rc_close },
60     { HC_READ,		rc_read },
61     { HC_WRITE,		rc_write },
62     { HC_REMOVE,	rc_remove },
63     { HC_MKDIR,		rc_mkdir },
64     { HC_RMDIR,		rc_rmdir },
65     { HC_CHOWN,		rc_chown },
66     { HC_LCHOWN,	rc_lchown },
67     { HC_CHMOD,		rc_chmod },
68     { HC_LINK,		rc_link },
69 #ifdef _ST_FLAGS_PRESENT_
70     { HC_CHFLAGS,	rc_chflags },
71 #endif
72     { HC_READLINK,	rc_readlink },
73     { HC_UMASK,		rc_umask },
74     { HC_SYMLINK,	rc_symlink },
75     { HC_RENAME,	rc_rename },
76     { HC_UTIMES,	rc_utimes },
77 };
78 
79 int
80 hc_connect(struct HostConf *hc)
81 {
82     if (hcc_connect(hc) < 0)
83 	return(-1);
84     return(hc_hello(hc));
85 }
86 
87 void
88 hc_slave(int fdin, int fdout)
89 {
90     hcc_slave(fdin, fdout, HCDispatchTable,
91 	      sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
92 
93 }
94 
95 /*
96  * A HELLO RPC is sent on the initial connect.
97  */
98 int
99 hc_hello(struct HostConf *hc)
100 {
101     struct HCHead *head;
102     struct HCLeaf *item;
103     char hostbuf[256];
104     int error;
105 
106     bzero(hostbuf, sizeof(hostbuf));
107     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
108         return(-1);
109     if (hostbuf[0] == 0)
110 	hostbuf[0] = '?';
111 
112     hcc_start_command(hc, HC_HELLO);
113     hcc_leaf_string(hc, LC_HELLOSTR, hostbuf);
114     if ((head = hcc_finish_command(hc)) == NULL)
115 	return(-1);
116 
117     if (head->error) {
118 	fprintf(stderr, "Connected to %s but remote returned error %d\n",
119 		hc->host, head->error);
120 	return(-1);
121     }
122 
123     error = -1;
124     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
125 	switch(item->leafid) {
126 	case LC_HELLOSTR:
127 	    fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
128 	    error = 0;
129 	}
130     }
131     if (error < 0)
132 	fprintf(stderr, "Handshake failed with %s\n", hc->host);
133     return (error);
134 }
135 
136 static int
137 rc_hello(struct HostConf *hc, struct HCHead *head __unused)
138 {
139     char hostbuf[256];
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     hcc_leaf_string(hc, LC_HELLOSTR, hostbuf);
148     return(0);
149 }
150 
151 /*
152  * STAT, LSTAT
153  */
154 int
155 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
156 {
157     struct HCHead *head;
158 
159     if (hc == NULL || hc->host == NULL)
160 	return(stat(path, st));
161 
162     hcc_start_command(hc, HC_STAT);
163     hcc_leaf_string(hc, LC_PATH1, path);
164     if ((head = hcc_finish_command(hc)) == NULL)
165 	return(-1);
166     if (head->error)
167 	return(-1);
168     return(hc_decode_stat(st, head));
169 }
170 
171 int
172 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
173 {
174     struct HCHead *head;
175 
176     if (hc == NULL || hc->host == NULL)
177 	return(lstat(path, st));
178 
179     hcc_start_command(hc, HC_LSTAT);
180     hcc_leaf_string(hc, LC_PATH1, path);
181     if ((head = hcc_finish_command(hc)) == NULL)
182 	return(-1);
183     if (head->error)
184 	return(-1);
185     return(hc_decode_stat(st, head));
186 }
187 
188 static int
189 hc_decode_stat(struct stat *st, struct HCHead *head)
190 {
191     struct HCLeaf *item;
192 
193     bzero(st, sizeof(*st));
194     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
195 	switch(item->leafid) {
196 	case LC_DEV:
197 		st->st_dev = HCC_INT32(item);
198 		break;
199 	case LC_INO:
200 		st->st_ino = HCC_INT64(item);
201 		break;
202 	case LC_MODE:
203 		st->st_mode = HCC_INT32(item);
204 		break;
205 	case LC_NLINK:
206 		st->st_nlink = HCC_INT32(item);
207 		break;
208 	case LC_UID:
209 		st->st_uid = HCC_INT32(item);
210 		break;
211 	case LC_GID:
212 		st->st_gid = HCC_INT32(item);
213 		break;
214 	case LC_RDEV:
215 		st->st_rdev = HCC_INT32(item);
216 		break;
217 	case LC_ATIME:
218 		st->st_atime = (time_t)HCC_INT64(item);
219 		break;
220 	case LC_MTIME:
221 		st->st_mtime = (time_t)HCC_INT64(item);
222 		break;
223 	case LC_CTIME:
224 		st->st_ctime = (time_t)HCC_INT64(item);
225 		break;
226 	case LC_FILESIZE:
227 		st->st_size = HCC_INT64(item);
228 		break;
229 	case LC_FILEBLKS:
230 		st->st_blocks = HCC_INT64(item);
231 		break;
232 	case LC_BLKSIZE:
233 		st->st_blksize = HCC_INT32(item);
234 		break;
235 #ifdef _ST_FSMID_PRESENT_
236 	case LC_FSMID:
237 		st->st_fsmid = HCC_INT64(item);
238 		break;
239 #endif
240 #ifdef _ST_FLAGS_PRESENT_
241 	case LC_FILEFLAGS:
242 		st->st_flags = (u_int32_t)HCC_INT64(item);
243 		break;
244 #endif
245 	}
246     }
247     return(0);
248 }
249 
250 static int
251 rc_stat(struct HostConf *hc, struct HCHead *head)
252 {
253     struct HCLeaf *item;
254     struct stat st;
255     const char *path = NULL;
256 
257     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
258 	switch(item->leafid) {
259 	case LC_PATH1:
260 	    path = HCC_STRING(item);
261 	    break;
262 	}
263     }
264     if (path == NULL)
265 	return(-2);
266     if (stat(path, &st) < 0)
267 	return(-1);
268     return (rc_encode_stat(hc, &st));
269 }
270 
271 static int
272 rc_lstat(struct HostConf *hc, struct HCHead *head)
273 {
274     struct HCLeaf *item;
275     struct stat st;
276     const char *path = NULL;
277 
278     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
279 	switch(item->leafid) {
280 	case LC_PATH1:
281 	    path = HCC_STRING(item);
282 	    break;
283 	}
284     }
285     if (path == NULL)
286 	return(-2);
287     if (lstat(path, &st) < 0)
288 	return(-1);
289     return (rc_encode_stat(hc, &st));
290 }
291 
292 static int
293 rc_encode_stat(struct HostConf *hc, struct stat *st)
294 {
295     hcc_leaf_int32(hc, LC_DEV, st->st_dev);
296     hcc_leaf_int64(hc, LC_INO, st->st_ino);
297     hcc_leaf_int32(hc, LC_MODE, st->st_mode);
298     hcc_leaf_int32(hc, LC_NLINK, st->st_nlink);
299     hcc_leaf_int32(hc, LC_UID, st->st_uid);
300     hcc_leaf_int32(hc, LC_GID, st->st_gid);
301     hcc_leaf_int32(hc, LC_RDEV, st->st_rdev);
302     hcc_leaf_int64(hc, LC_ATIME, st->st_atime);
303     hcc_leaf_int64(hc, LC_MTIME, st->st_mtime);
304     hcc_leaf_int64(hc, LC_CTIME, st->st_ctime);
305     hcc_leaf_int64(hc, LC_FILESIZE, st->st_size);
306     hcc_leaf_int64(hc, LC_FILEBLKS, st->st_blocks);
307     hcc_leaf_int32(hc, LC_BLKSIZE, st->st_blksize);
308 #ifdef _ST_FSMID_PRESENT_
309     hcc_leaf_int64(hc, LC_FSMID, st->st_fsmid);
310 #endif
311 #ifdef _ST_FLAGS_PRESENT_
312     hcc_leaf_int64(hc, LC_FILEFLAGS, st->st_flags);
313 #endif
314     return(0);
315 }
316 
317 /*
318  * OPENDIR
319  */
320 DIR *
321 hc_opendir(struct HostConf *hc, const char *path)
322 {
323     struct HCHead *head;
324     struct HCLeaf *item;
325     struct dirent *den;
326     int desc = 0;
327 
328     if (hc == NULL || hc->host == NULL)
329 	return(opendir(path));
330 
331     hcc_start_command(hc, HC_OPENDIR);
332     hcc_leaf_string(hc, LC_PATH1, path);
333     if ((head = hcc_finish_command(hc)) == NULL)
334 	return(NULL);
335     if (head->error)
336 	return(NULL);
337     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
338 	switch(item->leafid) {
339 	case LC_DESCRIPTOR:
340 	    desc = HCC_INT32(item);
341 	    break;
342 	}
343     }
344     if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
345 	fprintf(stderr, "hc_opendir: remote reused active descriptor %d\n",
346 		desc);
347 	return(NULL);
348     }
349     den = malloc(sizeof(*den));
350     bzero(den, sizeof(*den));
351     hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
352     return((void *)desc);
353 }
354 
355 static int
356 rc_opendir(struct HostConf *hc, struct HCHead *head)
357 {
358     struct HCLeaf *item;
359     const char *path = NULL;
360     DIR *dir;
361     int desc;
362 
363     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
364 	switch(item->leafid) {
365 	case LC_PATH1:
366 	    path = HCC_STRING(item);
367 	    break;
368 	}
369     }
370     if (path == NULL)
371 	return(-2);
372     if ((dir = opendir(path)) == NULL) {
373 	head->error = errno;
374     } else {
375 	desc = hcc_alloc_descriptor(hc, dir, HC_DESC_DIR);
376 	hcc_leaf_int32(hc, LC_DESCRIPTOR, desc);
377     }
378     return(0);
379 }
380 
381 /*
382  * READDIR
383  */
384 struct dirent *
385 hc_readdir(struct HostConf *hc, DIR *dir)
386 {
387     struct HCHead *head;
388     struct HCLeaf *item;
389     struct dirent *den;
390 
391     if (hc == NULL || hc->host == NULL)
392 	return(readdir(dir));
393 
394     hcc_start_command(hc, HC_READDIR);
395     hcc_leaf_int32(hc, LC_DESCRIPTOR, (int)dir);
396     if ((head = hcc_finish_command(hc)) == NULL)
397 	return(NULL);
398     if (head->error)
399 	return(NULL);	/* XXX errno */
400     den = hcc_get_descriptor(hc, (int)dir, HC_DESC_DIR);
401     if (den == NULL)
402 	return(NULL);	/* XXX errno */
403     if (den->d_name)
404 	den->d_name[0] = 0;
405     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
406 	switch(item->leafid) {
407 	case LC_PATH1:
408 	    snprintf(den->d_name, sizeof(den->d_name), "%s", HCC_STRING(item));
409 	    break;
410 	case LC_INO:
411 	    den->d_fileno = HCC_INT64(item);
412 	    break;
413 	case LC_TYPE:
414 	    den->d_type = HCC_INT32(item);
415 	    break;
416 	}
417     }
418     if (den->d_name[0]) {
419 #ifdef _DIRENT_HAVE_D_NAMLEN
420 	den->d_namlen = strlen(den->d_name);
421 #endif
422 	return(den);
423     }
424     return(NULL);	/* XXX errno */
425 }
426 
427 static int
428 rc_readdir(struct HostConf *hc, struct HCHead *head)
429 {
430     struct HCLeaf *item;
431     struct dirent *den;
432     DIR *dir = NULL;
433 
434     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
435 	switch(item->leafid) {
436 	case LC_DESCRIPTOR:
437 	    dir = hcc_get_descriptor(hc, HCC_INT32(item), HC_DESC_DIR);
438 	    break;
439 	}
440     }
441     if (dir == NULL)
442 	return(-2);
443     if ((den = readdir(dir)) != NULL) {
444 	hcc_leaf_string(hc, LC_PATH1, den->d_name);
445 	hcc_leaf_int64(hc, LC_INO, den->d_fileno);
446 	hcc_leaf_int32(hc, LC_TYPE, den->d_type);
447     }
448     return(0);
449 }
450 
451 /*
452  * CLOSEDIR
453  *
454  * XXX cpdup needs to check error code to avoid truncated dirs?
455  */
456 int
457 hc_closedir(struct HostConf *hc, DIR *dir)
458 {
459     struct HCHead *head;
460     struct dirent *den;
461 
462     if (hc == NULL || hc->host == NULL)
463 	return(closedir(dir));
464     den = hcc_get_descriptor(hc, (int)dir, HC_DESC_DIR);
465     if (den) {
466 	free(den);
467 	hcc_set_descriptor(hc, (int)dir, NULL, HC_DESC_DIR);
468 
469 	hcc_start_command(hc, HC_CLOSEDIR);
470 	hcc_leaf_int32(hc, LC_DESCRIPTOR, (int)dir);
471 	if ((head = hcc_finish_command(hc)) == NULL)
472 	    return(-1);
473 	if (head->error)
474 	    return(-1);		/* XXX errno */
475 	return(0);
476     } else {
477 	/* errno */
478 	return(-1);
479     }
480 }
481 
482 static int
483 rc_closedir(struct HostConf *hc, struct HCHead *head)
484 {
485     struct HCLeaf *item;
486     DIR *dir = NULL;
487 
488     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
489 	switch(item->leafid) {
490 	case LC_DESCRIPTOR:
491 	    dir = hcc_get_descriptor(hc, HCC_INT32(item), HC_DESC_DIR);
492 	    break;
493 	}
494     }
495     if (dir == NULL)
496 	return(-2);
497     return(closedir(dir));
498 }
499 
500 /*
501  * OPEN
502  */
503 int
504 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
505 {
506     struct HCHead *head;
507     struct HCLeaf *item;
508     int *fdp;
509     int desc = 0;
510     int nflags;
511 
512     if (hc == NULL || hc->host == NULL) {
513 #ifdef O_LARGEFILE
514 	flags |= O_LARGEFILE;
515 #endif
516 	return(open(path, flags, mode));
517     }
518 
519     nflags = flags & XO_NATIVEMASK;
520     if (flags & O_CREAT)
521 	nflags |= XO_CREAT;
522     if (flags & O_EXCL)
523 	nflags |= XO_EXCL;
524     if (flags & O_TRUNC)
525 	nflags |= XO_TRUNC;
526 
527     hcc_start_command(hc, HC_OPEN);
528     hcc_leaf_string(hc, LC_PATH1, path);
529     hcc_leaf_int32(hc, LC_OFLAGS, nflags);
530     hcc_leaf_int32(hc, LC_MODE, mode);
531 
532     if ((head = hcc_finish_command(hc)) == NULL)
533 	return(-1);
534     if (head->error)
535 	return(-1);
536     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
537 	switch(item->leafid) {
538 	case LC_DESCRIPTOR:
539 	    desc = HCC_INT32(item);
540 	    break;
541 	}
542     }
543     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
544 	fprintf(stderr, "hc_opendir: remote reused active descriptor %d\n",
545 		desc);
546 	return(-1);
547     }
548     fdp = malloc(sizeof(int));
549     *fdp = desc;	/* really just a dummy */
550     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
551     return(desc);
552 }
553 
554 static int
555 rc_open(struct HostConf *hc, struct HCHead *head)
556 {
557     struct HCLeaf *item;
558     const char *path = NULL;
559     int nflags = 0;
560     int flags;
561     mode_t mode = 0666;
562     int desc;
563     int *fdp;
564     int fd;
565 
566     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
567 	switch(item->leafid) {
568 	case LC_PATH1:
569 	    path = HCC_STRING(item);
570 	    break;
571 	case LC_OFLAGS:
572 	    nflags = HCC_INT32(item);
573 	    break;
574 	case LC_MODE:
575 	    mode = HCC_INT32(item);
576 	    break;
577 	}
578     }
579     if (path == NULL)
580 	return(-2);
581 
582     flags = nflags & XO_NATIVEMASK;
583     if (nflags & XO_CREAT)
584 	flags |= O_CREAT;
585     if (nflags & XO_EXCL)
586 	flags |= O_EXCL;
587     if (nflags & XO_TRUNC)
588 	flags |= O_TRUNC;
589 
590 #ifdef O_LARGEFILE
591     flags |= O_LARGEFILE;
592 #endif
593     if ((fd = open(path, flags, mode)) < 0) {
594 	head->error = errno;
595 	return(0);
596     }
597     fdp = malloc(sizeof(int));
598     *fdp = fd;
599     desc = hcc_alloc_descriptor(hc, fdp, HC_DESC_FD);
600     hcc_leaf_int32(hc, LC_DESCRIPTOR, desc);
601     return(0);
602 }
603 
604 /*
605  * CLOSE
606  */
607 int
608 hc_close(struct HostConf *hc, int fd)
609 {
610     struct HCHead *head;
611     int *fdp;
612 
613     if (hc == NULL || hc->host == NULL)
614 	return(close(fd));
615 
616     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
617     if (fdp) {
618 	free(fdp);
619 	hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
620 
621 	hcc_start_command(hc, HC_CLOSE);
622 	hcc_leaf_int32(hc, LC_DESCRIPTOR, fd);
623 	if ((head = hcc_finish_command(hc)) == NULL)
624 	    return(-1);
625 	if (head->error)
626 	    return(-1);
627 	return(0);
628     } else {
629 	return(-1);
630     }
631 }
632 
633 static int
634 rc_close(struct HostConf *hc, struct HCHead *head)
635 {
636     struct HCLeaf *item;
637     int *fdp = NULL;
638     int fd;
639     int desc = -1;
640 
641     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
642 	switch(item->leafid) {
643 	case LC_DESCRIPTOR:
644 	    desc = HCC_INT32(item);
645 	    break;
646 	}
647     }
648     if (desc < 0)
649 	return(-2);
650     if ((fdp = hcc_get_descriptor(hc, desc, HC_DESC_FD)) == NULL)
651 	return(-2);
652     fd = *fdp;
653     free(fdp);
654     hcc_set_descriptor(hc, desc, NULL, HC_DESC_FD);
655     return(close(fd));
656 }
657 
658 /*
659  * READ
660  */
661 ssize_t
662 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
663 {
664     struct HCHead *head;
665     struct HCLeaf *item;
666     int *fdp;
667     int r;
668 
669     if (hc == NULL || hc->host == NULL)
670 	return(read(fd, buf, bytes));
671 
672     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
673     if (fdp) {
674 	r = 0;
675 	while (bytes) {
676 	    int n = (bytes > 32768) ? 32768 : bytes;
677 	    int x = 0;
678 
679 	    hcc_start_command(hc, HC_READ);
680 	    hcc_leaf_int32(hc, LC_DESCRIPTOR, fd);
681 	    hcc_leaf_int32(hc, LC_BYTES, n);
682 	    if ((head = hcc_finish_command(hc)) == NULL)
683 		return(-1);
684 	    if (head->error)
685 		return(-1);
686 	    for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
687 		switch(item->leafid) {
688 		case LC_DATA:
689 		    x = item->bytes - sizeof(*item);
690 		    if (x > (int)bytes)
691 			x = (int)bytes;
692 		    bcopy(HCC_BINARYDATA(item), buf, x);
693 		    buf = (char *)buf + x;
694 		    bytes -= (size_t)x;
695 		    r += x;
696 		    break;
697 		}
698 	    }
699 	    if (x < n)
700 		break;
701 	}
702 	return(r);
703     } else {
704 	return(-1);
705     }
706 }
707 
708 static int
709 rc_read(struct HostConf *hc, struct HCHead *head)
710 {
711     struct HCLeaf *item;
712     int *fdp = NULL;
713     char buf[32768];
714     int bytes = -1;
715     int n;
716 
717     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
718 	switch(item->leafid) {
719 	case LC_DESCRIPTOR:
720 	    fdp = hcc_get_descriptor(hc, HCC_INT32(item), HC_DESC_FD);
721 	    break;
722 	case LC_BYTES:
723 	    bytes = HCC_INT32(item);
724 	    break;
725 	}
726     }
727     if (fdp == NULL)
728 	return(-2);
729     if (bytes < 0 || bytes > 32768)
730 	return(-2);
731     n = read(*fdp, buf, bytes);
732     if (n < 0) {
733 	head->error = errno;
734 	return(0);
735     }
736     hcc_leaf_data(hc, LC_DATA, buf, n);
737     return(0);
738 }
739 
740 /*
741  * WRITE
742  */
743 ssize_t
744 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
745 {
746     struct HCHead *head;
747     struct HCLeaf *item;
748     int *fdp;
749     int r;
750 
751     if (hc == NULL || hc->host == NULL)
752 	return(write(fd, buf, bytes));
753 
754     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
755     if (fdp) {
756 	r = 0;
757 	while (bytes) {
758 	    int n = (bytes > 32768) ? 32768 : bytes;
759 	    int x = 0;
760 
761 	    hcc_start_command(hc, HC_WRITE);
762 	    hcc_leaf_int32(hc, LC_DESCRIPTOR, fd);
763 	    hcc_leaf_data(hc, LC_DATA, buf, n);
764 	    if ((head = hcc_finish_command(hc)) == NULL)
765 		return(-1);
766 	    if (head->error)
767 		return(-1);
768 	    for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
769 		switch(item->leafid) {
770 		case LC_BYTES:
771 		    x = HCC_INT32(item);
772 		    break;
773 		}
774 	    }
775 	    if (x < 0 || x > n)
776 		return(-1);
777 	    r += x;
778 	    buf = (const char *)buf + x;
779 	    bytes -= x;
780 	    if (x < n)
781 		break;
782 	}
783 	return(r);
784     } else {
785 	return(-1);
786     }
787 }
788 
789 static int
790 rc_write(struct HostConf *hc, struct HCHead *head)
791 {
792     struct HCLeaf *item;
793     int *fdp = NULL;
794     void *buf = NULL;
795     int n = -1;
796 
797     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
798 	switch(item->leafid) {
799 	case LC_DESCRIPTOR:
800 	    fdp = hcc_get_descriptor(hc, HCC_INT32(item), HC_DESC_FD);
801 	    break;
802 	case LC_DATA:
803 	    buf = HCC_BINARYDATA(item);
804 	    n = item->bytes - sizeof(*item);
805 	    break;
806 	}
807     }
808     if (fdp == NULL)
809 	return(-2);
810     if (n < 0 || n > 32768)
811 	return(-2);
812     n = write(*fdp, buf, n);
813     if (n < 0) {
814 	head->error = errno;
815     } else {
816 	hcc_leaf_int32(hc, LC_BYTES, n);
817     }
818     return(0);
819 }
820 
821 /*
822  * REMOVE
823  */
824 int
825 hc_remove(struct HostConf *hc, const char *path)
826 {
827     struct HCHead *head;
828 
829     if (hc == NULL || hc->host == NULL)
830 	return(remove(path));
831 
832     hcc_start_command(hc, HC_REMOVE);
833     hcc_leaf_string(hc, LC_PATH1, path);
834     if ((head = hcc_finish_command(hc)) == NULL)
835 	return(-1);
836     if (head->error)
837 	return(-1);
838     return(0);
839 }
840 
841 static int
842 rc_remove(struct HostConf *hc __unused, struct HCHead *head)
843 {
844     struct HCLeaf *item;
845     const char *path = NULL;
846 
847     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
848 	switch(item->leafid) {
849 	case LC_PATH1:
850 	    path = HCC_STRING(item);
851 	    break;
852 	}
853     }
854     if (path == NULL)
855 	return(-2);
856     return(remove(path));
857 }
858 
859 /*
860  * MKDIR
861  */
862 int
863 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
864 {
865     struct HCHead *head;
866 
867     if (hc == NULL || hc->host == NULL)
868 	return(mkdir(path, mode));
869 
870     hcc_start_command(hc, HC_MKDIR);
871     hcc_leaf_string(hc, LC_PATH1, path);
872     hcc_leaf_int32(hc, LC_MODE, mode);
873     if ((head = hcc_finish_command(hc)) == NULL)
874 	return(-1);
875     if (head->error)
876 	return(-1);
877     return(0);
878 }
879 
880 static int
881 rc_mkdir(struct HostConf *hc __unused, struct HCHead *head)
882 {
883     struct HCLeaf *item;
884     const char *path = NULL;
885     mode_t mode = 0777;
886 
887     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
888 	switch(item->leafid) {
889 	case LC_PATH1:
890 	    path = HCC_STRING(item);
891 	    break;
892 	case LC_MODE:
893 	    mode = HCC_INT32(item);
894 	    break;
895 	}
896     }
897     if (path == NULL)
898 	return(-1);
899     return(mkdir(path, mode));
900 }
901 
902 /*
903  * RMDIR
904  */
905 int
906 hc_rmdir(struct HostConf *hc, const char *path)
907 {
908     struct HCHead *head;
909 
910     if (hc == NULL || hc->host == NULL)
911 	return(rmdir(path));
912 
913     hcc_start_command(hc, HC_RMDIR);
914     hcc_leaf_string(hc, LC_PATH1, path);
915     if ((head = hcc_finish_command(hc)) == NULL)
916 	return(-1);
917     if (head->error)
918 	return(-1);
919     return(0);
920 }
921 
922 static int
923 rc_rmdir(struct HostConf *hc __unused, struct HCHead *head)
924 {
925     struct HCLeaf *item;
926     const char *path = NULL;
927 
928     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
929 	switch(item->leafid) {
930 	case LC_PATH1:
931 	    path = HCC_STRING(item);
932 	    break;
933 	}
934     }
935     if (path == NULL)
936 	return(-1);
937     return(rmdir(path));
938 }
939 
940 /*
941  * CHOWN
942  */
943 int
944 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
945 {
946     struct HCHead *head;
947 
948     if (hc == NULL || hc->host == NULL)
949 	return(chown(path, owner, group));
950 
951     hcc_start_command(hc, HC_CHOWN);
952     hcc_leaf_string(hc, LC_PATH1, path);
953     hcc_leaf_int32(hc, LC_UID, owner);
954     hcc_leaf_int32(hc, LC_GID, group);
955     if ((head = hcc_finish_command(hc)) == NULL)
956 	return(-1);
957     if (head->error)
958 	return(-1);
959     return(0);
960 }
961 
962 static int
963 rc_chown(struct HostConf *hc __unused, struct HCHead *head)
964 {
965     struct HCLeaf *item;
966     const char *path = NULL;
967     uid_t uid = (uid_t)-1;
968     gid_t gid = (gid_t)-1;
969 
970     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
971 	switch(item->leafid) {
972 	case LC_PATH1:
973 	    path = HCC_STRING(item);
974 	    break;
975 	case LC_UID:
976 	    uid = HCC_INT32(item);
977 	    break;
978 	case LC_GID:
979 	    gid = HCC_INT32(item);
980 	    break;
981 	}
982     }
983     if (path == NULL)
984 	return(-1);
985     return(chown(path, uid, gid));
986 }
987 
988 /*
989  * LCHOWN
990  */
991 int
992 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
993 {
994     struct HCHead *head;
995 
996     if (hc == NULL || hc->host == NULL)
997 	return(lchown(path, owner, group));
998 
999     hcc_start_command(hc, HC_LCHOWN);
1000     hcc_leaf_string(hc, LC_PATH1, path);
1001     hcc_leaf_int32(hc, LC_UID, owner);
1002     hcc_leaf_int32(hc, LC_GID, group);
1003     if ((head = hcc_finish_command(hc)) == NULL)
1004 	return(-1);
1005     if (head->error)
1006 	return(-1);
1007     return(0);
1008 }
1009 
1010 static int
1011 rc_lchown(struct HostConf *hc __unused, struct HCHead *head)
1012 {
1013     struct HCLeaf *item;
1014     const char *path = NULL;
1015     uid_t uid = (uid_t)-1;
1016     gid_t gid = (gid_t)-1;
1017 
1018     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1019 	switch(item->leafid) {
1020 	case LC_PATH1:
1021 	    path = HCC_STRING(item);
1022 	    break;
1023 	case LC_UID:
1024 	    uid = HCC_INT32(item);
1025 	    break;
1026 	case LC_GID:
1027 	    gid = HCC_INT32(item);
1028 	    break;
1029 	}
1030     }
1031     if (path == NULL)
1032 	return(-1);
1033     return(lchown(path, uid, gid));
1034 }
1035 
1036 /*
1037  * CHMOD
1038  */
1039 int
1040 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1041 {
1042     struct HCHead *head;
1043 
1044     if (hc == NULL || hc->host == NULL)
1045 	return(chmod(path, mode));
1046 
1047     hcc_start_command(hc, HC_CHMOD);
1048     hcc_leaf_string(hc, LC_PATH1, path);
1049     hcc_leaf_int32(hc, LC_MODE, mode);
1050     if ((head = hcc_finish_command(hc)) == NULL)
1051 	return(-1);
1052     if (head->error)
1053 	return(-1);
1054     return(0);
1055 }
1056 
1057 static int
1058 rc_chmod(struct HostConf *hc __unused, struct HCHead *head)
1059 {
1060     struct HCLeaf *item;
1061     const char *path = NULL;
1062     mode_t mode = 0666;
1063 
1064     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1065 	switch(item->leafid) {
1066 	case LC_PATH1:
1067 	    path = HCC_STRING(item);
1068 	    break;
1069 	case LC_MODE:
1070 	    mode = HCC_INT32(item);
1071 	    break;
1072 	}
1073     }
1074     if (path == NULL)
1075 	return(-1);
1076     return(chmod(path, mode));
1077 }
1078 
1079 /*
1080  * LINK
1081  */
1082 int
1083 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1084 {
1085     struct HCHead *head;
1086 
1087     if (hc == NULL || hc->host == NULL)
1088 	return(link(name1, name2));
1089 
1090     hcc_start_command(hc, HC_LINK);
1091     hcc_leaf_string(hc, LC_PATH1, name1);
1092     hcc_leaf_string(hc, LC_PATH2, name2);
1093     if ((head = hcc_finish_command(hc)) == NULL)
1094 	return(-1);
1095     if (head->error)
1096 	return(-1);
1097     return(0);
1098 }
1099 
1100 static int
1101 rc_link(struct HostConf *hc __unused, struct HCHead *head)
1102 {
1103     struct HCLeaf *item;
1104     const char *name1 = NULL;
1105     const char *name2 = NULL;
1106 
1107     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1108 	switch(item->leafid) {
1109 	case LC_PATH1:
1110 	    name1 = HCC_STRING(item);
1111 	    break;
1112 	case LC_PATH2:
1113 	    name2 = HCC_STRING(item);
1114 	    break;
1115 	}
1116     }
1117     if (name1 == NULL || name2 == NULL)
1118 	return(-2);
1119     return(link(name1, name2));
1120 }
1121 
1122 #ifdef _ST_FLAGS_PRESENT_
1123 /*
1124  * CHFLAGS
1125  */
1126 int
1127 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1128 {
1129     struct HCHead *head;
1130 
1131     if (hc == NULL || hc->host == NULL)
1132 	return(chflags(path, flags));
1133 
1134     hcc_start_command(hc, HC_CHFLAGS);
1135     hcc_leaf_string(hc, LC_PATH1, path);
1136     hcc_leaf_int64(hc, LC_FILEFLAGS, flags);
1137     if ((head = hcc_finish_command(hc)) == NULL)
1138 	return(-1);
1139     if (head->error)
1140 	return(-1);
1141     return(0);
1142 }
1143 
1144 static int
1145 rc_chflags(struct HostConf *hc __unused, struct HCHead *head)
1146 {
1147     struct HCLeaf *item;
1148     const char *path = NULL;
1149     u_long flags = 0;
1150 
1151     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1152 	switch(item->leafid) {
1153 	case LC_PATH1:
1154 	    path = HCC_STRING(item);
1155 	    break;
1156 	case LC_FILEFLAGS:
1157 	    flags = (u_long)HCC_INT64(item);
1158 	    break;
1159 	}
1160     }
1161     if (path == NULL)
1162 	return(-2);
1163     return(chflags(path, flags));
1164 }
1165 
1166 #endif
1167 
1168 /*
1169  * READLINK
1170  */
1171 int
1172 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1173 {
1174     struct HCHead *head;
1175     struct HCLeaf *item;
1176     int r;
1177 
1178     if (hc == NULL || hc->host == NULL)
1179 	return(readlink(path, buf, bufsiz));
1180 
1181     hcc_start_command(hc, HC_READLINK);
1182     hcc_leaf_string(hc, LC_PATH1, path);
1183     if ((head = hcc_finish_command(hc)) == NULL)
1184 	return(-1);
1185     if (head->error)
1186 	return(-1);
1187 
1188     r = 0;
1189     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1190 	switch(item->leafid) {
1191 	case LC_DATA:
1192 	    r = item->bytes - sizeof(*item);
1193 	    if (r < 0)
1194 		r = 0;
1195 	    if (r > bufsiz)
1196 		r = bufsiz;
1197 	    bcopy(HCC_BINARYDATA(item), buf, r);
1198 	    break;
1199 	}
1200     }
1201     return(r);
1202 }
1203 
1204 static int
1205 rc_readlink(struct HostConf *hc, struct HCHead *head)
1206 {
1207     struct HCLeaf *item;
1208     const char *path = NULL;
1209     char buf[1024];
1210     int r;
1211 
1212     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1213 	switch(item->leafid) {
1214 	case LC_PATH1:
1215 	    path = HCC_STRING(item);
1216 	    break;
1217 	}
1218     }
1219     if (path == NULL)
1220 	return(-2);
1221     r = readlink(path, buf, sizeof(buf));
1222     if (r < 0)
1223 	return(-1);
1224     hcc_leaf_data(hc, LC_DATA, buf, r);
1225     return(0);
1226 }
1227 
1228 /*
1229  * UMASK
1230  */
1231 mode_t
1232 hc_umask(struct HostConf *hc, mode_t numask)
1233 {
1234     struct HCHead *head;
1235     struct HCLeaf *item;
1236 
1237     if (hc == NULL || hc->host == NULL)
1238 	return(umask(numask));
1239 
1240     hcc_start_command(hc, HC_UMASK);
1241     hcc_leaf_int32(hc, LC_MODE, numask);
1242     if ((head = hcc_finish_command(hc)) == NULL)
1243 	return((mode_t)-1);
1244     if (head->error)
1245 	return((mode_t)-1);
1246 
1247     numask = ~0666;
1248     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1249 	switch(item->leafid) {
1250 	case LC_MODE:
1251 	    numask = HCC_INT32(item);
1252 	    break;
1253 	}
1254     }
1255     return(numask);
1256 }
1257 
1258 static int
1259 rc_umask(struct HostConf *hc, struct HCHead *head)
1260 {
1261     struct HCLeaf *item;
1262     mode_t numask = ~0666;
1263 
1264     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1265 	switch(item->leafid) {
1266 	case LC_MODE:
1267 	    numask = HCC_INT32(item);
1268 	    break;
1269 	}
1270     }
1271     numask = umask(numask);
1272     hcc_leaf_int32(hc, LC_MODE, numask);
1273     return(0);
1274 }
1275 
1276 /*
1277  * SYMLINK
1278  */
1279 int
1280 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1281 {
1282     struct HCHead *head;
1283 
1284     if (hc == NULL || hc->host == NULL)
1285 	return(symlink(name1, name2));
1286 
1287     hcc_start_command(hc, HC_SYMLINK);
1288     hcc_leaf_string(hc, LC_PATH1, name1);
1289     hcc_leaf_string(hc, LC_PATH2, name2);
1290     if ((head = hcc_finish_command(hc)) == NULL)
1291 	return(-1);
1292     if (head->error)
1293 	return(-1);
1294     return(0);
1295 }
1296 
1297 static int
1298 rc_symlink(struct HostConf *hc __unused, struct HCHead *head)
1299 {
1300     struct HCLeaf *item;
1301     const char *name1 = NULL;
1302     const char *name2 = NULL;
1303 
1304     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1305 	switch(item->leafid) {
1306 	case LC_PATH1:
1307 	    name1 = HCC_STRING(item);
1308 	    break;
1309 	case LC_PATH2:
1310 	    name2 = HCC_STRING(item);
1311 	    break;
1312 	}
1313     }
1314     if (name1 == NULL || name2 == NULL)
1315 	return(-2);
1316     return(symlink(name1, name2));
1317 }
1318 
1319 /*
1320  * RENAME
1321  */
1322 int
1323 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1324 {
1325     struct HCHead *head;
1326 
1327     if (hc == NULL || hc->host == NULL)
1328 	return(rename(name1, name2));
1329 
1330     hcc_start_command(hc, HC_RENAME);
1331     hcc_leaf_string(hc, LC_PATH1, name1);
1332     hcc_leaf_string(hc, LC_PATH2, name2);
1333     if ((head = hcc_finish_command(hc)) == NULL)
1334 	return(-1);
1335     if (head->error)
1336 	return(-1);
1337     return(0);
1338 }
1339 
1340 static int
1341 rc_rename(struct HostConf *hc __unused, struct HCHead *head)
1342 {
1343     struct HCLeaf *item;
1344     const char *name1 = NULL;
1345     const char *name2 = NULL;
1346 
1347     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1348 	switch(item->leafid) {
1349 	case LC_PATH1:
1350 	    name1 = HCC_STRING(item);
1351 	    break;
1352 	case LC_PATH2:
1353 	    name2 = HCC_STRING(item);
1354 	    break;
1355 	}
1356     }
1357     if (name1 == NULL || name2 == NULL)
1358 	return(-2);
1359     return(rename(name1, name2));
1360 }
1361 
1362 /*
1363  * UTIMES
1364  */
1365 int
1366 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1367 {
1368     struct HCHead *head;
1369 
1370     if (hc == NULL || hc->host == NULL)
1371 	return(utimes(path, times));
1372 
1373     hcc_start_command(hc, HC_UTIMES);
1374     hcc_leaf_string(hc, LC_PATH1, path);
1375     hcc_leaf_int64(hc, LC_ATIME, times[0].tv_sec);
1376     hcc_leaf_int64(hc, LC_MTIME, times[1].tv_sec);
1377     if ((head = hcc_finish_command(hc)) == NULL)
1378 	return(-1);
1379     if (head->error)
1380 	return(-1);
1381     return(0);
1382 }
1383 
1384 static int
1385 rc_utimes(struct HostConf *hc __unused, struct HCHead *head)
1386 {
1387     struct HCLeaf *item;
1388     struct timeval times[2];
1389     const char *path;
1390 
1391     bzero(times, sizeof(times));
1392     path = NULL;
1393 
1394     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1395 	switch(item->leafid) {
1396 	case LC_PATH1:
1397 	    path = HCC_STRING(item);
1398 	    break;
1399 	case LC_ATIME:
1400 	    times[0].tv_sec = HCC_INT64(item);
1401 	    break;
1402 	case LC_MTIME:
1403 	    times[1].tv_sec = HCC_INT64(item);
1404 	    break;
1405 	}
1406     }
1407     if (path == NULL)
1408 	return(-2);
1409     return(utimes(path, times));
1410 }
1411