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