|
5 | 5 | */ |
6 | 6 | #include "cache.h" |
7 | 7 |
|
8 | | -static void create_directories(const char *path) |
| 8 | +static int read_one_entry(unsigned char *sha1, const char *pathname, unsigned mode) |
9 | 9 | { |
10 | | - int len = strlen(path); |
11 | | - char *buf = malloc(len + 1); |
12 | | - const char *slash = path; |
| 10 | + int len = strlen(pathname); |
| 11 | + unsigned int size = cache_entry_size(len); |
| 12 | + struct cache_entry *ce = malloc(size); |
13 | 13 |
|
14 | | - while ((slash = strchr(slash+1, '/')) != NULL) { |
15 | | - len = slash - path; |
16 | | - memcpy(buf, path, len); |
17 | | - buf[len] = 0; |
18 | | - mkdir(buf, 0700); |
19 | | - } |
20 | | -} |
| 14 | + memset(ce, 0, size); |
21 | 15 |
|
22 | | -static int create_file(const char *path) |
23 | | -{ |
24 | | - int fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0600); |
25 | | - if (fd < 0) { |
26 | | - if (errno == ENOENT) { |
27 | | - create_directories(path); |
28 | | - fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0600); |
29 | | - } |
30 | | - } |
31 | | - return fd; |
| 16 | + ce->st_mode = mode; |
| 17 | + ce->namelen = len; |
| 18 | + memcpy(ce->name, pathname, len+1); |
| 19 | + memcpy(ce->sha1, sha1, 20); |
| 20 | + return add_cache_entry(ce); |
32 | 21 | } |
33 | 22 |
|
34 | | -static int unpack(unsigned char *sha1) |
| 23 | +static int read_tree(unsigned char *sha1) |
35 | 24 | { |
36 | 25 | void *buffer; |
37 | 26 | unsigned long size; |
38 | 27 | char type[20]; |
39 | 28 |
|
40 | 29 | buffer = read_sha1_file(sha1, type, &size); |
41 | 30 | if (!buffer) |
42 | | - usage("unable to read sha1 file"); |
| 31 | + return -1; |
43 | 32 | if (strcmp(type, "tree")) |
44 | | - usage("expected a 'tree' node"); |
| 33 | + return -1; |
45 | 34 | while (size) { |
46 | 35 | int len = strlen(buffer)+1; |
47 | 36 | unsigned char *sha1 = buffer + len; |
48 | 37 | char *path = strchr(buffer, ' ')+1; |
49 | | - char *data; |
50 | | - unsigned long filesize; |
51 | 38 | unsigned int mode; |
52 | | - int fd; |
53 | 39 |
|
54 | 40 | if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1) |
55 | | - usage("corrupt 'tree' file"); |
| 41 | + return -1; |
| 42 | + |
56 | 43 | buffer = sha1 + 20; |
57 | 44 | size -= len + 20; |
58 | | - data = read_sha1_file(sha1, type, &filesize); |
59 | | - if (!data || strcmp(type, "blob")) |
60 | | - usage("tree file refers to bad file data"); |
61 | | - fd = create_file(path); |
62 | | - if (fd < 0) |
63 | | - usage("unable to create file"); |
64 | | - if (write(fd, data, filesize) != filesize) |
65 | | - usage("unable to write file"); |
66 | | - fchmod(fd, mode); |
67 | | - close(fd); |
68 | | - free(data); |
| 45 | + |
| 46 | + if (read_one_entry(sha1, path, mode) < 0) |
| 47 | + return -1; |
69 | 48 | } |
70 | 49 | return 0; |
71 | 50 | } |
72 | 51 |
|
73 | 52 | int main(int argc, char **argv) |
74 | 53 | { |
| 54 | + int i, newfd; |
75 | 55 | unsigned char sha1[20]; |
76 | 56 |
|
77 | | - if (argc != 2) |
78 | | - usage("read-tree <key>"); |
79 | | - if (get_sha1_hex(argv[1], sha1) < 0) |
80 | | - usage("read-tree <key>"); |
81 | | - sha1_file_directory = getenv(DB_ENVIRONMENT); |
82 | | - if (!sha1_file_directory) |
83 | | - sha1_file_directory = DEFAULT_DB_ENVIRONMENT; |
84 | | - if (unpack(sha1) < 0) |
85 | | - usage("unpack failed"); |
86 | | - return 0; |
| 57 | + newfd = open(".dircache/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600); |
| 58 | + if (newfd < 0) |
| 59 | + usage("unable to create new cachefile"); |
| 60 | + |
| 61 | + for (i = 1; i < argc; i++) { |
| 62 | + const char *arg = argv[i]; |
| 63 | + |
| 64 | + /* "-m" stands for "merge" current directory cache */ |
| 65 | + if (!strcmp(arg, "-m")) { |
| 66 | + if (active_cache) { |
| 67 | + fprintf(stderr, "read-tree: cannot merge old cache on top of new\n"); |
| 68 | + goto out; |
| 69 | + } |
| 70 | + if (read_cache() < 0) { |
| 71 | + fprintf(stderr, "read-tree: corrupt directory cache\n"); |
| 72 | + goto out; |
| 73 | + } |
| 74 | + continue; |
| 75 | + } |
| 76 | + if (get_sha1_hex(arg, sha1) < 0) { |
| 77 | + fprintf(stderr, "read-tree [-m] <sha1>\n"); |
| 78 | + goto out; |
| 79 | + } |
| 80 | + if (read_tree(sha1) < 0) { |
| 81 | + fprintf(stderr, "failed to unpack tree object %s\n", arg); |
| 82 | + goto out; |
| 83 | + } |
| 84 | + } |
| 85 | + if (!write_cache(newfd, active_cache, active_nr) && !rename(".dircache/index.lock", ".dircache/index")) |
| 86 | + return 0; |
| 87 | + |
| 88 | +out: |
| 89 | + unlink(".dircache/index.lock"); |
| 90 | + exit(1); |
87 | 91 | } |
0 commit comments