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 }