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