1943
char **old_dir, char **new_dir)
1944
{
1945
char *end_of_old, *end_of_new;
1946
- int old_len, new_len;
1946
1947
+ /* Default return values: NULL, meaning no rename */
1948
*old_dir = NULL;
1949
*new_dir = NULL;
1950
1955
* "a/b/c/d" was renamed to "a/b/some/thing/else"
1956
* so, for this example, this function returns "a/b/c/d" in
1957
* *old_dir and "a/b/some/thing/else" in *new_dir.
1958
- *
1959
- * Also, if the basename of the file changed, we don't care. We
1960
- * want to know which portion of the directory, if any, changed.
1958
+ */
1959
+
1960
+ /*
1961
+ * If the basename of the file changed, we don't care. We want
1962
+ * to know which portion of the directory, if any, changed.
1963
*/
1964
end_of_old = strrchr(old_path, '/');
1965
end_of_new = strrchr(new_path, '/');
1964
-
1966
if (end_of_old == NULL || end_of_new == NULL)
1966
- return;
1967
+ return; /* We haven't modified *old_dir or *new_dir yet. */
1968
+
1969
+ /* Find the first non-matching character traversing backwards */
1970
while (*--end_of_new == *--end_of_old &&
1971
end_of_old != old_path &&
1972
end_of_new != new_path)
1973
; /* Do nothing; all in the while loop */
1974
+
1975
/*
1972
- * We've found the first non-matching character in the directory
1973
- * paths. That means the current directory we were comparing
1974
- * represents the rename. Move end_of_old and end_of_new back
1975
- * to the full directory name.
1976
+ * If both got back to the beginning of their strings, then the
1977
+ * directory didn't change at all, only the basename did.
1978
*/
1977
- if (*end_of_old == '/')
1978
- end_of_old++;
1979
- if (*end_of_old != '/')
1980
- end_of_new++;
1981
- end_of_old = strchr(end_of_old, '/');
1982
- end_of_new = strchr(end_of_new, '/');
1979
+ if (end_of_old == old_path && end_of_new == new_path &&
1980
+ *end_of_old == *end_of_new)
1981
+ return; /* We haven't modified *old_dir or *new_dir yet. */
1982
1983
/*
1985
- * It may have been the case that old_path and new_path were the same
1986
- * directory all along. Don't claim a rename if they're the same.
1984
+ * We've found the first non-matching character in the directory
1985
+ * paths. That means the current characters we were looking at
1986
+ * were part of the first non-matching subdir name going back from
1987
+ * the end of the strings. Get the whole name by advancing both
1988
+ * end_of_old and end_of_new to the NEXT '/' character. That will
1989
+ * represent the entire directory rename.
1990
+ *
1991
+ * The reason for the increment is cases like
1992
+ * a/b/star/foo/whatever.c -> a/b/tar/foo/random.c
1993
+ * After dropping the basename and going back to the first
1994
+ * non-matching character, we're now comparing:
1995
+ * a/b/s and a/b/
1996
+ * and we want to be comparing:
1997
+ * a/b/star/ and a/b/tar/
1998
+ * but without the pre-increment, the one on the right would stay
1999
+ * a/b/.
2000
*/
1988
- old_len = end_of_old - old_path;
1989
- new_len = end_of_new - new_path;
2001
+ end_of_old = strchr(++end_of_old, '/');
2002
+ end_of_new = strchr(++end_of_new, '/');
2003
1991
- if (old_len != new_len || strncmp(old_path, new_path, old_len)) {
1992
- *old_dir = xstrndup(old_path, old_len);
1993
- *new_dir = xstrndup(new_path, new_len);
1994
- }
2004
+ /* Copy the old and new directories into *old_dir and *new_dir. */
2005
+ *old_dir = xstrndup(old_path, end_of_old - old_path);
2006
+ *new_dir = xstrndup(new_path, end_of_new - new_path);
2007
}
2008
2009
static void remove_hashmap_entries(struct hashmap *dir_renames,