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