From d98b46f8d9a3daf965a39f8c0089c1401e0081ee Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 20 Apr 2005 01:10:46 -0700 Subject: Do SHA1 hash _before_ compression. And add a "convert-cache" program to convert from old-style to new-style. diff --git a/Makefile b/Makefile index 0d07b9a..cd299f8 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ AR=ar PROG= update-cache show-diff init-db write-tree read-tree commit-tree \ cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \ check-files ls-tree merge-base merge-cache unpack-file git-export \ - diff-cache + diff-cache convert-cache all: $(PROG) @@ -88,12 +88,16 @@ git-export: git-export.o $(LIB_FILE) diff-cache: diff-cache.o $(LIB_FILE) $(CC) $(CFLAGS) -o diff-cache diff-cache.o $(LIBS) +convert-cache: convert-cache.o $(LIB_FILE) + $(CC) $(CFLAGS) -o convert-cache convert-cache.o $(LIBS) + blob.o: $(LIB_H) cat-file.o: $(LIB_H) check-files.o: $(LIB_H) checkout-cache.o: $(LIB_H) commit.o: $(LIB_H) commit-tree.o: $(LIB_H) +convert-cache.o: $(LIB_H) diff-cache.o: $(LIB_H) diff-tree.o: $(LIB_H) fsck-cache.o: $(LIB_H) diff --git a/cache.h b/cache.h index efeb82b..dd91a71 100644 --- a/cache.h +++ b/cache.h @@ -112,7 +112,7 @@ extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size); extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size); extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size); extern int write_sha1_file(char *buf, unsigned len, unsigned char *return_sha1); -extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size); +extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type); /* Convert to/from hex/sha1 representation */ extern int get_sha1_hex(const char *hex, unsigned char *sha1); diff --git a/convert-cache.c b/convert-cache.c new file mode 100644 index 0000000..97e9952 --- /dev/null +++ b/convert-cache.c @@ -0,0 +1,138 @@ +#include "cache.h" + +struct entry { + unsigned char old_sha1[20]; + unsigned char new_sha1[20]; + int converted; +}; + +#define MAXOBJECTS (1000000) + +static struct entry *convert[MAXOBJECTS]; +static int nr_convert; + +static struct entry * convert_entry(unsigned char *sha1); + +static struct entry *insert_new(unsigned char *sha1, int pos) +{ + struct entry *new = malloc(sizeof(struct entry)); + + memset(new, 0, sizeof(*new)); + memcpy(new->old_sha1, sha1, 20); + memmove(convert + pos + 1, convert + pos, (nr_convert - pos) * sizeof(struct entry *)); + convert[pos] = new; + nr_convert++; + if (nr_convert == MAXOBJECTS) + die("you're kidding me - hit maximum object limit"); + return new; +} + +static struct entry *lookup_entry(unsigned char *sha1) +{ + int low = 0, high = nr_convert; + + while (low < high) { + int next = (low + high) / 2; + struct entry *n = convert[next]; + int cmp = memcmp(sha1, n->old_sha1, 20); + if (!cmp) + return n; + if (cmp < 0) { + high = next; + continue; + } + low = next+1; + } + return insert_new(sha1, low); +} + +static void convert_blob(void *buffer, unsigned long size) +{ + /* Nothing to do */ +} + +static void convert_binary_sha1(void *buffer) +{ + struct entry *entry = convert_entry(buffer); + memcpy(buffer, entry->new_sha1, 20); +} + +static void convert_ascii_sha1(void *buffer) +{ + unsigned char sha1[20]; + struct entry *entry; + + if (get_sha1_hex(buffer, sha1)) + die("bad sha1"); + entry = convert_entry(sha1); + memcpy(buffer, sha1_to_hex(entry->new_sha1), 40); +} + +static void convert_tree(void *buffer, unsigned long size) +{ + while (size) { + int len = 1+strlen(buffer); + + convert_binary_sha1(buffer + len); + + len += 20; + if (len > size) + die("corrupt tree object"); + size -= len; + buffer += len; + } +} + +static void convert_commit(void *buffer, unsigned long size) +{ + convert_ascii_sha1(buffer+5); + buffer += 46; /* "tree " + "hex sha1" + "\n" */ + while (!memcmp(buffer, "parent ", 7)) { + convert_ascii_sha1(buffer+7); + buffer += 48; + } +} + +static struct entry * convert_entry(unsigned char *sha1) +{ + struct entry *entry = lookup_entry(sha1); + char type[20]; + void *buffer, *data; + unsigned long size, offset; + + if (entry->converted) + return entry; + data = read_sha1_file(sha1, type, &size); + if (!data) + die("unable to read object %s", sha1_to_hex(sha1)); + + buffer = malloc(size + 100); + offset = sprintf(buffer, "%s %lu", type, size)+1; + memcpy(buffer + offset, data, size); + + if (!strcmp(type, "blob")) + convert_blob(buffer + offset, size); + else if (!strcmp(type, "tree")) + convert_tree(buffer + offset, size); + else if (!strcmp(type, "commit")) + convert_commit(buffer + offset, size); + else + die("unknown object type '%s' in %s", type, sha1_to_hex(sha1)); + write_sha1_file(buffer, size + offset, entry->new_sha1); + entry->converted = 1; + free(buffer); + return entry; +} + +int main(int argc, char **argv) +{ + unsigned char sha1[20]; + struct entry *entry; + + if (argc != 2 || get_sha1_hex(argv[1], sha1)) + usage("convert-cache "); + + entry = convert_entry(sha1); + printf("new sha1: %s\n", sha1_to_hex(entry->new_sha1)); + return 0; +} diff --git a/fsck-cache.c b/fsck-cache.c index 952d413..96b8eb1 100644 --- a/fsck-cache.c +++ b/fsck-cache.c @@ -85,12 +85,13 @@ static int fsck_name(char *hex) if (map) { char type[100]; unsigned long size; - void *buffer = NULL; - if (!check_sha1_signature(sha1, map, mapsize)) - buffer = unpack_sha1_file(map, mapsize, type, - &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 (buffer && !fsck_entry(sha1, type, buffer, size)) + if (!fsck_entry(sha1, type, buffer, size)) return 0; } } diff --git a/sha1_file.c b/sha1_file.c index bb44a01..40c00b7 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -80,12 +80,14 @@ char *sha1_file_name(const unsigned char *sha1) return base; } -int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size) +int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type) { + char header[100]; unsigned char real_sha1[20]; SHA_CTX c; SHA1_Init(&c); + SHA1_Update(&c, header, 1+sprintf(header, "%s %lu", type, size)); SHA1_Update(&c, map, size); SHA1_Final(real_sha1, &c); return memcmp(sha1, real_sha1, 20) ? -1 : 0; @@ -172,6 +174,11 @@ int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1) unsigned char sha1[20]; SHA_CTX c; + /* Sha1.. */ + SHA1_Init(&c); + SHA1_Update(&c, buf, len); + SHA1_Final(sha1, &c); + /* Set it up */ memset(&stream, 0, sizeof(stream)); deflateInit(&stream, Z_BEST_COMPRESSION); @@ -188,11 +195,6 @@ int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1) deflateEnd(&stream); size = stream.total_out; - /* Sha1.. */ - SHA1_Init(&c); - SHA1_Update(&c, compressed, size); - SHA1_Final(sha1, &c); - if (write_sha1_buffer(sha1, compressed, size) < 0) return -1; if (returnsha1) -- cgit v0.10.2-6-g49f6