Versi singkat: Dalam keadaan apa dd
aman digunakan untuk menyalin data, aman berarti bahwa tidak ada risiko korupsi karena membaca atau menulis sebagian?
Versi panjang - mukadimah: dd
sering digunakan untuk menyalin data, terutama dari atau ke perangkat ( contoh ). Kadang-kadang dikaitkan sifat mistis karena dapat mengakses perangkat pada tingkat yang lebih rendah daripada alat lain (padahal sebenarnya itu adalah file perangkat yang melakukan keajaiban) - namun dd if=/dev/sda
hal yang sama cat /dev/sda
. dd
kadang-kadang dianggap lebih cepat, tetapi cat
dapat mengalahkannya dalam praktik . Meskipun demikian, dd
memiliki sifat unik yang membuatnya kadang-kadang benar-benar bermanfaat .
Masalah: dd if=foo of=bar
sebenarnya tidak sama dengan cat <foo >bar
. Pada sebagian besar uni¹, dd
lakukan satu panggilan ke read()
. (Saya menemukan POSIX kabur pada apa yang disebut "membaca blok input" dd
.) Jika read()
mengembalikan hasil parsial (yang, menurut POSIX dan dokumen referensi lainnya, diizinkan kecuali kecuali dokumentasi implementasi mengatakan sebaliknya), sebagian blok disalin. Persis masalah yang sama ada untuk write()
.
Pengamatan : Dalam praktiknya, saya telah 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 dd
menyalahkan; misalnya coba kode ini :
yes | dd of=out bs=1024k count=10
dan periksa ukuran out
file (kemungkinan berada di bawah 10MB).
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
flag untuk memberitahukannya untuk memanggil read()
atau write()
dalam satu loop sehingga untuk mentransfer blok penuh. Jadi dd iflag=fullblock
selalu aman. Pertanyaan saya adalah tentang kasus ketika flag-flag ini (yang tidak ada pada implementasi lain) tidak digunakan .)
¹ Saya sudah memeriksa OpenBSD, GNU coreutils dan BusyBox.
count
,iflag=fullblock
ini wajib (atau, sebagai alternatif,iflag=count_bytes
). Tidak adaoflag=fullblock
.Jawaban:
Dari spec :
bs=
expr
operan ditentukan dan tidak ada konversi selainsync
,,noerror
ataunotrunc
diminta, data yang dikembalikan dari setiap blok input harus ditulis sebagai blok output terpisah; jikaread()
pengembalian kurang dari blok penuh dansync
konversi tidak ditentukan, blok output yang dihasilkan harus sama dengan blok input.Jadi ini mungkin yang menyebabkan kebingungan Anda. Ya, karena
dd
ini dirancang untuk memblokir, secara default parsialread()
s akan dipetakan 1: 1 sampai parsialwrite()
s, atausync
d pada ekor bantalan NUL atau karakter ruang untukbs=
ukuran ketikaconv=sync
ditentukan.Ini berarti bahwa
dd
adalah aman digunakan untuk menyalin data (w / tidak ada risiko korupsi karena membaca sebagian atau write) di setiap kasus tapi satu di mana ia sewenang-wenang dibatasi olehcount=
argumen, karena jika tidakdd
akan dengan senang hatiwrite()
output dalam blok berukuran identik untuk mereka yang inputnyaread()
sampairead()
benar-benar melewatinya. Dan bahkan peringatan ini hanya berlaku bilabs=
ditentukan atauobs=
yang tidak ditentukan, sebagai kalimat berikutnya di negara-negara spesifikasi:bs=
expr
operan tidak ditentukan, atau konversi selainsync
,,noerror
ataunotrunc
diminta, input harus diproses dan dikumpulkan ke dalam blok output berukuran penuh sampai akhir input tercapai.Tanpa
ibs=
dan / atauobs=
argumen ini tidak masalah - karenaibs
danobs
keduanya berukuran sama secara default. Namun, Anda bisa mendapatkan secara eksplisit tentang buffer input dengan menentukan ukuran yang berbeda untuk salah satu dan tidak menentukanbs=
(karena itu diutamakan) .Misalnya, jika Anda melakukannya:
... maka POSIX
dd
akanwrite()
dalam potongan 512 byte dengan mengumpulkan setiapread()
byte tunggal ke dalam satu blok output.Jika tidak, jika Anda ...
... POSIX
dd
akanread()
maksimal 512 byte pada satu waktu, tetapiwrite()
setiap blok output berukuran megabyte (kernel memungkinkan dan mengecualikan yang terakhir - karena EOF) secara penuh dengan mengumpulkan input ke dalam blok output berukuran penuh .Juga dari spec, meskipun:
count=n
count=
peta kei?bs=
blok, dan untuk menangani batas sewenang-wenangcount=
portable Anda akan membutuhkan duadd
s. Cara paling praktis untuk melakukannya dengan duadd
s adalah dengan menyalurkan output dari satu ke input yang lain, yang tentunya menempatkan kita dalam bidang membaca / menulis file khusus terlepas dari jenis input asli.Pipa IPC berarti bahwa ketika menetapkan
[io]bs=
argumen bahwa, untuk melakukannya dengan aman, Anda harus menyimpan nilai-nilai tersebut dalamPIPE_BUF
batas yang ditentukan sistem . POSIX menyatakan bahwa sistem kernel hanya harus menjamin atomread()
danwrite()
s dalam batas-batasPIPE_BUF
sebagaimana didefinisikan dalamlimits.h
. POSIX menjamin bahwaPIPE_BUF
menjadi setidaknya ...{_POSIX_PIPE_BUF}
... (yang juga merupakan default
dd
i / o blocksize) , tetapi nilai sebenarnya biasanya setidaknya 4k. Pada sistem linux yang terbaru, secara default, 64k.Jadi ketika Anda mengatur
dd
proses Anda, Anda harus melakukannya pada faktor blok berdasarkan pada tiga nilai:PIPE_BUF
atau lebih kecil)Suka:
Anda harus menyinkronkan i / ow /
dd
untuk menangani input yang tidak dapat dicari. Dengan kata lain, buat penyangga pipa eksplisit dan tidak lagi menjadi masalah. Itu untuk apadd
. Kuantitas yang tidak diketahui di sini adalahyes
ukuran buffer - tetapi jika Anda memblokirnya ke kuantitas yang diketahui dengan yang lain,dd
maka penggandaan informasi yang sedikit dapat membuatdd
aman untuk digunakan untuk menyalin data (tanpa risiko korupsi karena membaca atau menulis sebagian) bahkan ketika secara sewenang-wenang membatasi input w /count=
w / sembarang tipe input sembarang pada sistem POSIX dan tanpa melewatkan satu byte pun.Berikut cuplikan dari spec POSIX :
ibs=
expr
expr
obs=
expr
expr
bs=
expr
expr
byte, menggantikanibs=
danobs=
. Jika tidak ada konversi selainsync
,,noerror
dannotrunc
ditentukan, setiap blok input harus disalin ke output sebagai satu blok tanpa mengagregasi blok pendek.Anda juga akan menemukan beberapa penjelasan yang lebih baik di sini .
sumber
Dengan soket, pipa, atau ttys, read () dan write () dapat mentransfer kurang dari ukuran yang diminta, jadi ketika menggunakan dd pada ini, Anda memerlukan bendera blok penuh. Namun, dengan file biasa dan blokir perangkat, hanya ada dua kali ketika mereka dapat melakukan baca / tulis singkat: ketika Anda mencapai EOF, atau jika ada kesalahan. Inilah sebabnya mengapa implementasi lama dari dd tanpa tanda blok penuh aman digunakan untuk duplikasi disk.
sumber
mke2fs
gagal secara diam-diam karena disebutwrite()
dengan beberapa ukuran non-power-of-2 (3kB IIRC) dan kernel bulat turun ke kekuatan 2.)cat </dev/sda >/dev/sdb
berfungsi dengan baik untuk mengkloning disk.cat
mengambil ukuran buffer untuk kinerja; itu tidak mendapatkan informasi terkait perangkat dari kernel. Terlepas dari kaset, Anda dapatread()
danwrite()
ke perangkat blok dengan ukuran apa pun. Setidaknya di Linux,st_blksize
hanya bergantung pada sistem file tempat inode perangkat blok berada, bukan pada perangkat yang mendasarinya.