threads / discuss / 370

[0/5] Updates for library, fsck-cache

Subject: [0/5] Updates for library, fsck-cache

## tl;dr

10 messages between Apr 28, 2005 and Apr 28, 2005.

replies: 9people: 2as markdown or json

Daniel Barkalow· Apr 28, 2005, 05:00 UTC · lore

This patch series updates the parser library for some new things, adds a function to parse an object of a type that's understood by the library but not known in advance by the program, updates fsck-cache to use it, and adds support for fsck-cache getting the root set out of .git/refs/.

 1: Consider a blob to be parsed
 2: Add tag header/parser to library
 3: Add function to parse an object of unspecified type.
 4: Rework fsck-cache to use parse_object().
 5: Make fsck-cache read heads out of .git/refs/*/*
	-Daniel
*This .sig left intentionally blank*
Daniel Barkalow· Apr 28, 2005, 05:04 UTC · re: Daniel Barkalow · lore

[1/5] Consider a blob to be parsed

We don't parse blobs at all, so any that we've got are as parsed as they're going to get. Don't make fsck-cache mark them.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: blob.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/blob.c  (mode:100644 sha1:3d99b93f020d84c5410c2b1056f2d7446b647d1e)
+++ 40a5a5657d67569bdc0e37b8ea2b76ec42824604/blob.c  (mode:100644 sha1:2fad8a5eb4c553190736870519f65c265dfb8526)
@@ -12,6 +12,7 @@
 		memset(ret, 0, sizeof(struct blob));
 		created_object(sha1, &ret->object);
 		ret->object.type = blob_type;
+		ret->object.parsed = 1;
 		return ret;
 	}
 	if (obj->parsed && obj->type != blob_type) {
Linus Torvalds· Apr 28, 2005, 05:28 UTC · re: Daniel Barkalow · lore

Re: [1/5] Consider a blob to be parsed

On Thu, 28 Apr 2005, Daniel Barkalow wrote:
>
> We don't parse blobs at all, so any that we've got are as parsed as
> they're going to get. Don't make fsck-cache mark them.
NO NO NO!

This is WRONG, dammit. I fixed it once, you are re-introducing the same bug.

Daniel, the problem is that you parse them only when you SEE them, and that is totally different from having seen a REFERENCE to them. One says "I've seen this object", the other says "I _want_ to see this object". They are two totally different things.

You now mark all "blob" objects parsed regardless of whether you have actually seen the blob or not. Ie you mark a blob parsed just from having seen a _reference_ to it, and fsck can never know whether it actually really saw the object or not.

This is the commit that already fixed this bug once, and that you are now re-introducing:

	commit 4728b861ace127dc39c648f3bea64c3b86bbabc5
	tree 242227fc3c3a74d070ed36496e790335dd00c44a
	parent da6abf5d9c342a74dffbcc2015b9c27d7819a900
	author Linus Torvalds <torvalds@ppc970.osdl.org> Sun, 24 Apr 2005 14:10:55 -0700
	committer Linus Torvalds <torvalds@ppc970.osdl.org> Sun, 24 Apr 2005 14:10:55 -0700
	
	    fsck-cache: notice missing "blob" objects.
	    
	    We should _not_ mark a blob object "parsed" just because we
	    looked it up: it gets marked that way only once we've actually
	    seen it. Otherwise we can never notice a missing blob.
please think about it.
Try to make some test-cases for fsck. They are quite easy to make: copy a 
good directory, and 
 - remove one commit (in the middle)
 - remove at least on tree
 - remove at least one blob
 - corrupt a file obviously (make it not uncompress ok)
 - corrupt a file in a subtle way (make it uncompress ok and have the
   right signature, but be the wrong type - for example, make a "commit" 
   object that points to a "tree" object that actually is a "blob")

And you'll see how this "consider a blob parsed" totally destroys fsck's ability to notice that the blob doesn't even _exist_ any more (case 3 above).

"parsing" and "looking up" are two totally independent operations. They are independent for commits and trees, and they are independent for blobs.

To mark a blob parsed, you _need_ to have actually looked it up and verified that it exists and that the object header is valid (and if you're fsck, that the sha1 matches). You MUST NOT do it in "lookup_blob()".

		Linus
Daniel Barkalow· Apr 28, 2005, 05:49 UTC · re: Linus Torvalds · lore

Re: [1/5] Consider a blob to be parsed

On Wed, 27 Apr 2005, Linus Torvalds wrote:
Show 11 quoted lines
> 
> 
> On Thu, 28 Apr 2005, Daniel Barkalow wrote:
> >
> > We don't parse blobs at all, so any that we've got are as parsed as
> > they're going to get. Don't make fsck-cache mark them.
> 
> NO NO NO!
> 
> This is WRONG, dammit. I fixed it once, you are re-introducing the same
> bug.
> Daniel, the problem is that you parse them only when you SEE them, and 
> that is totally different from having seen a REFERENCE to them. One says 
> "I've seen this object", the other says "I _want_ to see this object". 
> They are two totally different things.

Good point; the right fix is actually to have a parse_blob that checks to make sure it's there, and not have a special case for the simple case.

Replacement [1/5] to follow...
	-Daniel
*This .sig left intentionally blank*
Daniel Barkalow· Apr 28, 2005, 05:58 UTC · re: Daniel Barkalow · lore

[1'/5] Mark blobs as parsed when they're actually parsed

This eliminates the special case for blobs versus other types of objects. Now the scheme is entirely regular and I won't introduce stupid bugs. (And fsck-cache doesn't have to do the do-nothing parse)

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: blob.c
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/blob.c  (mode:100644 sha1:3d99b93f020d84c5410c2b1056f2d7446b647d1e)
+++ bcb43fecd82fa6f851e266b7e3873973068d51f3/blob.c  (mode:100644 sha1:d4af4a309433744d2fe819886d66741ab016f62b)
@@ -14,10 +14,28 @@
 		ret->object.type = blob_type;
 		return ret;
 	}
-	if (obj->parsed && obj->type != blob_type) {
+	if (obj->type != blob_type) {
 		error("Object %s is a %s, not a blob", 
 		      sha1_to_hex(sha1), obj->type);
 		return NULL;
 	}
 	return (struct blob *) obj;
 }
+
+int parse_blob(struct blob *item)
+{
+        char type[20];
+        void *buffer;
+        unsigned long size;
+        if (item->object.parsed)
+                return 0;
+        item->object.parsed = 1;
+        buffer = read_sha1_file(item->object.sha1, type, &size);
+        if (!buffer)
+                return error("Could not read %s",
+                             sha1_to_hex(item->object.sha1));
+        if (strcmp(type, blob_type))
+                return error("Object %s not a blob",
+                             sha1_to_hex(item->object.sha1));
+	return 0;
+}
Index: blob.h
===================================================================
--- 89fdfd09b281fdf5071bc13a30ef683bd6851b61/blob.h  (mode:100644 sha1:5cbf6d65ee88e1e0c0f1153af4aa7f80c3c48c16)
+++ bcb43fecd82fa6f851e266b7e3873973068d51f3/blob.h  (mode:100644 sha1:4afad0f067e1979d7ccc4778e254cce6962ad136)
@@ -11,4 +11,6 @@
 
 struct blob *lookup_blob(unsigned char *sha1);
 
+int parse_blob(struct blob *item);
+
 #endif /* BLOB_H */
Daniel Barkalow· Apr 28, 2005, 05:06 UTC · re: Daniel Barkalow · lore

[2/5] Add tag header/parser to library

This adds preliminary support for tags in the library. It doesn't even store the signature, however, let alone provide any way of checking it.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: Makefile
===================================================================
--- 40a5a5657d67569bdc0e37b8ea2b76ec42824604/Makefile  (mode:100644 sha1:2d2913b6b98ac836b43755b1304d2a838dad87dd)
+++ e08498de8d0216a24378c454597ecb38f65c4ee1/Makefile  (mode:100644 sha1:b533a2834da564f2fc8d00680aeac59c9d197bd8)
@@ -25,7 +25,7 @@
 install: $(PROG) $(SCRIPTS)
 	install $(PROG) $(SCRIPTS) $(HOME)/bin/
 
-LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o
+LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o tag.o
 LIB_FILE=libgit.a
 LIB_H=cache.h object.h
 
Index: tag.c
===================================================================
--- /dev/null  (tree:40a5a5657d67569bdc0e37b8ea2b76ec42824604)
+++ e08498de8d0216a24378c454597ecb38f65c4ee1/tag.c  (mode:100644 sha1:f079d83a9de5c3d6d98b2a29339ec1ef3a25f333)
@@ -0,0 +1,73 @@
+#include "tag.h"
+#include "cache.h"
+
+const char *tag_type = "tag";
+
+struct tag *lookup_tag(unsigned char *sha1)
+{
+        struct object *obj = lookup_object(sha1);
+        if (!obj) {
+                struct tag *ret = xmalloc(sizeof(struct tag));
+                memset(ret, 0, sizeof(struct tag));
+                created_object(sha1, &ret->object);
+                ret->object.type = tag_type;
+                return ret;
+        }
+        if (obj->type != tag_type) {
+                error("Object %s is a %s, not a tree", 
+                      sha1_to_hex(sha1), obj->type);
+                return NULL;
+        }
+        return (struct tag *) obj;
+}
+
+int parse_tag(struct tag *item)
+{
+        char type[20];
+        void *data, *bufptr;
+        unsigned long size;
+        if (item->object.parsed)
+                return 0;
+        item->object.parsed = 1;
+        data = bufptr = read_sha1_file(item->object.sha1, type, &size);
+        if (!data)
+                return error("Could not read %s",
+                             sha1_to_hex(item->object.sha1));
+        if (strcmp(type, tag_type))
+                return error("Object %s not a tag",
+                             sha1_to_hex(item->object.sha1));
+
+	int typelen, taglen;
+	unsigned char object[20];
+	const char *type_line, *tag_line, *sig_line;
+
+	if (size < 64)
+		return -1;
+	if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object))
+		return -1;
+
+	item->tagged = parse_object(object);
+
+	type_line = data + 48;
+	if (memcmp("\ntype ", type_line-1, 6))
+		return -1;
+
+	tag_line = strchr(type_line, '\n');
+	if (!tag_line || memcmp("tag ", ++tag_line, 4))
+		return -1;
+
+	sig_line = strchr(tag_line, '\n');
+	if (!sig_line)
+		return -1;
+	sig_line++;
+
+	typelen = tag_line - type_line - strlen("type \n");
+	if (typelen >= 20)
+		return -1;
+	taglen = sig_line - tag_line - strlen("tag \n");
+	item->tag = xmalloc(taglen + 1);
+	memcpy(item->tag, tag_line + 4, taglen);
+	item->tag[taglen] = '\0';
+
+	return 0;
+}
Index: tag.h
===================================================================
--- /dev/null  (tree:40a5a5657d67569bdc0e37b8ea2b76ec42824604)
+++ e08498de8d0216a24378c454597ecb38f65c4ee1/tag.h  (mode:100644 sha1:7ae7864d8a8477bfd22d4e29d78119d345f2bbb9)
@@ -0,0 +1,15 @@
+#ifndef TAG_H
+#define TAG_H
+
+#include "object.h"
+
+extern const char *tag_type;
+
+struct tag {
+	struct object object;
+	struct object *tagged;
+	char *tag;
+	char *signature; /* not actually implemented */
+};
+
+#endif /* TAG_H */
Daniel Barkalow· Apr 28, 2005, 05:11 UTC · re: Daniel Barkalow · lore

[3/5] Add function to parse an object of unspecified type

This adds a function that parses an object from the database when we have to look up its actual type. It also checks the hash of the file, due to its heritage as part of fsck-cache.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: object.c
===================================================================
--- e08498de8d0216a24378c454597ecb38f65c4ee1/object.c  (mode:100644 sha1:91bbc6e5e2eadfb0a66b14d992eac260d07267f8)
+++ dd06c679f8acb720976073de90a9eeabbc11e951/object.c  (mode:100644 sha1:787cda1f5667cdd4e92b7c18eb115cf125f6df9c)
@@ -1,5 +1,9 @@
 #include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
 #include "cache.h"
+#include "tag.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -94,3 +98,39 @@
 		p = p->next;
 	}
 }
+
+struct object *parse_object(unsigned char *sha1)
+{
+	unsigned long mapsize;
+	void *map = map_sha1_file(sha1, &mapsize);
+	if (map) {
+		char type[100];
+		unsigned long size;
+		void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+		if (!buffer)
+			return NULL;
+		if (check_sha1_signature(sha1, buffer, size, type) < 0)
+			printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
+		munmap(map, mapsize);
+		if (!strcmp(type, "blob")) {
+			struct blob *ret = lookup_blob(sha1);
+			//parse_blob(ret);
+			return &ret->object;
+		} else if (!strcmp(type, "tree")) {
+			struct tree *ret = lookup_tree(sha1);
+			parse_tree(ret);
+			return &ret->object;
+		} else if (!strcmp(type, "commit")) {
+			struct commit *ret = lookup_commit(sha1);
+			parse_commit(ret);
+			return &ret->object;
+		} else if (!strcmp(type, "tag")) {
+			struct tag *ret = lookup_tag(sha1);
+			parse_tag(ret);
+			return &ret->object;
+		} else {
+			return NULL;
+		}
+	}
+	return NULL;
+}
Index: object.h
===================================================================
--- e08498de8d0216a24378c454597ecb38f65c4ee1/object.h  (mode:100644 sha1:bc607fd55f6ce4e56ce87766369b5d4d55ec79af)
+++ dd06c679f8acb720976073de90a9eeabbc11e951/object.h  (mode:100644 sha1:d53a35a4d7321b5ec970103208ac576f9f722dff)
@@ -22,6 +22,9 @@
 
 void created_object(unsigned char *sha1, struct object *obj);
 
+/** Returns the object, having parsed it to find out what it is. **/
+struct object *parse_object(unsigned char *sha1);
+
 void add_ref(struct object *refer, struct object *target);
 
 void mark_reachable(struct object *obj, unsigned int mask);
Daniel Barkalow· Apr 28, 2005, 06:01 UTC · re: Daniel Barkalow · lore

[3'/5] Add function to parse an object of unspecified type (take 2)

This adds a function that parses an object from the database when we have to look up its actual type. It also checks the hash of the file, due to its heritage as part of fsck-cache.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: object.c
===================================================================
--- bcb43fecd82fa6f851e266b7e3873973068d51f3/object.c  (mode:100644 sha1:91bbc6e5e2eadfb0a66b14d992eac260d07267f8)
+++ 52505514b78c9bd77fcd701663c1967919d1cec3/object.c  (mode:100644 sha1:ca4af8fa2dc0672b92310a3ebdd4d14bf070dd69)
@@ -1,5 +1,9 @@
 #include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
 #include "cache.h"
+#include "tag.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -94,3 +98,39 @@
 		p = p->next;
 	}
 }
+
+struct object *parse_object(unsigned char *sha1)
+{
+	unsigned long mapsize;
+	void *map = map_sha1_file(sha1, &mapsize);
+	if (map) {
+		char type[100];
+		unsigned long size;
+		void *buffer = unpack_sha1_file(map, mapsize, type, &size);
+		if (!buffer)
+			return NULL;
+		if (check_sha1_signature(sha1, buffer, size, type) < 0)
+			printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
+		munmap(map, mapsize);
+		if (!strcmp(type, "blob")) {
+			struct blob *ret = lookup_blob(sha1);
+			parse_blob(ret);
+			return &ret->object;
+		} else if (!strcmp(type, "tree")) {
+			struct tree *ret = lookup_tree(sha1);
+			parse_tree(ret);
+			return &ret->object;
+		} else if (!strcmp(type, "commit")) {
+			struct commit *ret = lookup_commit(sha1);
+			parse_commit(ret);
+			return &ret->object;
+		} else if (!strcmp(type, "tag")) {
+			struct tag *ret = lookup_tag(sha1);
+			parse_tag(ret);
+			return &ret->object;
+		} else {
+			return NULL;
+		}
+	}
+	return NULL;
+}
Index: object.h
===================================================================
--- bcb43fecd82fa6f851e266b7e3873973068d51f3/object.h  (mode:100644 sha1:bc607fd55f6ce4e56ce87766369b5d4d55ec79af)
+++ 52505514b78c9bd77fcd701663c1967919d1cec3/object.h  (mode:100644 sha1:d53a35a4d7321b5ec970103208ac576f9f722dff)
@@ -22,6 +22,9 @@
 
 void created_object(unsigned char *sha1, struct object *obj);
 
+/** Returns the object, having parsed it to find out what it is. **/
+struct object *parse_object(unsigned char *sha1);
+
 void add_ref(struct object *refer, struct object *target);
 
 void mark_reachable(struct object *obj, unsigned int mask);
Daniel Barkalow· Apr 28, 2005, 05:13 UTC · re: Daniel Barkalow · lore

[4/5] Rework fsck-cache to use parse_object()

With support for parse_object() and tags in the core, fsck_cache can just call them, and can be simplified a bit.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: fsck-cache.c
===================================================================
--- dd06c679f8acb720976073de90a9eeabbc11e951/fsck-cache.c  (mode:100644 sha1:f9b1431dd8f4f3b426a7e410de952277aaa11401)
+++ ca8a271be1370ab0795a869c15114e566bdd15d8/fsck-cache.c  (mode:100644 sha1:280a104050b665515418c00c33af8e6b0b0e2101)
@@ -6,6 +6,7 @@
 #include "commit.h"
 #include "tree.h"
 #include "blob.h"
+#include "tag.h"
 
 #define REACHABLE 0x0001
 
@@ -21,6 +22,7 @@
 	/* Look up all the requirements, warn about missing objects.. */
 	for (i = 0; i < nr_objs; i++) {
 		struct object *obj = objs[i];
+		struct object_list *refs;
 
 		if (show_unreachable && !(obj->flags & REACHABLE)) {
 			printf("unreachable %s %s\n", obj->type, sha1_to_hex(obj->sha1));
@@ -35,101 +37,49 @@
 			printf("dangling %s %s\n", obj->type, 
 			       sha1_to_hex(obj->sha1));
 		}
+		for (refs = obj->refs; refs; refs = refs->next) {
+			if (!refs->item->parsed) {
+				printf("broken link from %s\n",
+				       sha1_to_hex(obj->sha1));
+				printf("              to %s\n",
+				       sha1_to_hex(refs->item->sha1));
+			}
+		}
 	}
 }
 
-static int fsck_tree(unsigned char *sha1, void *data, unsigned long size)
+static int fsck_tree(struct tree *item)
 {
-	struct tree *item = lookup_tree(sha1);
-	if (parse_tree(item))
-		return -1;
 	if (item->has_full_path) {
 		fprintf(stderr, "warning: fsck-cache: tree %s "
-			"has full pathnames in it\n", sha1_to_hex(sha1));
+			"has full pathnames in it\n", 
+			sha1_to_hex(item->object.sha1));
 	}
 	return 0;
 }
 
-static int fsck_commit(unsigned char *sha1, void *data, unsigned long size)
+static int fsck_commit(struct commit *commit)
 {
-	struct commit *commit = lookup_commit(sha1);
-	if (parse_commit(commit))
-		return -1;
 	if (!commit->tree)
 		return -1;
 	if (!commit->parents && show_root)
-		printf("root %s\n", sha1_to_hex(sha1));
+		printf("root %s\n", sha1_to_hex(commit->object.sha1));
 	if (!commit->date)
-		printf("bad commit date in %s\n", sha1_to_hex(sha1));
-	return 0;
-}
-
-static int fsck_blob(unsigned char *sha1, void *data, unsigned long size)
-{
-	struct blob *blob = lookup_blob(sha1);
-	blob->object.parsed = 1;
+		printf("bad commit date in %s\n", 
+		       sha1_to_hex(commit->object.sha1));
 	return 0;
 }
 
-static int fsck_tag(unsigned char *sha1, void *data, unsigned long size)
+static int fsck_tag(struct tag *tag)
 {
-	int typelen, taglen;
-	unsigned char object[20];
-	char object_hex[60];
-	const char *type_line, *tag_line, *sig_line;
-
-	if (size < 64)
-		return -1;
-	if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object))
-		return -1;
-
-	type_line = data + 48;
-	if (memcmp("\ntype ", type_line-1, 6))
-		return -1;
-
-	tag_line = strchr(type_line, '\n');
-	if (!tag_line || memcmp("tag ", ++tag_line, 4))
-		return -1;
-
-	sig_line = strchr(tag_line, '\n');
-	if (!sig_line)
-		return -1;
-	sig_line++;
-
-	typelen = tag_line - type_line - strlen("type \n");
-	if (typelen >= 20)
-		return -1;
-	taglen = sig_line - tag_line - strlen("tag \n");
-
 	if (!show_tags)
 		return 0;
 
-	strcpy(object_hex, sha1_to_hex(object));
-	printf("tagged %.*s %s (%.*s) in %s\n",
-		typelen, type_line + 5,
-		object_hex,
-		taglen, tag_line + 4,
-		sha1_to_hex(sha1));
-	return 0;
-}
-
-static int fsck_entry(unsigned char *sha1, char *tag, void *data, 
-		      unsigned long size)
-{
-	if (!strcmp(tag, "blob")) {
-		if (fsck_blob(sha1, data, size) < 0)
-			return -1;
-	} else if (!strcmp(tag, "tree")) {
-		if (fsck_tree(sha1, data, size) < 0)
-			return -1;
-	} else if (!strcmp(tag, "commit")) {
-		if (fsck_commit(sha1, data, size) < 0)
-			return -1;
-	} else if (!strcmp(tag, "tag")) {
-		if (fsck_tag(sha1, data, size) < 0)
-			return -1;
-	} else
-		return -1;
+	printf("tagged %s %s",
+	       tag->tagged->type,
+	       sha1_to_hex(tag->tagged->sha1));
+	printf(" (%s) in %s\n",
+	       tag->tag, sha1_to_hex(tag->object.sha1));
 	return 0;
 }
 
@@ -137,20 +87,17 @@
 {
 	unsigned char sha1[20];
 	if (!get_sha1_hex(hex, sha1)) {
-		unsigned long mapsize;
-		void *map = map_sha1_file(sha1, &mapsize);
-		if (map) {
-			char type[100];
-			unsigned long size;
-			void *buffer = unpack_sha1_file(map, mapsize, type, &size);
-			if (!buffer)
-				return -1;
-			if (check_sha1_signature(sha1, buffer, size, type) < 0)
-				printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
-			munmap(map, mapsize);
-			if (!fsck_entry(sha1, type, buffer, size))
-				return 0;
-		}
+		struct object *obj = parse_object(sha1);
+		if (!obj)
+			return -1;
+		if (obj->type == blob_type)
+			return 0;
+		if (obj->type == tree_type)
+			return fsck_tree((struct tree *) obj);
+		if (obj->type == commit_type)
+			return fsck_commit((struct commit *) obj);
+		if (obj->type == tag_type)
+			return fsck_tag((struct tag *) obj);
 	}
 	return -1;
 }
Daniel Barkalow· Apr 28, 2005, 05:17 UTC · re: Daniel Barkalow · lore

[5/5] Make fsck-cache read heads out of .git/refs/*/*

This makes fsck-cache expect the root set of the reachability graph (i.e., your heads and tags) to be .git/refs/*/*, which contain hex versions of hashs of roots (like .get/HEAD has always been).

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Index: fsck-cache.c
===================================================================
--- ca8a271be1370ab0795a869c15114e566bdd15d8/fsck-cache.c  (mode:100644 sha1:280a104050b665515418c00c33af8e6b0b0e2101)
+++ c53109e78c0b0d8925a4198fdec8295620f8f349/fsck-cache.c  (mode:100644 sha1:c4ff5bf3d71c35236e769d30035b00acf08d452b)
@@ -135,6 +135,67 @@
 	return 0;
 }
 
+int read_refs_dirs(char *path)
+{
+	DIR *dir = opendir(path);
+	char filename[NAME_MAX+1];
+	struct dirent *de;
+	int total = 0;
+	char *base;
+
+	if (!dir) {
+		error("missing refs directory '%s'", path);
+		return 0;
+	}
+	strcpy(filename, path);
+	base = filename + strlen(path);
+	*(base++) = '/';
+	while ((de = readdir(dir)) != NULL) {
+		DIR *subdir;
+		char *subbase;
+		if (de->d_name[0] == '.')
+			continue;
+		strcpy(base, de->d_name);
+		subbase = base + strlen(de->d_name);
+		subdir = opendir(filename);
+		if (!subdir) {
+			fprintf(stderr, "can't open subdir %s\n", filename);
+			continue;
+		}
+		*(subbase++) = '/';
+		while ((de = readdir(subdir)) != NULL) {
+			char hex[41];
+			char sha1[20];
+			int fd;
+			struct object *obj;
+			if (de->d_name[0] == '.')
+				continue;
+			strcpy(subbase, de->d_name);
+			fd = open(filename, O_RDONLY);
+			if (fd < 0) {
+				fprintf(stderr, "Couldn't open %s\n", filename);
+				continue;
+			}
+			if ((read(fd, hex, 41) < 41) ||
+			    (hex[40] != '\n') ||
+			    get_sha1_hex(hex, sha1)) {
+				fprintf(stderr, "Couldn't read a hash from %s\n",
+					filename);
+				continue;
+			}
+			obj = parse_object(sha1);
+			obj->used = 1;
+			mark_reachable(obj, REACHABLE);
+			
+			total++;
+		}
+		closedir(subdir);
+	}
+	closedir(dir);
+
+	return total;
+}
+
 int main(int argc, char **argv)
 {
 	int i, heads;
@@ -183,6 +244,8 @@
 		error("expected sha1, got %s", arg);
 	}
 
+	heads += read_refs_dirs(".git/refs");
+
 	if (!heads) {
 		if (show_unreachable) {
 			fprintf(stderr, "unable to do reachability without a head\n");

← back to recent threads