t / t5303-pack-corruption-resilience.shon commit upload-pack: support hidden refs with protocol v2 (e20b419)
   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-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
  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 bs=1 conv=notrunc seek=$ofs &&
  55    test_must_fail git verify-pack ${pack}.pack
  56}
  57
  58printf '\0' > zero
  59
  60test_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'
  68
  69test_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'
  75
  76test_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'
  84
  85test_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'
  95
  96test_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'
 105
 106test_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'
 114
 115test_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'
 125
 126test_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'
 134
 135test_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'
 143
 144test_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'
 152
 153test_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'
 162
 163test_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'
 171
 172test_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'
 180
 181test_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'
 189
 190test_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'
 198
 199test_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'
 207
 208test_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'
 216
 217test_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'
 225
 226test_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'
 234
 235test_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'
 243
 244test_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'
 252
 253test_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'
 261
 262test_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'
 277
 278test_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'
 286
 287test_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'
 295
 296test_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'
 304
 305test_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'
 313
 314test_done