Pull to refresh

Comments 25

а честно говоря не могу ответить, как и не могу вспомнить о чем думал в момент, когда делал эту картинку.
PDF вполне себе нормально идентифицируется по первым 4 байтам. То, что в libmagic сигнатура записана в 5 байт — это, видимо, для надёжности, вдруг кто-нибудь захочет написать в текстовом файле "%PDF", и тогда этот файл засчитается за pdf файл. Но как в таком случае поможет сигнатура из 5 байт — непонятно, ведь добавляется символ "-", который тоже вполне может встретиться в текстовом файле :)

Однажды помнится задался идеей собрать базу сигнатур файлов, для эксперимента, раздал программу нескольким сотням добровольцев. Программа сканировала все имеющиеся в системе носители и читала по первые 4 байта из каждого файла. В отчёт записывалось 4 байта + расширение, которое было у файла. В результате понял, что 4 байт достаточно в большинстве случаев, но есть исключения, типа контейнеров, например doc и xls, или ещё хуже docx и xlsx.
Спасибо за комментарий, надо будет увеличить диапазон файлов для более точного исследования.

Исходя из полученный в мною данных, audio/mpeg определилось корректно за 2291 байт.

Кстати, если посмотреть таблицы, то можно заметить, что есть интересные исключения, например, iso-файлы, у которых заголовок находится со смещением от начала файла.
mpeg — это вообще такая штука: особого заголовка для него не определено, плеер сканирует поток в поисках знакомых структур (кадров звука или видео) и их воспроизводит

короче, на mpeg-данные вообще не ориентируйтесь, вполне такое возможно (для огромного битрейта и сложного transport stream) что и за двадцать килобайт вы файл не узнаете — а играться он тем не менее будет без проблем
PDF в общем-то текстовый формат, как и PostScript. Просто в них есть поддержка бинарных данных :)
Если правильно помню libmagic хорошо справляется с бинарными файлами — там огромная база магических байт-последовательностей, по ним либа и распознает. А текстовые файлы имеет смысл просто смотреть на расширение, и если надо вывести попросить libmagic определить кодировку — определилась считаем что файл текстовый и используем mime расширения, а если нет то по умолчанию application/octet-stream.
По похожему алгоритму работает гитхаб и его либа libguist она внутри использует libmagic.
Ну вот с a.out, полученным в результате компиляции приведенного выше кода libmagic справился в 18 байт.
И в чем смысл статьи?.. Можно не брутфорсить, оставляя N байт от файла, а заглянуть в /usr/share/misc/magic и увидеть все своими глазами.

А у PDF просто первые 5 байт жестко закреплены спецификацией:
Развернуть
image

Тут ведь трэйдофф между сложностью и надежностью определения типа. То есть можно определять хоть по одному байту, если например стоит задача выбрать тип из PDF, PNG, EXE и WAV, с очень низкой надежностью. При этом в случае PDF можно без увеличения сложности алгоритма расширить этот размер до 5 байт, и выиграть в надежности. Ну а с другой стороны весов (максимальная надежность, максимальная сложность) — просто парсить файл по спецификации. Распарсился как PDF? Это PDF.
Смысл статьи очень прост — поделиться своими наблюдениями. Кому-то они показались интересными, кому-то нет, с этим ничего не поделаешь. Вам как я вижу они показались вообще бесполезными, это ваше мнение.

Лезть в libmagic я не стал потому что были плохие погодные условия, болела голова, было не когда было лень. Да и алгоритм его работы мне примерно понятен.

То, что '-' входит в спецификацию pdf пятым символом я не знал, спасибо.
Просматривать все спецификации всех форматов было бы глупо в плане затрат времени и, на мой взгляд, бессмысленно.
Ну вот с a.out, полученным в результате компиляции приведенного выше кода libmagic справился в 18 байт.
Товарищи минусующие, если вы будете писать, что вам не понравилось пользы будет гораздо больше.
Например, в следующий раз я напишу или не напишу что-то или напишу это по-другому.
Ну, например, далеко не все mime-типы можно определить по начальным байтам файла.
Всякие mpeg-и, например, нельзя, потому что для них вообще не определено понятие «файла». Например, в ip или спутниковом телевидении никаких файлов нет, а транспортный поток mime-типа video/mpeg — есть:) rtfm transport stream (2), etc. То же самое касается радио.
Поэтому, кстати, большинство видеофайлов завернуты в контейнеры типа риффов (ави) и т.п.
На этот вопрос не могу ответить, так как не знаком с этими инструментами.

Спасибо за наводку, примусь изучать.
я конечно дико извиняюсь, но подскажите, чем православный file не устраивает, который конечно же использует libmagic?

Извините, но ответ мне было лень разбираться с ним и я сделал свой велосипед, с косоугольными колёсами ещё не повод делать очередной костыль.
file не устраивает по простой причине, так как для того, чтоб определить с помощью него MIME-тип файл должен находится локально, а мне понадобилось определять MIME-тип файлов, находящихся где-то на smb серверах. Лучшее, что я придумал — копировать часть файла с сервера на локальную машину и потом с помощью libmagic определять его тип. Поэтому я и задался вопросом, а сколько мне надо скопировать с этого сервера, чтоб точно определить тип файла.

А зачем мне лезть в детальное устройство libmagic? Чем мне это поможет, подскажите?
А, так вот оно что, что же вы молчали!

У SMB есть удивительная возможность — протокол умеет произвольный доступ к файлу (чтение из любого места). Получается, чтобы сэкономить время и трафик, и при этом не париться со странными мерками «сколько байт из начала хватит чтоб распознать любой файл», достаточно дёргать из файла те области, которые проверяются сигнатурами libmagic (см всё-таки /usr/share/misc/magic).

Вот это было бы интересно: модификация утилиты file, которая читает из файла только нужные области, ну и кеширует то что уже прочитала, чтоб несколько раз не дёргать один участок.
Судя по strace-у, сейчас file всегда сразу грузит первые 98304 байта файла. Наверно это максимальный оффсет, который встречается в моей базе magic.
мы используем imagemagick identify, exiftool, самописные детекторы + быстрое определение по расширению, правда требования немного другие.
Ещё стандартные методы распознавания типов можно увидеть в проекте Apache Tika, в неплохом и понятном xml.
Хотя Tika легко путает message/rfc822 и text/plain, например. По вполне простым и понятным причинам)
Есть еще один тонкий момент в определении типа файла — гибридные файлы, являющиеся одновременно валидными файлами двух типов. Например, пресловутый RARJPEG или, частый для *nix-софта случай, tar.gz архив с bash-скриптом установщика в начале.

Подозреваю, что для автора поста этот случай не очень актуален, но если есть задача найти все файлы определенного типа для последующего анализа, такие гибриды могут сбить поисковый алгоритм с толку.
Если на скрине Ваш код, то там опечатка:
#define PDF «applicatiion/pdf» :)
Это «код» был написан, специально для этой картинке) Спасибо за обнаруженную опечатку, исправил.
Sign up to leave a comment.

Articles