ddはいつデータのコピーに適していますか? (またはread()とwrite()が部分的な場合)

ddはいつデータのコピーに適していますか? (またはread()とwrite()が部分的な場合)

簡潔なバージョン:どのような状況でデータをコピーするのに安全に使用できますかdd?つまり、部分的な読み取りまたは書き込みによる損傷の危険性がないという意味ですか?

長いバージョン - 序文: dd通常、特にデバイスからデバイスにデータをコピーするために使用されます(はい)。時々、他のツールよりもデバイスの不思議な属性への低レベルのアクセス権を持つと見なされますが(実際には魔法を実行するデバイスファイルです)、dd if=/dev/sda時にはcat /dev/sdaddcat実戦では勝てる。それにもかかわらず、dd独自の特性を持ち、時には便利です。

質問: dd if=foo of=bar実際にcat <foo >bar。ほとんどの unice1 ではdd一度だけ呼び出すだけです。read()。 (私が見つけたときPOSIX「読み込み入力ブロック」の構成がぼやけていますdd。 )read()部分的な結果が返されると(実装文書に別段の指示がない限り、POSIXおよび他の参照文書に従って許可されている場合)、部分ブロックがコピーされます。まったく同じ問題がありますwrite()

観察結果:実際にブロックデバイスと一般ファイルの両方を処理していることがわかりましたdd。しかし、これは実際に使った経験があまりなかったためかもしれません。パイプラインを使用すると、ddエラーを見つけるのは難しくありません。例えばこのコード:

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

そして、ファイルサイズを確認してくださいout(おそらく10 MB未満です)。

質問dd:どのような状況でデータコピーに安全に使用できますか?つまり、ブロックサイズ、実装、ファイルタイプなど、どのような条件がすべてのddデータがコピーされることを保証しますか?

GNU dd完全なチャンクを転送するために呼び出すかループfullblockするように指示するフラグがあります。だからいつも安全です。私の質問は、これらのフラグが使用されていない場合(他の実装には存在しない場合)に関するものです。 )read()write()dd iflag=fullblock

1OpenBSD 、GNU coreutils、BusyBoxを確認しました。

答え1

~から仕様:

  • もしbs=exprオペランドが指定されsyncnoerrorまたは以外の変換が要求されていない場合、各入力ブロックから返されたデータはブロック全体より少なく、変換が指定されていないnotrunc場合は別々の出力ブロックに書き込まれます。入力チャンクのサイズは同じです。read()sync

それで、それはおそらくあなたの混乱を引き起こすでしょう。うん、そうddだからデザイン済みブロックの場合、部分 s は基本的にread()部分 s に 1:1 にマップされます。それ以外の場合は、write()指定時にsync末尾のNULまたは空白文字がサイズに合うように埋められますbs=conv=sync

これはdd次のことを意味します。データのコピーに安全です(部分的な読み取りまたは書き込みによる破損の危険性なし)パラメータによってランダムに制限される場合を除き、すべての場合に入力が完全に渡されるまで、入力と同じサイズのチャンクで出力されますcount=。この警告でさえddwrite()read()read()唯一の本物bs=指定された場合obs=、またはいいえ仕様の次の文に指定されているとおりに指定されます。

  • もしbs=exprsyncオペランドが指定されていない場合、noerrorまたはそれ以外の変換が要求された場合は、notrunc入力を処理する必要があります。フルサイズ出力ブロックとして収集入力が終わるまで。

ibs=および/またはパラメータがない場合、これは重要ではありません。obs=基本的には、ibsとのサイズが同じですobs。しかし、あなたは明らかにあり得る入力バッファリングに関しては、以下を指定します。異なるサイズどんな金額でもいいえ指定するbs= (優先順位だから)

たとえば、次のような場合:

IN| dd ibs=1| OUT

...これで、POSIXは512バイト単位になりますddwrite()集めるread()バイトを単一の出力ブロックに入れます。

それ以外の場合は...

IN| dd obs=1kx1k| OUT

...POSIXddread() 最高一度に512バイトですが、write()各メガバイトサイズの出力ブロック(カーネルは最後の可能性を許可して除外します - それがEOFだからです)入力を収集して完全にフルサイズ出力ブロック

ただし、仕様でも次のようになります。

  • count=n
    • コピーのみ可能N入力ブロック。

count=ブロックにマッピングされるため、移植性のランダムな制限をi?bs=処理するにはcount=2つが必要ですdd。 2つのsでこれを行う最も実用的な方法ddは、ある出力を別の入力にパイプすることです。これは確かに私たちが読書領域に入るようにします。 /書き込みㄱ。特殊ファイル元の入力タイプに関係なく。

IPC パイプは、args を指定する際に[io]bs=安全に実行するために、値をシステム定義のPIPE_BUF制限内に保持する必要があることを意味します。 POSIXは、システムカーネルが原子sとsが定義read()されたwrite()範囲内にあることを保証する必要があることを規定しています。PIPE_BUFlimits.hPIPE_BUFPOSIX保証少なくとも...

  • {_POSIX_PIPE_BUF}
    • パイプに書き込むときに原子性を保証する最大バイト数。
    • 値:512

...dd(これはデフォルトのI / Oブロックサイズでもあります。)ただし、実際の値は通常少なくとも4kです。最新のLinuxシステムでは、デフォルトでは64kです。

したがって、プロセスを設定するときはddブロックで実行する必要があります。要因3つの価値に基づいています。

  1. bs=(obs=PIPE_BUF以下)
  2. n = 読み込む総バイト数
  3. 個数 = n/BS

良い:

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

dd検索できない入力を処理するには、i / ow /を同期する必要があります。つまり、パイプバッファを明示的に作成しても問題はありません。それがdd目的です。ここで不明な数量はyesバッファサイズです。しかし、次のようにブロックするとみんな知ってる異なる数量を使っddて少しの乗算をするとdd データのコピーに安全です(部分的な読み取りまたは書き込みによる破損の危険性なし)すべてのPOSIXシステムでも、任意count=の入力タイプに入力をランダムに制限し、シングルバイトを失うことはありません。

これはから来たものですPOSIX仕様:

  • ibs=expr
    • 入力ブロックサイズをバイト単位で指定します。expr (既定値は 512 です)
  • obs=expr
    • 出力ブロックサイズをバイト単位で指定expr (既定値は 512 です)
  • bs=expr
    • 入出力ブロックサイズを次に設定します。expr、、、ibs=およびobs=その他の変換が指定されていない場合、各入力ブロックは短いブロックを集約せずに単一ブロックとして出力にコピーする必要があります。syncnoerrornotrunc

また、これらのいくつかはよりよく説明されていることがわかります。ここ

答え2

ソケット、パイプ、または tty の場合、read() および write() は要求されたサイズよりも少なく送信できるため、dd を使用する場合は fullblock フラグが必要です。ただし、通常のファイルおよびブロックデバイスの場合、簡単な読み取り/書き込みが可能な場合は、EOFに達した場合、またはエラーが発生した場合の2回だけです。これが fullblock フラグのない古い dd 実装をディスクコピーに安全に使用できる理由です。

関連情報