diff mbox series

[v2,07/10] hash-object: pass along type length to object.c

Message ID patch-07.10-a5ac9f1dd8-20210420T125416Z-avarab@gmail.com (mailing list archive)
State New, archived
Headers show
Series {tag,object}*.c: refactorings + prep for a larger change | expand

Commit Message

Ævar Arnfjörð Bjarmason April 20, 2021, 1 p.m. UTC
Change the functions to do with passing the type down to
hash_object_file_literally() to pass the length of the type as well as
the "const char *" type name.

The immediate motivation for this is to move hash-object.c over to
type_from_string_gently() to emit a better error message, but it will
also allow us in the future to craft an invalid object with a "\0" in
the type name.

We'd need to learn a --type-file=* option or similar (we can't of
course, pass a string with "\0" on the command-line). Right now such
an object can be manually crafted, but we can't test for it with
--literally.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/hash-object.c | 31 +++++++++++++++++--------------
 object-file.c         | 26 +++++++++++++++-----------
 object-store.h        |  4 ++--
 3 files changed, 34 insertions(+), 27 deletions(-)
diff mbox series

Patch

diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 640ef4ded5..4d3b8c49d2 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -25,14 +25,14 @@  static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
 	if (strbuf_read(&buf, fd, 4096) < 0)
 		ret = -1;
 	else
-		ret = hash_object_file_literally(buf.buf, buf.len, type, oid,
-						 flags);
+		ret = hash_object_file_literally(buf.buf, buf.len, type,
+						 strlen(type), oid, flags);
 	strbuf_release(&buf);
 	return ret;
 }
 
-static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
-		    int literally)
+static void hash_fd(int fd, const char *type, size_t type_len,
+		    const char *path, unsigned flags, int literally)
 {
 	struct stat st;
 	struct object_id oid;
@@ -49,31 +49,32 @@  static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
 	maybe_flush_or_die(stdout, "hash to stdout");
 }
 
-static void hash_object(const char *path, const char *type, const char *vpath,
-			unsigned flags, int literally)
+static void hash_object(const char *path, const char *type, size_t type_len,
+			const char *vpath, unsigned flags, int literally)
 {
 	int fd;
 	fd = open(path, O_RDONLY);
 	if (fd < 0)
 		die_errno("Cannot open '%s'", path);
-	hash_fd(fd, type, vpath, flags, literally);
+	hash_fd(fd, type, type_len, vpath, flags, literally);
 }
 
-static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
-			     int literally)
+static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,
+			     unsigned flags, int literally)
 {
 	struct strbuf buf = STRBUF_INIT;
 	struct strbuf unquoted = STRBUF_INIT;
 
 	while (strbuf_getline(&buf, stdin) != EOF) {
+		const char *vpath;
 		if (buf.buf[0] == '"') {
 			strbuf_reset(&unquoted);
 			if (unquote_c_style(&unquoted, buf.buf, NULL))
 				die("line is badly quoted");
 			strbuf_swap(&buf, &unquoted);
 		}
-		hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,
-			    literally);
+		vpath = no_filters ? NULL : buf.buf;
+		hash_object(buf.buf, type, type_len, vpath , flags, literally);
 	}
 	strbuf_release(&buf);
 	strbuf_release(&unquoted);
@@ -87,6 +88,7 @@  int cmd_hash_object(int argc, const char **argv, const char *prefix)
 		NULL
 	};
 	const char *type = blob_type;
+	size_t type_len;
 	int hashstdin = 0;
 	int stdin_paths = 0;
 	int no_filters = 0;
@@ -141,8 +143,9 @@  int cmd_hash_object(int argc, const char **argv, const char *prefix)
 		usage_with_options(hash_object_usage, hash_object_options);
 	}
 
+	type_len = strlen(type);
 	if (hashstdin)
-		hash_fd(0, type, vpath, flags, literally);
+		hash_fd(0, type, type_len, vpath, flags, literally);
 
 	for (i = 0 ; i < argc; i++) {
 		const char *arg = argv[i];
@@ -150,13 +153,13 @@  int cmd_hash_object(int argc, const char **argv, const char *prefix)
 
 		if (prefix)
 			arg = to_free = prefix_filename(prefix, arg);
-		hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
+		hash_object(arg, type, type_len, no_filters ? NULL : vpath ? vpath : arg,
 			    flags, literally);
 		free(to_free);
 	}
 
 	if (stdin_paths)
-		hash_stdin_paths(type, no_filters, flags, literally);
+		hash_stdin_paths(type, type_len, no_filters, flags, literally);
 
 	return 0;
 }
diff --git a/object-file.c b/object-file.c
index 398f2b60f9..b27ed57e0b 100644
--- a/object-file.c
+++ b/object-file.c
@@ -1715,13 +1715,15 @@  void *read_object_with_reference(struct repository *r,
 
 static void write_object_file_prepare(const struct git_hash_algo *algo,
 				      const void *buf, unsigned long len,
-				      const char *type, struct object_id *oid,
-				      char *hdr, int *hdrlen)
+				      const char *type, size_t type_len,
+				      struct object_id *oid, char *hdr,
+				      int *hdrlen)
 {
 	git_hash_ctx c;
 
 	/* Generate the header */
-	*hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1;
+	*hdrlen = xsnprintf(hdr, *hdrlen, "%.*s %"PRIuMAX,
+			    (int)type_len, type, (uintmax_t)len) + 1;
 
 	/* Sha1.. */
 	algo->init_fn(&c);
@@ -1786,7 +1788,8 @@  int hash_object_file(const struct git_hash_algo *algo, const void *buf,
 {
 	char hdr[MAX_HEADER_LEN];
 	int hdrlen = sizeof(hdr);
-	write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
+	write_object_file_prepare(algo, buf, len, type, strlen(type), oid, hdr,
+				  &hdrlen);
 	return 0;
 }
 
@@ -1940,29 +1943,30 @@  int write_object_file(const void *buf, unsigned long len, const char *type,
 {
 	char hdr[MAX_HEADER_LEN];
 	int hdrlen = sizeof(hdr);
+	size_t type_len = strlen(type);
 
 	/* Normally if we have it in the pack then we do not bother writing
 	 * it out into .git/objects/??/?{38} file.
 	 */
-	write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,
-				  &hdrlen);
+	write_object_file_prepare(the_hash_algo, buf, len, type, type_len, oid,
+				  hdr, &hdrlen);
 	if (freshen_packed_object(oid) || freshen_loose_object(oid))
 		return 0;
 	return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
 }
 
 int hash_object_file_literally(const void *buf, unsigned long len,
-			       const char *type, struct object_id *oid,
-			       unsigned flags)
+			       const char *type, size_t type_len,
+			       struct object_id *oid, unsigned flags)
 {
 	char *header;
 	int hdrlen, status = 0;
 
 	/* type string, SP, %lu of the length plus NUL must fit this */
-	hdrlen = strlen(type) + MAX_HEADER_LEN;
+	hdrlen = type_len + MAX_HEADER_LEN;
 	header = xmalloc(hdrlen);
-	write_object_file_prepare(the_hash_algo, buf, len, type, oid, header,
-				  &hdrlen);
+	write_object_file_prepare(the_hash_algo, buf, len, type, type_len, oid,
+				  header, &hdrlen);
 
 	if (!(flags & HASH_WRITE_OBJECT))
 		goto cleanup;
diff --git a/object-store.h b/object-store.h
index eab9674d08..8f043a6069 100644
--- a/object-store.h
+++ b/object-store.h
@@ -220,8 +220,8 @@  int write_object_file(const void *buf, unsigned long len,
 		      const char *type, struct object_id *oid);
 
 int hash_object_file_literally(const void *buf, unsigned long len,
-			       const char *type, struct object_id *oid,
-			       unsigned flags);
+			       const char *type, size_t type_len,
+			       struct object_id *oid, unsigned flags);
 
 /*
  * Add an object file to the in-memory object store, without writing it