Linux Man на русском

  User    Syst    Libr    Device    Files    Other    Admin  



   fstat - считывает состояние файла

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

Other Alias

stat, lstat, fstatat


ОБЗОР

#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_IFMT 0170000 битовая маска битового поля для типа файла

S_IFSOCK 0140000 сокет
S_IFLNK 0120000 символьная ссылка
S_IFREG 0100000 обычный файл
S_IFBLK 0060000 блочное устройство
S_IFDIR 0040000 каталог
S_IFCHR 0020000 символьное устройство
S_IFIFO 0010000 FIFO

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

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_ISUID 04000 бит set-user-ID
S_ISGID 02000 бит set-group-ID (см. далее)
S_ISVTX 01000 закрепляющий бит (см. далее)

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 восм. описание
f000 S_IFMT 170000 маска типа файла
0000 000000 в SCO — недействующий inode; в BSD — неизвестный тип; в SVID-v2 и XPG2 — 0 и 0100000 означают обычный файл
1000 S_IFIFO p| 010000 FIFO (именованный канал)
2000 S_IFCHR c 020000 символьный специальный (V7)
3000 S_IFMPC 030000 мультиплексированный символьный
специальный (V7)
4000 S_IFDIR d/ 040000 каталог (V7)
5000 S_IFNAM 050000 в XENIX — именованный специальный файл с двумя подтипами, различающимися значениями st_rdev — 1, 2
0001 S_INSEM s 000001 подтип IFNAM семафора XENIX
0002 S_INSHD m 000002 подтип IFNAM общих данных XENIX
6000 S_IFBLK b 060000 блочный специальный (V7)
7000 S_IFMPB 070000 мультиплексированный блочный
специальный (V7)
8000 S_IFREG - 100000 обычный (V7)
9000 S_IFCMP 110000 VxFS: сжатый
9000 S_IFNWK n 110000 сетевой специальный (HP-UX)
a000 S_IFLNK email-protected 120000 символьная ссылка (BSD)
b000 S_IFSHAD 130000 в Solaris — теневой inode для ACL (не виден пользовательскими процессами)
c000 S_IFSOCK s= 140000 сокет (BSD; также «S_IFSOC» в VxFS)
d000 S_IFDOOR D> 150000 Solaris: дверь
e000 S_IFWHT w% 160000 BSD whiteout (не используется для inode)
0200 S_ISVTX 001000 закрепляющий бит: сохраняет код программы в файле подкачки даже после использования (V7)
зарезервировано (SVID-v2)
для не каталогов: не кэшировать этот файл (SunOS)
для каталогов: флаг ограниченного удаления (SVID-v4.2)
0400 S_ISGID 002000 set-group-ID при выполнении (V7)
для каталогов: использовать семантику BSD для распространения GID
0400 S_ENFMT 002000 жёсткая блокировка файлов в стиле System V (общий c S_ISGID)
0800 S_ISUID 004000 set-user-ID на выполнение (V7)
0800 S_CDF 004000 каталог является файлом, зависящим от контекста (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);
}