Вот моя ситуация. У меня есть два тома архива холодного хранения, которые (должны) содержать идентичные наборы данных. Эти тома содержат редко используемые резервные копии. Я обеспокоен тем, что в конечном итоге 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
Однако вы всегда можете исправить пути внутри sed
mainfest.txt