据我所知,即使更改文件的一小部分,也会更改整个校验和结果,但是当我更改文件名时,这不会影响其校验和(我尝试过 SHA-1、SHA-256 和 MD5)。
为什么?文件名不是文件数据的一部分?它取决于文件系统吗?
答案1
文件的名称是目录条目中的字符串,并且许多其他元数据(文件类型、权限、所有权、时间戳等)存储在 inode 中。因此,文件名不是构成文件实际数据的一部分。事实上,单个文件在文件系统中可以有任意数量的名称(硬链接),并且还可以通过任意数量的任意命名的符号链接进行访问。
md5
由于文件名不是文件数据的一部分,因此当您使用或md5sum
或某些类似实用程序计算 MD5 校验和时,它不会自动包含在内。
因此,更改文件的名称(或所有权、时间戳或权限等)或通过其他名称或符号链接之一访问该文件(如果有)不会对文件的 MD5 校验和产生任何影响。
答案2
是的,正如您所说“文件名不是文件数据的一部分”
文件名无法保存在文件。如果是的话,它将更改该文件。然而,对文件名、其他元数据和文件数据进行校验和可能是有效的,但这通常是一个坏主意。
文件名是其包含目录的一部分。不是文件的一部分。
如果你想对两者进行校验和/哈希,那么这样的事情就可以工作
(可能不是一个好主意)
echo "$filename" | xargs -n1 -I{} bash -c 'echo "$1"; cat "$1"' x {} | shasum
答案3
当我更改文件名时,这不会影响其校验和(我已尝试过 SHA-1、SHA-256 和 MD5)。
嗯,这有点错误的联系。 SHA-1、SHA-256 和 MD5 不计算文件或文件名的哈希值,而是计算比特流的哈希值。因此,您得到的结果完全取决于您选择提供的输入内容,而您没有显示这一点。
现在,您可能使用了sha1sum
、sha256sum
和md5sum
实用程序,实际上它们仅在要散列的数据中包含给定文件的内容。不是文件名,不是权限位、所有者信息、时间戳或其他元数据。
但事实并非如此有那样做。以下是两个文件及其名称的 SHA-256 哈希值:
$ echo hello > a.txt; cp a.txt b.txt
$ ./checksum.sh a.txt b.txt
aed49f7730ca0736fe1a021375d1ca9b509a4e72910b422578df8b4b1930aeca -
bad46702033923726add35ef8d97570f1aa40d93dad1d6ba63e7b051a34b9efc -
该脚本只是将文件名添加到哈希数据前面。另一个应用程序可以将元数据与文件内容一起包含在哈希输入中,或者包含仅覆盖部分数据的哈希。
显然,包含文件名有一个缺点,即即使是同一个文件也可以由不同的名称引用,因此可以有许多不同的哈希值:
/tmp/test$ ./checksum.sh a.txt ./a.txt /tmp/test/a.txt
aed49f7730ca0736fe1a021375d1ca9b509a4e72910b422578df8b4b1930aeca -
85ec58226886f4f853212b2d21bb2fb72447813ac13a59e9376b2e0c02074839 -
25c1c072481131e07c3fc20d16109472872233f658f4df3c4982fb195a048b96 -
在等式中添加时间戳、所有者等几乎可以保证在将文件复制到另一个系统后哈希值会有所不同,从而使哈希值的有用性相当值得怀疑。甚至文件名也可能丢失或更改。
如果您想将元数据包含在哈希中,最简单的方法可能是将文件放入 tar 存档或其他存储您认为有用的元数据的容器中,然后对其进行哈希和复制。从存档中提取文件(内容)后,文件系统上的元数据可能会有所不同,但您仍然可以验证文件来自的存档。
上面的脚本是:
$ cat checksum.sh
#!/bin/bash
for f in "$@"; do
(printf "%s\0" "$f" ; cat "$f") | sha256sum -
done
答案4
正如您自己所说,以及现在在两个答案中强调的那样:文件名不是数据的一部分,它是有关文件的数据(也称为元数据)。
这实际上是有用的,因为通过这种方式,即使它们具有不同的名称,您也可以检测到重复项。类似fdupes
和搜索重复项的程序jdupes
实际上使用校验和来加速该过程(校验和就是所谓的不变量)。