]>
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 | ||
7223a88c BR |
96 | write_sha1_file(buffer + i, offset - i, returnsha1); |
97 | free(buffer); | |
d6d3f9d0 LT |
98 | return nr; |
99 | } | |
100 | ||
101 | int main(int argc, char **argv) | |
102 | { | |
c347ea5d | 103 | int i, unmerged; |
d6d3f9d0 LT |
104 | int entries = read_cache(); |
105 | unsigned char sha1[20]; | |
106 | ||
107 | if (entries <= 0) | |
2de381f9 | 108 | die("write-tree: no cache contents to write"); |
c347ea5d LT |
109 | |
110 | /* Verify that the tree is merged */ | |
111 | unmerged = 0; | |
112 | for (i = 0; i < entries; i++) { | |
113 | struct cache_entry *ce = active_cache[i]; | |
114 | if (ntohs(ce->ce_flags) & ~CE_NAMEMASK) { | |
115 | if (++unmerged > 10) { | |
116 | fprintf(stderr, "...\n"); | |
117 | break; | |
118 | } | |
119 | fprintf(stderr, "%s: unmerged (%s)\n", ce->name, sha1_to_hex(ce->sha1)); | |
120 | } | |
121 | } | |
122 | if (unmerged) | |
123 | die("write-tree: not able to write tree"); | |
124 | ||
125 | /* Ok, write it out */ | |
d6d3f9d0 | 126 | if (write_tree(active_cache, entries, "", 0, sha1) != entries) |
2de381f9 | 127 | die("write-tree: internal error"); |
d6d3f9d0 | 128 | printf("%s\n", sha1_to_hex(sha1)); |
e83c5163 LT |
129 | return 0; |
130 | } |