Чтение онлайн

ЖАНРЫ

Linux программирование в примерах
Шрифт:

6 #include <unistd.h>

7 #include <sys/types.h>

8 #include <sys/stat.h>

9

10 int main(void)

11 {

12 int fd;

13 struct stat sbuf;

14

15 fd = open(".", O_RDONLY); /* открыть каталог для чтения */

16 fstat(fd, &sbuf); /* получить сведения, нужны начальные права доступа */

17 chdir(".."); /* 'cd ..' */

18 fchmod(fd, 0); /*
отменить права доступа каталога */

19

20 if (fchdir(fd) < 0) /* попытаться выполнить 'cd' обратно, должно завершиться неудачей */

21 perror("fchdxr back");

22

23 fchmod(fd, sbuf.st_mode & 07777); /* восстановить первоначальные права доступа */

24 close(fd); /* все сделано */

25

26 return 0;

27 }

Строка 15 открывает текущий каталог. Строка 16 вызывает

fstat
для открытого каталога, так что мы получаем копию его прав доступа. Строка 17 использует
chdir
для перемещения на один уровень в иерархии файлов. Строка 18 выполняет грязную работу, отменяя все права доступа первоначального каталога.

Строки 20–21 пытаются перейти обратно в первоначальный каталог. Ожидается, что эта попытка будет безуспешной, поскольку текущие права доступа не позволяют это. Строка 23 восстанавливает первоначальные права доступа, '

sbuf.st_mode & 07777
' получает младшие 12 битов прав доступа; это обычные 9 битов rwxrwxrwx и биты setuid, setgid и «липкий» бит, которые мы обсудим в главе 11 «Права доступа и ID пользователя и группы». Наконец, строка 24 заканчивает работу, закрывая открытый дескриптор файла. Вот что происходит при запуске программы.

$ ls -ld . /* Показать текущие права доступа */

drwxr-xr-x 2 arnold devel 4096 Sep 9 16:42 .

$ ch08-chdir /* Запустить программу */

fchdir back: Permission denied /* Ожидаемая неудача */

$ ls -ld . /* Снова посмотреть на права доступа */

drwxr-xr-x 2 arnold devel 4096 Sep 9 16:42 /* Все восстановлено как раньше */

8.4.2. Получение текущего каталога:

getcwd

Названная должным образом функция

getcwd
получает абсолютный путь текущего рабочего каталога.

#include <unistd.h> /* POSIX */

char *getcwd(char *buf, size_t size);

Функция заносит в

buf
путь; ожидается, что размер
buf
равен
size
байтам. При успешном завершении функция возвращает свой первый аргумент. В противном случае, если требуется более
size
байтов, она возвращает
NULL
и устанавливает в
errno ЕRANGE
. Смысл в том, что если случится
ERANGE
, следует попытаться выделить буфер большего размера (с помощью
malloc
или
realloc
) и попытаться снова.

Если любой из компонентов каталога, ведущих к текущему каталогу, не допускает чтения или поиска,

getcwd
может завершиться неудачей, а
errno
будет установлен в
EACCESS
. Следующая простая программа демонстрирует ее использование:

/* ch08-getcwd.c --- демонстрация getcwd.

Проверка ошибок для краткости опущена */

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

int main(void) {

 char buf[PATH_MAX];

 char *cp;

 cp = getcwd(buf, sizeof(buf));

 printf("Current dir: %s\n", buf);

 printf("Changing to ..\n");

 chdir(".."); /* 'cd ..' */

 cp = getcwd(buf, sizeof(buf));

 printf("Current dir is now: %s\n", buf);

 return 0;

}

Эта простая программа выводит текущий каталог, переходит в родительский каталог, затем выводит новый текущий каталог. (Переменная

cp
здесь на самом деле не нужна, но в реальной программе она была бы использована для проверки ошибок). При запуске программа создает следующий вывод:

$ ch08-getcwd

Current dir: /home/arnold/work/prenhall/progex/code/ch08

Changing to ..

Current dir is now: /home/arnold/work/prenhall/progex/code

Формально, если аргумент

buf
равен
NULL
, поведение
getcwd
не определено. В данном случае версия GLIBC
getcwd
вызовет
malloc
за вас, выделяя буфер с размером
size
. Идя даже дальше, если
size
равен 0, выделяется «достаточно большой» буфер для вмещения возвращенного имени пути. В любом случае вы должны вызвать для возвращенного указателя
free
после завершения работы с буфером.

Поведение GLIBC полезно, но не переносимо. Для кода, который должен работать на разных платформах, вы можете написать замещающую функцию, которая предоставляет те же самые возможности, в то же время заставив ее непосредственно вызывать

getcwd
на системе с GLIBC.

Системы GNU/Linux предоставляют файл

/proc/self/cwd
. Этот файл является символической ссылкой на текущий каталог:

$ cd /tmp /* Сменить каталог */

$ ls -l /рroc/self/cwd /* Посмотреть на файл */

lrwxrwxrwx 1 arnold devel 0 Sep 9 17:29 /proc/self/cwd -> /tmp

$ cd /* Перейти в домашний каталог */

$ ls -l /proc/self/cwd /* Снова посмотреть на него */

lrwxrwxrwx 1 arnold devel 0 Sep 9 17:30 /proc/self/cwd -> /home/arnold

Это удобно на уровне оболочки, но представляет проблему на уровне программирования. В частности, размер файла равен нулю! (Это потому, что это файл в

/proc
, который продуцирует ядро; это не настоящий файл, находящийся на диске.)

Поделиться с друзьями: