diff mbox series

[2/4] attr: notice and report read failure of .gitattributes files

Message ID 20240618234436.4107855-3-gitster@pobox.com (mailing list archive)
State New, archived
Headers show
Series .git{ignore,attributes} directories? | expand

Commit Message

Junio C Hamano June 18, 2024, 11:44 p.m. UTC
The code that reads .gitattributes files was careless in dealing in
unusual circumstances.

 - It let read errors silently ignored.

 - It tried to read ".gitattributes" that is a directory on
   platforms that allowed open(2) to open directories.

To make the latter consistent with what we do for fopen() on
directories ("git grep" for FREAD_READS_DIRECTORIES for details),
check if we opened a directory, silently close it and return
success.  Catch all read errors before we close and report as
needed.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 attr.c                | 10 +++++++++-
 t/t0003-attributes.sh |  9 +++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

Comments

Eric Sunshine June 19, 2024, 12:21 a.m. UTC | #1
On Tue, Jun 18, 2024 at 7:46 PM Junio C Hamano <gitster@pobox.com> wrote:
> The code that reads .gitattributes files was careless in dealing in
> unusual circumstances.
>
>  - It let read errors silently ignored.

ECANTPARSE: perhaps? s/errors/& be/

>  - It tried to read ".gitattributes" that is a directory on
>    platforms that allowed open(2) to open directories.
>
> To make the latter consistent with what we do for fopen() on
> directories ("git grep" for FREAD_READS_DIRECTORIES for details),
> check if we opened a directory, silently close it and return
> success.  Catch all read errors before we close and report as
> needed.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano June 19, 2024, 1:18 a.m. UTC | #2
Eric Sunshine <sunshine@sunshineco.com> writes:

> ECANTPARSE: perhaps? s/errors/& be/

You're right.  Thanks.
Eric Sunshine June 19, 2024, 2:35 a.m. UTC | #3
On Tue, Jun 18, 2024 at 9:18 PM Junio C Hamano <gitster@pobox.com> wrote:
> Eric Sunshine <sunshine@sunshineco.com> writes:
> > ECANTPARSE: perhaps? s/errors/& be/
>
> You're right.  Thanks.

The same problem occurs in the commit message of patch [3/4].
Jeff King June 19, 2024, 1:57 p.m. UTC | #4
On Tue, Jun 18, 2024 at 04:44:33PM -0700, Junio C Hamano wrote:

> The code that reads .gitattributes files was careless in dealing in
> unusual circumstances.
> 
>  - It let read errors silently ignored.
> 
>  - It tried to read ".gitattributes" that is a directory on
>    platforms that allowed open(2) to open directories.
> 
> To make the latter consistent with what we do for fopen() on
> directories ("git grep" for FREAD_READS_DIRECTORIES for details),
> check if we opened a directory, silently close it and return
> success.  Catch all read errors before we close and report as
> needed.

Makes sense, but...

> diff --git a/attr.c b/attr.c
> index 300f994ba6..9ab9cf1551 100644
> --- a/attr.c
> +++ b/attr.c
> @@ -747,6 +747,11 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
>  		fclose(fp);
>  		return NULL;
>  	}
> +	if (S_ISDIR(st.st_mode)) {
> +		/* On FREAD_READS_DIRECTORIES platforms */
> +		fclose(fp);
> +		return NULL;
> +	}

I don't know that this is really consistent with callers of fopen(),
since they tend to complain noisily. Usually via warn_on_fopen_errors(),
which we ourselves call above.

I.e., if we were using fopen() here rather than open()+fdopen(), our
call would likewise complain noisily. And we even did so prior to
2ef579e261 (attr: do not respect symlinks for in-tree .gitattributes,
2021-02-16)! We had to switch to open() then to use O_NOFOLLOW.

And I notice that every caller of open_nofollow() does an fdopen()
anyway. So I wonder if the better solution would be to make an
fopen_nofollow() that handles the FREAD_READS_DIRECTORIES stuff itself,
just like fopen() does?


That is also an interesting data point regarding the "is it sane to have
directory .gitattributes" question. Older versions would definitely
complain about it (once per file in the diff even):

  $ mkdir .gitattributes
  $ git.v2.31.0 show >/dev/null
  warning: unable to access '.gitattributes': Is a directory
  warning: unable to access '.gitattributes': Is a directory

-Peff
Junio C Hamano June 20, 2024, 4:20 p.m. UTC | #5
Jeff King <peff@peff.net> writes:

> I don't know that this is really consistent with callers of fopen(),
> since they tend to complain noisily. Usually via warn_on_fopen_errors(),
> which we ourselves call above.

Argh, you're right.  I thought the guard in warn_on_fopen_errors()
would catch the artificial error code we give when we found that we
opened a directory (by mistake), but the error we use is EISDIR, so
it will be shown.

OK, let's scrap the whole thing.  It does not look like it is
solving any real-world problems.

Thanks.
diff mbox series

Patch

diff --git a/attr.c b/attr.c
index 300f994ba6..9ab9cf1551 100644
--- a/attr.c
+++ b/attr.c
@@ -747,6 +747,11 @@  static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
 		fclose(fp);
 		return NULL;
 	}
+	if (S_ISDIR(st.st_mode)) {
+		/* On FREAD_READS_DIRECTORIES platforms */
+		fclose(fp);
+		return NULL;
+	}
 	if (st.st_size >= ATTR_MAX_FILE_SIZE) {
 		warning(_("ignoring overly large gitattributes file '%s'"), path);
 		fclose(fp);
@@ -760,7 +765,10 @@  static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
 		handle_attr_line(res, buf.buf, path, ++lineno, flags);
 	}
 
-	fclose(fp);
+	if (ferror(fp))
+		warning_errno(_("failed while reading gitattributes file '%s'"), path);
+	if (fclose(fp))
+		warning_errno(_("cannot fclose gitattributes file '%s'"), path);
 	strbuf_release(&buf);
 	return res;
 }
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 66ccb5889d..783c20146d 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -603,6 +603,15 @@  test_expect_success EXPENSIVE 'large attributes blob ignored' '
 	test_cmp expect err
 '
 
+test_expect_success '.gitattribute directory behaves as if it does not exist' '
+	test_when_finished "rm -fr dir" &&
+	mkdir -p dir/.gitattributes &&
+	>dir/ectory &&
+	git -C dir check-attr --all ectory >out 2>err &&
+	test_grep ! "failed while reading" err &&
+	test_grep ! "cannot fclose" err
+'
+
 test_expect_success 'builtin object mode attributes work (dir and regular paths)' '
 	>normal &&
 	attr_check_object_mode normal 100644 &&