Versão curta: Em que circunstâncias é dd
seguro usar para copiar dados, o que significa que não há risco de corrupção devido a uma leitura ou gravação parcial?
Versão longa - preâmbulo: dd
geralmente é usado para copiar dados, especialmente de ou para um dispositivo ( exemplo ). Às vezes, são atribuídas propriedades místicas de poder acessar dispositivos em um nível mais baixo do que outras ferramentas (quando na verdade é o arquivo do dispositivo que está fazendo a mágica) - mas dd if=/dev/sda
é a mesma coisa que cat /dev/sda
. dd
às vezes é pensado para ser mais rápido, mas cat
pode superá-lo na prática . No entanto, dd
possui propriedades únicas que o tornam genuinamente útil às vezes .
Problema: dd if=foo of=bar
não é, de fato, o mesmo que cat <foo >bar
. Na maioria dos unices¹, dd
faz uma única chamada para read()
. (Acho POSIX confuso sobre o que constitui “lendo um bloco de entrada” em dd
.) Se read()
retornar um resultado parcial (que, de acordo com o POSIX e outros documentos de referência, é permitido, a menos que a documentação de implementação diga o contrário), um bloco parcial será copiado. Exatamente o mesmo problema existe para write()
.
Observações : Na prática, descobri que é dd
capaz de lidar com dispositivos de bloco e arquivos regulares, mas pode ser que não tenha exercido muito. Quando se trata de tubos, não é difícil colocar dd
a culpa; por exemplo, tente este código :
yes | dd of=out bs=1024k count=10
e verifique o tamanho do out
arquivo (é provável que esteja bem abaixo de 10 MB).
Pergunta : Em que circunstâncias é dd
seguro usar para copiar dados? Em outras palavras, quais condições nos tamanhos dos blocos, na implementação, nos tipos de arquivo, etc., podem garantir que dd
copie todos os dados?
(O GNU dd tem um fullblock
sinalizador para dizer para chamar read()
ou write()
em um loop para transferir um bloco completo. Portanto, dd iflag=fullblock
é sempre seguro. Minha pergunta é sobre o caso em que esses sinalizadores (que não existem em outras implementações) não são usados .)
¹ Verifiquei no OpenBSD, GNU coreutils e BusyBox.
count
,iflag=fullblock
é obrigatório (ou, alternativamente,iflag=count_bytes
). Não existeoflag=fullblock
.Respostas:
Das especificações :
bs=
expr
operando for especificado e nenhuma conversão além desync
,noerror
ounotrunc
for solicitada, os dados retornados de cada bloco de entrada serão gravados como um bloco de saída separado; se oread()
retorno for menor que um bloco completo e async
conversão não for especificada, o bloco de saída resultante deverá ter o mesmo tamanho que o bloco de entrada.Então é provavelmente isso que causa sua confusão. Sim, por
dd
ser projetado para bloqueio, por padrão, os parciaisread()
s serão mapeados 1: 1 para os parciaiswrite()
, ou então serãosync
preenchidos com NUL de preenchimento de cauda ou caracteres debs=
tamanho de espaço quandoconv=sync
especificados.Isso significa que
dd
é seguro usar para copiar dados (sem risco de corrupção devido a uma leitura ou gravação parcial) em todos os casos, mas aquele em que ele é arbitrariamente limitado por umcount=
argumento, porque, caso contrário,dd
será felizwrite()
sua saída em blocos de tamanho idêntico para aqueles em que sua entrada eraread()
até que elaread()
passasse completamente. E mesmo esta ressalva é verdade apenas quandobs=
for especificado ouobs=
se não especificado, como a próxima sentença nos estados de especificação:bs=
expr
operando não for especificado, ou uma conversão diferente desync
,noerror
ounotrunc
for solicitada, a entrada deve ser processada e coletada em blocos de saída de tamanho normal até que o final da entrada seja alcançado.Sem
ibs=
e / ouobs=
argumentos, isso não importa - porqueibs
eobs
ambos são do mesmo tamanho por padrão. No entanto, você pode ser explícito sobre o buffer de entrada especificando tamanhos diferentes para um e para não especificarbs=
(porque tem precedência) .Por exemplo, se você fizer:
... então um POSIX
dd
iráwrite()
em pedaços de 512 bytes, coletando cadaread()
byte isolado em um único bloco de saída.Caso contrário, se você fizer ...
... um POSIX
dd
teráread()
no máximo 512 bytes de cada vez, maswrite()
cada bloco de saída do tamanho de megabytes (o kernel permite e exceto, possivelmente, o último - porque esse é EOF) por completo, coletando entrada em blocos de saída de tamanho completo .Também das especificações, no entanto:
count=n
count=
mapas parai?bs=
blocos e, portanto, para lidar com um limite arbitrário emcount=
portabilidade, você precisará de doisdd
s. A maneira mais prática de fazer isso com doisdd
s é canalizar a saída de um para a entrada de outro, o que certamente nos coloca na área de leitura / gravação de um arquivo especial, independentemente do tipo de entrada original.Um canal IPC significa que, ao especificar
[io]bs=
argumentos que, para fazê-lo com segurança, você deve manter esses valores dentro doPIPE_BUF
limite definido pelo sistema . O POSIX afirma que o kernel do sistema deve garantir apenas atômicaread()
s ewrite()
s dentro dos limitesPIPE_BUF
definidos emlimits.h
. POSIX garante quePIPE_BUF
seja pelo menos ...{_POSIX_PIPE_BUF}
... (que também é
dd
o tamanho de bloco de E / S padrão ) , mas o valor real geralmente é de pelo menos 4k. Em um sistema linux atualizado, é, por padrão, 64k.Portanto, quando você configura seus
dd
processos, deve fazê-lo em um fator de bloco com base em três valores:PIPE_BUF
ou menor)Gostar:
Você precisa sincronizar o i / ow /
dd
para manipular entradas não procuráveis. Em outras palavras, torne os buffers de pipe explícitos e eles deixam de ser um problema. É para isso quedd
serve. A quantidade desconhecida aqui éyes
o tamanho do buffer - mas se você bloquear uma quantidade conhecida com outradd
, uma pequena multiplicação informada poderá serdd
segura para copiar dados (sem risco de corrupção devido a leitura ou gravação parcial) mesmo ao limitar arbitrariamente a entrada comcount=
qualquer tipo de entrada arbitrária em qualquer sistema POSIX e sem perder um único byte.Aqui está um trecho da especificação POSIX :
ibs=
expr
expr
obs=
expr
expr
bs=
expr
expr
bytes, substituindoibs=
eobs=
. Se nenhuma conversão diferente desync
,noerror
enotrunc
for especificada, cada bloco de entrada deve ser copiado para a saída como um único bloco sem agregar blocos curtos.Você também encontrará algumas dessas explicações melhor aqui .
fonte
Com soquetes, tubulações ou ttys, read () e write () podem transferir menos do que o tamanho solicitado, portanto, ao usar dd neles, você precisa do sinalizador fullblock. No entanto, com arquivos regulares e dispositivos de bloco, há apenas duas vezes em que eles podem fazer uma breve leitura / gravação: quando você alcança o EOF ou se houver um erro. É por isso que implementações mais antigas do dd sem o sinalizador fullblock eram seguras para a duplicação de disco.
fonte
mke2fs
falhar silenciosamente porque chamouwrite()
com algum tamanho que não fosse o tamanho 2 (3kB IIRC) e o kernel arredondado até uma potência de 2.)cat </dev/sda >/dev/sdb
funciona bem para clonar um disco.cat
escolhe um tamanho de buffer para desempenho; ele não obtém nenhuma informação relacionada ao dispositivo do kernel. Além de fitas, você poderead()
ewrite()
para um dispositivo de bloco de qualquer tamanho. No Linux, pelo menos,st_blksize
depende apenas do sistema de arquivos em que o inode do dispositivo de bloco está localizado, não do dispositivo subjacente.