]>
Commit | Line | Data |
---|---|---|
8bc9a0c7 LT |
1 | /* |
2 | * GIT - The information manager from hell | |
3 | * | |
4 | * Copyright (C) Linus Torvalds, 2005 | |
5 | */ | |
e83c5163 LT |
6 | #include "cache.h" |
7 | ||
8 | static int check_valid_sha1(unsigned char *sha1) | |
9 | { | |
10 | char *filename = sha1_file_name(sha1); | |
11 | int ret; | |
12 | ||
13 | /* If we were anal, we'd check that the sha1 of the contents actually matches */ | |
14 | ret = access(filename, R_OK); | |
15 | if (ret) | |
16 | perror(filename); | |
17 | return ret; | |
18 | } | |
19 | ||
20 | static int prepend_integer(char *buffer, unsigned val, int i) | |
21 | { | |
22 | buffer[--i] = '\0'; | |
23 | do { | |
24 | buffer[--i] = '0' + (val % 10); | |
25 | val /= 10; | |
26 | } while (val); | |
27 | return i; | |
28 | } | |
29 | ||
30 | #define ORIG_OFFSET (40) /* Enough space to add the header of "tree <size>\0" */ | |
31 | ||
d6d3f9d0 | 32 | static int write_tree(struct cache_entry **cachep, int maxentries, const char *base, int baselen, unsigned char *returnsha1) |
e83c5163 | 33 | { |
d6d3f9d0 | 34 | unsigned char subdir_sha1[20]; |
19b2860c | 35 | unsigned long size, offset; |
e83c5163 | 36 | char *buffer; |
d6d3f9d0 | 37 | int i, nr; |
e83c5163 | 38 | |
d6d3f9d0 LT |
39 | /* Guess at some random initial size */ |
40 | size = 8192; | |
e83c5163 LT |
41 | buffer = malloc(size); |
42 | offset = ORIG_OFFSET; | |
43 | ||
d6d3f9d0 LT |
44 | nr = 0; |
45 | do { | |
46 | struct cache_entry *ce = cachep[nr]; | |
47 | const char *pathname = ce->name, *filename, *dirname; | |
ccc4feb5 | 48 | int pathlen = ce_namelen(ce), entrylen; |
d6d3f9d0 LT |
49 | unsigned char *sha1; |
50 | unsigned int mode; | |
51 | ||
52 | /* Did we hit the end of the directory? Return how many we wrote */ | |
53 | if (baselen >= pathlen || memcmp(base, pathname, baselen)) | |
54 | break; | |
55 | ||
56 | sha1 = ce->sha1; | |
ccc4feb5 | 57 | mode = ntohl(ce->ce_mode); |
d6d3f9d0 LT |
58 | |
59 | /* Do we have _further_ subdirectories? */ | |
60 | filename = pathname + baselen; | |
61 | dirname = strchr(filename, '/'); | |
62 | if (dirname) { | |
63 | int subdir_written; | |
64 | ||
65 | subdir_written = write_tree(cachep + nr, maxentries - nr, pathname, dirname-pathname+1, subdir_sha1); | |
d6d3f9d0 LT |
66 | nr += subdir_written; |
67 | ||
68 | /* Now we need to write out the directory entry into this tree.. */ | |
69 | mode = S_IFDIR; | |
70 | pathlen = dirname - pathname; | |
71 | ||
72 | /* ..but the directory entry doesn't count towards the total count */ | |
73 | nr--; | |
74 | sha1 = subdir_sha1; | |
75 | } | |
76 | ||
77 | if (check_valid_sha1(sha1) < 0) | |
e83c5163 | 78 | exit(1); |
d6d3f9d0 LT |
79 | |
80 | entrylen = pathlen - baselen; | |
81 | if (offset + entrylen + 100 > size) { | |
82 | size = alloc_nr(offset + entrylen + 100); | |
e83c5163 LT |
83 | buffer = realloc(buffer, size); |
84 | } | |
d6d3f9d0 | 85 | offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename); |
e83c5163 | 86 | buffer[offset++] = 0; |
d6d3f9d0 | 87 | memcpy(buffer + offset, sha1, 20); |
e83c5163 | 88 | offset += 20; |
d6d3f9d0 LT |
89 | nr++; |
90 | } while (nr < maxentries); | |
e83c5163 LT |
91 | |
92 | i = prepend_integer(buffer, offset - ORIG_OFFSET, ORIG_OFFSET); | |
93 | i -= 5; | |
94 | memcpy(buffer+i, "tree ", 5); | |
95 | ||
96 | buffer += i; | |
97 | offset -= i; | |
98 | ||
d6d3f9d0 LT |
99 | write_sha1_file(buffer, offset, returnsha1); |
100 | return nr; | |
101 | } | |
102 | ||
103 | int main(int argc, char **argv) | |
104 | { | |
105 | int entries = read_cache(); | |
106 | unsigned char sha1[20]; | |
107 | ||
108 | if (entries <= 0) | |
2de381f9 | 109 | die("write-tree: no cache contents to write"); |
d6d3f9d0 | 110 | if (write_tree(active_cache, entries, "", 0, sha1) != entries) |
2de381f9 | 111 | die("write-tree: internal error"); |
d6d3f9d0 | 112 | printf("%s\n", sha1_to_hex(sha1)); |
e83c5163 LT |
113 | return 0; |
114 | } |