Выбрать главу

5.5. Смена владельца, прав доступа и времени изменения

Несколько других системных вызовов дают вам возможность изменять другие относящиеся к файлу сведения: в частности, владельца и группу файла, права доступа к файлу и времена доступа и изменения файла.

5.5.1. Смена владельца файла: chown(), fchown() и lchown()

Владелец и группа файла изменяются с помощью трех сходных системных вызовов.

#include <sys/types.h> /* POSIX */

#include <unistd.h>

int chown(const char *path, uid_t owner, gid_t group);

int fchown(int fd, uid_t owner, gid_t group);

int lchown(const char *path, uid_t owner, gid_t group);

chown() работает с аргументом имени файла, fchown() работает с открытым файлом, а lchown() работает с символической ссылкой вместо файла, на который эта ссылка указывает. Во всех других отношениях эти три вызова работают идентично, возвращая 0 в случае успеха и -1 при ошибке.

Стоит заметить, что один системный вызов изменяет как владельца, так и группу файла. Чтобы изменить лишь владельца или лишь группу, передайте (-1) в качестве того идентификационного номера, который должен остаться без изменений.

Хотя вы могли бы подумать, что можно передать соответствующее значение из полученного заранее struct stat для файла или файлового дескриптора, этот метод больше подвержен ошибкам. Возникает условие состязания: между вызовами stat() и chown() владелец или группа могут измениться.

Вы могли бы поинтересоваться: «Зачем нужно изменять владельца символической ссылки? Права доступа и владение ей не имеют значения». Но что случится, если пользователь уходит, а все его файлы все еще нужны? Необходима возможность изменения владельца всех файлов этого лица на кого-то еще, включая символические ссылки.

Системы GNU/Linux обычно не позволяют рядовым пользователям (не root) изменять владельца («отдавать») своих файлов. Смена группы на одну из групп пользователя, конечно, разрешена. Ограничение в смене владельцев идет от BSD систем, у которых тоже есть этот запрет. Главная причина в том, что разрешение пользователям отдавать файлы может нарушить дисковый учет. Рассмотрите такой сценарий:

$ mkdir mywork /* Создать каталог */

$ chmod go-rwx mywork /* Установить права доступа drwx------ */

$ cd mywork /* Перейти в него */

$ myprogram > large_data_file /* Создать большой файл */

$ chmod ugo+rw large_data_file /* Установить доступ -rw-rw-rw- */

$ chown otherguy large_data_file /* Передать файл otherguy */

В этом примере large_data_file теперь принадлежит пользователю otherguy. Первоначальный пользователь может продолжать читать и записывать файл из-за его прав доступа. Но дисковое пространство, которое он занимает, будет записано на счет otherguy. Однако, поскольку он находится в каталоге, который принадлежит первому пользователю и к которому otherguy не может получить доступ, otherguy не имеет возможности удалить файл.

Некоторые системы System V разрешают пользователям передавать свои файлы. (При смене владельца соответствующие биты файлов setuid и setgid сбрасываются.) Это может быть особенной проблемой, когда файлы извлекаются из архива .tar или .cpio; извлеченные файлы имеют UID и GID, закодированный в архиве. На таких системах программы tar и cpio имеют опции, предотвращающие это, но важно знать, что поведение chown() действительно отличается на разных системах.

В разделе 6.3 «Имена пользователя и группы» мы увидим, как соотносить имена пользователя и группы с соответствующими числовыми значениями

5.5.2. Изменение прав доступа: chmod() и fchmod()

Изменение прав доступа осуществляется с помощью одного из двух системных вызовов, chmod() и fchmod():

#include <sys/types.h> /* POSIX */

#include <sys/stat.h>

int chmod(const char *path, mode_t mode);

int fchmod(int fildes, mode_t mode);

chmod() работает с аргументом имени файла, a fchmod() работает с открытым файлом. (В POSIX нет вызова lchmod(), поскольку система игнорирует установки прав доступа для символических ссылок. Хотя на некоторых системах такой вызов действительно есть). Как и для большинства других системных вызовов, они возвращают 0 в случае успеха и -1 при ошибке. Права доступа к файлу может изменить лишь владелец файла или root.

Значение mode создается таким же образом, как для open() и creat(), как обсуждалось в разделе 4.6 «Создание файлов». См. также табл. 5.2, в которой перечислены константы прав доступа.

Система не допустит установки бита setgid (S_ISGID), если группа файла не совпадает с ID действующей группы процесса или с одной из его дополнительных групп. (Мы пока не обсуждали подробно эти проблемы; см. раздел 11.1.1 «Реальные и действующие ID».) Разумеется, эта проверка не относится к root или коду, выполняющемуся как root.

5.5.3. Изменение временных отметок: utime()

Структура struct stat содержит три поля типа time_t:

st_atime  Время последнего доступа к файлу (чтение)

st_mtime  Время последнего изменения файла (запись).

st_ctime  Время последнего изменения индекса файла (например, переименования)

Значение time_t представляет время в «секундах с начала эпохи». Эпоха является Началом Времени для компьютерных систем GNU/Linux и Unix используют в качестве начала Эпохи полночь 1 января 1970 г по универсальному скоординированному времени (UTC).[62] Системы Microsoft Windows используют в качестве начала Эпохи полночь 1 января 1980 г. (очевидно, местное время).

Значения time_t иногда называют временными отметками (timestamps). В разделе 6.1 «Время и даты» мы рассмотрим, как получаются эти данные и как они используются. Пока достаточно знать, чем является значение time_t и то, что оно представляет секунды с начала Эпохи.

Системный вызов utime() позволяет изменять отметки времени доступа к файлу и его изменения:

#include <sys/types.h> /* POSIX */

#include <utime.h>

int utime(const char *filename, struct utimbuf *buf);

Структура utimbuf выглядит следующим образом:

struct utimbuf {

 time_t actime;  /* время доступа */

 time_t modtime; /* время изменения */

};

При успешном вызове возвращается 0, в противном случае возвращается -1. Если buf равен NULL, система устанавливает время доступа и время изменения равным текущему времени.

вернуться

62

UTC представляет собой независимое от языка сокращение для Coordinated Universal Time (универсальное скоординированное время). Старый код (а иногда и люди постарше) называют это Гринвичским временем (Greenwich Mean Time, GMT), которое является временем в Гринвиче, Великобритания. Когда стали широко использоваться часовые пояса, в качестве точки отсчета, относительно которого все остальные часовые пояса отсчитывались либо вперед, либо назад, был выбран Гринвич — Примеч. автора.