Merge from vendor branch LESS:
[dragonfly.git] / bin / cpdup / hcproto.c
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 }