linux - 为什么使用 dd 克隆磁盘时使用 conv=notrunc?

如果您在网上查找如何将整个磁盘克隆到另一个磁盘,您会发现类似的内容:

dd if=/dev/sda of=/dev/sdb conv=notrunc,noerror

虽然我理解 noerror,但我很难理解为什么人们认为“数据完整性”需要 notrunc(如 ArchLinux's Wiki 所述,对于实例)。

确实,如果您将一个分区复制到另一个磁盘上的另一个分区,并且您不想覆盖整个磁盘,只覆盖一个分区,我确实同意这一点。在这种情况下,根据 dd 的手册页,notrunc 就是您想要的。

但是,如果您要克隆整个磁盘,notrunc 会为您改变什么?只是时间优化?

最佳答案

TL;DR 版本:

notrunc 仅在写入文件时防止截断很重要。这对 block 设备没有影响,例如 sdasdb

教育版

我查看了包含 dd.ccoreutils 源代码,以了解如何处理 notrunc

这是我正在查看的代码段:

int opts = (output_flags
            | (conversions_mask & C_NOCREAT ? 0 : O_CREAT)
            | (conversions_mask & C_EXCL ? O_EXCL : 0)
            | (seek_records || (conversions_mask & C_NOTRUNC) ? 0 : O_TRUNC));

/* Open the output file with *read* access only if we might
need to read to satisfy a `seek=' request.  If we can't read
the file, go ahead with write-only access; it might work.  */
if ((! seek_records
    || fd_reopen (STDOUT_FILENO, output_file, O_RDWR | opts, perms) < 0)
    && (fd_reopen (STDOUT_FILENO, output_file, O_WRONLY | opts, perms) < 0))
        error (EXIT_FAILURE, errno, _("opening %s"), quote (output_file));

在这里我们可以看到,如果notruncnot 指定的,那么输出文件将以O_TRUNC 打开。下面看看 O_TRUNC 是如何被处理的,我们可以看到一个普通的文件如果写入会被截断。

O_TRUNC

If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0. If the file is a FIFO or terminal device file, the O_TRUNC flag is ignored. Otherwise the effect of O_TRUNC is unspecified.

notrunc/O_TRUNC I

的影响

在以下示例中,我们首先创建大小为 1024 字节的 junk.txt。接下来,我们使用 conv=notrunc 将 512 个字节写入它的开头。我们可以看到大小保持不变,为 1024 字节。最后,我们尝试不带notrunc选项,可以看到新文件大小为512。这是因为它是用O_TRUNC打开的。

$ dd if=/dev/urandom of=junk.txt bs=1024 count=1
$ ls -l junk.txt
-rw-rw-r-- 1 akyserr akyserr 1024 Dec 11 17:08 junk.txt

$ dd if=/dev/urandom of=junk.txt bs=512 count=1 conv=notrunc
$ ls -l junk.txt
-rw-rw-r-- 1 akyserr akyserr 1024 Dec 11 17:10 junk.txt

$ dd if=/dev/urandom of=junk.txt bs=512 count=1
$ ls -l junk.txt
-rw-rw-r-- 1 akyserr akyserr 512 Dec 11 17:10 junk.txt

notrunc/O_TRUNC II

的效果

我仍然没有回答您最初的问题,即为什么在进行磁盘到磁盘克隆时,为什么 conv=notrunc 很重要。根据上面的定义,O_TRUNC 在打开某些特殊文件时似乎被忽略了,我希望 block 设备节点也是如此。但是,我不想假设任何事情,并会在这里尝试证明这一点。

openclose.c

我在这里编写了一个简单的 C 程序,它可以打开和关闭一个文件,该文件作为带有 O_TRUNC 标志的参数给出。

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

int main(int argc, char * argv[])
{
    if (argc < 2)
    {
        fprintf(stderr, "Not enough arguments...\n");
        return (1);
    }

    int f = open(argv[1], O_RDWR | O_TRUNC);

    if (f >= 0)
    {
        fprintf(stderr, "%s was opened\n", argv[1]);
        close(f);
        fprintf(stderr, "%s was closed\n", argv[1]);
    } else {
        perror("Opening device node");
    }

    return (0);
}

普通文件测试

我们可以在下面看到,使用 O_TRUNC 打开和关闭文件的简单操作将导致它丢失已经存在的任何内容。

$ dd if=/dev/urandom of=junk.txt bs=1024 count=1^C
$ ls -l junk.txt 
-rw-rw-r-- 1 akyserr akyserr 1024 Dec 11 17:26 junk.txt

$ ./openclose junk.txt
junk.txt was opened
junk.txt was closed

$ ls -l junk.txt
-rw-rw-r-- 1 akyserr akyserr 0 Dec 11 17:27 junk.txt

block 设备文件测试

让我们在 USB 闪存驱动器上尝试类似的测试。我们可以看到我们从 USB 闪存驱动器上的单个分区开始。如果它被“截断”,也许分区会消失(考虑到它是在磁盘的前 512 个字节中定义的)?

$ ls -l /dev/sdc*
brw-rw---- 1 root disk 8, 32 Dec 11 17:22 /dev/sdc
brw-rw---- 1 root disk 8, 33 Dec 11 17:22 /dev/sdc1

$ sudo ./openclose /dev/sdc
/dev/sdc was opened
/dev/sdc was closed

$ sudo ./openclose /dev/sdc1
/dev/sdc1 was opened
/dev/sdc1 was closed

$ ls -l /dev/sdc*
brw-rw---- 1 root disk 8, 32 Dec 11 17:31 /dev/sdc
brw-rw---- 1 root disk 8, 33 Dec 11 17:31 /dev/sdc1

使用 O_TRUNC 选项打开磁盘或磁盘的分区 1 似乎没有任何影响。据我所知,文件系统仍然是可挂载的,文件是可访问且完整的。

notrunc/O_TRUNC III的影响

好的,对于我的最终测试,我将直接在我的闪存驱动器上使用 dd。我将从写入 512 字节的随机数据开始,然后在开头写入 256 字节的零。对于最终测试,我们将验证最后 256 个字节是否保持不变。

$ sudo dd if=/dev/urandom of=/dev/sdc bs=256 count=2
$ sudo hexdump -n 512 /dev/sdc
0000000 3fb6 d17f 8824 a24d 40a5 2db3 2319 ac5b
0000010 c659 5780 2d04 3c4e f985 053c 4b3d 3eba
0000020 0be9 8105 cec4 d6fb 5825 a8e5 ec58 a38e
0000030 d736 3d47 d8d3 9067 8db8 25fb 44da af0f
0000040 add7 c0f2 fc11 d734 8e26 00c6 cfbb b725
0000050 8ff7 3e79 af97 2676 b9af 1c0d fc34 5eb1
0000060 6ede 318c 6f9f 1fea d200 39fe 4591 2ffb
0000070 0464 9637 ccc5 dfcc 3b0f 5432 cdc3 5d3c
0000080 01a9 7408 a10a c3c4 caba 270c 60d0 d2f7
0000090 2f8d a402 f91a a261 587b 5609 1260 a2fc
00000a0 4205 0076 f08b b41b 4738 aa12 8008 053f
00000b0 26f0 2e08 865e 0e6a c87e fc1c 7ef6 94c6
00000c0 9ced 37cf b2e7 e7ef 1f26 0872 cd72 54a4
00000d0 3e56 e0e1 bd88 f85b 9002 c269 bfaa 64f7
00000e0 08b9 5957 aad6 a76c 5e37 7e8a f5fc d066
00000f0 8f51 e0a1 2d69 0a8e 08a9 0ecf cee5 880c
0000100 3835 ef79 0998 323d 3d4f d76b 8434 6f20
0000110 534c a847 e1e2 778c 776b 19d4 c5f1 28ab
0000120 a7dc 75ea 8a8b 032a c9d4 fa08 268f 95e8
0000130 7ff3 3cd7 0c12 4943 fd23 33f9 fe5a 98d9
0000140 aa6d 3d89 c8b4 abec 187f 5985 8e0f 58d1
0000150 8439 b539 9a45 1c13 68c2 a43c 48d2 3d1e
0000160 02ec 24a5 e016 4c2d 27be 23ee 8eee 958e
0000170 dd48 b5a1 10f1 bf8e 1391 9355 1b61 6ffa
0000180 fd37 7718 aa80 20ff 6634 9213 0be1 f85e
0000190 a77f 4238 e04d 9b64 d231 aee8 90b6 5c7f
00001a0 5088 2a3e 0201 7108 8623 b98a e962 0860
00001b0 c0eb 21b7 53c6 31de f042 ac80 20ee 94dd
00001c0 b86c f50d 55bc 32db 9920 fd74 a21e 911a
00001d0 f7db 82c2 4d16 3786 3e18 2c0f 47c2 ebb0
00001e0 75af 6a8c 2e80 c5b6 e4ea a9bc a494 7d47
00001f0 f493 8b58 0765 44c5 ff01 42a3 b153 d395

$ sudo dd if=/dev/zero of=/dev/sdc bs=256 count=1
$ sudo hexdump -n 512 /dev/sdc
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0000100 3835 ef79 0998 323d 3d4f d76b 8434 6f20
0000110 534c a847 e1e2 778c 776b 19d4 c5f1 28ab
0000120 a7dc 75ea 8a8b 032a c9d4 fa08 268f 95e8
0000130 7ff3 3cd7 0c12 4943 fd23 33f9 fe5a 98d9
0000140 aa6d 3d89 c8b4 abec 187f 5985 8e0f 58d1
0000150 8439 b539 9a45 1c13 68c2 a43c 48d2 3d1e
0000160 02ec 24a5 e016 4c2d 27be 23ee 8eee 958e
0000170 dd48 b5a1 10f1 bf8e 1391 9355 1b61 6ffa
0000180 fd37 7718 aa80 20ff 6634 9213 0be1 f85e
0000190 a77f 4238 e04d 9b64 d231 aee8 90b6 5c7f
00001a0 5088 2a3e 0201 7108 8623 b98a e962 0860
00001b0 c0eb 21b7 53c6 31de f042 ac80 20ee 94dd
00001c0 b86c f50d 55bc 32db 9920 fd74 a21e 911a
00001d0 f7db 82c2 4d16 3786 3e18 2c0f 47c2 ebb0
00001e0 75af 6a8c 2e80 c5b6 e4ea a9bc a494 7d47
00001f0 f493 8b58 0765 44c5 ff01 42a3 b153 d395

总结

通过上面的实验,notrunc 似乎只在你有一个你想写入的文件时才重要,但又不想截断它。这似乎对 sda 或 sdb 之类的 block 设备没有影响。

https://stackoverflow.com/questions/20526198/

相关文章:

regex - 在 Linux 中,名称与正则表达式匹配的文件的磁盘使用情况?

linux - 如何将 ISO8859-15 转换为 UTF8?

linux - 导出在我的 shell 脚本中不起作用

linux - yum 可以告诉我哪些存储库提供了特定的包吗?

linux - 如何获取unix数据文件中每行的前n个字符

linux - 是否可以使用 shell 脚本递归地创建文件夹?

linux - 仅当变量包含特定字符串时才运行 Ansible 任务

linux - 如何从 Bash 中的字符串中删除所有非数字字符?

linux - 如何获取自上次使用 bash 修改文件以来的时间(以秒为单位)?

python - 比较两个图像的 python/linux 方式