[PATCH] SHA1 naive collision checking
[git.git] / read-tree.c
1 /*
2  * GIT - The information manager from hell
3  *
4  * Copyright (C) Linus Torvalds, 2005
5  */
6 #include "cache.h"
7
8 static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
9 {
10         int len = strlen(pathname);
11         unsigned int size = cache_entry_size(baselen + len);
12         struct cache_entry *ce = malloc(size);
13
14         memset(ce, 0, size);
15
16         ce->st_mode = mode;
17         ce->namelen = baselen + len;
18         memcpy(ce->name, base, baselen);
19         memcpy(ce->name + baselen, pathname, len+1);
20         memcpy(ce->sha1, sha1, 20);
21         return add_cache_entry(ce, 1);
22 }
23
24 static int read_tree(unsigned char *sha1, const char *base, int baselen)
25 {
26         void *buffer;
27         unsigned long size;
28         char type[20];
29
30         buffer = read_sha1_file(sha1, type, &size);
31         if (!buffer)
32                 return -1;
33         if (strcmp(type, "tree"))
34                 return -1;
35         while (size) {
36                 int len = strlen(buffer)+1;
37                 unsigned char *sha1 = buffer + len;
38                 char *path = strchr(buffer, ' ')+1;
39                 unsigned int mode;
40
41                 if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
42                         return -1;
43
44                 buffer = sha1 + 20;
45                 size -= len + 20;
46
47                 if (S_ISDIR(mode)) {
48                         int retval;
49                         int pathlen = strlen(path);
50                         char *newbase = malloc(baselen + 1 + pathlen);
51                         memcpy(newbase, base, baselen);
52                         memcpy(newbase + baselen, path, pathlen);
53                         newbase[baselen + pathlen] = '/';
54                         retval = read_tree(sha1, newbase, baselen + pathlen + 1);
55                         free(newbase);
56                         if (retval)
57                                 return -1;
58                         continue;
59                 }
60                 if (read_one_entry(sha1, base, baselen, path, mode) < 0)
61                         return -1;
62         }
63         return 0;
64 }
65
66 static int remove_lock = 0;
67
68 static void remove_lock_file(void)
69 {
70         if (remove_lock)
71                 unlink(".git/index.lock");
72 }
73
74 int main(int argc, char **argv)
75 {
76         int i, newfd;
77         unsigned char sha1[20];
78
79         newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
80         if (newfd < 0)
81                 usage("unable to create new cachefile");
82         atexit(remove_lock_file);
83         remove_lock = 1;
84
85         for (i = 1; i < argc; i++) {
86                 const char *arg = argv[i];
87
88                 /* "-m" stands for "merge" current directory cache */
89                 if (!strcmp(arg, "-m")) {
90                         if (active_cache)
91                                 usage("read-tree: cannot merge old cache on top of new");
92                         if (read_cache() < 0)
93                                 usage("read-tree: corrupt directory cache");
94                         continue;
95                 }
96                 if (get_sha1_hex(arg, sha1) < 0)
97                         usage("read-tree [-m] <sha1>");
98                 if (read_tree(sha1, "", 0) < 0)
99                         usage("failed to unpack tree object %s", arg);
100         }
101         if (write_cache(newfd, active_cache, active_nr) ||
102             rename(".git/index.lock", ".git/index"))
103                 usage("unable to write new index file");
104         remove_lock = 0;
105         return 0;
106 }