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