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
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.
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]
23 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved
24 * Copyright (c) 2016 by Delphix. All rights reserved.
30 * routines to carryout reconciliation actions and make the
31 * appropriate updates to the database file structure.
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
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.
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
55 * set fp->f_flags |= F_CONFLICT
57 * bump bp->b_unresolved
58 * return ERR_UNRESOLVED
60 * pretend this never happened:
61 * return 0, and baseline will be unchanged
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.
79 #include <sys/mkdev.h>
80 #include <sys/statvfs.h>
88 * globals and importeds
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 */
97 static errmask_t
copy(char *, char *, int);
98 static int checksparse(int);
99 static char *copy_err_str
; /* what went wrong w/copy */
106 * to propagate ownership and protection changes between
107 * one existing file and another.
111 * src/dst indication for who needs to change
112 * whether or not to update statistics (there may be a copy and a like)
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.
123 do_like(struct file
*fp
, side_t srcdst
, bool_t do_stats
)
126 int do_chown
, do_chmod
, do_chgrp
, do_acls
;
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
);
142 return (ERR_UNRESOLVED
);
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
];
152 sp
= &fp
->f_info
[ OPT_SRC
];
153 dp
= &fp
->f_info
[ OPT_DST
];
156 ip
= &fp
->f_info
[ OPT_BASE
];
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
);
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.
171 errstr
= gettext(PROB_chown
);
172 else if (my_uid
!= dp
->f_uid
) {
174 errstr
= gettext(PROB_chmod
);
176 errstr
= gettext(PROB_chacl
);
178 errstr
= gettext(PROB_chgrp
);
181 else if (do_acls
&& my_gid
!= dp
->f_gid
)
182 errstr
= gettext(PROB_botch
);
188 /* if the user doesn't care, shine it on */
189 if (opt_everything
== 0)
192 /* if the user does care, return the error */
198 if (opt_debug
& DBG_RECON
) {
199 fprintf(stderr
, "RECO: do_like %s (", dst
);
201 fprintf(stderr
, "chmod ");
203 fprintf(stderr
, "acls ");
205 fprintf(stderr
, "chown ");
207 fprintf(stderr
, "chgrp ");
208 fprintf(stderr
, ")\n");
213 fprintf(stdout
, "chmod %o %s\n", sp
->f_mode
,
217 /* should we simulate a chmod failure */
218 if (errno
= dbg_chk_error(dst
, 'p'))
222 rc
= opt_notouch
? 0 : chmod(dst
, sp
->f_mode
);
224 if (opt_debug
& DBG_RECON
)
225 fprintf(stderr
, "RECO: do_chmod %o -> %d(%d)\n",
226 sp
->f_mode
, rc
, errno
);
228 /* update dest and baseline to reflect the change */
230 dp
->f_mode
= sp
->f_mode
;
231 ip
->f_mode
= sp
->f_mode
;
233 errstr
= gettext(PROB_chmod
);
237 * see if we need to fix the acls
239 if (rc
== 0 && do_acls
) {
241 fprintf(stdout
, "setfacl %s %s\n",
242 show_acls(sp
->f_numacls
, sp
->f_acls
),
246 /* should we simulate a set acl failure */
247 if (errno
= dbg_chk_error(dst
, 'a'))
251 rc
= opt_notouch
? 0 : set_acls(dst
, sp
);
253 if (opt_debug
& DBG_RECON
)
254 fprintf(stderr
, "RECO: do_acls %d -> %d(%d)\n",
255 sp
->f_numacls
, rc
, errno
);
257 /* update dest and baseline to reflect the change */
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
;
264 /* SETFACL changes a file's UID/GID */
265 if (my_uid
!= dp
->f_uid
) {
269 if (my_gid
!= dp
->f_gid
) {
274 } else if (errno
== ENOSYS
) {
276 * if the file system doesn't support ACLs
277 * we should just pretend we never saw them
279 fprintf(stderr
, gettext(WARN_noacls
), dst
);
285 errstr
= gettext(PROB_chacl
);
289 * see if we need to fix the ownership
291 if (rc
== 0 && (do_chown
|| do_chgrp
)) {
293 fprintf(stdout
, "chown %ld %s; ",
294 sp
->f_uid
, noblanks(dst
));
296 fprintf(stdout
, "chgrp %ld %s",
297 sp
->f_gid
, noblanks(dst
));
299 fprintf(stdout
, "\n");
302 /* should we simulate a chown failure */
303 if (errno
= dbg_chk_error(dst
, 'O'))
307 rc
= opt_notouch
? 0 : lchown(dst
, sp
->f_uid
, sp
->f_gid
);
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
);
313 /* update the destination to reflect changes */
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
;
320 if (errno
== EPERM
) {
322 if (opt_everything
== 0)
327 errstr
= gettext(do_chown
?
328 PROB_chown
: PROB_chgrp
);
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
338 if (rc
== 0 && do_stats
)
339 link_update(fp
, srcdst
);
346 fprintf(stderr
, gettext(ERR_cannot
), errstr
, dst
);
347 fp
->f_problem
= errstr
;
348 fp
->f_flags
|= F_CONFLICT
;
350 errs
|= ERR_PERM
| ERR_UNRESOLVED
;
353 * it worked, so update the baseline and statistics
355 if (srcdst
== OPT_SRC
)
361 errs
|= ERR_RESOLVABLE
;
372 * to propagate a creation or change
376 * src/dst indication for who gets the copy
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
390 do_copy(struct file
*fp
, side_t srcdst
)
392 char cmdbuf
[ MAX_PATH
+ MAX_NAME
];
393 int mode
, maj
, min
, type
;
404 char *errstr
= "???";
408 struct fileinfo
*sp
, *dp
;
409 struct utimbuf newtimes
;
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
;
419 return (ERR_UNRESOLVED
);
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
];
429 sp
= &fp
->f_info
[ OPT_SRC
];
430 dp
= &fp
->f_info
[ OPT_DST
];
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) */
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
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
)
459 if (dp
->f_gid
!= gid
)
462 if (dp
->f_mode
!= mode
)
465 /* if we will be creating a new file */
476 * if the source has acls, we will surely have to set them for dest
482 * for any case other than replacing a normal file with a normal
483 * file, we need to delete the existing file before creating
487 if (dp
->f_type
== S_IFDIR
) {
489 fprintf(stdout
, "rmdir %s\n", noblanks(dst
));
491 errstr
= gettext(PROB_rmdir
);
493 /* should we simulate a rmdir failure */
494 if (errno
= dbg_chk_error(dst
, 'D'))
498 rc
= opt_notouch
? 0 : rmdir(dst
);
501 fprintf(stdout
, "rm %s\n", noblanks(dst
));
503 errstr
= gettext(PROB_unlink
);
505 /* should we simulate a unlink failure */
506 if (errno
= dbg_chk_error(dst
, 'u'))
510 rc
= opt_notouch
? 0 : unlink(dst
);
516 /* note that this file no longer exists */
521 if (opt_debug
& DBG_RECON
) {
522 fprintf(stderr
, "RECO: do_copy %s %s (", src
, dst
);
524 fprintf(stderr
, "unlink ");
526 fprintf(stderr
, "chmod ");
528 fprintf(stderr
, "acls ");
530 fprintf(stderr
, "chown ");
532 fprintf(stderr
, "chgrp ");
533 fprintf(stderr
, ")\n");
537 * how we go about copying a file depends on what type of file
538 * it is that we are supposed to copy
543 fprintf(stdout
, "mkdir %s;", noblanks(dst
));
544 fprintf(stdout
, " chmod %o %s;\n", mode
, noblanks(dst
));
547 errstr
= gettext(PROB_mkdir
);
550 /* should we simulate a mkdir failure */
551 if (errno
= dbg_chk_error(dst
, 'd'))
555 rc
= opt_notouch
? 0 : mkdir(dst
, mode
);
557 /* update stat with what we have just created */
559 dp
->f_type
= S_IFDIR
;
568 errstr
= gettext(PROB_readlink
);
570 /* should we simulate a symlink read failure */
571 if (errno
= dbg_chk_error(dst
, 'r'))
575 rc
= readlink(src
, cmdbuf
, sizeof (cmdbuf
));
579 fprintf(stdout
, "ln -s %s", noblanks(cmdbuf
));
580 fprintf(stdout
, " %s;\n", noblanks(dst
));
582 errstr
= gettext(PROB_symlink
);
584 /* should we simulate a symlink failure */
585 if (errno
= dbg_chk_error(dst
, 'l'))
589 rc
= opt_notouch
? 0 : symlink(cmdbuf
, dst
);
592 dp
->f_type
= S_IFLNK
;
599 fprintf(stdout
, "mknod %s %s %d %d\n", noblanks(dst
),
600 (type
== S_IFBLK
) ? "b" : "c", maj
, min
);
602 errstr
= gettext(PROB_mknod
);
604 /* should we simulate a mknod failure */
605 if (errno
= dbg_chk_error(dst
, 'd'))
610 : mknod(dst
, mode
|type
, makedev(maj
, min
));
612 /* update stat with what we have just created */
619 if (dp
->f_mode
!= mode
)
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.
631 lp
= find_link(fp
, srcdst
);
633 /* figure out name of existing file */
634 src
= full_name(lp
, srcdst
, OPT_BASE
);
637 * if file already exists, it must be deleted
641 fprintf(stdout
, "rm %s\n",
644 errstr
= gettext(PROB_unlink
);
646 /* should we simulate a unlink failure */
647 if (errno
= dbg_chk_error(dst
, 'u'))
651 rc
= opt_notouch
? 0 : unlink(dst
);
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.
661 lp
->f_flags
|= F_CONFLICT
;
662 lp
->f_problem
= gettext(PROB_link
);
668 fprintf(stdout
, "ln %s", noblanks(src
));
669 fprintf(stdout
, " %s\n", noblanks(dst
));
671 errstr
= gettext(PROB_link
);
674 /* should we simulate a link failure */
675 if (errno
= dbg_chk_error(dst
, 'l'))
679 rc
= opt_notouch
? 0 : link(src
, dst
);
682 * if this is a link, there is no reason to worry
683 * about ownership and modes, they are automatic
685 do_chown
= 0; do_chgrp
= 0; do_chmod
= 0; do_acls
= 0;
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.
700 lp
->f_flags
|= F_CONFLICT
;
701 lp
->f_problem
= errstr
;
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.
712 /* we are going to resolve this by making a copy */
714 fprintf(stdout
, "cp %s", noblanks(src
));
715 fprintf(stdout
, " %s\n", noblanks(dst
));
717 rc
= opt_notouch
? 0 : copy(src
, dst
, mode
);
721 errstr
= copy_err_str
;
723 errstr
= gettext(PROB_copy
);
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.
733 } else if (dp
->f_mode
== 0) {
734 dp
->f_type
= S_IFREG
;
739 /* FIX: inode number is still wrong */
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
;
747 /* ignore the error return on this one */
748 (void) utime(dst
, &newtimes
);
753 errstr
= gettext(PROB_deal
);
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.
762 if (rc
== 0 && (do_chmod
|| do_chown
|| do_chgrp
|| do_acls
)) {
763 rc
= do_like(fp
, srcdst
, FALSE
);
764 errstr
= fp
->f_problem
;
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).
779 errstr
= gettext(PROB_restat
);
782 /* should we simulate a restat failure */
783 if (errno
= dbg_chk_error(dst
, 'R'))
787 rc
= lstat(dst
, &statb
);
790 note_info(fp
, &statb
, srcdst
);
791 link_update(fp
, srcdst
);
793 (void) get_acls(dst
, dp
);
794 update_info(fp
, srcdst
);
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.
810 if (dp
->f_ino
== 0 || dp
->f_nlink
== 0) {
811 dp
->f_ino
= sp
->f_ino
;
817 fprintf(stderr
, gettext(ERR_cannot
), errstr
, dst
);
819 fp
->f_flags
|= F_CONFLICT
;
820 fp
->f_problem
= errstr
;
823 errs
|= ERR_UNRESOLVED
;
825 /* update the statistics */
826 if (srcdst
== OPT_SRC
)
830 errs
|= ERR_RESOLVABLE
;
841 * to propagate a deletion
845 * src/dst indication for which side gets changed
851 do_remove(struct file
*fp
, side_t srcdst
)
854 struct base
*bp
= fp
->f_base
;
856 char *errstr
= "???";
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
;
863 return (ERR_UNRESOLVED
);
866 name
= (srcdst
== OPT_SRC
) ? srcname
: dstname
;
868 if (fp
->f_info
[0].f_type
== S_IFDIR
) {
870 fprintf(stdout
, "rmdir %s\n", noblanks(name
));
872 errstr
= gettext(PROB_rmdir
);
875 /* should we simulate a rmdir failure */
876 if (errno
= dbg_chk_error(name
, 'D'))
880 rc
= opt_notouch
? 0 : rmdir(name
);
883 fprintf(stdout
, "rm %s\n", noblanks(name
));
885 errstr
= gettext(PROB_unlink
);
888 /* should we simulate an unlink failure */
889 if (errno
= dbg_chk_error(name
, 'u'))
893 rc
= opt_notouch
? 0 : unlink(name
);
896 if (opt_debug
& DBG_RECON
)
897 fprintf(stderr
, "RECO: do_remove %s -> %d(%d)\n",
901 /* tell any other hard links that one has gone away */
902 fp
->f_info
[srcdst
].f_nlink
--;
903 link_update(fp
, srcdst
);
905 fp
->f_flags
|= F_REMOVE
;
906 if (srcdst
== OPT_SRC
)
907 fp
->f_base
->b_src_deletes
++;
909 fp
->f_base
->b_dst_deletes
++;
910 errs
|= ERR_RESOLVABLE
;
912 fprintf(stderr
, gettext(ERR_cannot
), errstr
, name
);
913 fp
->f_problem
= errstr
;
914 fp
->f_flags
|= F_CONFLICT
;
916 errs
|= ERR_PERM
| ERR_UNRESOLVED
;
927 * to propagate a rename
930 * file pointer for the new name
931 * src/dst indication for which side gets changed
937 do_rename(struct file
*fp
, side_t srcdst
)
939 struct file
*pp
= fp
->f_previous
;
940 struct base
*bp
= fp
->f_base
;
942 char *errstr
= "???";
947 /* see if this is a forbidden propagation */
948 if (srcdst
== opt_oneway
) {
949 fp
->f_problem
= gettext(PROB_prohibited
);
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
;
955 return (ERR_UNRESOLVED
);
958 newname
= (srcdst
== OPT_SRC
) ? srcname
: dstname
;
959 oldname
= full_name(pp
, srcdst
, OPT_BASE
);
962 fprintf(stdout
, "%s %s %s\n",
963 (fp
->f_info
[0].f_type
== S_IFDIR
) ? "mvdir" : "mv",
964 noblanks(oldname
), noblanks(newname
));
967 /* should we simulate a rename failure */
968 if (errno
= dbg_chk_error(oldname
, 'm'))
972 rc
= opt_notouch
? 0 : rename(oldname
, newname
);
974 if (opt_debug
& DBG_RECON
)
975 fprintf(stderr
, "RECO: do_rename %s %s -> %d(%d)\n",
976 oldname
, newname
, rc
, errno
);
978 /* if we succeed, update the baseline */
981 errstr
= gettext(PROB_restat
);
984 /* should we simulate a restat failure */
985 if (errno
= dbg_chk_error(newname
, 'S'))
989 rc
= lstat(newname
, &statb
);
992 note_info(fp
, &statb
, srcdst
);
993 link_update(fp
, srcdst
);
994 update_info(fp
, srcdst
);
999 * in order for link tests to work in notouch
1000 * mode we have to dummy up some updated status
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
);
1012 errstr
= gettext(PROB_rename2
);
1015 pp
->f_flags
|= F_REMOVE
;
1017 if (srcdst
== OPT_SRC
) {
1019 bp
->b_src_deletes
++;
1022 bp
->b_dst_deletes
++;
1024 errs
|= ERR_RESOLVABLE
;
1026 fprintf(stderr
, gettext(ERR_cannot
), errstr
, oldname
);
1029 fp
->f_flags
|= F_CONFLICT
;
1030 pp
->f_flags
|= F_CONFLICT
;
1032 fp
->f_problem
= errstr
;
1033 pp
->f_problem
= gettext(PROB_rename
);
1035 errs
|= ERR_PERM
| ERR_UNRESOLVED
;
1046 * to copy one file to another
1050 * destination file name
1055 * else error mask, and a setting of copy_err_str
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.
1065 copy(char *src
, char *dst
, int mode
)
1066 { int ifd
, ofd
, count
, ret
;
1068 long long length
; /* total size of file */
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 */
1079 /* open the input file */
1081 if (opt_errors
&& dbg_chk_error(src
, 'o'))
1085 ifd
= open(src
, O_RDONLY
);
1088 copy_err_str
= gettext(PROB_copyin
);
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.
1098 bsize
= checksparse(ifd
);
1099 if (bsize
> 0 && bsize
<= COPY_BSIZE
)
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.
1115 ret
= statvfs(dst
, &statvsbuf
);
1116 if (ret
== 0 && statvsbuf
.f_frsize
!= 0) {
1118 /* should we simulate an out-of-space situation */
1119 if ((length
= dbg_chk_error(dst
, 'Z')) == 0)
1121 length
= statvsbuf
.f_bavail
* statvsbuf
.f_frsize
;
1123 ret
= fstat(ifd
, &statbuf
);
1125 length
/= 512; /* st_blocks in 512s */
1126 if (length
< statbuf
.st_blocks
) {
1127 copy_err_str
= gettext(PROB_space
);
1132 copy_err_str
= gettext(PROB_restat
);
1138 /* create the output file */
1140 if (opt_errors
&& dbg_chk_error(dst
, 'c'))
1144 ofd
= creat(dst
, mode
);
1148 copy_err_str
= gettext(PROB_copyout
);
1152 /* copy the data from the input file to the output file */
1155 if (opt_errors
&& dbg_chk_error(dst
, 'r'))
1159 count
= read(ifd
, (char *) inbuf
, bsize
);
1164 * if the file might be sparse and we got an entire block,
1165 * we should see if the block is all zeros
1167 if (sparse
&& count
== bsize
) {
1168 p
= inbuf
; e
= &inbuf
[count
/4];
1169 while (p
< e
&& *p
== 0)
1172 (void) lseek(ofd
, (off_t
) count
, SEEK_CUR
);
1180 if (opt_errors
&& dbg_chk_error(dst
, 'w'))
1184 ret
= write(ofd
, (char *) inbuf
, count
);
1188 copy_err_str
= gettext(PROB_write
);
1194 copy_err_str
= gettext(PROB_read
);
1196 } else if (was_hole
) {
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.
1202 (void) lseek(ofd
, (off_t
)-1, SEEK_CUR
);
1203 (void) write(ofd
, "", 1);
1207 * if the output file was botched, free up its space
1210 ftruncate(ofd
, (off_t
) 0);
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
1227 * file descriptor for file in question
1230 * 0 file does not appear to be sparse
1231 * else block size for this file
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
1243 if (fstat(fd
, &statb
) < 0)
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
1255 if (statb
.st_size
> 512 * statb
.st_blocks
)
1256 return (statb
.st_blksize
);