Gab*_*iel 5 linux operating-system inode
我将 inode 解释为指向文件实际存储位置的指针。
但我的理解有问题:
如果我在已经存在的cp file1 file2地方使用,inode 不会改变。如果最初存在指向 file2 的硬链接,那么它们现在都指向刚刚复制到此处的新文件。file2
但是当我使用时mv file1 file2,inode 变成了 的 inode file1。
您的说法是正确的,这cp将修改文件而不是删除并重新创建。
下面是底层系统调用的视图strace(部分输出strace cp file1 file2):
open("file2", O_WRONLY|O_TRUNC) = 4
stat("file2", {st_mode=S_IFREG|0664, st_size=6, ...}) = 0
stat("file1", {st_mode=S_IFREG|0664, st_size=3, ...}) = 0
stat("file2", {st_mode=S_IFREG|0664, st_size=6, ...}) = 0
open("file1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=3, ...}) = 0
open("file2", O_WRONLY|O_TRUNC) = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "hi\n", 65536) = 3
write(4, "hi\n", 3) = 3
read(3, "", 65536) = 0
close(4) = 0
close(3) = 0
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它检测到file2存在(stat返回 0),但随后打开它进行写入(O_WRONLY|O_TRUNC),而无需先执行unlink.
请参阅 POSIX.1-2017 示例,它指定目标文件只能unlink在无法打开写入的情况下进行 -ed 并-f使用:
dest_file 的文件描述符应通过执行与 POSIX.1-2017 系统接口卷中定义的 open() 函数等效的操作来获取,该函数使用 dest_file 作为路径参数,并使用 O_WRONLY 和 O_TRUNC 的按位或或作为oflag 论证。
如果尝试获取文件描述符失败并且 -f 选项有效,则 cp 应尝试通过执行与使用 dest_file 调用的 POSIX.1-2017 系统接口卷中定义的 unlink() 函数等效的操作来删除文件作为路径参数。如果此尝试成功,cp 将继续执行步骤 3b。
这意味着,如果目标文件存在,-f如果cp进程对其具有写权限(不一定以拥有该文件的用户身份运行),则复制将成功(不诉诸行为),即使它对目标文件没有写权限。包含目录。相比之下,取消链接和重新创建将需要目录的写入权限。我推测这就是标准之所以如此的原因。
--remove-destinationGNU 上的选项将cp使其执行您认为应该默认的操作。
这是输出的相关部分strace cp --remove-destination file1 file2。注意unlink这次。
stat("file2", {st_mode=S_IFREG|0664, st_size=6, ...}) = 0
stat("file1", {st_mode=S_IFREG|0664, st_size=3, ...}) = 0
lstat("file2", {st_mode=S_IFREG|0664, st_size=6, ...}) = 0
unlink("file2") = 0
open("file1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=3, ...}) = 0
open("file2", O_WRONLY|O_CREAT|O_EXCL, 0664) = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "hi\n", 65536) = 3
write(4, "hi\n", 3) = 3
read(3, "", 65536) = 0
close(4) = 0
close(3) = 0
Run Code Online (Sandbox Code Playgroud)
当您使用mv并且源路径和目标路径位于同一文件系统上时,它将执行 操作rename,这将具有取消链接目标路径中任何现有文件的效果。这是输出的相关部分strace mv file1 file2。
access("file2", W_OK) = 0
rename("file1", "file2") = 0
Run Code Online (Sandbox Code Playgroud)
在任一情况下,目标路径未链接(无论是通过unlink()as 调用 from显式调用,还是作为as 调用 fromcp --remove-destination的效果的一部分),它所指向的 inode 的链接计数将减少,但仍将保留在文件系统,如果链接计数仍然 > 0 或者任何进程在其上打开了文件句柄。到此 inode 的任何其他(硬)链接(即它的其他目录条目)都将保留。rename()mv
ls -ils -i将显示索引节点号(与 组合时作为第一列-l),这有助于演示正在发生的情况。
cp默认操作的示例
$ rm file1 file2 file3
$ echo hi > file1
$ echo world > file2
$ ln file2 file3
$ ls -li file*
49 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 10:43 file1
50 -rw-rw-r-- 2 myuser mygroup 6 Jun 13 10:43 file2
50 -rw-rw-r-- 2 myuser mygroup 6 Jun 13 10:43 file3
$ cp file1 file2
$ ls -li file*
49 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 10:43 file1
50 -rw-rw-r-- 2 myuser mygroup 3 Jun 13 10:43 file2 <=== exsting inode
50 -rw-rw-r-- 2 myuser mygroup 3 Jun 13 10:43 file3 <=== exsting inode
Run Code Online (Sandbox Code Playgroud)
(请注意,现有 inode 50 现在的大小为 3)。
示例为--remove-destination
$ rm file1 file2 file3
$ echo hi > file1
$ echo world > file2
$ ln file2 file3
$ ls -li file*
49 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 10:46 file1
50 -rw-rw-r-- 2 myuser mygroup 6 Jun 13 10:46 file2
50 -rw-rw-r-- 2 myuser mygroup 6 Jun 13 10:46 file3
$ cp --remove-destination file1 file2
$ ls -li file*
49 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 10:46 file1
55 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 10:47 file2 <=== new inode
50 -rw-rw-r-- 1 myuser mygroup 6 Jun 13 10:46 file3 <=== existing inode
Run Code Online (Sandbox Code Playgroud)
(注意新的 inode 55 的大小为 3。未修改的 inode 50 的大小仍然为 6。)
示例为mv
$ rm file1 file2 file3
$ echo hi > file1
$ echo world > file2
$ ln file2 file3
$ ls -li file*
49 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 11:05 file1
50 -rw-rw-r-- 2 myuser mygroup 6 Jun 13 11:05 file2
50 -rw-rw-r-- 2 myuser mygroup 6 Jun 13 11:05 file3
$ mv file1 file2
$ ls -li file*
49 -rw-rw-r-- 1 myuser mygroup 3 Jun 13 11:05 file2 <== existing inode
50 -rw-rw-r-- 1 myuser mygroup 6 Jun 13 11:05 file3 <== existing inode
Run Code Online (Sandbox Code Playgroud)