Как пропатчить find под FreeBSD?

    Учим FreeBSD искать файлы по расширенным атрибутам


    Аннотация: в ОС FreeBSD на уровне файловой системы реализован механизм управления расширенными атрибутами файла (extattr). При помощи стандартных команд setextattr, getextattr и rmextattr можно создавать, читать и удалять комментарии, ключевые слова и другие метаданные файлов. А вот искать файлы по расширенным атрибутам пока нельзя. К тому же, расширенные атрибуты теряются при копировании файла. В двух статьях я предложу свои патчи для команд find и cp, устраняющие эти недостатки. Однако, я не профессиональный программист и делал патчи под свои задачи, поэтому предложенное решение стоит рассматривать исключительно как proof of concept и дорабатывать напильником.

    В наследство от древних времён нам достались монструозные и неповоротливые иерархические файловые системы. Но вместе со стремительным увеличением объёма информации всё ярче проявляется их главный недостаток — ограниченные возможности классификации. Таких возможностей, собственно, две: задавать осмысленные имена файлов и рассортировывать эти файлы по каталогам с осмысленными названиями. Это хорошо работало, когда самая распространённая фотоплёнка содержала всего 36 кадров. Их расходовали неторопливо, подчас в течение нескольких месяцев, тщательно выбирая объекты съёмки. Потом 36 фотографий можно было отсканировать и разместить по папкам «Дача», «Отпуск» и «Кошки». Но сейчас, когда на камеру смартфона можно сделать сотни снимков за день, а из Интернета скачать пару сотен PDF-инструкций за час, такой подход становится чрезмерно трудоёмким. Возросший объём информации уже не получается классифицировать иерархически — человеческий мозг просто запутается в такой иерархии. Поэтому на компьютере со временем появляются каталоги «Новая папка (2)», «Все фотки» и «Разобрать».

    В ответ на возникшие ограничения появилась концепция семантической файловой системы. В такой ФС файлам присваиваются некоторые метаданные, по которым затем и осуществляются классификация и поиск. Иерархия каталогов здесь уже не имеет значения, как и имя файла. Яркий пример — облачные объектные хранилища, в которых все объекты располагаются в плоском адресном пространстве и снабжены описывающими их метаданными. Вот только предназначены они для работы на уровне API, а не на уровне пользователя. До настольных систем объектные хранилища пока не добрались.

    А мне захотелось присваивать всем своим файлам ключевые слова и хранить их на одном уровне на своей локальной машине прямо сейчас. У меня много интересов, а, поскольку всего не упомнишь, постоянно приходится записывать заметки, рецепты, методики, инструкции и фотографии. Распихивать всё это по папкам — уже нет ни сил, ни времени.

    К счастью, настольные ФС подтягиваются к тренду. Во многих из них уже давно можно задавать ключевые слова некоторым типам файлов (в Windows, насколько мне известно, — для вордовских документов и изображений). Правда, в большинстве случаев эти метаданные сохраняются в самом файле, а не на уровне файловой системы (отсюда и ограничение по типу файлов — не все поддерживают EXIF и IPTC). Но моя любимая FreeBSD предоставляет механизм управления расширенными атрибутами файла любого типа именно на уровне файловой системы. Я так понимаю, где-то в недрах ФС создаётся мета-файл, намертво связанный с основным файлом, и все метаданные записываются в него. Для работы с расширенными атрибутами во FreeBSD существует семейство команд setextattr, getextattr и rmextattr.

    Простой пример:

    $ setextattr user comment cats cat.jpg
    $ getextattr user comment cat.jpg
    cat.jpg cats

    В принципе, с этим уже что-то можно сделать. Если бы не одно «но»: во фряшечке нет механизма поиска файлов по расширенным атрибутам. Что толку от тегирования файлов, если я всё равно не смогу найти их по тегам?

    Но если гора не идёт к Магомету… В общем, я решил сам научить фряшечку искать мои документы по ключевым словам. Но я ведь химик-аналитик, а не программист, и кодинг изучал самостоятельно по гуглу. Поэтому, прежде всего я к гуглу и обратился. Вдруг всё давно придумано до меня, и мне не придётся мучительно вспоминать особенности работы с указателями в Си? Оказалось — да, придумано. Я нашёл один патч для команды find. Вот только незадача — патч обучал команду find проверять, установлен ли конкретный атрибут у файла. И всё. А искать по содержимому этого атрибута — увольте.

    Пришлось, всё-таки, мучиться с указателями и памятью на Си. Пара бессонных ночей, три литра зелёного чаю и чёрный пояс по гуглению — и у меня получился такой патч (для FreeBSD 11.2.0-RELEASE).

    Применить его можно так (во FreeBSD должны быть установлены исходники):

    cd /usr/src/usr.bin/find
    patch < /patch-find.diff
    make
    make install clean

    А использовать так:

    find . -userattr comment=cats
    ./cat.jpg

    Эта команда найдёт все файлы, у которых атрибут comment содержит подстроку cats.

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

    … Итак, теперь я мог худо-бедно искать файлы по ключевым словам. Но возникла новая напасть: при копировании файла все связанные с ним расширенные атрибуты терялись… Проблема была в команде cp, но об этом в следующий раз.
    Поделиться публикацией

    Комментарии 18

      +4
      Я конечно все понимаю, но хабр это вам не форум анимэшников!
        +1
        Ня
        • НЛО прилетело и опубликовало эту надпись здесь
          +1

          А FreeBSD по своему желанию используете или по служебной необходимости? Интересно, почему не Linux?

            +2
            Да, по собственному желанию, дома. В 2010, когда захотел создать собственный домашний мини-сервер, попробовал FreeBSD — и влюбился.
              +2
              Пришёл к FreeBSD аналогичным способом, пользуюсь уже много лет. Не так давно пробовал TrueOS (бывшая PC-BSD): есть интересные решения, но в целом пока не то.
                +2
                Её огромный плюс (FreeBSD) — это то, что она одна и handbook тоже один.
                Поэтому нет такого разброда и шатания, как в линуксе, когда есть различия даже в настройке сети в debian, rhel, а теперь и ubuntu (netplan).
                  +1
                  Ну, в этом нет ничего удивительного: FreeBSD — система, а Linux — ядро. Даже между DragonflyBSD, NetBSD и OpenBSD есть некоторые различия. Не знаю, как там в Debian и kFreeBSD, но подозреваю, что даже там натягивание совы на глобус не прошло бесследно. А вот что действительно радует, так это более предсказуемые последствия обновлений, в том числе смены версий.
                  0
                  Мне она нравится за стабильность и однозначность. Самая, на мой взгляд, «железная» система. И простая.
              0

              Планируете ли Вы выложить программу в FreeBSD base или хотя бы в качестве порта?

                0
                Я пока предпочитаю опубликовать эти два патча (второй скоро будет) на GitHub Gist и предоставить пользователям самим решать, нужно ли оно им. Я не уверен в качестве своего кода, чтобы предлагать его в ядро FreeBSD. Нужно, чтобы профессиональные программисты это поправили.
                  0

                  Ваш код выглядит достаточно хорошо, чтобы попробовать отправить его на review, подробно изложив мотивацию и имплементацию, ответив, например, на вопросы, почему менее выгодно воспользоваться find . -exec для достижения того же самого результата в базовой системе.


                  Так же Вы упомянули патч по наличию расширенного аттрибута у файла. Имеет смысл поискать его историю тоже: был ли отправлен запрос, какой был результат принятия и почему.


                  Мне очень интересен процесс и результат, буду благодарен, если будете его освещать.

                    +1
                    Ваш код не затрагивает ядро FreeBSD. Чтобы компетентные люди могли посмотреть и поправить ваш код, нужно оформить его в виде патча и создать баг репорт:
                    bugs.freebsd.org/bugzilla/enter_bug.cgi

                    Можно так же написать о вашей идее в список рассылки, например freebsd-hackers: lists.freebsd.org/mailman/listinfo/freebsd-hackers

                    Чуть более развёрнуто: www.freebsd.org/doc/en/articles/contributing/article.html

                    Так же для рассмотрения патчей существует phabricator: wiki.freebsd.org/Phabricator
                      0
                      За ссылки спасибо. Может быть, когда доведу патч до ума, всё-таки отправлю им. Видите, если отправлять патч команде FreeBSD, нужно его тогда делать универсальным. А значит, как минимум, добавить возможность поиска по атрибутам в system namespace.
                  +1
                  Удивительно, что FreeBSD не копирует EA. Даже Windows, где эти EA, вроде бы, никак не используются, командой copy их копирует. (Кстати, если патч для cp ещё не написали, погуглите, уже есть такой для NetBSD.)

                  И то, что не копирует, портит всю затею, к сожалению. Есть шанс разом потерять все нажитые непосильным трудом теги.
                    0
                    Да, я видел патч для NetBSD, и на его основе написал для фряшечки. У NetBSD некоторые нужные функции добавлены в extattr.h напрямую, а я дальше кода cp лезть не хотел.
                    +2
                    У меня много интересов, а, поскольку всего не упомнишь, постоянно приходится записывать заметки, рецепты, методики, инструкции и фотографии. Распихивать всё это по папкам — уже нет ни сил, ни времени.

                    На самом деле, то, что Вам нужно, называется PIM — Personal Information Manager. Поищите на Хабре статью про MyTetra или другие аналоги, например, ZIM, CherryTree...


                    Я так понимаю, где-то в недрах ФС создаётся мета-файл, намертво связанный с основным файлом, и все метаданные записываются в него

                    Нет, так делала OS/2 на FAT, и, вроде, делает в каких-то случаях Samba. На современных FS же под это выделены прям вот отдельные блоки данных.


                    где-то читал, что ограничение на размер расширенного атрибута — 1024 байта, но потом не смог найти эту информацию

                    Может быть, это на размер одного атрибута, или у самбы… на все атрибуты целиком в случае фревой UFS2 в inode выделено два указателя на блоки, т.е. например при типичном сейчас размере блока fs в 32 Кб это будет 64 Кб.


                    P.S. Присоединяюсь к предыдущему оратору насчет отправить патч в аптсрим. К сожалению, реальность опенсорс-проектов (кроме самых больших, типа Линукса), что надо самостоятельно пробивать дорогу своим патчам, иначе оно так и останется болтаться на гитхабе, а пользователи о нём даже не узнают. А те, кто узнают, забудут — стоимость поддержки накладывания локальных патчей при апгрейдах такая, что это редко делают...

                      0
                      За PIM спасибо, не знал, хотя сам для себя написал что-то подобное на Qt. MyTetra выглядит очень достойно.

                      Про 64 Кб — важное уточнение. Значит, размер буфера можно смело выставлять в 65536 байт. Дойдут руки до гитхаба — поправлю.

                      А что касается отправки патча в апстрим — я подумаю. Для начала, тогда нужно будет добавить возможность поиска атрибутов не только в user namespase, но и в system namespace.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое