LISTXATTR(2)

ИМЯ
listxattr, llistxattr, flistxattr - выводит список названий расширенных атрибутов

ОБЗОР
#include <sys/types.h>
#include <sys/xattr.h>

ssize_t listxattr(const char *path, char *list, size_t size);
ssize_t llistxattr(const char *path, char *list, size_t size);
ssize_t flistxattr(int fd, char *list, size_t size);

ОПИСАНИЕ
Расширенные атрибуты представляют собой пару имя:значение и связываются с записями inode (файлы, каталоги, символьные ссылки и т.п.). Они являются расширениями к обычным атрибутам, связанным со всеми записями inode в системе (например, данные stat(2)). Полное описание модели расширенных атрибутов можно найти в xattr(7).

listxattr() получает список названий расширенных атрибутов, связанных с заданным путем path в файловой системе. Список помещается в list вызывающего, который выделил для этого буфер размером size (задаётся в байтах). Список представляет собой набор названий (заканчивающихся null) один за одним. Названия расширенных атрибутов, к которым вызывающий процесс не может иметь доступ, могут отсутствовать в списке. Возвращается длина списка list.

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

flistxattr() идентичен listxattr(), отличием является то, что используется открытый файл, на который указывает fd (возвращаемом open(2)), а не указанный в path.

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

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

  Пример
Список названий возвращается в виде неупорядоченного массива символьных строк, заканчивающихся null (названия атрибутов разделяются байтами null ('\0')), например:

    user.name1\0system.name1\0user.name2\0

Файловые системы, реализующие ACL стандарта POSIX с помощью расширенных атрибутов, могут возвращать такой список:

    system.posix_acl_access\0system.posix_acl_default\0

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном завершении работы возвращается неотрицательное число, обозначающее размер списка названий расширенных атрибутов. При ошибках возвращается -1 и errno устанавливается в соответствующее значение.

ОШИБКИ

E2BIG
    Размер списка имён расширенных атрибутов превышает максимально допустимый; список невозможно получить. Это может случиться в файловых системах, которые поддерживают бесконечное количество расширенных атрибутов на файл, например XFS. Смотрите ДЕФЕКТЫ.

ENOTSUP
    Расширенные атрибуты не поддерживаются файловой системой или отключены.

ERANGE
    Размер size буфера list слишком мал для хранения результата.

Также могут возникать ошибки, описанные в stat(2).

ВЕРСИИ
Данные системные вызовы доступны в Linux начиная с ядра версии 2.4; поддержка в glibc появилась в версии 2.3.

СООТВЕТСТВИЕ СТАНДАРТАМ
Данные системные вызовы есть только в Linux.

ДЕФЕКТЫ
Как упоминалось в xattr(7), в VFS есть ограничение в 64 КБ на размер списка имён расширенных атрибутов, возвращаемый listxattr(7). Если полный размер имён атрибутов, прикреплённых к файлу, превышает это ограничение, то становится невозможно получить список имён атрибутов.

ПРИМЕР
В следующей программе показано использование listxattr() и getxattr(2). Для файла, чьё имя указывается параметром в командной строке, выводится список файловых атрибутов и их значения.

Для упрощения кода при выполнении программы ключи атрибутов и значения считаются константами. В реальной программе нужно учитывать и обрабатывать изменения при выполнении программы. Например, количество байт, необходимое для ключей атрибутов, может увеличиваться между двумя вызовами listxattr(). В приложении нужно предусмотреть эту возможность с помощью цикла, который повторяет вызов (возможно, ввести задаваемое максимальное количество попыток) с большим буфером каждый раз при ошибке ERANGE. Вызовы getxattr(2) могут обрабатываться схожим образом.

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

  Пример вывода
    $ touch /tmp/foo
    $ setfattr -n user.fred -v chocolate /tmp/foo
    $ setfattr -n user.frieda -v bar /tmp/foo
    $ setfattr -n user.empty /tmp/foo
    $ ./listxattr /tmp/foo
    user.fred: chocolate
    user.frieda: bar
    user.empty: <нет значения>

  Исходный код программы (listxattr.c)
    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/xattr.h>
    int
    main(int argc, char *argv[])
    {
        ssize_t buflen, keylen, vallen;
        char *buf, *key, *val;
        if (argc != 2) {
            fprintf(stderr, "Использование: %s путь\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        /*
         * Определение длины буфера.
         */
        buflen = listxattr(argv[1], NULL, 0);
        if (buflen == -1) {
            perror("listxattr");
            exit(EXIT_FAILURE);
        }
        if (buflen == 0) {
            printf("%s не имеет атрибутов.\n", argv[1]);
            exit(EXIT_SUCCESS);
        }
        /*
         * Выделение буфера.
         */
        buf = malloc(buflen);
        if (buf == NULL) {
            perror("malloc");
            exit(EXIT_FAILURE);
        }
        /*
         * Копирование списка ключей атрибутов в буфер.
         */
        buflen = listxattr(argv[1], buf, buflen);
        if (buflen == -1) {
            perror("listxattr");
            exit(EXIT_FAILURE);
        }
        /*
         * Циклический проход по списку строк (завершающихся 0) с
         * ключей атрибутов. Используется оставшаяся длина буфера для
         * определения конца списка.
         */
        key = buf;
        while (buflen > 0) {
            /*
             * Вывод ключа атрибута.
             */
            printf("%s: ", key);
            /*
             * Определение длины значения.
             */
            vallen = getxattr(argv[1], key, NULL, 0);
            if (vallen == -1)
                perror("getxattr");
            if (vallen > 0) {
                /*
                 * Выделение буфера под значения.
                 * Один доп. байт нужен для добавляемого 0x00.
                 */
                val = malloc(vallen + 1);
                if (val == NULL) {
                    perror("malloc");
                    exit(EXIT_FAILURE);
                }
                /*
                 * Копирование значения в буфер.
                 */
                vallen = getxattr(argv[1], key, val, vallen);
                if (vallen == -1)
                    perror("getxattr");
                else {
                    /*
                     * Вывод значения атрибута.
                     */
                    val[vallen] = 0;
                    printf("%s", val);
                }
                free(val);
            } else if (vallen == 0)
                printf("<нет значения>");
            printf("\n");
            /*
             * Переход к следующему ключу атрибута.
             */
            keylen = strlen(key) + 1;
            buflen -= keylen;
            key += keylen;
        }
        free(buf);
        exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
getfattr(1), setfattr(1), getxattr(2), open(2), removexattr(2), setxattr(2), stat(2), symlink(7), xattr(7)