xref: /titanic_41/usr/src/cmd/filesync/action.c (revision dcda19f50b2b80bfc622fff718ac04fb0e1cb670)
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
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
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
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
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
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
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