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


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

Как всегда, помог Google. Во-первых, нашлась интересная статья "Extended attributes: the good, the not so good, the bad", в которой предлагается обходной путь решения задачи поиска файлов по содержимому их расширенных атрибутов. То есть, то, что я в предыдущей публикации пытался решить на уровне патча утилиты find, здесь решено штатными средствами ОС. Из этой же статьи следует, что завоевание cp — похоже, действительно, последний рубеж, который необходимо преодолеть для активации полноценной поддержки extattr во фряшечке.

Далее, Google подсовывает патч для NetBSD, заставляющий cp копировать расширенные атрибуты. Его почитать — так там вообще делать нечего. Стоит только в нужном месте исходного кода добавить эту строку:

if (pflag && (fcpxattr(from_fd, to_fd) != 0))
               warn("%s: error copying extended attributes", to.p_path);

И всё. Можно копировать. Хорошо, идём в исходники FreeBSD, открываем файл utils.c, добавляем в него заветные строки и… Приехали. FreeBSD не знает, что такое fcpxattr(). Вообще, за объявление этой функции отвечает заголовочный файл sys/extattr.h, но он о ней тоже не знает. Все эти fcpxattr — это фишка NetBSD. У них sys/extattr.h проапгрейден относительно FreeBSD.

Но моя задача была — обучить cp копировать расширенные атрибуты, а не перелопачивать половину ядра системы. Поэтому, ничтоже сумняшеся, я решил требуемый extattr-функционал включить в исходники cp. Конечно, с точки зрения целостности системы это неправильно, но как патч под конкретную задачу — сойдёт.

Чтобы наделать поменьше ошибок в коде, я поискал NetBSD-шные исходники extattr.c и взял их за образец.

В итоге, у меня получился такой патч (для FreeBSD 11.2.0-RELEASE).

Применить его можно так:

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

Если вы обратили внимание, в моём варианте расширенные атрибуты копируются всегда, а не только с флагом -p, как в варианте для NetBSD. Мне показалось, что так удобнее. В любом случае, как и в предыдущей публикации, я выложил на Github полный код утилиты cp, скопированный из репозитория FreeBSD, с моими изменениями. Чтобы вы тоже могли развлечься.

Комментарии (13)


  1. KYuri
    11.10.2018 16:14
    +3

    Чувствую, так и до KDE дело дойдёт)


    1. scifinder Автор
      11.10.2018 16:15

      А в KDE тоже проблема с extattr?))


    1. SemmZemm
      11.10.2018 18:25

      Вряд ли, Хабр не специализируется на аниме


      1. ivan386
        11.10.2018 20:51

        Хмм.


        1. поиск по слову "аниме"
          Публикации 263
          Хабы и компании 1
          Пользователи 238
          Комментарии 1k


        2. Первая статья в списке "Как создается аниме"



  1. Sabubu
    11.10.2018 17:36

    Мне не нравится ваше решение. Это годится только в одном случае: если нужно срочно сделать приватный патч для себя для одноразовой задачи.

    Нормальное решение — не накапливать различия между ОС, а портировать API из Netbsd (если оно совместимо с FreeBSD). Работа с атрибутами должна вестись через разделяемую библиотеку, как в Windows, а не так, что каждая программа содержит свой вариант реализации.


    1. Karpion
      11.10.2018 22:46

      Вот это правильный совет. Делать «каждая программа содержит свой вариант реализации» допустимо на уровне разработки, как proof of concept. Но потом надо будет нормально портировать.
      И если в NetBSD всё эт уже есть — то надо не патчить программы самостоятельно, а просто портировать. Желательно — с минимальными изменениями.

      И кстати — надо предусмотреть вариант, когда исходная или целевая файловая система не поддерживает эти атрибуты.


      1. scifinder Автор
        12.10.2018 07:04

        Во FreeBSD это всё тоже есть, только в виде отдельных команд. В NetBSD просто добавили удобную оболочку для этой последовательности. В итоге, во FreeBSD нужно выполнить цепочку команд «получить список атрибутов файла А — пройтись по списку и прочитать атрибуты — запомнить в буфер — записать атрибуты в файл Б из буфера», а в NetBSD просто «скопировать атрибуты из файла А в файл Б» (а под капотом у неё та же самая последовательность).


        1. Apx
          13.10.2018 22:57

          Всего один вопрос why not alias/function в своём rc файле любимого терминала? Может быть глобальным, действие/кодинг выполняется всего один раз, сохраняет "атомарность" cp.


          1. Sirikid
            14.10.2018 08:19

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


    1. eirnym
      11.10.2018 23:11

      Это идеальное решение в случае наличия ресурсов у автора и/или поддерживающего окружения. Можно начать с двух feature request, при положительном отклике со стороны FreeBSD — сделать остальное. В случае reject можно сделать порт в виде патча к исходному коду и установке в качестве отдельной программы (в этом случае даже отдельного репозитория не нужно)


    1. scifinder Автор
      12.10.2018 06:57

      Согласен, что в библиотеку extattr во FreeBSD неплохо бы перенести дополнительный функционал из таковой для NetBSD. Сам очень удивился, когда обнаружил, что читать, писать и удалять расширенные атрибуты FreeBSD может, а скопировать из одного файла в другой — нет. Когда стал разбираться внимательнее, понял, что FreeBSD умеет всё это делать, но по частям. Например, чтобы скопировать расширенные атрибуты, нужно последовательно выполнить lsextattr и getextattr на первом файле и setextattr на втором. А в NetBSD для всей этой последовательности просто придумали красивую обёртку и добавили в библиотеку extattr. FreeBSD, как более консервативная система, скорее всего, придерживается взгляда, что раз функционал можно выполнить последовательностью команд, то нет смысла создавать для этой последовательности обёртку в виде одной команды.

      Поэтому я и принял решение обёртку над последовательностью стандартных команд lsextattr, getextattr и setextattr добавить в файл utils.c исходников утилиты cp. В результате, мой код точно также использует разделяемую библиотеку.


  1. eirnym
    11.10.2018 23:19

    Есть одно замечание по существу.


    В среде *BSD принято, что если что-то меняется, это либо должно быть очень хорошо обосновано, либо быть опциональным. Я пока не вижу ни одного "за", почему предложенный функционал (1) должен быть включён по-умолчанию и (2) не может быть выключен.


    1. scifinder Автор
      12.10.2018 06:31

      Конечно, можно добавить проверку на флаг -p и копировать атрибуты только с включённым флагом. А для своей задачи создать alias вида «cp -p» -> «cp». Именно поэтому я ещё в предыдущей публикации утверждал, что оба моих патча — это только proof of concept. С другой стороны, в ОС от Apple копирование расширенных атрибутов вместе с файлом включено по-умолчанию. Чтобы разобраться, как будет лучше и удобнее, я и опубликовал свои наработки.