threads / patch / 47785

patchname-hash: properly fold directory names in adjust_dirname_case()

Subject: [PATCH v1] name-hash: properly fold directory names in adjust_dirname_case()

## tl;dr

8 messages between Feb 8, 2018 and Feb 9, 2018. Diffs are folded; open one to read it.

replies: 7people: 4as markdown or json

Ben Peart· Feb 8, 2018, 00:41 UTC · lore

Correct the pointer arithmetic in adjust_dirname_case() so that it calls find_dir_entry() with the correct string length. Previously passing in "dir1/foo" would pass a length of 6 instead of the correct 4. This resulted in find_dir_entry() never finding the entry and so the subsequent memcpy that would fold the name to the version with the correct case never executed.

Add a test to validate the corrected behavior with name folding of directories.
Signed-off-by: Ben Peart <benpeart@microsoft.com>
---
Notes:
    Base Ref: v2.16.1
    Web-Diff: https://github.com/benpeart/git/commit/2944970f4e
    Checkout: git fetch https://github.com/benpeart/git adjust_dirname-v1 && git checkout 2944970f4e
 name-hash.c           |  6 +++---
 t/t0050-filesystem.sh | 12 +++++++++++-
 2 files changed, 14 insertions(+), 4 deletions(-)
Show changes to 2 files +14 −4

name-hash.c, t/t0050-filesystem.sh

diff --git a/name-hash.c b/name-hash.c
index 45c98db0a0..2ddbb72647 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -696,12 +696,12 @@ void adjust_dirname_case(struct index_state *istate, char *name)
 		if (*ptr == '/') {
 			struct dir_entry *dir;
 
-			ptr++;
-			dir = find_dir_entry(istate, name, ptr - name + 1);
+			dir = find_dir_entry(istate, name, ptr - name);
 			if (dir) {
 				memcpy((void *)startPtr, dir->name + (startPtr - name), ptr - startPtr);
-				startPtr = ptr;
+				startPtr = ptr + 1;
 			}
+			ptr++;
 		}
 	}
 }
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index b29d749bb7..219c96594c 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -80,7 +80,17 @@ test_expect_success 'merge (case change)' '
 	git merge topic
 '
 
-
+test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
+	git reset --hard initial &&
+	mkdir -p dir1 &&
+	mkdir -p dir1/dir2 &&
+	touch dir1/dir2/a &&
+	touch dir1/dir2/b &&
+	git add dir1/dir2/a &&
+	git add dir1/DIR2/b &&
+	camel=$(git ls-files | grep dir2) &&
+	test $(echo "$camel" | wc -l) = 2
+'
 
 test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
 	git reset --hard initial &&

base-commit: 8279ed033f703d4115bee620dccd32a9ec94d9aa
-- 
2.15.0.windows.1
David Turner· Feb 8, 2018, 01:02 UTC · re: Ben Peart · lore

Re: [PATCH v1] name-hash: properly fold directory names in adjust_dirname_case()

On Wed, 2018-02-07 at 19:41 -0500, Ben Peart wrote:
Show 12 quoted lines
> Correct the pointer arithmetic in adjust_dirname_case() so that it
> calls
> find_dir_entry() with the correct string length.  Previously passing
> in
> "dir1/foo" would pass a length of 6 instead of the correct 4.  This
> resulted in
> find_dir_entry() never finding the entry and so the subsequent memcpy
> that would
> fold the name to the version with the correct case never executed.
> 
> Add a test to validate the corrected behavior with name folding of
> directories.
Looks good to me.
Torsten Bögershausen· Feb 8, 2018, 17:21 UTC · re: Ben Peart · lore

Re: [PATCH v1] name-hash: properly fold directory names in adjust_dirname_case()

On Wed, Feb 07, 2018 at 07:41:56PM -0500, Ben Peart wrote: []

Show 21 quoted lines
> diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
> index b29d749bb7..219c96594c 100755
> --- a/t/t0050-filesystem.sh
> +++ b/t/t0050-filesystem.sh
> @@ -80,7 +80,17 @@ test_expect_success 'merge (case change)' '
>  	git merge topic
>  '
>  
> -
> +test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
> +	git reset --hard initial &&
> +	mkdir -p dir1 &&
> +	mkdir -p dir1/dir2 &&
> +	touch dir1/dir2/a &&
> +	touch dir1/dir2/b &&
> +	git add dir1/dir2/a &&
> +	git add dir1/DIR2/b &&
> +	camel=$(git ls-files | grep dir2) &&
> +	test $(echo "$camel" | wc -l) = 2
> +'
>  

There is nothing wrong with with "wc -l", but: a more new-style would probably use test_line_count() here.

My personal favorite would be to spell out what we expect and run a diff. When it fails, we can see what fails, and the function would look like this:

test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
	git reset --hard initial &&
	mkdir -p dir1 &&
	mkdir -p dir1/dir2 &&
	touch dir1/dir2/a &&
	touch dir1/dir2/b &&
	git add dir1/dir2/a &&
	git add dir1/DIR2/b &&
	git ls-files | grep dir2 | sort >actual &&
	cat >expected <<-\EOF &&
	dir1/dir2/a
	dir1/dir2/b
	EOF
	test_cmp expected actual
'
Ben Peart· Feb 8, 2018, 17:45 UTC · re: Torsten Bögershausen · lore

Re: [PATCH v1] name-hash: properly fold directory names in adjust_dirname_case()

On 2/8/2018 12:21 PM, Torsten Bögershausen wrote:
Show 32 quoted lines
> On Wed, Feb 07, 2018 at 07:41:56PM -0500, Ben Peart wrote:
> []
> 
>> diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
>> index b29d749bb7..219c96594c 100755
>> --- a/t/t0050-filesystem.sh
>> +++ b/t/t0050-filesystem.sh
>> @@ -80,7 +80,17 @@ test_expect_success 'merge (case change)' '
>>   	git merge topic
>>   '
>>   
>> -
>> +test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
>> +	git reset --hard initial &&
>> +	mkdir -p dir1 &&
>> +	mkdir -p dir1/dir2 &&
>> +	touch dir1/dir2/a &&
>> +	touch dir1/dir2/b &&
>> +	git add dir1/dir2/a &&
>> +	git add dir1/DIR2/b &&
>> +	camel=$(git ls-files | grep dir2) &&
>> +	test $(echo "$camel" | wc -l) = 2
>> +'
>>   
> 
> There is nothing wrong with with "wc -l", but:
> a more new-style would probably use test_line_count() here.
> 
> My personal favorite would be to spell out what we expect and run a diff.
> When it fails, we can see what fails, and the function would look
> like this:
> 

I agree with you completely that this is a better format and is easier to read. All the new tests I've been writing follow this same pattern.

In this particular test file, I opted (for better and for worse) to stick with the style of all the other tests rather than 1) have this one test be very different than all the others or 2) rewriting all the existing tests in the new style.

Show 19 quoted lines
> 
> test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
> 	git reset --hard initial &&
> 	mkdir -p dir1 &&
> 	mkdir -p dir1/dir2 &&
> 	touch dir1/dir2/a &&
> 	touch dir1/dir2/b &&
> 	git add dir1/dir2/a &&
> 	git add dir1/DIR2/b &&
> 	git ls-files | grep dir2 | sort >actual &&
> 	cat >expected <<-\EOF &&
> 	dir1/dir2/a
> 	dir1/dir2/b
> 	EOF
> 	test_cmp expected actual
> '
> 
> 
> 
Junio C Hamano· Feb 8, 2018, 18:24 UTC · re: Torsten Bögershausen · lore

Re: [PATCH v1] name-hash: properly fold directory names in adjust_dirname_case()

Torsten Bögershausen <tboegi@web.de> writes:
> My personal favorite would be to spell out what we expect and run a diff.
> When it fails, we can see what fails, and the function would look
> like this:

I'd rather not to have the "sort" there; output from ls-files is meant to be stable; passing it through sort would miss breakages. I agree that comparison between "expect" and "actual" is a good idea nevertheless.

Speaking of styles, I'd prefer to reserve use of "touch" to cases where resulting timestamp matters, and not "make sure it exists".

Thanks.
Show 15 quoted lines
> test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
> 	git reset --hard initial &&
> 	mkdir -p dir1 &&
> 	mkdir -p dir1/dir2 &&
> 	touch dir1/dir2/a &&
> 	touch dir1/dir2/b &&
> 	git add dir1/dir2/a &&
> 	git add dir1/DIR2/b &&
> 	git ls-files | grep dir2 | sort >actual &&
> 	cat >expected <<-\EOF &&
> 	dir1/dir2/a
> 	dir1/dir2/b
> 	EOF
> 	test_cmp expected actual
> '
Junio C Hamano· Feb 8, 2018, 18:20 UTC · re: Ben Peart · lore

Re: [PATCH v1] name-hash: properly fold directory names in adjust_dirname_case()

Ben Peart <benpeart@microsoft.com> writes:
Show 10 quoted lines
> Correct the pointer arithmetic in adjust_dirname_case() so that it calls
> find_dir_entry() with the correct string length.  Previously passing in
> "dir1/foo" would pass a length of 6 instead of the correct 4.  This resulted in
> find_dir_entry() never finding the entry and so the subsequent memcpy that would
> fold the name to the version with the correct case never executed.
>
> Add a test to validate the corrected behavior with name folding of directories.
>
> Signed-off-by: Ben Peart <benpeart@microsoft.com>
> ---
Thanks.

It appears that this codepath has been miscounting ever since it was introduced in 41284eb0 ("name-hash: don't reuse cache_entry in dir_entry", 2015-10-21).

Show 10 quoted lines
> diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
> index b29d749bb7..219c96594c 100755
> --- a/t/t0050-filesystem.sh
> +++ b/t/t0050-filesystem.sh
> @@ -80,7 +80,17 @@ test_expect_success 'merge (case change)' '
> ...
> +test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
> +	git reset --hard initial &&
> +	mkdir -p dir1 &&
> +	mkdir -p dir1/dir2 &&
A single "mkdir -p dir1/dir2" should be sufficient, thanks to "-p" ;-)
> +	touch dir1/dir2/a &&
> +	touch dir1/dir2/b &&
Hmph.
Ben Peart· Feb 8, 2018, 19:23 UTC · re: Ben Peart · lore

[PATCH v2] name-hash: properly fold directory names in adjust_dirname_case()

Correct the pointer arithmetic in adjust_dirname_case() so that it calls find_dir_entry() with the correct string length. Previously passing in "dir1/foo" would pass a length of 6 instead of the correct 4. This resulted in find_dir_entry() never finding the entry and so the subsequent memcpy that would fold the name to the version with the correct case never executed.

Add a test to validate the corrected behavior with name folding of directories.
Signed-off-by: Ben Peart <benpeart@microsoft.com>
---
Notes:
    Base Ref: v2.16.1
    Web-Diff: https://github.com/benpeart/git/commit/477da4602c
    Checkout: git fetch https://github.com/benpeart/git adjust_dirname-v2 && git checkout 477da4602c
    
    ### Interdiff (v1..v2):
    
    diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
    index 219c96594c..0e4e51b79a 100755
    --- a/t/t0050-filesystem.sh
    +++ b/t/t0050-filesystem.sh
    @@ -82,14 +82,18 @@ test_expect_success 'merge (case change)' '
    
     test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
     	git reset --hard initial &&
    -	mkdir -p dir1 &&
     	mkdir -p dir1/dir2 &&
    -	touch dir1/dir2/a &&
    -	touch dir1/dir2/b &&
    +	echo > dir1/dir2/a &&
    +	echo > dir1/dir2/b &&
     	git add dir1/dir2/a &&
     	git add dir1/DIR2/b &&
    -	camel=$(git ls-files | grep dir2) &&
    -	test $(echo "$camel" | wc -l) = 2
    +	git ls-files >actual &&
    +	cat >expected <<-\EOF &&
    +		camelcase
    +		dir1/dir2/a
    +		dir1/dir2/b
    +	EOF
    +	test_cmp expected actual
     '
    
     test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
    
    ### Patches
 name-hash.c           |  6 +++---
 t/t0050-filesystem.sh | 16 +++++++++++++++-
 2 files changed, 18 insertions(+), 4 deletions(-)
Show changes to 2 files +18 −4

name-hash.c, t/t0050-filesystem.sh

diff --git a/name-hash.c b/name-hash.c
index 45c98db0a0..2ddbb72647 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -696,12 +696,12 @@ void adjust_dirname_case(struct index_state *istate, char *name)
 		if (*ptr == '/') {
 			struct dir_entry *dir;
 
-			ptr++;
-			dir = find_dir_entry(istate, name, ptr - name + 1);
+			dir = find_dir_entry(istate, name, ptr - name);
 			if (dir) {
 				memcpy((void *)startPtr, dir->name + (startPtr - name), ptr - startPtr);
-				startPtr = ptr;
+				startPtr = ptr + 1;
 			}
+			ptr++;
 		}
 	}
 }
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index b29d749bb7..0e4e51b79a 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -80,7 +80,21 @@ test_expect_success 'merge (case change)' '
 	git merge topic
 '
 
-
+test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
+	git reset --hard initial &&
+	mkdir -p dir1/dir2 &&
+	echo > dir1/dir2/a &&
+	echo > dir1/dir2/b &&
+	git add dir1/dir2/a &&
+	git add dir1/DIR2/b &&
+	git ls-files >actual &&
+	cat >expected <<-\EOF &&
+		camelcase
+		dir1/dir2/a
+		dir1/dir2/b
+	EOF
+	test_cmp expected actual
+'
 
 test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
 	git reset --hard initial &&

base-commit: 8279ed033f703d4115bee620dccd32a9ec94d9aa
-- 
2.15.0.windows.1
Torsten Bögershausen· Feb 9, 2018, 05:43 UTC · re: Ben Peart · lore

Re: [PATCH v2] name-hash: properly fold directory names in adjust_dirname_case()

On Thu, Feb 08, 2018 at 02:23:33PM -0500, Ben Peart wrote:
[]
Show 6 quoted lines
> -
> +test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
> +	git reset --hard initial &&
> +	mkdir -p dir1/dir2 &&
> +	echo > dir1/dir2/a &&
> +	echo > dir1/dir2/b &&
Thanks for working on this-
One and a half style nits:
The ">" should be close to the file name:
	echo >dir1/dir2/a &&
But then we don't even look into the file, so that the "\" produced by echo is not needed.
A simple 
	>dir1/dir2/a &&
is all that is needed.

← back to recent threads