Veri kopyalamaya ne zaman uygundur? (veya okunduğunda () ve (() kısmi yazdığında)


60

Kısa versiyon: Hangi durumlarda ddveri kopyalamak için kullanmak güvenlidir, kısmi bir okuma veya yazma nedeniyle yolsuzluk riski bulunmadığı anlamına gelir?

Uzun versiyon - başlangıç: dd genellikle verileri bir cihazdan veya bir cihazdan kopyalamak için kullanılır ( örnek ). Bazen, diğer araçlara göre (aslında sihir yapan aygıt dosyası olduğunda) aygıtlara daha düşük bir düzeyde erişebilmenin mistik özelliklerine atfedilir - yine dd if=/dev/sdade aynı şey cat /dev/sda. ddbazen daha hızlı olduğu düşünülmektedir, ancak catpratikte yenebilir . Bununla birlikte, ddbazen onu gerçekten yararlı kılan benzersiz özelliklere sahiptir .

Sorun: dd if=foo of=bar aslında aynı değildir cat <foo >bar. Çoğu united¹de ddtek bir çağrı yapar read(). ( “Giriş bloğunu okuma” nın ne olduğuna ilişkin olarak POSIX'i bulanık buluyorum dd.) read()Kısmi bir sonuç verirse (bu, POSIX ve diğer referans belgelerine göre, uygulama belgeleri aksi belirtilmedikçe izin verilir), kısmi bir blok kopyalanır. Tam olarak aynı konu için var write().

Gözlemler : Uygulamada, ddblok aygıtlarla ve normal dosyalarla başa çıkabileceğimi öğrendim , ancak bu çok fazla kullanmadığım olabilir. Borular söz konusu olduğunda dd, hata yapmak zor değildir ; örneğin bu kodu deneyin :

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

ve outdosyanın boyutunu kontrol edin (10 MB'ın altında olması muhtemeldir).

Soru : Hangi durumlarda ddveri kopyalamak için kullanmak güvenlidir? Başka bir deyişle, blok boyutları, uygulamada, dosya türlerinde vs. hangi koşullar ddtüm verilerin kopyalanmasını sağlayabilir ?

( GNU dd , tam bir bloğu transfer fullblocketmek için çağrı yapmasını read()veya write()bir döngü içinde olduğunu söyleyecek bir bayrağa sahiptir . Her dd iflag=fullblockzaman güvenlidir. Sorum bu bayrakların (diğer uygulamalarda bulunmayan) kullanılmadığı durumla ilgili. .)

BS OpenBSD, GNU coreutils ve BusyBox'ı kontrol ettim.


Tek bir okumadan birkaç MiB okuyabilen bir Unixy sistemi hiç görmedim (2) ...
vonbrand

3
Kullanırken count, iflag=fullblockzorunludur (veya alternatif olarak iflag=count_bytes). Yok oflag=fullblock.
frostschutz

Yanıtlar:


10

Gönderen spec :

  • Eğer bs=exprişlenen belirtilen ve daha dönüşüm için diğer bir sync, noerrorya da notruncistenen, her bir giriş bloğu dönen verilerin ayrı bir çıkış bloğu olarak yazılır; Eğer read()döner bir tam bloğun daha az ve syncdönüşüm belirtilmemişse, elde edilen çıkış bloğu, giriş bloğu ile aynı boyutta olacaktır.

Demek muhtemelen kafan karışıyor. Evet, çünkü ddedilir tasarlanmış varsayılan olarak, kısmi engelleme için read()kısmi 1: s 1 eşleştirilir write()s, ya da başka synckuyruk dolgusu NUL veya boşluk karakter üzerinde d bs=zaman boyutu conv=syncbelirtilir.

Bu şu demektir ddolan (bozulma riski / ağırlık nedeniyle kısmi okuma veya yazma için) kopyalama verisi için kullanılacak güvenli keyfi bir sınırlı edildiği her durumda ancak bir count=argüman, çünkü aksi halde ddolacak mutlu write()aynı büyüklükte bloklar olarak çıkışında girişi tamamen read()geçinceye kadar olanlara read(). Ve hatta bu ihtar tek gerçek olduğunda bs=belirtilen veya obs=edilir değil Spec devletlerde hemen ertesi cümlede olarak, belirtilen:

  • Eğer bs=exprişlenen belirtilen veya daha dönüşüm başka değildir sync, noerrorya da notrunctalep edilir, giriş işlem görecektir ve tam boyutlu çıkış bloklar halinde toplanan girdi sonuna ulaşılıncaya kadar.

Olmadan ibs=ve / veya obs=argümanlar bu önemli olamaz - çünkü ibsve obsvarsayılan olarak aynı boyutta her ikisi de. Ancak, açık alabilirsiniz belirterek girdi ara bellek hakkında farklı boyutlarda biri için ve değil belirterek bs= (o önceliklidir çünkü) .

Örneğin, yaparsanız:

IN| dd ibs=1| OUT

... sonra bir POSIX dd, her bir baytı tek bir çıkış bloğunda toplayarakwrite() 512 baytlık parçalar halinde olacaktır .read()

Aksi takdirde, eğer ...

IN| dd obs=1kx1k| OUT

... bir POSIX bir seferde en fazla 512 bayt ddolacaktır , ancak her megabayt boyutlu çıktı bloğu (çekirdeğin sonuncuya izin veren ve hariç olan - hariç, çünkü bu EOF'dir) girişi tam boyutlu çıktı bloklarına toplayarak .read() write()

Ayrıca, özelliklerinden olsa da:

  • count=n
    • Sadece n giriş bloğunu kopyala .

count=i?bs=blokları eşler ve böylece keyfi bir sınırlamayı ele almak için count=taşınabilir olarak iki ddsaniyeye ihtiyacınız olur . İki dds ile yapmanın en pratik yolu , bir çıktının bir başkasının girişine bağlanmasıdır; bu da bizi orijinal giriş türünden bağımsız olarak özel bir dosyayı okuma / yazma alanına sokar .

Bir IPC borusu [io]bs=, güvenli bir şekilde yapmak için, bu tür değerleri sistemin tanımlanmış PIPE_BUFlimiti dahilinde tutmanız gerektiğini belirtir . POSIX, sistem çekirdeğinin yalnızca içinde read()ve write()içinde PIPE_BUFtanımlandığı şekilde atom atomunu garanti etmesi gerektiğini belirtir limits.h. POSIX garanti PIPE_BUFolması , en azından ...

  • {_POSIX_PIPE_BUF}
    • Bir boruya yazarken atomik olması garanti edilen maksimum bayt sayısı.
    • Değer: 512

... (ayrıca varsayılan giriş dd/ çıkış blok büyüklüğü olur ) , ancak gerçek değer genellikle en az 4k'dir. Güncel bir linux sisteminde, varsayılan olarak 64k'dir.

Dolayısıyla, ddsüreçlerinizi ayarlarken bunu üç değere dayalı bir blok faktörü üzerinde yapmalısınız :

  1. bs = (obs = PIPE_BUFveya daha az)
  2. n = okunan toplam bayt sayısı
  3. sayım = n / bs

Sevmek:

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

ddAranamayan girdileri işlemek için i / ow / ile senkronize etmeniz gerekir . Başka bir deyişle, boru tamponlarını belirginleştirin ve problem olmaktan çıkın. Bunun ddiçin var. Buradaki bilinmeyen miktarın yesarabellek boyutu - ancak bunu başka bir taneyle bilinen bir miktarın üzerine çıkarırsanız dd, az miktarda bilgilendirilmiş bir çarpma dd verilerin kopyalanması için güvenli hale getirebilir (kısmi okuma veya yazma nedeniyle bozulma riski olmadan)count= herhangi bir POSIX sistemindeki herhangi bir isteğe bağlı giriş tipini isteğe bağlı olarak sınırsızken ve bir bayt eksik olmadan bile olsa .

İşte POSIX özelliklerinden bir pasaj :

  • ibs=expr
    • Giriş bloğu boyutunu bayt olarak belirtin (varsayılan 512) .expr
  • obs=expr
    • Çıkış bloğu boyutunu bayt olarak belirtin (varsayılan 512) .expr
  • bs=expr
    • İçin hem giriş hem de çıkış bloğu boyutlarını ayarlama exprbayt yerine geçer ibs=ve obs=. Daha dönüşüm için diğer ise sync, noerrorve notruncbelirtilen her bir giriş bloğu kısa blok yığılmasma neden olmadan tek bir blok olarak çıkışına kopyalanmalıdır.

Ayrıca burada daha iyi anlatılanları da bulacaksınız .


5

Soketler, borular veya tty'ler ile, read () ve write () istenen boyuttan daha azını aktarabilir, bu nedenle dd kullanırken tam blok bayrağı gerekir. Bununla birlikte, normal dosyalar ve engelleme aygıtlarıyla, kısa bir okuma / yazma yapabildiklerinde yalnızca iki kez: EOF'ye ulaştığınızda veya bir hata olduğunda. Bu nedenle gd'nin tam blok bayrağı olmadan yapılan eski uygulamalarının disk çoğaltması için kullanımı güvenliydi.


Bu tüm modern birliklerin doğru mu? (Linux'un bir noktada doğru olmadığını, muhtemelen 2.0.x veya 2.2.x'e kadar olduğunu biliyorum. Sessizce mke2fsbaşarısız olduğumu hatırlıyorum, çünkü write()2 büyüklüğünde olmayan bir güç (3kB IIRC) ve çekirdek yuvarlanmış 2)
Gilles 'SO- kötülük' dur

@Gilles tamamen farklı bir konuya benziyor. Her zaman uygun blok boyutunun bir çoğunu blok cihazlarıyla kullanmanız gerekir. Tüm politikalar için geçerli olduğundan ve Windows için de geçerli olduğundan eminim.
psusi

Bantlardan başka, bir cihazın blok büyüklüğü tamamen çekirdeğin umurunda olduğu veya ummadığı içindir. cat </dev/sda >/dev/sdbbir diski klonlamak için gayet iyi çalışıyor.
Gilles 'SO- kötülük yapmayı kes'

@Gilles, kedinin OrbWeaver'ın cevabında belirttiği gibi uygun blok boyutunu kullanmasından kaynaklanıyor.
psusi

Hayır, “uygun blok boyutu” yoktur. catperformans için bir tampon boyutu seçer; çekirdekten aygıtla ilgili herhangi bir bilgi alamaz. Dışında kasetleri yapabilirsiniz read()ve write()herhangi bir boyut ile bir blok cihazına. En azından Linux'ta st_blksize, temel alınan cihaza değil, yalnızca blok cihaz inode'unun bulunduğu dosya sistemine bağlıdır.
Gilles 'SO- kötü olmayı durdur' 17
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.