Versión corta: ¿En qué circunstancias es dd
seguro usar para copiar datos, lo que significa que no hay riesgo de corrupción debido a una lectura o escritura parcial?
Versión larga - preámbulo: a dd
menudo se usa para copiar datos, especialmente desde o hacia un dispositivo ( ejemplo ). A veces se le atribuyen propiedades místicas de poder acceder a dispositivos en un nivel más bajo que otras herramientas (cuando en realidad es el archivo del dispositivo el que está haciendo la magia), pero dd if=/dev/sda
es lo mismo cat /dev/sda
. dd
a veces se piensa que es más rápido, pero cat
puede vencerlo en la práctica . Sin embargo, dd
tiene propiedades únicas que lo hacen realmente útil a veces .
Problema: dd if=foo of=bar
no es, de hecho, lo mismo que cat <foo >bar
. En la mayoría de las unidades¹, dd
realiza una sola llamada a read()
. (Encuentro POSIX borroso en lo que constituye "leer un bloque de entrada" en dd
). Si read()
devuelve un resultado parcial (que, según POSIX y otros documentos de referencia, está permitido a menos que la documentación de implementación indique lo contrario), se copia un bloque parcial. Exactamente el mismo problema existe para write()
.
Observaciones : en la práctica, he descubierto que dd
puede hacer frente a dispositivos de bloque y archivos normales, pero puede ser que no lo haya ejercitado demasiado. Cuando se trata de tuberías, no es difícil dd
culpar; por ejemplo prueba este código :
yes | dd of=out bs=1024k count=10
y verifique el tamaño del out
archivo (es probable que sea muy inferior a 10 MB).
Pregunta : ¿En qué circunstancias es dd
seguro usar para copiar datos? En otras palabras, ¿qué condiciones en los tamaños de bloque, en la implementación, en los tipos de archivo, etc., pueden garantizar que dd
se copiarán todos los datos?
( GNU dd tiene una fullblock
bandera para decirle que llame read()
o write()
en un bucle para transferir un bloque completo. Por dd iflag=fullblock
lo tanto, siempre es seguro. Mi pregunta es sobre el caso cuando estas banderas (que no existen en otras implementaciones) no se usan .)
Checked He comprobado OpenBSD, GNU coreutils y BusyBox.
count
,iflag=fullblock
es obligatorio (o, alternativamente,iflag=count_bytes
). No hay ningunaoflag=fullblock
.Respuestas:
De la especificación :
bs=
expr
se especifica el operando y no se solicitan conversiones que no seansync
,noerror
onotrunc
se soliciten, los datos devueltos de cada bloque de entrada se escribirán como un bloque de salida separado; Si elread()
retorno es inferior a un bloque completo ysync
no se especifica la conversión, el bloque de salida resultante será del mismo tamaño que el bloque de entrada.Entonces esto es probablemente lo que causa tu confusión. Sí, debido a que
dd
está diseñado para el bloqueo, de manera predeterminada, losread()
s parciales se asignarán 1: 1 awrite()
s parciales , o bien sesync
dotarán de NUL de relleno de cola o caracteres de espaciobs=
cuandoconv=sync
se especifique.Esto significa que
dd
es seguro de usar para copiar datos (sin riesgo de corrupción debido a una lectura o escritura parcial) en todos los casos, excepto uno en el que está limitado arbitrariamente por uncount=
argumento, porque de lo contrariodd
felizmentewrite()
su salida en bloques de tamaño idéntico a aquellos en los que su entrada fueread()
hasta queread()
la atravesó por completo. E incluso esta advertencia es sólo es cierto cuandobs=
se especifica oobs=
se no se especifica, como el siguiente oración en los estados de especificaciones:bs=
expr
no se especifica el operando , o si se solicita una conversión diferente async
,noerror
onotrunc
se solicita, la entrada se procesará y se recopilará en bloques de salida de tamaño completo hasta llegar al final de la entrada.Sin
ibs=
y / oobs=
argumentos esto no puede importa - porqueibs
yobs
son a la vez el mismo tamaño por defecto. Sin embargo, puede ser explícito sobre el almacenamiento en búfer de entrada especificando diferentes tamaños para cualquiera y no especificandobs=
(porque tiene prioridad) .Por ejemplo, si haces:
... entonces un POSIX lo
dd
haráwrite()
en fragmentos de 512 bytes al recopilar cadaread()
byte individualmente en un solo bloque de salida.De lo contrario, si lo haces ...
... un POSIX
dd
tendráread()
un máximo de 512 bytes a la vez, perowrite()
cada bloque de salida de un tamaño de megabyte (el kernel permite y exceptúa posiblemente el último, porque eso es EOF) completo al recopilar la entrada en bloques de salida de tamaño completo .Sin embargo, también de la especificación:
count=n
count=
asigna ai?bs=
bloques, por lo que para manejar un límite arbitrario de formacount=
portátil necesitarás dosdd
s. La forma más práctica de hacerlo con dosdd
s es canalizando la salida de uno en la entrada de otro, lo que seguramente nos coloca en el ámbito de la lectura / escritura de un archivo especial independientemente del tipo de entrada original.Una tubería IPC significa que al especificar
[io]bs=
argumentos que, para hacerlo de manera segura, debe mantener dichos valores dentro delPIPE_BUF
límite definido del sistema . POSIX establece que el núcleo del sistema sólo debe garantizar atómicasread()
s ywrite()
s dentro de los límites dePIPE_BUF
como se define enlimits.h
. POSIX garantiza quePIPE_BUF
sea al menos ...{_POSIX_PIPE_BUF}
... (que también es el
dd
tamaño de bloque de E / S predeterminado ) , pero el valor real suele ser al menos 4k. En un sistema Linux actualizado es, por defecto, 64k.Entonces, cuando configura sus
dd
procesos, debe hacerlo en un factor de bloque basado en tres valores:PIPE_BUF
o menor)Me gusta:
Tiene que sincronizar i / ow /
dd
para manejar entradas no buscables. En otras palabras, haga explícitos los amortiguadores de tubería y dejarán de ser un problema. Para esodd
es eso . La cantidad desconocida aquí esyes
el tamaño del búfer, pero si bloquea eso a una cantidad conocida con otra,dd
entonces una pequeña multiplicación informada puede serdd
segura de usar para copiar datos (sin riesgo de corrupción debido a una lectura o escritura parcial) incluso cuando limite arbitrariamente la entrada concount=
cualquier tipo de entrada arbitraria en cualquier sistema POSIX y sin perder un solo byte.Aquí hay un fragmento de la especificación POSIX :
ibs=
expr
expr
obs=
expr
expr
bs=
expr
expr
bytes, reemplazandoibs=
yobs=
. Si no se especifica otra conversión quesync
,noerror
ynotrunc
se especifica, cada bloque de entrada se copiará a la salida como un bloque único sin agregar bloques cortos.También encontrarás algo de esto mejor explicado aquí .
fuente
Con sockets, tuberías o ttys, read () y write () pueden transferir menos del tamaño solicitado, por lo que cuando se usa dd en estos, necesita el indicador de bloque completo. Sin embargo, con los archivos normales y los dispositivos de bloqueo, solo hay dos veces cuando pueden hacer una lectura / escritura corta: cuando llega a EOF, o si hay un error. Esta es la razón por la cual las implementaciones anteriores de dd sin el indicador de bloque completo eran seguras de usar para la duplicación de disco.
fuente
mke2fs
falló en silencio porque llamówrite()
con un tamaño no potenciado de 2 (3kB IIRC) y el núcleo redondeado hasta un poder de 2.)cat </dev/sda >/dev/sdb
funciona bien para clonar un disco.cat
selecciona un tamaño de búfer para el rendimiento; no obtiene ninguna información relacionada con el dispositivo del núcleo. Aparte de las cintas, se puederead()
ywrite()
a un dispositivo de bloque con cualquier tamaño. Al menos en Linux,st_blksize
depende solo del sistema de archivos donde se encuentra el inodo del dispositivo de bloque, no del dispositivo subyacente.