STAT(2) Руководство программиста Linux 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:

Устройство, на котором расположен файл (для разбора идентификатора этого поля могут пригодиться макросы major(3) и minor(3)).
Номер иноды файла.
Тип файла и режим доступа. Дополнительную информацию смотрите в inode(7).
Количество жёстких ссылок на файл.
Пользовательский идентификатор владельца файла.
Групповой идентификатор владельца файла.
Устройство, который этот файл (инода) представляет.
Размер файла (если он обычный или является символьной ссылкой) в байтах. Размер символьной ссылки равен длине пути файла, на который она ссылается, без конечного нулевого байта.
«Предпочтительный» размер блока для эффективного ввода/вывода в файловой системе.
Количество блоков (по 512 байт), выделенных для файла (может быть меньше, чем st_size/512, когда в файле есть пропуски (holes)).
Метка времени последнего доступа к файлу.
Метка времени последнего изменения файла.
Метка времени последнего изменения состояния файла.

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

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

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

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

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

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

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

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

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

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

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

Значение dirfd не является правильным файловым дескриптором.
Указано неверное значение в flags.
Значение 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
Самая первая версия структуры со слегка узкими полями и без заполнителей.
Увеличенное поле st_ino и добавлены заполнители в различные части структуры для расширения в дальнейшем.
Ещё раз увеличенное поле 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), statx(2), utime(2), capabilities(7), inode(7), symlink(7)

2019-03-06 Linux