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