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 }