我的情况如下。我有两个冷存储存档卷,它们(应该)包含相同的数据集。这些卷包含不经常访问的备份。我担心,最终,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 内部的路径进行修复