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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved
24 * Copyright (c) 2016 by Delphix. All rights reserved.
25 *
26 * module:
27 * action.c
28 *
29 * purpose:
30 * routines to carryout reconciliation actions and make the
31 * appropriate updates to the database file structure.
32 *
33 * contents:
34 * do_like ... change ownership and protection
35 * do_copy ... copy a file from one side to the other
36 * do_remove . remove a file from one side
37 * do_rename . rename a file on one side
38 * copy ...... (static) do the actual copy
39 * checksparse (static) figure out if a file is sparse
40 *
41 * ASSERTIONS:
42 * any of these action routines is responsible for all baseline
43 * and statistics updates associated with the reconciliation
44 * actions. If notouch is specified, they should fake the
45 * updates well enough so that link tests will still work.
46 *
47 * success:
48 * bump bp->b_{src,dst}_{copies,deletes,misc}
49 * update fp->f_info[srcdst]
50 * update fp->f_info[OPT_BASE] from fp->f_info[srcdst]
51 * if there might be multiple links, call link_update
52 * return ERR_RESOLVABLE
53 *
54 * failure:
55 * set fp->f_flags |= F_CONFLICT
56 * set fp->f_problem
57 * bump bp->b_unresolved
58 * return ERR_UNRESOLVED
59 *
60 * pretend this never happened:
61 * return 0, and baseline will be unchanged
62 *
63 * notes:
64 * Action routines can be called in virtually any order
65 * or combination, and it is certainly possible for an
66 * earlier action to succeed while a later action fails.
67 * If each successful action results in a completed baseline
68 * update, a subsequent failure will force the baseline to
69 * roll back to the last success ... which is appropriate.
70 */
71 #ident "%W% %E% SMI"
72
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <unistd.h>
76 #include <fcntl.h>
77 #include <utime.h>
78 #include <errno.h>
79 #include <sys/mkdev.h>
80 #include <sys/statvfs.h>
81
82 #include "filesync.h"
83 #include "database.h"
84 #include "messages.h"
85 #include "debug.h"
86
87 /*
88 * globals and importeds
89 */
90 bool_t need_super; /* warn user that we can't fix ownership */
91 extern char *srcname; /* file we are emulating */
92 extern char *dstname; /* file we are updating */
93
94 /*
95 * locals
96 */
97 static errmask_t copy(char *, char *, int);
98 static int checksparse(int);
99 static char *copy_err_str; /* what went wrong w/copy */
100
101 /*
102 * routine:
103 * do_like
104 *
105 * purpose:
106 * to propagate ownership and protection changes between
107 * one existing file and another.
108 *
109 * parameters:
110 * file pointer
111 * src/dst indication for who needs to change
112 * whether or not to update statistics (there may be a copy and a like)
113 *
114 * returns:
115 * error mask
116 *
117 * notes:
118 * if we are called from reconcile, we should update
119 * the statistics, but if we were called from do_copy
120 * that routine will do the honors.
121 */
122 errmask_t
do_like(struct file * fp,side_t srcdst,bool_t do_stats)123 do_like(struct file *fp, side_t srcdst, bool_t do_stats)
124 { char *dst;
125 int rc = 0;
126 int do_chown, do_chmod, do_chgrp, do_acls;
127 errmask_t errs = 0;
128 char *errstr = 0;
129 struct base *bp;
130 struct fileinfo *sp;
131 struct fileinfo *dp;
132 struct fileinfo *ip;
133 extern int errno;
134
135 bp = fp->f_base;
136
137 /* see if this is a forbidden propagation */
138 if (srcdst == opt_oneway) {
139 fp->f_flags |= F_CONFLICT;
140 fp->f_problem = gettext(PROB_prohibited);
141 bp->b_unresolved++;
142 return (ERR_UNRESOLVED);
143 }
144
145
146 /* get info about source and target files */
147 if (srcdst == OPT_SRC) {
148 sp = &fp->f_info[ OPT_DST ];
149 dp = &fp->f_info[ OPT_SRC ];
150 dst = srcname;
151 } else {
152 sp = &fp->f_info[ OPT_SRC ];
153 dp = &fp->f_info[ OPT_DST ];
154 dst = dstname;
155 }
156 ip = &fp->f_info[ OPT_BASE ];
157
158 /* figure out what needs fixing */
159 do_chmod = (sp->f_mode != dp->f_mode);
160 do_chown = (sp->f_uid != dp->f_uid);
161 do_chgrp = (sp->f_gid != dp->f_gid);
162 do_acls = ((fp->f_srcdiffs|fp->f_dstdiffs) & D_FACLS);
163
164 /*
165 * try to anticipate things that we might not be able to
166 * do, and return appropriate errorst if the calling user
167 * cannot safely perform the requiested updates.
168 */
169 if (my_uid != 0) {
170 if (do_chown)
171 errstr = gettext(PROB_chown);
172 else if (my_uid != dp->f_uid) {
173 if (do_chmod)
174 errstr = gettext(PROB_chmod);
175 else if (do_acls)
176 errstr = gettext(PROB_chacl);
177 else if (do_chgrp)
178 errstr = gettext(PROB_chgrp);
179 }
180 #ifdef ACL_UID_BUG
181 else if (do_acls && my_gid != dp->f_gid)
182 errstr = gettext(PROB_botch);
183 #endif
184
185 if (errstr) {
186 need_super = TRUE;
187
188 /* if the user doesn't care, shine it on */
189 if (opt_everything == 0)
190 return (0);
191
192 /* if the user does care, return the error */
193 rc = -1;
194 goto nogood;
195 }
196 }
197
198 if (opt_debug & DBG_RECON) {
199 fprintf(stderr, "RECO: do_like %s (", dst);
200 if (do_chmod)
201 fprintf(stderr, "chmod ");
202 if (do_acls)
203 fprintf(stderr, "acls ");
204 if (do_chown)
205 fprintf(stderr, "chown ");
206 if (do_chgrp)
207 fprintf(stderr, "chgrp ");
208 fprintf(stderr, ")\n");
209 }
210
211 if (do_chmod) {
212 if (!opt_quiet)
213 fprintf(stdout, "chmod %o %s\n", sp->f_mode,
214 noblanks(dst));
215
216 #ifdef DBG_ERRORS
217 /* should we simulate a chmod failure */
218 if (errno = dbg_chk_error(dst, 'p'))
219 rc = -1;
220 else
221 #endif
222 rc = opt_notouch ? 0 : chmod(dst, sp->f_mode);
223
224 if (opt_debug & DBG_RECON)
225 fprintf(stderr, "RECO: do_chmod %o -> %d(%d)\n",
226 sp->f_mode, rc, errno);
227
228 /* update dest and baseline to reflect the change */
229 if (rc == 0) {
230 dp->f_mode = sp->f_mode;
231 ip->f_mode = sp->f_mode;
232 } else
233 errstr = gettext(PROB_chmod);
234 }
235
236 /*
237 * see if we need to fix the acls
238 */
239 if (rc == 0 && do_acls) {
240 if (!opt_quiet)
241 fprintf(stdout, "setfacl %s %s\n",
242 show_acls(sp->f_numacls, sp->f_acls),
243 noblanks(dst));
244
245 #ifdef DBG_ERRORS
246 /* should we simulate a set acl failure */
247 if (errno = dbg_chk_error(dst, 'a'))
248 rc = -1;
249 else
250 #endif
251 rc = opt_notouch ? 0 : set_acls(dst, sp);
252
253 if (opt_debug & DBG_RECON)
254 fprintf(stderr, "RECO: do_acls %d -> %d(%d)\n",
255 sp->f_numacls, rc, errno);
256
257 /* update dest and baseline to reflect the change */
258 if (rc == 0) {
259 dp->f_numacls = sp->f_numacls;
260 dp->f_acls = sp->f_acls;
261 ip->f_numacls = sp->f_numacls;
262 ip->f_acls = sp->f_acls;
263 #ifdef ACL_UID_BUG
264 /* SETFACL changes a file's UID/GID */
265 if (my_uid != dp->f_uid) {
266 do_chown = 1;
267 dp->f_uid = my_uid;
268 }
269 if (my_gid != dp->f_gid) {
270 do_chgrp = 1;
271 dp->f_gid = my_gid;
272 }
273 #endif
274 } else if (errno == ENOSYS) {
275 /*
276 * if the file system doesn't support ACLs
277 * we should just pretend we never saw them
278 */
279 fprintf(stderr, gettext(WARN_noacls), dst);
280 ip->f_numacls = 0;
281 sp->f_numacls = 0;
282 dp->f_numacls = 0;
283 rc = 0;
284 } else
285 errstr = gettext(PROB_chacl);
286 }
287
288 /*
289 * see if we need to fix the ownership
290 */
291 if (rc == 0 && (do_chown || do_chgrp)) {
292 if (do_chown)
293 fprintf(stdout, "chown %ld %s; ",
294 sp->f_uid, noblanks(dst));
295 if (do_chgrp)
296 fprintf(stdout, "chgrp %ld %s",
297 sp->f_gid, noblanks(dst));
298
299 fprintf(stdout, "\n");
300
301 #ifdef DBG_ERRORS
302 /* should we simulate a chown failure */
303 if (errno = dbg_chk_error(dst, 'O'))
304 rc = -1;
305 else
306 #endif
307 rc = opt_notouch ? 0 : lchown(dst, sp->f_uid, sp->f_gid);
308
309 if (opt_debug & DBG_RECON)
310 fprintf(stderr, "RECO: do_chown %ld %ld -> %d(%d)\n",
311 sp->f_uid, sp->f_gid, rc, errno);
312
313 /* update the destination to reflect changes */
314 if (rc == 0) {
315 dp->f_uid = sp->f_uid;
316 dp->f_gid = sp->f_gid;
317 ip->f_uid = sp->f_uid;
318 ip->f_gid = sp->f_gid;
319 } else {
320 if (errno == EPERM) {
321 need_super = TRUE;
322 if (opt_everything == 0)
323 return (0);
324 }
325
326 if (rc != 0)
327 errstr = gettext(do_chown ?
328 PROB_chown : PROB_chgrp);
329 }
330 }
331
332 /*
333 * if we were successful, we should make sure the other links
334 * see the changes. If we were called from do_copy, we don't
335 * want to do the link_updates either because do_copy will
336 * handle them too.
337 */
338 if (rc == 0 && do_stats)
339 link_update(fp, srcdst);
340
341 nogood:
342 if (!do_stats)
343 return (errs);
344
345 if (rc != 0) {
346 fprintf(stderr, gettext(ERR_cannot), errstr, dst);
347 fp->f_problem = errstr;
348 fp->f_flags |= F_CONFLICT;
349 bp->b_unresolved++;
350 errs |= ERR_PERM | ERR_UNRESOLVED;
351 } else {
352 /*
353 * it worked, so update the baseline and statistics
354 */
355 if (srcdst == OPT_SRC)
356 bp->b_src_misc++;
357 else
358 bp->b_dst_misc++;
359
360 fp->f_problem = 0;
361 errs |= ERR_RESOLVABLE;
362 }
363
364 return (errs);
365 }
366
367 /*
368 * routine:
369 * do_copy
370 *
371 * purpose:
372 * to propagate a creation or change
373 *
374 * parameters:
375 * file pointer
376 * src/dst indication for who gets the copy
377 *
378 * returns:
379 * error mask
380 *
381 * note:
382 * after any successful operation we update the stat/info
383 * structure for the updated file. This is somewhat redundant
384 * because we will restat at the end of the routine, but these
385 * anticipatory updates help to ensure that the link finding
386 * code will still behave properly in notouch mode (when restats
387 * cannot be done).
388 */
389 errmask_t
do_copy(struct file * fp,side_t srcdst)390 do_copy(struct file *fp, side_t srcdst)
391 { char *src, *dst;
392 char cmdbuf[ MAX_PATH + MAX_NAME ];
393 int mode, maj, min, type;
394 uid_t uid;
395 gid_t gid;
396 int rc;
397 long mtime;
398 int do_chmod = 0;
399 int do_chown = 0;
400 int do_chgrp = 0;
401 int do_unlink = 0;
402 int do_acls = 0;
403 int do_create = 0;
404 char *errstr = "???";
405 errmask_t errs = 0;
406 struct base *bp;
407 struct file *lp;
408 struct fileinfo *sp, *dp;
409 struct utimbuf newtimes;
410 struct stat statb;
411
412 bp = fp->f_base;
413
414 /* see if this is a forbidden propagation */
415 if (srcdst == opt_oneway) {
416 fp->f_problem = gettext(PROB_prohibited);
417 fp->f_flags |= F_CONFLICT;
418 bp->b_unresolved++;
419 return (ERR_UNRESOLVED);
420 }
421
422 /* figure out who is the source and who is the destination */
423 if (srcdst == OPT_SRC) {
424 sp = &fp->f_info[ OPT_DST ];
425 dp = &fp->f_info[ OPT_SRC ];
426 src = dstname;
427 dst = srcname;
428 } else {
429 sp = &fp->f_info[ OPT_SRC ];
430 dp = &fp->f_info[ OPT_DST ];
431 src = srcname;
432 dst = dstname;
433 }
434
435 /* note information about the file to be created */
436 type = sp->f_type; /* type of the new file */
437 uid = sp->f_uid; /* owner of the new file */
438 gid = sp->f_gid; /* group of the new file */
439 mode = sp->f_mode; /* modes for the new file */
440 mtime = sp->f_modtime; /* modtime (if preserving) */
441 maj = sp->f_rd_maj; /* major (if it is a device) */
442 min = sp->f_rd_min; /* minor (if it is a device) */
443
444 /*
445 * creating a file does not guarantee it will get the desired
446 * modes, uid and gid. If the file already exists, it will
447 * retain its old ownership and protection. If my UID/GID
448 * are not the desired ones, the new file will also require
449 * manual correction. If the file has the wrong type, we will
450 * need to delete it and recreate it. If the file is not writable,
451 * it is easier to delete it than to chmod it to permit overwrite
452 */
453 if ((dp->f_type == S_IFREG && sp->f_type == S_IFREG) &&
454 (dp->f_mode & 0200)) {
455 /* if the file already exists */
456 if (dp->f_uid != uid)
457 do_chown = 1;
458
459 if (dp->f_gid != gid)
460 do_chgrp = 1;
461
462 if (dp->f_mode != mode)
463 do_chmod = 1;
464 } else {
465 /* if we will be creating a new file */
466 do_create = 1;
467 if (dp->f_type)
468 do_unlink = 1;
469 if (uid != my_uid)
470 do_chown = 1;
471 if (gid != my_gid)
472 do_chgrp = 1;
473 }
474
475 /*
476 * if the source has acls, we will surely have to set them for dest
477 */
478 if (sp->f_numacls)
479 do_acls = 1;
480
481 /*
482 * for any case other than replacing a normal file with a normal
483 * file, we need to delete the existing file before creating
484 * the new one.
485 */
486 if (do_unlink) {
487 if (dp->f_type == S_IFDIR) {
488 if (!opt_quiet)
489 fprintf(stdout, "rmdir %s\n", noblanks(dst));
490
491 errstr = gettext(PROB_rmdir);
492 #ifdef DBG_ERRORS
493 /* should we simulate a rmdir failure */
494 if (errno = dbg_chk_error(dst, 'D'))
495 rc = -1;
496 else
497 #endif
498 rc = opt_notouch ? 0 : rmdir(dst);
499 } else {
500 if (!opt_quiet)
501 fprintf(stdout, "rm %s\n", noblanks(dst));
502
503 errstr = gettext(PROB_unlink);
504 #ifdef DBG_ERRORS
505 /* should we simulate a unlink failure */
506 if (errno = dbg_chk_error(dst, 'u'))
507 rc = -1;
508 else
509 #endif
510 rc = opt_notouch ? 0 : unlink(dst);
511 }
512
513 if (rc != 0)
514 goto cant;
515
516 /* note that this file no longer exists */
517 dp->f_type = 0;
518 dp->f_mode = 0;
519 }
520
521 if (opt_debug & DBG_RECON) {
522 fprintf(stderr, "RECO: do_copy %s %s (", src, dst);
523 if (do_unlink)
524 fprintf(stderr, "unlink ");
525 if (do_chmod)
526 fprintf(stderr, "chmod ");
527 if (do_acls)
528 fprintf(stderr, "acls ");
529 if (do_chown)
530 fprintf(stderr, "chown ");
531 if (do_chgrp)
532 fprintf(stderr, "chgrp ");
533 fprintf(stderr, ")\n");
534 }
535
536 /*
537 * how we go about copying a file depends on what type of file
538 * it is that we are supposed to copy
539 */
540 switch (type) {
541 case S_IFDIR:
542 if (!opt_quiet) {
543 fprintf(stdout, "mkdir %s;", noblanks(dst));
544 fprintf(stdout, " chmod %o %s;\n", mode, noblanks(dst));
545 }
546
547 errstr = gettext(PROB_mkdir);
548
549 #ifdef DBG_ERRORS
550 /* should we simulate a mkdir failure */
551 if (errno = dbg_chk_error(dst, 'd'))
552 rc = -1;
553 else
554 #endif
555 rc = opt_notouch ? 0 : mkdir(dst, mode);
556
557 /* update stat with what we have just created */
558 if (rc == 0) {
559 dp->f_type = S_IFDIR;
560 dp->f_uid = my_uid;
561 dp->f_gid = my_gid;
562 dp->f_mode = mode;
563 }
564
565 break;
566
567 case S_IFLNK:
568 errstr = gettext(PROB_readlink);
569 #ifdef DBG_ERRORS
570 /* should we simulate a symlink read failure */
571 if (errno = dbg_chk_error(dst, 'r'))
572 rc = -1;
573 else
574 #endif
575 rc = readlink(src, cmdbuf, sizeof (cmdbuf));
576 if (rc > 0) {
577 cmdbuf[rc] = 0;
578 if (!opt_quiet) {
579 fprintf(stdout, "ln -s %s", noblanks(cmdbuf));
580 fprintf(stdout, " %s;\n", noblanks(dst));
581 }
582 errstr = gettext(PROB_symlink);
583 #ifdef DBG_ERRORS
584 /* should we simulate a symlink failure */
585 if (errno = dbg_chk_error(dst, 'l'))
586 rc = -1;
587 else
588 #endif
589 rc = opt_notouch ? 0 : symlink(cmdbuf, dst);
590
591 if (rc == 0)
592 dp->f_type = S_IFLNK;
593 }
594 break;
595
596 case S_IFBLK:
597 case S_IFCHR:
598 if (!opt_quiet)
599 fprintf(stdout, "mknod %s %s %d %d\n", noblanks(dst),
600 (type == S_IFBLK) ? "b" : "c", maj, min);
601
602 errstr = gettext(PROB_mknod);
603 #ifdef DBG_ERRORS
604 /* should we simulate a mknod failure */
605 if (errno = dbg_chk_error(dst, 'd'))
606 rc = -1;
607 else
608 #endif
609 rc = opt_notouch ? 0
610 : mknod(dst, mode|type, makedev(maj, min));
611
612 /* update stat with what we have just created */
613 if (rc == 0) {
614 dp->f_type = type;
615 dp->f_uid = my_uid;
616 dp->f_gid = my_gid;
617 dp->f_mode = 0666;
618
619 if (dp->f_mode != mode)
620 do_chmod = 1;
621 }
622 break;
623
624 case S_IFREG:
625 /*
626 * The first thing to do is ascertain whether or not
627 * the alleged new copy might in fact be a new link.
628 * We trust find_link to weigh all the various factors,
629 * so if it says make a link, we'll do it.
630 */
631 lp = find_link(fp, srcdst);
632 if (lp) {
633 /* figure out name of existing file */
634 src = full_name(lp, srcdst, OPT_BASE);
635
636 /*
637 * if file already exists, it must be deleted
638 */
639 if (dp->f_type) {
640 if (!opt_quiet)
641 fprintf(stdout, "rm %s\n",
642 noblanks(dst));
643
644 errstr = gettext(PROB_unlink);
645 #ifdef DBG_ERRORS
646 /* should we simulate a unlink failure */
647 if (errno = dbg_chk_error(dst, 'u'))
648 rc = -1;
649 else
650 #endif
651 rc = opt_notouch ? 0 : unlink(dst);
652
653 /*
654 * if we couldn't do the unlink, we must
655 * mark the linkee in conflict as well
656 * so its reference count remains the same
657 * in the baseline and it continues to show
658 * up on the change list.
659 */
660 if (rc != 0) {
661 lp->f_flags |= F_CONFLICT;
662 lp->f_problem = gettext(PROB_link);
663 goto cant;
664 }
665 }
666
667 if (!opt_quiet) {
668 fprintf(stdout, "ln %s", noblanks(src));
669 fprintf(stdout, " %s\n", noblanks(dst));
670 }
671 errstr = gettext(PROB_link);
672
673 #ifdef DBG_ERRORS
674 /* should we simulate a link failure */
675 if (errno = dbg_chk_error(dst, 'l'))
676 rc = -1;
677 else
678 #endif
679 rc = opt_notouch ? 0 : link(src, dst);
680
681 /*
682 * if this is a link, there is no reason to worry
683 * about ownership and modes, they are automatic
684 */
685 do_chown = 0; do_chgrp = 0; do_chmod = 0; do_acls = 0;
686 if (rc == 0) {
687 dp->f_type = type;
688 dp->f_uid = uid;
689 dp->f_gid = gid;
690 dp->f_mode = mode;
691 break;
692 } else {
693 /*
694 * if we failed to make a link, we want to
695 * mark the linkee in conflict too, so that
696 * its reference count remains the same in
697 * the baseline, and it shows up on the change
698 * list again next time.
699 */
700 lp->f_flags |= F_CONFLICT;
701 lp->f_problem = errstr;
702 break;
703 }
704
705 /*
706 * in some situation we haven't figured out yet
707 * we might want to fall through and try a copy
708 * if the link failed.
709 */
710 }
711
712 /* we are going to resolve this by making a copy */
713 if (!opt_quiet) {
714 fprintf(stdout, "cp %s", noblanks(src));
715 fprintf(stdout, " %s\n", noblanks(dst));
716 }
717 rc = opt_notouch ? 0 : copy(src, dst, mode);
718 if (rc != 0) {
719 errs |= rc;
720 if (copy_err_str)
721 errstr = copy_err_str;
722 else
723 errstr = gettext(PROB_copy);
724
725 /*
726 * The new copy (if it exists at all) is a botch.
727 * If this was a new create or a remove and copy
728 * we should get rid of the botched copy so that
729 * it doesn't show up as two versions next time.
730 */
731 if (do_create)
732 unlink(dst);
733 } else if (dp->f_mode == 0) {
734 dp->f_type = S_IFREG;
735 dp->f_uid = my_uid;
736 dp->f_gid = my_gid;
737 dp->f_mode = mode;
738
739 /* FIX: inode number is still wrong */
740 }
741
742 /* for normal files we have an option to preserve mod time */
743 if (rc == 0 && opt_notouch == 0 && opt_mtime) {
744 newtimes.actime = mtime;
745 newtimes.modtime = mtime;
746
747 /* ignore the error return on this one */
748 (void) utime(dst, &newtimes);
749 }
750 break;
751
752 default:
753 errstr = gettext(PROB_deal);
754 rc = -1;
755 }
756
757 /*
758 * if any of the file's attributes need attention, I should let
759 * do_like take care of them, since it knows all rules for who
760 * can and cannot make what types of changes.
761 */
762 if (rc == 0 && (do_chmod || do_chown || do_chgrp || do_acls)) {
763 rc = do_like(fp, srcdst, FALSE);
764 errstr = fp->f_problem;
765 errs |= rc;
766 }
767
768 /*
769 * finish off by re-stating the destination and using that to
770 * update the baseline. If we were completely successful in
771 * our chowns/chmods, stating the destination will confirm it.
772 * If we were unable to make all the necessary changes, stating
773 * the destination will make the source appear to have changed,
774 * so that the differences will continue to reappear as new
775 * changes (inconsistancies).
776 */
777 if (rc == 0)
778 if (!opt_notouch) {
779 errstr = gettext(PROB_restat);
780
781 #ifdef DBG_ERRORS
782 /* should we simulate a restat failure */
783 if (errno = dbg_chk_error(dst, 'R'))
784 rc = -1;
785 else
786 #endif
787 rc = lstat(dst, &statb);
788
789 if (rc == 0) {
790 note_info(fp, &statb, srcdst);
791 link_update(fp, srcdst);
792 if (do_acls)
793 (void) get_acls(dst, dp);
794 update_info(fp, srcdst);
795 }
796 } else {
797 /*
798 * BOGOSITY ALERT
799 * we are in notouch mode and haven't really
800 * done anything, but if we want link detection
801 * to work and be properly reflected in the
802 * what-I-would-do output for a case where
803 * multiple links are created to a new file,
804 * we have to make the new file appear to
805 * have been created. Since we didn't create
806 * the new file we can't stat it, but if
807 * no file exists, we can't make a link to
808 * it, so we will pretend we created a file.
809 */
810 if (dp->f_ino == 0 || dp->f_nlink == 0) {
811 dp->f_ino = sp->f_ino;
812 dp->f_nlink = 1;
813 }
814 }
815
816 cant: if (rc != 0) {
817 fprintf(stderr, gettext(ERR_cannot), errstr, dst);
818 bp->b_unresolved++;
819 fp->f_flags |= F_CONFLICT;
820 fp->f_problem = errstr;
821 if (errs == 0)
822 errs = ERR_PERM;
823 errs |= ERR_UNRESOLVED;
824 } else {
825 /* update the statistics */
826 if (srcdst == OPT_SRC)
827 bp->b_src_copies++;
828 else
829 bp->b_dst_copies++;
830 errs |= ERR_RESOLVABLE;
831 }
832
833 return (errs);
834 }
835
836 /*
837 * routine:
838 * do_remove
839 *
840 * purpose:
841 * to propagate a deletion
842 *
843 * parameters:
844 * file pointer
845 * src/dst indication for which side gets changed
846 *
847 * returns:
848 * error mask
849 */
850 errmask_t
do_remove(struct file * fp,side_t srcdst)851 do_remove(struct file *fp, side_t srcdst)
852 { char *name;
853 int rc;
854 struct base *bp = fp->f_base;
855 errmask_t errs = 0;
856 char *errstr = "???";
857
858 /* see if this is a forbidden propagation */
859 if (srcdst == opt_oneway) {
860 fp->f_problem = gettext(PROB_prohibited);
861 fp->f_flags |= F_CONFLICT;
862 bp->b_unresolved++;
863 return (ERR_UNRESOLVED);
864 }
865
866 name = (srcdst == OPT_SRC) ? srcname : dstname;
867
868 if (fp->f_info[0].f_type == S_IFDIR) {
869 if (!opt_quiet)
870 fprintf(stdout, "rmdir %s\n", noblanks(name));
871
872 errstr = gettext(PROB_rmdir);
873
874 #ifdef DBG_ERRORS
875 /* should we simulate a rmdir failure */
876 if (errno = dbg_chk_error(name, 'D'))
877 rc = -1;
878 else
879 #endif
880 rc = opt_notouch ? 0 : rmdir(name);
881 } else {
882 if (!opt_quiet)
883 fprintf(stdout, "rm %s\n", noblanks(name));
884
885 errstr = gettext(PROB_unlink);
886
887 #ifdef DBG_ERRORS
888 /* should we simulate an unlink failure */
889 if (errno = dbg_chk_error(name, 'u'))
890 rc = -1;
891 else
892 #endif
893 rc = opt_notouch ? 0 : unlink(name);
894 }
895
896 if (opt_debug & DBG_RECON)
897 fprintf(stderr, "RECO: do_remove %s -> %d(%d)\n",
898 name, rc, errno);
899
900 if (rc == 0) {
901 /* tell any other hard links that one has gone away */
902 fp->f_info[srcdst].f_nlink--;
903 link_update(fp, srcdst);
904
905 fp->f_flags |= F_REMOVE;
906 if (srcdst == OPT_SRC)
907 fp->f_base->b_src_deletes++;
908 else
909 fp->f_base->b_dst_deletes++;
910 errs |= ERR_RESOLVABLE;
911 } else {
912 fprintf(stderr, gettext(ERR_cannot), errstr, name);
913 fp->f_problem = errstr;
914 fp->f_flags |= F_CONFLICT;
915 bp->b_unresolved++;
916 errs |= ERR_PERM | ERR_UNRESOLVED;
917 }
918
919 return (errs);
920 }
921
922 /*
923 * routine:
924 * do_rename
925 *
926 * purpose:
927 * to propagate a rename
928 *
929 * parameters:
930 * file pointer for the new name
931 * src/dst indication for which side gets changed
932 *
933 * returns:
934 * error mask
935 */
936 errmask_t
do_rename(struct file * fp,side_t srcdst)937 do_rename(struct file *fp, side_t srcdst)
938 { int rc;
939 struct file *pp = fp->f_previous;
940 struct base *bp = fp->f_base;
941 errmask_t errs = 0;
942 char *errstr = "???";
943 char *newname;
944 char *oldname;
945 struct stat statb;
946
947 /* see if this is a forbidden propagation */
948 if (srcdst == opt_oneway) {
949 fp->f_problem = gettext(PROB_prohibited);
950
951 /* if we can't resolve the TO, the FROM is also unresolved */
952 pp->f_problem = gettext(PROB_prohibited);
953 pp->f_flags |= F_CONFLICT;
954 bp->b_unresolved++;
955 return (ERR_UNRESOLVED);
956 }
957
958 newname = (srcdst == OPT_SRC) ? srcname : dstname;
959 oldname = full_name(pp, srcdst, OPT_BASE);
960
961 if (!opt_quiet)
962 fprintf(stdout, "%s %s %s\n",
963 (fp->f_info[0].f_type == S_IFDIR) ? "mvdir" : "mv",
964 noblanks(oldname), noblanks(newname));
965
966 #ifdef DBG_ERRORS
967 /* should we simulate a rename failure */
968 if (errno = dbg_chk_error(oldname, 'm'))
969 rc = -1;
970 else
971 #endif
972 rc = opt_notouch ? 0 : rename(oldname, newname);
973
974 if (opt_debug & DBG_RECON)
975 fprintf(stderr, "RECO: do_rename %s %s -> %d(%d)\n",
976 oldname, newname, rc, errno);
977
978 /* if we succeed, update the baseline */
979 if (rc == 0)
980 if (!opt_notouch) {
981 errstr = gettext(PROB_restat);
982
983 #ifdef DBG_ERRORS
984 /* should we simulate a restat failure */
985 if (errno = dbg_chk_error(newname, 'S'))
986 rc = -1;
987 else
988 #endif
989 rc = lstat(newname, &statb);
990
991 if (rc == 0) {
992 note_info(fp, &statb, srcdst);
993 link_update(fp, srcdst);
994 update_info(fp, srcdst);
995 }
996 } else {
997 /*
998 * BOGOSITY ALERT
999 * in order for link tests to work in notouch
1000 * mode we have to dummy up some updated status
1001 */
1002 fp->f_info[srcdst].f_ino = pp->f_info[srcdst].f_ino;
1003 fp->f_info[srcdst].f_nlink = pp->f_info[srcdst].f_nlink;
1004 fp->f_info[srcdst].f_type = pp->f_info[srcdst].f_type;
1005 fp->f_info[srcdst].f_size = pp->f_info[srcdst].f_size;
1006 fp->f_info[srcdst].f_mode = pp->f_info[srcdst].f_mode;
1007 fp->f_info[srcdst].f_uid = pp->f_info[srcdst].f_uid;
1008 fp->f_info[srcdst].f_gid = pp->f_info[srcdst].f_gid;
1009 update_info(fp, srcdst);
1010 }
1011 else
1012 errstr = gettext(PROB_rename2);
1013
1014 if (rc == 0) {
1015 pp->f_flags |= F_REMOVE;
1016
1017 if (srcdst == OPT_SRC) {
1018 bp->b_src_copies++;
1019 bp->b_src_deletes++;
1020 } else {
1021 bp->b_dst_copies++;
1022 bp->b_dst_deletes++;
1023 }
1024 errs |= ERR_RESOLVABLE;
1025 } else {
1026 fprintf(stderr, gettext(ERR_cannot), errstr, oldname);
1027
1028 bp->b_unresolved++;
1029 fp->f_flags |= F_CONFLICT;
1030 pp->f_flags |= F_CONFLICT;
1031
1032 fp->f_problem = errstr;
1033 pp->f_problem = gettext(PROB_rename);
1034
1035 errs |= ERR_PERM | ERR_UNRESOLVED;
1036 }
1037
1038 return (errs);
1039 }
1040
1041 /*
1042 * routine:
1043 * copy
1044 *
1045 * purpose:
1046 * to copy one file to another
1047 *
1048 * parameters:
1049 * source file name
1050 * destination file name
1051 * desired modes
1052 *
1053 * returns:
1054 * 0 OK
1055 * else error mask, and a setting of copy_err_str
1056 *
1057 * notes:
1058 * We try to preserve the holes in sparse files, by skipping over
1059 * any holes that are at least MIN_HOLE bytes long. There are
1060 * pathological cases where the hole detection test could become
1061 * expensive, but for most blocks of most files we will fall out
1062 * of the zero confirming loop in the first couple of bytes.
1063 */
1064 static errmask_t
copy(char * src,char * dst,int mode)1065 copy(char *src, char *dst, int mode)
1066 { int ifd, ofd, count, ret;
1067 long *p, *e;
1068 long long length; /* total size of file */
1069 errmask_t errs = 0;
1070 int bsize; /* block-size for file */
1071 bool_t sparse; /* file may be sparse */
1072 bool_t was_hole = FALSE; /* file ends with hole */
1073 long inbuf[ COPY_BSIZE/4 ]; /* long to speed checks */
1074 struct stat statbuf; /* info on source file */
1075 struct statvfs statvsbuf; /* info on target fs */
1076
1077 copy_err_str = 0;
1078
1079 /* open the input file */
1080 #ifdef DBG_ERRORS
1081 if (opt_errors && dbg_chk_error(src, 'o'))
1082 ifd = -1;
1083 else
1084 #endif
1085 ifd = open(src, O_RDONLY);
1086
1087 if (ifd < 0) {
1088 copy_err_str = gettext(PROB_copyin);
1089 return (ERR_PERM);
1090 }
1091
1092 /*
1093 * if we suspect a file may be sparse, we must process it
1094 * a little more carefully, looking for holes and skipping
1095 * over them in the output. If a file is not sparse, we
1096 * can move through it at greater speed.
1097 */
1098 bsize = checksparse(ifd);
1099 if (bsize > 0 && bsize <= COPY_BSIZE)
1100 sparse = TRUE;
1101 else {
1102 sparse = FALSE;
1103 bsize = COPY_BSIZE;
1104 }
1105
1106 /*
1107 * if the target file already exists and we overwrite it without
1108 * first ascertaining that there is enough room, we could wind
1109 * up actually losing data. Try to determine how much space is
1110 * available on the target file system, and if that is not enough
1111 * for the source file, fail without even trying. If, however,
1112 * the target file does not already exist, we have nothing to
1113 * lose by just doing the copy without checking the space.
1114 */
1115 ret = statvfs(dst, &statvsbuf);
1116 if (ret == 0 && statvsbuf.f_frsize != 0) {
1117 #ifdef DBG_ERRORS
1118 /* should we simulate an out-of-space situation */
1119 if ((length = dbg_chk_error(dst, 'Z')) == 0)
1120 #endif
1121 length = statvsbuf.f_bavail * statvsbuf.f_frsize;
1122
1123 ret = fstat(ifd, &statbuf);
1124 if (ret == 0) {
1125 length /= 512; /* st_blocks in 512s */
1126 if (length < statbuf.st_blocks) {
1127 copy_err_str = gettext(PROB_space);
1128 close(ifd);
1129 return (ERR_FILES);
1130 }
1131 } else {
1132 copy_err_str = gettext(PROB_restat);
1133 close(ifd);
1134 return (ERR_FILES);
1135 }
1136 }
1137
1138 /* create the output file */
1139 #ifdef DBG_ERRORS
1140 if (opt_errors && dbg_chk_error(dst, 'c'))
1141 ofd = -1;
1142 else
1143 #endif
1144 ofd = creat(dst, mode);
1145
1146 if (ofd < 0) {
1147 close(ifd);
1148 copy_err_str = gettext(PROB_copyout);
1149 return (ERR_PERM);
1150 }
1151
1152 /* copy the data from the input file to the output file */
1153 for (;;) {
1154 #ifdef DBG_ERRORS
1155 if (opt_errors && dbg_chk_error(dst, 'r'))
1156 count = -1;
1157 else
1158 #endif
1159 count = read(ifd, (char *) inbuf, bsize);
1160 if (count <= 0)
1161 break;
1162
1163 /*
1164 * if the file might be sparse and we got an entire block,
1165 * we should see if the block is all zeros
1166 */
1167 if (sparse && count == bsize) {
1168 p = inbuf; e = &inbuf[count/4];
1169 while (p < e && *p == 0)
1170 p++;
1171 if (p == e) {
1172 (void) lseek(ofd, (off_t) count, SEEK_CUR);
1173 was_hole = TRUE;
1174 continue;
1175 }
1176 }
1177 was_hole = FALSE;
1178
1179 #ifdef DBG_ERRORS
1180 if (opt_errors && dbg_chk_error(dst, 'w'))
1181 ret = -1;
1182 else
1183 #endif
1184 ret = write(ofd, (char *) inbuf, count);
1185
1186 if (ret != count) {
1187 errs = ERR_FILES;
1188 copy_err_str = gettext(PROB_write);
1189 break;
1190 }
1191 }
1192
1193 if (count < 0) {
1194 copy_err_str = gettext(PROB_read);
1195 errs = ERR_FILES;
1196 } else if (was_hole) {
1197 /*
1198 * if we skipped the last write because of a hole, we
1199 * need to make sure that we write a single byte of null
1200 * at the end of the file to update the file length.
1201 */
1202 (void) lseek(ofd, (off_t)-1, SEEK_CUR);
1203 (void) write(ofd, "", 1);
1204 }
1205
1206 /*
1207 * if the output file was botched, free up its space
1208 */
1209 if (errs)
1210 ftruncate(ofd, (off_t) 0);
1211
1212 close(ifd);
1213 close(ofd);
1214 return (errs);
1215 }
1216
1217 /*
1218 * routine:
1219 * checksparse
1220 *
1221 * purpose:
1222 * to determine whether or not a file might be sparse, and if
1223 * it is sparse, what the granularity of the holes is likely
1224 * to be.
1225 *
1226 * parameters:
1227 * file descriptor for file in question
1228 *
1229 * returns:
1230 * 0 file does not appear to be sparse
1231 * else block size for this file
1232 */
1233 static int
checksparse(int fd)1234 checksparse(int fd)
1235 {
1236 struct stat statb;
1237
1238 /*
1239 * unable to stat the file is very strange (since we got it
1240 * open) but it probably isn't worth causing a fuss over.
1241 * Return the conservative answer
1242 */
1243 if (fstat(fd, &statb) < 0)
1244 return (MIN_HOLE);
1245
1246 /*
1247 * if the file doesn't have enough blocks to account for
1248 * all of its bytes, there is a reasonable chance that it
1249 * is sparse. This test is not perfect, in that it will
1250 * fail to find holes in cases where the holes aren't
1251 * numerous enough to componsent for the indirect blocks
1252 * ... but losing those few holes is not going to be a
1253 * big deal.
1254 */
1255 if (statb.st_size > 512 * statb.st_blocks)
1256 return (statb.st_blksize);
1257 else
1258 return (0);
1259 }
1260