improve reliability of fixup_pack_header_footer()
Currently, this function has the potential to read corrupted pack data from disk and give it a valid SHA1 checksum. Let's add the ability to validate SHA1 checksum of existing data along the way, including before and after any arbitrary point in the pack. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nicolas Pitre committed
Aug 29, 2008 at 16:07 UTC
abeb40e5aa5b4a39799ae1caad241c8c7708053a
5 files changed
+66
-16
builtin-pack-objects.c
+2
-1
@@ -493,7 +493,8 @@ static void write_pack_file(void)
493
sha1close(f, sha1, CSUM_FSYNC);
494
} else {
495
int fd = sha1close(f, NULL, 0);
496
- fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
496
+ fixup_pack_header_footer(fd, sha1, pack_tmp_name,
497
+ nr_written, NULL, 0);
498
close(fd);
499
}
500
fast-import.c
+2
-1
@@ -951,7 +951,8 @@ static void end_packfile(void)
951
952
close_pack_windows(pack_data);
953
fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
954
- pack_data->pack_name, object_count);
954
+ pack_data->pack_name, object_count,
955
+ NULL, 0);
956
close(pack_data->pack_fd);
957
idx_name = keep_pack(create_index());
958
index-pack.c
+2
-1
@@ -982,7 +982,8 @@ int main(int argc, char **argv)
982
nr_objects - nr_objects_initial);
983
stop_progress_msg(&progress, msg);
984
fixup_pack_header_footer(output_fd, sha1,
985
- curr_pack, nr_objects);
985
+ curr_pack, nr_objects,
986
+ NULL, 0);
987
}
988
if (nr_deltas != nr_resolved_deltas)
989
die("pack has %d unresolved deltas",
pack-write.c
+59
-12
@@ -144,41 +144,88 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects,
144
return index_name;
145
}
146
147
+/*
148
+ * Update pack header with object_count and compute new SHA1 for pack data
149
+ * associated to pack_fd, and write that SHA1 at the end. That new SHA1
150
+ * is also returned in new_pack_sha1.
151
+ *
152
+ * If partial_pack_sha1 is non null, then the SHA1 of the existing pack
153
+ * (without the header update) is computed and validated against the
154
+ * one provided in partial_pack_sha1. The validation is performed at
155
+ * partial_pack_offset bytes in the pack file. The SHA1 of the remaining
156
+ * data (i.e. from partial_pack_offset to the end) is then computed and
157
+ * returned in partial_pack_sha1.
158
+ *
159
+ * Note that new_pack_sha1 is updated last, so both new_pack_sha1 and
160
+ * partial_pack_sha1 can refer to the same buffer if the caller is not
161
+ * interested in the resulting SHA1 of pack data above partial_pack_offset.
162
+ */
163
void fixup_pack_header_footer(int pack_fd,
148
- unsigned char *pack_file_sha1,
164
+ unsigned char *new_pack_sha1,
165
const char *pack_name,
150
- uint32_t object_count)
166
+ uint32_t object_count,
167
+ unsigned char *partial_pack_sha1,
168
+ off_t partial_pack_offset)
169
{
170
static const int buf_sz = 128 * 1024;
153
- SHA_CTX c;
171
+ SHA_CTX old_sha1_ctx, new_sha1_ctx;
172
struct pack_header hdr;
173
char *buf;
174
175
+ SHA1_Init(&old_sha1_ctx);
176
+ SHA1_Init(&new_sha1_ctx);
177
+
178
if (lseek(pack_fd, 0, SEEK_SET) != 0)
158
- die("Failed seeking to start: %s", strerror(errno));
179
+ die("Failed seeking to start of %s: %s", pack_name, strerror(errno));
180
if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
181
die("Unable to reread header of %s: %s", pack_name, strerror(errno));
182
if (lseek(pack_fd, 0, SEEK_SET) != 0)
162
- die("Failed seeking to start: %s", strerror(errno));
183
+ die("Failed seeking to start of %s: %s", pack_name, strerror(errno));
184
+ SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr));
185
hdr.hdr_entries = htonl(object_count);
186
+ SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr));
187
write_or_die(pack_fd, &hdr, sizeof(hdr));
165
-
166
- SHA1_Init(&c);
167
- SHA1_Update(&c, &hdr, sizeof(hdr));
188
+ partial_pack_offset -= sizeof(hdr);
189
190
buf = xmalloc(buf_sz);
191
for (;;) {
171
- ssize_t n = xread(pack_fd, buf, buf_sz);
192
+ ssize_t m, n;
193
+ m = (partial_pack_sha1 && partial_pack_offset < buf_sz) ?
194
+ partial_pack_offset : buf_sz;
195
+ n = xread(pack_fd, buf, m);
196
if (!n)
197
break;
198
if (n < 0)
199
die("Failed to checksum %s: %s", pack_name, strerror(errno));
176
- SHA1_Update(&c, buf, n);
200
+ SHA1_Update(&new_sha1_ctx, buf, n);
201
+
202
+ if (!partial_pack_sha1)
203
+ continue;
204
+
205
+ SHA1_Update(&old_sha1_ctx, buf, n);
206
+ partial_pack_offset -= n;
207
+ if (partial_pack_offset == 0) {
208
+ unsigned char sha1[20];
209
+ SHA1_Final(sha1, &old_sha1_ctx);
210
+ if (hashcmp(sha1, partial_pack_sha1) != 0)
211
+ die("Unexpected checksum for %s "
212
+ "(disk corruption?)", pack_name);
213
+ /*
214
+ * Now let's compute the SHA1 of the remainder of the
215
+ * pack, which also means making partial_pack_offset
216
+ * big enough not to matter anymore.
217
+ */
218
+ SHA1_Init(&old_sha1_ctx);
219
+ partial_pack_offset = ~partial_pack_offset;
220
+ partial_pack_offset -= MSB(partial_pack_offset, 1);
221
+ }
222
}
223
free(buf);
224
180
- SHA1_Final(pack_file_sha1, &c);
181
- write_or_die(pack_fd, pack_file_sha1, 20);
225
+ if (partial_pack_sha1)
226
+ SHA1_Final(partial_pack_sha1, &old_sha1_ctx);
227
+ SHA1_Final(new_pack_sha1, &new_sha1_ctx);
228
+ write_or_die(pack_fd, new_pack_sha1, 20);
229
fsync_or_die(pack_fd, pack_name);
230
}
231
pack.h
+1
-1
@@ -58,7 +58,7 @@ struct pack_idx_entry {
58
extern char *write_idx_file(char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
59
extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
60
extern int verify_pack(struct packed_git *);
61
-extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
61
+extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
62
extern char *index_pack_lockfile(int fd);
63
64
#define PH_ERROR_EOF (-1)