Существует ли инструмент вроде diff -r, который сравнивает дерево каталогов с файлом манифеста, используя хэши?

Существует ли инструмент вроде diff -r, который сравнивает дерево каталогов с файлом манифеста, используя хэши?

Вот моя ситуация. У меня есть два тома архива холодного хранения, которые (должны) содержать идентичные наборы данных. Эти тома содержат редко используемые резервные копии. Я обеспокоен тем, что в конечном итоге bitrot доберется до одного или обоих из них и незаметно испортит содержащиеся в них данные. Я знаю, что могу найти diff -rдва тома и найти файлы, которые изменились или исчезли между ними, но я не получаю полезной информации о том, на каком томе находится «хорошая» копия. Это USB-диски, и преобразование их во что-то вроде ZFS кажется... обременительным.

Мне бы хотелось иметь инструмент, который будет рекурсивно проходить по дереву каталогов и записывать файл манифеста, содержащий путь и имя файла вместе с хешем содержимого файла. Я бы запускал этот инструмент сразу после записи данных в каждый том и сохранял полученный файл манифеста в теплом хранилище, возможно, под каким-то контролем ревизий.

Из этого файла я хотел бы иметь возможность запустить что-то, что работает точно так же diff -r— оно бы сообщало мне, были ли добавлены, удалены файлы или изменилось их содержимое. Только вместо того, чтобы сравнивать один том с другим, оно бы сравнивало один том с заведомо исправным файлом манифеста. Используя этот метод, я должен был бы иметь возможность определить, идентичны ли данные, которые я считываю с диска через несколько месяцев/лет в будущем, данным, которые я изначально на него поместил.

Я должен был бы подумать, что что-то подобное уже существует. Я могу получить что-то, приблизительно похожее на файл манифеста, используя:

find /mnt/my-volume -type f -exec md5sum {} + > manifest.txt

но пока я не придумал хорошего способа парсить этот файл и рекурсивно проверять каждый хэш. Также, что менее важно, это не скажет мне, появился или исчез пустой каталог. (Не могу придумать, почему это важно, но было бы неплохо знать, что это произошло.)

На правильном ли я пути или есть более подходящий инструмент, который может делать такие вещи?

решение1

Вы правы, такой инструмент уже существует. Хотя я вижу, что ваш пост помечен как 'linux,' возможно, решение, ориентированное на BSD, будет поучительным.

Утилита FreeBSD mtree(8)можем сделать именно то, о чем вы просите.

Предполагать:

$ find .
.
./c
./c/file3
./b
./b/file2
./a
./a/file1

Чтобы создать манифест этой файловой иерархии, включая хэш sha256 каждого файла, нужно:

$ mtree -c -K sha256 > /tmp/manifest.txt
$ cat /tmp/manifest.txt
#          user: diego
#       machine: myhost.example.com
#          tree: /data/home/diego/foo
#          date: Wed Mar 28 10:31:17 2018

# .
/set type=file uid=1001 gid=1001 mode=0710 nlink=1 flags=uarch
.               type=dir nlink=5 time=1522257963.738221000

# ./a
/set type=file uid=1001 gid=1001 mode=0600 nlink=1 flags=uarch
a               type=dir mode=0710 nlink=2 time=1522257932.680802000
    file1       size=29 time=1522257932.682389000 \
                sha256digest=6b4114c4f12e63c0ca44073de5ca0a2b39fedaceaa533af3dfdc89f00039c973
# ./a
..


# ./b
b               type=dir mode=0710 nlink=2 time=1522257937.929131000
    file2       size=29 time=1522257937.930666000 \
                sha256digest=9f7a0a49475bb6f98e609a4e057f0bc702c5e4706be5bd656a676fd8d15da7ef
# ./b
..


# ./c
c               type=dir mode=0710 nlink=2 time=1522257942.064315000
    file3       size=29 time=1522257942.065882000 \
                sha256digest=bd617f47217ef0605d3aff036778d10bf18cb2f415c45e8e362e2c091df19491
# ./c
..

Затем можно проверить иерархию файлов по манифесту, передав манифест в mtree:

$ mtree < /tmp/manifest.txt || echo fail

Добавление, удаление, переименование или изменение файлов приведет к сбою проверки:

$ touch foo
$ mtree < /tmp/manifest.txt || echo fail
.:      modification time (Wed Mar 28 10:34:56 2018, Wed Mar 28 10:37:01 2018)
extra: foo
fail
$ rm foo; touch b/file2; mtree < /tmp/manifest.txt || echo fail
.:      modification time (Wed Mar 28 10:34:56 2018, Wed Mar 28 10:39:39 2018)
b/file2: 
        modification time (Wed Mar 28 10:25:37 2018, Wed Mar 28 10:39:39 2018)
fail
$ mv c/file3 c/FILE3; rm a/file1; date >> b/file2; mtree < /tmp/manifest.txt || echo fail
.:      modification time (Wed Mar 28 10:34:56 2018, Wed Mar 28 10:39:39 2018)
c:      modification time (Wed Mar 28 10:25:42 2018, Wed Mar 28 10:41:59 2018)
extra: c/FILE3
b/file2:
        size (29, 58)
        modification time (Wed Mar 28 10:25:37 2018, Wed Mar 28 10:47:31 2018)
        sha256digest (0x9f7a0a49475bb6f98e609a4e057f0bc702c5e4706be5bd656a676fd8d15da7ef, 0x569c17bd1a1ca2447fd8167f103531bf3a7b7b4268f0f68b18506e586e7eea94)
a:      modification time (Wed Mar 28 10:25:32 2018, Wed Mar 28 10:41:59 2018)
./a/file1 missing
./c/file3 missing
fail

решение2

Будет md5sum -c manifest.txtучитывать пути, хранящиеся в manifest.txt. findПрограмма подставляет {}полный путь к найденному файлу, включая любое местоположение поиска, указанное в findкомандной строке, т.е. для файла ./a/b/c/d/eона заменит то же самое ./a/b/c/d/eна команду find ./a -type f -exec md5sum {} \;

Возможная проблема — абсолютные пути, поэтому более подходящая «команда создания манифеста» выглядит так:

cd /mnt/my-volume; find  -type f -exec md5sum {} + > manifest.txt

Однако вы всегда можете исправить пути внутри sedmainfest.txt

Связанный контент