diff: fix failed compare when ignoring file case

With --ignore-file-name-case we need to compare files regardless of
case. We need to propigate both names down to diffit so we can look up
the correct file when the names differ based on case, otherwise we try
to look up the file using the case from the a tree which might not be
discoverable if its case is different in the b tree.

Reviewed by:	bapt
Sponsored by:	Klara Inc.
Differential Revision:	https://reviews.freebsd.org/D34201
This commit is contained in:
Tom Jones 2022-02-18 15:21:23 +00:00
parent cffebd1e8f
commit 3931c072c6
2 changed files with 31 additions and 9 deletions

View File

@ -38,7 +38,8 @@ __FBSDID("$FreeBSD$");
#include "diff.h"
static int selectfile(const struct dirent *);
static void diffit(struct dirent *, char *, size_t, char *, size_t, int);
static void diffit(struct dirent *, char *, size_t, struct dirent *,
char *, size_t, int);
static void print_only(const char *, size_t, const char *);
#define d_status d_type /* we need to store status for -l */
@ -128,14 +129,14 @@ diffdir(char *p1, char *p2, int flags)
strcmp(dent1->d_name, dent2->d_name) ;
if (pos == 0) {
/* file exists in both dirs, diff it */
diffit(dent1, path1, dirlen1, path2, dirlen2, flags);
diffit(dent1, path1, dirlen1, dent2, path2, dirlen2, flags);
dp1++;
dp2++;
} else if (pos < 0) {
/* file only in first dir, only diff if -N */
if (Nflag) {
diffit(dent1, path1, dirlen1, path2, dirlen2,
flags);
diffit(dent1, path1, dirlen1, dent2, path2,
dirlen2, flags);
} else {
print_only(path1, dirlen1, dent1->d_name);
status |= 1;
@ -144,8 +145,8 @@ diffdir(char *p1, char *p2, int flags)
} else {
/* file only in second dir, only diff if -N or -P */
if (Nflag || Pflag)
diffit(dent2, path1, dirlen1, path2, dirlen2,
flags);
diffit(dent2, path1, dirlen1, dent1, path2,
dirlen2, flags);
else {
print_only(path2, dirlen2, dent2->d_name);
status |= 1;
@ -171,12 +172,20 @@ diffdir(char *p1, char *p2, int flags)
* Do the actual diff by calling either diffreg() or diffdir().
*/
static void
diffit(struct dirent *dp, char *path1, size_t plen1, char *path2, size_t plen2,
int flags)
diffit(struct dirent *dp, char *path1, size_t plen1, struct dirent *dp2,
char *path2, size_t plen2, int flags)
{
flags |= D_HEADER;
strlcpy(path1 + plen1, dp->d_name, PATH_MAX - plen1);
strlcpy(path2 + plen2, dp->d_name, PATH_MAX - plen2);
/*
* If we are ignoring file case, use dent2s name here if both names are
* the same apart from case.
*/
if (ignore_file_case && strcasecmp(dp2->d_name, dp2->d_name) == 0)
strlcpy(path2 + plen2, dp2->d_name, PATH_MAX - plen2);
else
strlcpy(path2 + plen2, dp->d_name, PATH_MAX - plen2);
if (noderef) {
if (lstat(path1, &stb1) != 0) {

View File

@ -21,6 +21,7 @@ atf_test_case non_regular_file
atf_test_case binary
atf_test_case functionname
atf_test_case noderef
atf_test_case ignorecase
simple_body()
{
@ -324,6 +325,17 @@ noderef_body()
atf_check -o inline:"Symbolic links A/test-file and B/test-file differ\n" -s exit:1 diff -r --no-dereference A B
}
ignorecase_body()
{
atf_check mkdir A
atf_check mkdir B
atf_check -x "echo hello > A/foo"
atf_check -x "echo hello > B/FOO"
atf_check -o empty -s exit:0 diff -u -r --ignore-file-name-case A B
}
atf_init_test_cases()
{
atf_add_test_case simple
@ -347,4 +359,5 @@ atf_init_test_cases()
atf_add_test_case binary
atf_add_test_case functionname
atf_add_test_case noderef
atf_add_test_case ignorecase
}