GNU/Linux >> Belajar Linux >  >> Linux

Kapan Dd Cocok Untuk Menyalin Data? (atau, Kapan Read() Dan Write() Partial)?

Versi singkat: Dalam keadaan apa dd aman digunakan untuk menyalin data, aman artinya tidak ada risiko korupsi karena sebagian membaca atau menulis?

Versi panjang — pembukaan: dd sering digunakan untuk menyalin data, terutama dari atau ke perangkat (contoh). Kadang-kadang dikaitkan dengan sifat mistik untuk dapat mengakses perangkat pada tingkat yang lebih rendah daripada alat lain (padahal sebenarnya file perangkat yang melakukan keajaiban) — namun dd if=/dev/sda sama dengan cat /dev/sda . dd terkadang dianggap lebih cepat, tetapi cat bisa mengalahkannya dalam latihan. Meskipun demikian, dd memiliki sifat unik yang terkadang membuatnya benar-benar berguna.

Masalah: dd if=foo of=bar sebenarnya tidak sama dengan cat <foo >bar . Pada kebanyakan unice, dd membuat satu panggilan ke read() . (Saya menemukan POSIX kabur pada apa yang merupakan "membaca blok input" di dd .) Jika read() mengembalikan sebagian hasil (yang, menurut POSIX dan dokumen referensi lainnya, diizinkan kecuali jika dokumentasi implementasi mengatakan sebaliknya), sebagian blok disalin. Masalah yang sama persis ada untuk write() .

Pengamatan :Dalam praktiknya, saya menemukan bahwa dd dapat mengatasi perangkat blok dan file biasa, tetapi itu mungkin karena saya belum banyak menggunakannya. Ketika berbicara tentang pipa, tidak sulit untuk menempatkan dd bersalah; misalnya coba kode ini:

yes | dd of=out bs=1024k count=10

dan periksa ukuran out file (kemungkinan di bawah 10 MB).

Pertanyaan :Dalam keadaan apa dd aman digunakan untuk menyalin data? Dengan kata lain, kondisi apa pada ukuran blok, pada implementasi, pada jenis file, dll, dapat memastikan bahwa dd akan menyalin semua data?

(GNU dd memiliki fullblock tandai untuk menyuruhnya memanggil read() atau write() dalam satu lingkaran untuk mentransfer blok penuh. Jadi dd iflag=fullblock selalu aman. Pertanyaan saya adalah tentang kasus ketika flag ini (yang tidak ada pada implementasi lain) tidak digunakan.)


Saya telah memeriksa OpenBSD, GNU coreutils dan BusyBox.

Jawaban yang Diterima:

Dari spesifikasi:

  • Jika bs= expr operan ditentukan dan tidak ada konversi selain sync , noerror , atau notrunc diminta, data yang dikembalikan dari setiap blok input harus ditulis sebagai blok output yang terpisah; jika read() mengembalikan kurang dari satu blok penuh dan sync konversi tidak ditentukan, blok keluaran yang dihasilkan harus berukuran sama dengan blok masukan.

Jadi ini mungkin yang menyebabkan kebingungan Anda. Ya, karena dd dirancang untuk memblokir, secara default sebagian read() s akan dipetakan 1:1 ke sebagian write() s, atau sync d out pada tail padding NUL atau karakter spasi ke bs= ukuran saat conv=sync ditentukan.

Artinya dd aman digunakan untuk menyalin data (tanpa risiko kerusakan karena membaca atau menulis sebagian) dalam setiap kasus kecuali satu yang secara sewenang-wenang dibatasi oleh count= argumen, karena jika tidak dd dengan senang hati akan write() outputnya dalam blok berukuran identik dengan yang inputnya read() sampai read() s sepenuhnya melalui itu. Dan bahkan peringatan ini hanya benar ketika bs= ditentukan atau obs= adalah tidak ditentukan, karena kalimat berikutnya dalam spesifikasi menyatakan:

  • Jika bs= expr operan tidak ditentukan, atau konversi selain sync , noerror , atau notrunc diminta, input akan diproses dan dikumpulkan menjadi blok output berukuran penuh sampai akhir input tercapai.
Terkait:Debian – kehilangan konektivitas nirkabel berulang?

Tanpa ibs= dan/atau obs= argumen ini tidak masalah – karena ibs dan obs keduanya berukuran sama secara default. Namun, Anda bisa menjadi eksplisit tentang buffering input dengan menentukan ukuran berbeda untuk keduanya dan tidak menentukan bs= (karena diutamakan) .

Misalnya, jika Anda melakukan:

IN| dd ibs=1| OUT

…lalu sebuah POSIX dd akan write() dalam potongan 512 byte dengan mengumpulkan setiap read() byte ke dalam satu blok keluaran.

Jika tidak, jika Anda melakukannya…

IN| dd obs=1kx1k| OUT

…a POSIX dd akan read() maksimum 512 byte sekaligus, tetapi write() setiap blok keluaran berukuran megabyte (kernel memungkinkan dan kecuali mungkin yang terakhir – karena itulah EOF) secara penuh dengan mengumpulkan masukan ke dalam blok keluaran berukuran penuh .

Juga dari spesifikasinya:

  • count=n
    • Hanya salin n blok masukan.

count= memetakan ke i?bs= blok, dan untuk menangani batas arbitrer pada count= portabel Anda akan membutuhkan dua dd s. Cara paling praktis untuk melakukannya dengan dua dd s adalah dengan menyalurkan output dari satu ke input yang lain, yang tentunya menempatkan kita di ranah membaca/menulis file khusus terlepas dari jenis input aslinya.

Pipa IPC berarti bahwa saat menentukan [io]bs= berpendapat bahwa, untuk melakukannya dengan aman, Anda harus menyimpan nilai tersebut dalam PIPE_BUF yang ditentukan sistem membatasi. POSIX menyatakan bahwa kernel sistem hanya harus menjamin atom read() s dan write() s dalam batas PIPE_BUF seperti yang didefinisikan dalam limits.h . POSIX menjamin bahwa PIPE_BUF menjadi setidaknya

  • {_POSIX_PIPE_BUF}
    • Jumlah byte maksimum yang dijamin atomik saat menulis ke pipa.
    • Nilai:512

(yang juga merupakan dd default) i/o ukuran blok) , tetapi nilai sebenarnya biasanya setidaknya 4k. Pada sistem linux terbaru, secara default, 64k.

Jadi ketika Anda mengatur dd proses Anda harus melakukannya di blok faktor berdasarkan tiga nilai:

  1. bs =( obs =PIPE_BUF atau lebih rendah )
  2. n =total jumlah byte yang diinginkan untuk dibaca
  3. hitungan =n / bs

Seperti:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

Anda harus menyinkronkan i/o dengan dd untuk menangani input yang tidak dapat dicari. Dengan kata lain, buat buffer pipa eksplisit dan mereka tidak lagi menjadi masalah. Itu yang dd adalah untuk. Jumlah yang tidak diketahui di sini adalah yes ukuran buffer – tetapi jika Anda memblokirnya ke dikenal kuantitas dengan dd another yang lain maka sedikit perkalian dapat membuat dd aman digunakan untuk menyalin data (tanpa risiko kerusakan karena membaca atau menulis sebagian) bahkan ketika secara sewenang-wenang membatasi input w/ count= w/ setiap jenis input arbitrer pada sistem POSIX apa pun dan tanpa melewatkan satu byte pun.

Berikut cuplikan dari spesifikasi POSIX:

  • ibs= expr
    • Tentukan ukuran blok input, dalam byte, dengan expr (default adalah 512) .
  • obs= expr
    • Tentukan ukuran blok keluaran, dalam byte, dengan expr (default adalah 512) .
  • bs= expr
    • Setel ukuran blok input dan output ke expr byte, menggantikan ibs= dan obs= . Jika tidak ada konversi selain sync , noerror , dan notrunc ditentukan, setiap blok input harus disalin ke output sebagai satu blok tanpa menggabungkan blok pendek.
Terkait:Bagaimana cara membuat tampilan terminal [dilindungi email] dalam huruf tebal?

Anda juga akan menemukan beberapa penjelasan yang lebih baik di sini.


Linux
  1. Di Bash, Kapan Alias ​​​​Kapan Skrip, Dan Kapan Menulis Fungsi?

  2. Ubah Izin Untuk Membaca Tulis Dan Jalankan?

  3. perintah bsdtar – Membaca dan menulis file arsip tape

  1. Baca dan tulis data dari mana saja dengan pengalihan di terminal Linux

  2. Gunakan Perintah Netcat untuk Membaca dan Menulis Data di Seluruh Jaringan di Ubuntu 20.04

  3. Kapan saya harus menggunakan TCP_NODELAY dan kapan TCP_CORK?

  1. Kapan harus memeriksa EINTR dan mengulangi pemanggilan fungsi?

  2. Bagaimana cara membuka, membaca, dan menulis dari port serial di C?

  3. copy_to_user() dan copy_from_user() untuk tipe data dasar