Teach "fsck" and "read-tree" about recursive tree-nodes.
[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);
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 int main(int argc, char **argv)
67 {
68         int i, newfd;
69         unsigned char sha1[20];
70
71         newfd = open(".dircache/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
72         if (newfd < 0)
73                 usage("unable to create new cachefile");
74
75         for (i = 1; i < argc; i++) {
76                 const char *arg = argv[i];
77
78                 /* "-m" stands for "merge" current directory cache */
79                 if (!strcmp(arg, "-m")) {
80                         if (active_cache) {
81                                 fprintf(stderr, "read-tree: cannot merge old cache on top of new\n");
82                                 goto out;
83                         }
84                         if (read_cache() < 0) {
85                                 fprintf(stderr, "read-tree: corrupt directory cache\n");
86                                 goto out;
87                         }
88                         continue;
89                 }
90                 if (get_sha1_hex(arg, sha1) < 0) {
91                         fprintf(stderr, "read-tree [-m] <sha1>\n");
92                         goto out;
93                 }
94                 if (read_tree(sha1, "", 0) < 0) {
95                         fprintf(stderr, "failed to unpack tree object %s\n", arg);
96                         goto out;
97                 }
98         }
99         if (!write_cache(newfd, active_cache, active_nr) && !rename(".dircache/index.lock", ".dircache/index"))
100                 return 0;
101
102 out:
103         unlink(".dircache/index.lock");
104         exit(1);
105 }