]>
Commit | Line | Data |
---|---|---|
29b0d019 NP |
1 | #!/bin/sh |
2 | # | |
3 | # Copyright (c) 2008 Nicolas Pitre | |
4 | # | |
5 | ||
6 | test_description='resilience to pack corruptions with redundant objects' | |
f40a6934 ÆAB |
7 | |
8 | TEST_PASSES_SANITIZE_LEAK=true | |
29b0d019 NP |
9 | . ./test-lib.sh |
10 | ||
11 | # Note: the test objects are created with knowledge of their pack encoding | |
12 | # to ensure good code path coverage, and to facilitate direct alteration | |
13 | # later on. The assumed characteristics are: | |
14 | # | |
15 | # 1) blob_2 is a delta with blob_1 for base and blob_3 is a delta with blob2 | |
16 | # for base, such that blob_3 delta depth is 2; | |
17 | # | |
18 | # 2) the bulk of object data is uncompressible so the text part remains | |
19 | # visible; | |
20 | # | |
21 | # 3) object header is always 2 bytes. | |
22 | ||
23 | create_test_files() { | |
c680668d NTND |
24 | test-tool genrandom "foo" 2000 > file_1 && |
25 | test-tool genrandom "foo" 1800 > file_2 && | |
26 | test-tool genrandom "foo" 1800 > file_3 && | |
29b0d019 NP |
27 | echo " base " >> file_1 && |
28 | echo " delta1 " >> file_2 && | |
29 | echo " delta delta2 " >> file_3 && | |
c680668d NTND |
30 | test-tool genrandom "bar" 150 >> file_2 && |
31 | test-tool genrandom "baz" 100 >> file_3 | |
29b0d019 NP |
32 | } |
33 | ||
34 | create_new_pack() { | |
35 | rm -rf .git && | |
36 | git init && | |
a64d080f EP |
37 | blob_1=$(git hash-object -t blob -w file_1) && |
38 | blob_2=$(git hash-object -t blob -w file_2) && | |
39 | blob_3=$(git hash-object -t blob -w file_3) && | |
40 | pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | | |
41 | git pack-objects $@ .git/objects/pack/pack) && | |
29b0d019 NP |
42 | pack=".git/objects/pack/pack-${pack}" && |
43 | git verify-pack -v ${pack}.pack | |
44 | } | |
45 | ||
538cf6b6 | 46 | do_repack() { |
a64d080f EP |
47 | pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" | |
48 | git pack-objects $@ .git/objects/pack/pack) && | |
538cf6b6 NP |
49 | pack=".git/objects/pack/pack-${pack}" |
50 | } | |
51 | ||
29b0d019 | 52 | do_corrupt_object() { |
a64d080f | 53 | ofs=$(git show-index < ${pack}.idx | grep $1 | cut -f1 -d" ") && |
29b0d019 NP |
54 | ofs=$(($ofs + $2)) && |
55 | chmod +w ${pack}.pack && | |
50b72ede | 56 | dd of=${pack}.pack bs=1 conv=notrunc seek=$ofs && |
29b0d019 NP |
57 | test_must_fail git verify-pack ${pack}.pack |
58 | } | |
59 | ||
b689ccf6 JS |
60 | printf '\0' > zero |
61 | ||
29b0d019 NP |
62 | test_expect_success \ |
63 | 'initial setup validation' \ | |
64 | 'create_test_files && | |
65 | create_new_pack && | |
66 | git prune-packed && | |
67 | git cat-file blob $blob_1 > /dev/null && | |
68 | git cat-file blob $blob_2 > /dev/null && | |
69 | git cat-file blob $blob_3 > /dev/null' | |
70 | ||
71 | test_expect_success \ | |
72 | 'create corruption in header of first object' \ | |
b689ccf6 | 73 | 'do_corrupt_object $blob_1 0 < zero && |
29b0d019 NP |
74 | test_must_fail git cat-file blob $blob_1 > /dev/null && |
75 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
76 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
77 | ||
78 | test_expect_success \ | |
79 | '... but having a loose copy allows for full recovery' \ | |
80 | 'mv ${pack}.idx tmp && | |
81 | git hash-object -t blob -w file_1 && | |
82 | mv tmp ${pack}.idx && | |
83 | git cat-file blob $blob_1 > /dev/null && | |
84 | git cat-file blob $blob_2 > /dev/null && | |
85 | git cat-file blob $blob_3 > /dev/null' | |
86 | ||
87 | test_expect_success \ | |
88 | '... and loose copy of first delta allows for partial recovery' \ | |
89 | 'git prune-packed && | |
90 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
91 | mv ${pack}.idx tmp && | |
92 | git hash-object -t blob -w file_2 && | |
93 | mv tmp ${pack}.idx && | |
94 | test_must_fail git cat-file blob $blob_1 > /dev/null && | |
95 | git cat-file blob $blob_2 > /dev/null && | |
96 | git cat-file blob $blob_3 > /dev/null' | |
97 | ||
98 | test_expect_success \ | |
99 | 'create corruption in data of first object' \ | |
100 | 'create_new_pack && | |
101 | git prune-packed && | |
102 | chmod +w ${pack}.pack && | |
94221d22 | 103 | perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && |
29b0d019 NP |
104 | test_must_fail git cat-file blob $blob_1 > /dev/null && |
105 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
106 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
107 | ||
108 | test_expect_success \ | |
109 | '... but having a loose copy allows for full recovery' \ | |
110 | 'mv ${pack}.idx tmp && | |
111 | git hash-object -t blob -w file_1 && | |
112 | mv tmp ${pack}.idx && | |
113 | git cat-file blob $blob_1 > /dev/null && | |
114 | git cat-file blob $blob_2 > /dev/null && | |
115 | git cat-file blob $blob_3 > /dev/null' | |
116 | ||
117 | test_expect_success \ | |
118 | '... and loose copy of second object allows for partial recovery' \ | |
119 | 'git prune-packed && | |
120 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
121 | mv ${pack}.idx tmp && | |
122 | git hash-object -t blob -w file_2 && | |
123 | mv tmp ${pack}.idx && | |
124 | test_must_fail git cat-file blob $blob_1 > /dev/null && | |
125 | git cat-file blob $blob_2 > /dev/null && | |
126 | git cat-file blob $blob_3 > /dev/null' | |
127 | ||
128 | test_expect_success \ | |
129 | 'create corruption in header of first delta' \ | |
130 | 'create_new_pack && | |
131 | git prune-packed && | |
b689ccf6 | 132 | do_corrupt_object $blob_2 0 < zero && |
29b0d019 NP |
133 | git cat-file blob $blob_1 > /dev/null && |
134 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
135 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
136 | ||
137 | test_expect_success \ | |
138 | '... but having a loose copy allows for full recovery' \ | |
139 | 'mv ${pack}.idx tmp && | |
140 | git hash-object -t blob -w file_2 && | |
141 | mv tmp ${pack}.idx && | |
142 | git cat-file blob $blob_1 > /dev/null && | |
143 | git cat-file blob $blob_2 > /dev/null && | |
144 | git cat-file blob $blob_3 > /dev/null' | |
145 | ||
538cf6b6 NP |
146 | test_expect_success \ |
147 | '... and then a repack "clears" the corruption' \ | |
148 | 'do_repack && | |
149 | git prune-packed && | |
150 | git verify-pack ${pack}.pack && | |
151 | git cat-file blob $blob_1 > /dev/null && | |
152 | git cat-file blob $blob_2 > /dev/null && | |
153 | git cat-file blob $blob_3 > /dev/null' | |
154 | ||
29b0d019 NP |
155 | test_expect_success \ |
156 | 'create corruption in data of first delta' \ | |
157 | 'create_new_pack && | |
158 | git prune-packed && | |
159 | chmod +w ${pack}.pack && | |
94221d22 | 160 | perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && |
29b0d019 NP |
161 | git cat-file blob $blob_1 > /dev/null && |
162 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
163 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
164 | ||
165 | test_expect_success \ | |
166 | '... but having a loose copy allows for full recovery' \ | |
167 | 'mv ${pack}.idx tmp && | |
168 | git hash-object -t blob -w file_2 && | |
169 | mv tmp ${pack}.idx && | |
170 | git cat-file blob $blob_1 > /dev/null && | |
171 | git cat-file blob $blob_2 > /dev/null && | |
172 | git cat-file blob $blob_3 > /dev/null' | |
173 | ||
538cf6b6 NP |
174 | test_expect_success \ |
175 | '... and then a repack "clears" the corruption' \ | |
176 | 'do_repack && | |
177 | git prune-packed && | |
178 | git verify-pack ${pack}.pack && | |
179 | git cat-file blob $blob_1 > /dev/null && | |
180 | git cat-file blob $blob_2 > /dev/null && | |
181 | git cat-file blob $blob_3 > /dev/null' | |
182 | ||
29b0d019 NP |
183 | test_expect_success \ |
184 | 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \ | |
185 | 'create_new_pack && | |
186 | git prune-packed && | |
b689ccf6 | 187 | do_corrupt_object $blob_2 2 < zero && |
29b0d019 NP |
188 | git cat-file blob $blob_1 > /dev/null && |
189 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
190 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
191 | ||
192 | test_expect_success \ | |
193 | '... but having a loose copy allows for full recovery' \ | |
194 | 'mv ${pack}.idx tmp && | |
195 | git hash-object -t blob -w file_2 && | |
196 | mv tmp ${pack}.idx && | |
197 | git cat-file blob $blob_1 > /dev/null && | |
198 | git cat-file blob $blob_2 > /dev/null && | |
199 | git cat-file blob $blob_3 > /dev/null' | |
200 | ||
201 | test_expect_success \ | |
538cf6b6 NP |
202 | '... and then a repack "clears" the corruption' \ |
203 | 'do_repack && | |
204 | git prune-packed && | |
205 | git verify-pack ${pack}.pack && | |
206 | git cat-file blob $blob_1 > /dev/null && | |
207 | git cat-file blob $blob_2 > /dev/null && | |
208 | git cat-file blob $blob_3 > /dev/null' | |
209 | ||
210 | test_expect_success \ | |
211 | 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \ | |
29b0d019 NP |
212 | 'create_new_pack --delta-base-offset && |
213 | git prune-packed && | |
b689ccf6 | 214 | do_corrupt_object $blob_2 2 < zero && |
29b0d019 NP |
215 | git cat-file blob $blob_1 > /dev/null && |
216 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
217 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
218 | ||
219 | test_expect_success \ | |
538cf6b6 | 220 | '... but having a loose copy allows for full recovery' \ |
29b0d019 | 221 | 'mv ${pack}.idx tmp && |
538cf6b6 NP |
222 | git hash-object -t blob -w file_2 && |
223 | mv tmp ${pack}.idx && | |
224 | git cat-file blob $blob_1 > /dev/null && | |
225 | git cat-file blob $blob_2 > /dev/null && | |
226 | git cat-file blob $blob_3 > /dev/null' | |
227 | ||
228 | test_expect_success \ | |
229 | '... and then a repack "clears" the corruption' \ | |
230 | 'do_repack --delta-base-offset && | |
231 | git prune-packed && | |
232 | git verify-pack ${pack}.pack && | |
233 | git cat-file blob $blob_1 > /dev/null && | |
234 | git cat-file blob $blob_2 > /dev/null && | |
235 | git cat-file blob $blob_3 > /dev/null' | |
236 | ||
237 | test_expect_success \ | |
238 | 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' \ | |
239 | 'create_new_pack --delta-base-offset && | |
240 | git prune-packed && | |
a2d2c478 | 241 | printf "\001" | do_corrupt_object $blob_2 2 && |
538cf6b6 NP |
242 | git cat-file blob $blob_1 > /dev/null && |
243 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
244 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
245 | ||
246 | test_expect_success \ | |
247 | '... but having a loose copy allows for full recovery' \ | |
248 | 'mv ${pack}.idx tmp && | |
249 | git hash-object -t blob -w file_2 && | |
250 | mv tmp ${pack}.idx && | |
251 | git cat-file blob $blob_1 > /dev/null && | |
252 | git cat-file blob $blob_2 > /dev/null && | |
253 | git cat-file blob $blob_3 > /dev/null' | |
254 | ||
255 | test_expect_success \ | |
256 | '... and then a repack "clears" the corruption' \ | |
257 | 'do_repack --delta-base-offset && | |
258 | git prune-packed && | |
259 | git verify-pack ${pack}.pack && | |
260 | git cat-file blob $blob_1 > /dev/null && | |
261 | git cat-file blob $blob_2 > /dev/null && | |
262 | git cat-file blob $blob_3 > /dev/null' | |
263 | ||
264 | test_expect_success \ | |
265 | '... and a redundant pack allows for full recovery too' \ | |
b689ccf6 | 266 | 'do_corrupt_object $blob_2 2 < zero && |
538cf6b6 NP |
267 | git cat-file blob $blob_1 > /dev/null && |
268 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
269 | test_must_fail git cat-file blob $blob_3 > /dev/null && | |
270 | mv ${pack}.idx tmp && | |
29b0d019 NP |
271 | git hash-object -t blob -w file_1 && |
272 | git hash-object -t blob -w file_2 && | |
273 | printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack && | |
274 | git prune-packed && | |
275 | mv tmp ${pack}.idx && | |
276 | git cat-file blob $blob_1 > /dev/null && | |
277 | git cat-file blob $blob_2 > /dev/null && | |
278 | git cat-file blob $blob_3 > /dev/null' | |
279 | ||
1ee886c1 JK |
280 | test_expect_success \ |
281 | 'corruption of delta base reference pointing to wrong object' \ | |
282 | 'create_new_pack --delta-base-offset && | |
283 | git prune-packed && | |
284 | printf "\220\033" | do_corrupt_object $blob_3 2 && | |
285 | git cat-file blob $blob_1 >/dev/null && | |
286 | git cat-file blob $blob_2 >/dev/null && | |
287 | test_must_fail git cat-file blob $blob_3 >/dev/null' | |
288 | ||
289 | test_expect_success \ | |
290 | '... but having a loose copy allows for full recovery' \ | |
291 | 'mv ${pack}.idx tmp && | |
292 | git hash-object -t blob -w file_3 && | |
293 | mv tmp ${pack}.idx && | |
294 | git cat-file blob $blob_1 > /dev/null && | |
295 | git cat-file blob $blob_2 > /dev/null && | |
296 | git cat-file blob $blob_3 > /dev/null' | |
297 | ||
298 | test_expect_success \ | |
299 | '... and then a repack "clears" the corruption' \ | |
300 | 'do_repack --delta-base-offset --no-reuse-delta && | |
301 | git prune-packed && | |
302 | git verify-pack ${pack}.pack && | |
303 | git cat-file blob $blob_1 > /dev/null && | |
304 | git cat-file blob $blob_2 > /dev/null && | |
305 | git cat-file blob $blob_3 > /dev/null' | |
306 | ||
b3118bdc SP |
307 | test_expect_success \ |
308 | 'corrupting header to have too small output buffer fails unpack' \ | |
309 | 'create_new_pack && | |
310 | git prune-packed && | |
311 | printf "\262\001" | do_corrupt_object $blob_1 0 && | |
312 | test_must_fail git cat-file blob $blob_1 > /dev/null && | |
313 | test_must_fail git cat-file blob $blob_2 > /dev/null && | |
314 | test_must_fail git cat-file blob $blob_3 > /dev/null' | |
315 | ||
9caf0107 JK |
316 | # \0 - empty base |
317 | # \1 - one byte in result | |
318 | # \1 - one literal byte (X) | |
319 | test_expect_success \ | |
320 | 'apply good minimal delta' \ | |
321 | 'printf "\0\1\1X" > minimal_delta && | |
322 | test-tool delta -p /dev/null minimal_delta /dev/null' | |
323 | ||
324 | # \0 - empty base | |
325 | # \1 - 1 byte in result | |
326 | # \2 - two literal bytes (one too many) | |
327 | test_expect_success \ | |
328 | 'apply delta with too many literal bytes' \ | |
329 | 'printf "\0\1\2XX" > too_big_literal && | |
330 | test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null' | |
331 | ||
18f60f2d | 332 | # \4 - four bytes in base |
9caf0107 JK |
333 | # \1 - one byte in result |
334 | # \221 - copy, one byte offset, one byte size | |
335 | # \0 - copy from offset 0 | |
336 | # \2 - copy two bytes (one too many) | |
337 | test_expect_success \ | |
338 | 'apply delta with too many copied bytes' \ | |
18f60f2d JK |
339 | 'printf "\4\1\221\0\2" > too_big_copy && |
340 | printf base >base && | |
9caf0107 JK |
341 | test_must_fail test-tool delta -p base too_big_copy /dev/null' |
342 | ||
343 | # \0 - empty base | |
344 | # \2 - two bytes in result | |
345 | # \2 - two literal bytes (we are short one) | |
21870efc | 346 | test_expect_success \ |
9caf0107 JK |
347 | 'apply delta with too few literal bytes' \ |
348 | 'printf "\0\2\2X" > truncated_delta && | |
349 | test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null' | |
350 | ||
351 | # \0 - empty base | |
352 | # \1 - one byte in result | |
353 | # \221 - copy, one byte offset, one byte size | |
354 | # \0 - copy from offset 0 | |
355 | # \1 - copy one byte (we are short one) | |
356 | test_expect_success \ | |
357 | 'apply delta with too few bytes in base' \ | |
358 | 'printf "\0\1\221\0\1" > truncated_base && | |
359 | test_must_fail test-tool delta -p /dev/null truncated_base /dev/null' | |
360 | ||
18f60f2d JK |
361 | # \4 - four bytes in base |
362 | # \2 - two bytes in result | |
9caf0107 JK |
363 | # \1 - one literal byte (X) |
364 | # \221 - copy, one byte offset, one byte size | |
365 | # (offset/size missing) | |
366 | # | |
367 | # Note that the literal byte is necessary to get past the uninteresting minimum | |
368 | # delta size check. | |
9514b0b2 | 369 | test_expect_success \ |
9caf0107 | 370 | 'apply delta with truncated copy parameters' \ |
18f60f2d JK |
371 | 'printf "\4\2\1X\221" > truncated_copy_delta && |
372 | printf base >base && | |
9caf0107 JK |
373 | test_must_fail test-tool delta -p base truncated_copy_delta /dev/null' |
374 | ||
fa72f90e JH |
375 | # \0 - empty base |
376 | # \1 - one byte in result | |
377 | # \1 - one literal byte (X) | |
378 | # \1 - trailing garbage command | |
379 | test_expect_success \ | |
380 | 'apply delta with trailing garbage literal' \ | |
381 | 'printf "\0\1\1X\1" > tail_garbage_literal && | |
382 | test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null' | |
383 | ||
18f60f2d | 384 | # \4 - four bytes in base |
fa72f90e JH |
385 | # \1 - one byte in result |
386 | # \1 - one literal byte (X) | |
387 | # \221 - copy, one byte offset, one byte size | |
388 | # \0 - copy from offset 0 | |
389 | # \1 - copy 1 byte | |
390 | test_expect_success \ | |
391 | 'apply delta with trailing garbage copy' \ | |
18f60f2d JK |
392 | 'printf "\4\1\1X\221\0\1" > tail_garbage_copy && |
393 | printf base >base && | |
fa72f90e JH |
394 | test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null' |
395 | ||
396 | # \0 - empty base | |
397 | # \1 - one byte in result | |
398 | # \1 - one literal byte (X) | |
399 | # \0 - bogus opcode | |
400 | test_expect_success \ | |
401 | 'apply delta with trailing garbage opcode' \ | |
402 | 'printf "\0\1\1X\0" > tail_garbage_opcode && | |
403 | test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null' | |
404 | ||
29b0d019 | 405 | test_done |