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 */
90bool_t need_super;	/* warn user that we can't fix ownership	*/
91extern char *srcname;	/* file we are emulating			*/
92extern char *dstname;	/* file we are updating				*/
93
94/*
95 * locals
96 */
97static errmask_t copy(char *, char *, int);
98static int checksparse(int);
99static 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 */
122errmask_t
123do_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
341nogood:
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 */
389errmask_t
390do_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
816cant:	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 */
850errmask_t
851do_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 */
936errmask_t
937do_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 */
1064static errmask_t
1065copy(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 */
1233static int
1234checksparse(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