STAT(2)

ИМЯ
stat, fstat, lstat, fstatat - считывает состояние файла

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

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
#include <fcntl.h>           /* определения констант AT_* */
#include <sys/stat.h>

int fstatat(int dirfd, const char *pathname, struct stat *statbuf,
            int flags);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

lstat():
    /* glibc 2.19 и старее */ _BSD_SOURCE
        || /* начиная с glibc 2.20 */ _DEFAULT_SOURCE
        || _XOPEN_SOURCE >= 500
        || /* начиная с glibc 2.10: */ _POSIX_C_SOURCE >= 200112L

fstatat():
    Начиная с glibc 2.10:
        _POSIX_C_SOURCE >= 200809L
    До glibc 2.10:
        _ATFILE_SOURCE

ОПИСАНИЕ

Данные системные вызовы возвращают информацию о файле в буфер, на который указывает statbuf. Для этого не требуется иметь права доступа к самому файлу, но — в случае stat(), fstatat() и lstat() — потребуются права выполнения (поиска) на все каталоги, указанные в полном имени файла pathname.

Вызовы stat() и fstatat() возвращают информацию о файле, указанном в pathname; различия с fstatat() описаны далее.

Вызов lstat() идентичен stat(), но в случае, если pathname является символьной ссылкой, то возвращается информация о самой ссылке, а не о файле, на который она указывает.

Вызов fstat() идентичен stat(), но опрашиваемый файл задаётся в виде файлового дескриптора fd.

  Структура stat
Все эти системные вызовы возвращают структуру stat, которая содержит следующие поля:

    struct stat {
        dev_t     st_dev;         /* ID устройства с файлом */
        ino_t     st_ino;         /* номер иноды */
        mode_t    st_mode;        /* тип файла и режим доступа */
        nlink_t   st_nlink;       /* количество жёстких ссылок */
        uid_t     st_uid;         /* идентификатор пользователя-владельца */
        gid_t     st_gid;         /* идентификатор группы-владельца */
        dev_t     st_rdev;        /* идентификатор устройства
                                     (для специального файла) */
        off_t     st_size;        /* общий размер в байтах */
        blksize_t st_blksize;     /* размер блока ввода-вывода файловой системы */
        blkcnt_t  st_blocks;      /* количество выделенных 512Б блоков */
        /* Начиная с Linux 2.6, ядро поддерживает точность до
           наносекунд в следующих полям меток времени.
           Подробней о версиях до Linux 2.6, смотрите ЗАМЕЧАНИЯ. */
        struct timespec st_atim;  /* время последнего доступа */
        struct timespec st_mtim;  /* время последнего изменения */
        struct timespec st_ctim;  /* время последней смены состояния */
    #define st_atime st_atim.tv_sec      /* для обратной совместимости */
    #define st_mtime st_mtim.tv_sec
    #define st_ctime st_ctim.tv_sec
    };

Замечание: порядок полей структуры stat для разных архитектур отличается. Также, в определении выше не показаны дополняющие байты, которые для различных архитектур могут присутствовать между некоторыми полями Если необходимы подробности, то посмотрите исходный код glibc и ядра.

Замечание: Для простоты и производительности различные поля структуры stat могут содержать информацию о состоянии из разных моментов работы системного вызова. Например, если st_mode или st_uid изменились другим процессом с помощью вызова chmod(2) или chown(2), то stat() может вернуть старое значение st_mode вместе с новым st_uid, или старое значение st_uid вместе с новым st_mode.

Поля структуры stat:

st_dev
    Устройство, на котором расположен файл (для разбора идентификатора этого поля могут пригодиться макросы major(3) и minor(3)).

st_ino
    Номер иноды файла.

st_mode
    Тип файла и режим доступа. Дополнительную информацию смотрите в inode(7).

st_nlink
    Количество жёстких ссылок на файл.

st_uid
    Пользовательский идентификатор владельца файла.

st_gid
    Групповой идентификатор владельца файла.

st_rdev
    Устройство, который этот файл (инода) представляет.

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

st_blksize
    «Предпочтительный» размер блока для эффективного ввода/вывода в файловой системе.

st_blocks
    Количество блоков (по 512 байт), выделенных для файла (может быть меньше, чем st_size/512, когда в файле есть пропуски (holes)).

st_atime
    Метка времени последнего доступа к файлу.

st_mtime
    Метка времени последнего изменения файла.

st_ctime
    Метка времени последнего изменения состояния файла.

Дополнительную информацию об этих полях смотрите в inode(7).

  fstatat()
Системный вызов fstatat() представляет собой обобщённый интерфейс доступа к файловой информации, и может выполнить работу за stat(), lstat() и fstat().

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в stat() и lstat()).

Если в pathname задан относительный путь и значение dirfd равно AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как stat() и lstat()).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Значение flags может быть 0, или включать один или более следующих флагов:

AT_EMPTY_PATH (начиная с Linux 2.6.39)
    Если значение pathname равно пустой строке, то выполнять действие над файлом, на который указывает dirfd (который может быть получен с помощью open(2) с флагом O_PATH). В этом случае dirfd может указывать на файл любого типа, а не только на каталог и поведение fstatat() подобно fstat(). Если dirfd равно AT_FDCWD, то вызов выполняет действие над текущим рабочим каталогом. Этот флаг есть только в Linux; для получения его определения определите _GNU_SOURCE.

AT_NO_AUTOMOUNT (начиная с Linux 2.6.38)
    Не выполнять автоматическое монтирование конечного компонента («basename») pathname, если этот каталог является точкой автоматического монтирования. Это позволяет вызывающему получить атрибуты точки автоматического монтирования (а не расположения, где её предполагалось смонтировать). Начиная с Linux 4.14, также не создаётся несуществующее имя в каталоге по требованию, например в неявных картах автоматического монтировщика. Этот флаг можно использовать в инструментах, сканирующих каталоги, для предотвращения массового автоматического монтирования каталогов в их точки автоматического монтирования. Флаг AT_NO_AUTOMOUNT не учитывается, если к точке уже была выполнено монтирование. Этот флаг есть только Linux; для его получения нужно задать _GNU_SOURCE. Вызовы stat() и lstat() работают, как если бы был установлен флаг AT_NO_AUTOMOUNT.

AT_SYMLINK_NOFOLLOW
    Если значение pathname является символьной ссылкой, не разыменовывать её, а вернуть информацию о самой ссылке, как это делается в lstat(). (По умолчанию, fstatat() разыменовывает символьные ссылки как и stat().)

Смотрите в openat(2) объяснение необходимости fstatat().

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

ОШИБКИ

EACCES
    Запрещён поиск в одном из каталогов пути pathname (смотрите также path_resolution(7)).

EBADF
    Значение fd не является правильным открытым файловым дескриптором.

EFAULT
    Неправильный адрес.

ELOOP
    Во время определения пути встретилось слишком много символьных ссылок.

ENAMETOOLONG
    Слишком длинное значение аргумента pathname.

ENOENT
    Компонент пути pathname не существует или в pathname указана пустая строка и в flags не указан AT_EMPTY_PATH.

ENOMEM
    Не хватает памяти (например, памяти ядра).

ENOTDIR
    Компонент в префиксе пути pathname не является каталогом.

EOVERFLOW
    Значение pathname или fd ссылаются на файл, чей размер, номер inode или количество блоков не может быть представлено с помощью типов off_t, ino_t или blkcnt_t, соответственно. Эта ошибка может возникнуть, если, например, приложение собрано на 32-битной платформе без флага -D_FILE_OFFSET_BITS=64 при вызове stat() для файла, чей размер превышает (1<<31)-1 байт.

В fstatat() дополнительно могут возникнуть следующие ошибки:

EBADF
    Значение dirfd не является правильным файловым дескриптором.

EINVAL
    Указано неверное значение в flags.

ENOTDIR
    Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

ВЕРСИИ
Вызов fstatat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

СООТВЕТСТВИЕ СТАНДАРТАМ
stat(), fstat(), lstat(): SVr4, 4.3BSD, POSIX.1-2001, POSIX.1.2008.

fstatat(): POSIX.1-2008.

Согласно POSIX.1-2001, lstat() для символьной ссылки требует вернуть корректную информацию только в поле st_size и в типе файла в поле st_mode структуры stat. В POSIX.1-2008 более жёсткая спецификация, требующая, чтобы lstat() возвращал корректную информацию во всех полях кроме битов режима в st_mode.

Использование полей st_blocks и st_blksize может усложнить перенос на другие платформы. (Эти поля появились из BSD. Их смысл различается в разных системах и, вероятно, даже в одной системе при использовании NFS).

ЗАМЕЧАНИЯ

  Поля с отметками времени
В старых ядрах и стандартах нет поддержки полей времени в наносекундах. Вместо них есть три поря времени — st_atime, st_mtime и st_ctime — с типом time_t, который имеет секундную точность.

Начиная с ядра 2.5.48, в структуре stat поддерживается наносекундная точность для всех трёх полей времени. Наносекундные компоненты каждой метки времени доступны под именами вида st_atim.tv_nsec, если определён подходящий макрос тестирования свойств. Наносекундные метки времени стандартизованы в POSIX.1-2008, и, начиная с версии 2.12, в glibc также есть поддержка имён наносекундных компонент, если определён _POSIX_C_SOURCE со значением 200809L или более, или _XOPEN_SOURCE со значением 700 или более. До glibc 2.19 включительно определения наносекундных компонент также доступны, если определён _BSD_SOURCE или _SVID_SOURCE. Если ни один из вышеупомянутых макросов не определён, то наносекундные значения доступны под именами вида st_atimensec.

  Отличия между библиотекой C и ядром
В течении долгого времени увеличение размера структуры stat привело к появлению трёх новых версий stat(): sys_stat() (слот __NR_oldstat), sys_newstat() (слот __NR_stat) и sys_stat64() (слот __NR_stat64) на 32-битных платформах, например, i386. Первые две версии уже существовали в Linux 1.0 (но под другими именами); последняя была добавлена в Linux 2.4. Подобное замечание применимо к fstat() и lstat().

Внутренние ядерные структуры stat в разных версиях:

__old_kernel_stat
    Самая первая версия структуры со слегка узкими полями и без заполнителей.

stat
    Увеличенное поле st_ino и добавлены заполнители в различные части структуры для расширения в дальнейшем.

stat64
    Ещё раз увеличенное поле st_ino, увеличены поля st_uid и st_gid для работы с увеличенными в Linux-2.4 UID и GID до 32 бит, увеличены другие поля, дальнейшее добавление заполнителей в структуру (различные байты заполнения в дальнейшем были задействованы в Linux 2.6 с появлением 32-битных ID устройств и наносекундной части в полях временных отметок).

Обёрточная функция glibc stat() прячет эти подробности от приложений, вызывая самую новую версию системного вызова, предоставляемого ядром, и перепаковывая возвращаемую информацию, если это нужно для старых программ.

В современных 64-битных системах жизнь упростилась: единственный системный вызов stat() и ядро работает со структурой stat, в которой поля достаточного размера.

Нижележащий системный вызов, используемый обёрточной функцией fstatat() в glibc, на самом деле называется fstatat64() или, на некоторых архитектурах, newfstatat().

ПРИМЕР
Следующая программа вызывает lstat() и показывает некоторые поля из полученной структуры stat.

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/sysmacros.h>
    int
    main(int argc, char *argv[])
    {
        struct stat sb;
        if (argc != 2) {
            fprintf(stderr, "Использование: %s <путь>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        if (lstat(argv[1], &sb) == -1) {
            perror("lstat");
            exit(EXIT_FAILURE);
        }
        printf("ID содержащего устройства:  [%lx,%lx]\n",
    	    (long) major(sb.st_dev), (long) minor(sb.st_dev));
        printf("Тип файла:                ");
        switch (sb.st_mode & S_IFMT) {
        case S_IFBLK:  printf("блочное устройство\n");     break;
        case S_IFCHR:  printf("символьное устройство\n");  break;
        case S_IFDIR:  printf("каталог\n");                break;
        case S_IFIFO:  printf("FIFO/канал\n");             break;
        case S_IFLNK:  printf("символьная ссылка\n");      break;
        case S_IFREG:  printf("обычный файл\n");           break;
        case S_IFSOCK: printf("сокет\n");                  break;
        default:       printf("неизвестно?\n");            break;
        }
        printf("номер inode:              %ld\n", (long) sb.st_ino);
        printf("Режим доступа:            %lo (octal)\n",
                (unsigned long) sb.st_mode);
        printf("Кол-во ссылок:            %ld\n", (long) sb.st_nlink);
        printf("Владелец:                 UID=%ld   GID=%ld\n",
                (long) sb.st_uid, (long) sb.st_gid);
        printf("Предпоч. размер бл. в/в:  %ld байт\n",
                (long) sb.st_blksize);
        printf("Размер файла:             %lld байт\n",
                (long long) sb.st_size);
        printf("Выделено блоков:          %lld\n",
                (long long) sb.st_blocks);
        printf("Посл. изм. состояния:     %s", ctime(&sb.st_ctime));
        printf("Посл. доступ к файлу:     %s", ctime(&sb.st_atime));
        printf("Посл. изм. файла:         %s", ctime(&sb.st_mtime));
        exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
ls(1), stat(1), access(2), chmod(2), chown(2), readlink(2), utime(2), capabilities(7), inode(7), symlink(7)