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 selainsync
,noerror
, ataunotrunc
diminta, data yang dikembalikan dari setiap blok input harus ditulis sebagai blok output yang terpisah; jikaread()
mengembalikan kurang dari satu blok penuh dansync
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 selainsync
,noerror
, ataunotrunc
diminta, input akan diproses dan dikumpulkan menjadi blok output berukuran penuh sampai akhir input tercapai.
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:
- bs =( obs =
PIPE_BUF
atau lebih rendah ) - n =total jumlah byte yang diinginkan untuk dibaca
- 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) .
- Tentukan ukuran blok input, dalam byte, dengan
obs=
expr
- Tentukan ukuran blok keluaran, dalam byte, dengan
expr
(default adalah 512) .
- Tentukan ukuran blok keluaran, dalam byte, dengan
bs=
expr
- Setel ukuran blok input dan output ke
expr
byte, menggantikanibs=
danobs=
. Jika tidak ada konversi selainsync
,noerror
, dannotrunc
ditentukan, setiap blok input harus disalin ke output sebagai satu blok tanpa menggabungkan blok pendek.
- Setel ukuran blok input dan output ke
Anda juga akan menemukan beberapa penjelasan yang lebih baik di sini.