| 1 | #!/bin/sh |
| 2 | # |
| 3 | # Copyright (c) 2007 Nicolas Pitre |
| 4 | # |
| 5 | |
| 6 | test_description='pack index with 64-bit offsets and object CRC' |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | |
| 10 | test_expect_success 'setup' ' |
| 11 | rawsz=$(test_oid rawsz) && |
| 12 | rm -rf .git && |
| 13 | git init && |
| 14 | git config pack.threads 1 && |
| 15 | i=1 && |
| 16 | while test $i -le 100 |
| 17 | do |
| 18 | iii=$(printf "%03i" $i) && |
| 19 | test-tool genrandom "bar" 200 > wide_delta_$iii && |
| 20 | test-tool genrandom "baz $iii" 50 >> wide_delta_$iii && |
| 21 | test-tool genrandom "foo"$i 100 > deep_delta_$iii && |
| 22 | test-tool genrandom "foo"$(expr $i + 1) 100 >> deep_delta_$iii && |
| 23 | test-tool genrandom "foo"$(expr $i + 2) 100 >> deep_delta_$iii && |
| 24 | echo $iii >file_$iii && |
| 25 | test-tool genrandom "$iii" 8192 >>file_$iii && |
| 26 | git update-index --add file_$iii deep_delta_$iii wide_delta_$iii && |
| 27 | i=$(expr $i + 1) || return 1 |
| 28 | done && |
| 29 | { echo 101 && test-tool genrandom 100 8192; } >file_101 && |
| 30 | git update-index --add file_101 && |
| 31 | tree=$(git write-tree) && |
| 32 | commit=$(git commit-tree $tree </dev/null) && { |
| 33 | echo $tree && |
| 34 | git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/" |
| 35 | } >obj-list && |
| 36 | git update-ref HEAD $commit |
| 37 | ' |
| 38 | |
| 39 | test_expect_success 'pack-objects with index version 1' ' |
| 40 | pack1=$(git pack-objects --index-version=1 test-1 <obj-list) && |
| 41 | git verify-pack -v "test-1-${pack1}.pack" |
| 42 | ' |
| 43 | |
| 44 | test_expect_success 'pack-objects with index version 2' ' |
| 45 | pack2=$(git pack-objects --index-version=2 test-2 <obj-list) && |
| 46 | git verify-pack -v "test-2-${pack2}.pack" |
| 47 | ' |
| 48 | |
| 49 | test_expect_success 'both packs should be identical' ' |
| 50 | cmp "test-1-${pack1}.pack" "test-2-${pack2}.pack" |
| 51 | ' |
| 52 | |
| 53 | test_expect_success 'index v1 and index v2 should be different' ' |
| 54 | ! cmp "test-1-${pack1}.idx" "test-2-${pack2}.idx" |
| 55 | ' |
| 56 | |
| 57 | test_expect_success 'index-pack with index version 1' ' |
| 58 | git index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack" |
| 59 | ' |
| 60 | |
| 61 | test_expect_success 'index-pack with index version 2' ' |
| 62 | git index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack" |
| 63 | ' |
| 64 | |
| 65 | test_expect_success 'index-pack results should match pack-objects ones' ' |
| 66 | cmp "test-1-${pack1}.idx" "1.idx" && |
| 67 | cmp "test-2-${pack2}.idx" "2.idx" |
| 68 | ' |
| 69 | |
| 70 | test_expect_success 'index-pack --verify on index version 1' ' |
| 71 | git index-pack --verify "test-1-${pack1}.pack" |
| 72 | ' |
| 73 | |
| 74 | test_expect_success 'index-pack --verify on index version 2' ' |
| 75 | git index-pack --verify "test-2-${pack2}.pack" |
| 76 | ' |
| 77 | |
| 78 | test_expect_success 'pack-objects --index-version=2, is not accepted' ' |
| 79 | test_must_fail git pack-objects --index-version=2, test-3 <obj-list |
| 80 | ' |
| 81 | |
| 82 | test_expect_success 'index v2: force some 64-bit offsets with pack-objects' ' |
| 83 | pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list) |
| 84 | ' |
| 85 | |
| 86 | if msg=$(git verify-pack -v "test-3-${pack3}.pack" 2>&1) || |
| 87 | ! (echo "$msg" | grep "pack too large .* off_t") |
| 88 | then |
| 89 | test_set_prereq OFF64_T |
| 90 | else |
| 91 | say "# skipping tests concerning 64-bit offsets" |
| 92 | fi |
| 93 | |
| 94 | test_expect_success OFF64_T 'index v2: verify a pack with some 64-bit offsets' ' |
| 95 | git verify-pack -v "test-3-${pack3}.pack" |
| 96 | ' |
| 97 | |
| 98 | test_expect_success OFF64_T '64-bit offsets: should be different from previous index v2 results' ' |
| 99 | ! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx" |
| 100 | ' |
| 101 | |
| 102 | test_expect_success OFF64_T 'index v2: force some 64-bit offsets with index-pack' ' |
| 103 | git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack" |
| 104 | ' |
| 105 | |
| 106 | test_expect_success OFF64_T '64-bit offsets: index-pack result should match pack-objects one' ' |
| 107 | cmp "test-3-${pack3}.idx" "3.idx" |
| 108 | ' |
| 109 | |
| 110 | test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2 (cheat)' ' |
| 111 | # This cheats by knowing which lower offset should still be encoded |
| 112 | # in 64-bit representation. |
| 113 | git index-pack --verify --index-version=2,0x40000 "test-3-${pack3}.pack" |
| 114 | ' |
| 115 | |
| 116 | test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2' ' |
| 117 | git index-pack --verify "test-3-${pack3}.pack" |
| 118 | ' |
| 119 | |
| 120 | # returns the object number for given object in given pack index |
| 121 | index_obj_nr() |
| 122 | { |
| 123 | idx_file=$1 |
| 124 | object_sha1=$2 |
| 125 | nr=0 |
| 126 | git show-index < $idx_file | |
| 127 | while read offs sha1 extra |
| 128 | do |
| 129 | nr=$(($nr + 1)) |
| 130 | test "$sha1" = "$object_sha1" || continue |
| 131 | echo "$(($nr - 1))" |
| 132 | break |
| 133 | done |
| 134 | } |
| 135 | |
| 136 | # returns the pack offset for given object as found in given pack index |
| 137 | index_obj_offset() |
| 138 | { |
| 139 | idx_file=$1 |
| 140 | object_sha1=$2 |
| 141 | git show-index < $idx_file | grep $object_sha1 | |
| 142 | ( read offs extra && echo "$offs" ) |
| 143 | } |
| 144 | |
| 145 | test_expect_success '[index v1] 1) stream pack to repository' ' |
| 146 | git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" && |
| 147 | git prune-packed && |
| 148 | git count-objects | ( read nr rest && test "$nr" -eq 1 ) && |
| 149 | cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && |
| 150 | cmp "test-1-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx" |
| 151 | ' |
| 152 | |
| 153 | test_expect_success \ |
| 154 | '[index v1] 2) create a stealth corruption in a delta base reference' ' |
| 155 | # This test assumes file_101 is a delta smaller than 16 bytes. |
| 156 | # It should be against file_100 but we substitute its base for file_099 |
| 157 | sha1_101=$(git hash-object file_101) && |
| 158 | sha1_099=$(git hash-object file_099) && |
| 159 | offs_101=$(index_obj_offset 1.idx $sha1_101) && |
| 160 | nr_099=$(index_obj_nr 1.idx $sha1_099) && |
| 161 | chmod +w ".git/objects/pack/pack-${pack1}.pack" && |
| 162 | recordsz=$((rawsz + 4)) && |
| 163 | dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \ |
| 164 | if=".git/objects/pack/pack-${pack1}.idx" \ |
| 165 | skip=$((4 + 256 * 4 + $nr_099 * recordsz)) \ |
| 166 | bs=1 count=$rawsz conv=notrunc && |
| 167 | git cat-file blob $sha1_101 > file_101_foo1 |
| 168 | ' |
| 169 | |
| 170 | test_expect_success \ |
| 171 | '[index v1] 3) corrupted delta happily returned wrong data' ' |
| 172 | test -f file_101_foo1 && ! cmp file_101 file_101_foo1 |
| 173 | ' |
| 174 | |
| 175 | test_expect_success \ |
| 176 | '[index v1] 4) confirm that the pack is actually corrupted' ' |
| 177 | test_must_fail git fsck --full $commit |
| 178 | ' |
| 179 | |
| 180 | test_expect_success \ |
| 181 | '[index v1] 5) pack-objects happily reuses corrupted data' ' |
| 182 | pack4=$(git pack-objects test-4 <obj-list) && |
| 183 | test -f "test-4-${pack4}.pack" |
| 184 | ' |
| 185 | |
| 186 | test_expect_success '[index v1] 6) newly created pack is BAD !' ' |
| 187 | test_must_fail git verify-pack -v "test-4-${pack4}.pack" |
| 188 | ' |
| 189 | |
| 190 | test_expect_success '[index v2] 1) stream pack to repository' ' |
| 191 | rm -f .git/objects/pack/* && |
| 192 | git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && |
| 193 | git prune-packed && |
| 194 | git count-objects | ( read nr rest && test "$nr" -eq 1 ) && |
| 195 | cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && |
| 196 | cmp "test-2-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx" |
| 197 | ' |
| 198 | |
| 199 | test_expect_success \ |
| 200 | '[index v2] 2) create a stealth corruption in a delta base reference' ' |
| 201 | # This test assumes file_101 is a delta smaller than 16 bytes. |
| 202 | # It should be against file_100 but we substitute its base for file_099 |
| 203 | sha1_101=$(git hash-object file_101) && |
| 204 | sha1_099=$(git hash-object file_099) && |
| 205 | offs_101=$(index_obj_offset 1.idx $sha1_101) && |
| 206 | nr_099=$(index_obj_nr 1.idx $sha1_099) && |
| 207 | chmod +w ".git/objects/pack/pack-${pack1}.pack" && |
| 208 | dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \ |
| 209 | if=".git/objects/pack/pack-${pack1}.idx" \ |
| 210 | skip=$((8 + 256 * 4 + $nr_099 * rawsz)) \ |
| 211 | bs=1 count=$rawsz conv=notrunc && |
| 212 | git cat-file blob $sha1_101 > file_101_foo2 |
| 213 | ' |
| 214 | |
| 215 | test_expect_success \ |
| 216 | '[index v2] 3) corrupted delta happily returned wrong data' ' |
| 217 | test -f file_101_foo2 && ! cmp file_101 file_101_foo2 |
| 218 | ' |
| 219 | |
| 220 | test_expect_success \ |
| 221 | '[index v2] 4) confirm that the pack is actually corrupted' ' |
| 222 | test_must_fail git fsck --full $commit |
| 223 | ' |
| 224 | |
| 225 | test_expect_success \ |
| 226 | '[index v2] 5) pack-objects refuses to reuse corrupted data' ' |
| 227 | test_must_fail git pack-objects test-5 <obj-list && |
| 228 | test_must_fail git pack-objects --no-reuse-object test-6 <obj-list |
| 229 | ' |
| 230 | |
| 231 | test_expect_success \ |
| 232 | '[index v2] 6) verify-pack detects CRC mismatch' ' |
| 233 | rm -f .git/objects/pack/* && |
| 234 | git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && |
| 235 | git verify-pack ".git/objects/pack/pack-${pack1}.pack" && |
| 236 | obj=$(git hash-object file_001) && |
| 237 | nr=$(index_obj_nr ".git/objects/pack/pack-${pack1}.idx" $obj) && |
| 238 | chmod +w ".git/objects/pack/pack-${pack1}.idx" && |
| 239 | printf xxxx | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ |
| 240 | bs=1 count=4 seek=$((8 + 256 * 4 + $(wc -l <obj-list) * rawsz + $nr * 4)) && |
| 241 | ( while read obj |
| 242 | do git cat-file -p $obj >/dev/null || exit 1 |
| 243 | done <obj-list ) && |
| 244 | test_must_fail git verify-pack ".git/objects/pack/pack-${pack1}.pack" |
| 245 | ' |
| 246 | |
| 247 | test_expect_success 'running index-pack in the object store' ' |
| 248 | rm -f .git/objects/pack/* && |
| 249 | cp test-1-${pack1}.pack .git/objects/pack/pack-${pack1}.pack && |
| 250 | ( |
| 251 | cd .git/objects/pack && |
| 252 | git index-pack pack-${pack1}.pack |
| 253 | ) && |
| 254 | test -f .git/objects/pack/pack-${pack1}.idx |
| 255 | ' |
| 256 | |
| 257 | test_expect_success 'index-pack --strict warns upon missing tagger in tag' ' |
| 258 | sha=$(git rev-parse HEAD) && |
| 259 | cat >wrong-tag <<EOF && |
| 260 | object $sha |
| 261 | type commit |
| 262 | tag guten tag |
| 263 | |
| 264 | This is an invalid tag. |
| 265 | EOF |
| 266 | |
| 267 | tag=$(git hash-object -t tag -w --stdin --literally <wrong-tag) && |
| 268 | pack1=$(echo $tag $sha | git pack-objects tag-test) && |
| 269 | echo remove tag object && |
| 270 | thirtyeight=${tag#??} && |
| 271 | rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight && |
| 272 | git index-pack --strict tag-test-${pack1}.pack 2>err && |
| 273 | test_grep "^warning:.* expected .tagger. line" err |
| 274 | ' |
| 275 | |
| 276 | test_expect_success 'index-pack --fsck-objects also warns upon missing tagger in tag' ' |
| 277 | git index-pack --fsck-objects tag-test-${pack1}.pack 2>err && |
| 278 | test_grep "^warning:.* expected .tagger. line" err |
| 279 | ' |
| 280 | |
| 281 | test_expect_success 'index-pack -v --stdin produces progress for both phases' ' |
| 282 | pack=$(git pack-objects --all pack </dev/null) && |
| 283 | GIT_PROGRESS_DELAY=0 git index-pack -v --stdin <pack-$pack.pack 2>err && |
| 284 | test_grep "Receiving objects" err && |
| 285 | test_grep "Resolving deltas" err |
| 286 | ' |
| 287 | |
| 288 | test_expect_success 'too-large packs report the breach' ' |
| 289 | pack=$(git pack-objects --all pack </dev/null) && |
| 290 | sz="$(test_file_size pack-$pack.pack)" && |
| 291 | test "$sz" -gt 20 && |
| 292 | test_must_fail git index-pack --max-input-size=20 pack-$pack.pack 2>err && |
| 293 | test_grep "maximum allowed size (20 bytes)" err |
| 294 | ' |
| 295 | |
| 296 | # git-index-pack(1) uses the default hash algorithm outside of the repository, |
| 297 | # and it has no way to tell it otherwise. So we can only run this test with the |
| 298 | # default hash algorithm, as it would otherwise fail to parse the tree. |
| 299 | test_expect_success DEFAULT_HASH_ALGORITHM 'index-pack --fsck-objects outside of a repo' ' |
| 300 | test_when_finished "rm -rf repo" && |
| 301 | git init repo && |
| 302 | ( |
| 303 | cd repo && |
| 304 | printf "100644 blob $(test_oid 001)\t.gitattributes\n" >tree && |
| 305 | git mktree --missing <tree >tree-oid && |
| 306 | git pack-objects <tree-oid pack && |
| 307 | test_must_fail nongit git index-pack --fsck-objects "$(pwd)"/pack-*.pack 2>err && |
| 308 | test_grep "cannot perform queued object checks outside of a repository" err |
| 309 | ) |
| 310 | ' |
| 311 | |
| 312 | test_done |