#!/bin/sh # # Copyright (c) 2007 Nicolas Pitre # global test_description := ''pack index with 64-bit offsets and object CRC'' source ./test-lib.sh test_expect_success \ 'setup' \ 'rm -rf .git && git init && git config pack.threads 1 && i=1 && while test $i -le 100 do iii=$(printf '%03i' $i) test-genrandom "bar" 200 > wide_delta_$iii && test-genrandom "baz $iii" 50 >> wide_delta_$iii && test-genrandom "foo"$i 100 > deep_delta_$iii && test-genrandom "foo"$(expr $i + 1) 100 >> deep_delta_$iii && test-genrandom "foo"$(expr $i + 2) 100 >> deep_delta_$iii && echo $iii >file_$iii && test-genrandom "$iii" 8192 >>file_$iii && git update-index --add file_$iii deep_delta_$iii wide_delta_$iii && i=$(expr $i + 1) || return 1 done && { echo 101 && test-genrandom 100 8192; } >file_101 && git update-index --add file_101 && tree=$(git write-tree) && commit=$(git commit-tree $tree obj-list && git update-ref HEAD $commit' test_expect_success \ 'pack-objects with index version 1' \ 'pack1=$(git pack-objects --index-version=1 test-1 !1] || ! shell {echo $msg | grep "pack too large .* off_t"} { test_set_prereq OFF64_T } else { say "# skipping tests concerning 64-bit offsets" } test_expect_success OFF64_T \ 'index v2: verify a pack with some 64-bit offsets' \ 'git verify-pack -v "test-3-${pack3}.pack"' test_expect_success OFF64_T \ '64-bit offsets: should be different from previous index v2 results' \ '! cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"' test_expect_success OFF64_T \ 'index v2: force some 64-bit offsets with index-pack' \ 'git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"' test_expect_success OFF64_T \ '64-bit offsets: index-pack result should match pack-objects one' \ 'cmp "test-3-${pack3}.idx" "3.idx"' test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2 (cheat)' ' # This cheats by knowing which lower offset should still be encoded # in 64-bit representation. git index-pack --verify --index-version=2,0x40000 "test-3-${pack3}.pack" ' test_expect_success OFF64_T 'index-pack --verify on 64-bit offset v2' ' git index-pack --verify "test-3-${pack3}.pack" ' # returns the object number for given object in given pack index proc index_obj_nr { global idx_file := $1 global object_sha1 := $2 global nr := '0' git show-index < $idx_file | while read offs sha1 extra { global nr := $($nr + 1) test $sha1 = $object_sha1 || continue echo "$($nr - 1)" break } } # returns the pack offset for given object as found in given pack index proc index_obj_offset { global idx_file := $1 global object_sha1 := $2 git show-index < $idx_file | grep $object_sha1 | shell { read offs extra && echo $offs } } test_expect_success \ '[index v1] 1) stream pack to repository' \ 'git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" && git prune-packed && git count-objects | ( read nr rest && test "$nr" -eq 1 ) && cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && cmp "test-1-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"' test_expect_success \ '[index v1] 2) create a stealth corruption in a delta base reference' \ '# This test assumes file_101 is a delta smaller than 16 bytes. # It should be against file_100 but we substitute its base for file_099 sha1_101=$(git hash-object file_101) && sha1_099=$(git hash-object file_099) && offs_101=$(index_obj_offset 1.idx $sha1_101) && nr_099=$(index_obj_nr 1.idx $sha1_099) && chmod +w ".git/objects/pack/pack-${pack1}.pack" && dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($offs_101 + 1)) \ if=".git/objects/pack/pack-${pack1}.idx" \ skip=$((4 + 256 * 4 + $nr_099 * 24)) \ bs=1 count=20 conv=notrunc && git cat-file blob $sha1_101 > file_101_foo1' test_expect_success \ '[index v1] 3) corrupted delta happily returned wrong data' \ 'test -f file_101_foo1 && ! cmp file_101 file_101_foo1' test_expect_success \ '[index v1] 4) confirm that the pack is actually corrupted' \ 'test_must_fail git fsck --full $commit' test_expect_success \ '[index v1] 5) pack-objects happily reuses corrupted data' \ 'pack4=$(git pack-objects test-4 file_101_foo2' test_expect_success \ '[index v2] 3) corrupted delta happily returned wrong data' \ 'test -f file_101_foo2 && ! cmp file_101 file_101_foo2' test_expect_success \ '[index v2] 4) confirm that the pack is actually corrupted' \ 'test_must_fail git fsck --full $commit' test_expect_success \ '[index v2] 5) pack-objects refuses to reuse corrupted data' \ 'test_must_fail git pack-objects test-5 /dev/null || exit 1 done wrong-tag <err && grep "^warning:.* expected .tagger. line" err ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"pack index with 64-bit offsets and object CRC">)} spids: [13] ) ] spids: [13] ) (C {(.)} {(./test-lib.sh)}) (C {(test_expect_success)} {(SQ )} { (SQ <"rm -rf .git &&\n"> <" git init &&\n"> <" git config pack.threads 1 &&\n"> <" i=1 &&\n"> <" while test $i -le 100\n"> <" do\n"> <" iii=$(printf "> ) (Lit_Other "%") (03i) (SQ <" $i)\n"> <" test-genrandom \"bar\" 200 > wide_delta_$iii &&\n"> <" test-genrandom \"baz $iii\" 50 >> wide_delta_$iii &&\n"> <" test-genrandom \"foo\"$i 100 > deep_delta_$iii &&\n"> <" test-genrandom \"foo\"$(expr $i + 1) 100 >> deep_delta_$iii &&\n"> <" test-genrandom \"foo\"$(expr $i + 2) 100 >> deep_delta_$iii &&\n"> <" echo $iii >file_$iii &&\n"> <" test-genrandom \"$iii\" 8192 >>file_$iii &&\n"> <" git update-index --add file_$iii deep_delta_$iii wide_delta_$iii &&\n"> <" i=$(expr $i + 1) || return 1\n"> <" done &&\n"> <" { echo 101 && test-genrandom 100 8192; } >file_101 &&\n"> <" git update-index --add file_101 &&\n"> <" tree=$(git write-tree) &&\n"> <" commit=$(git commit-tree $tree <"\t echo $tree &&\n"> <"\t git ls-tree $tree | sed -e \"s/.* \\\\([0-9a-f]*\\\\)\t.*/\\\\1/\"\n"> <" } >obj-list &&\n"> <" git update-ref HEAD $commit"> ) } ) (C {(test_expect_success)} {(SQ <"pack-objects with index version 1">)} { (SQ <"pack1=$(git pack-objects --index-version=1 test-1 <" git verify-pack -v \"test-1-${pack1}.pack\""> ) } ) (C {(test_expect_success)} {(SQ <"pack-objects with index version 2">)} { (SQ <"pack2=$(git pack-objects --index-version=2 test-2 <" git verify-pack -v \"test-2-${pack2}.pack\""> ) } ) (C {(test_expect_success)} {(SQ <"both packs should be identical">)} {(SQ <"cmp \"test-1-${pack1}.pack\" \"test-2-${pack2}.pack\"">)} ) (C {(test_expect_success)} {(SQ <"index v1 and index v2 should be different">)} {(SQ <"! cmp \"test-1-${pack1}.idx\" \"test-2-${pack2}.idx\"">)} ) (C {(test_expect_success)} {(SQ <"index-pack with index version 1">)} {(SQ <"git index-pack --index-version=1 -o 1.idx \"test-1-${pack1}.pack\"">)} ) (C {(test_expect_success)} {(SQ <"index-pack with index version 2">)} {(SQ <"git index-pack --index-version=2 -o 2.idx \"test-1-${pack1}.pack\"">)} ) (C {(test_expect_success)} {(SQ <"index-pack results should match pack-objects ones">)} { (SQ <"cmp \"test-1-${pack1}.idx\" \"1.idx\" &&\n"> <" cmp \"test-2-${pack2}.idx\" \"2.idx\""> ) } ) (C {(test_expect_success)} {(SQ <"index-pack --verify on index version 1">)} {(SQ <"\n"> <"\tgit index-pack --verify \"test-1-${pack1}.pack\"\n">)} ) (C {(test_expect_success)} {(SQ <"index-pack --verify on index version 2">)} {(SQ <"\n"> <"\tgit index-pack --verify \"test-2-${pack2}.pack\"\n">)} ) (C {(test_expect_success)} {(SQ <"pack-objects --index-version=2, is not accepted">)} {(SQ <"test_must_fail git pack-objects --index-version=2, test-3 )} ) (C {(test_expect_success)} {(SQ <"index v2: force some 64-bit offsets with pack-objects">)} {(SQ <"pack3=$(git pack-objects --index-version=2,0x40000 test-3 )} ) (If arms: [ (if_arm cond: [ (AndOr children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:msg) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (SimpleCommand words: [ {(git)} {(verify-pack)} {(-v)} {(DQ (test-3-) (${ VSub_Name pack3) (.pack))} ] redirects: [ (Redir op_id: Redir_GreatAnd fd: 2 arg_word: {(1)} spids: [247] ) ] ) ] ) left_token: spids: [232 249] ) } spids: [231] ) ] spids: [231] ) (Pipeline children: [ (Subshell child: (Pipeline children: [ (C {(echo)} {(DQ ($ VSub_Name "$msg"))}) (C {(grep)} {(DQ ("pack too large .* off_t"))}) ] negated: False ) spids: [256 270] ) ] negated: True ) ] op_id: Op_DPipe ) ] action: [(C {(test_set_prereq)} {(OFF64_T)})] spids: [-1 272] ) ] else_action: [(C {(say)} {(DQ ("# skipping tests concerning 64-bit offsets"))})] spids: [279 288] ) (C {(test_expect_success)} {(OFF64_T)} {(SQ <"index v2: verify a pack with some 64-bit offsets">)} {(SQ <"git verify-pack -v \"test-3-${pack3}.pack\"">)} ) (C {(test_expect_success)} {(OFF64_T)} {(SQ <"64-bit offsets: should be different from previous index v2 results">)} {(SQ <"! cmp \"test-2-${pack2}.idx\" \"test-3-${pack3}.idx\"">)} ) (C {(test_expect_success)} {(OFF64_T)} {(SQ <"index v2: force some 64-bit offsets with index-pack">)} {(SQ <"git index-pack --index-version=2,0x40000 -o 3.idx \"test-1-${pack1}.pack\"">)} ) (C {(test_expect_success)} {(OFF64_T)} {(SQ <"64-bit offsets: index-pack result should match pack-objects one">)} {(SQ <"cmp \"test-3-${pack3}.idx\" \"3.idx\"">)} ) (C {(test_expect_success)} {(OFF64_T)} {(SQ <"index-pack --verify on 64-bit offset v2 (cheat)">)} { (SQ <"\n"> <"\t# This cheats by knowing which lower offset should still be encoded\n"> <"\t# in 64-bit representation.\n"> <"\tgit index-pack --verify --index-version=2,0x40000 \"test-3-${pack3}.pack\"\n"> ) } ) (C {(test_expect_success)} {(OFF64_T)} {(SQ <"index-pack --verify on 64-bit offset v2">)} {(SQ <"\n"> <"\tgit index-pack --verify \"test-3-${pack3}.pack\"\n">)} ) (FuncDef name: index_obj_nr body: (BraceGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:idx_file) op: Equal rhs: {($ VSub_Number "$1")} spids: [399] ) ] spids: [399] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:object_sha1) op: Equal rhs: {($ VSub_Number "$2")} spids: [403] ) ] spids: [403] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:nr) op:Equal rhs:{(0)} spids:[407])] spids: [407] ) (Pipeline children: [ (SimpleCommand words: [{(git)} {(show-index)}] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {($ VSub_Name "$idx_file")} spids: [415] ) ] ) (While cond: [(C {(read)} {(offs)} {(sha1)} {(extra)})] body: (DoGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:nr) op: Equal rhs: { (ArithSubPart anode: (ArithBinary op_id: Arith_Plus left: (ArithWord w:{($ VSub_Name "$nr")}) right: (ArithWord w:{(Lit_Digits 1)}) ) spids: [437 444] ) } spids: [436] ) ] spids: [436] ) (AndOr children: [ (C {(test)} {(DQ ($ VSub_Name "$sha1"))} {(Lit_Other "=")} {(DQ ($ VSub_Name "$object_sha1"))} ) (ControlFlow token: ) ] op_id: Op_DPipe ) (C {(echo)} { (DQ (ArithSubPart anode: (ArithBinary op_id: Arith_Minus left: (ArithWord w:{($ VSub_Name "$nr")}) right: (ArithWord w:{(Lit_Digits 1)}) ) spids: [467 474] ) ) } ) (ControlFlow token:) ] spids: [433 481] ) ) ] negated: False ) ] spids: [396] ) spids: [392 395] ) (FuncDef name: index_obj_offset body: (BraceGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:idx_file) op: Equal rhs: {($ VSub_Number "$1")} spids: [496] ) ] spids: [496] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:object_sha1) op: Equal rhs: {($ VSub_Number "$2")} spids: [500] ) ] spids: [500] ) (Pipeline children: [ (SimpleCommand words: [{(git)} {(show-index)}] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {($ VSub_Name "$idx_file")} spids: [508] ) ] ) (C {(grep)} {($ VSub_Name "$object_sha1")}) (Subshell child: (AndOr children: [ (C {(read)} {(offs)} {(extra)}) (C {(echo)} {(DQ ($ VSub_Name "$offs"))}) ] op_id: Op_DAmp ) spids: [521 537] ) ] negated: False ) ] spids: [493] ) spids: [489 492] ) (C {(test_expect_success)} {(SQ <"[index v1] 1) stream pack to repository">)} { (SQ <"git index-pack --index-version=1 --stdin < \"test-1-${pack1}.pack\" &&\n"> <" git prune-packed &&\n"> <" git count-objects | ( read nr rest && test \"$nr\" -eq 1 ) &&\n"> <" cmp \"test-1-${pack1}.pack\" \".git/objects/pack/pack-${pack1}.pack\" &&\n"> <" cmp \"test-1-${pack1}.idx\" \".git/objects/pack/pack-${pack1}.idx\""> ) } ) (C {(test_expect_success)} {(SQ <"[index v1] 2) create a stealth corruption in a delta base reference">)} { (SQ <"# This test assumes file_101 is a delta smaller than 16 bytes.\n"> <" # It should be against file_100 but we substitute its base for file_099\n"> <" sha1_101=$(git hash-object file_101) &&\n"> <" sha1_099=$(git hash-object file_099) &&\n"> <" offs_101=$(index_obj_offset 1.idx $sha1_101) &&\n"> <" nr_099=$(index_obj_nr 1.idx $sha1_099) &&\n"> <" chmod +w \".git/objects/pack/pack-${pack1}.pack\" &&\n"> <" dd of=\".git/objects/pack/pack-${pack1}.pack\" seek=$(($offs_101 + 1)) \\\n"> <" if=\".git/objects/pack/pack-${pack1}.idx\" \\\n"> <" skip=$((4 + 256 * 4 + $nr_099 * 24)) \\\n"> <" bs=1 count=20 conv=notrunc &&\n"> <" git cat-file blob $sha1_101 > file_101_foo1"> ) } ) (C {(test_expect_success)} {(SQ <"[index v1] 3) corrupted delta happily returned wrong data">)} {(SQ <"test -f file_101_foo1 && ! cmp file_101 file_101_foo1">)} ) (C {(test_expect_success)} {(SQ <"[index v1] 4) confirm that the pack is actually corrupted">)} {(SQ <"test_must_fail git fsck --full $commit">)} ) (C {(test_expect_success)} {(SQ <"[index v1] 5) pack-objects happily reuses corrupted data">)} { (SQ <"pack4=$(git pack-objects test-4 <" test -f \"test-4-${pack4}.pack\""> ) } ) (C {(test_expect_success)} {(SQ <"[index v1] 6) newly created pack is BAD !">)} {(SQ <"test_must_fail git verify-pack -v \"test-4-${pack4}.pack\"">)} ) (C {(test_expect_success)} {(SQ <"[index v2] 1) stream pack to repository">)} { (SQ <"rm -f .git/objects/pack/* &&\n"> <" git index-pack --index-version=2 --stdin < \"test-1-${pack1}.pack\" &&\n"> <" git prune-packed &&\n"> <" git count-objects | ( read nr rest && test \"$nr\" -eq 1 ) &&\n"> <" cmp \"test-1-${pack1}.pack\" \".git/objects/pack/pack-${pack1}.pack\" &&\n"> <" cmp \"test-2-${pack1}.idx\" \".git/objects/pack/pack-${pack1}.idx\""> ) } ) (C {(test_expect_success)} {(SQ <"[index v2] 2) create a stealth corruption in a delta base reference">)} { (SQ <"# This test assumes file_101 is a delta smaller than 16 bytes.\n"> <" # It should be against file_100 but we substitute its base for file_099\n"> <" sha1_101=$(git hash-object file_101) &&\n"> <" sha1_099=$(git hash-object file_099) &&\n"> <" offs_101=$(index_obj_offset 1.idx $sha1_101) &&\n"> <" nr_099=$(index_obj_nr 1.idx $sha1_099) &&\n"> <" chmod +w \".git/objects/pack/pack-${pack1}.pack\" &&\n"> <" dd of=\".git/objects/pack/pack-${pack1}.pack\" seek=$(($offs_101 + 1)) \\\n"> <" if=\".git/objects/pack/pack-${pack1}.idx\" \\\n"> <" skip=$((8 + 256 * 4 + $nr_099 * 20)) \\\n"> <" bs=1 count=20 conv=notrunc &&\n"> <" git cat-file blob $sha1_101 > file_101_foo2"> ) } ) (C {(test_expect_success)} {(SQ <"[index v2] 3) corrupted delta happily returned wrong data">)} {(SQ <"test -f file_101_foo2 && ! cmp file_101 file_101_foo2">)} ) (C {(test_expect_success)} {(SQ <"[index v2] 4) confirm that the pack is actually corrupted">)} {(SQ <"test_must_fail git fsck --full $commit">)} ) (C {(test_expect_success)} {(SQ <"[index v2] 5) pack-objects refuses to reuse corrupted data">)} { (SQ <"test_must_fail git pack-objects test-5 <" test_must_fail git pack-objects --no-reuse-object test-6 ) } ) (C {(test_expect_success)} {(SQ <"[index v2] 6) verify-pack detects CRC mismatch">)} { (SQ <"rm -f .git/objects/pack/* &&\n"> <" git index-pack --index-version=2 --stdin < \"test-1-${pack1}.pack\" &&\n"> <" git verify-pack \".git/objects/pack/pack-${pack1}.pack\" &&\n"> <" obj=$(git hash-object file_001) &&\n"> <" nr=$(index_obj_nr \".git/objects/pack/pack-${pack1}.idx\" $obj) &&\n"> <" chmod +w \".git/objects/pack/pack-${pack1}.idx\" &&\n"> <" printf xxxx | dd of=\".git/objects/pack/pack-${pack1}.idx\" conv=notrunc \\\n"> <" bs=1 count=4 seek=$((8 + 256 * 4 + $(wc -l <" ( while read obj\n"> <" do git cat-file -p $obj >/dev/null || exit 1\n"> <" done <" test_must_fail git verify-pack \".git/objects/pack/pack-${pack1}.pack\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"running index-pack in the object store">)} { (SQ <"\n"> <" rm -f .git/objects/pack/* &&\n"> <" cp test-1-${pack1}.pack .git/objects/pack/pack-${pack1}.pack &&\n"> <" (\n"> <"\tcd .git/objects/pack\n"> <"\tgit index-pack pack-${pack1}.pack\n"> <" ) &&\n"> <" test -f .git/objects/pack/pack-${pack1}.idx\n"> ) } ) (C {(test_expect_success)} {(SQ <"index-pack --strict warns upon missing tagger in tag">)} { (SQ <"\n"> <" sha=$(git rev-parse HEAD) &&\n"> <" cat >wrong-tag < <"object $sha\n"> <"type commit\n"> <"tag guten tag\n"> <"\n"> <"This is an invalid tag.\n"> <"EOF\n"> <"\n"> <" tag=$(git hash-object -t tag -w --stdin <" pack1=$(echo $tag $sha | git pack-objects tag-test) &&\n"> <" echo remove tag object &&\n"> <" thirtyeight=${tag#??} &&\n"> <" rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight &&\n"> <" git index-pack --strict tag-test-${pack1}.pack 2>err &&\n"> <" grep \"^warning:.* expected .tagger. line\" err\n"> ) } ) (C {(test_done)}) ] )