commit: fix duplication regression in permission error output

Fix a regression in the error output emitted when .git/objects can't be written to. Before 9c4d6c0297b (cache-tree: Write updated cache-tree after commit, 2014-07-13) we'd emit only one "insufficient permission" error, now we'll do so again. The cause is rather straightforward, we've got WRITE_TREE_SILENT for the use-case of wanting to prepare an index silently, quieting any permission etc. error output. Then when we attempt to update to that (possibly broken) index we'll run into the same errors again. But with 9c4d6c0297b the gap between the cache-tree API and the object store wasn't closed in terms of asking write_object_file() to be silent. I.e. post-9c4d6c0297b the first call is to prepare_index(), and after that we'll call prepare_to_commit(). We only want verbose error output from the latter. So let's add and use that facility with a corresponding HASH_SILENT flag, its only user is cache-tree.c's update_one(), which will set it if its "WRITE_TREE_SILENT" flag is set. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ævar Arnfjörð Bjarmason committed Oct 12, 2021 at 16:30 UTC 4ef91a2d795c424eda2bec1bfbbd0c813bcc978a
5 files changed +25 -13
cache-tree.c
+3 -2
@@ -440,8 +440,9 @@ static int update_one(struct cache_tree *it,
440 } else if (dryrun) {
441 hash_object_file(the_hash_algo, buffer.buf, buffer.len,
442 tree_type, &it->oid);
443 - } else if (write_object_file(buffer.buf, buffer.len, tree_type,
444 - &it->oid)) {
443 + } else if (write_object_file_flags(buffer.buf, buffer.len, tree_type,
444 + &it->oid, flags & WRITE_TREE_SILENT
445 + ? HASH_SILENT : 0)) {
446 strbuf_release(&buffer);
447 return -1;
448 }
cache.h
+1
@@ -887,6 +887,7 @@ int ie_modified(struct index_state *, const struct cache_entry *, struct stat *,
887 #define HASH_WRITE_OBJECT 1
888 #define HASH_FORMAT_CHECK 2
889 #define HASH_RENORMALIZE 4
890 +#define HASH_SILENT 8
891 int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
892 int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
893
object-file.c
+12 -8
@@ -1915,7 +1915,7 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
1915
1916 static int write_loose_object(const struct object_id *oid, char *hdr,
1917 int hdrlen, const void *buf, unsigned long len,
1918 - time_t mtime)
1918 + time_t mtime, unsigned flags)
1919 {
1920 int fd, ret;
1921 unsigned char compressed[4096];
@@ -1929,7 +1929,9 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
1929
1930 fd = create_tmpfile(&tmp_file, filename.buf);
1931 if (fd < 0) {
1932 - if (errno == EACCES)
1932 + if (flags & HASH_SILENT)
1933 + return -1;
1934 + else if (errno == EACCES)
1935 return error(_("insufficient permission for adding an object to repository database %s"), get_object_directory());
1936 else
1937 return error_errno(_("unable to create temporary file"));
@@ -1979,7 +1981,8 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
1981 struct utimbuf utb;
1982 utb.actime = mtime;
1983 utb.modtime = mtime;
1982 - if (utime(tmp_file.buf, &utb) < 0)
1984 + if (utime(tmp_file.buf, &utb) < 0 &&
1985 + !(flags & HASH_SILENT))
1986 warning_errno(_("failed utime() on %s"), tmp_file.buf);
1987 }
1988
@@ -2004,8 +2007,9 @@ static int freshen_packed_object(const struct object_id *oid)
2007 return 1;
2008 }
2009
2007 -int write_object_file(const void *buf, unsigned long len, const char *type,
2008 - struct object_id *oid)
2010 +int write_object_file_flags(const void *buf, unsigned long len,
2011 + const char *type, struct object_id *oid,
2012 + unsigned flags)
2013 {
2014 char hdr[MAX_HEADER_LEN];
2015 int hdrlen = sizeof(hdr);
@@ -2017,7 +2021,7 @@ int write_object_file(const void *buf, unsigned long len, const char *type,
2021 &hdrlen);
2022 if (freshen_packed_object(oid) || freshen_loose_object(oid))
2023 return 0;
2020 - return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
2024 + return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
2025 }
2026
2027 int hash_object_file_literally(const void *buf, unsigned long len,
@@ -2037,7 +2041,7 @@ int hash_object_file_literally(const void *buf, unsigned long len,
2041 goto cleanup;
2042 if (freshen_packed_object(oid) || freshen_loose_object(oid))
2043 goto cleanup;
2040 - status = write_loose_object(oid, header, hdrlen, buf, len, 0);
2044 + status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
2045
2046 cleanup:
2047 free(header);
@@ -2059,7 +2063,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
2063 if (!buf)
2064 return error(_("cannot read object for %s"), oid_to_hex(oid));
2065 hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
2062 - ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
2066 + ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
2067 free(buf);
2068
2069 return ret;
object-store.h
+8 -2
@@ -222,8 +222,14 @@ int hash_object_file(const struct git_hash_algo *algo, const void *buf,
222 unsigned long len, const char *type,
223 struct object_id *oid);
224
225 -int write_object_file(const void *buf, unsigned long len,
226 - const char *type, struct object_id *oid);
225 +int write_object_file_flags(const void *buf, unsigned long len,
226 + const char *type, struct object_id *oid,
227 + unsigned flags);
228 +static inline int write_object_file(const void *buf, unsigned long len,
229 + const char *type, struct object_id *oid)
230 +{
231 + return write_object_file_flags(buf, len, type, oid, 0);
232 +}
233
234 int hash_object_file_literally(const void *buf, unsigned long len,
235 const char *type, struct object_id *oid,
t/t0004-unwritable.sh
+1 -1
@@ -37,7 +37,7 @@ test_expect_success POSIXPERM,SANITY 'commit should notice unwritable repository
37 '
38
39 test_lazy_prereq COMMIT_OUT 'test -e "$TRASH_DIRECTORY"/out.commit'
40 -test_expect_failure COMMIT_OUT 'commit output on unwritable repository' '
40 +test_expect_success COMMIT_OUT 'commit output on unwritable repository' '
41 cat >expect <<-\EOF &&
42 error: insufficient permission for adding an object to repository database .git/objects
43 error: Error building trees