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
29 * process the reconciliation list, figure out exactly what the
30 * changes were, and what we should do about them.
33 * reconcile ... (top level) process the reconciliation list
34 * samedata .... (static) do two files have the same contents
35 * samestuff ... (static) do two files have the same ownership/protection
36 * samecompare . (static) actually read and compare the contents
37 * samelink .... (static) do two symlinks have the same contents
38 * truncated ... (static) was one of the two copies truncted
39 * older ....... (static) which copy is older
40 * newer ....... (static) which copy is newer
41 * full_name ... generate a full path name for a file
44 * If you only study one routine in this whole program, reconcile
45 * is that routine. Everything else is just book keeping.
47 * things were put onto the reconciliation list because analyze
48 * thought that they might have changed ... but up until now
49 * nobody has figured out what the changes really were, or even
50 * if there really were any changes.
52 * queue_file has ordered the reconciliation list with directory
53 * creations first (depth ordered) and deletions last (inversely
54 * depth ordered). all other changes have been ordered by mod time.
70 * local routines to figure out how the files really differ
72 static bool_t
samedata(struct file
*);
73 static bool_t
samestuff(struct file
*);
74 static bool_t
samecompare(struct file
*);
75 static bool_t
truncated(struct file
*);
76 static bool_t
samelink();
77 static side_t
newer(struct file
*);
78 static side_t
older(struct file
*);
83 char *srcname
; /* file we are emulating */
84 char *dstname
; /* file we are updating */
91 * to perform the reconciliation action associated with a file
101 * The switch statement handles the obvious stuff.
102 * The TRUE side of the samedata test handles minor differences.
103 * The interesting stuff is in the FALSE side of the samedata test.
105 * The desparation heuristics (in the diffmask&CONTENTS test) are
106 * not rigorously correct ... but they always try do the right thing
107 * with data, and only lose mode/ownership changes in relatively
108 * pathological cases. But I claim that the benefits outweigh the
109 * risks, and most users will be pleased with the resulting decisions.
111 * Another trick is in the deletion cases of the switch. We
112 * normally won't allow an unlink that conflicts with data
113 * changes. If there are multiple links to the file, however,
114 * we can make the changes and do the deletion.
116 * The action routines do_{remove,rename,like,copy} handle all
117 * of their own statistics and status updating. This routine
118 * only has to handle its own reconciliation failures (when we
119 * can't decide what to do).
122 reconcile(struct file
*fp
)
123 { errmask_t errs
= 0;
126 if (opt_debug
& DBG_RECON
)
127 fprintf(stderr
, "RECO: %s flgs=%s, mtime=%08lx.%08lx\n",
129 showflags(fileflags
, fp
->f_flags
),
130 fp
->f_modtime
, fp
->f_modns
);
133 * form the fully qualified names for both files
135 srcname
= full_name(fp
, OPT_SRC
, OPT_SRC
);
136 dstname
= full_name(fp
, OPT_DST
, OPT_DST
);
139 * because they are so expensive to read and so troublesome
140 * to set, we try to put off reading ACLs as long as possible.
141 * If we haven't read them yet, we must read them now (so that
142 * samestuff can compare them).
144 if (opt_acls
== 0 && fp
->f_info
[ OPT_BASE
].f_numacls
== 0) {
145 if (get_acls(srcname
, &fp
->f_info
[ OPT_SRC
]))
146 fp
->f_srcdiffs
|= D_FACLS
;
147 if (get_acls(dstname
, &fp
->f_info
[ OPT_DST
]))
148 fp
->f_dstdiffs
|= D_FACLS
;
152 * If a rename has been detected, we don't have to figure
153 * it out, since both the rename-to and rename-from files
154 * have already been designated. When we encounter a rename-to
155 * we should carry it out. When we encounter a rename-from
156 * we can ignore it, since it should be dealt with as a side
157 * effect of processing the rename-to.
159 if ((fp
->f_srcdiffs
|fp
->f_dstdiffs
) & D_RENAME_FROM
)
162 if ((fp
->f_srcdiffs
|fp
->f_dstdiffs
) & D_RENAME_TO
) {
165 fprintf(stdout
, gettext(V_renamed
),
166 fp
->f_previous
->f_fullname
, fp
->f_name
);
168 if (fp
->f_srcdiffs
& D_RENAME_TO
) {
169 errs
= do_rename(fp
, OPT_DST
);
170 fp
->f_srcdiffs
&= D_MTIME
| D_SIZE
;
171 } else if (fp
->f_dstdiffs
& D_RENAME_TO
) {
172 errs
= do_rename(fp
, OPT_SRC
);
173 fp
->f_dstdiffs
&= D_MTIME
| D_SIZE
;
176 if (errs
!= ERR_RESOLVABLE
)
180 * if any differences remain, then we may be dealing
181 * with contents changes in addition to a rename
183 if ((fp
->f_srcdiffs
| fp
->f_dstdiffs
) == 0)
187 * fall through to reconcile the data changes
192 * pull of the easy cases (non-conflict creations & deletions)
194 switch (fp
->f_flags
& (F_WHEREFOUND
)) {
195 case F_IN_BASELINE
: /* only exists in baseline */
196 case 0: /* only exists in rules */
198 fprintf(stdout
, gettext(V_nomore
),
200 fp
->f_flags
|= F_REMOVE
; /* fix baseline */
203 case F_IN_BASELINE
|F_IN_SOURCE
: /* deleted from dest */
205 * the basic principle here is that we are willing
206 * to do the deletion if:
207 * no changes were made on the other side
209 * we have been told to force in this direction
211 * we do, however, make an exception for files that
212 * will still have other links. In this case, the
213 * (changed) data will still be accessable through
214 * another link and so we are willing to do the unlink
215 * inspite of conflicting changes (which may well
216 * have been introduced through another link.
218 * The jury is still out on this one
220 if (((fp
->f_srcdiffs
&D_IMPORTANT
) == 0) ||
221 (opt_force
== OPT_DST
) ||
222 has_other_links(fp
, OPT_SRC
)) {
224 fprintf(stdout
, gettext(V_deleted
),
225 fp
->f_fullname
, "dst");
226 errs
= do_remove(fp
, OPT_SRC
);
230 /* a deletion combined with changes */
232 fprintf(stdout
, gettext(V_delconf
),
235 /* if we are to resolve in favor of source */
236 if (opt_force
== OPT_SRC
) {
237 errs
= do_copy(fp
, OPT_DST
);
241 fp
->f_problem
= gettext(PROB_del_change
);
244 case F_IN_BASELINE
|F_IN_DEST
: /* deleted from src */
245 /* just like previous case, w/sides reversed */
246 if (((fp
->f_dstdiffs
&D_IMPORTANT
) == 0) ||
247 (opt_force
== OPT_SRC
) ||
248 has_other_links(fp
, OPT_DST
)) {
250 fprintf(stdout
, gettext(V_deleted
),
251 fp
->f_fullname
, "src");
252 errs
= do_remove(fp
, OPT_DST
);
256 /* a deletion combined with changes */
258 fprintf(stdout
, gettext(V_delconf
),
261 /* if we are to resolve in favor of destination */
262 if (opt_force
== OPT_DST
) {
263 errs
= do_copy(fp
, OPT_SRC
);
267 fp
->f_problem
= gettext(PROB_del_change
);
271 * if something new shows up, and for some reason we cannot
272 * propagate it to the other side, we should suppress the
273 * file from the baseline, so it will show up as a new
274 * creation next time too.
276 case F_IN_SOURCE
: /* created in src */
278 fprintf(stdout
, gettext(V_created
),
279 fp
->f_fullname
, "src");
280 errs
= do_copy(fp
, OPT_DST
);
283 case F_IN_DEST
: /* created in dest */
285 fprintf(stdout
, gettext(V_created
),
286 fp
->f_fullname
, "dst");
287 errs
= do_copy(fp
, OPT_SRC
);
290 case F_IN_SOURCE
|F_IN_DEST
: /* not in baseline */
292 * since we don't have a baseline, we cannot
293 * know which of the two copies should prevail
297 case F_IN_BASELINE
|F_IN_SOURCE
|F_IN_DEST
:
299 * we have a baseline where the two copies agreed,
300 * so maybe we can determine that only one of the
301 * two copies have changed ... but before we decide
302 * who should be the winner we should determine
303 * that the two copies are actually different.
309 * if we have fallen out of the case statement, it is because
310 * we have discovered a non-obvious situation where potentially
311 * changed versions of the file exist on both sides.
313 * if the two copies turn out to be identical, this is simple
317 /* files are identical, just update baseline */
319 fprintf(stdout
, gettext(V_unchanged
),
321 update_info(fp
, OPT_SRC
);
325 * contents agree but ownership/protection does
326 * not agree, so we have to bring these into
327 * agreement. We can pick a winner if one
328 * side hasn't changed, or if the user has
329 * specified a force flag.
332 fprintf(stdout
, gettext(V_modes
),
335 if (((fp
->f_srcdiffs
& D_ADMIN
) == 0) ||
336 (opt_force
== OPT_DST
)) {
337 errs
= do_like(fp
, OPT_SRC
, TRUE
);
341 if (((fp
->f_dstdiffs
& D_ADMIN
) == 0) ||
342 (opt_force
== OPT_SRC
)) {
343 errs
= do_like(fp
, OPT_DST
, TRUE
);
347 /* falls down to cant */
350 * The two files have different contents, so we have
351 * a potential conflict here. If we know that only one
352 * side has changed, we go with that side.
354 if (fp
->f_dstdiffs
== 0 || fp
->f_srcdiffs
== 0) {
356 fprintf(stdout
, gettext(V_changed
),
358 errs
= do_copy(fp
, fp
->f_srcdiffs
? OPT_DST
: OPT_SRC
);
363 * Both sides have changed, so we have a real conflict.
367 gettext(truncated(fp
) ?
368 V_trunconf
: V_different
),
372 * See if the user has given us explicit instructions
373 * on how to resolve conflicts. We may have been told
374 * to favor the older, the newer, the source, or the
375 * destination ... but the default is to leave the
376 * conflict unresolved.
378 if (opt_force
== OPT_OLD
) {
379 errs
= do_copy(fp
, newer(fp
));
383 if (opt_force
== OPT_NEW
) {
384 errs
= do_copy(fp
, older(fp
));
388 if (opt_force
!= 0) {
389 errs
= do_copy(fp
, (opt_force
== OPT_SRC
) ?
396 * This is our last chance before giving up.
398 * We know that the files have different contents and
399 * that there were changes on both sides. The only way
400 * we can safely handle this is if there were pure contents
401 * changes on one side and pure ownership changes on the
402 * other side. In this case we can propagate the ownership
403 * one way and the contents the other way.
405 * We decide whether or not this is possible by ANDing
406 * together the changes on the two sides, and seeing
407 * if the changes were all orthogonal (none of the same
408 * things changed on both sides).
410 diffmask
= fp
->f_srcdiffs
& fp
->f_dstdiffs
;
411 if ((diffmask
& D_CONTENTS
) == 0) {
413 * if ownership changes were only made on one side
414 * (presumably the side that didn't have data changes)
415 * we can handle them separately. In this case,
416 * ownership changes must be fixed first, because
417 * the subsequent do_copy will overwrite them.
419 if ((diffmask
& D_ADMIN
) == 0)
420 errs
|= do_like(fp
, (fp
->f_srcdiffs
&D_ADMIN
) ?
425 * Now we can deal with the propagation of the data
426 * changes. Note that any ownership/protection
427 * changes (from the other side) that have not been
428 * propagated yet are about to be lost. The cases
429 * in which this might happen are all pathological
430 * and the consequences of losing the protection
431 * changes are (IMHO) minor when compared to the
432 * obviously correct data propagation.
434 errs
|= do_copy(fp
, (fp
->f_srcdiffs
&D_CONTENTS
) ?
440 * there are conflicting changes, nobody has told us how to
441 * resolve conflicts, and we cannot figure out how to merge
444 fp
->f_problem
= gettext(PROB_different
);
449 * I'm not smart enough to resolve this conflict automatically,
450 * so I have no choice but to bounce it back to the user.
452 fp
->f_flags
|= F_CONFLICT
;
453 fp
->f_base
->b_unresolved
++;
454 errs
|= ERR_UNRESOLVED
;
458 * if we have a conflict and the file is not in the baseline,
459 * then there was never any point at which the two copies were
460 * in agreement, and we want to preserve the conflict for future
463 if ((errs
&ERR_UNRESOLVED
) && (fp
->f_flags
& F_IN_BASELINE
) == 0)
464 if (fp
->f_files
== 0)
466 * in most cases, this is most easily done by just
467 * excluding the file in question from the baseline
469 fp
->f_flags
|= F_REMOVE
;
472 * but ... if the file in question is a directory
473 * with children, excluding it from the baseline
474 * would keep all of its children (even those with
475 * no conflicts) out of the baseline as well. In
476 * This case, it is better to tell a lie and to
477 * manufacture a point of imaginary agreement
478 * in the baseline ... but one that is absurd enough
479 * that we will still see conflicts each time we run.
481 * recording a type of directory, and everything
482 * else as zero should be absurd enough.
484 fp
->f_info
[ OPT_BASE
].f_type
= S_IFDIR
;
486 if (opt_debug
& DBG_MISC
)
487 fprintf(stderr
, "MISC: %s ERRS=%s\n", fp
->f_fullname
,
488 showflags(errmap
, errs
));
498 * determine which of two files is newer
507 newer(struct file
*fp
)
509 struct fileinfo
*sp
, *dp
;
511 sp
= &fp
->f_info
[OPT_SRC
];
512 dp
= &fp
->f_info
[OPT_DST
];
514 if (sp
->f_modtime
> dp
->f_modtime
)
517 if (sp
->f_modtime
< dp
->f_modtime
)
520 if (sp
->f_modns
>= dp
->f_modns
)
531 * determine which of two files is older
540 older(struct file
*fp
)
542 struct fileinfo
*sp
, *dp
;
544 sp
= &fp
->f_info
[OPT_SRC
];
545 dp
= &fp
->f_info
[OPT_DST
];
547 if (sp
->f_modtime
< dp
->f_modtime
)
550 if (sp
->f_modtime
> dp
->f_modtime
)
553 if (sp
->f_modns
<= dp
->f_modns
)
564 * determine whether or not two files contain the same data
570 * bool_t (true/false)
573 samedata(struct file
*fp
)
575 struct fileinfo
*sp
, *dp
;
577 sp
= &fp
->f_info
[OPT_SRC
];
578 dp
= &fp
->f_info
[OPT_DST
];
580 /* cheap test: types are different */
581 if (sp
->f_type
!= dp
->f_type
)
584 /* cheap test: directories have same contents */
585 if (sp
->f_type
== S_IFDIR
)
588 /* special files are compared via their maj/min */
589 if ((sp
->f_type
== S_IFBLK
) || (sp
->f_type
== S_IFCHR
)) {
590 if (sp
->f_rd_maj
!= dp
->f_rd_maj
)
592 if (sp
->f_rd_min
!= dp
->f_rd_min
)
597 /* symlinks are the same if their contents are the same */
598 if (sp
->f_type
== S_IFLNK
)
601 /* cheap test: sizes are different */
602 if (fp
->f_info
[OPT_SRC
].f_size
!= fp
->f_info
[OPT_DST
].f_size
)
605 /* expensive test: byte for byte comparison */
606 if (samecompare(fp
) == 0)
617 * determine whether or not two files have same owner/protection
623 * bool_t (true/false)
626 samestuff(struct file
*fp
)
627 { int same_mode
, same_uid
, same_gid
, same_acl
;
628 struct fileinfo
*sp
, *dp
;
630 sp
= &fp
->f_info
[OPT_SRC
];
631 dp
= &fp
->f_info
[OPT_DST
];
633 same_mode
= (sp
->f_mode
== dp
->f_mode
);
634 same_uid
= (sp
->f_uid
== dp
->f_uid
);
635 same_gid
= (sp
->f_gid
== dp
->f_gid
);
636 same_acl
= cmp_acls(sp
, dp
);
638 /* if the are all the same, it is easy to tell the truth */
639 if (same_uid
&& same_gid
&& same_mode
&& same_acl
)
642 /* note the nature of the conflict */
643 if (!same_uid
|| !same_gid
|| !same_acl
)
644 fp
->f_problem
= gettext(PROB_ownership
);
646 fp
->f_problem
= gettext(PROB_protection
);
656 * do a byte-for-byte comparison of two files
662 * bool_t (true/false)
665 samecompare(struct file
*fp
)
668 char srcbuf
[ COPY_BSIZE
], dstbuf
[ COPY_BSIZE
];
672 sfd
= open(srcname
, 0);
676 dfd
= open(dstname
, 0);
683 count
= read(sfd
, srcbuf
, COPY_BSIZE
);
685 count
= read(sfd
, srcbuf
, COPY_BSIZE
)) {
687 /* do a matching read */
688 if (read(dfd
, dstbuf
, COPY_BSIZE
) != count
) {
693 /* do the comparison for this block */
694 for (i
= 0; i
< count
; i
++) {
695 if (srcbuf
[i
] != dstbuf
[i
]) {
703 if (opt_debug
& DBG_ANAL
)
704 fprintf(stderr
, "ANAL: SAME=%d %s\n", same
, fp
->f_fullname
);
716 * to determine whether or not a file has been truncated
719 * pointer to file structure
725 truncated(struct file
*fp
)
727 /* either source or destination must now be zero length */
728 if (fp
->f_info
[OPT_SRC
].f_size
&& fp
->f_info
[OPT_DST
].f_size
)
731 /* file must have originally had a non-zero length */
732 if (fp
->f_info
[OPT_BASE
].f_size
== 0)
735 /* file type must "normal" all around */
736 if (fp
->f_info
[OPT_BASE
].f_type
!= S_IFREG
)
738 if (fp
->f_info
[OPT_SRC
].f_type
!= S_IFREG
)
740 if (fp
->f_info
[OPT_DST
].f_type
!= S_IFREG
)
752 * to determine whether or not two symbolic links agree
755 * pointer to file structure
762 { int i
, srclen
, dstlen
;
763 char srcbuf
[ MAX_PATH
], dstbuf
[ MAX_PATH
];
766 /* read both copies of the link */
767 srclen
= readlink(srcname
, srcbuf
, sizeof (srcbuf
));
768 dstlen
= readlink(dstname
, dstbuf
, sizeof (dstbuf
));
770 /* if they aren't the same length, they disagree */
771 if (srclen
< 0 || dstlen
< 0 || srclen
!= dstlen
)
774 /* look for differences in contents */
775 for (i
= 0; i
< srclen
; i
++)
776 if (srcbuf
[i
] != dstbuf
[i
])
787 * to figure out the fully qualified path name to a file on the
788 * reconciliation list.
791 * pointer to the file structure
792 * side indication for which base to use
793 * side indication for which buffer to use
796 * pointer to a clobberable buffer
799 * the zero'th buffer is used for renames and links, where
800 * we need the name of another file on the same side.
803 full_name(struct file
*fp
, side_t srcdst
, side_t whichbuf
)
804 { static char *buffers
[3];
805 static int buflen
= 0;
809 /* see if the existing buffer is long enough */
810 b
= (srcdst
== OPT_SRC
) ? fp
->f_base
->b_src_name
811 : fp
->f_base
->b_dst_name
;
813 /* see if the allocated buffer is long enough */
814 l
= strlen(b
) + strlen(fp
->f_fullname
) + 2;
816 /* figure out the next "nice" size to use */
817 for (buflen
= MAX_PATH
; buflen
< l
; buflen
+= MAX_NAME
);
819 /* reallocate all buffers to this size */
820 for (l
= 0; l
< 3; l
++) {
821 buffers
[l
] = (char *) realloc(buffers
[l
], buflen
);
827 /* assemble the name in the buffer and reurn it */
828 p
= buffers
[whichbuf
];
831 strcat(p
, fp
->f_fullname
);