Файловая модель Linux достаточно хорошо поддерживает стандартизацию большинства файловых операций через обобщенные функции наподобие
read
и
write
(например, запись в программный канал выполняется так же, как запись в файл на диске). Однако некоторые устройства поддерживают операции, которые плохо моделируются такой абстракцией. Например, терминальные устройства, представленные как устройства символьные, нуждаются в представлении метода изменения скорости терминала, и приводы CD-ROM, представленные как блочные устройства, нуждаются в том, чтобы знать, кода они должны воспроизводить аудиодорожки, чтобы помочь увеличить производительность работы программистов.
Все эти разнообразные операции доступны через единственный системный вызов —
ioctl
(сокращение для "I/O control" — управление вводом-выводом), прототип которого показан ниже.
#include <sys/ioctl.h>
int ioctl(int fd, int request, ...);
Хотя
часто он применяется следующим образом:
int ioctl (int fd, int request, void *arg);
Всякий раз когда используется
ioctl
, его первый аргумент — это файл, с которым выполняются манипуляции, а второй аргумент указывает операцию, которая должна быть выполнена. Последний аргумент обычно представляет собой указатель на нечто, но на что именно, а так же точная семантика возвращаемого кода зависит от типа файла
fd
и типа запрошенной операции. Для некоторых операций
arg
— длинное целое вместо указателя; в этих случаях обычно применяется приведение типов. В нашей книге есть множество примеров применения
ioctl
, и вам нет нужды заботиться об
ioctl
до тех пор, пока вы не доберетесь до них.
11.3. Запрос и изменение информации inode
11.3.1. Поиск информации inode
В начале этой главы информационный узел файла (inode) был представлен как структура данных, которая отслеживает информацию о файле, независимо от представления ее для процесса. Например, размер файла является константой в любой момент времени — он не изменяется для разных процессов, которые имеют доступ к этому файлу (сравните это с текущей позицией в файле, которая уникальна для каждого вызова
open
, а не свойство самого файла). Linux предлагает три способа чтения информации inode.
#include <sys/stat.h>
int stat(const char *pathname, struct stat *statbuf);
int lstat (const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
Первая версия,
stat
возвращает информацию
inode
для файла, на который осуществляется ссылка через
pathname
, следуя всем символическим ссылкам, которые она представляет. Если вы не хотите следовать символическим ссылкам (например, чтобы проверить, не является ли само имя такой ссылкой), то используйте вместо этого
lstat
. Последняя версия,
fstat
, возвращает
inode
, на который ссылается текущий открытый файловый дескриптор. Все три системных вызова заполняют структуру
struct stat
, на которую указывает параметр
statbuf
, информацией о файловом inode. В табл. 11.3 описана информация, доступная в
struct stat
.
Таблица 11.3. Члены структуры
struct stat
Тип
Поле
Описание
dev_t
st_dev
Номер устройства, на котором находится файл.
ino_t
st_ino
Номер файлового on-disk inode. Каждый файл имеет номер on-disk inode, уникальный в пределах устройства, на котором он расположен. То есть пара (
st_dev
,
st_ino
) представляет собой уникальный идентификатор файла.
mode_t
st mode
Режим файла. Сюда включена информация о правах доступа и типе файла.
nlink_t
st_nlink
Количество путевых имен, ссылающихся на данный inode. Сюда не включаются символические ссылки, потому что они ссылаются на другие имена, а не на inode.
uid_t
st_uid
Идентификатор пользователя, владеющего файлом.
gid_t
st_gid
Идентификатор группы, владеющей файлом.
dev_t
st_rdev
Если файл — символьное или блочное устройство, это задает старший (major) и младший (minor) номера файла. Чтобы получить информацию о членах и макросах, которые манипулируют этим значением, обратитесь к обсуждению mknod далее в этой главе.
off_t
st size
Размер
файла в байтах. Это определено только для обычных файлов.
unsigned long
st_blksize
Размер блока в файловой системе, хранящей файл.
unsigned long
st_blocks
Количество блоков, выделенных файлу. Обычно
st_blksize * st_blocks
— это немного больше, чем
st_size
, потому что некоторое пространство в конечном блоке не используется. Однако для файлов с "дырками"
st_blksize * st_blocks
может быть заметно меньше, чем
st_size
.
time_t
st_atime
Время последнего доступа к файлу. Обновляется при каждом открытии файла или модификации его inode.
time_t
st_mtime
Время последней модификации файла. Обновляется при изменении данных файла.
time_t
st_ctime
Последнее время изменения файла или его inode, включая владельца, группу, счетчик связей и так далее.
11.3.2. Простой пример
stat
Рассмотрим простую программу, которая отображает информацию из
lstat
для каждого имени файла, переданного в аргументе. Она иллюстрирует, как использовать значения, возвращенные семейством функций
stat
.
1: /* statsamp.с */
2:
3: /* Для каждого имени файла, переданного в командной строке, отображаем
4: всю информацию, которую возвращает lstat для файла. */
5:
6: #include <errno.h>
7: #include <stdio.h>
8: #include <string.h>
9: #include <sys/stat.h>
10: #include <sys/sysmacros.h>
11: #include <sys/types.h>
12: #include <time.h>
13: #include <unistd.h>
14:
15: #define TIME_STRING_BUF 50
16:
17: /* Пользователь передает buf (минимальной длины TIME_STRING_BUF) вместо
18: использования статического для функции буфера, чтобы избежать применения
19: локальных статических переменных и динамической памяти. Никаких ошибок
20: происходить не должно, поэтому никакой проверки ошибок не делаем. */
21: char *time String (time_t t, char *buf) {
22: struct tm *local;
23:
24: local = localtime(&t);
25: strftime(buf, TIME_STRING_BUF, "%c", local);
26:
27: return buf;
28: }
29:
30: /* Отобразить всю информацию, полученную от lstat по имени
31: файла как единственному параметру. */
32: int statFile(const char *file) {
33: struct stat statbuf;
34: char timeBuf[TIME_STRING_BUF];
35:
36: if (lstat(file, &statbuf)) {
37: fprintf(stderr, "не удалось lstat %s: %s\n", file,
38: strerror(errno));
39: return 1;
40: }
41:
42: printf("Имя файла : %s\n", file);
43: printf("На устройстве: старший %d/младший %d Inode номер: %ld\n" ,