tra-loi-cau-hoi-phat-trien-web.com

Tại sao sử dụng conv = notrunc khi sao chép đĩa với dd?

Nếu bạn tìm cách sao chép toàn bộ đĩa vào một đĩa khác trên web, bạn sẽ tìm thấy một cái gì đó như thế:

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

Trong khi tôi hiểu noerror, tôi đang gặp khó khăn để hiểu lý do tại sao mọi người nghĩ rằng notrunc là bắt buộc cho "tính toàn vẹn dữ liệu" (ví dụ như Wiki của ArchLinux ).

Thật vậy, tôi đồng ý rằng nếu bạn đang sao chép một phân vùng sang một phân vùng khác trên một đĩa khác và bạn không muốn ghi đè lên toàn bộ đĩa, chỉ một phân vùng. Trong trường hợp này notrunc, theo trang hướng dẫn của dd, là những gì bạn muốn.

Nhưng nếu bạn đang nhân bản toàn bộ đĩa, notrunc sẽ thay đổi gì cho bạn? Chỉ cần tối ưu hóa thời gian?

39
Undo

Phiên bản TL; DR:

notrunc chỉ quan trọng để ngăn chặn việc cắt ngắn khi ghi vào tệp. Điều này không có tác dụng đối với một thiết bị khối như sda hoặc sdb.

Phiên bản giáo dục

Tôi đã xem xét coreutils mã nguồn chứa dd.c để xem cách xử lý notrunc.

Đây là đoạn mã mà tôi đang xem:

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));

Chúng ta có thể thấy ở đây rằng nếu notrunc không được chỉ định , thì tệp đầu ra sẽ được mở bằng O_TRUNC. Nhìn bên dưới làm thế nào O_TRUNC được xử lý, chúng ta có thể thấy rằng một tệp bình thường sẽ bị cắt ngắn nếu được ghi vào.

O_TRUNC

Nếu tệp đã tồn tại và là một tệp thông thường và chế độ mở cho phép ghi (nghĩa là O_RDWR hoặc O_WRONLY), nó sẽ bị cắt ngắn đến độ dài 0. Nếu tệp là một FIFO hoặc thiết bị đầu cuối tệp, cờ O_TRUNC bị bỏ qua. Nếu không, ảnh hưởng của O_TRUNC là không xác định.

Ảnh hưởng của notrunc/O_TRUNC Tôi

Trong ví dụ sau, chúng tôi bắt đầu bằng cách tạo junk.txt có kích thước 1024 byte. Tiếp theo, chúng tôi viết 512 byte vào đầu của nó bằng conv=notrunc. Chúng ta có thể thấy rằng kích thước vẫn giữ nguyên ở mức 1024 byte. Cuối cùng, chúng tôi thử nó mà không có tùy chọn notrunc và chúng tôi có thể thấy rằng kích thước tệp mới là 512. Điều này là do nó được mở bằng 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

Ảnh hưởng của notrunc/O_TRUNC II

Tôi vẫn chưa trả lời câu hỏi ban đầu của bạn về lý do tại sao khi thực hiện sao chép từ đĩa sang đĩa, tại sao conv=notrunc là quan trọng. Theo định nghĩa trên, O_TRUNC dường như bị bỏ qua khi mở một số tệp đặc biệt và tôi cũng mong điều này đúng với các nút thiết bị khối. Tuy nhiên, tôi không muốn thừa nhận bất cứ điều gì và sẽ cố gắng chứng minh điều đó ở đây.

openclose.c

Tôi đã viết một chương trình C đơn giản ở đây để mở và đóng một tệp được cung cấp dưới dạng đối số với O_TRUNC cờ.

#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);
}

Kiểm tra tập tin bình thường

Dưới đây chúng ta có thể thấy rằng hành động đơn giản mở và đóng tệp bằng O_TRUNC sẽ khiến nó mất bất cứ thứ gì đã có ở đó.

$ 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

Chặn kiểm tra tệp thiết bị

Hãy thử một thử nghiệm tương tự trên ổ flash USB. Chúng ta có thể thấy rằng chúng ta bắt đầu với một phân vùng duy nhất trên ổ flash USB. Nếu nó bị 'cắt ngắn', có lẽ phân vùng sẽ biến mất (xem xét nó được xác định trong 512 byte đầu tiên của đĩa)?

$ 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

Có vẻ như nó không ảnh hưởng gì đến việc mở đĩa hoặc phân vùng 1 của đĩa bằng O_TRUNC Tùy chọn. Từ những gì tôi có thể nói, hệ thống tập tin vẫn có thể gắn kết và các tập tin có thể truy cập và nguyên vẹn.

Ảnh hưởng của notrunc/O_TRUNC III

Được rồi, đối với thử nghiệm cuối cùng của tôi, tôi sẽ sử dụng dd trên ổ đĩa flash của mình trực tiếp. Tôi sẽ bắt đầu bằng cách viết 512 byte dữ liệu ngẫu nhiên, sau đó viết 256 byte số 0 ở đầu. Đối với thử nghiệm cuối cùng, chúng tôi sẽ xác minh rằng 256 byte cuối cùng không thay đổi.

$ 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

Tóm lược

Qua thử nghiệm ở trên, dường như notrunc chỉ quan trọng khi bạn có một tệp bạn muốn ghi vào, nhưng không muốn cắt bớt nó. Điều này dường như không có tác dụng đối với một thiết bị khối như sda hoặc sdb.

93
rkyser