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 static int chown_warning; 73 static int chflags_warning; 74 75 /* 76 * If not running as root generate a silent warning and return no error. 77 * 78 * If running as root return an error. 79 */ 80 static int 81 silentwarning(int *didwarn, const char *ctl, ...) 82 { 83 va_list va; 84 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); 93 } 94 return(0); 95 } 96 97 int 98 hc_connect(struct HostConf *hc) 99 { 100 if (hcc_connect(hc) < 0) { 101 fprintf(stderr, "Unable to connect to %s\n", hc->host); 102 return(-1); 103 } 104 return(hc_hello(hc)); 105 } 106 107 void 108 hc_slave(int fdin, int fdout) 109 { 110 hcc_slave(fdin, fdout, HCDispatchTable, 111 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0])); 112 113 } 114 115 /* 116 * A HELLO RPC is sent on the initial connect. 117 */ 118 int 119 hc_hello(struct HostConf *hc) 120 { 121 struct HCHead *head; 122 struct HCLeaf *item; 123 hctransaction_t trans; 124 char hostbuf[256]; 125 int error; 126 127 bzero(hostbuf, sizeof(hostbuf)); 128 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0) 129 return(-1); 130 if (hostbuf[0] == 0) 131 hostbuf[0] = '?'; 132 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); 140 } 141 142 if (head->error) { 143 fprintf(stderr, "Connected to %s but remote returned error %d\n", 144 hc->host, head->error); 145 return(-1); 146 } 147 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; 158 } 159 } 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; 164 } 165 if (error < 0) 166 fprintf(stderr, "Handshake failed with %s\n", hc->host); 167 return (error); 168 } 169 170 static int 171 rc_hello(hctransaction_t trans, struct HCHead *head __unused) 172 { 173 char hostbuf[256]; 174 175 bzero(hostbuf, sizeof(hostbuf)); 176 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0) 177 return(-1); 178 if (hostbuf[0] == 0) 179 hostbuf[0] = '?'; 180 181 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf); 182 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION); 183 return(0); 184 } 185 186 /* 187 * STAT, LSTAT 188 */ 189 int 190 hc_stat(struct HostConf *hc, const char *path, struct stat *st) 191 { 192 struct HCHead *head; 193 hctransaction_t trans; 194 195 if (hc == NULL || hc->host == NULL) 196 return(stat(path, st)); 197 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)); 205 } 206 207 int 208 hc_lstat(struct HostConf *hc, const char *path, struct stat *st) 209 { 210 struct HCHead *head; 211 hctransaction_t trans; 212 213 if (hc == NULL || hc->host == NULL) 214 return(lstat(path, st)); 215 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)); 223 } 224 225 static int 226 hc_decode_stat(struct stat *st, struct HCHead *head) 227 { 228 struct HCLeaf *item; 229 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 282 } 283 } 284 return(0); 285 } 286 287 static int 288 rc_stat(hctransaction_t trans, struct HCHead *head) 289 { 290 struct HCLeaf *item; 291 struct stat st; 292 const char *path = NULL; 293 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; 299 } 300 } 301 if (path == NULL) 302 return(-2); 303 if (stat(path, &st) < 0) 304 return(-1); 305 return (rc_encode_stat(trans, &st)); 306 } 307 308 static int 309 rc_lstat(hctransaction_t trans, struct HCHead *head) 310 { 311 struct HCLeaf *item; 312 struct stat st; 313 const char *path = NULL; 314 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; 320 } 321 } 322 if (path == NULL) 323 return(-2); 324 if (lstat(path, &st) < 0) 325 return(-1); 326 return (rc_encode_stat(trans, &st)); 327 } 328 329 static int 330 rc_encode_stat(hctransaction_t trans, struct stat *st) 331 { 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); 352 } 353 354 /* 355 * OPENDIR 356 */ 357 DIR * 358 hc_opendir(struct HostConf *hc, const char *path) 359 { 360 hctransaction_t trans; 361 struct HCHead *head; 362 struct HCLeaf *item; 363 struct dirent *den; 364 intptr_t desc = 0; 365 366 if (hc == NULL || hc->host == NULL) 367 return(opendir(path)); 368 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; 380 } 381 } 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); 386 } 387 den = malloc(sizeof(*den)); 388 bzero(den, sizeof(*den)); 389 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR); 390 return((void *)desc); 391 } 392 393 static int 394 rc_opendir(hctransaction_t trans, struct HCHead *head) 395 { 396 struct HCLeaf *item; 397 const char *path = NULL; 398 DIR *dir; 399 int desc; 400 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; 406 } 407 } 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); 415 } 416 return(0); 417 } 418 419 /* 420 * READDIR 421 */ 422 struct dirent * 423 hc_readdir(struct HostConf *hc, DIR *dir) 424 { 425 hctransaction_t trans; 426 struct HCHead *head; 427 struct HCLeaf *item; 428 struct dirent *den; 429 430 if (hc == NULL || hc->host == NULL) 431 return(readdir(dir)); 432 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; 455 } 456 } 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); 462 } 463 return(NULL); /* XXX errno */ 464 } 465 466 static int 467 rc_readdir(hctransaction_t trans, struct HCHead *head) 468 { 469 struct HCLeaf *item; 470 struct dirent *den; 471 DIR *dir = NULL; 472 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; 478 } 479 } 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); 486 } 487 return(0); 488 } 489 490 /* 491 * CLOSEDIR 492 * 493 * XXX cpdup needs to check error code to avoid truncated dirs? 494 */ 495 int 496 hc_closedir(struct HostConf *hc, DIR *dir) 497 { 498 hctransaction_t trans; 499 struct HCHead *head; 500 struct dirent *den; 501 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); 508 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); 519 } 520 } 521 522 static int 523 rc_closedir(hctransaction_t trans, struct HCHead *head) 524 { 525 struct HCLeaf *item; 526 DIR *dir = NULL; 527 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; 535 } 536 } 537 if (dir == NULL) 538 return(-2); 539 return(closedir(dir)); 540 } 541 542 /* 543 * OPEN 544 */ 545 int 546 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode) 547 { 548 hctransaction_t trans; 549 struct HCHead *head; 550 struct HCLeaf *item; 551 int *fdp; 552 int desc = 0; 553 int nflags; 554 555 if (hc == NULL || hc->host == NULL) { 556 #ifdef O_LARGEFILE 557 flags |= O_LARGEFILE; 558 #endif 559 return(open(path, flags, mode)); 560 } 561 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; 569 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); 574 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; 584 } 585 } 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); 590 } 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); 595 } 596 597 static int 598 rc_open(hctransaction_t trans, struct HCHead *head) 599 { 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; 608 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; 620 } 621 } 622 if (path == NULL) 623 return(-2); 624 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; 632 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); 639 } 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); 645 } 646 647 /* 648 * CLOSE 649 */ 650 int 651 hc_close(struct HostConf *hc, int fd) 652 { 653 hctransaction_t trans; 654 struct HCHead *head; 655 int *fdp; 656 657 if (hc == NULL || hc->host == NULL) 658 return(close(fd)); 659 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); 664 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); 674 } 675 } 676 677 static int 678 rc_close(hctransaction_t trans, struct HCHead *head) 679 { 680 struct HCLeaf *item; 681 int *fdp = NULL; 682 int fd; 683 int desc = -1; 684 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; 690 } 691 } 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)); 700 } 701 702 static int 703 getiolimit(void) 704 { 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 716 } 717 718 /* 719 * READ 720 */ 721 ssize_t 722 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes) 723 { 724 hctransaction_t trans; 725 struct HCHead *head; 726 struct HCLeaf *item; 727 int *fdp; 728 int r; 729 730 if (hc == NULL || hc->host == NULL) 731 return(read(fd, buf, bytes)); 732 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; 740 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; 759 } 760 } 761 if (x < n) 762 break; 763 } 764 return(r); 765 } else { 766 return(-1); 767 } 768 } 769 770 static int 771 rc_read(hctransaction_t trans, struct HCHead *head) 772 { 773 struct HCLeaf *item; 774 int *fdp = NULL; 775 char buf[32768]; 776 int bytes = -1; 777 int n; 778 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; 787 } 788 } 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); 797 } 798 hcc_leaf_data(trans, LC_DATA, buf, n); 799 return(0); 800 } 801 802 /* 803 * WRITE 804 */ 805 ssize_t 806 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes) 807 { 808 hctransaction_t trans; 809 struct HCHead *head; 810 struct HCLeaf *item; 811 int *fdp; 812 int r; 813 814 if (hc == NULL || hc->host == NULL) 815 return(write(fd, buf, bytes)); 816 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; 824 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; 837 } 838 } 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; 846 } 847 return(r); 848 } else { 849 return(-1); 850 } 851 } 852 853 static int 854 rc_write(hctransaction_t trans, struct HCHead *head) 855 { 856 struct HCLeaf *item; 857 int *fdp = NULL; 858 void *buf = NULL; 859 int n = -1; 860 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; 870 } 871 } 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); 881 } 882 return(0); 883 } 884 885 /* 886 * REMOVE 887 * 888 * NOTE: This function returns -errno if an error occured. 889 */ 890 int 891 hc_remove(struct HostConf *hc, const char *path) 892 { 893 hctransaction_t trans; 894 struct HCHead *head; 895 int res; 896 897 if (hc == NULL || hc->host == NULL) { 898 res = remove(path); 899 if (res < 0) 900 res = -errno; 901 return(res); 902 } 903 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); 911 } 912 913 static int 914 rc_remove(hctransaction_t trans __unused, struct HCHead *head) 915 { 916 struct HCLeaf *item; 917 const char *path = NULL; 918 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; 924 } 925 } 926 if (path == NULL) 927 return(-2); 928 return(remove(path)); 929 } 930 931 /* 932 * MKDIR 933 */ 934 int 935 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode) 936 { 937 hctransaction_t trans; 938 struct HCHead *head; 939 940 if (hc == NULL || hc->host == NULL) 941 return(mkdir(path, mode)); 942 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); 951 } 952 953 static int 954 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head) 955 { 956 struct HCLeaf *item; 957 const char *path = NULL; 958 mode_t mode = 0777; 959 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; 968 } 969 } 970 if (path == NULL) 971 return(-1); 972 return(mkdir(path, mode)); 973 } 974 975 /* 976 * RMDIR 977 */ 978 int 979 hc_rmdir(struct HostConf *hc, const char *path) 980 { 981 hctransaction_t trans; 982 struct HCHead *head; 983 984 if (hc == NULL || hc->host == NULL) 985 return(rmdir(path)); 986 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); 994 } 995 996 static int 997 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head) 998 { 999 struct HCLeaf *item; 1000 const char *path = NULL; 1001 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; 1007 } 1008 } 1009 if (path == NULL) 1010 return(-1); 1011 return(rmdir(path)); 1012 } 1013 1014 /* 1015 * CHOWN 1016 * 1017 * Almost silently ignore chowns that fail if we are not root. 1018 */ 1019 int 1020 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group) 1021 { 1022 hctransaction_t trans; 1023 struct HCHead *head; 1024 int rc; 1025 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); 1031 } 1032 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); 1042 } 1043 1044 static int 1045 rc_chown(hctransaction_t trans __unused, struct HCHead *head) 1046 { 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; 1052 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; 1064 } 1065 } 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); 1072 } 1073 1074 /* 1075 * LCHOWN 1076 */ 1077 int 1078 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group) 1079 { 1080 hctransaction_t trans; 1081 struct HCHead *head; 1082 int rc; 1083 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); 1089 } 1090 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); 1100 } 1101 1102 static int 1103 rc_lchown(hctransaction_t trans __unused, struct HCHead *head) 1104 { 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; 1110 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; 1122 } 1123 } 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); 1130 } 1131 1132 /* 1133 * CHMOD 1134 */ 1135 int 1136 hc_chmod(struct HostConf *hc, const char *path, mode_t mode) 1137 { 1138 hctransaction_t trans; 1139 struct HCHead *head; 1140 1141 if (hc == NULL || hc->host == NULL) 1142 return(chmod(path, mode)); 1143 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); 1152 } 1153 1154 static int 1155 rc_chmod(hctransaction_t trans __unused, struct HCHead *head) 1156 { 1157 struct HCLeaf *item; 1158 const char *path = NULL; 1159 mode_t mode = 0666; 1160 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; 1169 } 1170 } 1171 if (path == NULL) 1172 return(-1); 1173 return(chmod(path, mode)); 1174 } 1175 1176 /* 1177 * MKNOD 1178 */ 1179 int 1180 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev) 1181 { 1182 hctransaction_t trans; 1183 struct HCHead *head; 1184 1185 if (hc == NULL || hc->host == NULL) 1186 return(mknod(path, mode, rdev)); 1187 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); 1197 } 1198 1199 static int 1200 rc_mknod(hctransaction_t trans __unused, struct HCHead *head) 1201 { 1202 struct HCLeaf *item; 1203 const char *path = NULL; 1204 mode_t mode = 0666; 1205 dev_t rdev = 0; 1206 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; 1218 } 1219 } 1220 if (path == NULL) 1221 return(-1); 1222 return(mknod(path, mode, rdev)); 1223 } 1224 1225 /* 1226 * LINK 1227 */ 1228 int 1229 hc_link(struct HostConf *hc, const char *name1, const char *name2) 1230 { 1231 hctransaction_t trans; 1232 struct HCHead *head; 1233 1234 if (hc == NULL || hc->host == NULL) 1235 return(link(name1, name2)); 1236 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); 1245 } 1246 1247 static int 1248 rc_link(hctransaction_t trans __unused, struct HCHead *head) 1249 { 1250 struct HCLeaf *item; 1251 const char *name1 = NULL; 1252 const char *name2 = NULL; 1253 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; 1262 } 1263 } 1264 if (name1 == NULL || name2 == NULL) 1265 return(-2); 1266 return(link(name1, name2)); 1267 } 1268 1269 #ifdef _ST_FLAGS_PRESENT_ 1270 /* 1271 * CHFLAGS 1272 */ 1273 int 1274 hc_chflags(struct HostConf *hc, const char *path, u_long flags) 1275 { 1276 hctransaction_t trans; 1277 struct HCHead *head; 1278 int rc; 1279 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); 1286 } 1287 if (rc < 0) 1288 rc = silentwarning(&chflags_warning, "file flags may differ\n"); 1289 } 1290 return (rc); 1291 } 1292 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); 1301 } 1302 1303 static int 1304 rc_chflags(hctransaction_t trans __unused, struct HCHead *head) 1305 { 1306 struct HCLeaf *item; 1307 const char *path = NULL; 1308 u_long flags = 0; 1309 int rc; 1310 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; 1319 } 1320 } 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); 1328 } 1329 if (rc < 0) 1330 rc = silentwarning(&chflags_warning, "file flags may differ\n"); 1331 } 1332 return(rc); 1333 } 1334 1335 #endif 1336 1337 /* 1338 * READLINK 1339 */ 1340 int 1341 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz) 1342 { 1343 hctransaction_t trans; 1344 struct HCHead *head; 1345 struct HCLeaf *item; 1346 int r; 1347 1348 if (hc == NULL || hc->host == NULL) 1349 return(readlink(path, buf, bufsiz)); 1350 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); 1357 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; 1369 } 1370 } 1371 return(r); 1372 } 1373 1374 static int 1375 rc_readlink(hctransaction_t trans, struct HCHead *head) 1376 { 1377 struct HCLeaf *item; 1378 const char *path = NULL; 1379 char buf[1024]; 1380 int r; 1381 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; 1387 } 1388 } 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); 1396 } 1397 1398 /* 1399 * UMASK 1400 */ 1401 mode_t 1402 hc_umask(struct HostConf *hc, mode_t numask) 1403 { 1404 hctransaction_t trans; 1405 struct HCHead *head; 1406 struct HCLeaf *item; 1407 1408 if (hc == NULL || hc->host == NULL) 1409 return(umask(numask)); 1410 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); 1417 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; 1424 } 1425 } 1426 return(numask); 1427 } 1428 1429 static int 1430 rc_umask(hctransaction_t trans, struct HCHead *head) 1431 { 1432 struct HCLeaf *item; 1433 mode_t numask = ~0666; 1434 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; 1440 } 1441 } 1442 numask = umask(numask); 1443 hcc_leaf_int32(trans, LC_MODE, numask); 1444 return(0); 1445 } 1446 1447 /* 1448 * SYMLINK 1449 */ 1450 int 1451 hc_symlink(struct HostConf *hc, const char *name1, const char *name2) 1452 { 1453 hctransaction_t trans; 1454 struct HCHead *head; 1455 1456 if (hc == NULL || hc->host == NULL) 1457 return(symlink(name1, name2)); 1458 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); 1467 } 1468 1469 static int 1470 rc_symlink(hctransaction_t trans __unused, struct HCHead *head) 1471 { 1472 struct HCLeaf *item; 1473 const char *name1 = NULL; 1474 const char *name2 = NULL; 1475 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; 1484 } 1485 } 1486 if (name1 == NULL || name2 == NULL) 1487 return(-2); 1488 return(symlink(name1, name2)); 1489 } 1490 1491 /* 1492 * RENAME 1493 */ 1494 int 1495 hc_rename(struct HostConf *hc, const char *name1, const char *name2) 1496 { 1497 hctransaction_t trans; 1498 struct HCHead *head; 1499 1500 if (hc == NULL || hc->host == NULL) 1501 return(rename(name1, name2)); 1502 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); 1511 } 1512 1513 static int 1514 rc_rename(hctransaction_t trans __unused, struct HCHead *head) 1515 { 1516 struct HCLeaf *item; 1517 const char *name1 = NULL; 1518 const char *name2 = NULL; 1519 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; 1528 } 1529 } 1530 if (name1 == NULL || name2 == NULL) 1531 return(-2); 1532 return(rename(name1, name2)); 1533 } 1534 1535 /* 1536 * UTIMES 1537 */ 1538 int 1539 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times) 1540 { 1541 hctransaction_t trans; 1542 struct HCHead *head; 1543 1544 if (hc == NULL || hc->host == NULL) 1545 return(utimes(path, times)); 1546 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); 1556 } 1557 1558 static int 1559 rc_utimes(hctransaction_t trans __unused, struct HCHead *head) 1560 { 1561 struct HCLeaf *item; 1562 struct timeval times[2]; 1563 const char *path; 1564 1565 bzero(times, sizeof(times)); 1566 path = NULL; 1567 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; 1579 } 1580 } 1581 if (path == NULL) 1582 return(-2); 1583 return(utimes(path, times)); 1584 } 1585