MFC if_ethersubr.c rev1.77:
[dragonfly.git] / bin / cpdup / hcproto.c
blobe5fa3b710fc424f0a1d820704787f54eabdae40c
1 /*
2 * HCPROTO.C
4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hcproto.c,v 1.6 2008/04/16 17:38:19 dillon Exp $
7 */
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
13 static int hc_decode_stat(struct stat *, struct HCHead *);
14 static int rc_encode_stat(hctransaction_t trans, struct stat *);
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 *);
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 },
72 int
73 hc_connect(struct HostConf *hc)
75 if (hcc_connect(hc) < 0) {
76 fprintf(stderr, "Unable to connect to %s\n", hc->host);
77 return(-1);
79 return(hc_hello(hc));
82 void
83 hc_slave(int fdin, int fdout)
85 hcc_slave(fdin, fdout, HCDispatchTable,
86 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
91 * A HELLO RPC is sent on the initial connect.
93 int
94 hc_hello(struct HostConf *hc)
96 struct HCHead *head;
97 struct HCLeaf *item;
98 hctransaction_t trans;
99 char hostbuf[256];
100 int error;
102 bzero(hostbuf, sizeof(hostbuf));
103 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
104 return(-1);
105 if (hostbuf[0] == 0)
106 hostbuf[0] = '?';
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);
117 if (head->error) {
118 fprintf(stderr, "Connected to %s but remote returned error %d\n",
119 hc->host, head->error);
120 return(-1);
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;
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;
140 if (error < 0)
141 fprintf(stderr, "Handshake failed with %s\n", hc->host);
142 return (error);
145 static int
146 rc_hello(hctransaction_t trans, struct HCHead *head __unused)
148 char hostbuf[256];
150 bzero(hostbuf, sizeof(hostbuf));
151 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
152 return(-1);
153 if (hostbuf[0] == 0)
154 hostbuf[0] = '?';
156 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
157 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
158 return(0);
162 * STAT, LSTAT
165 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
167 struct HCHead *head;
168 hctransaction_t trans;
170 if (hc == NULL || hc->host == NULL)
171 return(stat(path, st));
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));
183 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
185 struct HCHead *head;
186 hctransaction_t trans;
188 if (hc == NULL || hc->host == NULL)
189 return(lstat(path, st));
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));
200 static int
201 hc_decode_stat(struct stat *st, struct HCHead *head)
203 struct HCLeaf *item;
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
259 return(0);
262 static int
263 rc_stat(hctransaction_t trans, struct HCHead *head)
265 struct HCLeaf *item;
266 struct stat st;
267 const char *path = NULL;
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;
276 if (path == NULL)
277 return(-2);
278 if (stat(path, &st) < 0)
279 return(-1);
280 return (rc_encode_stat(trans, &st));
283 static int
284 rc_lstat(hctransaction_t trans, struct HCHead *head)
286 struct HCLeaf *item;
287 struct stat st;
288 const char *path = NULL;
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;
297 if (path == NULL)
298 return(-2);
299 if (lstat(path, &st) < 0)
300 return(-1);
301 return (rc_encode_stat(trans, &st));
304 static int
305 rc_encode_stat(hctransaction_t trans, struct stat *st)
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);
330 * OPENDIR
332 DIR *
333 hc_opendir(struct HostConf *hc, const char *path)
335 hctransaction_t trans;
336 struct HCHead *head;
337 struct HCLeaf *item;
338 struct dirent *den;
339 int desc = 0;
341 if (hc == NULL || hc->host == NULL)
342 return(opendir(path));
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;
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);
362 den = malloc(sizeof(*den));
363 bzero(den, sizeof(*den));
364 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
365 return((void *)desc);
368 static int
369 rc_opendir(hctransaction_t trans, struct HCHead *head)
371 struct HCLeaf *item;
372 const char *path = NULL;
373 DIR *dir;
374 int desc;
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;
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);
391 return(0);
395 * READDIR
397 struct dirent *
398 hc_readdir(struct HostConf *hc, DIR *dir)
400 hctransaction_t trans;
401 struct HCHead *head;
402 struct HCLeaf *item;
403 struct dirent *den;
405 if (hc == NULL || hc->host == NULL)
406 return(readdir(dir));
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;
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);
438 return(NULL); /* XXX errno */
441 static int
442 rc_readdir(hctransaction_t trans, struct HCHead *head)
444 struct HCLeaf *item;
445 struct dirent *den;
446 DIR *dir = NULL;
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;
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);
462 return(0);
466 * CLOSEDIR
468 * XXX cpdup needs to check error code to avoid truncated dirs?
471 hc_closedir(struct HostConf *hc, DIR *dir)
473 hctransaction_t trans;
474 struct HCHead *head;
475 struct dirent *den;
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);
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);
497 static int
498 rc_closedir(hctransaction_t trans, struct HCHead *head)
500 struct HCLeaf *item;
501 DIR *dir = NULL;
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;
512 if (dir == NULL)
513 return(-2);
514 return(closedir(dir));
518 * OPEN
521 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
523 hctransaction_t trans;
524 struct HCHead *head;
525 struct HCLeaf *item;
526 int *fdp;
527 int desc = 0;
528 int nflags;
530 if (hc == NULL || hc->host == NULL) {
531 #ifdef O_LARGEFILE
532 flags |= O_LARGEFILE;
533 #endif
534 return(open(path, flags, mode));
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;
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);
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;
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);
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);
572 static int
573 rc_open(hctransaction_t trans, struct HCHead *head)
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;
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;
597 if (path == NULL)
598 return(-2);
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;
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);
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);
623 * CLOSE
626 hc_close(struct HostConf *hc, int fd)
628 hctransaction_t trans;
629 struct HCHead *head;
630 int *fdp;
632 if (hc == NULL || hc->host == NULL)
633 return(close(fd));
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);
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);
652 static int
653 rc_close(hctransaction_t trans, struct HCHead *head)
655 struct HCLeaf *item;
656 int *fdp = NULL;
657 int fd;
658 int desc = -1;
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;
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));
677 static int
678 getiolimit(void)
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
694 * READ
696 ssize_t
697 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
699 hctransaction_t trans;
700 struct HCHead *head;
701 struct HCLeaf *item;
702 int *fdp;
703 int r;
705 if (hc == NULL || hc->host == NULL)
706 return(read(fd, buf, bytes));
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;
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;
736 if (x < n)
737 break;
739 return(r);
740 } else {
741 return(-1);
745 static int
746 rc_read(hctransaction_t trans, struct HCHead *head)
748 struct HCLeaf *item;
749 int *fdp = NULL;
750 char buf[32768];
751 int bytes = -1;
752 int n;
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;
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);
773 hcc_leaf_data(trans, LC_DATA, buf, n);
774 return(0);
778 * WRITE
780 ssize_t
781 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
783 hctransaction_t trans;
784 struct HCHead *head;
785 struct HCLeaf *item;
786 int *fdp;
787 int r;
789 if (hc == NULL || hc->host == NULL)
790 return(write(fd, buf, bytes));
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;
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;
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;
822 return(r);
823 } else {
824 return(-1);
828 static int
829 rc_write(hctransaction_t trans, struct HCHead *head)
831 struct HCLeaf *item;
832 int *fdp = NULL;
833 void *buf = NULL;
834 int n = -1;
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;
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);
857 return(0);
861 * REMOVE
864 hc_remove(struct HostConf *hc, const char *path)
866 hctransaction_t trans;
867 struct HCHead *head;
869 if (hc == NULL || hc->host == NULL)
870 return(remove(path));
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);
881 static int
882 rc_remove(hctransaction_t trans __unused, struct HCHead *head)
884 struct HCLeaf *item;
885 const char *path = NULL;
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;
894 if (path == NULL)
895 return(-2);
896 return(remove(path));
900 * MKDIR
903 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
905 hctransaction_t trans;
906 struct HCHead *head;
908 if (hc == NULL || hc->host == NULL)
909 return(mkdir(path, mode));
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);
921 static int
922 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head)
924 struct HCLeaf *item;
925 const char *path = NULL;
926 mode_t mode = 0777;
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;
938 if (path == NULL)
939 return(-1);
940 return(mkdir(path, mode));
944 * RMDIR
947 hc_rmdir(struct HostConf *hc, const char *path)
949 hctransaction_t trans;
950 struct HCHead *head;
952 if (hc == NULL || hc->host == NULL)
953 return(rmdir(path));
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);
964 static int
965 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head)
967 struct HCLeaf *item;
968 const char *path = NULL;
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;
977 if (path == NULL)
978 return(-1);
979 return(rmdir(path));
983 * CHOWN
986 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
988 hctransaction_t trans;
989 struct HCHead *head;
991 if (hc == NULL || hc->host == NULL)
992 return(chown(path, owner, group));
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);
1005 static int
1006 rc_chown(hctransaction_t trans __unused, struct HCHead *head)
1008 struct HCLeaf *item;
1009 const char *path = NULL;
1010 uid_t uid = (uid_t)-1;
1011 gid_t gid = (gid_t)-1;
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;
1026 if (path == NULL)
1027 return(-1);
1028 return(chown(path, uid, gid));
1032 * LCHOWN
1035 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1037 hctransaction_t trans;
1038 struct HCHead *head;
1040 if (hc == NULL || hc->host == NULL)
1041 return(lchown(path, owner, group));
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);
1054 static int
1055 rc_lchown(hctransaction_t trans __unused, struct HCHead *head)
1057 struct HCLeaf *item;
1058 const char *path = NULL;
1059 uid_t uid = (uid_t)-1;
1060 gid_t gid = (gid_t)-1;
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;
1075 if (path == NULL)
1076 return(-1);
1077 return(lchown(path, uid, gid));
1081 * CHMOD
1084 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1086 hctransaction_t trans;
1087 struct HCHead *head;
1089 if (hc == NULL || hc->host == NULL)
1090 return(chmod(path, mode));
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);
1102 static int
1103 rc_chmod(hctransaction_t trans __unused, struct HCHead *head)
1105 struct HCLeaf *item;
1106 const char *path = NULL;
1107 mode_t mode = 0666;
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;
1119 if (path == NULL)
1120 return(-1);
1121 return(chmod(path, mode));
1125 * MKNOD
1128 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1130 hctransaction_t trans;
1131 struct HCHead *head;
1133 if (hc == NULL || hc->host == NULL)
1134 return(mknod(path, mode, rdev));
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);
1147 static int
1148 rc_mknod(hctransaction_t trans __unused, struct HCHead *head)
1150 struct HCLeaf *item;
1151 const char *path = NULL;
1152 mode_t mode = 0666;
1153 dev_t rdev = 0;
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;
1168 if (path == NULL)
1169 return(-1);
1170 return(mknod(path, mode, rdev));
1174 * LINK
1177 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1179 hctransaction_t trans;
1180 struct HCHead *head;
1182 if (hc == NULL || hc->host == NULL)
1183 return(link(name1, name2));
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);
1195 static int
1196 rc_link(hctransaction_t trans __unused, struct HCHead *head)
1198 struct HCLeaf *item;
1199 const char *name1 = NULL;
1200 const char *name2 = NULL;
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;
1212 if (name1 == NULL || name2 == NULL)
1213 return(-2);
1214 return(link(name1, name2));
1217 #ifdef _ST_FLAGS_PRESENT_
1219 * CHFLAGS
1222 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1224 hctransaction_t trans;
1225 struct HCHead *head;
1227 if (hc == NULL || hc->host == NULL)
1228 return(chflags(path, flags));
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);
1240 static int
1241 rc_chflags(hctransaction_t trans __unused, struct HCHead *head)
1243 struct HCLeaf *item;
1244 const char *path = NULL;
1245 u_long flags = 0;
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;
1257 if (path == NULL)
1258 return(-2);
1259 return(chflags(path, flags));
1262 #endif
1265 * READLINK
1268 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1270 hctransaction_t trans;
1271 struct HCHead *head;
1272 struct HCLeaf *item;
1273 int r;
1275 if (hc == NULL || hc->host == NULL)
1276 return(readlink(path, buf, bufsiz));
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);
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;
1298 return(r);
1301 static int
1302 rc_readlink(hctransaction_t trans, struct HCHead *head)
1304 struct HCLeaf *item;
1305 const char *path = NULL;
1306 char buf[1024];
1307 int r;
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;
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);
1326 * UMASK
1328 mode_t
1329 hc_umask(struct HostConf *hc, mode_t numask)
1331 hctransaction_t trans;
1332 struct HCHead *head;
1333 struct HCLeaf *item;
1335 if (hc == NULL || hc->host == NULL)
1336 return(umask(numask));
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);
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;
1353 return(numask);
1356 static int
1357 rc_umask(hctransaction_t trans, struct HCHead *head)
1359 struct HCLeaf *item;
1360 mode_t numask = ~0666;
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;
1369 numask = umask(numask);
1370 hcc_leaf_int32(trans, LC_MODE, numask);
1371 return(0);
1375 * SYMLINK
1378 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1380 hctransaction_t trans;
1381 struct HCHead *head;
1383 if (hc == NULL || hc->host == NULL)
1384 return(symlink(name1, name2));
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);
1396 static int
1397 rc_symlink(hctransaction_t trans __unused, struct HCHead *head)
1399 struct HCLeaf *item;
1400 const char *name1 = NULL;
1401 const char *name2 = NULL;
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;
1413 if (name1 == NULL || name2 == NULL)
1414 return(-2);
1415 return(symlink(name1, name2));
1419 * RENAME
1422 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1424 hctransaction_t trans;
1425 struct HCHead *head;
1427 if (hc == NULL || hc->host == NULL)
1428 return(rename(name1, name2));
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);
1440 static int
1441 rc_rename(hctransaction_t trans __unused, struct HCHead *head)
1443 struct HCLeaf *item;
1444 const char *name1 = NULL;
1445 const char *name2 = NULL;
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;
1457 if (name1 == NULL || name2 == NULL)
1458 return(-2);
1459 return(rename(name1, name2));
1463 * UTIMES
1466 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1468 hctransaction_t trans;
1469 struct HCHead *head;
1471 if (hc == NULL || hc->host == NULL)
1472 return(utimes(path, times));
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);
1485 static int
1486 rc_utimes(hctransaction_t trans __unused, struct HCHead *head)
1488 struct HCLeaf *item;
1489 struct timeval times[2];
1490 const char *path;
1492 bzero(times, sizeof(times));
1493 path = NULL;
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;
1508 if (path == NULL)
1509 return(-2);
1510 return(utimes(path, times));