1 /* 2 * HCPROTO.C 3 * 4 * This module implements a simple remote control protocol 5 * 6 * $DragonFly: src/bin/cpdup/hcproto.c,v 1.8 2008/11/11 04:36:00 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 intptr_t 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 %jd\n", 359 (intmax_t)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, (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; 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, (intptr_t)dir, HC_DESC_DIR); 480 if (den) { 481 free(den); 482 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR); 483 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); 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 * NOTE: This function returns -errno if an error occured. 864 */ 865 int 866 hc_remove(struct HostConf *hc, const char *path) 867 { 868 hctransaction_t trans; 869 struct HCHead *head; 870 int res; 871 872 if (hc == NULL || hc->host == NULL) { 873 res = remove(path); 874 if (res < 0) 875 res = -errno; 876 return(res); 877 } 878 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); 886 } 887 888 static int 889 rc_remove(hctransaction_t trans __unused, struct HCHead *head) 890 { 891 struct HCLeaf *item; 892 const char *path = NULL; 893 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; 899 } 900 } 901 if (path == NULL) 902 return(-2); 903 return(remove(path)); 904 } 905 906 /* 907 * MKDIR 908 */ 909 int 910 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode) 911 { 912 hctransaction_t trans; 913 struct HCHead *head; 914 915 if (hc == NULL || hc->host == NULL) 916 return(mkdir(path, mode)); 917 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); 926 } 927 928 static int 929 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head) 930 { 931 struct HCLeaf *item; 932 const char *path = NULL; 933 mode_t mode = 0777; 934 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; 943 } 944 } 945 if (path == NULL) 946 return(-1); 947 return(mkdir(path, mode)); 948 } 949 950 /* 951 * RMDIR 952 */ 953 int 954 hc_rmdir(struct HostConf *hc, const char *path) 955 { 956 hctransaction_t trans; 957 struct HCHead *head; 958 959 if (hc == NULL || hc->host == NULL) 960 return(rmdir(path)); 961 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); 969 } 970 971 static int 972 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head) 973 { 974 struct HCLeaf *item; 975 const char *path = NULL; 976 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; 982 } 983 } 984 if (path == NULL) 985 return(-1); 986 return(rmdir(path)); 987 } 988 989 /* 990 * CHOWN 991 */ 992 int 993 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group) 994 { 995 hctransaction_t trans; 996 struct HCHead *head; 997 998 if (hc == NULL || hc->host == NULL) 999 return(chown(path, owner, group)); 1000 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); 1010 } 1011 1012 static int 1013 rc_chown(hctransaction_t trans __unused, struct HCHead *head) 1014 { 1015 struct HCLeaf *item; 1016 const char *path = NULL; 1017 uid_t uid = (uid_t)-1; 1018 gid_t gid = (gid_t)-1; 1019 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; 1031 } 1032 } 1033 if (path == NULL) 1034 return(-1); 1035 return(chown(path, uid, gid)); 1036 } 1037 1038 /* 1039 * LCHOWN 1040 */ 1041 int 1042 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group) 1043 { 1044 hctransaction_t trans; 1045 struct HCHead *head; 1046 1047 if (hc == NULL || hc->host == NULL) 1048 return(lchown(path, owner, group)); 1049 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); 1059 } 1060 1061 static int 1062 rc_lchown(hctransaction_t trans __unused, struct HCHead *head) 1063 { 1064 struct HCLeaf *item; 1065 const char *path = NULL; 1066 uid_t uid = (uid_t)-1; 1067 gid_t gid = (gid_t)-1; 1068 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; 1080 } 1081 } 1082 if (path == NULL) 1083 return(-1); 1084 return(lchown(path, uid, gid)); 1085 } 1086 1087 /* 1088 * CHMOD 1089 */ 1090 int 1091 hc_chmod(struct HostConf *hc, const char *path, mode_t mode) 1092 { 1093 hctransaction_t trans; 1094 struct HCHead *head; 1095 1096 if (hc == NULL || hc->host == NULL) 1097 return(chmod(path, mode)); 1098 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); 1107 } 1108 1109 static int 1110 rc_chmod(hctransaction_t trans __unused, struct HCHead *head) 1111 { 1112 struct HCLeaf *item; 1113 const char *path = NULL; 1114 mode_t mode = 0666; 1115 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; 1124 } 1125 } 1126 if (path == NULL) 1127 return(-1); 1128 return(chmod(path, mode)); 1129 } 1130 1131 /* 1132 * MKNOD 1133 */ 1134 int 1135 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev) 1136 { 1137 hctransaction_t trans; 1138 struct HCHead *head; 1139 1140 if (hc == NULL || hc->host == NULL) 1141 return(mknod(path, mode, rdev)); 1142 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); 1152 } 1153 1154 static int 1155 rc_mknod(hctransaction_t trans __unused, struct HCHead *head) 1156 { 1157 struct HCLeaf *item; 1158 const char *path = NULL; 1159 mode_t mode = 0666; 1160 dev_t rdev = 0; 1161 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; 1173 } 1174 } 1175 if (path == NULL) 1176 return(-1); 1177 return(mknod(path, mode, rdev)); 1178 } 1179 1180 /* 1181 * LINK 1182 */ 1183 int 1184 hc_link(struct HostConf *hc, const char *name1, const char *name2) 1185 { 1186 hctransaction_t trans; 1187 struct HCHead *head; 1188 1189 if (hc == NULL || hc->host == NULL) 1190 return(link(name1, name2)); 1191 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); 1200 } 1201 1202 static int 1203 rc_link(hctransaction_t trans __unused, struct HCHead *head) 1204 { 1205 struct HCLeaf *item; 1206 const char *name1 = NULL; 1207 const char *name2 = NULL; 1208 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; 1217 } 1218 } 1219 if (name1 == NULL || name2 == NULL) 1220 return(-2); 1221 return(link(name1, name2)); 1222 } 1223 1224 #ifdef _ST_FLAGS_PRESENT_ 1225 /* 1226 * CHFLAGS 1227 */ 1228 int 1229 hc_chflags(struct HostConf *hc, const char *path, u_long flags) 1230 { 1231 hctransaction_t trans; 1232 struct HCHead *head; 1233 1234 if (hc == NULL || hc->host == NULL) 1235 return(chflags(path, flags)); 1236 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); 1245 } 1246 1247 static int 1248 rc_chflags(hctransaction_t trans __unused, struct HCHead *head) 1249 { 1250 struct HCLeaf *item; 1251 const char *path = NULL; 1252 u_long flags = 0; 1253 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; 1262 } 1263 } 1264 if (path == NULL) 1265 return(-2); 1266 return(chflags(path, flags)); 1267 } 1268 1269 #endif 1270 1271 /* 1272 * READLINK 1273 */ 1274 int 1275 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz) 1276 { 1277 hctransaction_t trans; 1278 struct HCHead *head; 1279 struct HCLeaf *item; 1280 int r; 1281 1282 if (hc == NULL || hc->host == NULL) 1283 return(readlink(path, buf, bufsiz)); 1284 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); 1291 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; 1303 } 1304 } 1305 return(r); 1306 } 1307 1308 static int 1309 rc_readlink(hctransaction_t trans, struct HCHead *head) 1310 { 1311 struct HCLeaf *item; 1312 const char *path = NULL; 1313 char buf[1024]; 1314 int r; 1315 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; 1321 } 1322 } 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); 1330 } 1331 1332 /* 1333 * UMASK 1334 */ 1335 mode_t 1336 hc_umask(struct HostConf *hc, mode_t numask) 1337 { 1338 hctransaction_t trans; 1339 struct HCHead *head; 1340 struct HCLeaf *item; 1341 1342 if (hc == NULL || hc->host == NULL) 1343 return(umask(numask)); 1344 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); 1351 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; 1358 } 1359 } 1360 return(numask); 1361 } 1362 1363 static int 1364 rc_umask(hctransaction_t trans, struct HCHead *head) 1365 { 1366 struct HCLeaf *item; 1367 mode_t numask = ~0666; 1368 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; 1374 } 1375 } 1376 numask = umask(numask); 1377 hcc_leaf_int32(trans, LC_MODE, numask); 1378 return(0); 1379 } 1380 1381 /* 1382 * SYMLINK 1383 */ 1384 int 1385 hc_symlink(struct HostConf *hc, const char *name1, const char *name2) 1386 { 1387 hctransaction_t trans; 1388 struct HCHead *head; 1389 1390 if (hc == NULL || hc->host == NULL) 1391 return(symlink(name1, name2)); 1392 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); 1401 } 1402 1403 static int 1404 rc_symlink(hctransaction_t trans __unused, struct HCHead *head) 1405 { 1406 struct HCLeaf *item; 1407 const char *name1 = NULL; 1408 const char *name2 = NULL; 1409 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; 1418 } 1419 } 1420 if (name1 == NULL || name2 == NULL) 1421 return(-2); 1422 return(symlink(name1, name2)); 1423 } 1424 1425 /* 1426 * RENAME 1427 */ 1428 int 1429 hc_rename(struct HostConf *hc, const char *name1, const char *name2) 1430 { 1431 hctransaction_t trans; 1432 struct HCHead *head; 1433 1434 if (hc == NULL || hc->host == NULL) 1435 return(rename(name1, name2)); 1436 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); 1445 } 1446 1447 static int 1448 rc_rename(hctransaction_t trans __unused, struct HCHead *head) 1449 { 1450 struct HCLeaf *item; 1451 const char *name1 = NULL; 1452 const char *name2 = NULL; 1453 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; 1462 } 1463 } 1464 if (name1 == NULL || name2 == NULL) 1465 return(-2); 1466 return(rename(name1, name2)); 1467 } 1468 1469 /* 1470 * UTIMES 1471 */ 1472 int 1473 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times) 1474 { 1475 hctransaction_t trans; 1476 struct HCHead *head; 1477 1478 if (hc == NULL || hc->host == NULL) 1479 return(utimes(path, times)); 1480 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); 1490 } 1491 1492 static int 1493 rc_utimes(hctransaction_t trans __unused, struct HCHead *head) 1494 { 1495 struct HCLeaf *item; 1496 struct timeval times[2]; 1497 const char *path; 1498 1499 bzero(times, sizeof(times)); 1500 path = NULL; 1501 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; 1513 } 1514 } 1515 if (path == NULL) 1516 return(-2); 1517 return(utimes(path, times)); 1518 } 1519