Subject: [PATCH 3/7] sha1_file: refuse to write commits referring to external objects

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Thu, 24 Jan 2013 15:42:16 +0700

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 sha1_file.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/sha1_file.c b/sha1_file.c
index af71122..5948dcb 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2615,12 +2615,46 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
 	return move_temp_to_file(tmp_file, filename);
 }
 
+static void check_sha1_file_for_external_source(const char *buf,
+						unsigned long len,
+						const char *type)
+{
+	struct object_info oi;
+	unsigned char sha1[20];
+
+	/*
+	 * It is assumed that the object is well formatted. Otherwise
+	 * die() is waiting..
+	 */
+	if (!strcmp(type, "commit")) {
+		const char *tail = buf + len;
+		if (get_sha1_hex(buf + 5, sha1) < 0 ||
+		    sha1_object_info_extended(sha1, &oi) != OBJ_TREE ||
+		    (oi.alt && oi.alt->external))
+			die("cannot create a commit with external tree %s",
+			    sha1_to_hex(sha1));
+		buf += 46; /* "tree " + "hex sha1" + "\n" */
+
+		while (buf + 48 < tail && !memcmp(buf, "parent ", 7)) {
+			if (get_sha1_hex(buf + 7, sha1) < 0 ||
+			    sha1_object_info_extended(sha1, &oi) != OBJ_COMMIT ||
+			    (oi.alt && oi.alt->external))
+				die("cannot create a commit with external parent %s",
+				    sha1_to_hex(sha1));
+			buf += 48; /* "parent " + hex sha1 + "\n" */
+		}
+	}
+}
+
 int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
 	unsigned char sha1[20];
 	char hdr[32];
 	int hdrlen;
 
+	if (object_database_contaminated)
+		check_sha1_file_for_external_source(buf, len, type);
+
 	/* Normally if we have it in the pack then we do not bother writing
 	 * it out into .git/objects/??/?{38} file.
 	 */
-- 
1.8.0.rc3.18.g0d9b108