1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2012 STRATO AG. All rights reserved. 23 */ 24 #include <sys/zfs_context.h> 25 #include <sys/stat.h> 26 #include <sys/mkdev.h> 27 #include <sys/errno.h> 28 #include <sys/types.h> 29 #include <sys/far.h> 30 #include <sys/far_impl.h> 31 #include <sys/far_crc32c.h> 32 33 #define TEMPNAME_PREFIX "far-tempname-" 34 /* 2^128 needs 39 digits in decimal */ 35 #define TEMPNAME_SIZE (sizeof (TEMPNAME_PREFIX) + 39) 36 37 void 38 far_send_init(far_t *f) 39 { 40 f->f_alloc_len = FAR_SEND_BUF_SIZE; 41 f->f_buf = kmem_alloc(f->f_alloc_len, KM_SLEEP); 42 f->f_size = 0; 43 } 44 45 void 46 far_send_fini(far_t *f) 47 { 48 kmem_free(f->f_buf, f->f_alloc_len); 49 } 50 51 static int 52 far_send_reserve(far_t *f, void **buf, int len) 53 { 54 int res = f->f_alloc_len - f->f_size; 55 if (len > res) 56 return (-E2BIG); 57 *buf = f->f_buf + f->f_size; 58 f->f_size += len; 59 60 return (0); 61 } 62 63 static int 64 far_send_put(far_t *f, void *buf, int len) 65 { 66 int ret; 67 void *p; 68 69 ret = far_send_reserve(f, &p, len); 70 if (ret) 71 return (ret); 72 73 memcpy(p, buf, len); 74 75 return (0); 76 } 77 78 static int 79 far_send_put_attr(far_t *f, uint16_t attr, void *buf, int len) 80 { 81 far_attr_header_t hdr; 82 int ret; 83 84 LE_OUT16(&hdr.fa_type, attr); 85 LE_OUT16(&hdr.fa_len, len); 86 87 ret = far_send_put(f, &hdr, sizeof (hdr)); 88 if (ret) 89 return (ret); 90 return (far_send_put(f, buf, len)); 91 } 92 93 static int 94 far_send_reserve_attr(far_t *f, uint16_t attr, void **buf, int len) 95 { 96 far_attr_header_t hdr; 97 int ret; 98 99 LE_OUT16(&hdr.fa_type, attr); 100 LE_OUT16(&hdr.fa_len, len); 101 102 ret = far_send_put(f, &hdr, sizeof (hdr)); 103 if (ret) 104 return (ret); 105 return (far_send_reserve(f, buf, len)); 106 } 107 108 static int 109 far_send_put_u64(far_t *f, uint16_t attr, uint64_t val) 110 { 111 uint64_t v; 112 113 LE_OUT64(&v, val); 114 return (far_send_put_attr(f, attr, &v, sizeof (v))); 115 } 116 117 static int 118 far_send_put_time(far_t *f, uint16_t attr, far_time_t *t) 119 { 120 char buf[12]; 121 122 LE_OUT64(buf, t->st_sec); 123 LE_OUT32(buf + 8, t->st_nsec); 124 125 return (far_send_put_attr(f, attr, buf, sizeof (buf))); 126 } 127 128 static int 129 far_cmd_start(far_t *f, uint16_t cmd) 130 { 131 far_cmd_header_t ch; 132 133 memset(&ch, 0, sizeof (ch)); 134 LE_OUT16(&ch.fc_cmd, cmd); 135 f->f_size = 0; 136 return (far_send_put(f, &ch, sizeof (ch))); 137 } 138 139 static int 140 far_cmd_send(far_t *f) 141 { 142 far_cmd_header_t *ch; 143 uint32_t crc; 144 int ret; 145 146 ch = (far_cmd_header_t *)f->f_buf; 147 LE_OUT32(&ch->fc_len, f->f_size - sizeof (*ch)); 148 ch->fc_crc = 0; 149 150 crc = far_crc32c(0, f->f_buf, f->f_size); 151 LE_OUT32(&ch->fc_crc, crc); 152 153 ret = far_write(f, f->f_buf, f->f_size); 154 f->f_size = 0; 155 156 mutex_enter(&f->f_tods->ds_sendstream_lock); 157 *f->f_dmu_sendarg.dsa_off += f->f_size; 158 mutex_exit(&f->f_tods->ds_sendstream_lock); 159 160 return (ret); 161 } 162 163 static int 164 far_send_stream_header(far_t *f) 165 { 166 far_stream_header_t header; 167 168 strcpy(header.fs_magic, FAR_SEND_STREAM_MAGIC); 169 LE_OUT32(&header.fs_version, FAR_SEND_STREAM_VERSION); 170 171 return (far_write(f, (uint8_t *)&header, sizeof (header))); 172 } 173 174 static void 175 tempname(uint64_t ino, char *buf, int maxlen) 176 { 177 int l = sizeof (TEMPNAME_PREFIX) - 1; 178 memcpy(buf, TEMPNAME_PREFIX, MIN(maxlen, l)); 179 snprintf(buf + l, maxlen - l, "%llu", (long long)ino); 180 } 181 182 static void 183 path_add_name(far_path_t **fp, char *name, int namelen) 184 { 185 far_path_t *new; 186 187 new = kmem_alloc(sizeof (*new) + namelen + 1, KM_SLEEP); 188 new->fp_next = *fp; 189 new->fp_len = namelen + 1; 190 new->fp_total_len = namelen + 1; 191 if (*fp) 192 new->fp_total_len += (*fp)->fp_total_len; 193 memcpy(new->fp_buf, name, namelen); 194 new->fp_buf[namelen] = '\0'; 195 *fp = new; 196 } 197 198 static void 199 path_copy(far_path_t *fp, char *b) 200 { 201 far_path_t *cur; 202 203 for (cur = fp; cur; cur = cur->fp_next) { 204 *b = '/'; 205 memcpy(b + 1, cur->fp_buf, cur->fp_len - 1); 206 b += cur->fp_len; 207 } 208 } 209 210 static void 211 path2buf(far_path_t *fp, char **buf, int *buf_len) 212 { 213 char *b; 214 215 *buf_len = fp->fp_total_len + 1; /* one for the trailing 0-byte */ 216 *buf = b = kmem_alloc(*buf_len, KM_SLEEP); 217 218 path_copy(fp, b); 219 220 b[*buf_len - 1] = '\0'; 221 } 222 223 static int 224 put_path(far_t *f, uint16_t attr, far_path_t *fp) 225 { 226 int ret; 227 void *p; 228 229 ret = far_send_reserve_attr(f, attr, &p, fp->fp_total_len); 230 if (ret) 231 return (ret); 232 path_copy(fp, p); 233 234 return (0); 235 } 236 237 void 238 far_path_free(far_path_t *fp) 239 { 240 far_path_t *next; 241 while (fp) { 242 next = fp->fp_next; 243 kmem_free(fp, fp->fp_len + sizeof (*fp)); 244 fp = next; 245 } 246 } 247 248 static int 249 is_ino_run(far_t *f, uint64_t ino) 250 { 251 int ret; 252 far_info_t si; 253 254 while (1) { 255 if (ino > f->f_current_ino) 256 return (0); 257 ret = far_get_info(f, ino, FAR_OLD, &si, 0); 258 if (ret && ret != ENOENT) 259 return (ret); 260 if (ret != ENOENT) 261 break; 262 ret = far_get_info(f, ino, FAR_NEW, &si, FI_ATTR_PARENT); 263 if (ret && ret != ENOENT) 264 return (ret); 265 if (ret) 266 return (0); /* ignore for now */ 267 ino = si.si_parent; 268 } 269 return (1); 270 } 271 272 static int 273 build_path(far_t *f, far_dirent_t *dirent, uint64_t ino, 274 int devise_tempname, far_which_t which_in, far_path_t **fp) 275 { 276 int ret = 0; 277 far_dirent_t *de; 278 far_info_t si; 279 far_which_t which; 280 far_dirent_t temp_dirent; 281 char temp_buf[TEMPNAME_SIZE]; 282 283 if (devise_tempname) { 284 if (!dirent) 285 return (EINVAL); 286 temp_dirent = *dirent; 287 tempname(ino, temp_buf, sizeof (temp_buf)); 288 temp_dirent.fd_name = temp_buf; 289 dirent = &temp_dirent; 290 } 291 292 *fp = NULL; 293 294 for (de = dirent; de; de = de->fd_prev) { 295 path_add_name(fp, de->fd_name, strlen(de->fd_name)); 296 ino = de->fd_parent_ino; 297 } 298 299 /* 300 * XXX TODO check if f->f_current_path is set. if yes, use it instead. 301 * otherwise save result of loop below to f_current_path 302 */ 303 while (1) { 304 int namebuflen; 305 char *name; 306 char *t_name; 307 uint64_t old_parent; 308 uint64_t new_parent; 309 uint64_t old_gen = 0; 310 uint64_t new_gen = 0; 311 uint64_t parent; 312 int check_tempname; 313 uint64_t old_mode = 0; 314 315 old_parent = 0; 316 new_parent = 0; 317 check_tempname = 0; 318 ret = far_get_info(f, ino, FAR_OLD, &si, FI_ATTR_PARENT | 319 FI_ATTR_GEN | FI_ATTR_MODE); 320 if (ret && ret != ENOENT) 321 return (ret); 322 if (ret == 0) { 323 old_parent = si.si_parent; 324 old_gen = si.si_gen; 325 old_mode = si.si_mode; 326 } 327 ret = far_get_info(f, ino, FAR_NEW, &si, FI_ATTR_PARENT | 328 FI_ATTR_GEN | FI_ATTR_MODE); 329 if (ret && ret != ENOENT) 330 return (ret); 331 if (ret == 0) { 332 new_parent = si.si_parent; 333 new_gen = si.si_gen; 334 } 335 if (old_parent && new_parent && old_gen != new_gen && 336 !(S_ISDIR(old_mode) && S_ISDIR(si.si_mode))) { 337 if (which_in == FAR_OLD) { 338 new_parent = 0; 339 } else if (which_in == FAR_NEW) { 340 old_parent = 0; 341 if (S_ISDIR(si.si_mode)) 342 check_tempname = 1; 343 } 344 } 345 346 if (f->f_pass == PASS_LINK) { 347 if (old_parent && !new_parent) { 348 which = FAR_OLD; 349 } else if (!old_parent && new_parent) { 350 which = FAR_NEW; 351 } else if (is_ino_run(f, new_parent)) { 352 check_tempname = 1; 353 which = FAR_NEW; 354 } else { 355 which = FAR_OLD; 356 } 357 } else { 358 if (old_parent && !new_parent) { 359 which = FAR_OLD; 360 } else { 361 check_tempname = 1; 362 which = FAR_NEW; 363 } 364 } 365 if (which == FAR_OLD) 366 parent = old_parent; 367 else 368 parent = new_parent; 369 if (parent == ino) 370 break; 371 ret = far_find_entry(f, parent, ino, which, &t_name); 372 if (ret) 373 return (ret); 374 name = strdup(t_name); 375 far_free_name(t_name); 376 namebuflen = strlen(name) + 1; 377 if (check_tempname) { 378 far_info_t si_old; 379 far_info_t si_new; 380 381 ret = far_get_info(f, parent, FAR_OLD, 382 &si_old, FI_ATTR_GEN); 383 if (ret && ret != ENOENT) 384 return (ret); 385 if (ret == 0) { 386 ret = far_get_info(f, parent, FAR_NEW, 387 &si_new, FI_ATTR_GEN); 388 if (ret) 389 return (ret); 390 if (si_old.si_gen != si_new.si_gen) 391 check_tempname = 0; 392 } else { 393 check_tempname = 0; 394 } 395 } 396 if (check_tempname) { 397 uint64_t old_ino; 398 399 ret = far_lookup_entry(f, parent, name, 400 FAR_OLD, &old_ino); 401 if (ret && ret != ENOENT) { 402 far_free_name(name); 403 return (ret); 404 } 405 if ((ret == 0 && old_ino != ino) || 406 (ret == 0 && S_ISDIR(si.si_mode) && 407 !S_ISDIR(old_mode) && old_ino == ino)) { 408 int ret; 409 uint64_t cnt = 1; 410 411 if (f->f_pass == PASS_UNLINK && 412 new_parent < f->f_current_ino) { 413 ret = far_get_count(&f->f_put_back_cnt, 414 old_ino, &cnt, NULL); 415 if (ret && ret != ENOENT) 416 return (ret); 417 } 418 if (cnt) { 419 kmem_free(name, namebuflen); 420 namebuflen = TEMPNAME_SIZE; 421 name = kmem_alloc(namebuflen, KM_SLEEP); 422 tempname(ino, name, namebuflen); 423 } 424 } 425 } 426 ino = parent; 427 path_add_name(fp, name, strlen(name)); 428 kmem_free(name, namebuflen); 429 } 430 if (*fp == NULL) 431 path_add_name(fp, "", 0); 432 433 return (0); 434 } 435 436 int 437 far_send_start(far_t *f) 438 { 439 int ret; 440 uint8_t o_uuid[16]; 441 uint8_t n_uuid[16]; 442 uint64_t o_ctrans; 443 uint64_t n_ctrans; 444 char *path = NULL; 445 int len; 446 char *p; 447 int cmd = FAR_CMD_SUBVOL; 448 449 ret = far_send_stream_header(f); 450 if (ret) { 451 far_abort(f); 452 return (ret); 453 } 454 455 if ((ret = far_get_uuid(f, FAR_NEW, n_uuid)) || 456 (ret = far_get_ctransid(f, FAR_NEW, &n_ctrans)) || 457 (ret = far_get_snapname(f, FAR_NEW, &path, &len))) 458 goto out; 459 /* for now, strip the pool name */ 460 if ((p = strchr(path, '/'))) 461 ++p; 462 else 463 p = path; 464 ret = far_get_uuid(f, FAR_OLD, o_uuid); 465 if (ret && ret != ENOENT) 466 goto out; 467 if (ret == 0) { 468 ret = far_get_ctransid(f, FAR_OLD, &o_ctrans); 469 if (ret) 470 goto out; 471 cmd = FAR_CMD_SNAPSHOT; 472 } 473 if ((ret = far_cmd_start(f, cmd)) || 474 (ret = far_send_put_attr(f, FAR_ATTR_PATH, p, strlen(p))) || 475 (ret = far_send_put_u64(f, FAR_ATTR_CTRANSID, n_ctrans)) || 476 (ret = far_send_put_attr(f, FAR_ATTR_UUID, n_uuid, 16))) 477 goto out; 478 if (cmd == FAR_CMD_SNAPSHOT) { 479 if ((ret = far_send_put_u64(f, FAR_ATTR_CLONE_CTRANSID, 480 o_ctrans)) || 481 (ret = far_send_put_attr(f, FAR_ATTR_CLONE_UUID, 482 o_uuid, 16))) 483 goto out; 484 } 485 ret = far_cmd_send(f); 486 487 out: 488 kmem_free(path, len); 489 490 return (ret); 491 } 492 493 int 494 far_send_create_file(far_t *f, far_dirent_t *dirent, uint64_t ino, 495 int devise_tempname, far_path_t **path_ret) 496 { 497 far_path_t *path = NULL; 498 far_info_t si; 499 int ret; 500 int send_rdev = 0; 501 int cmd; 502 uint64_t rdev = 0; 503 char *symlink = NULL; 504 int symlen = 0; 505 506 ret = build_path(f, dirent, ino, devise_tempname, FAR_NEW, &path); 507 if (ret) 508 goto out; 509 510 ret = far_get_info(f, ino, FAR_NEW, &si, 511 FI_ATTR_MODE | FI_ATTR_UID | FI_ATTR_GID); 512 if (ret) 513 goto out; 514 515 if (S_ISREG(si.si_mode)) { 516 cmd = FAR_CMD_MKFILE; 517 } else if (S_ISDIR(si.si_mode)) { 518 cmd = FAR_CMD_MKDIR; 519 } else if (S_ISLNK(si.si_mode)) { 520 cmd = FAR_CMD_SYMLINK; 521 ret = far_read_symlink(f, ino, FAR_NEW, &symlink, &symlen); 522 if (ret) 523 goto out; 524 } else if (S_ISCHR(si.si_mode) || S_ISBLK(si.si_mode)) { 525 cmd = FAR_CMD_MKNOD; 526 send_rdev = 1; 527 } else if (S_ISFIFO(si.si_mode)) { 528 cmd = FAR_CMD_MKFIFO; 529 } else if (S_ISSOCK(si.si_mode)) { 530 cmd = FAR_CMD_MKSOCK; 531 } else { 532 /* unknown file type, ignore for now */ 533 return (0); 534 } 535 536 if (send_rdev) { 537 far_info_t sirdev; 538 uint64_t r_major; 539 uint64_t r_minor; 540 ret = far_get_info(f, ino, FAR_NEW, &sirdev, FI_ATTR_RDEV); 541 if (ret) 542 goto out; 543 rdev = sirdev.si_rdev; 544 545 /* XXX hardcodedly transform rdev to linux form */ 546 r_major = rdev >> 32; 547 r_minor = rdev & 0xffffffful; 548 rdev = ((r_minor & 0xff) | ((r_major & 0xfff) << 8) | 549 ((r_minor >> 8) << 20) | ((r_major >> 12) << 44)); 550 } 551 /* send MKFILE */ 552 if ((ret = far_cmd_start(f, cmd)) || 553 (ret = put_path(f, FAR_ATTR_PATH, path)) || 554 (ret = far_send_put_u64(f, FAR_ATTR_INO, ino))) 555 goto out; 556 if (send_rdev) { 557 ret = far_send_put_u64(f, FAR_ATTR_RDEV, rdev); 558 if (ret) 559 goto out; 560 ret = far_send_put_u64(f, FAR_ATTR_MODE, si.si_mode); 561 if (ret) 562 goto out; 563 } 564 if (S_ISLNK(si.si_mode)) { 565 ret = far_send_put_attr(f, FAR_ATTR_PATH_LINK, 566 symlink, strlen(symlink)); 567 if (ret) 568 goto out; 569 } 570 if ((ret = far_cmd_send(f))) 571 goto out; 572 573 /* send CHOWN */ 574 if ((ret = far_cmd_start(f, FAR_CMD_CHOWN)) || 575 (ret = put_path(f, FAR_ATTR_PATH, path)) || 576 (ret = far_send_put_u64(f, FAR_ATTR_UID, si.si_uid)) || 577 (ret = far_send_put_u64(f, FAR_ATTR_GID, si.si_gid)) || 578 (ret = far_cmd_send(f))) 579 goto out; 580 581 /* send CHMOD, but not for symlinks */ 582 if (!S_ISLNK(si.si_mode)) { 583 if ((ret = far_cmd_start(f, FAR_CMD_CHMOD)) || 584 (ret = put_path(f, FAR_ATTR_PATH, path)) || 585 (ret = far_send_put_u64(f, FAR_ATTR_MODE, 586 si.si_mode & 0xfff)) || 587 (ret = far_cmd_send(f))) 588 goto out; 589 } 590 591 out: 592 if (ret == 0 && path_ret) 593 *path_ret = path; 594 else 595 far_path_free(path); 596 if (symlink) 597 kmem_free(symlink, symlen); 598 return (ret); 599 } 600 601 int 602 far_send_link(far_t *f, far_dirent_t *new_dirent, uint64_t ino, 603 uint64_t old_parent_ino, far_which_t which, int devise_tempname) 604 { 605 far_path_t *new_path = NULL; 606 far_path_t *old_path = NULL; 607 int ret; 608 far_dirent_t old_dirent = { 609 .fd_name = NULL, 610 .fd_parent_ino = old_parent_ino, 611 .fd_prev = NULL, 612 }; 613 614 ret = far_find_entry(f, old_parent_ino, ino, which, 615 &old_dirent.fd_name); 616 if (ret) 617 return (ret); 618 ret = build_path(f, &old_dirent, ino, 0, FAR_OLD, &old_path); 619 if (ret) 620 goto out; 621 622 ret = build_path(f, new_dirent, ino, devise_tempname, FAR_NEW, 623 &new_path); 624 if (ret) 625 goto out; 626 627 if ((ret = far_cmd_start(f, FAR_CMD_LINK)) || 628 (ret = put_path(f, FAR_ATTR_PATH_LINK, old_path)) || 629 (ret = put_path(f, FAR_ATTR_PATH, new_path)) || 630 (ret = far_cmd_send(f))) 631 goto out; 632 633 if (f->f_pass == PASS_UNLINK) 634 ret = far_send_mtime_update(f, new_dirent, ino); 635 out: 636 if (old_dirent.fd_name) 637 kmem_free(old_dirent.fd_name, strlen(old_dirent.fd_name) + 1); 638 far_path_free(old_path); 639 far_path_free(new_path); 640 return (ret); 641 } 642 643 int 644 far_send_mkdir(far_t *f, far_dirent_t *dirent, 645 uint64_t ino, int devise_tempname) 646 { 647 far_path_t *path = NULL; 648 far_info_t si; 649 int ret; 650 651 ret = build_path(f, dirent, ino, devise_tempname, FAR_NEW, &path); 652 if (ret) 653 goto out; 654 655 ret = far_get_info(f, ino, FAR_NEW, &si, 656 FI_ATTR_UID | FI_ATTR_GID | FI_ATTR_MODE); 657 if (ret) 658 goto out; 659 660 if (path->fp_total_len != 1) { 661 /* don't send an mkdir for the root, but send chown/chmod */ 662 if ((ret = far_cmd_start(f, FAR_CMD_MKDIR)) || 663 (ret = put_path(f, FAR_ATTR_PATH, path)) || 664 (ret = far_send_put_u64(f, FAR_ATTR_INO, ino)) || 665 (ret = far_cmd_send(f))) 666 goto out; 667 } 668 669 /* send CHOWN */ 670 if ((ret = far_cmd_start(f, FAR_CMD_CHOWN)) || 671 (ret = put_path(f, FAR_ATTR_PATH, path)) || 672 (ret = far_send_put_u64(f, FAR_ATTR_UID, si.si_uid)) || 673 (ret = far_send_put_u64(f, FAR_ATTR_GID, si.si_gid)) || 674 (ret = far_cmd_send(f))) 675 goto out; 676 677 /* send CHMOD */ 678 if ((ret = far_cmd_start(f, FAR_CMD_CHMOD)) || 679 (ret = put_path(f, FAR_ATTR_PATH, path)) || 680 (ret = far_send_put_u64(f, FAR_ATTR_MODE, 681 si.si_mode & 0xfff)) || 682 (ret = far_cmd_send(f))) 683 goto out; 684 685 out: 686 far_path_free(path); 687 return (ret); 688 } 689 690 /* this one is only used for directory renames */ 691 int 692 far_send_rename(far_t *f, far_dirent_t *new_dirent, uint64_t ino, 693 uint64_t old_parent_ino, int devise_tempname) 694 { 695 far_path_t *new_path = NULL; 696 far_path_t *old_path = NULL; 697 int ret; 698 far_dirent_t old_dirent = { 699 .fd_name = NULL, 700 .fd_parent_ino = old_parent_ino, 701 .fd_prev = NULL, 702 }; 703 704 ret = far_find_entry(f, old_parent_ino, ino, FAR_OLD, 705 &old_dirent.fd_name); 706 if (ret) 707 return (ret); 708 ret = build_path(f, &old_dirent, ino, 0, FAR_OLD, &old_path); 709 if (ret) 710 goto out; 711 712 ret = build_path(f, new_dirent, ino, devise_tempname, FAR_NEW, 713 &new_path); 714 if (ret) 715 goto out; 716 717 if ((ret = far_cmd_start(f, FAR_CMD_RENAME)) || 718 (ret = put_path(f, FAR_ATTR_PATH, old_path)) || 719 (ret = put_path(f, FAR_ATTR_PATH_TO, new_path)) || 720 (ret = far_cmd_send(f))) 721 goto out; 722 out: 723 far_path_free(old_path); 724 far_path_free(new_path); 725 return (ret); 726 } 727 728 int 729 far_send_rename_from_tempname(far_t *f, far_dirent_t *dirent, 730 uint64_t ino, uint64_t old) 731 { 732 char buf[TEMPNAME_SIZE]; 733 far_path_t *new_path = NULL; 734 far_path_t *old_path = NULL; 735 int ret; 736 far_dirent_t old_dirent; 737 738 tempname(old, buf, sizeof (buf)); 739 old_dirent = *dirent; 740 old_dirent.fd_name = buf; 741 742 ret = build_path(f, &old_dirent, old, 0, FAR_OLD, &old_path); 743 if (ret) 744 goto out; 745 ret = build_path(f, dirent, ino, 0, FAR_NEW, &new_path); 746 if (ret) 747 goto out; 748 749 if ((ret = far_cmd_start(f, FAR_CMD_RENAME)) || 750 (ret = put_path(f, FAR_ATTR_PATH, old_path)) || 751 (ret = put_path(f, FAR_ATTR_PATH_TO, new_path)) || 752 (ret = far_cmd_send(f))) 753 goto out; 754 755 ret = far_send_mtime_update(f, dirent, old); 756 757 out: 758 far_path_free(old_path); 759 far_path_free(new_path); 760 return (ret); 761 } 762 763 int 764 far_send_unlink(far_t *f, far_dirent_t *dirent, uint64_t ino) 765 { 766 far_path_t *path = NULL; 767 int ret; 768 769 ret = build_path(f, dirent, ino, 0, FAR_OLD, &path); 770 if (ret) 771 goto out; 772 773 if ((ret = far_cmd_start(f, FAR_CMD_UNLINK)) || 774 (ret = put_path(f, FAR_ATTR_PATH, path)) || 775 (ret = far_cmd_send(f))) 776 goto out; 777 778 out: 779 far_path_free(path); 780 return (ret); 781 } 782 783 int 784 far_send_rmdir(far_t *f, far_dirent_t *dirent, uint64_t ino) 785 { 786 far_path_t *path; 787 int ret; 788 789 ret = build_path(f, dirent, ino, 0, FAR_OLD, &path); 790 if (ret) 791 goto out; 792 793 if ((ret = far_cmd_start(f, FAR_CMD_RMDIR)) || 794 (ret = put_path(f, FAR_ATTR_PATH, path)) || 795 (ret = far_cmd_send(f))) 796 goto out; 797 798 out: 799 far_path_free(path); 800 return (ret); 801 } 802 803 int 804 far_send_file_data(far_t *f, far_path_t **path_p, 805 far_dirent_t *dirent, uint64_t ino, 806 uint64_t off, uint64_t len, void *data) 807 { 808 int ret = 0; 809 810 if (!*path_p) { 811 ret = build_path(f, dirent, ino, 0, FAR_NEW, path_p); 812 if (ret) 813 return (ret); 814 } 815 816 while (len) { 817 uint64_t l = MIN(len, FAR_SEND_READ_SIZE); 818 819 if ((ret = far_cmd_start(f, FAR_CMD_WRITE)) || 820 (ret = put_path(f, FAR_ATTR_PATH, *path_p)) || 821 (ret = far_send_put_u64(f, FAR_ATTR_FILE_OFFSET, off))|| 822 (ret = far_send_put_attr(f, FAR_ATTR_DATA, data, l)) || 823 (ret = far_cmd_send(f))) 824 goto out; 825 data += l; 826 off += l; 827 len -= l; 828 } 829 830 out: 831 return (ret); 832 } 833 834 int 835 far_send_mtime_update(far_t *f, far_dirent_t *dirent, uint64_t ino) 836 { 837 far_path_t *path = NULL; 838 int ret; 839 far_info_t si; 840 841 ret = far_get_info(f, ino, FAR_NEW, &si, 842 FI_ATTR_ATIME | FI_ATTR_MTIME | 843 FI_ATTR_CTIME | FI_ATTR_OTIME); 844 if (ret) { 845 if (ret == ENOENT) 846 ret = 0; 847 goto out; 848 } 849 850 ret = build_path(f, dirent, ino, 0, FAR_NEW, &path); 851 if (ret) 852 goto out; 853 854 if ((ret = far_cmd_start(f, FAR_CMD_UTIMES)) || 855 (ret = put_path(f, FAR_ATTR_PATH, path)) || 856 (ret = far_send_put_time(f, FAR_ATTR_ATIME, &si.si_atime)) || 857 (ret = far_send_put_time(f, FAR_ATTR_MTIME, &si.si_mtime)) || 858 (ret = far_send_put_time(f, FAR_ATTR_CTIME, &si.si_ctime)) || 859 (ret = far_send_put_time(f, FAR_ATTR_OTIME, &si.si_otime)) || 860 (ret = far_cmd_send(f))) 861 goto out; 862 863 out: 864 far_path_free(path); 865 return (ret); 866 } 867 868 int 869 far_send_truncate(far_t *f, far_dirent_t *dirent, uint64_t ino, 870 uint64_t new_size) 871 { 872 far_path_t *path = NULL; 873 int ret; 874 875 ret = build_path(f, dirent, ino, 0, FAR_NEW, &path); 876 if (ret) 877 return (ret); 878 879 if ((ret = far_cmd_start(f, FAR_CMD_TRUNCATE)) || 880 (ret = put_path(f, FAR_ATTR_PATH, path)) || 881 (ret = far_send_put_u64(f, FAR_ATTR_SIZE, new_size)) || 882 (ret = far_cmd_send(f))) 883 goto out; 884 885 out: 886 far_path_free(path); 887 return (ret); 888 } 889 890 int 891 far_send_chown(far_t *f, far_dirent_t *dirent, uint64_t ino, 892 uint64_t new_uid, uint64_t new_gid) 893 { 894 far_path_t *path = NULL; 895 int ret; 896 897 ret = build_path(f, dirent, ino, 0, FAR_NEW, &path); 898 if (ret) 899 return (ret); 900 901 if ((ret = far_cmd_start(f, FAR_CMD_CHOWN)) || 902 (ret = put_path(f, FAR_ATTR_PATH, path)) || 903 (ret = far_send_put_u64(f, FAR_ATTR_UID, new_uid)) || 904 (ret = far_send_put_u64(f, FAR_ATTR_GID, new_gid)) || 905 (ret = far_cmd_send(f))) 906 goto out; 907 908 out: 909 far_path_free(path); 910 return (ret); 911 } 912 913 int 914 far_send_chmod(far_t *f, far_dirent_t *dirent, uint64_t ino, 915 uint64_t new_mode) 916 { 917 far_path_t *path = NULL; 918 int ret; 919 920 ret = build_path(f, dirent, ino, 0, FAR_NEW, &path); 921 if (ret) 922 return (ret); 923 924 if ((ret = far_cmd_start(f, FAR_CMD_CHMOD)) || 925 (ret = put_path(f, FAR_ATTR_PATH, path)) || 926 (ret = far_send_put_u64(f, FAR_ATTR_MODE, new_mode)) || 927 (ret = far_cmd_send(f))) 928 goto out; 929 930 out: 931 far_path_free(path); 932 return (ret); 933 } 934 935 int 936 far_send_end(far_t *f) 937 { 938 int ret; 939 940 if ((ret = far_cmd_start(f, FAR_CMD_END)) || 941 (ret = far_cmd_send(f))) 942 goto out; 943 944 out: 945 return (ret); 946 }