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/fits.h> 30 #include <sys/fits_impl.h> 31 #include <sys/fits_crc32c.h> 32 33 #define TEMPNAME_PREFIX "fits-tempname-" 34 /* 2^128 needs 39 digits in decimal */ 35 #define TEMPNAME_SIZE (sizeof (TEMPNAME_PREFIX) + 39) 36 37 void 38 fits_send_init(fits_t *f) 39 { 40 f->f_alloc_len = FITS_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 fits_send_fini(fits_t *f) 47 { 48 kmem_free(f->f_buf, f->f_alloc_len); 49 } 50 51 static int 52 fits_send_reserve(fits_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 fits_send_put(fits_t *f, void *buf, int len) 65 { 66 int ret; 67 void *p; 68 69 ret = fits_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 fits_send_put_attr(fits_t *f, uint16_t attr, void *buf, int len) 80 { 81 fits_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 = fits_send_put(f, &hdr, sizeof (hdr)); 88 if (ret) 89 return (ret); 90 return (fits_send_put(f, buf, len)); 91 } 92 93 static int 94 fits_send_reserve_attr(fits_t *f, uint16_t attr, void **buf, int len) 95 { 96 fits_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 = fits_send_put(f, &hdr, sizeof (hdr)); 103 if (ret) 104 return (ret); 105 return (fits_send_reserve(f, buf, len)); 106 } 107 108 static int 109 fits_send_put_u64(fits_t *f, uint16_t attr, uint64_t val) 110 { 111 uint64_t v; 112 113 LE_OUT64(&v, val); 114 return (fits_send_put_attr(f, attr, &v, sizeof (v))); 115 } 116 117 static int 118 fits_send_put_time(fits_t *f, uint16_t attr, fits_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 (fits_send_put_attr(f, attr, buf, sizeof (buf))); 126 } 127 128 static int 129 fits_cmd_start(fits_t *f, uint16_t cmd) 130 { 131 fits_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 (fits_send_put(f, &ch, sizeof (ch))); 137 } 138 139 static int 140 fits_cmd_send(fits_t *f) 141 { 142 fits_cmd_header_t *ch; 143 uint32_t crc; 144 int ret; 145 146 ch = (fits_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 = fits_crc32c(0, f->f_buf, f->f_size); 151 LE_OUT32(&ch->fc_crc, crc); 152 153 ret = fits_write(f, f->f_buf, f->f_size); 154 f->f_size = 0; 155 156 return (ret); 157 } 158 159 static int 160 fits_send_stream_header(fits_t *f) 161 { 162 fits_stream_header_t header; 163 164 strcpy(header.fs_magic, FITS_SEND_STREAM_MAGIC); 165 LE_OUT32(&header.fs_version, FITS_SEND_STREAM_VERSION); 166 167 return (fits_write(f, (uint8_t *)&header, sizeof (header))); 168 } 169 170 static void 171 tempname(uint64_t ino, char *buf, int maxlen) 172 { 173 int l = sizeof (TEMPNAME_PREFIX) - 1; 174 memcpy(buf, TEMPNAME_PREFIX, MIN(maxlen, l)); 175 snprintf(buf + l, maxlen - l, "%llu", (long long)ino); 176 } 177 178 static void 179 path_add_name(fits_path_t **fp, char *name, int namelen) 180 { 181 fits_path_t *new; 182 183 new = kmem_alloc(sizeof (*new) + namelen + 1, KM_SLEEP); 184 new->fp_next = *fp; 185 new->fp_len = namelen + 1; 186 new->fp_total_len = namelen + 1; 187 if (*fp) 188 new->fp_total_len += (*fp)->fp_total_len; 189 memcpy(new->fp_buf, name, namelen); 190 new->fp_buf[namelen] = '\0'; 191 *fp = new; 192 } 193 194 static void 195 path_copy(fits_path_t *fp, char *b) 196 { 197 fits_path_t *cur; 198 199 for (cur = fp; cur; cur = cur->fp_next) { 200 *b = '/'; 201 memcpy(b + 1, cur->fp_buf, cur->fp_len - 1); 202 b += cur->fp_len; 203 } 204 } 205 206 static void 207 path2buf(fits_path_t *fp, char **buf, int *buf_len) 208 { 209 char *b; 210 211 *buf_len = fp->fp_total_len + 1; /* one for the trailing 0-byte */ 212 *buf = b = kmem_alloc(*buf_len, KM_SLEEP); 213 214 path_copy(fp, b); 215 216 b[*buf_len - 1] = '\0'; 217 } 218 219 static int 220 put_path(fits_t *f, uint16_t attr, fits_path_t *fp) 221 { 222 int ret; 223 void *p; 224 225 ret = fits_send_reserve_attr(f, attr, &p, fp->fp_total_len); 226 if (ret) 227 return (ret); 228 path_copy(fp, p); 229 230 return (0); 231 } 232 233 void 234 fits_path_free(fits_path_t *fp) 235 { 236 fits_path_t *next; 237 while (fp) { 238 next = fp->fp_next; 239 kmem_free(fp, fp->fp_len + sizeof (*fp)); 240 fp = next; 241 } 242 } 243 244 static int 245 is_ino_run(fits_t *f, uint64_t ino) 246 { 247 int ret; 248 fits_info_t si; 249 250 while (1) { 251 if (ino > f->f_current_ino) 252 return (0); 253 ret = fits_get_info(f, ino, FITS_OLD, &si, 0); 254 if (ret && ret != ENOENT) 255 return (ret); 256 if (ret != ENOENT) 257 break; 258 ret = fits_get_info(f, ino, FITS_NEW, &si, FI_ATTR_PARENT); 259 if (ret && ret != ENOENT) 260 return (ret); 261 if (ret) 262 return (0); /* ignore for now */ 263 ino = si.si_parent; 264 } 265 return (1); 266 } 267 268 static int 269 build_path(fits_t *f, fits_dirent_t *dirent, uint64_t ino, 270 int devise_tempname, fits_which_t which_in, fits_path_t **fp) 271 { 272 int ret = 0; 273 fits_dirent_t *de; 274 fits_info_t si; 275 fits_which_t which; 276 fits_dirent_t temp_dirent; 277 char temp_buf[TEMPNAME_SIZE]; 278 279 if (devise_tempname) { 280 if (!dirent) 281 return (EINVAL); 282 temp_dirent = *dirent; 283 tempname(ino, temp_buf, sizeof (temp_buf)); 284 temp_dirent.fd_name = temp_buf; 285 dirent = &temp_dirent; 286 } 287 288 *fp = NULL; 289 290 for (de = dirent; de; de = de->fd_prev) { 291 path_add_name(fp, de->fd_name, strlen(de->fd_name)); 292 ino = de->fd_parent_ino; 293 } 294 295 /* 296 * XXX TODO check if f->f_current_path is set. if yes, use it instead. 297 * otherwise save result of loop below to f_current_path 298 */ 299 while (1) { 300 int namebuflen; 301 char *name; 302 char *t_name; 303 uint64_t old_parent; 304 uint64_t new_parent; 305 uint64_t old_gen = 0; 306 uint64_t new_gen = 0; 307 uint64_t parent; 308 int check_tempname; 309 uint64_t old_mode = 0; 310 311 old_parent = 0; 312 new_parent = 0; 313 check_tempname = 0; 314 ret = fits_get_info(f, ino, FITS_OLD, &si, FI_ATTR_PARENT | 315 FI_ATTR_GEN | FI_ATTR_MODE); 316 if (ret && ret != ENOENT) 317 return (ret); 318 if (ret == 0) { 319 old_parent = si.si_parent; 320 old_gen = si.si_gen; 321 old_mode = si.si_mode; 322 } 323 ret = fits_get_info(f, ino, FITS_NEW, &si, FI_ATTR_PARENT | 324 FI_ATTR_GEN | FI_ATTR_MODE); 325 if (ret && ret != ENOENT) 326 return (ret); 327 if (ret == 0) { 328 new_parent = si.si_parent; 329 new_gen = si.si_gen; 330 } 331 if (old_parent && new_parent && old_gen != new_gen && 332 !(S_ISDIR(old_mode) && S_ISDIR(si.si_mode))) { 333 if (which_in == FITS_OLD) { 334 new_parent = 0; 335 } else if (which_in == FITS_NEW) { 336 old_parent = 0; 337 if (S_ISDIR(si.si_mode)) 338 check_tempname = 1; 339 } 340 } 341 342 if (f->f_pass == PASS_LINK) { 343 if (old_parent && !new_parent) { 344 which = FITS_OLD; 345 } else if (!old_parent && new_parent) { 346 which = FITS_NEW; 347 } else if (is_ino_run(f, new_parent)) { 348 check_tempname = 1; 349 which = FITS_NEW; 350 } else { 351 which = FITS_OLD; 352 } 353 } else { 354 if (old_parent && !new_parent) { 355 which = FITS_OLD; 356 } else { 357 check_tempname = 1; 358 which = FITS_NEW; 359 } 360 } 361 if (which == FITS_OLD) 362 parent = old_parent; 363 else 364 parent = new_parent; 365 if (parent == ino) 366 break; 367 ret = fits_find_entry(f, parent, ino, which, &t_name); 368 if (ret) 369 return (ret); 370 name = strdup(t_name); 371 fits_free_name(t_name); 372 namebuflen = strlen(name) + 1; 373 if (check_tempname) { 374 fits_info_t si_old; 375 fits_info_t si_new; 376 377 ret = fits_get_info(f, parent, FITS_OLD, 378 &si_old, FI_ATTR_GEN); 379 if (ret && ret != ENOENT) 380 return (ret); 381 if (ret == 0) { 382 ret = fits_get_info(f, parent, FITS_NEW, 383 &si_new, FI_ATTR_GEN); 384 if (ret) 385 return (ret); 386 if (si_old.si_gen != si_new.si_gen) 387 check_tempname = 0; 388 } else { 389 check_tempname = 0; 390 } 391 } 392 if (check_tempname) { 393 uint64_t old_ino; 394 395 ret = fits_lookup_entry(f, parent, name, 396 FITS_OLD, &old_ino); 397 if (ret && ret != ENOENT) { 398 fits_free_name(name); 399 return (ret); 400 } 401 if ((ret == 0 && old_ino != ino) || 402 (ret == 0 && S_ISDIR(si.si_mode) && 403 !S_ISDIR(old_mode) && old_ino == ino)) { 404 int ret; 405 uint64_t cnt = 1; 406 407 if (f->f_pass == PASS_UNLINK && 408 new_parent < f->f_current_ino) { 409 ret = fits_get_count(&f->f_put_back_cnt, 410 old_ino, &cnt, NULL); 411 if (ret && ret != ENOENT) 412 return (ret); 413 } 414 if (cnt) { 415 kmem_free(name, namebuflen); 416 namebuflen = TEMPNAME_SIZE; 417 name = kmem_alloc(namebuflen, KM_SLEEP); 418 tempname(ino, name, namebuflen); 419 } 420 } 421 } 422 ino = parent; 423 path_add_name(fp, name, strlen(name)); 424 kmem_free(name, namebuflen); 425 } 426 if (*fp == NULL) 427 path_add_name(fp, "", 0); 428 429 return (0); 430 } 431 432 int 433 fits_send_start(fits_t *f) 434 { 435 int ret; 436 uint8_t o_uuid[16]; 437 uint8_t n_uuid[16]; 438 uint64_t o_ctrans; 439 uint64_t n_ctrans; 440 char *path = NULL; 441 int len; 442 char *p; 443 int cmd = FITS_CMD_SUBVOL; 444 445 ret = fits_send_stream_header(f); 446 if (ret) { 447 fits_abort(f); 448 return (ret); 449 } 450 451 if ((ret = fits_get_uuid(f, FITS_NEW, n_uuid)) || 452 (ret = fits_get_ctransid(f, FITS_NEW, &n_ctrans)) || 453 (ret = fits_get_snapname(f, FITS_NEW, &path, &len))) 454 goto out; 455 /* for now, strip the pool name */ 456 if ((p = strchr(path, '/'))) 457 ++p; 458 else 459 p = path; 460 ret = fits_get_uuid(f, FITS_OLD, o_uuid); 461 if (ret && ret != ENOENT) 462 goto out; 463 if (ret == 0) { 464 ret = fits_get_ctransid(f, FITS_OLD, &o_ctrans); 465 if (ret) 466 goto out; 467 cmd = FITS_CMD_SNAPSHOT; 468 } 469 if ((ret = fits_cmd_start(f, cmd)) || 470 (ret = fits_send_put_attr(f, FITS_ATTR_PATH, p, strlen(p))) || 471 (ret = fits_send_put_u64(f, FITS_ATTR_CTRANSID, n_ctrans)) || 472 (ret = fits_send_put_attr(f, FITS_ATTR_UUID, n_uuid, 16))) 473 goto out; 474 if (cmd == FITS_CMD_SNAPSHOT) { 475 if ((ret = fits_send_put_u64(f, FITS_ATTR_CLONE_CTRANSID, 476 o_ctrans)) || 477 (ret = fits_send_put_attr(f, FITS_ATTR_CLONE_UUID, 478 o_uuid, 16))) 479 goto out; 480 } 481 ret = fits_cmd_send(f); 482 483 out: 484 kmem_free(path, len); 485 486 return (ret); 487 } 488 489 int 490 fits_send_create_file(fits_t *f, fits_dirent_t *dirent, uint64_t ino, 491 int devise_tempname, fits_path_t **path_ret) 492 { 493 fits_path_t *path = NULL; 494 fits_info_t si; 495 int ret; 496 int send_rdev = 0; 497 int cmd; 498 uint64_t rdev = 0; 499 char *symlink = NULL; 500 int symlen = 0; 501 502 ret = build_path(f, dirent, ino, devise_tempname, FITS_NEW, &path); 503 if (ret) 504 goto out; 505 506 ret = fits_get_info(f, ino, FITS_NEW, &si, 507 FI_ATTR_MODE | FI_ATTR_UID | FI_ATTR_GID); 508 if (ret) 509 goto out; 510 511 if (S_ISREG(si.si_mode)) { 512 cmd = FITS_CMD_MKFILE; 513 } else if (S_ISDIR(si.si_mode)) { 514 cmd = FITS_CMD_MKDIR; 515 } else if (S_ISLNK(si.si_mode)) { 516 cmd = FITS_CMD_SYMLINK; 517 ret = fits_read_symlink(f, ino, FITS_NEW, &symlink, &symlen); 518 if (ret) 519 goto out; 520 } else if (S_ISCHR(si.si_mode) || S_ISBLK(si.si_mode)) { 521 cmd = FITS_CMD_MKNOD; 522 send_rdev = 1; 523 } else if (S_ISFIFO(si.si_mode)) { 524 cmd = FITS_CMD_MKFIFO; 525 } else if (S_ISSOCK(si.si_mode)) { 526 cmd = FITS_CMD_MKSOCK; 527 } else { 528 /* unknown file type, ignore for now */ 529 printf("!send_create_file: ignore file with mode 0%lo\n", 530 (unsigned long)si.si_mode); 531 return (0); 532 } 533 534 if (send_rdev) { 535 fits_info_t sirdev; 536 uint64_t r_major; 537 uint64_t r_minor; 538 ret = fits_get_info(f, ino, FITS_NEW, &sirdev, FI_ATTR_RDEV); 539 if (ret) 540 goto out; 541 rdev = sirdev.si_rdev; 542 543 /* XXX hardcodedly transform rdev to linux form */ 544 r_major = rdev >> 32; 545 r_minor = rdev & 0xffffffful; 546 rdev = ((r_minor & 0xff) | ((r_major & 0xfff) << 8) | 547 ((r_minor >> 8) << 20) | ((r_major >> 12) << 44)); 548 } 549 /* send MKFILE */ 550 if ((ret = fits_cmd_start(f, cmd)) || 551 (ret = put_path(f, FITS_ATTR_PATH, path)) || 552 (ret = fits_send_put_u64(f, FITS_ATTR_INO, ino))) 553 goto out; 554 if (send_rdev) { 555 ret = fits_send_put_u64(f, FITS_ATTR_RDEV, rdev); 556 if (ret) 557 goto out; 558 ret = fits_send_put_u64(f, FITS_ATTR_MODE, si.si_mode); 559 if (ret) 560 goto out; 561 } 562 if (S_ISLNK(si.si_mode)) { 563 ret = fits_send_put_attr(f, FITS_ATTR_PATH_LINK, 564 symlink, strlen(symlink)); 565 if (ret) 566 goto out; 567 } 568 if ((ret = fits_cmd_send(f))) 569 goto out; 570 571 /* send CHOWN */ 572 if ((ret = fits_cmd_start(f, FITS_CMD_CHOWN)) || 573 (ret = put_path(f, FITS_ATTR_PATH, path)) || 574 (ret = fits_send_put_u64(f, FITS_ATTR_UID, si.si_uid)) || 575 (ret = fits_send_put_u64(f, FITS_ATTR_GID, si.si_gid)) || 576 (ret = fits_cmd_send(f))) 577 goto out; 578 579 /* send CHMOD */ 580 if ((ret = fits_cmd_start(f, FITS_CMD_CHMOD)) || 581 (ret = put_path(f, FITS_ATTR_PATH, path)) || 582 (ret = fits_send_put_u64(f, FITS_ATTR_MODE, 583 si.si_mode & 0xfff)) || 584 (ret = fits_cmd_send(f))) 585 goto out; 586 587 out: 588 if (ret == 0 && path_ret) 589 *path_ret = path; 590 else 591 fits_path_free(path); 592 if (symlink) 593 kmem_free(symlink, symlen); 594 return (ret); 595 } 596 597 int 598 fits_send_link(fits_t *f, fits_dirent_t *new_dirent, uint64_t ino, 599 uint64_t old_parent_ino, fits_which_t which, int devise_tempname) 600 { 601 fits_path_t *new_path = NULL; 602 fits_path_t *old_path = NULL; 603 int ret; 604 fits_dirent_t old_dirent = { 605 .fd_name = NULL, 606 .fd_parent_ino = old_parent_ino, 607 .fd_prev = NULL, 608 }; 609 610 ret = fits_find_entry(f, old_parent_ino, ino, which, 611 &old_dirent.fd_name); 612 if (ret) 613 return (ret); 614 ret = build_path(f, &old_dirent, ino, 0, FITS_OLD, &old_path); 615 if (ret) 616 goto out; 617 618 ret = build_path(f, new_dirent, ino, devise_tempname, FITS_NEW, 619 &new_path); 620 if (ret) 621 goto out; 622 623 if ((ret = fits_cmd_start(f, FITS_CMD_LINK)) || 624 (ret = put_path(f, FITS_ATTR_PATH_LINK, old_path)) || 625 (ret = put_path(f, FITS_ATTR_PATH, new_path)) || 626 (ret = fits_cmd_send(f))) 627 goto out; 628 629 if (f->f_pass == PASS_UNLINK) 630 ret = fits_send_mtime_update(f, new_dirent, ino); 631 out: 632 if (old_dirent.fd_name) 633 kmem_free(old_dirent.fd_name, strlen(old_dirent.fd_name) + 1); 634 fits_path_free(old_path); 635 fits_path_free(new_path); 636 return (ret); 637 } 638 639 int 640 fits_send_mkdir(fits_t *f, fits_dirent_t *dirent, 641 uint64_t ino, int devise_tempname) 642 { 643 fits_path_t *path = NULL; 644 fits_info_t si; 645 int ret; 646 647 ret = build_path(f, dirent, ino, devise_tempname, FITS_NEW, &path); 648 if (ret) 649 goto out; 650 651 ret = fits_get_info(f, ino, FITS_NEW, &si, 652 FI_ATTR_UID | FI_ATTR_GID | FI_ATTR_MODE); 653 if (ret) 654 goto out; 655 656 if (path->fp_total_len != 1) { 657 /* don't send an mkdir for the root, but send chown/chmod */ 658 if ((ret = fits_cmd_start(f, FITS_CMD_MKDIR)) || 659 (ret = put_path(f, FITS_ATTR_PATH, path)) || 660 (ret = fits_send_put_u64(f, FITS_ATTR_INO, ino)) || 661 (ret = fits_cmd_send(f))) 662 goto out; 663 } 664 665 /* send CHOWN */ 666 if ((ret = fits_cmd_start(f, FITS_CMD_CHOWN)) || 667 (ret = put_path(f, FITS_ATTR_PATH, path)) || 668 (ret = fits_send_put_u64(f, FITS_ATTR_UID, si.si_uid)) || 669 (ret = fits_send_put_u64(f, FITS_ATTR_GID, si.si_gid)) || 670 (ret = fits_cmd_send(f))) 671 goto out; 672 673 /* send CHMOD */ 674 if ((ret = fits_cmd_start(f, FITS_CMD_CHMOD)) || 675 (ret = put_path(f, FITS_ATTR_PATH, path)) || 676 (ret = fits_send_put_u64(f, FITS_ATTR_MODE, 677 si.si_mode & 0xfff)) || 678 (ret = fits_cmd_send(f))) 679 goto out; 680 681 out: 682 fits_path_free(path); 683 return (ret); 684 } 685 686 /* this one is only used for directory renames */ 687 int 688 fits_send_rename(fits_t *f, fits_dirent_t *new_dirent, uint64_t ino, 689 uint64_t old_parent_ino, int devise_tempname) 690 { 691 fits_path_t *new_path = NULL; 692 fits_path_t *old_path = NULL; 693 int ret; 694 fits_dirent_t old_dirent = { 695 .fd_name = NULL, 696 .fd_parent_ino = old_parent_ino, 697 .fd_prev = NULL, 698 }; 699 700 ret = fits_find_entry(f, old_parent_ino, ino, FITS_OLD, 701 &old_dirent.fd_name); 702 if (ret) 703 return (ret); 704 ret = build_path(f, &old_dirent, ino, 0, FITS_OLD, &old_path); 705 if (ret) 706 goto out; 707 708 ret = build_path(f, new_dirent, ino, devise_tempname, FITS_NEW, 709 &new_path); 710 if (ret) 711 goto out; 712 713 if ((ret = fits_cmd_start(f, FITS_CMD_RENAME)) || 714 (ret = put_path(f, FITS_ATTR_PATH, old_path)) || 715 (ret = put_path(f, FITS_ATTR_PATH_TO, new_path)) || 716 (ret = fits_cmd_send(f))) 717 goto out; 718 out: 719 fits_path_free(old_path); 720 fits_path_free(new_path); 721 return (ret); 722 } 723 724 int 725 fits_send_rename_from_tempname(fits_t *f, fits_dirent_t *dirent, 726 uint64_t ino, uint64_t old) 727 { 728 char buf[TEMPNAME_SIZE]; 729 fits_path_t *new_path = NULL; 730 fits_path_t *old_path = NULL; 731 int ret; 732 fits_dirent_t old_dirent; 733 734 tempname(old, buf, sizeof (buf)); 735 old_dirent = *dirent; 736 old_dirent.fd_name = buf; 737 738 ret = build_path(f, &old_dirent, old, 0, FITS_OLD, &old_path); 739 if (ret) 740 goto out; 741 ret = build_path(f, dirent, ino, 0, FITS_NEW, &new_path); 742 if (ret) 743 goto out; 744 745 if ((ret = fits_cmd_start(f, FITS_CMD_RENAME)) || 746 (ret = put_path(f, FITS_ATTR_PATH, old_path)) || 747 (ret = put_path(f, FITS_ATTR_PATH_TO, new_path)) || 748 (ret = fits_cmd_send(f))) 749 goto out; 750 751 ret = fits_send_mtime_update(f, dirent, old); 752 753 out: 754 fits_path_free(old_path); 755 fits_path_free(new_path); 756 return (ret); 757 } 758 759 int 760 fits_send_unlink(fits_t *f, fits_dirent_t *dirent, uint64_t ino) 761 { 762 fits_path_t *path = NULL; 763 int ret; 764 765 ret = build_path(f, dirent, ino, 0, FITS_OLD, &path); 766 if (ret) 767 goto out; 768 769 if ((ret = fits_cmd_start(f, FITS_CMD_UNLINK)) || 770 (ret = put_path(f, FITS_ATTR_PATH, path)) || 771 (ret = fits_cmd_send(f))) 772 goto out; 773 774 out: 775 fits_path_free(path); 776 return (ret); 777 } 778 779 int 780 fits_send_rmdir(fits_t *f, fits_dirent_t *dirent, uint64_t ino) 781 { 782 fits_path_t *path; 783 int ret; 784 785 ret = build_path(f, dirent, ino, 0, FITS_OLD, &path); 786 if (ret) 787 goto out; 788 789 if ((ret = fits_cmd_start(f, FITS_CMD_RMDIR)) || 790 (ret = put_path(f, FITS_ATTR_PATH, path)) || 791 (ret = fits_cmd_send(f))) 792 goto out; 793 794 out: 795 fits_path_free(path); 796 return (ret); 797 } 798 799 int 800 fits_send_file_data(fits_t *f, fits_path_t **path_p, 801 fits_dirent_t *dirent, uint64_t ino, 802 uint64_t off, uint64_t len, void *data) 803 { 804 int ret = 0; 805 806 if (!*path_p) { 807 ret = build_path(f, dirent, ino, 0, FITS_NEW, path_p); 808 if (ret) 809 return (ret); 810 } 811 812 while (len) { 813 uint64_t l = MIN(len, FITS_SEND_READ_SIZE); 814 815 if ((ret = fits_cmd_start(f, FITS_CMD_WRITE)) || 816 (ret = put_path(f, FITS_ATTR_PATH, *path_p)) || 817 (ret = fits_send_put_u64(f, FITS_ATTR_FILE_OFFSET, off))|| 818 (ret = fits_send_put_attr(f, FITS_ATTR_DATA, data, l)) || 819 (ret = fits_cmd_send(f))) 820 goto out; 821 data += l; 822 off += l; 823 len -= l; 824 } 825 826 out: 827 return (ret); 828 } 829 830 int 831 fits_send_mtime_update(fits_t *f, fits_dirent_t *dirent, uint64_t ino) 832 { 833 fits_path_t *path = NULL; 834 int ret; 835 fits_info_t si; 836 837 ret = fits_get_info(f, ino, FITS_NEW, &si, 838 FI_ATTR_ATIME | FI_ATTR_MTIME | 839 FI_ATTR_CTIME | FI_ATTR_OTIME); 840 if (ret) { 841 if (ret == ENOENT) 842 ret = 0; 843 goto out; 844 } 845 846 ret = build_path(f, dirent, ino, 0, FITS_NEW, &path); 847 if (ret) 848 goto out; 849 850 if ((ret = fits_cmd_start(f, FITS_CMD_UTIMES)) || 851 (ret = put_path(f, FITS_ATTR_PATH, path)) || 852 (ret = fits_send_put_time(f, FITS_ATTR_ATIME, &si.si_atime)) || 853 (ret = fits_send_put_time(f, FITS_ATTR_MTIME, &si.si_mtime)) || 854 (ret = fits_send_put_time(f, FITS_ATTR_CTIME, &si.si_ctime)) || 855 (ret = fits_send_put_time(f, FITS_ATTR_OTIME, &si.si_otime)) || 856 (ret = fits_cmd_send(f))) 857 goto out; 858 859 out: 860 fits_path_free(path); 861 return (ret); 862 } 863 864 int 865 fits_send_truncate(fits_t *f, fits_dirent_t *dirent, uint64_t ino, 866 uint64_t new_size) 867 { 868 fits_path_t *path = NULL; 869 int ret; 870 871 ret = build_path(f, dirent, ino, 0, FITS_NEW, &path); 872 if (ret) 873 return (ret); 874 875 if ((ret = fits_cmd_start(f, FITS_CMD_TRUNCATE)) || 876 (ret = put_path(f, FITS_ATTR_PATH, path)) || 877 (ret = fits_send_put_u64(f, FITS_ATTR_SIZE, new_size)) || 878 (ret = fits_cmd_send(f))) 879 goto out; 880 881 out: 882 fits_path_free(path); 883 return (ret); 884 } 885 886 int 887 fits_send_chown(fits_t *f, fits_dirent_t *dirent, uint64_t ino, 888 uint64_t new_uid, uint64_t new_gid) 889 { 890 fits_path_t *path = NULL; 891 int ret; 892 893 ret = build_path(f, dirent, ino, 0, FITS_NEW, &path); 894 if (ret) 895 return (ret); 896 897 if ((ret = fits_cmd_start(f, FITS_CMD_CHOWN)) || 898 (ret = put_path(f, FITS_ATTR_PATH, path)) || 899 (ret = fits_send_put_u64(f, FITS_ATTR_UID, new_uid)) || 900 (ret = fits_send_put_u64(f, FITS_ATTR_GID, new_gid)) || 901 (ret = fits_cmd_send(f))) 902 goto out; 903 904 out: 905 fits_path_free(path); 906 return (ret); 907 } 908 909 int 910 fits_send_chmod(fits_t *f, fits_dirent_t *dirent, uint64_t ino, 911 uint64_t new_mode) 912 { 913 fits_path_t *path = NULL; 914 int ret; 915 916 ret = build_path(f, dirent, ino, 0, FITS_NEW, &path); 917 if (ret) 918 return (ret); 919 920 if ((ret = fits_cmd_start(f, FITS_CMD_CHMOD)) || 921 (ret = put_path(f, FITS_ATTR_PATH, path)) || 922 (ret = fits_send_put_u64(f, FITS_ATTR_MODE, new_mode)) || 923 (ret = fits_cmd_send(f))) 924 goto out; 925 926 out: 927 fits_path_free(path); 928 return (ret); 929 } 930 931 int 932 fits_send_end(fits_t *f) 933 { 934 int ret; 935 936 if ((ret = fits_cmd_start(f, FITS_CMD_END)) || 937 (ret = fits_cmd_send(f))) 938 goto out; 939 940 out: 941 return (ret); 942 }