Краткая версия: При каких обстоятельствах dd
безопасно использовать для копирования данных, это означает, что нет риска повреждения из-за частичного чтения или записи?
Длинная версия - преамбула: dd
часто используется для копирования данных, особенно с или на устройство ( пример ). Иногда это объясняется мистическими свойствами доступа к устройствам на более низком уровне, чем у других инструментов (хотя на самом деле это файл устройства, который творит чудеса) - но dd if=/dev/sda
это то же самое, что и cat /dev/sda
. dd
Иногда думают, что это быстрее, но cat
может побить его на практике . Тем не менее, dd
обладает уникальными свойствами, которые иногда делают его действительно полезным .
Проблема: dd if=foo of=bar
на самом деле это не то же самое, что cat <foo >bar
. На большинстве офисов¹, dd
делает один звонок read()
. (Я нахожу POSIX нечетким в том, что представляет собой «чтение блока ввода» dd
.) Если read()
возвращается частичный результат (который, согласно POSIX и другим справочным документам, разрешается, если в документации реализации не указано иное), частичный блок копируется. Точно такая же проблема существует для write()
.
Наблюдения : на практике я обнаружил, что он dd
может справиться с блочными устройствами и обычными файлами, но это может быть просто из-за того, что я не слишком много использовал его. Когда дело доходит до труб, это не трудно поставить dd
в вину; например попробуйте этот код :
yes | dd of=out bs=1024k count=10
и проверьте размер out
файла (вероятно, он будет меньше 10 МБ).
Вопрос : при каких обстоятельствах dd
безопасно использовать данные для копирования? Другими словами, какие условия относительно размеров блоков, реализации, типов файлов и т. Д. Могут обеспечить dd
копирование всех данных?
(У GNU dd есть fullblock
флаг, указывающий, что он должен вызываться read()
или write()
в цикле, чтобы передать полный блок. Так dd iflag=fullblock
всегда безопасно. Мой вопрос касается случая, когда эти флаги (которых нет в других реализациях) не используются .)
Checked Я проверил OpenBSD, GNU coreutils и BusyBox.
count
,iflag=fullblock
это обязательно (или, альтернативно,iflag=count_bytes
). Существует нетoflag=fullblock
.Ответы:
Из спецификации :
bs=
expr
операнд определен и никаких преобразований, кромеsync
,noerror
илиnotrunc
просят, то данные , возвращенные из каждого входного блока должна быть записана в виде отдельного выходного блока; еслиread()
возвращается меньше, чем полный блок, иsync
преобразование не указано, результирующий выходной блок должен быть того же размера, что и входной блок.Так что это, вероятно, то, что вызывает ваше замешательство. Да, поскольку
dd
он предназначен для блокировки, по умолчанию частичныеread()
s будут отображаться в пропорции 1: 1 в частичныеwrite()
s, или жеsync
,bs=
еслиconv=sync
задано значение NUL или символьный пробел в d, если задано.Это означает , что
dd
является безопасным для использования для копирования данных (ж / без риска коррупции из - за частичное чтение или запись) , в каждом случае , кроме одного , в котором она произвольно ограничена поcount=
аргументу, поскольку в противном случаеdd
будет счастливоwrite()
его выход в одинаковом размере блоков к тем, в которых вход былread()
до тех пор, пока онread()
полностью не прошел через него. И даже это предостережение только справедливо , еслиbs=
указан илиobs=
в не указан, как следующее предложение в спецификации говорится:bs=
expr
операнд не указан, или преобразования, кромеsync
,noerror
илиnotrunc
запрашиваются, вход должен быть обработан и собран в полноразмерные выходных блоки до конца ввода не будет достигнут.Без
ibs=
и / илиobs=
аргументы , это не может дело - потому чтоibs
иobs
оба тот же размер по умолчанию. Тем не менее, вы можете получить явные сведения о буферизации ввода, указав разные размеры для каждого и не указавbs=
(потому что это имеет приоритет) .Например, если вы делаете:
... тогда POSIX
dd
будетwrite()
состоять из 512 байтов, собирая каждыйread()
отдельный байт в один выходной блок.В противном случае, если вы делаете ...
... POSIX
dd
будетread()
максимум 512 байт за раз, ноwrite()
каждый выходной блок размером с мегабайт (ядро разрешает и исключает, возможно, последний - потому что это EOF) полностью, собирая входные данные в полноразмерные выходные блоки .Также из спецификации, хотя:
count=n
count=
сопоставляется сi?bs=
блоками, и поэтому для обработки произвольного ограничения наcount=
переносимость вам понадобится дваdd
s. Наиболее практичный способ сделать это с двумяdd
s - это передать вывод одного на вход другого, что, несомненно, ставит нас в область чтения / записи специального файла независимо от исходного типа ввода.Канал IPC означает, что при указании
[io]bs=
аргументов, чтобы сделать это безопасно, вы должны держать такие значения в пределах определенногоPIPE_BUF
предела системы. POSIX заявляет, что ядро системы должно гарантировать только атомарныеread()
s иwrite()
s в пределах,PIPE_BUF
определенных вlimits.h
. POSIX гарантирует, чтоPIPE_BUF
будет хотя бы ...{_POSIX_PIPE_BUF}
... (который также является
dd
размером блока ввода-вывода по умолчанию ) , но фактическое значение обычно составляет не менее 4k. В современной системе Linux это по умолчанию 64 КБ.Поэтому, когда вы настраиваете свои
dd
процессы, вы должны делать это с блочным фактором на основе трех значений:PIPE_BUF
или меньше)Подобно:
Вы должны синхронизировать I / OW /
dd
для обработки входов без поиска. Другими словами, сделайте конвейерные буферы явными, и они перестанут быть проблемой. Вот для чегоdd
. Неизвестное количество здесь -yes
это размер буфера, но если вы заблокируете его в известном количестве с другим,dd
то небольшое информированное умножение может бытьdd
безопасно использовано для копирования данных (без риска повреждения из-за частичного чтения или записи) даже когда произвольно ограничивает вводcount=
с любым произвольным типом ввода в любой системе POSIX и не пропускает ни одного байта.Вот фрагмент из спецификации POSIX :
ibs=
expr
expr
obs=
expr
expr
bs=
expr
expr
байтах, заменяяibs=
иobs=
. Если не указано никакого преобразования, кромеsync
,noerror
иnotrunc
, каждый входной блок должен быть скопирован на выход как один блок без агрегирования коротких блоков.Вы также найдете некоторые из этих объяснений лучше здесь .
источник
С сокетами, pipe или ttys read () и write () могут передавать меньше, чем запрошенный размер, поэтому при использовании dd для них вам нужен флаг fullblock. Однако с обычными файлами и блочными устройствами они могут выполнить короткое чтение / запись только два раза: когда вы достигнете EOF или возникнет ошибка. Вот почему более старые реализации dd без флага fullblock были безопасны для дублирования диска.
источник
mke2fs
неисправного молча , потому что это называетсяwrite()
с некоторым Неэнергетические-из-2 размера (3KB IIRC) и ядро округлой до степени 2.)cat </dev/sda >/dev/sdb
прекрасно работает, чтобы клонировать диск.cat
выбирает размер буфера для производительности; он не получает никакой информации об устройстве из ядра. Помимо кассет, можноread()
иwrite()
на блочное устройство любого размера. В Linux, по крайней мере,st_blksize
зависит только от файловой системы, в которой находится inode блочного устройства, а не от базового устройства.