fstatat(2) считывает состояние файла

Other Alias

stat, fstat, lstat

ОБЗОР

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);

#include <fcntl.h> /* определения констант AT_* */
#include <sys/stat.h>

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

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

lstat():

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

fstatat():

Начиная с glibc 2.10:
_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
До glibc 2.10:
_ATFILE_SOURCE

ОПИСАНИЕ

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

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

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

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

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

struct stat {
    dev_t     st_dev;         /* ID устройства с файлом */
    ino_t     st_ino;         /* номер inode */
    mode_t    st_mode;        /* права доступа */
    nlink_t   st_nlink;       /* кол-во жёстких ссылок */
    uid_t     st_uid;         /* ID пользователя-владельца */
    gid_t     st_gid;         /* ID группы-владельца */
    dev_t     st_rdev;        /* ID устройства (если это спец. файл) */
    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.

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

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

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

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

В поле st_blksize хранится «предпочтительный» размер блока для эффективного ввода/вывода в файловой системе (запись в файл более мелкими порциями может привести к неэффективному чтению/изменению/повторной записи).

Не во всех файловых системах Linux используются все поля меток времени. Некоторые файловые системы можно смонтировать так, что факт доступа к файлу или каталогу не вызовет изменение поля st_atime (смотрите описание noatime, nodiratime и relatime в mount(8) и связанную с ними информацию в mount(2)). Кроме того, поле st_atime не обновляется, если файл открыт с флагом O_NOATIME; см. open(2).

Поле st_atime изменяется при доступе к файлу, например, при выполнении execve(2), mknod(2), pipe(2), utime(2) и read(2) (при чтении ненулевого количества байт). Другие процедуры, например mmap(2), могут изменять st_atime, но могут и не делать этого.

Поле st_mtime изменяется при изменении файла, например, при выполнении mknod(2), truncate(2), utime(2) и write(2) (если записано не менее одного байта). Кроме того, поле st_mtime у каталога изменяется при создании и удалении файлов в этом каталоге. Поле st_mtime не изменяется при изменении владельца, группы, количества жёстких ссылок или режима доступа к нему.

Поле st_ctime изменяется при записи или установке информации об inode (владельце, группе, количестве ссылок, режиме и т.д.).

В POSIX относятся к битам st_mode равным маске S_IFMT (смотрите ниже) как к типу файла (file type), 12 битам, соответствующим маске 07777, как к битам режима файла (file mode bits) и наименее значащим 9 битам (0777) как к битам доступа к файлу (file permission bits).

Следующие значения масок определены для типа файла в поле st_mode:

S_IFMT0170000битовая маска битового поля для типа файла

S_IFSOCK0140000сокет
S_IFLNK0120000символьная ссылка
S_IFREG0100000обычный файл
S_IFBLK0060000блочное устройство
S_IFDIR0040000каталог
S_IFCHR0020000символьное устройство
S_IFIFO0010000FIFO

Таким образом, чтобы проверить обычный файл (например) на возможность записи:

stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {
    /* обработка обычного файла */
}

Так как приведённое выше тестирование имеет общий вид, в POSIX определены дополнительные макросы, которые позволяют тестировать тип файла в st_mode более краткой записью:

S_ISREG(m)
обычный файл?
S_ISDIR(m)
каталог?
S_ISCHR(m)
символьное устройство?
S_ISBLK(m)
блочное устройство?
S_ISFIFO(m)
FIFO (именованный канал)?
S_ISLNK(m)
символьная ссылка? (нет в POSIX.1-1996.)
S_ISSOCK(m)
сокет? (нет в POSIX.1-1996.)

Таким образом, ранее показанный фрагмент кода можно переписать как:

stat(pathname, &sb);
if (S_ISREG(sb.st_mode)) {
    /* обработка обычного файла */
}

Большинство определений показанных ранее макросов тестирования типа файла доступно, если определён любой из следующих макросов тестирования свойств: _BSD_SOURCE (в glibc 2.19 и старее), _SVID_SOURCE (в glibc 2.19 и старее) или _DEFAULT_SOURCE (в glibc 2.20 и новее). Также, определение всех макросов, за исключением S_IFSOCK и S_ISSOCK(), доступны при наличии _XOPEN_SOURCE. Определение S_IFSOCK также можно получить определив _XOPEN_SOURCE со значением 500 или более.

Определение S_ISSOCK() доступно, если определён любой из следующих макросов тестирования свойств: _BSD_SOURCE (в glibc 2.19 и старее), _DEFAULT_SOURCE (в glibc 2.20 и новее), _XOPEN_SOURCE со значением 500 или более или _POSIX_C_SOURCE со значением 200112L или более.

Следующие значения масок определены для компонента режима доступа к файлу в поле st_mode:

S_ISUID04000бит set-user-ID
S_ISGID02000бит set-group-ID (см. далее)
S_ISVTX01000закрепляющий бит (см. далее)

S_IRWXU 00700владелец имеет права на чтение, запись и выполнение файла
S_IRUSR 00400владелец имеет право чтения
S_IWUSR 00200владелец имеет право записи
S_IXUSR 00100владелец имеет право выполнения

S_IRWXG 00070группа имеет права на чтение, запись и выполнение файла
S_IRGRP 00040группа имеет право чтения
S_IWGRP 00020группа имеет право записи
S_IXGRP 00010группа имеет право выполнения

S_IRWXO 00007 все остальные (вне группы) имеют права на чтение, запись и выполнение файла
S_IROTH 00004все прочие имеют право чтения
S_IWOTH 00002все прочие имеют право записи
S_IXOTH 00001все прочие имеют право выполнения

Бит set-group-ID (S_ISGID) имеет несколько специальных применений. Для каталога он указывает, что используется семантика BSD: файлы, создаваемые в каталоге, наследуют ID группы этого каталога, а не фактическую группу создающего процесса, а для подкаталогов данного каталога также будет установлен бит S_ISGID. Если файл не имеет бита выполнения группой (S_IXGRP), то бит set-group-ID означает обязательную (mandatory) блокировку файла/записей.

Закрепляющий (sticky) бит (S_ISVTX) на каталоге означает, что файлы в этом каталоге могут быть удалены или переименованы только владельцем файла, владельцем каталога и привилегированным процессом.

fstatat()

Системный вызов fstatat() работает также как системный вызов stat(), за исключением случаев, описанных здесь.

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

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

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

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

AT_EMPTY_PATH (начиная с Linux 2.6.39)
Если значение pathname равно пустой строке, то выполнять действие над файлом, на который указывает dirfd (который может быть получен с помощью open(2) с флагом O_PATH). Если dirfd равно AT_FDCWD, то вызов выполняет действие над текущим рабочим каталогом. В этом случае, dirfd может указывать на файл любого типа, а не только на каталог. Этот флаг есть только в Linux; для получения его определения определите _GNU_SOURCE.
AT_NO_AUTOMOUNT (начиная с Linux 2.6.38)
Не выполнять автоматическое монтирование конечного компонента («basename») pathname, если это каталог, который является точкой монтирования. Это позволяет вызывающему получить атрибуты точки монтирования (а не расположения, где её предполагалось смонтировать). Этот флаг можно использовать в инструментах, сканирующих каталоги, для предотвращения массового автоматического монтирования каталогов в их точки монтирования. Флаг AT_NO_AUTOMOUNT не учитывается, если к точке уже уже была выполнено монтирование. Этот флаг есть только Linux; для его получения нужно задать _GNU_SOURCE.
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 указана пустая строка.
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). Если вам нужно получить определение типа blkcnt_t или blksize_t из <sys/stat.h>, то определите _XOPEN_SOURCE со значением 500 или больше (до включения каких-либо заголовочных файлов).

В POSIX.1-1990 не описаны константы S_IFMT, S_IFSOCK, S_IFLNK, S_IFREG, S_IFBLK, S_IFDIR, S_IFCHR, S_IFIFO, S_ISVTX, вместо них требуется использовать макросы S_ISDIR() и т.п. Константы S_IF* определены в POSIX.1-2001 и новее.

Макросы S_ISLNK() и S_ISSOCK() не описаны в POSIX.1-1996, но есть в POSIX.1-2001; первый взят из SVID 4, последний из SUSv2.

В UNIX V7 (и более поздних системах) есть S_IREAD, S_IWRITE, S_IEXEC, для которых в POSIX есть синонимы S_IRUSR, S_IWUSR, S_IXUSR.

Другие системы

Значения, которые использовались (или используются) в различных системах:
шест.имяlsвосм.описание
f000S_IFMT170000маска типа файла
0000000000 в SCO — недействующий inode; в BSD — неизвестный тип; в SVID-v2 и XPG2 — 0 и 0100000 означают обычный файл
1000S_IFIFOp|010000FIFO (именованный канал)
2000S_IFCHRc020000символьный специальный (V7)
3000S_IFMPC030000мультиплексированный символьный
специальный (V7)
4000S_IFDIRd/040000каталог (V7)
5000S_IFNAM050000 в XENIX — именованный специальный файл с двумя подтипами, различающимися значениями st_rdev — 1, 2
0001S_INSEMs000001подтип IFNAM семафора XENIX
0002S_INSHDm000002подтип IFNAM общих данных XENIX
6000S_IFBLKb060000блочный специальный (V7)
7000S_IFMPB070000мультиплексированный блочный
специальный (V7)
8000S_IFREG-100000обычный (V7)
9000S_IFCMP110000VxFS: сжатый
9000S_IFNWKn110000сетевой специальный (HP-UX)
a000S_IFLNKl@120000символьная ссылка (BSD)
b000S_IFSHAD130000 в Solaris — теневой inode для ACL (не виден пользовательскими процессами)
c000S_IFSOCKs=140000сокет (BSD; также «S_IFSOC» в VxFS)
d000S_IFDOORD>150000Solaris: дверь
e000S_IFWHTw%160000BSD whiteout (не используется для inode)
0200S_ISVTX001000 закрепляющий бит: сохраняет код программы в файле подкачки даже после использования (V7)
зарезервировано (SVID-v2)
для не каталогов: не кэшировать этот файл (SunOS)
для каталогов: флаг ограниченного удаления (SVID-v4.2)
0400S_ISGID002000 set-group-ID при выполнении (V7)
для каталогов: использовать семантику BSD для распространения GID
0400S_ENFMT002000 жёсткая блокировка файлов в стиле System V (общий c S_ISGID)
0800S_ISUID004000set-user-ID на выполнение (V7)
0800S_CDF004000 каталог является файлом, зависящим от контекста (HP-UX)

Закрепляющий бит появился в Version 32V AT&T UNIX.

ЗАМЕЧАНИЯ

В Linux lstat(), обычно, не вызывает автоматическое монтирование, в отличие от stat() (но смотрите fstatat(2)).

Для большинства файлов в каталоге /proc вызов stat() не возвращает размер файла в поле st_size (значение этого поля равно 0).

Поля с отметками времени

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

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

Наносекундные метки времени поддерживаются в XFS, JFS, Btrfs и ext4 (начиная с Linux 2.6.23). Наносекундные метки времени не поддерживаются в ext2, ext3 и Reiserfs. В файловых системах, не поддерживающих досекундные метки времени, в наносекундных полях возвращается значение 0.

Отличия между библиотекой 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().

ПРИМЕР

Следующая программа вызывает stat() и показывает некоторые поля из полученной структуры stat.
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    struct stat sb;
    if (argc != 2) {
        fprintf(stderr, "Использование: %s <путь>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if (stat(argv[1], &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }
    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);
}