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