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

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

14.1. Текущий рабочий каталог

14.1.1. Поиск текущего рабочего каталога

Функция

getcwd
позволяет процессу найти имя своего текущего каталога относительно корневого каталога системы.

#include <unistd.h>

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

Первый параметр,

buf
, указывает на буфер, хранящий путь к текущему каталогу. Если длина текущего пути превышает
size - 1
байт (-1 позволяет пути завершаться символом
'\0'
), функция возвращает ошибку
ЕRANGE
. Если вызов удается, возвращается
buf
; в случае ошибки возвращается
NULL
. Несмотря на то что в большинстве
современных оболочек поддерживается переменная окружения
PWD
, хранящая путь в текущий каталог, ее значение необязательно равняется значению, возвращаемому
getcwd
.
PWD
часто содержит элементы путей, являющиеся символическими ссылками на другие каталоги, но
getcwd
всегда возвращает путь, свободный от символических ссылок.

Если текущий путь неизвестен (например, во время запуска программы), буфер, содержащий текущий каталог, должен быть динамически распределен, поскольку размер текущего пути может быть произвольным. Код, должным образом читающий текущий путь, выглядит так, как показано ниже.

char * buf;

int len = 50;

buf = malloc(len);

while (!getcwd(buf, len) && errno == ERANGE) {

 len += 50;

 buf = realloc(buf, len);

}

Как и многие другие Unix-подобные системы, Linux предоставляет полезное расширение POSIX-спецификации

getcwd
. Если
buf
является
NULL
, функция распределяет буфер, размер которого достаточен для содержания текущего пути, с помощью нормального механизма
malloc
. Несмотря на то что вызывающий код должен позаботиться о надлежащем освобождении памяти, используемой результатом, это расширение обеспечивает лучшую очистку, нежели цикл, как показано в предыдущем примере.

Функция BSD по имени

getwd
является наиболее распространенной альтернативой
getcwd
, но ее определенные дефекты привели к разработке
getcwd
.

#include <unistd.h>

char * getwd(char * buf);

Как и

getcwd
,
getwd
заполняет
buf
текущим путем, хотя функция не имеет представления о размере
buf
.
getwd
никогда не записывает в буфер больше, чем
PATH_MAX
(определенная в
<limits.h>
), что позволяет программам избегать переполнения буферов, но не предоставляет программе механизма поиска правильного пути, если он превышает
PATH_MAX
байт [100] . Эта функция поддерживается Linux только для унаследованных приложений и не может использоваться новыми приложениями. Вместо этого применяйте правильную и более переносимую функцию
getcwd
.

100

Это верно;

PATH_MAX
не является фактическим пределом. POSIX считает его неопределенным, что обычно является эквивалентом "не используйте его".

Если для пользователей необходимо отображать текущий путь каталога, хорошим решением будет проверка переменной окружения

PWD
. Если она установлена, она содержит путь, который применяется пользователем и который может содержать символические ссылки на некоторые элементы пути. Этот путь обычно и должен отображаться приложением по желанию пользователя. Для облегчения задачи библиотека С в Linux предоставляет функцию
get_current_dir_name
, реализуемую следующим образом.

char * get_current_dir_name {

char * env = getenv("PWD");

if (env)

 return strdup(env);

else

 return getcwd(NULL, 0);

}

14.1.2. Специальные файлы

.
и
..

Каждый каталог, включая корневой, содержит также два специальных файла под именами

.
и
..
, полезные при определенных условиях. Первый,
.
то же самое, что и текущий каталог. Это означает, что имена
somefile
и
./somefile
эквивалентны.

Еще одно специальное имя файла,

..
, является родительским каталогом текущего каталога. В случае корневого каталога
..
относится к самому корневому каталогу (поскольку у корневого каталога нет родительского каталога).

И

.
, и
..
можно применять везде, где можно использовать имя каталога. Нормально то, что отношение символических ссылок к путям вроде
../include/mylib
и именам файлов наподобие
/./foo/.././bar/./fubar/../../usr/bin/less
является законным (хотя эти названия довольно запутаны) [101] .

101

Имя этого пути эквивалентно более простому

/usr/bin/less
.

14.1.3. Смена текущего каталога

Предусмотрено два системных вызова, меняющих текущий каталог процесса:

chdir
и
fchdir
.

#include <unistd.h>

int chdir(const char * pathname);

int fchdir(int fd);

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

14.2. Смена корневого каталога

Хотя в системе имеется один корневой каталог, значение

/
может меняться для каждого процесса в системе. Это обычно делается для предотвращения доступа к файловой системе со стороны сомнительных процессов (например, демоны ftp, обрабатывающие запросы ненадежных пользователей). Например, если в качестве корневого каталога процесса определен
/home/ftp
, запуск
chdir("/")
сделает текущий каталог процесса
/home/ftp
, a
getcwd
вернет
/
для поддержания последовательности данного процесса. С целью обеспечения безопасности, если процесс пытается выполнить
chdir("/..")
, он остается в своем каталоге
/
(каталог
/home/ftp
в масштабах всей системы), так же как и нормальные процессы, выполняющие
chdir("/..")
остаются в корневом каталоге в масштабах всей системы. Процесс может легко изменять свой текущий корневой каталог с помощью системного вызова
chroot
. Но путь нового корневого каталога процесса интерпретируется с помощью текущего установленного корневого каталога, поэтому
chroot("/")
не модифицирует текущий корневой каталог процесса.

#include <unistd.h>

int chroot(const char * path);

Здесь

path
определяет новый корневой каталог для процесса. Этот системный вызов, однако, не изменяет текущий каталог процесса. У процесса все еще есть доступ к файлам в текущем каталоге, а также в родственном ему каталоге (
../../directory/file
). Большинство процессов, выполняющих
chroot
, немедленно меняют свои текущие каталоги, чтобы находиться внутри новой корневой иерархии, с помощью
chdir("/")
или чего-либо подобного. Отмена этого действия может вызвать проблемы с безопасностью в некоторых приложениях.

14.3. Создание и удаление каталогов

14.3.1. Создание новых каталогов

Создание новых каталогов выполняется очень просто.

#include <fcntl.h>

#include <unistd.h>

int mkdir(const char * dirname, mode_t mode);

Путь, определенный в

dirname
, создается как новый каталог с полномочием
mode
(что модифицируется
umask
процесса). Если
dirname
определяет существующий файл, или некоторые элементы dirname не являются каталогом или символической ссылкой на него, системный вызов не удается.

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