summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 91d7b8a)
raw | patch | inline | side by side (parent: 91d7b8a)
author | Nicolas Pitre <nico@cam.org> | |
Fri, 20 May 2005 20:59:17 +0000 (16:59 -0400) | ||
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | |
Fri, 20 May 2005 22:41:45 +0000 (15:41 -0700) |
This adds knowledge of delta objects to fsck-cache and various object
parsing code. A new switch to git-fsck-cache is provided to display the
maximum delta depth found in a repository.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
parsing code. A new switch to git-fsck-cache is provided to display the
maximum delta depth found in a repository.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Makefile | patch | blob | history | |
blob.c | patch | blob | history | |
commit.c | patch | blob | history | |
delta.c | [new file with mode: 0644] | patch | blob |
delta.h | patch | blob | history | |
fsck-cache.c | patch | blob | history | |
object.c | patch | blob | history | |
object.h | patch | blob | history | |
tag.c | patch | blob | history | |
tree.c | patch | blob | history |
diff --git a/Makefile b/Makefile
index 5211edc4ba0999b87ce1aa899683bd495fe345dd..fc69a409aea200e5b4e1ddd6fe61821220a57955 100644 (file)
--- a/Makefile
+++ b/Makefile
$(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bin)
LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
- tag.o date.o index.o diff-delta.o patch-delta.o
+ tag.o delta.o date.o index.o diff-delta.o patch-delta.o
LIB_FILE=libgit.a
LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h
index 280f5241577ac029e9d5a7eb5bf895642b342fc8..c800cd3905e2a4e97098064a588e15c0ae33a0b0 100644 (file)
--- a/blob.c
+++ b/blob.c
ret->object.type = blob_type;
return ret;
}
+ if (!obj->type)
+ obj->type = blob_type;
if (obj->type != blob_type) {
error("Object %s is a %s, not a blob",
sha1_to_hex(sha1), obj->type);
diff --git a/commit.c b/commit.c
index e83056406f54495fe8a1090a816c425375858d4d..3f2235ecf87b63bc5d16342ebcf7f8faf098530a 100644 (file)
--- a/commit.c
+++ b/commit.c
ret->object.type = commit_type;
return ret;
}
+ if (!obj->type)
+ obj->type = commit_type;
return check_commit(obj, sha1);
}
diff --git a/delta.c b/delta.c
--- /dev/null
+++ b/delta.c
@@ -0,0 +1,115 @@
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "tag.h"
+#include "delta.h"
+#include "cache.h"
+#include <string.h>
+
+/* the delta object definition (it can alias any other object) */
+struct delta {
+ union {
+ struct object object;
+ struct blob blob;
+ struct tree tree;
+ struct commit commit;
+ struct tag tag;
+ } u;
+};
+
+struct delta *lookup_delta(unsigned char *sha1)
+{
+ struct object *obj = lookup_object(sha1);
+ if (!obj) {
+ struct delta *ret = xmalloc(sizeof(struct delta));
+ memset(ret, 0, sizeof(struct delta));
+ created_object(sha1, &ret->u.object);
+ return ret;
+ }
+ return (struct delta *) obj;
+}
+
+int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size)
+{
+ struct object *reference;
+ struct object_list *p;
+
+ if (item->u.object.delta)
+ return 0;
+ item->u.object.delta = 1;
+ if (size <= 20)
+ return -1;
+ reference = lookup_object(buffer);
+ if (!reference) {
+ struct delta *ref = xmalloc(sizeof(struct delta));
+ memset(ref, 0, sizeof(struct delta));
+ created_object(buffer, &ref->u.object);
+ reference = &ref->u.object;
+ }
+
+ p = xmalloc(sizeof(*p));
+ p->item = &item->u.object;
+ p->next = reference->attached_deltas;
+ reference->attached_deltas = p;
+ return 0;
+}
+
+int process_deltas(void *src, unsigned long src_size, const char *src_type,
+ struct object_list *delta_list)
+{
+ int deepest = 0;
+ do {
+ struct object *obj = delta_list->item;
+ static char type[10];
+ void *map, *delta, *buf;
+ unsigned long map_size, delta_size, buf_size;
+ map = map_sha1_file(obj->sha1, &map_size);
+ if (!map)
+ continue;
+ delta = unpack_sha1_file(map, map_size, type, &delta_size);
+ munmap(map, map_size);
+ if (!delta)
+ continue;
+ if (strcmp(type, "delta") || delta_size <= 20) {
+ free(delta);
+ continue;
+ }
+ buf = patch_delta(src, src_size,
+ delta+20, delta_size-20,
+ &buf_size);
+ free(delta);
+ if (!buf)
+ continue;
+ if (check_sha1_signature(obj->sha1, buf, buf_size, src_type) < 0)
+ printf("sha1 mismatch for delta %s\n", sha1_to_hex(obj->sha1));
+ if (obj->type && obj->type != src_type) {
+ error("got %s when expecting %s for delta %s",
+ src_type, obj->type, sha1_to_hex(obj->sha1));
+ free(buf);
+ continue;
+ }
+ obj->type = src_type;
+ if (src_type == blob_type) {
+ parse_blob_buffer((struct blob *)obj, buf, buf_size);
+ } else if (src_type == tree_type) {
+ parse_tree_buffer((struct tree *)obj, buf, buf_size);
+ } else if (src_type == commit_type) {
+ parse_commit_buffer((struct commit *)obj, buf, buf_size);
+ } else if (src_type == tag_type) {
+ parse_tag_buffer((struct tag *)obj, buf, buf_size);
+ } else {
+ error("unknown object type %s", src_type);
+ free(buf);
+ continue;
+ }
+ if (obj->attached_deltas) {
+ int depth = process_deltas(buf, buf_size, src_type,
+ obj->attached_deltas);
+ if (deepest < depth)
+ deepest = depth;
+ }
+ free(buf);
+ } while ((delta_list = delta_list->next));
+ return deepest + 1;
+}
index e073dff831ab5062638ddc33e32a7c7aae807c39..8e4efdf4acb568a4bd439884911d0ee947bd7f92 100644 (file)
--- a/delta.h
+++ b/delta.h
+#ifndef DELTA_H
+#define DELTA_H
+
+/* handling of delta buffers */
extern void *diff_delta(void *from_buf, unsigned long from_size,
void *to_buf, unsigned long to_size,
unsigned long *delta_size);
extern void *patch_delta(void *src_buf, unsigned long src_size,
void *delta_buf, unsigned long delta_size,
unsigned long *dst_size);
+
+/* handling of delta objects */
+struct delta;
+struct object_list;
+extern struct delta *lookup_delta(unsigned char *sha1);
+extern int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size);
+extern int parse_delta(struct delta *item, unsigned char sha1);
+extern int process_deltas(void *src, unsigned long src_size,
+ const char *src_type, struct object_list *delta);
+
+#endif
diff --git a/fsck-cache.c b/fsck-cache.c
index 6c65f2bb2262f378e17fc75600a32abeaf4e1ed6..6ac122b71cf9a5eec298a003032c5724d47f306d 100644 (file)
--- a/fsck-cache.c
+++ b/fsck-cache.c
#include "tree.h"
#include "blob.h"
#include "tag.h"
+#include "delta.h"
#define REACHABLE 0x0001
static int show_root = 0;
static int show_tags = 0;
static int show_unreachable = 0;
+static int show_max_delta_depth = 0;
static int keep_cache_objects = 0;
static unsigned char head_sha1[20];
+static void expand_deltas(void)
+{
+ int i, max_depth = 0;
+
+ /*
+ * To be as efficient as possible we look for delta heads and
+ * recursively process them going backward, and parsing
+ * resulting objects along the way. This allows for processing
+ * each delta objects only once regardless of the delta depth.
+ */
+ for (i = 0; i < nr_objs; i++) {
+ struct object *obj = objs[i];
+ if (obj->parsed && !obj->delta && obj->attached_deltas) {
+ int depth = 0;
+ char type[10];
+ unsigned long size;
+ void *buf = read_sha1_file(obj->sha1, type, &size);
+ if (!buf)
+ continue;
+ depth = process_deltas(buf, size, obj->type,
+ obj->attached_deltas);
+ if (max_depth < depth)
+ max_depth = depth;
+ }
+ }
+ if (show_max_delta_depth)
+ printf("maximum delta depth = %d\n", max_depth);
+}
+
static void check_connectivity(void)
{
int i;
struct object_list *refs;
if (!obj->parsed) {
- printf("missing %s %s\n", obj->type, sha1_to_hex(obj->sha1));
+ if (obj->delta)
+ printf("unresolved delta %s\n",
+ sha1_to_hex(obj->sha1));
+ else
+ printf("missing %s %s\n",
+ obj->type, sha1_to_hex(obj->sha1));
continue;
}
continue;
if (show_unreachable && !(obj->flags & REACHABLE)) {
- printf("unreachable %s %s\n", obj->type, sha1_to_hex(obj->sha1));
+ if (obj->attached_deltas)
+ printf("foreign delta reference %s\n",
+ sha1_to_hex(obj->sha1));
+ else
+ printf("unreachable %s %s\n",
+ obj->type, sha1_to_hex(obj->sha1));
continue;
}
return fsck_commit((struct commit *) obj);
if (obj->type == tag_type)
return fsck_tag((struct tag *) obj);
+ if (!obj->type && obj->delta)
+ return 0;
return -1;
}
show_root = 1;
continue;
}
+ if (!strcmp(arg, "--delta-depth")) {
+ show_max_delta_depth = 1;
+ continue;
+ }
if (!strcmp(arg, "--cache")) {
keep_cache_objects = 1;
continue;
}
fsck_sha1_list();
+ expand_deltas();
+
heads = 0;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
}
/*
- * If we've not been gived any explicit head information, do the
+ * If we've not been given any explicit head information, do the
* default ones from .git/refs. We also consider the index file
* in this case (ie this implies --cache).
*/
diff --git a/object.c b/object.c
index b5a62e7f87f24c2ab0ea83f3c445d81bcbff027a..deb683076d7e1a91e913398ff905085230014a4f 100644 (file)
--- a/object.c
+++ b/object.c
#include "commit.h"
#include "cache.h"
#include "tag.h"
+#include "delta.h"
#include <stdlib.h>
#include <string.h>
unsigned long mapsize;
void *map = map_sha1_file(sha1, &mapsize);
if (map) {
+ int is_delta;
struct object *obj;
char type[100];
unsigned long size;
munmap(map, mapsize);
if (!buffer)
return NULL;
- if (check_sha1_signature(sha1, buffer, size, type) < 0)
+ is_delta = !strcmp(type, "delta");
+ if (!is_delta && check_sha1_signature(sha1, buffer, size, type) < 0)
printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
- if (!strcmp(type, "blob")) {
+ if (is_delta) {
+ struct delta *delta = lookup_delta(sha1);
+ parse_delta_buffer(delta, buffer, size);
+ obj = (struct object *) delta;
+ } else if (!strcmp(type, "blob")) {
struct blob *blob = lookup_blob(sha1);
parse_blob_buffer(blob, buffer, size);
obj = &blob->object;
diff --git a/object.h b/object.h
index 09700d376077b2d6136620faf6efb77ee679deeb..464bb0a292c11515ecb074de37daa7fa5536d8e5 100644 (file)
--- a/object.h
+++ b/object.h
struct object {
unsigned parsed : 1;
unsigned used : 1;
+ unsigned delta : 1;
unsigned int flags;
unsigned char sha1[20];
const char *type;
struct object_list *refs;
+ struct object_list *attached_deltas;
};
extern int nr_objs;
index 22deb243ad58b2c57fb8652fe2d08c571ee3e781..26494ca9695fdd2e81952378f64bbc361698117d 100644 (file)
--- a/tag.c
+++ b/tag.c
ret->object.type = tag_type;
return ret;
}
+ if (!obj->type)
+ obj->type = tag_type;
if (obj->type != tag_type) {
error("Object %s is a %s, not a tree",
sha1_to_hex(sha1), obj->type);
index ca800a85f771be1bd10d6575d93ca05bd3fc381c..d448daeab172a2a8b1a1c0624319f3f0096d40c0 100644 (file)
--- a/tree.c
+++ b/tree.c
ret->object.type = tree_type;
return ret;
}
+ if (!obj->type)
+ obj->type = tree_type;
if (obj->type != tree_type) {
error("Object %s is a %s, not a tree",
sha1_to_hex(sha1), obj->type);