#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
Функция stat возвращает структуру с информацией о файле, указанном в аргументе pathname. Функция fstat возвращает информацию об открытом файле, который определяется дескриптором filedes. Функция lstat похожа на функцию stat, но когда ей передается имя символической ссылки, она возвращает сведения о самой символической ссылке, а не о файле, на который она ссылается. Второй аргумент, buf, является указателем на структуру, которую функция будет заполнять информацией. Определение структуры может отличаться для разных реализаций, но основная ее часть выглядит следующим образом:
struct stat {
mode_t st_mode; /* тип файла и режим (права доступа) */
ino_t st_ino; /* номер индексного узла */
dev_t st_dev; /* номер устройства (файловой системы) */
dev_t st_rdev; /* номер устройства для специальных файлов */
nlink_t st_nlink; /* количество ссылок */
uid_t st_uid; /* идентификатор пользователя владельца */
gid_t st_gid; /* идентификатор группы владельца */
off_t st_size; /* размер в байтах, для обычных файлов */
time_t st_atime; /* время последнего обращения к файлу */
time_t st_mtime; /* время последнего изменения файла */
time_t st_ctime; /* время последнего изменения флагов состояния файла */
blksize_t st_blksize; /* оптимальный размер блока ввода вывода */
blkcnt_t st_blocks; /* количество занятых дисковых блоков */
};
- Обычный файл – наиболее распространенный тип файлов, который хранит данные в том или ином виде. Ядро UNIX не делает различий между текстовыми и двоичными файлами. Любая интерпретация содержимого файла полностью возлагается на прикладную программу, обрабатываю щую файл.
- Файл каталога. Файлы этого типа содержат имена других файлов и ссылки на информацию о них. Любой процесс, обладающий правом на чтение каталога, может проверить его содержимое, но только ядро обладает правом на запись в файл каталога. Чтобы внести изменения в каталог, про цессы должны пользоваться функциями, обсуждаемыми в данной главе.
- Специальный файл блочного устройства. Этот тип файлов обеспечивает буферизованный ввод вывод для таких устройств, как дисковые устрой ства с фиксированным размером блока.
- Специальный файл символьного устройства. Этот тип файлов обеспечивает небуферизованный ввод вывод для устройств с переменным размером блока. Все устройства в системе являются либо специальными файлами блочных устройств, либо специальными файлами символьных устройств.
- FIFO, или именованный канал. Этот тип файлов используется для организации обмена информацией между процессами.
- Сокет. Этот тип файлов используется для организации обмена информацией между процессами через сетевые соединения. Сокеты можно применять и для обмена информацией между процессами на одной и той же ма шине.
- Символическая ссылка. Файлы этого типа представляют собой ссылки на другие файлы.
Тип файла хранится в поле st_mode структуры stat. Определить тип файла можно с помощью макроопределений, приведенных ниже
(Макросы для определения типа файла из <sys/stat.h>
)
- S_ISREG(st_mode) Обычный файл
- S_ISDIR(st_mode) Каталог
- S_ISCHR(st_mode) Специальный файл символьного устройства
- S_ISBLK(st_mode) Специальный файл блочного устройства
- S_ISFIFO(st_mode) Канал (именованный или неименованный)
- S_ISLNK(st_mode) Символическая ссылка
- S_ISSOCK(st_mode) Сокет
#include <unistd.h>
int access(const char *pathname, int mode);
Проверяет, какие операции с файлом по данному пути процесс может выполнить. Симлинки разыменовываются. Что можно проверить (флаги в mode, можно комбинировать через побитовое или):
- F_OK - просто факт существования
- R_OK - файл можно читать
- W_OK - в файл можно писать
- X_OK - файл можно исполнить
В случае успеха (всё, что спрашивалось, можно) вызов возвращает 0. В противном случае (в том числе, в случае ошибки) вызов возвращает -1 и выставляет errno в соответствии с причиной отказа.
Создание каталогов производится с помощью функции mkdir, а удаление – с помощью функции rmdir.
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode); /* Возвращает 0 в случае успеха, –1 в случае ошибки*/
#include <unistd.h>
int rmdir(const char *pathname); /* Возвращает 0 в случае успеха, –1 в случае ошибки */
#include <dirent.h>
DIR *opendir(const char *pathname); //Возвращает указатель в случае успеха или NULL в случае ошибки.
struct dirent *readdir(DIR *dp); // Возвращает указатель в случае успеха,
// NULL в случае достижения конца каталога или ошибки.
void rewinddir(DIR *dp); // Обнуляет текущую позицию в директории. Вызов всегда успешен.
int closedir(DIR *dp); // Парный вызов для opendir. Возвращает 0 в случае успеха или –1 в случае ошибки.
long telldir(DIR *dp); // Возвращает значение текущей позиции в каталоге, ассоциированном с dp,
// или -1 в случае ошибки.
void seekdir(DIR *dp, long loc); // Устанавливает текущую позицию в директории. Вызов всегда успешен.
Функции telldir и seekdir не являются частью стандарта POSIX.1. Это расширения XSI стандарта Single UNIX Specification – таким образом, предполагается, что они должны быть реализованы во всех версиях UNIX, следующих этой спецификации.
Структура dirent определена в файле <dirent.h> и зависит от конкретной реализации. Однако в любой версии UNIX эта структура содержит как минимум следующие два поля:
struct dirent {
ino_t d_ino; /* номер индексного узла */
char d_name[NAME_MAX + 1]; /* строка имени файла, завершающаяся нулевым символом */
}
Для каждого процесса определен текущий рабочий каталог. Относительно этого каталога вычисляются все относительные пути (то есть пути, которые не начинаются с символа слэша). Когда пользователь входит в систему, текущим рабочим каталогом обычно становится каталог, указанный в шестом поле записи из файла /etc/passwd, – домашний каталог пользователя. Текущий рабочий каталог – это атрибут процесса, домашний каталог – атрибут пользователя. Процесс может изменить текущий рабочий каталог с помощью функции chdirили fchdir.
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
/* Возвращают 0 в случае успеха, –1 в случае ошибки */
Пример использования функции chdir
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if (chdir("/tmp") < 0) {
fprintf(stderr, "ошибка вызова функции chdir: %s\n", strerror(errno));
exit(1);
}
printf("каталог /tmp стал текущим рабочим каталогом\n");
exit(0);
}
Поскольку ядро хранит сведения о текущем рабочем каталоге, должен быть способ получить его текущее значение. К сожалению, ядро хранит не полный путь к каталогу, а некоторую иную информацию, такую как указатель на виртуальный узел (v-node) каталога. Чтобы определить абсолютный путь к текущему рабочему каталогу, нужна функция, которая будет перемещаться вверх по дереву каталогов, начиная с текущего («точка») и далее через специальные каталоги «точка - точка»,пока не достигнет корневого каталога. В каждом из промежуточных каталогов функция будет читать записи из файла каталога, пока не найдет название, которое соответствует индексному узлу предыдущего каталога. Повторяя эту процедуру до тех пор, пока небудет достигнут корневой каталог, мы в результате получим абсолютный путь к текущему рабочему каталогу. К счастью, такая функция уже существует.
#include <unistd.h>
char *getcwd(char *buf, size_t size);
/* Возвращает указатель на buf в случае успеха, NULL в случае ошибки */
Пример использования функции getcwd
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
char *ptr;
size_t size = PATH_MAX + 1;
if (chdir("/usr/spool/uucppublic") < 0) {
fprintf(stderr, "ошибка вызова функции chdir: %s\n", strerror(errno));
exit(1);
}
if (!(ptr = malloc(size))) {
fprintf(stderr, "ошибка выделения памяти: %s\n", strerror(errno));
fflush(NULL);
abort();
}
if (getcwd(ptr, size) == NULL) {
fprintf(stderr, "ошибка вызова функции getcwd: %s\n", strerror(errno));
exit(1);
}
printf("cwd = %s\n", ptr);
exit(0);
}
Системные вызовы работы с временем были рассмотрены в лекции 6.
Тип time_t
.
Тип struct tm
.
Системный вызов time
.
Библиотечные функции localtime
, gmtime
.
Библиотечная функция mktime
.
В качестве основной службы времени ядро UNIX предоставляет счетчик секунд, прошедших от начала Эпохи – 00:00:00 1 января 1970 года по всеобщему скоординированному времени (UTC) Значение счетчика представлено типом данных time_tи называется календарным временем. С помощью календарного времени можно представить как дату, так и время суток. ОС UNIX всегда отличалась от других системтем, что она (а) хранит время UTC, а неместное время, (б) автоматически выполняет преобразования, такие как переход на летнее время, и (в) хранит дату и время как единое целое. Функция time возвращает текущее время и дату.
#include <time.h>
time_t time(time_t *calptr);
Возвращает значение времени в случае успеха, –1 в случае ошибки.Функция всегда возвращает значение времени. Если в качестве аргумента calptr передается непустой указатель, то значение времени дополнительно записывается по указанному адресу. Функция gettimeofdayдает более высокую точность, чем функция time (до микросекунд). Для некоторых приложений это очень важно.
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
Всегда возвращает значение 0. Эта функция определена стандартом Single UNIX Specification как расширение XSI. Единственное допустимое значение аргумента tzp– NULL; любые другие значения могут привести к непредсказуемым результатам. Некоторые платформы поддерживают указание часового пояса через аргумент tzp, но это зависит от конкретной реализации и не определено в Single UNIX Specification. Функция gettimeofdayсохраняет время, прошедшее от начала Эпохи до настоящего момента, по адресу tp. Это время представлено в виде структуры timeval, которая хранит секунды и микросекунды:
struct timeval {
time_t tv_sec; /* секунды */
long tv_usec; /* микросекунды */
};
Как только получено целочисленное значение количества секунд, прошедших с начала Эпохи, как правило, вызывается одна из функций преобразования, которая переведет числовое значение в удобочитаемые время и дату. Две функции, localtime и gmtime, преобразуют календарное время в структуру tm, состоящую из следующих элементов:
struct tm { /* время, разбитое на составляющие */
int tm_sec; /* секунды от начала минуты: [0 -60] */
int tm_min; /* минуты от начала часа: [0 - 59] */
int tm_hour; /* часы от полуночи: [0 - 23] */
int tm_mday; /* дни от начала месяца: [1 - 31] */
int tm_mon; /* месяцы с января: [0 - 11] */
int tm_year; /* годы с 1900 года */
int tm_wday; /* дни с воскресенья: [0 - 6] */
int tm_yday; /* дни от начала года (1 января): [0 - 365] */
int tm_isdst; /* флаг перехода на летнее время: <0, 0, >0 */
};
Количество секунд может превышать 59, когда для коррекции времени вставляется дополнительная секунда. Обратите внимание, что отсчет всех компонентов, кроме дня месяца, начинается с 0. Флаг перехода на летнее время представлен положительным числом, если действует летнее время, 0 – если нет и отрицательным числом, если данная информация недоступна.
#include <time.h>
struct tm *gmtime(const time_t *calptr);
struct tm *localtime(const time_t *calptr);
Функции localtimeи gmtimeотличаются тем, что первая преобразует календарное время в местное, учитывая при этом часовой пояс и переход на летнее время, а вторая разбивает календарное время UTC на составляющие. Функция mktime принимает местное время в виде структуры tm и преобразует его в значение time_t.
#include <time.h>
time_t mktime(struct tm *tmptr);
Возвращает календарное время в случае успеха, –1 в случае ошибки
Функции asctimeи ctimeвозвращают строку длиной 26 байт, которая напоминает вывод команды date(1):
Tue Feb 10 18:27:38 2004\n\0
#include <time.h>
char *asctime(const struct tm *tmptr);
char *ctime(const time_t *calptr);
Обе возвращают указатель на строку, завершающуюся нулевым символом
Функции asctime в качестве аргумента передается структура tm, тогда как функции ctime– календарное время. И наконец, последняя и самая сложная функция времени – strftime. Это printf подобная функция для представления временных значений.
#include <time.h>
size_t strftime(char *restrict buf, size_t maxsize, const char *restrict format,const struct tm *restrict tmptr);
Возвращает количество символов, записанных в массив,если в нем достаточно места, в противном случае возвращает 0
Последний аргумент функции – указатель на структуру tm, содержащую время, которое должно быть представлено в виде отформатированной строки. Результат форматирования сохраняется в буфере buf, размер которого определяется аргументом maxsize. Если полученная в результате преобразования строка, включая завершающий нулевой символ, умещается в буфере, то функция возвращает длину полученной строки без завершающего нулевогосимвола. В противном случае возвращается 0. Аргумент format управляет форматированием значения времени. Как и в случае с функцией printf, спецификаторы формата начинаются с символа процента, за которым следуют служебные символы. Все остальные символы встроке formatвыводятся без изменений. Два символа процента, следующие друг за другом, будут отображаться как один символ процента. В отличие от функции printf, каждый спецификатор формата генерирует на выходе строки фиксированного размера – спецификаторы ширины поля вывода не предусмотрены.
Функция mktime
#include <time.h>
time_t mktime( struct tm * ptrtime );
Интерпретирует содержимое структуры tm, передаваемой в функцию в качестве аргумента через указатель на ptrtime в формат местного времени. Данная функция по некоторым исходным значениям времени восстанавливает значения остальных членов ptrtime, соответственно. Исходные значения членов структуры tm_wday и tm_yday из ptrtime игнорируются. Диапазоны значений для остальных членов структуры ограничиваются их нормальными значениями (например, диапазон значений tm_mday находится между 1 и 31). Объект, на который указывает ptrtime изменяется, а именно — инициализируются переменные-члены tm_wday и tm_yday, и изменяются значения других переменных-членов в пределах нормы, в соответствии с указанным временем.
//пример использования функции mktime: определить день недели
#include <iostream>
#include <ctime>
int main ()
{
time_t rawtime; // тип данных для хранения количества секунд
struct tm * timeinfo; // структура даты и времени
int year, month ,day;
char * weekday[] = { "Воскресенье", "Понедельник",
"Вторник", "Среда",
"Четверг", "Пятница", "Суббота"};
//Ввод даты
std::cout << "Введите год: "; std::cin >> year;
std::cout << "Введите месяц: "; std::cin >> month;
std::cout << "Введите день: "; std::cin >> day;
// получить текущую информацию о дате и изменить её относительно введенной
time( &rawtime ); // текущая дата в секундах
timeinfo = localtime( &rawtime ); // преобразовние текущей даты из секунд к нормальному виду
timeinfo->tm_year = year - 1900; // корректируем год
timeinfo->tm_mon = month - 1; // корректируем значение месяца
timeinfo->tm_mday = day; // введённый день
mktime( timeinfo ); // определить день недели
std::cout << "День недели: " << weekday[timeinfo->tm_wday] << std::endl;
return 0;
}