Linux программирование в примерах - Роббинс Арнольд
Шрифт:
Интервал:
Закладка:
244 /* Возвращает 1, если PATH является годным к использованию
245 каталогом, 0 если нет, 2 если он не существует. */
246
247 static int
248 dir_ok(const char *path)
249 {
250 struct stat stats;
251
252 if (stat (path, &stats)) /* Nonzero return = failure */
253 return 2;
254
255 if (!S_ISDIR(stats.st_mode))
256 {
257 error(0, 0, _("'%s" is not a directory"), path);
258 return 0;
259 }
260
261 /* Используйте access для проверки прав доступа на поиск,
262 поскольку при проверке битов прав доступа st_mode они могут
263 потеряться новыми механизмами управления доступом. Конечно,
264 доступ теряется, если вы используете setuid. */
265 if (access (path, X_OK) != 0)
266 {
267 if (errno == EACCES)
268 error (0, 0, _("directory '%s' is not searchable"), path);
269 else
270 error(0, errno, "%s", path);
271 return 0;
272 }
273
274 return 1;
275 }
Код прост. Строки 252–253 проверяют, существует ли файл. Если stat() завершится неудачей, файл не существует. Строки 255–259 удостоверяют, что файл в самом деле является каталогом.
Комментарий в строках 261–264 объясняет использование access(). Проверки битов st_mode недостаточно: файл может находиться в файловой системе, которая смонтирована только для чтения, в удаленной файловой системе или в файловой системе, не принадлежащей Linux или Unix, или у файла могут быть атрибуты, предотвращающие доступ. Таким образом, лишь ядро может в действительности сказать, будет ли работать access. Строки 265–272 осуществляют проверку, выдавая сообщение об ошибке, определяемое значением errno (строки 267–270).
11.4. Проверка для эффективного пользователя: euidaccess() (GLIBC)
GLIBC предоставляет дополнительную функцию, которая работает подобно access(), но проверяет в соответствии с эффективными UID, GID и набором групп:
#include <unistd.h> /* CLIBC */
int euidaccess(const char *path, int amode);
Аргументы и возвращаемое значение имеют тот же смысл, как для access(). Когда равны эффективный и действительный UID и эффективный и действительный GID, euidaccess() вызывает для осуществления теста access(). Это имеет то преимущество, что ядро может проверить файловую систему только для чтения или другие условия, которые не отражаются в правах доступа и владении файлами.
В противном случае euidaccess() сравнивает значения владельца и группы файла со значениями эффективных UID и GID и набора групп, используя соответствующие биты прав доступа. Этот тест основан на сведениях о файле от stat().
Если вы пишете переносимую программу, но предпочитаете использовать этот интерфейс, достаточно просто извлечь исходный файл из архива GLIBC и приспособить его для общего использования.
11.5. Установка дополнительных битов доступа для каталогов
На современных системах setgid и «липкий» биты имеют особое значение при применении к каталогам.
11.5.1. Группа по умолчанию для новых файлов и каталогов
В оригинальной системе Unix, когда open() или creat() создавали новый файл, он получал эффективные UID и GID создавшего их процесса.
V7, BSD вплоть до BSD 4.1 и System V вплоть до Release 3 все трактовали каталоги как файлы. Однако, с добавлением дополнительного набора групп в BSD 4.2 способ создания новых каталогов изменился: новые каталоги наследовали группу родительского каталога. Более того, новые файлы также наследовали ID группы родительского каталога, а не эффективный GID создающего процесса.
Идея, лежащая в основе множества групп и каталогов, которые работают таким способом, была в усилении группового взаимодействия. У каждого проекта организации, использующего систему, была бы отдельная назначенная ему группа. Для каждой такой группы в группе этого проекта был бы каталог верхнего уровня, и все файлы проекта имели бы доступ на чтение и запись (а при необходимости и на исполнение). Вдобавок, новые файлы автоматически получают группу родительского каталога. Состоя одновременно в нескольких группах (наборе групп), пользователь мог бы как угодно перемещаться между проектами с помощью простой команды cd, а все файлы и каталоги сохраняли бы свою надлежащую группу.
Что происходит на современных системах? Ну, это еще один из немногих случаев, когда можно поймать двух зайцев. SunOS 4.0 придумал механизм, который был включен в System V Release 4; сегодня он используется по крайней мере в Solaris и GNU/Linux. Эти системы придают биту setgid родительского каталога нового файла или каталога следующее значение:
Бит setgid родительского каталога сброшен
Новые файлы и каталоги получают эффективный GID создающего процесса.
Бит setgid родительского каталога установлен
Новые файлы и каталоги получают GID родительского каталога. Новые каталоги наследуют также установленный бит setgid.
(До SunOS 4.0 бит setgid для каталогов не имел определенного значения.) Следующий сеанс показывает бит setgid в действии:
$ <b>cd /tmp</b> /* Перейти в /tmp */
$ <b>ls -ld .</b> /* Проверить его права доступа */
drwxrwxrwt 8 root root 4096 Oct 16 17:40 .
$ <b>id</b> /* Отметить текущие группы */
uid=2076(arnold) gid=42(devel) groups=19(floppy),42(devel),2076(arnold)
$ <b>mkdir d1 ; ls -ld d1</b> /* Создать новый каталог */