tcsh: fix warning to keep compiling with WARNS=2
[dragonfly.git] / bin / cpdup / hcproto.c
bloba9e4207c5dbfe8d04ce31d2844ac83aa50633305
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 static int chown_warning;
73 static int chflags_warning;
76 * If not running as root generate a silent warning and return no error.
78 * If running as root return an error.
80 static int
81 silentwarning(int *didwarn, const char *ctl, ...)
83 va_list va;
85 if (RunningAsRoot)
86 return(-1);
87 if (*didwarn == 0) {
88 *didwarn = 1;
89 fprintf(stderr, "WARNING: Not running as root, ");
90 va_start(va, ctl);
91 vfprintf(stderr, ctl, va);
92 va_end(va);
94 return(0);
97 int
98 hc_connect(struct HostConf *hc)
100 if (hcc_connect(hc) < 0) {
101 fprintf(stderr, "Unable to connect to %s\n", hc->host);
102 return(-1);
104 return(hc_hello(hc));
107 void
108 hc_slave(int fdin, int fdout)
110 hcc_slave(fdin, fdout, HCDispatchTable,
111 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
116 * A HELLO RPC is sent on the initial connect.
119 hc_hello(struct HostConf *hc)
121 struct HCHead *head;
122 struct HCLeaf *item;
123 hctransaction_t trans;
124 char hostbuf[256];
125 int error;
127 bzero(hostbuf, sizeof(hostbuf));
128 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
129 return(-1);
130 if (hostbuf[0] == 0)
131 hostbuf[0] = '?';
133 trans = hcc_start_command(hc, HC_HELLO);
134 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
135 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
136 if ((head = hcc_finish_command(trans)) == NULL) {
137 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
138 hc->host);
139 return(-1);
142 if (head->error) {
143 fprintf(stderr, "Connected to %s but remote returned error %d\n",
144 hc->host, head->error);
145 return(-1);
148 error = -1;
149 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
150 switch(item->leafid) {
151 case LC_HELLOSTR:
152 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
153 error = 0;
154 break;
155 case LC_VERSION:
156 hc->version = HCC_INT32(item);
157 break;
160 if (hc->version < HCPROTO_VERSION_COMPAT) {
161 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
162 hc->host);
163 error = -1;
165 if (error < 0)
166 fprintf(stderr, "Handshake failed with %s\n", hc->host);
167 return (error);
170 static int
171 rc_hello(hctransaction_t trans, struct HCHead *head __unused)
173 char hostbuf[256];
175 bzero(hostbuf, sizeof(hostbuf));
176 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
177 return(-1);
178 if (hostbuf[0] == 0)
179 hostbuf[0] = '?';
181 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
182 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
183 return(0);
187 * STAT, LSTAT
190 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
192 struct HCHead *head;
193 hctransaction_t trans;
195 if (hc == NULL || hc->host == NULL)
196 return(stat(path, st));
198 trans = hcc_start_command(hc, HC_STAT);
199 hcc_leaf_string(trans, LC_PATH1, path);
200 if ((head = hcc_finish_command(trans)) == NULL)
201 return(-1);
202 if (head->error)
203 return(-1);
204 return(hc_decode_stat(st, head));
208 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
210 struct HCHead *head;
211 hctransaction_t trans;
213 if (hc == NULL || hc->host == NULL)
214 return(lstat(path, st));
216 trans = hcc_start_command(hc, HC_LSTAT);
217 hcc_leaf_string(trans, LC_PATH1, path);
218 if ((head = hcc_finish_command(trans)) == NULL)
219 return(-1);
220 if (head->error)
221 return(-1);
222 return(hc_decode_stat(st, head));
225 static int
226 hc_decode_stat(struct stat *st, struct HCHead *head)
228 struct HCLeaf *item;
230 bzero(st, sizeof(*st));
231 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
232 switch(item->leafid) {
233 case LC_DEV:
234 st->st_dev = HCC_INT32(item);
235 break;
236 case LC_INO:
237 st->st_ino = HCC_INT64(item);
238 break;
239 case LC_MODE:
240 st->st_mode = HCC_INT32(item);
241 break;
242 case LC_NLINK:
243 st->st_nlink = HCC_INT32(item);
244 break;
245 case LC_UID:
246 st->st_uid = HCC_INT32(item);
247 break;
248 case LC_GID:
249 st->st_gid = HCC_INT32(item);
250 break;
251 case LC_RDEV:
252 st->st_rdev = HCC_INT32(item);
253 break;
254 case LC_ATIME:
255 st->st_atime = (time_t)HCC_INT64(item);
256 break;
257 case LC_MTIME:
258 st->st_mtime = (time_t)HCC_INT64(item);
259 break;
260 case LC_CTIME:
261 st->st_ctime = (time_t)HCC_INT64(item);
262 break;
263 case LC_FILESIZE:
264 st->st_size = HCC_INT64(item);
265 break;
266 case LC_FILEBLKS:
267 st->st_blocks = HCC_INT64(item);
268 break;
269 case LC_BLKSIZE:
270 st->st_blksize = HCC_INT32(item);
271 break;
272 #ifdef _ST_FSMID_PRESENT_
273 case LC_FSMID:
274 st->st_fsmid = HCC_INT64(item);
275 break;
276 #endif
277 #ifdef _ST_FLAGS_PRESENT_
278 case LC_FILEFLAGS:
279 st->st_flags = (u_int32_t)HCC_INT64(item);
280 break;
281 #endif
284 return(0);
287 static int
288 rc_stat(hctransaction_t trans, struct HCHead *head)
290 struct HCLeaf *item;
291 struct stat st;
292 const char *path = NULL;
294 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
295 switch(item->leafid) {
296 case LC_PATH1:
297 path = HCC_STRING(item);
298 break;
301 if (path == NULL)
302 return(-2);
303 if (stat(path, &st) < 0)
304 return(-1);
305 return (rc_encode_stat(trans, &st));
308 static int
309 rc_lstat(hctransaction_t trans, struct HCHead *head)
311 struct HCLeaf *item;
312 struct stat st;
313 const char *path = NULL;
315 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
316 switch(item->leafid) {
317 case LC_PATH1:
318 path = HCC_STRING(item);
319 break;
322 if (path == NULL)
323 return(-2);
324 if (lstat(path, &st) < 0)
325 return(-1);
326 return (rc_encode_stat(trans, &st));
329 static int
330 rc_encode_stat(hctransaction_t trans, struct stat *st)
332 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
333 hcc_leaf_int64(trans, LC_INO, st->st_ino);
334 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
335 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
336 hcc_leaf_int32(trans, LC_UID, st->st_uid);
337 hcc_leaf_int32(trans, LC_GID, st->st_gid);
338 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
339 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
340 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
341 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
342 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
343 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
344 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
345 #ifdef _ST_FSMID_PRESENT_
346 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
347 #endif
348 #ifdef _ST_FLAGS_PRESENT_
349 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
350 #endif
351 return(0);
355 * OPENDIR
357 DIR *
358 hc_opendir(struct HostConf *hc, const char *path)
360 hctransaction_t trans;
361 struct HCHead *head;
362 struct HCLeaf *item;
363 struct dirent *den;
364 intptr_t desc = 0;
366 if (hc == NULL || hc->host == NULL)
367 return(opendir(path));
369 trans = hcc_start_command(hc, HC_OPENDIR);
370 hcc_leaf_string(trans, LC_PATH1, path);
371 if ((head = hcc_finish_command(trans)) == NULL)
372 return(NULL);
373 if (head->error)
374 return(NULL);
375 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
376 switch(item->leafid) {
377 case LC_DESCRIPTOR:
378 desc = HCC_INT32(item);
379 break;
382 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
383 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
384 (intmax_t)desc);
385 return(NULL);
387 den = malloc(sizeof(*den));
388 bzero(den, sizeof(*den));
389 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
390 return((void *)desc);
393 static int
394 rc_opendir(hctransaction_t trans, struct HCHead *head)
396 struct HCLeaf *item;
397 const char *path = NULL;
398 DIR *dir;
399 int desc;
401 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
402 switch(item->leafid) {
403 case LC_PATH1:
404 path = HCC_STRING(item);
405 break;
408 if (path == NULL)
409 return(-2);
410 if ((dir = opendir(path)) == NULL) {
411 head->error = errno;
412 } else {
413 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
414 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
416 return(0);
420 * READDIR
422 struct dirent *
423 hc_readdir(struct HostConf *hc, DIR *dir)
425 hctransaction_t trans;
426 struct HCHead *head;
427 struct HCLeaf *item;
428 struct dirent *den;
430 if (hc == NULL || hc->host == NULL)
431 return(readdir(dir));
433 trans = hcc_start_command(hc, HC_READDIR);
434 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
435 if ((head = hcc_finish_command(trans)) == NULL)
436 return(NULL);
437 if (head->error)
438 return(NULL); /* XXX errno */
439 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
440 if (den == NULL)
441 return(NULL); /* XXX errno */
442 if (den->d_name)
443 den->d_name[0] = 0;
444 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
445 switch(item->leafid) {
446 case LC_PATH1:
447 snprintf(den->d_name, sizeof(den->d_name), "%s", HCC_STRING(item));
448 break;
449 case LC_INO:
450 den->d_fileno = HCC_INT64(item);
451 break;
452 case LC_TYPE:
453 den->d_type = HCC_INT32(item);
454 break;
457 if (den->d_name[0]) {
458 #ifdef _DIRENT_HAVE_D_NAMLEN
459 den->d_namlen = strlen(den->d_name);
460 #endif
461 return(den);
463 return(NULL); /* XXX errno */
466 static int
467 rc_readdir(hctransaction_t trans, struct HCHead *head)
469 struct HCLeaf *item;
470 struct dirent *den;
471 DIR *dir = NULL;
473 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
474 switch(item->leafid) {
475 case LC_DESCRIPTOR:
476 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
477 break;
480 if (dir == NULL)
481 return(-2);
482 if ((den = readdir(dir)) != NULL) {
483 hcc_leaf_string(trans, LC_PATH1, den->d_name);
484 hcc_leaf_int64(trans, LC_INO, den->d_fileno);
485 hcc_leaf_int32(trans, LC_TYPE, den->d_type);
487 return(0);
491 * CLOSEDIR
493 * XXX cpdup needs to check error code to avoid truncated dirs?
496 hc_closedir(struct HostConf *hc, DIR *dir)
498 hctransaction_t trans;
499 struct HCHead *head;
500 struct dirent *den;
502 if (hc == NULL || hc->host == NULL)
503 return(closedir(dir));
504 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
505 if (den) {
506 free(den);
507 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
509 trans = hcc_start_command(hc, HC_CLOSEDIR);
510 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
511 if ((head = hcc_finish_command(trans)) == NULL)
512 return(-1);
513 if (head->error)
514 return(-1); /* XXX errno */
515 return(0);
516 } else {
517 /* errno */
518 return(-1);
522 static int
523 rc_closedir(hctransaction_t trans, struct HCHead *head)
525 struct HCLeaf *item;
526 DIR *dir = NULL;
528 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
529 switch(item->leafid) {
530 case LC_DESCRIPTOR:
531 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
532 if (dir != NULL)
533 hcc_set_descriptor(trans->hc, HCC_INT32(item), NULL, HC_DESC_DIR);
534 break;
537 if (dir == NULL)
538 return(-2);
539 return(closedir(dir));
543 * OPEN
546 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
548 hctransaction_t trans;
549 struct HCHead *head;
550 struct HCLeaf *item;
551 int *fdp;
552 int desc = 0;
553 int nflags;
555 if (hc == NULL || hc->host == NULL) {
556 #ifdef O_LARGEFILE
557 flags |= O_LARGEFILE;
558 #endif
559 return(open(path, flags, mode));
562 nflags = flags & XO_NATIVEMASK;
563 if (flags & O_CREAT)
564 nflags |= XO_CREAT;
565 if (flags & O_EXCL)
566 nflags |= XO_EXCL;
567 if (flags & O_TRUNC)
568 nflags |= XO_TRUNC;
570 trans = hcc_start_command(hc, HC_OPEN);
571 hcc_leaf_string(trans, LC_PATH1, path);
572 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
573 hcc_leaf_int32(trans, LC_MODE, mode);
575 if ((head = hcc_finish_command(trans)) == NULL)
576 return(-1);
577 if (head->error)
578 return(-1);
579 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
580 switch(item->leafid) {
581 case LC_DESCRIPTOR:
582 desc = HCC_INT32(item);
583 break;
586 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
587 fprintf(stderr, "hc_opendir: remote reused active descriptor %d\n",
588 desc);
589 return(-1);
591 fdp = malloc(sizeof(int));
592 *fdp = desc; /* really just a dummy */
593 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
594 return(desc);
597 static int
598 rc_open(hctransaction_t trans, struct HCHead *head)
600 struct HCLeaf *item;
601 const char *path = NULL;
602 int nflags = 0;
603 int flags;
604 mode_t mode = 0666;
605 int desc;
606 int *fdp;
607 int fd;
609 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
610 switch(item->leafid) {
611 case LC_PATH1:
612 path = HCC_STRING(item);
613 break;
614 case LC_OFLAGS:
615 nflags = HCC_INT32(item);
616 break;
617 case LC_MODE:
618 mode = HCC_INT32(item);
619 break;
622 if (path == NULL)
623 return(-2);
625 flags = nflags & XO_NATIVEMASK;
626 if (nflags & XO_CREAT)
627 flags |= O_CREAT;
628 if (nflags & XO_EXCL)
629 flags |= O_EXCL;
630 if (nflags & XO_TRUNC)
631 flags |= O_TRUNC;
633 #ifdef O_LARGEFILE
634 flags |= O_LARGEFILE;
635 #endif
636 if ((fd = open(path, flags, mode)) < 0) {
637 head->error = errno;
638 return(0);
640 fdp = malloc(sizeof(int));
641 *fdp = fd;
642 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
643 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
644 return(0);
648 * CLOSE
651 hc_close(struct HostConf *hc, int fd)
653 hctransaction_t trans;
654 struct HCHead *head;
655 int *fdp;
657 if (hc == NULL || hc->host == NULL)
658 return(close(fd));
660 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
661 if (fdp) {
662 free(fdp);
663 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
665 trans = hcc_start_command(hc, HC_CLOSE);
666 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
667 if ((head = hcc_finish_command(trans)) == NULL)
668 return(-1);
669 if (head->error)
670 return(-1);
671 return(0);
672 } else {
673 return(-1);
677 static int
678 rc_close(hctransaction_t trans, struct HCHead *head)
680 struct HCLeaf *item;
681 int *fdp = NULL;
682 int fd;
683 int desc = -1;
685 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
686 switch(item->leafid) {
687 case LC_DESCRIPTOR:
688 desc = HCC_INT32(item);
689 break;
692 if (desc < 0)
693 return(-2);
694 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
695 return(-2);
696 fd = *fdp;
697 free(fdp);
698 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
699 return(close(fd));
702 static int
703 getiolimit(void)
705 #if USE_PTHREADS
706 if (CurParallel < 2)
707 return(32768);
708 if (CurParallel < 4)
709 return(16384);
710 if (CurParallel < 8)
711 return(8192);
712 return(4096);
713 #else
714 return(32768);
715 #endif
719 * READ
721 ssize_t
722 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
724 hctransaction_t trans;
725 struct HCHead *head;
726 struct HCLeaf *item;
727 int *fdp;
728 int r;
730 if (hc == NULL || hc->host == NULL)
731 return(read(fd, buf, bytes));
733 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
734 if (fdp) {
735 r = 0;
736 while (bytes) {
737 size_t limit = getiolimit();
738 int n = (bytes > limit) ? limit : bytes;
739 int x = 0;
741 trans = hcc_start_command(hc, HC_READ);
742 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
743 hcc_leaf_int32(trans, LC_BYTES, n);
744 if ((head = hcc_finish_command(trans)) == NULL)
745 return(-1);
746 if (head->error)
747 return(-1);
748 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
749 switch(item->leafid) {
750 case LC_DATA:
751 x = item->bytes - sizeof(*item);
752 if (x > (int)bytes)
753 x = (int)bytes;
754 bcopy(HCC_BINARYDATA(item), buf, x);
755 buf = (char *)buf + x;
756 bytes -= (size_t)x;
757 r += x;
758 break;
761 if (x < n)
762 break;
764 return(r);
765 } else {
766 return(-1);
770 static int
771 rc_read(hctransaction_t trans, struct HCHead *head)
773 struct HCLeaf *item;
774 int *fdp = NULL;
775 char buf[32768];
776 int bytes = -1;
777 int n;
779 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
780 switch(item->leafid) {
781 case LC_DESCRIPTOR:
782 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
783 break;
784 case LC_BYTES:
785 bytes = HCC_INT32(item);
786 break;
789 if (fdp == NULL)
790 return(-2);
791 if (bytes < 0 || bytes > 32768)
792 return(-2);
793 n = read(*fdp, buf, bytes);
794 if (n < 0) {
795 head->error = errno;
796 return(0);
798 hcc_leaf_data(trans, LC_DATA, buf, n);
799 return(0);
803 * WRITE
805 ssize_t
806 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
808 hctransaction_t trans;
809 struct HCHead *head;
810 struct HCLeaf *item;
811 int *fdp;
812 int r;
814 if (hc == NULL || hc->host == NULL)
815 return(write(fd, buf, bytes));
817 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
818 if (fdp) {
819 r = 0;
820 while (bytes) {
821 size_t limit = getiolimit();
822 int n = (bytes > limit) ? limit : bytes;
823 int x = 0;
825 trans = hcc_start_command(hc, HC_WRITE);
826 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
827 hcc_leaf_data(trans, LC_DATA, buf, n);
828 if ((head = hcc_finish_command(trans)) == NULL)
829 return(-1);
830 if (head->error)
831 return(-1);
832 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
833 switch(item->leafid) {
834 case LC_BYTES:
835 x = HCC_INT32(item);
836 break;
839 if (x < 0 || x > n)
840 return(-1);
841 r += x;
842 buf = (const char *)buf + x;
843 bytes -= x;
844 if (x < n)
845 break;
847 return(r);
848 } else {
849 return(-1);
853 static int
854 rc_write(hctransaction_t trans, struct HCHead *head)
856 struct HCLeaf *item;
857 int *fdp = NULL;
858 void *buf = NULL;
859 int n = -1;
861 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
862 switch(item->leafid) {
863 case LC_DESCRIPTOR:
864 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
865 break;
866 case LC_DATA:
867 buf = HCC_BINARYDATA(item);
868 n = item->bytes - sizeof(*item);
869 break;
872 if (fdp == NULL)
873 return(-2);
874 if (n < 0 || n > 32768)
875 return(-2);
876 n = write(*fdp, buf, n);
877 if (n < 0) {
878 head->error = errno;
879 } else {
880 hcc_leaf_int32(trans, LC_BYTES, n);
882 return(0);
886 * REMOVE
888 * NOTE: This function returns -errno if an error occured.
891 hc_remove(struct HostConf *hc, const char *path)
893 hctransaction_t trans;
894 struct HCHead *head;
895 int res;
897 if (hc == NULL || hc->host == NULL) {
898 res = remove(path);
899 if (res < 0)
900 res = -errno;
901 return(res);
904 trans = hcc_start_command(hc, HC_REMOVE);
905 hcc_leaf_string(trans, LC_PATH1, path);
906 if ((head = hcc_finish_command(trans)) == NULL)
907 return(-EIO);
908 if (head->error)
909 return(-(int)head->error);
910 return(0);
913 static int
914 rc_remove(hctransaction_t trans __unused, struct HCHead *head)
916 struct HCLeaf *item;
917 const char *path = NULL;
919 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
920 switch(item->leafid) {
921 case LC_PATH1:
922 path = HCC_STRING(item);
923 break;
926 if (path == NULL)
927 return(-2);
928 return(remove(path));
932 * MKDIR
935 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
937 hctransaction_t trans;
938 struct HCHead *head;
940 if (hc == NULL || hc->host == NULL)
941 return(mkdir(path, mode));
943 trans = hcc_start_command(hc, HC_MKDIR);
944 hcc_leaf_string(trans, LC_PATH1, path);
945 hcc_leaf_int32(trans, LC_MODE, mode);
946 if ((head = hcc_finish_command(trans)) == NULL)
947 return(-1);
948 if (head->error)
949 return(-1);
950 return(0);
953 static int
954 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head)
956 struct HCLeaf *item;
957 const char *path = NULL;
958 mode_t mode = 0777;
960 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
961 switch(item->leafid) {
962 case LC_PATH1:
963 path = HCC_STRING(item);
964 break;
965 case LC_MODE:
966 mode = HCC_INT32(item);
967 break;
970 if (path == NULL)
971 return(-1);
972 return(mkdir(path, mode));
976 * RMDIR
979 hc_rmdir(struct HostConf *hc, const char *path)
981 hctransaction_t trans;
982 struct HCHead *head;
984 if (hc == NULL || hc->host == NULL)
985 return(rmdir(path));
987 trans = hcc_start_command(hc, HC_RMDIR);
988 hcc_leaf_string(trans, LC_PATH1, path);
989 if ((head = hcc_finish_command(trans)) == NULL)
990 return(-1);
991 if (head->error)
992 return(-1);
993 return(0);
996 static int
997 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head)
999 struct HCLeaf *item;
1000 const char *path = NULL;
1002 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1003 switch(item->leafid) {
1004 case LC_PATH1:
1005 path = HCC_STRING(item);
1006 break;
1009 if (path == NULL)
1010 return(-1);
1011 return(rmdir(path));
1015 * CHOWN
1017 * Almost silently ignore chowns that fail if we are not root.
1020 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1022 hctransaction_t trans;
1023 struct HCHead *head;
1024 int rc;
1026 if (hc == NULL || hc->host == NULL) {
1027 rc = chown(path, owner, group);
1028 if (rc < 0)
1029 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1030 return(rc);
1033 trans = hcc_start_command(hc, HC_CHOWN);
1034 hcc_leaf_string(trans, LC_PATH1, path);
1035 hcc_leaf_int32(trans, LC_UID, owner);
1036 hcc_leaf_int32(trans, LC_GID, group);
1037 if ((head = hcc_finish_command(trans)) == NULL)
1038 return(-1);
1039 if (head->error)
1040 return(-1);
1041 return(0);
1044 static int
1045 rc_chown(hctransaction_t trans __unused, struct HCHead *head)
1047 struct HCLeaf *item;
1048 const char *path = NULL;
1049 uid_t uid = (uid_t)-1;
1050 gid_t gid = (gid_t)-1;
1051 int rc;
1053 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1054 switch(item->leafid) {
1055 case LC_PATH1:
1056 path = HCC_STRING(item);
1057 break;
1058 case LC_UID:
1059 uid = HCC_INT32(item);
1060 break;
1061 case LC_GID:
1062 gid = HCC_INT32(item);
1063 break;
1066 if (path == NULL)
1067 return(-1);
1068 rc = chown(path, uid, gid);
1069 if (rc < 0)
1070 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1071 return(rc);
1075 * LCHOWN
1078 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1080 hctransaction_t trans;
1081 struct HCHead *head;
1082 int rc;
1084 if (hc == NULL || hc->host == NULL) {
1085 rc = lchown(path, owner, group);
1086 if (rc < 0)
1087 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1088 return(rc);
1091 trans = hcc_start_command(hc, HC_LCHOWN);
1092 hcc_leaf_string(trans, LC_PATH1, path);
1093 hcc_leaf_int32(trans, LC_UID, owner);
1094 hcc_leaf_int32(trans, LC_GID, group);
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_lchown(hctransaction_t trans __unused, struct HCHead *head)
1105 struct HCLeaf *item;
1106 const char *path = NULL;
1107 uid_t uid = (uid_t)-1;
1108 gid_t gid = (gid_t)-1;
1109 int rc;
1111 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1112 switch(item->leafid) {
1113 case LC_PATH1:
1114 path = HCC_STRING(item);
1115 break;
1116 case LC_UID:
1117 uid = HCC_INT32(item);
1118 break;
1119 case LC_GID:
1120 gid = HCC_INT32(item);
1121 break;
1124 if (path == NULL)
1125 return(-1);
1126 rc = lchown(path, uid, gid);
1127 if (rc < 0)
1128 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1129 return(rc);
1133 * CHMOD
1136 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1138 hctransaction_t trans;
1139 struct HCHead *head;
1141 if (hc == NULL || hc->host == NULL)
1142 return(chmod(path, mode));
1144 trans = hcc_start_command(hc, HC_CHMOD);
1145 hcc_leaf_string(trans, LC_PATH1, path);
1146 hcc_leaf_int32(trans, LC_MODE, mode);
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_chmod(hctransaction_t trans __unused, struct HCHead *head)
1157 struct HCLeaf *item;
1158 const char *path = NULL;
1159 mode_t mode = 0666;
1161 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1162 switch(item->leafid) {
1163 case LC_PATH1:
1164 path = HCC_STRING(item);
1165 break;
1166 case LC_MODE:
1167 mode = HCC_INT32(item);
1168 break;
1171 if (path == NULL)
1172 return(-1);
1173 return(chmod(path, mode));
1177 * MKNOD
1180 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1182 hctransaction_t trans;
1183 struct HCHead *head;
1185 if (hc == NULL || hc->host == NULL)
1186 return(mknod(path, mode, rdev));
1188 trans = hcc_start_command(hc, HC_MKNOD);
1189 hcc_leaf_string(trans, LC_PATH1, path);
1190 hcc_leaf_int32(trans, LC_MODE, mode);
1191 hcc_leaf_int32(trans, LC_RDEV, rdev);
1192 if ((head = hcc_finish_command(trans)) == NULL)
1193 return(-1);
1194 if (head->error)
1195 return(-1);
1196 return(0);
1199 static int
1200 rc_mknod(hctransaction_t trans __unused, struct HCHead *head)
1202 struct HCLeaf *item;
1203 const char *path = NULL;
1204 mode_t mode = 0666;
1205 dev_t rdev = 0;
1207 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1208 switch(item->leafid) {
1209 case LC_PATH1:
1210 path = HCC_STRING(item);
1211 break;
1212 case LC_MODE:
1213 mode = HCC_INT32(item);
1214 break;
1215 case LC_RDEV:
1216 rdev = HCC_INT32(item);
1217 break;
1220 if (path == NULL)
1221 return(-1);
1222 return(mknod(path, mode, rdev));
1226 * LINK
1229 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1231 hctransaction_t trans;
1232 struct HCHead *head;
1234 if (hc == NULL || hc->host == NULL)
1235 return(link(name1, name2));
1237 trans = hcc_start_command(hc, HC_LINK);
1238 hcc_leaf_string(trans, LC_PATH1, name1);
1239 hcc_leaf_string(trans, LC_PATH2, name2);
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_link(hctransaction_t trans __unused, struct HCHead *head)
1250 struct HCLeaf *item;
1251 const char *name1 = NULL;
1252 const char *name2 = NULL;
1254 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1255 switch(item->leafid) {
1256 case LC_PATH1:
1257 name1 = HCC_STRING(item);
1258 break;
1259 case LC_PATH2:
1260 name2 = HCC_STRING(item);
1261 break;
1264 if (name1 == NULL || name2 == NULL)
1265 return(-2);
1266 return(link(name1, name2));
1269 #ifdef _ST_FLAGS_PRESENT_
1271 * CHFLAGS
1274 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1276 hctransaction_t trans;
1277 struct HCHead *head;
1278 int rc;
1280 if (hc == NULL || hc->host == NULL) {
1281 rc = chflags(path, flags);
1282 if (rc < 0) {
1283 if (RunningAsUser) {
1284 flags &= UF_SETTABLE;
1285 rc = chflags(path, flags);
1287 if (rc < 0)
1288 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1290 return (rc);
1293 trans = hcc_start_command(hc, HC_CHFLAGS);
1294 hcc_leaf_string(trans, LC_PATH1, path);
1295 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1296 if ((head = hcc_finish_command(trans)) == NULL)
1297 return(-1);
1298 if (head->error)
1299 return(-1);
1300 return(0);
1303 static int
1304 rc_chflags(hctransaction_t trans __unused, struct HCHead *head)
1306 struct HCLeaf *item;
1307 const char *path = NULL;
1308 u_long flags = 0;
1309 int rc;
1311 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1312 switch(item->leafid) {
1313 case LC_PATH1:
1314 path = HCC_STRING(item);
1315 break;
1316 case LC_FILEFLAGS:
1317 flags = (u_long)HCC_INT64(item);
1318 break;
1321 if (path == NULL)
1322 return(-2);
1323 rc = chflags(path, flags);
1324 if (rc < 0) {
1325 if (RunningAsUser) {
1326 flags &= UF_SETTABLE;
1327 rc = chflags(path, flags);
1329 if (rc < 0)
1330 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1332 return(rc);
1335 #endif
1338 * READLINK
1341 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1343 hctransaction_t trans;
1344 struct HCHead *head;
1345 struct HCLeaf *item;
1346 int r;
1348 if (hc == NULL || hc->host == NULL)
1349 return(readlink(path, buf, bufsiz));
1351 trans = hcc_start_command(hc, HC_READLINK);
1352 hcc_leaf_string(trans, LC_PATH1, path);
1353 if ((head = hcc_finish_command(trans)) == NULL)
1354 return(-1);
1355 if (head->error)
1356 return(-1);
1358 r = 0;
1359 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1360 switch(item->leafid) {
1361 case LC_DATA:
1362 r = item->bytes - sizeof(*item);
1363 if (r < 0)
1364 r = 0;
1365 if (r > bufsiz)
1366 r = bufsiz;
1367 bcopy(HCC_BINARYDATA(item), buf, r);
1368 break;
1371 return(r);
1374 static int
1375 rc_readlink(hctransaction_t trans, struct HCHead *head)
1377 struct HCLeaf *item;
1378 const char *path = NULL;
1379 char buf[1024];
1380 int r;
1382 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1383 switch(item->leafid) {
1384 case LC_PATH1:
1385 path = HCC_STRING(item);
1386 break;
1389 if (path == NULL)
1390 return(-2);
1391 r = readlink(path, buf, sizeof(buf));
1392 if (r < 0)
1393 return(-1);
1394 hcc_leaf_data(trans, LC_DATA, buf, r);
1395 return(0);
1399 * UMASK
1401 mode_t
1402 hc_umask(struct HostConf *hc, mode_t numask)
1404 hctransaction_t trans;
1405 struct HCHead *head;
1406 struct HCLeaf *item;
1408 if (hc == NULL || hc->host == NULL)
1409 return(umask(numask));
1411 trans = hcc_start_command(hc, HC_UMASK);
1412 hcc_leaf_int32(trans, LC_MODE, numask);
1413 if ((head = hcc_finish_command(trans)) == NULL)
1414 return((mode_t)-1);
1415 if (head->error)
1416 return((mode_t)-1);
1418 numask = ~0666;
1419 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1420 switch(item->leafid) {
1421 case LC_MODE:
1422 numask = HCC_INT32(item);
1423 break;
1426 return(numask);
1429 static int
1430 rc_umask(hctransaction_t trans, struct HCHead *head)
1432 struct HCLeaf *item;
1433 mode_t numask = ~0666;
1435 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1436 switch(item->leafid) {
1437 case LC_MODE:
1438 numask = HCC_INT32(item);
1439 break;
1442 numask = umask(numask);
1443 hcc_leaf_int32(trans, LC_MODE, numask);
1444 return(0);
1448 * SYMLINK
1451 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1453 hctransaction_t trans;
1454 struct HCHead *head;
1456 if (hc == NULL || hc->host == NULL)
1457 return(symlink(name1, name2));
1459 trans = hcc_start_command(hc, HC_SYMLINK);
1460 hcc_leaf_string(trans, LC_PATH1, name1);
1461 hcc_leaf_string(trans, LC_PATH2, name2);
1462 if ((head = hcc_finish_command(trans)) == NULL)
1463 return(-1);
1464 if (head->error)
1465 return(-1);
1466 return(0);
1469 static int
1470 rc_symlink(hctransaction_t trans __unused, struct HCHead *head)
1472 struct HCLeaf *item;
1473 const char *name1 = NULL;
1474 const char *name2 = NULL;
1476 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1477 switch(item->leafid) {
1478 case LC_PATH1:
1479 name1 = HCC_STRING(item);
1480 break;
1481 case LC_PATH2:
1482 name2 = HCC_STRING(item);
1483 break;
1486 if (name1 == NULL || name2 == NULL)
1487 return(-2);
1488 return(symlink(name1, name2));
1492 * RENAME
1495 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1497 hctransaction_t trans;
1498 struct HCHead *head;
1500 if (hc == NULL || hc->host == NULL)
1501 return(rename(name1, name2));
1503 trans = hcc_start_command(hc, HC_RENAME);
1504 hcc_leaf_string(trans, LC_PATH1, name1);
1505 hcc_leaf_string(trans, LC_PATH2, name2);
1506 if ((head = hcc_finish_command(trans)) == NULL)
1507 return(-1);
1508 if (head->error)
1509 return(-1);
1510 return(0);
1513 static int
1514 rc_rename(hctransaction_t trans __unused, struct HCHead *head)
1516 struct HCLeaf *item;
1517 const char *name1 = NULL;
1518 const char *name2 = NULL;
1520 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1521 switch(item->leafid) {
1522 case LC_PATH1:
1523 name1 = HCC_STRING(item);
1524 break;
1525 case LC_PATH2:
1526 name2 = HCC_STRING(item);
1527 break;
1530 if (name1 == NULL || name2 == NULL)
1531 return(-2);
1532 return(rename(name1, name2));
1536 * UTIMES
1539 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1541 hctransaction_t trans;
1542 struct HCHead *head;
1544 if (hc == NULL || hc->host == NULL)
1545 return(utimes(path, times));
1547 trans = hcc_start_command(hc, HC_UTIMES);
1548 hcc_leaf_string(trans, LC_PATH1, path);
1549 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1550 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1551 if ((head = hcc_finish_command(trans)) == NULL)
1552 return(-1);
1553 if (head->error)
1554 return(-1);
1555 return(0);
1558 static int
1559 rc_utimes(hctransaction_t trans __unused, struct HCHead *head)
1561 struct HCLeaf *item;
1562 struct timeval times[2];
1563 const char *path;
1565 bzero(times, sizeof(times));
1566 path = NULL;
1568 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1569 switch(item->leafid) {
1570 case LC_PATH1:
1571 path = HCC_STRING(item);
1572 break;
1573 case LC_ATIME:
1574 times[0].tv_sec = HCC_INT64(item);
1575 break;
1576 case LC_MTIME:
1577 times[1].tv_sec = HCC_INT64(item);
1578 break;
1581 if (path == NULL)
1582 return(-2);
1583 return(utimes(path, times));