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 * routines to determine whether or not any renames have taken place
30 * and note them (for reconciliation) if we find any
33 * find_renames . look for files that have been renamed
34 * find_oldname . (static) find the file we were renamed from
35 * note_rename .. (static) note the rename for subsequent reconciliation
38 * the reason renames warrant special attention is because the tree
39 * we have constructed is name based, and a directory rename can
40 * appear as zillions of changes. We attempt to find and deal with
41 * renames prior to doing the difference analysis.
43 * The only case we deal with here is simple renames. If new links
44 * have been created beneath other directories (i.e. a file has been
45 * moved from one directory to another), the generalized link finding
46 * stuff will deal with it.
48 * This is still under construction, and to completely deal with
49 * directory renames may require some non-trivial tree restructuring.
50 * There is a whole design note on this subject. In the mean time,
51 * we still detect file renames, so that the user will see them
52 * reported as "mv"s rather than as "ln"s and "rm"s. Until directory
53 * renames are fully implemented, they will instead be handled as
54 * mkdirs, massive links and unlinks, and rmdirs.
65 static struct file
*find_oldname(struct file
*, struct file
*, side_t
);
67 note_rename(struct file
*, struct file
*, struct file
*, side_t
);
74 * recursively perform rename analysis on a directory
77 * file node for the suspected directory
83 * the basic algorithm here is to search every directory
84 * for files that have been newly created on one side,
85 * and then look to see if they correspond to an identical
86 * file that has been newly deleted on the same side.
89 find_renames(struct file
*fp
)
90 { struct file
*np
, *rp
;
92 int stype
, dtype
, btype
, side
;
94 /* if this isn't a directory, there is nothing to analyze */
98 /* look for any files under this directory that may have been renamed */
99 for (np
= fp
->f_files
; np
; np
= np
->f_next
) {
100 btype
= np
->f_info
[OPT_BASE
].f_type
;
101 stype
= np
->f_info
[OPT_SRC
].f_type
;
102 dtype
= np
->f_info
[OPT_DST
].f_type
;
104 /* a rename must be a file that is new on only one side */
105 if (btype
== 0 && stype
!= dtype
&& (!stype
|| !dtype
)) {
106 side
= stype
? OPT_SRC
: OPT_DST
;
107 rp
= find_oldname(fp
, np
, side
);
109 errs
|= note_rename(fp
, np
, rp
, side
);
113 /* recursively examine all my children */
114 for (np
= fp
->f_files
; np
; np
= np
->f_next
) {
115 errs
|= find_renames(np
);
126 * to search for an old name for a newly discovered file
129 * file node for the containing directory
130 * file node for the new file
131 * which side the rename is believed to have happened on
134 * pointer to likely previous file
135 * 0 no candidate found
138 * this routine only deals with simple renames within a single
141 static struct file
*find_oldname(struct file
*dirp
, struct file
*new,
147 side_t otherside
= (side
== OPT_SRC
) ? OPT_DST
: OPT_SRC
;
149 /* figure out what we're looking for */
150 inum
= new->f_info
[side
].f_ino
;
151 maj
= new->f_info
[side
].f_d_maj
;
152 min
= new->f_info
[side
].f_d_min
;
153 size
= new->f_info
[side
].f_size
;
156 * search the same directory for any entry that might describe
157 * the previous name of the new file.
159 for (fp
= dirp
->f_files
; fp
; fp
= fp
->f_next
) {
160 /* previous name on changed side must no longer exist */
161 if (fp
->f_info
[side
].f_type
!= 0)
164 /* previous name on the other side must still exist */
165 if (fp
->f_info
[otherside
].f_type
== 0)
168 /* it must describe the same inode as the new file */
169 if (fp
->f_info
[OPT_BASE
].f_type
!= new->f_info
[side
].f_type
)
170 continue; /* must be same type */
171 if (((side
== OPT_SRC
) ? fp
->f_s_inum
: fp
->f_d_inum
) != inum
)
172 continue; /* must be same inode # */
173 if (((side
== OPT_SRC
) ? fp
->f_s_maj
: fp
->f_d_maj
) != maj
)
174 continue; /* must be same major # */
175 if (((side
== OPT_SRC
) ? fp
->f_s_min
: fp
->f_d_min
) != min
)
176 continue; /* must be same minor # */
179 * occasionally a prompt delete and create can reuse the
180 * same i-node in the same directory. What we really
181 * want is generation, but that isn't available just
182 * yet, so our poor-man's approximation is the size.
183 * There is little point in checking ownership and
184 * modes, since the fact that it is in the same
185 * directory strongly suggests that it is the same
186 * user who is doing the deleting and creating.
188 if (fp
->f_info
[OPT_BASE
].f_size
!= size
)
191 /* looks like we found a match */
204 * to record a discovered rename, so that the reconciliation
205 * phase will deal with it as a rename rather than as link
206 * followed by an unlink.
209 * file node for the containing directory
210 * file node for the new file
211 * file node for the old file
212 * which side the rename is believed to have happened on
218 note_rename(struct file
*dirp
, struct file
*new,
219 struct file
*old
, side_t side
)
223 static char *sidenames
[] = {"base", "source", "dest"};
225 dir
= new->f_info
[side
].f_type
== S_IFDIR
;
227 if (opt_debug
& DBG_ANAL
)
228 fprintf(stderr
, "ANAL: NOTE RENAME %s %s/%s -> %s/%s on %s\n",
229 dir
? "directory" : "file",
230 dirp
->f_name
, old
->f_name
, dirp
->f_name
, new->f_name
,
233 /* FIX: we don't deal with directory renames yet */
237 /* note that a rename has taken place */
238 if (side
== OPT_SRC
) {
239 new->f_srcdiffs
|= D_RENAME_TO
;
240 old
->f_srcdiffs
|= D_RENAME_FROM
;
242 new->f_dstdiffs
|= D_RENAME_TO
;
243 old
->f_dstdiffs
|= D_RENAME_FROM
;
246 /* put a link to the old name in the new name */
247 new->f_previous
= old
;
249 /* for most files, there is nothing else we have to do */
254 * FIX ... someday we are going to have to merge the old and
255 * new children into a single tree, but there are
256 * horrendous backout problems if we are unable to
257 * do the mvdir, so I have postponed this feature.