4

Недавно я частично восстановил 2.5TB неисправный диск. ddrescue создал образ, который я могу смонтировать в режиме loopback, 2,1 ТБ восстановлено, 450 ГБ отсутствуют, к сожалению, распределены по всему диску.

Чтобы увидеть, какие файлы затронуты, я мог бы использовать filefrag -v и посмотреть файл карты, сгенерированный ddrescue .

НО это заняло бы целую вечность. Я обнаружил, что, поскольку восстанавливаю только видеофайлы, большие нули не ожидаются, но они присутствуют, где ddrescue не считывает данные с диска.

Поэтому мне понадобится команда для сканирования файла, если в файле есть (произвольный) большой патч всех нулей. В действительности, они всегда будут кратны 512 байтам и всегда начинаются с адреса 512 байт. Есть ли команда, которая может сканировать файл на наличие такой двоичной последовательности байтов (т. Е. 512 × '\0')?

5 ответов5

4

Я изменил ответ xenoid, чтобы специально искать нулевые байты, основываясь на ответе этого другого вопроса о том, как искать нулевые байты:

grep -Pal '\x00{512}' the_files
2

Заставить grep явно искать нулевые символы ускользает от меня. Тем не менее, заставить его искать 512 последовательных одинаковых символов (что маловероятно) несколько проще:

grep -Eal '(.)\1{511}' the_files

перечисляет файлы, в которых была найдена последовательность из 512 идентичных символов. Параметр -a необходим для соответствия нулевым символам (в противном случае они рассматриваются как символы конца строки и игнорируются).

2

Ответ xenoid, вероятно, быстро найдет для вас уязвимые файлы. Для подтверждения и дальнейшего анализа вы можете запустить:

<"file" tr '\000-\377' 'oL' | fold -w 512 | grep -vn 'L' | cut -f 1 -d ':'

Это работает следующим образом:

  1. "file" открывается и передается первой команде.
  2. tr преобразует каждый нулевой символ в o , каждый ненулевой символ в L
  3. fold вставляет новую строку после каждых 512 символов. На данный момент поток может рассматриваться как чистый текст.
  4. grep берет строки, которые не содержат L и печатает их со своими номерами.
  5. cut изолирует эти числа (удаляет ooo…).

Таким образом, вы получите порядковые номера 512-байтовых кусков, заполненных нулями. Нумерация начинается с 1 . Передайте вывод в wc -l чтобы увидеть, сколько кусков затронуто в данном файле.

1

Я был заинтригован этим, так как это то, чего я иногда хотел, и я немного искал, придумывая эту программу на Python 3.

Я выполнил команду wget внизу страницы, и она отлично работает (хотя вам может потребоваться sudo , в зависимости от ваших прав). Как и grep , он имеет много мощных опций, включая поиск по регулярным выражениям: примеры в заголовке показывают некоторые из них; bgrep --help дает полный список.

Для вашего использования вам понадобится строка запуска с 512 двойными нулями: не вводите их, используйте что-то вроде:

bgrep -l $(for f in {0..511}; do echo -n 00; done) files...

Вы можете использовать опцию -r для обхода полного дерева каталогов.

Я добавил этот ответ не потому, что другие неадекватны (мне особенно понравилась изобретательность последовательности команд Камиля Мачоровского), а потому, что он может быть полезен для других (таких как я), имеющих связанные проблемы, которые сталкиваются с этим вопросом.

1

Другой подход, поэтому другой ответ от меня.

Вы можете использовать ddrescue для поиска нулей. Используйте --generate-mode .

Когда ddrescue вызывается с --generate-mode он работает в "режиме генерации", который отличается от "режима восстановления" по умолчанию. То есть, если вы используете --generate-mode , ddrescue ничего не спасет. Он только пытается сгенерировать mapfile для последующего использования.

[...]

В некоторых случаях ddrescue может сгенерировать приблизительный mapfile из infile и (частичной) копии в outfile , что почти так же хорошо, как точный mapfile . Это можно сделать, просто предполагая, что сектора, содержащие все нули, не были спасены.

[...]

ddrescue --generate-mode infile outfile mapfile

(источник)

Давайте предположим, что ваш файл outfile от предыдущего запуска ddrescue Мы не можем использовать его как infile (поскольку ddrescue отказывается работать, когда infile и outfile - это один и тот же файл), нам нужен фиктивный файл, подойдет /dev/zero . Чтобы найти каждый ноль, вам нужно -b 1 . Это команда (mapfile не должен существовать):

ddrescue -b 1 --generate-mode /dev/zero file mapfile

Каждая запись с ? в списке блоков данных внутри mapfile означает блок нулей (при -b 1 один ноль также является блоком). Смотрите структуру файла карты для ddrescue. Затем вы можете получить информацию из mapfile .

Например, следующая команда даст вам длину (шестнадцатеричное, в байтах из-за -b 1) наибольшего блока нулей (пустой вывод означает, что его не было):

grep '0x.*0x.*[?]' mapfile | awk -F ' ' '{print $2}' | sort -ru | head -n 1

Чтобы ускорить процесс, вы можете использовать больший размер блока (-b), но тогда блоки нулей, начинающиеся в одном блоке и заканчивающиеся в следующем, могут остаться незамеченными, даже если они немного длиннее выбранного размера блока; их смещение становится важным.

Чтобы не пропустить ни одного отрезка нулей длиной N или более, вам необходим размер блока не более M=$(((N+1)/2)) байтов (например, не более 5 для N=10 , 6 для N=11) Команда

ddrescue -b "$M" --generate-mode /dev/zero file mapfile

сгенерирует mapfile где каждая строка с ? в списке блоков данных подразумевается не менее M нулей (с правым смещением), но каждый отрезок из N нулей (независимо от его смещения) будет генерировать такую линию наверняка. Поскольку два блока из M имеют по меньшей мере N , применяются следующие соображения:

Принимая строки с ? из списка блоков данных,

  • если длина (второй столбец в mapfile , помните, что единицей является M) равна 0x2 или больше, тогда у вас есть N или более нулей в этой позиции;
  • если длина равна 0x1 то вам следует продолжить исследование, если вокруг этой позиции есть хотя бы N нулей;
  • если такой строки нет, то в файле наверняка нет натяжения N нулей.

На самом деле они всегда будут кратны 512 байтам и всегда начинаются с адреса 512 байт.

В этом случае

ddrescue -b 512 --generate-mode /dev/zero file mapfile

найдет и сопоставит их всех.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .