Андрей Робачевский - Операционная система UNIX
Некоторые флаги, представленные в таблице, уже являются объединением нескольких флагов. Так, например, флаг S_RWXU эквивалентен S_IRUSR | S_IWUSR | S_IXUSR. Значение флага S_ISGID зависит от того, установлено или нет право на выполнение для группы (S_IXGRP). В первом случае, он будет означать установку SGID, а во втором — обязательное блокирование файла.
Для иллюстрации приведем небольшую программу, создающую файл с полными правами доступа для владельца, а затем изменяющую их. После каждой установки прав доступа в программе вызывается библиотечная функция system(3S), позволяющая запустить утилиту ls(1) и отобразить изменение прав доступа и дополнительных атрибутов.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
main() {
int fd;
/* Создадим файл с правами rwx------ */
fd = creat("my_file", S_IRUSR | S_IWUSR | S_IXUSR);
system("ls -l my_file");
/*Добавим флаг SUID */
fchmod(fd, S_IRWXU | S_ISUID);
/* Установим блокирование записей файла */
fchmod(fd, S_IRWXU | S_ISUID | S_ISGID);
system("ls -l my_file");
/* Теперь установим флаг SGID */
fchmod(fd, S_IRWXU | S_ISUID | S_ISGID | S_IXGRP);
system("ls -l my_file");
}
В результате запуска программы на выполнение, получим следующий вывод:
$ a.out
-rwx------ 1 andy user 0 Jan 6 19:28 my_file
-rws------ 1 andy user 0 Jan 6 19:28 my_file
-rws--1--- 1 andy user 0 Jan 6 19:28 my_file
-rws--s--- 1 andy user 0 Jan 6 19:28 my_file
Перемещение по файловой системе
Каждый процесс имеет два атрибута, связанных с файловой системой — корневой каталог (root directory) и текущий рабочий каталог (current working directory). Когда некоторый файл адресуется по имени (например, в системных вызовах open(2), creat(2) или readlink(2)), ядро системы производит поиск файла, начиная с корневого каталога, если имя файла задано как абсолютное, либо текущего каталога, если имя файла является относительным. Абсолютное имя файла начинается с символа '/', обозначающего корневой каталог. Все остальные имена файлов являются относительными. Например, имя /usr/bin/sh является абсолютным, в то время как mydir/test1.c или ../andy/mydir/test1.c — относительным, при котором фактическое расположение файла в файловой системе зависит от текущего каталога.
Процесс может изменить свой корневой каталог с помощью системного вызова chroot(2) или fchroot(2).
#include <unistd.h>
int chroot (const char *path);
int fchroot(int fildes);
После этого поиск всех адресуемых файлов с абсолютными именами будет производиться, начиная с нового каталога, указанного аргументом path. Например, после изменения корневого каталога на домашний каталог пользователя абсолютное имя инициализационного скрипта .profile станет /.profile.[22]
Изменение корневого каталога может потребоваться, например, при распаковке архива, созданного с абсолютными именами файла, в другом месте файловой системы, либо при работе над большим программным проектом, затрагивающим существенную часть корневой файловой системы. В этом случае для отладочной версии удобно создать собственную корневую иерархию.
Процесс также может изменить и текущий каталог. Для этого используются системные вызовы chdir(2) или fchdir(2):
#include <unistd.h>
int chdir(const char* path);
int fchdir(int fildes);
Например, внутренняя команда командного интерпретатора cd может быть реализована следующим кодом:
...
char newdir[PATH_MAX];
...
/* Предположим, что имя нового каталога,
введенного пользователем, уже находится
в переменной newdir*/
if (chdir(newdir) == -1) perror("sh: cd");
...
Метаданные файла
Как уже говорилось, каждый файл помимо собственно данных содержит метаданные, описывающие его характеристики, например, владельцев, права доступа, тип и размер файла, а также содержащие указатели на фактическое расположение данных файла. Метаданные файла хранятся в структуре inode. Часть полей этой структуры могут быть получены с помощью системных вызовов stat(2):
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
int lstat (const char *path, struct stat *buf);
int fstat(int fildes, struct stat *buf);
В качестве аргумента функции принимают имя файла или файловый дескриптор (fstat(2)) и возвращают заполненные поля структуры stat, которые приведены в табл. 2.15.
Таблица 2.15. Поля структуры stat
Поле Значение mode_t st_mode Тип файла и права доступа ino_t st_ino Номер inode. Поля st_ino и st_dev однозначно определяют обычные файлы dev_t st_dev Номер устройства, на котором расположен файл (номер устройства файловой системы) dev_t st_rdev Для специального файла устройства содержит номер устройства, адресуемого этим файлом nlink_t st_link Число жестких связей uid_t st_uid Идентификатор пользователя-владельца файла gid_t st_gid Идентификатор группы-владельца файла off_t st_size Размер файла в байтах. Для специальных файлов устройств это поле не определено time_t st_atime Время последнего доступа к файлу time_t st_mtime Время последней модификации данных файла time_t st_ctime Время последней модификации метаданных файла long st_blksize Оптимальный размер блока для операций ввода/вывода. Для специальных файлов устройств и каналов это поле не определено long st_blocks Число размещенных 512-байтовых блоков хранения данных. Для специальных файлов устройств это поле не определеноДля определения типа файла служат следующие макроопределения, описанные в файле <sys/stat.h>:
Таблица 2.16. Определение типа файла
Макроопределение Тип файла S_ISFIFO(mode) FIFO S_ISCHR(mode) Специальный файл символьного устройства S_ISDIR(mode) Каталог S_ISBLK(mode) Специальный файл блочного устройства S_ISREG(mode) Обычный файл S_ISLNK(mode) Символическая связь S_ISSOCK(mode) СокетВсе значения времени, связанные с файлом (время доступа, модификации данных и метаданных) хранятся в секундах, прошедших с 0 часов 1 января 1970 года. Заметим, что информация о времени создания файла отсутствует.
Приведенная ниже программа выводит информацию о файле, имя которого передается ей в качестве аргумента:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
main(int argc, char *argv[]) {
struct stat s;
char* ptype;
lstat(argv[1] , &s); /* Определим тип файла */
if (S_ISREG(s.st_mode)) ptype = "Обычный файл";
else if (S_ISDIR(s.st_mode)) ptype = "Каталог";
else if (S_ISLNK(s.st_mode)) ptype = "Симв. Связь";
else if (S_ISCHR(s.st_mode)) ptype = "Симв. Устройство";
else if (S_ISBLK(s.st_mode)) ptype = "Бл.устройство";
else if (S_ISSOCK(s.st_mode)) ptype = "Сокет";
else if (S_ISFIFO(s.st_mode)) ptype = "FIFO";
else ptype = "Неизвестный тип";
/* Выведем информацию о файле */
/* Его тип */
printf("type = %sn", ptype);