Merge branch 'bc/more-git-var'
[alt-git.git] / t / t5303-pack-corruption-resilience.sh
blob61469ef4a681200044f45f0a98f54f39dec2a4c2
1 #!/bin/sh
3 # Copyright (c) 2008 Nicolas Pitre
6 test_description='resilience to pack corruptions with redundant objects'
8 TEST_PASSES_SANITIZE_LEAK=true
9 . ./test-lib.sh
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:
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;
18 # 2) the bulk of object data is uncompressible so the text part remains
19 # visible;
21 # 3) object header is always 2 bytes.
23 create_test_files() {
24 test-tool genrandom "foo" 2000 > file_1 &&
25 test-tool genrandom "foo" 1800 > file_2 &&
26 test-tool genrandom "foo" 1800 > file_3 &&
27 echo " base " >> file_1 &&
28 echo " delta1 " >> file_2 &&
29 echo " delta delta2 " >> file_3 &&
30 test-tool genrandom "bar" 150 >> file_2 &&
31 test-tool genrandom "baz" 100 >> file_3
34 create_new_pack() {
35 rm -rf .git &&
36 git init &&
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) &&
42 pack=".git/objects/pack/pack-${pack}" &&
43 git verify-pack -v ${pack}.pack
46 do_repack() {
47 pack=$(printf "$blob_1\n$blob_2\n$blob_3\n" |
48 git pack-objects $@ .git/objects/pack/pack) &&
49 pack=".git/objects/pack/pack-${pack}"
52 do_corrupt_object() {
53 ofs=$(git show-index < ${pack}.idx | grep $1 | cut -f1 -d" ") &&
54 ofs=$(($ofs + $2)) &&
55 chmod +w ${pack}.pack &&
56 dd of=${pack}.pack bs=1 conv=notrunc seek=$ofs &&
57 test_must_fail git verify-pack ${pack}.pack
60 printf '\0' > zero
62 test_expect_success 'initial setup validation' '
63 create_test_files &&
64 create_new_pack &&
65 git prune-packed &&
66 git cat-file blob $blob_1 > /dev/null &&
67 git cat-file blob $blob_2 > /dev/null &&
68 git cat-file blob $blob_3 > /dev/null
71 test_expect_success 'create corruption in header of first object' '
72 do_corrupt_object $blob_1 0 < zero &&
73 test_must_fail git cat-file blob $blob_1 > /dev/null &&
74 test_must_fail git cat-file blob $blob_2 > /dev/null &&
75 test_must_fail git cat-file blob $blob_3 > /dev/null
78 test_expect_success '... but having a loose copy allows for full recovery' '
79 mv ${pack}.idx tmp &&
80 git hash-object -t blob -w file_1 &&
81 mv tmp ${pack}.idx &&
82 git cat-file blob $blob_1 > /dev/null &&
83 git cat-file blob $blob_2 > /dev/null &&
84 git cat-file blob $blob_3 > /dev/null
87 test_expect_success '... and loose copy of first delta allows for partial recovery' '
88 git prune-packed &&
89 test_must_fail git cat-file blob $blob_2 > /dev/null &&
90 mv ${pack}.idx tmp &&
91 git hash-object -t blob -w file_2 &&
92 mv tmp ${pack}.idx &&
93 test_must_fail git cat-file blob $blob_1 > /dev/null &&
94 git cat-file blob $blob_2 > /dev/null &&
95 git cat-file blob $blob_3 > /dev/null
98 test_expect_success 'create corruption in data of first object' '
99 create_new_pack &&
100 git prune-packed &&
101 chmod +w ${pack}.pack &&
102 perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
103 test_must_fail git cat-file blob $blob_1 > /dev/null &&
104 test_must_fail git cat-file blob $blob_2 > /dev/null &&
105 test_must_fail git cat-file blob $blob_3 > /dev/null
108 test_expect_success '... but having a loose copy allows for full recovery' '
109 mv ${pack}.idx tmp &&
110 git hash-object -t blob -w file_1 &&
111 mv tmp ${pack}.idx &&
112 git cat-file blob $blob_1 > /dev/null &&
113 git cat-file blob $blob_2 > /dev/null &&
114 git cat-file blob $blob_3 > /dev/null
117 test_expect_success '... and loose copy of second object allows for partial recovery' '
118 git prune-packed &&
119 test_must_fail git cat-file blob $blob_2 > /dev/null &&
120 mv ${pack}.idx tmp &&
121 git hash-object -t blob -w file_2 &&
122 mv tmp ${pack}.idx &&
123 test_must_fail git cat-file blob $blob_1 > /dev/null &&
124 git cat-file blob $blob_2 > /dev/null &&
125 git cat-file blob $blob_3 > /dev/null
128 test_expect_success 'create corruption in header of first delta' '
129 create_new_pack &&
130 git prune-packed &&
131 do_corrupt_object $blob_2 0 < zero &&
132 git cat-file blob $blob_1 > /dev/null &&
133 test_must_fail git cat-file blob $blob_2 > /dev/null &&
134 test_must_fail git cat-file blob $blob_3 > /dev/null
137 test_expect_success '... but having a loose copy allows for full recovery' '
138 mv ${pack}.idx tmp &&
139 git hash-object -t blob -w file_2 &&
140 mv tmp ${pack}.idx &&
141 git cat-file blob $blob_1 > /dev/null &&
142 git cat-file blob $blob_2 > /dev/null &&
143 git cat-file blob $blob_3 > /dev/null
146 test_expect_success '... and then a repack "clears" the corruption' '
147 do_repack &&
148 git prune-packed &&
149 git verify-pack ${pack}.pack &&
150 git cat-file blob $blob_1 > /dev/null &&
151 git cat-file blob $blob_2 > /dev/null &&
152 git cat-file blob $blob_3 > /dev/null
155 test_expect_success 'create corruption in data of first delta' '
156 create_new_pack &&
157 git prune-packed &&
158 chmod +w ${pack}.pack &&
159 perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
160 git cat-file blob $blob_1 > /dev/null &&
161 test_must_fail git cat-file blob $blob_2 > /dev/null &&
162 test_must_fail git cat-file blob $blob_3 > /dev/null
165 test_expect_success '... but having a loose copy allows for full recovery' '
166 mv ${pack}.idx tmp &&
167 git hash-object -t blob -w file_2 &&
168 mv tmp ${pack}.idx &&
169 git cat-file blob $blob_1 > /dev/null &&
170 git cat-file blob $blob_2 > /dev/null &&
171 git cat-file blob $blob_3 > /dev/null
174 test_expect_success '... and then a repack "clears" the corruption' '
175 do_repack &&
176 git prune-packed &&
177 git verify-pack ${pack}.pack &&
178 git cat-file blob $blob_1 > /dev/null &&
179 git cat-file blob $blob_2 > /dev/null &&
180 git cat-file blob $blob_3 > /dev/null
183 test_expect_success 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' '
184 create_new_pack &&
185 git prune-packed &&
186 do_corrupt_object $blob_2 2 < zero &&
187 git cat-file blob $blob_1 > /dev/null &&
188 test_must_fail git cat-file blob $blob_2 > /dev/null &&
189 test_must_fail git cat-file blob $blob_3 > /dev/null
192 test_expect_success '... but having a loose copy allows for full recovery' '
193 mv ${pack}.idx tmp &&
194 git hash-object -t blob -w file_2 &&
195 mv tmp ${pack}.idx &&
196 git cat-file blob $blob_1 > /dev/null &&
197 git cat-file blob $blob_2 > /dev/null &&
198 git cat-file blob $blob_3 > /dev/null
201 test_expect_success '... and then a repack "clears" the corruption' '
202 do_repack &&
203 git prune-packed &&
204 git verify-pack ${pack}.pack &&
205 git cat-file blob $blob_1 > /dev/null &&
206 git cat-file blob $blob_2 > /dev/null &&
207 git cat-file blob $blob_3 > /dev/null
210 test_expect_success 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' '
211 create_new_pack --delta-base-offset &&
212 git prune-packed &&
213 do_corrupt_object $blob_2 2 < zero &&
214 git cat-file blob $blob_1 > /dev/null &&
215 test_must_fail git cat-file blob $blob_2 > /dev/null &&
216 test_must_fail git cat-file blob $blob_3 > /dev/null
219 test_expect_success '... but having a loose copy allows for full recovery' '
220 mv ${pack}.idx tmp &&
221 git hash-object -t blob -w file_2 &&
222 mv tmp ${pack}.idx &&
223 git cat-file blob $blob_1 > /dev/null &&
224 git cat-file blob $blob_2 > /dev/null &&
225 git cat-file blob $blob_3 > /dev/null
228 test_expect_success '... and then a repack "clears" the corruption' '
229 do_repack --delta-base-offset &&
230 git prune-packed &&
231 git verify-pack ${pack}.pack &&
232 git cat-file blob $blob_1 > /dev/null &&
233 git cat-file blob $blob_2 > /dev/null &&
234 git cat-file blob $blob_3 > /dev/null
237 test_expect_success 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' '
238 create_new_pack --delta-base-offset &&
239 git prune-packed &&
240 printf "\001" | do_corrupt_object $blob_2 2 &&
241 git cat-file blob $blob_1 > /dev/null &&
242 test_must_fail git cat-file blob $blob_2 > /dev/null &&
243 test_must_fail git cat-file blob $blob_3 > /dev/null
246 test_expect_success '... but having a loose copy allows for full recovery' '
247 mv ${pack}.idx tmp &&
248 git hash-object -t blob -w file_2 &&
249 mv tmp ${pack}.idx &&
250 git cat-file blob $blob_1 > /dev/null &&
251 git cat-file blob $blob_2 > /dev/null &&
252 git cat-file blob $blob_3 > /dev/null
255 test_expect_success '... and then a repack "clears" the corruption' '
256 do_repack --delta-base-offset &&
257 git prune-packed &&
258 git verify-pack ${pack}.pack &&
259 git cat-file blob $blob_1 > /dev/null &&
260 git cat-file blob $blob_2 > /dev/null &&
261 git cat-file blob $blob_3 > /dev/null
264 test_expect_success '... and a redundant pack allows for full recovery too' '
265 do_corrupt_object $blob_2 2 < zero &&
266 git cat-file blob $blob_1 > /dev/null &&
267 test_must_fail git cat-file blob $blob_2 > /dev/null &&
268 test_must_fail git cat-file blob $blob_3 > /dev/null &&
269 mv ${pack}.idx tmp &&
270 git hash-object -t blob -w file_1 &&
271 git hash-object -t blob -w file_2 &&
272 printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack &&
273 git prune-packed &&
274 mv tmp ${pack}.idx &&
275 git cat-file blob $blob_1 > /dev/null &&
276 git cat-file blob $blob_2 > /dev/null &&
277 git cat-file blob $blob_3 > /dev/null
280 test_expect_success 'corruption of delta base reference pointing to wrong object' '
281 create_new_pack --delta-base-offset &&
282 git prune-packed &&
283 printf "\220\033" | do_corrupt_object $blob_3 2 &&
284 git cat-file blob $blob_1 >/dev/null &&
285 git cat-file blob $blob_2 >/dev/null &&
286 test_must_fail git cat-file blob $blob_3 >/dev/null
289 test_expect_success '... but having a loose copy allows for full recovery' '
290 mv ${pack}.idx tmp &&
291 git hash-object -t blob -w file_3 &&
292 mv tmp ${pack}.idx &&
293 git cat-file blob $blob_1 > /dev/null &&
294 git cat-file blob $blob_2 > /dev/null &&
295 git cat-file blob $blob_3 > /dev/null
298 test_expect_success '... and then a repack "clears" the corruption' '
299 do_repack --delta-base-offset --no-reuse-delta &&
300 git prune-packed &&
301 git verify-pack ${pack}.pack &&
302 git cat-file blob $blob_1 > /dev/null &&
303 git cat-file blob $blob_2 > /dev/null &&
304 git cat-file blob $blob_3 > /dev/null
307 test_expect_success 'corrupting header to have too small output buffer fails unpack' '
308 create_new_pack &&
309 git prune-packed &&
310 printf "\262\001" | do_corrupt_object $blob_1 0 &&
311 test_must_fail git cat-file blob $blob_1 > /dev/null &&
312 test_must_fail git cat-file blob $blob_2 > /dev/null &&
313 test_must_fail git cat-file blob $blob_3 > /dev/null
316 # \0 - empty base
317 # \1 - one byte in result
318 # \1 - one literal byte (X)
319 test_expect_success 'apply good minimal delta' '
320 printf "\0\1\1X" > minimal_delta &&
321 test-tool delta -p /dev/null minimal_delta /dev/null
324 # \0 - empty base
325 # \1 - 1 byte in result
326 # \2 - two literal bytes (one too many)
327 test_expect_success 'apply delta with too many literal bytes' '
328 printf "\0\1\2XX" > too_big_literal &&
329 test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null
332 # \4 - four bytes in base
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 'apply delta with too many copied bytes' '
338 printf "\4\1\221\0\2" > too_big_copy &&
339 printf base >base &&
340 test_must_fail test-tool delta -p base too_big_copy /dev/null
343 # \0 - empty base
344 # \2 - two bytes in result
345 # \2 - two literal bytes (we are short one)
346 test_expect_success 'apply delta with too few literal bytes' '
347 printf "\0\2\2X" > truncated_delta &&
348 test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null
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 'apply delta with too few bytes in base' '
357 printf "\0\1\221\0\1" > truncated_base &&
358 test_must_fail test-tool delta -p /dev/null truncated_base /dev/null
361 # \4 - four bytes in base
362 # \2 - two bytes in result
363 # \1 - one literal byte (X)
364 # \221 - copy, one byte offset, one byte size
365 # (offset/size missing)
367 # Note that the literal byte is necessary to get past the uninteresting minimum
368 # delta size check.
369 test_expect_success 'apply delta with truncated copy parameters' '
370 printf "\4\2\1X\221" > truncated_copy_delta &&
371 printf base >base &&
372 test_must_fail test-tool delta -p base truncated_copy_delta /dev/null
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 'apply delta with trailing garbage literal' '
380 printf "\0\1\1X\1" > tail_garbage_literal &&
381 test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null
384 # \4 - four bytes in base
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 'apply delta with trailing garbage copy' '
391 printf "\4\1\1X\221\0\1" > tail_garbage_copy &&
392 printf base >base &&
393 test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null
396 # \0 - empty base
397 # \1 - one byte in result
398 # \1 - one literal byte (X)
399 # \0 - bogus opcode
400 test_expect_success 'apply delta with trailing garbage opcode' '
401 printf "\0\1\1X\0" > tail_garbage_opcode &&
402 test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null
405 test_done