Oops, remove '*'.
[dragonfly.git] / bin / cpdup / hcproto.c
blob2f812acb2ac6c1784a32a0923dca1c7f59eb49d3
1 /*
2 * HCPROTO.C
4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hcproto.c,v 1.8 2008/11/11 04:36:00 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 intptr_t 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 %jd\n",
359 (intmax_t)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, (intptr_t)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, (intptr_t)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, (intptr_t)dir, HC_DESC_DIR);
480 if (den) {
481 free(den);
482 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
484 trans = hcc_start_command(hc, HC_CLOSEDIR);
485 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)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
863 * NOTE: This function returns -errno if an error occured.
866 hc_remove(struct HostConf *hc, const char *path)
868 hctransaction_t trans;
869 struct HCHead *head;
870 int res;
872 if (hc == NULL || hc->host == NULL) {
873 res = remove(path);
874 if (res < 0)
875 res = -errno;
876 return(res);
879 trans = hcc_start_command(hc, HC_REMOVE);
880 hcc_leaf_string(trans, LC_PATH1, path);
881 if ((head = hcc_finish_command(trans)) == NULL)
882 return(-EIO);
883 if (head->error)
884 return(-(int)head->error);
885 return(0);
888 static int
889 rc_remove(hctransaction_t trans __unused, struct HCHead *head)
891 struct HCLeaf *item;
892 const char *path = NULL;
894 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
895 switch(item->leafid) {
896 case LC_PATH1:
897 path = HCC_STRING(item);
898 break;
901 if (path == NULL)
902 return(-2);
903 return(remove(path));
907 * MKDIR
910 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
912 hctransaction_t trans;
913 struct HCHead *head;
915 if (hc == NULL || hc->host == NULL)
916 return(mkdir(path, mode));
918 trans = hcc_start_command(hc, HC_MKDIR);
919 hcc_leaf_string(trans, LC_PATH1, path);
920 hcc_leaf_int32(trans, LC_MODE, mode);
921 if ((head = hcc_finish_command(trans)) == NULL)
922 return(-1);
923 if (head->error)
924 return(-1);
925 return(0);
928 static int
929 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head)
931 struct HCLeaf *item;
932 const char *path = NULL;
933 mode_t mode = 0777;
935 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
936 switch(item->leafid) {
937 case LC_PATH1:
938 path = HCC_STRING(item);
939 break;
940 case LC_MODE:
941 mode = HCC_INT32(item);
942 break;
945 if (path == NULL)
946 return(-1);
947 return(mkdir(path, mode));
951 * RMDIR
954 hc_rmdir(struct HostConf *hc, const char *path)
956 hctransaction_t trans;
957 struct HCHead *head;
959 if (hc == NULL || hc->host == NULL)
960 return(rmdir(path));
962 trans = hcc_start_command(hc, HC_RMDIR);
963 hcc_leaf_string(trans, LC_PATH1, path);
964 if ((head = hcc_finish_command(trans)) == NULL)
965 return(-1);
966 if (head->error)
967 return(-1);
968 return(0);
971 static int
972 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head)
974 struct HCLeaf *item;
975 const char *path = NULL;
977 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
978 switch(item->leafid) {
979 case LC_PATH1:
980 path = HCC_STRING(item);
981 break;
984 if (path == NULL)
985 return(-1);
986 return(rmdir(path));
990 * CHOWN
993 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
995 hctransaction_t trans;
996 struct HCHead *head;
998 if (hc == NULL || hc->host == NULL)
999 return(chown(path, owner, group));
1001 trans = hcc_start_command(hc, HC_CHOWN);
1002 hcc_leaf_string(trans, LC_PATH1, path);
1003 hcc_leaf_int32(trans, LC_UID, owner);
1004 hcc_leaf_int32(trans, LC_GID, group);
1005 if ((head = hcc_finish_command(trans)) == NULL)
1006 return(-1);
1007 if (head->error)
1008 return(-1);
1009 return(0);
1012 static int
1013 rc_chown(hctransaction_t trans __unused, struct HCHead *head)
1015 struct HCLeaf *item;
1016 const char *path = NULL;
1017 uid_t uid = (uid_t)-1;
1018 gid_t gid = (gid_t)-1;
1020 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1021 switch(item->leafid) {
1022 case LC_PATH1:
1023 path = HCC_STRING(item);
1024 break;
1025 case LC_UID:
1026 uid = HCC_INT32(item);
1027 break;
1028 case LC_GID:
1029 gid = HCC_INT32(item);
1030 break;
1033 if (path == NULL)
1034 return(-1);
1035 return(chown(path, uid, gid));
1039 * LCHOWN
1042 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1044 hctransaction_t trans;
1045 struct HCHead *head;
1047 if (hc == NULL || hc->host == NULL)
1048 return(lchown(path, owner, group));
1050 trans = hcc_start_command(hc, HC_LCHOWN);
1051 hcc_leaf_string(trans, LC_PATH1, path);
1052 hcc_leaf_int32(trans, LC_UID, owner);
1053 hcc_leaf_int32(trans, LC_GID, group);
1054 if ((head = hcc_finish_command(trans)) == NULL)
1055 return(-1);
1056 if (head->error)
1057 return(-1);
1058 return(0);
1061 static int
1062 rc_lchown(hctransaction_t trans __unused, struct HCHead *head)
1064 struct HCLeaf *item;
1065 const char *path = NULL;
1066 uid_t uid = (uid_t)-1;
1067 gid_t gid = (gid_t)-1;
1069 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1070 switch(item->leafid) {
1071 case LC_PATH1:
1072 path = HCC_STRING(item);
1073 break;
1074 case LC_UID:
1075 uid = HCC_INT32(item);
1076 break;
1077 case LC_GID:
1078 gid = HCC_INT32(item);
1079 break;
1082 if (path == NULL)
1083 return(-1);
1084 return(lchown(path, uid, gid));
1088 * CHMOD
1091 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1093 hctransaction_t trans;
1094 struct HCHead *head;
1096 if (hc == NULL || hc->host == NULL)
1097 return(chmod(path, mode));
1099 trans = hcc_start_command(hc, HC_CHMOD);
1100 hcc_leaf_string(trans, LC_PATH1, path);
1101 hcc_leaf_int32(trans, LC_MODE, mode);
1102 if ((head = hcc_finish_command(trans)) == NULL)
1103 return(-1);
1104 if (head->error)
1105 return(-1);
1106 return(0);
1109 static int
1110 rc_chmod(hctransaction_t trans __unused, struct HCHead *head)
1112 struct HCLeaf *item;
1113 const char *path = NULL;
1114 mode_t mode = 0666;
1116 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1117 switch(item->leafid) {
1118 case LC_PATH1:
1119 path = HCC_STRING(item);
1120 break;
1121 case LC_MODE:
1122 mode = HCC_INT32(item);
1123 break;
1126 if (path == NULL)
1127 return(-1);
1128 return(chmod(path, mode));
1132 * MKNOD
1135 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1137 hctransaction_t trans;
1138 struct HCHead *head;
1140 if (hc == NULL || hc->host == NULL)
1141 return(mknod(path, mode, rdev));
1143 trans = hcc_start_command(hc, HC_MKNOD);
1144 hcc_leaf_string(trans, LC_PATH1, path);
1145 hcc_leaf_int32(trans, LC_MODE, mode);
1146 hcc_leaf_int32(trans, LC_RDEV, rdev);
1147 if ((head = hcc_finish_command(trans)) == NULL)
1148 return(-1);
1149 if (head->error)
1150 return(-1);
1151 return(0);
1154 static int
1155 rc_mknod(hctransaction_t trans __unused, struct HCHead *head)
1157 struct HCLeaf *item;
1158 const char *path = NULL;
1159 mode_t mode = 0666;
1160 dev_t rdev = 0;
1162 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1163 switch(item->leafid) {
1164 case LC_PATH1:
1165 path = HCC_STRING(item);
1166 break;
1167 case LC_MODE:
1168 mode = HCC_INT32(item);
1169 break;
1170 case LC_RDEV:
1171 rdev = HCC_INT32(item);
1172 break;
1175 if (path == NULL)
1176 return(-1);
1177 return(mknod(path, mode, rdev));
1181 * LINK
1184 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1186 hctransaction_t trans;
1187 struct HCHead *head;
1189 if (hc == NULL || hc->host == NULL)
1190 return(link(name1, name2));
1192 trans = hcc_start_command(hc, HC_LINK);
1193 hcc_leaf_string(trans, LC_PATH1, name1);
1194 hcc_leaf_string(trans, LC_PATH2, name2);
1195 if ((head = hcc_finish_command(trans)) == NULL)
1196 return(-1);
1197 if (head->error)
1198 return(-1);
1199 return(0);
1202 static int
1203 rc_link(hctransaction_t trans __unused, struct HCHead *head)
1205 struct HCLeaf *item;
1206 const char *name1 = NULL;
1207 const char *name2 = NULL;
1209 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1210 switch(item->leafid) {
1211 case LC_PATH1:
1212 name1 = HCC_STRING(item);
1213 break;
1214 case LC_PATH2:
1215 name2 = HCC_STRING(item);
1216 break;
1219 if (name1 == NULL || name2 == NULL)
1220 return(-2);
1221 return(link(name1, name2));
1224 #ifdef _ST_FLAGS_PRESENT_
1226 * CHFLAGS
1229 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1231 hctransaction_t trans;
1232 struct HCHead *head;
1234 if (hc == NULL || hc->host == NULL)
1235 return(chflags(path, flags));
1237 trans = hcc_start_command(hc, HC_CHFLAGS);
1238 hcc_leaf_string(trans, LC_PATH1, path);
1239 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1240 if ((head = hcc_finish_command(trans)) == NULL)
1241 return(-1);
1242 if (head->error)
1243 return(-1);
1244 return(0);
1247 static int
1248 rc_chflags(hctransaction_t trans __unused, struct HCHead *head)
1250 struct HCLeaf *item;
1251 const char *path = NULL;
1252 u_long flags = 0;
1254 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1255 switch(item->leafid) {
1256 case LC_PATH1:
1257 path = HCC_STRING(item);
1258 break;
1259 case LC_FILEFLAGS:
1260 flags = (u_long)HCC_INT64(item);
1261 break;
1264 if (path == NULL)
1265 return(-2);
1266 return(chflags(path, flags));
1269 #endif
1272 * READLINK
1275 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1277 hctransaction_t trans;
1278 struct HCHead *head;
1279 struct HCLeaf *item;
1280 int r;
1282 if (hc == NULL || hc->host == NULL)
1283 return(readlink(path, buf, bufsiz));
1285 trans = hcc_start_command(hc, HC_READLINK);
1286 hcc_leaf_string(trans, LC_PATH1, path);
1287 if ((head = hcc_finish_command(trans)) == NULL)
1288 return(-1);
1289 if (head->error)
1290 return(-1);
1292 r = 0;
1293 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1294 switch(item->leafid) {
1295 case LC_DATA:
1296 r = item->bytes - sizeof(*item);
1297 if (r < 0)
1298 r = 0;
1299 if (r > bufsiz)
1300 r = bufsiz;
1301 bcopy(HCC_BINARYDATA(item), buf, r);
1302 break;
1305 return(r);
1308 static int
1309 rc_readlink(hctransaction_t trans, struct HCHead *head)
1311 struct HCLeaf *item;
1312 const char *path = NULL;
1313 char buf[1024];
1314 int r;
1316 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1317 switch(item->leafid) {
1318 case LC_PATH1:
1319 path = HCC_STRING(item);
1320 break;
1323 if (path == NULL)
1324 return(-2);
1325 r = readlink(path, buf, sizeof(buf));
1326 if (r < 0)
1327 return(-1);
1328 hcc_leaf_data(trans, LC_DATA, buf, r);
1329 return(0);
1333 * UMASK
1335 mode_t
1336 hc_umask(struct HostConf *hc, mode_t numask)
1338 hctransaction_t trans;
1339 struct HCHead *head;
1340 struct HCLeaf *item;
1342 if (hc == NULL || hc->host == NULL)
1343 return(umask(numask));
1345 trans = hcc_start_command(hc, HC_UMASK);
1346 hcc_leaf_int32(trans, LC_MODE, numask);
1347 if ((head = hcc_finish_command(trans)) == NULL)
1348 return((mode_t)-1);
1349 if (head->error)
1350 return((mode_t)-1);
1352 numask = ~0666;
1353 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1354 switch(item->leafid) {
1355 case LC_MODE:
1356 numask = HCC_INT32(item);
1357 break;
1360 return(numask);
1363 static int
1364 rc_umask(hctransaction_t trans, struct HCHead *head)
1366 struct HCLeaf *item;
1367 mode_t numask = ~0666;
1369 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1370 switch(item->leafid) {
1371 case LC_MODE:
1372 numask = HCC_INT32(item);
1373 break;
1376 numask = umask(numask);
1377 hcc_leaf_int32(trans, LC_MODE, numask);
1378 return(0);
1382 * SYMLINK
1385 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1387 hctransaction_t trans;
1388 struct HCHead *head;
1390 if (hc == NULL || hc->host == NULL)
1391 return(symlink(name1, name2));
1393 trans = hcc_start_command(hc, HC_SYMLINK);
1394 hcc_leaf_string(trans, LC_PATH1, name1);
1395 hcc_leaf_string(trans, LC_PATH2, name2);
1396 if ((head = hcc_finish_command(trans)) == NULL)
1397 return(-1);
1398 if (head->error)
1399 return(-1);
1400 return(0);
1403 static int
1404 rc_symlink(hctransaction_t trans __unused, struct HCHead *head)
1406 struct HCLeaf *item;
1407 const char *name1 = NULL;
1408 const char *name2 = NULL;
1410 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1411 switch(item->leafid) {
1412 case LC_PATH1:
1413 name1 = HCC_STRING(item);
1414 break;
1415 case LC_PATH2:
1416 name2 = HCC_STRING(item);
1417 break;
1420 if (name1 == NULL || name2 == NULL)
1421 return(-2);
1422 return(symlink(name1, name2));
1426 * RENAME
1429 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1431 hctransaction_t trans;
1432 struct HCHead *head;
1434 if (hc == NULL || hc->host == NULL)
1435 return(rename(name1, name2));
1437 trans = hcc_start_command(hc, HC_RENAME);
1438 hcc_leaf_string(trans, LC_PATH1, name1);
1439 hcc_leaf_string(trans, LC_PATH2, name2);
1440 if ((head = hcc_finish_command(trans)) == NULL)
1441 return(-1);
1442 if (head->error)
1443 return(-1);
1444 return(0);
1447 static int
1448 rc_rename(hctransaction_t trans __unused, struct HCHead *head)
1450 struct HCLeaf *item;
1451 const char *name1 = NULL;
1452 const char *name2 = NULL;
1454 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1455 switch(item->leafid) {
1456 case LC_PATH1:
1457 name1 = HCC_STRING(item);
1458 break;
1459 case LC_PATH2:
1460 name2 = HCC_STRING(item);
1461 break;
1464 if (name1 == NULL || name2 == NULL)
1465 return(-2);
1466 return(rename(name1, name2));
1470 * UTIMES
1473 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1475 hctransaction_t trans;
1476 struct HCHead *head;
1478 if (hc == NULL || hc->host == NULL)
1479 return(utimes(path, times));
1481 trans = hcc_start_command(hc, HC_UTIMES);
1482 hcc_leaf_string(trans, LC_PATH1, path);
1483 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1484 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1485 if ((head = hcc_finish_command(trans)) == NULL)
1486 return(-1);
1487 if (head->error)
1488 return(-1);
1489 return(0);
1492 static int
1493 rc_utimes(hctransaction_t trans __unused, struct HCHead *head)
1495 struct HCLeaf *item;
1496 struct timeval times[2];
1497 const char *path;
1499 bzero(times, sizeof(times));
1500 path = NULL;
1502 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1503 switch(item->leafid) {
1504 case LC_PATH1:
1505 path = HCC_STRING(item);
1506 break;
1507 case LC_ATIME:
1508 times[0].tv_sec = HCC_INT64(item);
1509 break;
1510 case LC_MTIME:
1511 times[1].tv_sec = HCC_INT64(item);
1512 break;
1515 if (path == NULL)
1516 return(-2);
1517 return(utimes(path, times));