1#!/bin/sh
2#
3# Copyright (c) 2008 Nicolas Pitre
4#
5
6test_description='resilience to pack corruptions with redundant objects'
7. ./test-lib.sh
8
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:
12#
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;
15#
16# 2) the bulk of object data is uncompressible so the text part remains
17# visible;
18#
19# 3) object header is always 2 bytes.
20
21create_test_files() {
22 test-genrandom "foo" 2000 > file_1 &&
23 test-genrandom "foo" 1800 > file_2 &&
24 test-genrandom "foo" 1800 > file_3 &&
25 echo " base " >> file_1 &&
26 echo " delta1 " >> file_2 &&
27 echo " delta delta2 " >> file_3 &&
28 test-genrandom "bar" 150 >> file_2 &&
29 test-genrandom "baz" 100 >> file_3
30}
31
32create_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
42}
43
44do_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}"
48}
49
50do_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 count=1 bs=1 conv=notrunc seek=$ofs &&
55 test_must_fail git verify-pack ${pack}.pack
56}
57
58test_expect_success \
59 'initial setup validation' \
60 'create_test_files &&
61 create_new_pack &&
62 git prune-packed &&
63 git cat-file blob $blob_1 > /dev/null &&
64 git cat-file blob $blob_2 > /dev/null &&
65 git cat-file blob $blob_3 > /dev/null'
66
67test_expect_success \
68 'create corruption in header of first object' \
69 'do_corrupt_object $blob_1 0 < /dev/zero &&
70 test_must_fail git cat-file blob $blob_1 > /dev/null &&
71 test_must_fail git cat-file blob $blob_2 > /dev/null &&
72 test_must_fail git cat-file blob $blob_3 > /dev/null'
73
74test_expect_success \
75 '... but having a loose copy allows for full recovery' \
76 'mv ${pack}.idx tmp &&
77 git hash-object -t blob -w file_1 &&
78 mv tmp ${pack}.idx &&
79 git cat-file blob $blob_1 > /dev/null &&
80 git cat-file blob $blob_2 > /dev/null &&
81 git cat-file blob $blob_3 > /dev/null'
82
83test_expect_success \
84 '... and loose copy of first delta allows for partial recovery' \
85 'git prune-packed &&
86 test_must_fail git cat-file blob $blob_2 > /dev/null &&
87 mv ${pack}.idx tmp &&
88 git hash-object -t blob -w file_2 &&
89 mv tmp ${pack}.idx &&
90 test_must_fail git cat-file blob $blob_1 > /dev/null &&
91 git cat-file blob $blob_2 > /dev/null &&
92 git cat-file blob $blob_3 > /dev/null'
93
94test_expect_success \
95 'create corruption in data of first object' \
96 'create_new_pack &&
97 git prune-packed &&
98 chmod +w ${pack}.pack &&
99 perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
100 test_must_fail git cat-file blob $blob_1 > /dev/null &&
101 test_must_fail git cat-file blob $blob_2 > /dev/null &&
102 test_must_fail git cat-file blob $blob_3 > /dev/null'
103
104test_expect_success \
105 '... but having a loose copy allows for full recovery' \
106 'mv ${pack}.idx tmp &&
107 git hash-object -t blob -w file_1 &&
108 mv tmp ${pack}.idx &&
109 git cat-file blob $blob_1 > /dev/null &&
110 git cat-file blob $blob_2 > /dev/null &&
111 git cat-file blob $blob_3 > /dev/null'
112
113test_expect_success \
114 '... and loose copy of second object allows for partial recovery' \
115 'git prune-packed &&
116 test_must_fail git cat-file blob $blob_2 > /dev/null &&
117 mv ${pack}.idx tmp &&
118 git hash-object -t blob -w file_2 &&
119 mv tmp ${pack}.idx &&
120 test_must_fail git cat-file blob $blob_1 > /dev/null &&
121 git cat-file blob $blob_2 > /dev/null &&
122 git cat-file blob $blob_3 > /dev/null'
123
124test_expect_success \
125 'create corruption in header of first delta' \
126 'create_new_pack &&
127 git prune-packed &&
128 do_corrupt_object $blob_2 0 < /dev/zero &&
129 git cat-file blob $blob_1 > /dev/null &&
130 test_must_fail git cat-file blob $blob_2 > /dev/null &&
131 test_must_fail git cat-file blob $blob_3 > /dev/null'
132
133test_expect_success \
134 '... but having a loose copy allows for full recovery' \
135 'mv ${pack}.idx tmp &&
136 git hash-object -t blob -w file_2 &&
137 mv tmp ${pack}.idx &&
138 git cat-file blob $blob_1 > /dev/null &&
139 git cat-file blob $blob_2 > /dev/null &&
140 git cat-file blob $blob_3 > /dev/null'
141
142test_expect_success \
143 '... and then a repack "clears" the corruption' \
144 'do_repack &&
145 git prune-packed &&
146 git verify-pack ${pack}.pack &&
147 git cat-file blob $blob_1 > /dev/null &&
148 git cat-file blob $blob_2 > /dev/null &&
149 git cat-file blob $blob_3 > /dev/null'
150
151test_expect_success \
152 'create corruption in data of first delta' \
153 'create_new_pack &&
154 git prune-packed &&
155 chmod +w ${pack}.pack &&
156 perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
157 git cat-file blob $blob_1 > /dev/null &&
158 test_must_fail git cat-file blob $blob_2 > /dev/null &&
159 test_must_fail git cat-file blob $blob_3 > /dev/null'
160
161test_expect_success \
162 '... but having a loose copy allows for full recovery' \
163 'mv ${pack}.idx tmp &&
164 git hash-object -t blob -w file_2 &&
165 mv tmp ${pack}.idx &&
166 git cat-file blob $blob_1 > /dev/null &&
167 git cat-file blob $blob_2 > /dev/null &&
168 git cat-file blob $blob_3 > /dev/null'
169
170test_expect_success \
171 '... and then a repack "clears" the corruption' \
172 'do_repack &&
173 git prune-packed &&
174 git verify-pack ${pack}.pack &&
175 git cat-file blob $blob_1 > /dev/null &&
176 git cat-file blob $blob_2 > /dev/null &&
177 git cat-file blob $blob_3 > /dev/null'
178
179test_expect_success \
180 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \
181 'create_new_pack &&
182 git prune-packed &&
183 do_corrupt_object $blob_2 2 < /dev/zero &&
184 git cat-file blob $blob_1 > /dev/null &&
185 test_must_fail git cat-file blob $blob_2 > /dev/null &&
186 test_must_fail git cat-file blob $blob_3 > /dev/null'
187
188test_expect_success \
189 '... but having a loose copy allows for full recovery' \
190 'mv ${pack}.idx tmp &&
191 git hash-object -t blob -w file_2 &&
192 mv tmp ${pack}.idx &&
193 git cat-file blob $blob_1 > /dev/null &&
194 git cat-file blob $blob_2 > /dev/null &&
195 git cat-file blob $blob_3 > /dev/null'
196
197test_expect_success \
198 '... and then a repack "clears" the corruption' \
199 'do_repack &&
200 git prune-packed &&
201 git verify-pack ${pack}.pack &&
202 git cat-file blob $blob_1 > /dev/null &&
203 git cat-file blob $blob_2 > /dev/null &&
204 git cat-file blob $blob_3 > /dev/null'
205
206test_expect_success \
207 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \
208 'create_new_pack --delta-base-offset &&
209 git prune-packed &&
210 do_corrupt_object $blob_2 2 < /dev/zero &&
211 git cat-file blob $blob_1 > /dev/null &&
212 test_must_fail git cat-file blob $blob_2 > /dev/null &&
213 test_must_fail git cat-file blob $blob_3 > /dev/null'
214
215test_expect_success \
216 '... but having a loose copy allows for full recovery' \
217 'mv ${pack}.idx tmp &&
218 git hash-object -t blob -w file_2 &&
219 mv tmp ${pack}.idx &&
220 git cat-file blob $blob_1 > /dev/null &&
221 git cat-file blob $blob_2 > /dev/null &&
222 git cat-file blob $blob_3 > /dev/null'
223
224test_expect_success \
225 '... and then a repack "clears" the corruption' \
226 'do_repack --delta-base-offset &&
227 git prune-packed &&
228 git verify-pack ${pack}.pack &&
229 git cat-file blob $blob_1 > /dev/null &&
230 git cat-file blob $blob_2 > /dev/null &&
231 git cat-file blob $blob_3 > /dev/null'
232
233test_expect_success \
234 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' \
235 'create_new_pack --delta-base-offset &&
236 git prune-packed &&
237 printf "\001" | do_corrupt_object $blob_2 2 &&
238 git cat-file blob $blob_1 > /dev/null &&
239 test_must_fail git cat-file blob $blob_2 > /dev/null &&
240 test_must_fail git cat-file blob $blob_3 > /dev/null'
241
242test_expect_success \
243 '... but having a loose copy allows for full recovery' \
244 'mv ${pack}.idx tmp &&
245 git hash-object -t blob -w file_2 &&
246 mv tmp ${pack}.idx &&
247 git cat-file blob $blob_1 > /dev/null &&
248 git cat-file blob $blob_2 > /dev/null &&
249 git cat-file blob $blob_3 > /dev/null'
250
251test_expect_success \
252 '... and then a repack "clears" the corruption' \
253 'do_repack --delta-base-offset &&
254 git prune-packed &&
255 git verify-pack ${pack}.pack &&
256 git cat-file blob $blob_1 > /dev/null &&
257 git cat-file blob $blob_2 > /dev/null &&
258 git cat-file blob $blob_3 > /dev/null'
259
260test_expect_success \
261 '... and a redundant pack allows for full recovery too' \
262 'do_corrupt_object $blob_2 2 < /dev/zero &&
263 git cat-file blob $blob_1 > /dev/null &&
264 test_must_fail git cat-file blob $blob_2 > /dev/null &&
265 test_must_fail git cat-file blob $blob_3 > /dev/null &&
266 mv ${pack}.idx tmp &&
267 git hash-object -t blob -w file_1 &&
268 git hash-object -t blob -w file_2 &&
269 printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack &&
270 git prune-packed &&
271 mv tmp ${pack}.idx &&
272 git cat-file blob $blob_1 > /dev/null &&
273 git cat-file blob $blob_2 > /dev/null &&
274 git cat-file blob $blob_3 > /dev/null'
275
276test_done