LINUX.ORG.RU

Найти случайно затёртый с диска исходник

 , , ,


4

6

В очередной (третий-четвёртый за несколько последних лет) раз затерев по неаккуратности файл с кодом (cp не в ту сторону), на который был потрачен предыдущий час или больше, и который ещё не был закоммичен, решил что искать его с помощью dd и grep - занятие утомительное. Слышал тут про binwalk, но, посмотрев описание, то ли не осилил найти способ её для этой цели использовать, то ли она и правда для другого.

Написал свою прогу в итоге: исходник.

Компилировать: gcc -o rawsearch rawsearch.c

Синтаксис: ./rawsearch if=/dev/sda8 str=some_string_from_file

Прога найдёт на диске все текстовые блоки (внимание: если файл фрагментирован то он будет не одним блоком а несколькими, прога их сцеплять не будет), что содержат эту строку и создаст пачку файлов с названиями found-NNN (NNN - байт где начинается) с этими текстами. Границы текстовых блоков определяются так:

static int is_binchar(char c) { return (c==127 || c>=0 && c<=6 || c>=14 && c!=27 && c<=31); }

(это символы которые по мнению проги в текстовых файлах не встречаются).

Возможно кому-то будет полезно.

Исходник максимально простой (всего 300 строк и 12кб), можно легко патчить под какие-то потребности по месту.

★★★★★

Последнее исправление: firkax (всего исправлений: 2)

Я не понял что именно оно восстанавливает из описания (пришел по тегу recovery). У нас есть 2 варианта - первый файл не удалён, а переименован (технически это значит что он просто перемещён), там нужна программа на поиск файла по содержимому. Второй вариант хуже, файл удалён и его надо восстанавливать с диска поскольку удаляли его rm-ом, а не shred-ом. Ну и 3 самый плохой вариант когда файл удалили таки shred-ом, там уже пиши пропало, если нет бэкапов (в некоторых случаях возможно что-то можно сделать теоретически, при наличии огромных ресурсов - миллионов долларов минимум и если физика не запрещает).

peregrine ★★★★★
()

Шлангом не собирается:

$ cc rawsearch.c -o rawsearch
rawsearch.c:68:5: error: first parameter of 'main' (argument count) must be of type 'int'
   68 | int main(unsigned int argc, char **argv) {
      |     ^
rawsearch.c:141:11: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
  141 |     if(pos=memmem(bb, avl, str, strsize)) return pos;
      |        ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
rawsearch.c:141:11: note: place parentheses around the assignment to silence this warning
  141 |     if(pos=memmem(bb, avl, str, strsize)) return pos;
      |           ^
      |        (                                )
rawsearch.c:141:11: note: use '==' to turn this assignment into an equality comparison
  141 |     if(pos=memmem(bb, avl, str, strsize)) return pos;
      |           ^
      |           ==
rawsearch.c:221:12: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
  221 |   while(csz=n) {
      |         ~~~^~
rawsearch.c:221:12: note: place parentheses around the assignment to silence this warning
  221 |   while(csz=n) {
      |            ^
      |         (    )
rawsearch.c:221:12: note: use '==' to turn this assignment into an equality comparison
  221 |   while(csz=n) {
      |            ^
      |            ==
rawsearch.c:236:12: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
  236 |   while(csz=n) {
      |         ~~~^~
rawsearch.c:236:12: note: place parentheses around the assignment to silence this warning
  236 |   while(csz=n) {
      |            ^
      |         (    )
rawsearch.c:236:12: note: use '==' to turn this assignment into an equality comparison
  236 |   while(csz=n) {
      |            ^
      |            ==
3 warnings and 1 error generated.
iron ★★★★★
()
Ответ на: комментарий от peregrine

Она ищет в произвольном хранилище текстовые блоки, содержащие нужную строку. наверно можно считать что это расширенный вариант strings+grep с поддержкой многострочных блоков и в одной проге.

Речь именно про случайное затирание, когда иноды уже нет, но данные никто с диска не удалил. Впрочем, если файл переименован неизвестно куда, то она тоже его может найти, иногда на это уйдёт даже меньше времени чем на честный поиск по файловой системе. Но есть минус - если файл фрагментированный то фрагменты будут находиться отдельными кусками, т.к. никакие структуры прога не парсит, только ищет текст.

И не знаю как в общем случае, но у меня (редактируя файлы в mcedit на файловой системе ext4) после каждого сохранения текст кладётся на новое место на диске, и таким образом нашлась не только последняя версия но и куча предыдущих.

firkax ★★★★★
() автор топика
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

и это правильно. потому что иначе оба варианта синтаксически корректны, и ошибки не будет, если афтар пришел из паскаля и привычно пишет a = b, для проверки на равевенство

alysnix ★★★
()
Ответ на: комментарий от alysnix

Ладно, в обучающем режиме - возможно и полезны. Дискуссию о том, насколько хорошо дефолтным режимом делать обучающий, давай не будем устраивать.

firkax ★★★★★
() автор топика

Добавь в свой профиль ссылку. Как делал тот кого забанил alex001. Иначе утонет в других темах и не вспомнится больше никогда.

Ура, никаких больше пятнашек и светофоров и гидрантов, теперь коды и еноты на капчах.

anonymous
()

Исходник схоронил :) Но вообще, практика показывает, что обычно если на диске остались какие-то текстовые куски, которые никто не успел перезатереть, они чудовищно перемешаны и что-то полезное оттуда выудить довольно маловероятно.

cp не в ту сторону

Двухпанельный файловый менеджер с хоткеями и подтверждениями обычно резко снижает вероятность cp не в ту сторону, например.

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

Зависит от степени заполнения диска и размера файла. Но да, если файл фрагментирован то собирать куски придётся вручную. Это всё равно скорее всего намного лучше чем писать заново. Если же файл большой а несохранённые правки были в маленькой его части - то можно только её и вытащить.

Двухпанельный файловый менеджер с хоткеями и подтверждениями обычно резко снижает вероятность cp не в ту сторону, например.

Ну я набрал стрелку вверх и энтер, а там не та команда была. «С подтверждениями» конечно такого бы не случилось, но я стрелкой вверх пользовался как раз чтоб без лишних кликов.

firkax ★★★★★
() автор топика

Извини, но я не смог осилить исходник.

Будет ли программа работать, если файлом будет /dev/stdin? Вижу pread(), в котором

The pread() function shall fail if: ESPIPE The file is incapable of seeking.

Если нет, то не проще ли было вместо всех этих «ехал buflen через bufsize» просто mmap’нуть файл? Не знаю, правда, какие есть ограничения на размер файла при mmap. Предполагаю, что это могут быть размер виртуального адресного пространства и ulimit -v.

Ещё такой вопрос: для чего и как работает эта проверка?

  k = strsize*4;
  if(k/4!=strsize) { fprintf(stderr, "string too long!\n"); goto usage; }

Насколько я знаю, длина аргументов ограничена размером стека и обычно составляет 1/4 от него. strsize у тебя имеет тип size_t, для которого SIZE_MAX всегда больше размера стека, для 64-битных систем уж точно, а для 32-битных, чтобы условие сработало, нужно чтобы стек занимал всю память. Мне так кажется.

anonymous
()
Ответ на: комментарий от anonymous

Ещё такой вопрос: для чего и как работает эта проверка?

проверяет на переполнение небось.

если умножение на 4 и деление на 4 не дают исходное число,значит у него потом будет переполнение, которого он боиццо.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от anonymous

Будет ли программа работать, если файлом будет /dev/stdin

Не будет.

Если нет, то не проще ли было вместо всех этих «ехал buflen через bufsize» просто mmap’нуть файл?

Проще, но mmap медленнее при некоторых условиях (прога не может сообщить ядру что его надо read-ahead). Конкретно тут не измерял.

Не знаю, правда, какие есть ограничения на размер файла при mmap

А, ну и да, mmap нельзя больше чем размер юзерспейсного адресного пространства (на 32 битах - около 3гб вроде), так что у меня бы оно тупо не запустилось даже с разделом на 150гб. Хотя я об этом не подумал. Вот был бы сюрприз если б забил на предыдущий аспект.

Ещё такой вопрос: для чего и как работает эта проверка?

Это проверка на переполнение.

Насколько я знаю, длина аргументов ограничена размером стека и обычно составляет 1/4 от него.

Это всё может быть, но любая арифметическая операция должна проверяться на переполнение, если прям строго-строго перед ней нет гарантий что переполнения не случится. Иначе при последующих изменениях обстоятельств или рефакторинге переполнение имеет шанс таки случиться, совершенно молча. Вот тут например строка берётся из аргументов, а вдруг потом она будет читаться из файла? Файлочиталка, очевидно, всё равно ограничит её в size_t, но вот прочитать SIZE_MAX/2 она уже вполне сможет. При этом о том, что при замене способа получения строки надо ещё и аллокацию буфера править, можно и не помнить.

firkax ★★★★★
() автор топика
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Понятно, спасибо за ответы.

Нашёл такие прикольные таблички с картами памяти в линуксе для x86_64: https://www.kernel.org/doc/html/latest/arch/x86/x86_64/mm.html Получается, если не ограничивать адресное пространство пользователя, то на x86_64 с 48 битным размером адреса можно ммапнуть файлик около 128 ТБ)

Ты меня тут вдохновил и я написал вариант с mmap на питоне, с юникодом и регулярками) Работает не быстро, где-то гигабайт в секунду только, на файле из tmpfs. Если ставить -i, то ещё в 10 раз медленнее получается.

$ ./binsearch.py --help           
usage: binsearch.py [-h] [-r] [-i] [-p] [-o OUTPUT] [--license] PATTERN FILE

Binary file search

positional arguments:
  PATTERN               pattern to search for
  FILE                  regular file or block device

options:
  -h, --help            show this help message and exit
  -r, --regexp          do regexp search instead of fixed string
  -i, --ignore_case     do case insensitive search (regexp)
  -p, --print_match     print matched substring (regexp)
  -o OUTPUT, --output OUTPUT
                        output file (default=stdout)
  --license             show license

$ ./binsearch.py -rp 'Мы с милёночком сидели.*?\n\n' /dev/sda3
@ 0x0027f45000 (670322688)
Мы с милёночком сидели,
Обнимались горячо:
Я ему сломала руку,
Он мне вывернул плечо.


$ ./binsearch.py do_all /dev/zram0          
@ 0x000a7215ea (175248874)
@ 0x000a72240a (175252490)
@ 0x000a72257c (175252860)
@ 0x000a7926ff (175711999)
@ 0x000a7928b2 (175712434)
anonymous
()

Клево, конечно, только кажется что быстрее заново написать: лично у меня прагруммирование - это поиск решений, а не написание. Если пропал файл к, но ты уже знаешь как он был сделан - заново набросать плевое дело.

pihter ★★★★★
()

А вообще, если оно у тебя не в первый раз, ну напиши скрипте, чтоб по сохранению бекапил. И пусть хранит, скажем, за последние сутки все изменённые тобой файлы.

Три строчки на скрипте, а вручать будет всюьжись

// хм… А не написать ли себе такой скриптец? Всяко же выручить когда-нибудь…

pihter ★★★★★
()
Ответ на: комментарий от pihter

Куда я его всуну этот скрипт? В mcedit на все компы где я могу его запустить? И не все файлы бекапить надо.

firkax ★★★★★
() автор топика
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от EXL

Да, есть такое, однако из hex-редактора скопировать нужный блок в отдельный файл всё равно пришлось бы возиться. Даже если б там была функция «сохранить участок» - его границы надо вручную было б подгонять. А тут идея в том чтоб просто указать где искать, что искать и сразу получить готовые файлы.

Вообще, я пробовал открывать дампы в mcview/mcedit и там искать строки, но у них выяснилась пачка проблем с этим, делающая затею нецелесообразной.

firkax ★★★★★
() автор топика
Последнее исправление: firkax (всего исправлений: 2)

можно написать прогу, что будет смотреть за файлами по указанным дирам и указанной маске, навроде гита короче.

составляет список файлов за которыми следит. ловит события inotify по изменениям файлов. если отслеживаемые файлы менялись, раз в n секунд, копирует их содержимое в карман. тогда в кармане будут примерно последние версии отслеживаемых файлов. спасать раз в пять минут например - и ненакладно и версии будут достаточно свежими.

хотя у inotify есть событие на удаление, оно, насколько я помню, испускается после удаления, то есть просто тупо спасать отслеживаемый файл при его удалении не получится.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от EXL

Пробовал поискать hexedit’ом - очень медленно шевелится, раз в пять медленнее питона. Но если приспичит, то можно и им воспользоваться. Есть возможно прыгать по адресам, выделять, копировать и сохранять куски в файл. Но хоткеи очень неинтуитивные, каждый раз приходится в справке по F1 смотреть.

anonymous
()

Расскажу как у меня.

Внёс изменения в исходники, поотлаживал и делаю архив в котором указываю дату и время.
Всё!

Если через месяц два всё ok, то если было несколько архивов на какую-то дату оставляю последний, остальные удаляю.

Вот и вся премудрость.
И ни разу не подвела.

Копии архивов сохраняю на нескольких дисках.

Forum0888
()
Ответ на: комментарий от Forum0888

То, что ты описал, обычно делает система контроля версий, и хранит она не архив за последнюю дату, а всю историю с самого начала. А в теме речь про то, когда ещё не успел «поотлаживать» и внести новую версию файла куда-то там, но случайно удалил.

firkax ★★★★★
() автор топика
Ответ на: комментарий от firkax

Не использую система контроля версий.
Она полезна когда несколько человек одновременно работают над проектом.

но случайно удалил.

В течении дня создаю несколько архивов.
За два часа новую ОС не разработаю.

Forum0888
()
Ответ на: комментарий от firkax

Ну поди ж исходники по часу правишь не на всех компах, где можешь запустить мс.

Да, бекапить нужно не все, но логичнее бекапить все, а потом отбрасывать ненужное, чем регулярно восстанавливать случайно удалённые файлы

pihter ★★★★★
()

Шутка

Найти случайно затёртый с диска исходник

Non problem.
В цикле в каждом секторе hdd ищите строку из исходника.
Всё!

Вот поэтому частенько в начале поста и помещаю «Шутка».
Народ на форуме весьма сурьёзный.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 2)
Ответ на: комментарий от firkax

И не знаю как в общем случае, но у меня (редактируя файлы в mcedit на файловой системе ext4) после каждого сохранения текст кладётся на новое место на диске

И это хорошо. Сначала сохранить на диске новое наполнение во временном файле, лишь затем атомарно переместить его под старое имя.

gag ★★★★★
()
Ответ на: комментарий от hobbit

Двухпанельный файловый менеджер с хоткеями и подтверждениями обычно резко снижает вероятность cp не в ту сторону, например.

В графических даже Ctrl+Z работает.

MOPKOBKA ★★★
()