Skip to content
Newer
Older
100644 182 lines (161 sloc) 4.74 KB
8b0eca7 Create pack-write.c for common pack writing code
Dana L. How authored May 2, 2007
1 #include "cache.h"
2 #include "pack.h"
aa7e44b Unify write_index_file functions
Geert Bosch authored Jun 1, 2007
3 #include "csum-file.h"
4
5 uint32_t pack_idx_default_version = 1;
6 uint32_t pack_idx_off32_limit = 0x7fffffff;
7
8 static int sha1_compare(const void *_a, const void *_b)
9 {
10 struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
11 struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
12 return hashcmp(a->sha1, b->sha1);
13 }
14
15 /*
16 * On entry *sha1 contains the pack content SHA1 hash, on exit it is
17 * the SHA1 hash of sorted object names. The objects array passed in
18 * will be sorted by SHA1 on exit.
19 */
20 const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
21 {
22 struct sha1file *f;
23 struct pack_idx_entry **sorted_by_sha, **list, **last;
24 off_t last_obj_offset = 0;
25 uint32_t array[256];
26 int i, fd;
27 SHA_CTX ctx;
28 uint32_t index_version;
29
30 if (nr_objects) {
31 sorted_by_sha = objects;
32 list = sorted_by_sha;
33 last = sorted_by_sha + nr_objects;
34 for (i = 0; i < nr_objects; ++i) {
35 if (objects[i]->offset > last_obj_offset)
36 last_obj_offset = objects[i]->offset;
37 }
38 qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
39 sha1_compare);
40 }
41 else
42 sorted_by_sha = list = last = NULL;
43
44 if (!index_name) {
45 static char tmpfile[PATH_MAX];
46 snprintf(tmpfile, sizeof(tmpfile),
47 "%s/tmp_idx_XXXXXX", get_object_directory());
48 fd = mkstemp(tmpfile);
49 index_name = xstrdup(tmpfile);
50 } else {
51 unlink(index_name);
52 fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
53 }
54 if (fd < 0)
55 die("unable to create %s: %s", index_name, strerror(errno));
56 f = sha1fd(fd, index_name);
57
58 /* if last object's offset is >= 2^31 we should use index V2 */
59 index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
60
61 /* index versions 2 and above need a header */
62 if (index_version >= 2) {
63 struct pack_idx_header hdr;
64 hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
65 hdr.idx_version = htonl(index_version);
66 sha1write(f, &hdr, sizeof(hdr));
67 }
68
69 /*
70 * Write the first-level table (the list is sorted,
71 * but we use a 256-entry lookup to be able to avoid
72 * having to do eight extra binary search iterations).
73 */
74 for (i = 0; i < 256; i++) {
75 struct pack_idx_entry **next = list;
76 while (next < last) {
77 struct pack_idx_entry *obj = *next;
78 if (obj->sha1[0] != i)
79 break;
80 next++;
81 }
82 array[i] = htonl(next - sorted_by_sha);
83 list = next;
84 }
85 sha1write(f, array, 256 * 4);
86
87 /* compute the SHA1 hash of sorted object names. */
88 SHA1_Init(&ctx);
89
90 /*
91 * Write the actual SHA1 entries..
92 */
93 list = sorted_by_sha;
94 for (i = 0; i < nr_objects; i++) {
95 struct pack_idx_entry *obj = *list++;
96 if (index_version < 2) {
97 uint32_t offset = htonl(obj->offset);
98 sha1write(f, &offset, 4);
99 }
100 sha1write(f, obj->sha1, 20);
101 SHA1_Update(&ctx, obj->sha1, 20);
102 }
103
104 if (index_version >= 2) {
105 unsigned int nr_large_offset = 0;
106
107 /* write the crc32 table */
108 list = sorted_by_sha;
109 for (i = 0; i < nr_objects; i++) {
110 struct pack_idx_entry *obj = *list++;
111 uint32_t crc32_val = htonl(obj->crc32);
112 sha1write(f, &crc32_val, 4);
113 }
114
115 /* write the 32-bit offset table */
116 list = sorted_by_sha;
117 for (i = 0; i < nr_objects; i++) {
118 struct pack_idx_entry *obj = *list++;
119 uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
120 obj->offset : (0x80000000 | nr_large_offset++);
121 offset = htonl(offset);
122 sha1write(f, &offset, 4);
123 }
124
125 /* write the large offset table */
126 list = sorted_by_sha;
127 while (nr_large_offset) {
128 struct pack_idx_entry *obj = *list++;
129 uint64_t offset = obj->offset;
130 if (offset > pack_idx_off32_limit) {
131 uint32_t split[2];
132 split[0] = htonl(offset >> 32);
133 split[1] = htonl(offset & 0xffffffff);
134 sha1write(f, split, 8);
135 nr_large_offset--;
136 }
137 }
138 }
139
140 sha1write(f, sha1, 20);
141 sha1close(f, NULL, 1);
142 SHA1_Final(sha1, &ctx);
143 return index_name;
144 }
8b0eca7 Create pack-write.c for common pack writing code
Dana L. How authored May 2, 2007
145
146 void fixup_pack_header_footer(int pack_fd,
147 unsigned char *pack_file_sha1,
148 const char *pack_name,
149 uint32_t object_count)
150 {
151 static const int buf_sz = 128 * 1024;
152 SHA_CTX c;
153 struct pack_header hdr;
154 char *buf;
155
156 if (lseek(pack_fd, 0, SEEK_SET) != 0)
157 die("Failed seeking to start: %s", strerror(errno));
158 if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
159 die("Unable to reread header of %s: %s", pack_name, strerror(errno));
160 if (lseek(pack_fd, 0, SEEK_SET) != 0)
161 die("Failed seeking to start: %s", strerror(errno));
162 hdr.hdr_entries = htonl(object_count);
163 write_or_die(pack_fd, &hdr, sizeof(hdr));
164
165 SHA1_Init(&c);
166 SHA1_Update(&c, &hdr, sizeof(hdr));
167
168 buf = xmalloc(buf_sz);
169 for (;;) {
2924415 @jherland Fix signedness on return value from xread()
jherland authored May 15, 2007
170 ssize_t n = xread(pack_fd, buf, buf_sz);
8b0eca7 Create pack-write.c for common pack writing code
Dana L. How authored May 2, 2007
171 if (!n)
172 break;
173 if (n < 0)
174 die("Failed to checksum %s: %s", pack_name, strerror(errno));
175 SHA1_Update(&c, buf, n);
176 }
177 free(buf);
178
179 SHA1_Final(pack_file_sha1, &c);
180 write_or_die(pack_fd, pack_file_sha1, 20);
181 }
Something went wrong with that request. Please try again.