Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 153 lines (139 sloc) 4.323 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
#!/bin/bash

escape_for_grep() {
    local a=${1//\\/\\\\}
    a=${a//./\\.}
    a=${a//\*/\\*}
    a=${a//\$/\\\$}
a=${a//\^/\\^}
a=${a//[/\\[}
a=${a//]/\\]}
printf '%s\n' "$a"
}

contains_files() {
    [[ $(find "$1" -maxdepth 1 -type f -printf . -quit) ]]
}

check_checksum() { (
    cd "$1" || exit
if [[ $nocheck ]]; then
        cfv -m -f .md5 || exit
else
        cfv -f .md5 || exit
fi
    unknown=
    while IFS= read -d '' -r filename; do
        filename=$(basename "$filename")
        [[ $filename != .md5 ]] || continue
        if ! grep -q " \*$(escape_for_grep "$filename")$" .md5; then
            unknown=1
            printf 'Missing checksum for: %s\n' "$dir/$filename"
        fi
    done < <(find . -maxdepth 1 -type f -print0)
    [[ ! $unknown || $nogenerate ]]
) }

create_checksum() { (
    cd "$1" || exit
cfv -C -tmd5 -f .md5
) }

base=${1-.}
nocheck=
nogenerate=
while [[ $# -gt 0 ]]; do
    if [[ $base = --nocheck ]]; then
        shift
base=${1-.}
        nocheck=1
    elif [[ $base = --nogenerate ]]; then
        shift
base=${1-.}
        nogenerate=1
    else
        shift
break
fi
done

if [[ ! -d $base || $# -ne 0 ]]; then
    echo "Usage: $(basename "$0") [--nocheck] [--nogenerate] [directory]"
    echo '
Verifies and updates checksum files recursively starting from the
given directory. If no directory is given, start from the current
directory.

With --nocheck no checksums are verified, only existence of files is
checked. In this mode checksum files may still be updated if files or
checksums are missing.

With --nogenerate no checksum files will be generated or modified.
This is the read-only mode.'
    exit 0
fi

if [[ $nocheck ]]; then
    printf '** Will check for missing files and missing checkums starting from %s\n' "$base"
    echo '** The checksums themselves will *not* be verified!'
else
    printf '** Will verify all checksums starting from %s\n' "$base"
fi
if [[ $nogenerate ]]; then
    echo '** Missing or wrong checksums will *not* be generated or fixed.'
    echo '** This is the read-only mode. Directories containing no checksum file will not be mentioned at all.'
else
    echo '** Missing checksums will be generated automatically.'
fi
read -p '** Proceed? [Yn]' answer

[[ ! $answer || $answer = y || $answer = Y ]] || exit 1

error=
missing=
while IFS= read -d '' -r dir; do
    contains_files "$dir" || continue
    # Remove empty .md5 file or skip this directory in read-only mode.
    if [[ -f $dir/.md5 && ! -s $dir/.md5 ]]; then
        if [[ $nogenerate ]]; then
            continue
        else
            rm "$dir/.md5"
        fi
    fi
    if [[ -f $dir/.md5 ]]; then
        echo -e "\n** Checking $dir"
        if ! check_checksum "$dir"; then
            error=1
            echo "** Checksum error in $dir"
            if [[ $nogenerate ]]; then
                continue
            fi
            read -u 1 -p "** Regenerate checkums for this directory? [Yn]" answer
            if [[ ! $answer || $answer = y || $answer = Y ]]; then
                echo "** Regenerating checksums..."
                old_md5=$(mktemp)
                mv "$dir/.md5" "$old_md5"
                create_checksum "$dir"
                echo "** Finished regenerating checksums for $dir"
                mv "$old_md5" "$dir/.md5_old"
                diff "$dir/.md5_old" "$dir/.md5"
                read -u 1 -p "** Remove old .md5 file? [Yn]" answer
                if [[ ! $answer || $answer = y || $answer = Y ]]; then
                    rm "$dir/.md5_old"
                    echo "** Removed old .md5 file."
                else
                    echo "** Keeping $dir/.md5_old"
                fi
            fi
        fi
    else
        missing=1
        if [[ $nogenerate ]]; then
            continue
        fi
        echo -e "\n** Checking $dir"
        echo '** No checksum file found. Generating new checksums...'
        create_checksum "$dir"
        echo "** Finished generating checksums for $dir"
    fi
done < <(find "$base" -type d -print0)

echo
if [[ $error ]]; then
    echo '** Errors were encountered.'
else
    echo '** No errors were encountered.'
fi

if [[ $missing && ! $nogenerate ]]; then
    echo '** Generated some missing checksum files.'
fi

exit 0
Something went wrong with that request. Please try again.