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