如果你查看如何将整个磁盘克隆到networking上的另一个磁盘,你会发现这样的:
dd if=/dev/sda of=/dev/sdb conv=notrunc,noerror
虽然我明白了这个noerror
,但是我noerror
难理解为什么人们认为notrunc
是“数据完整性”所必需的(比如ArchLinux的Wiki )。
事实上,我同意如果你正在复制一个分区到另一个磁盘上的另一个分区,而你不想覆盖整个磁盘,只需要一个分区。 在这种情况下,notrunc,根据dd的手册页,是你想要的。
但是,如果你正在克隆整个磁盘, notrunc
会为你改变什么? 只是时间优化?
notrunc
只有在写入文件时防止截断才是重要的。 这对块设备(如sda
或sdb
没有影响。
我查看了包含dd.c的coreutils源代码,看看如何处理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));
我们可以在这里看到,如果没有指定notrunc,那么输出文件将用O_TRUNC打开。 下面看看如何处理O_TRUNC
,我们可以看到,一个正常的文件将被截断,如果写入。
如果该文件已经存在并且是一个常规文件,并且打开模式允许写入(即为O_RDWR或O_WRONLY),则该文件将被截断为长度0.如果文件是FIFO或终端设备文件,则忽略O_TRUNC标志。 否则,O_TRUNC的作用是未指定的。
O_TRUNC
/ O_TRUNC
在下面的例子中,我们开始创建大小为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
O_TRUNC
/ O_TRUNC
II的影响 我还没有回答你为什么做磁盘到磁盘克隆的原始问题,为什么conv=notrunc
是重要的。 根据上面的定义,当打开某些特殊文件时, O_TRUNC
似乎被忽略了,我也希望块设备节点也是如此。 但是,我不想承担任何事情,并会试图在这里证明。
我在这里写了一个简单的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
让我们尝试在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
它看起来没有任何影响打开磁盘或磁盘的分区1与O_TRUNC
选项。 从我可以告诉,文件系统仍然是可挂载的,文件是可访问和完整的。
O_TRUNC
/ 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)没有影响。
将映像部署到磁盘存储时conv=sync,noerror
切勿使用conv=sync,noerror
或者conv=noerror
。 在现代的Linux环境中。 总是使用conv=notrunc,noerror
来正确地记录图像。