• Если аргумент oldpath ссылается на файл, который не является каталогом, то в этом случае в аргументе newpath нельзя указывать имя пути для каталога (ошибка EISDIR). Чтобы переименовать файл, указав на местоположение внутри каталога (то есть переместить файл в другой каталог), аргумент newpath должен содержать новое имя файла. Следующий системный вызов одновременно перемещает файл в другой каталог и меняет его имя:

rename("sub1/x", "sub2/y");

• При указании имени каталога в аргументе oldpath появляется возможность переименовать этот каталог. В таком случае ссылка newpath должна либо быть несуществующей, либо являться именем пустого каталога. Если аргумент newpath — существующий файл или существующий непустой каталог, то возникнет ошибка (соответственно ENOTDIR и ENOTEMPTY).

• Если аргумент oldpath является каталогом, то аргумент newpath не может содержать тот же префикс каталога, что и у аргумента oldpath. Например, мы не смогли бы переименовать /home/mtk на /home/mtk/bin (ошибка EINVAL).

• Файлы, с которыми соотносятся аргументы oldpath и newpath, должны располагаться в одной файловой системе. Это необходимо, поскольку каталог является списком жестких ссылок, указывающих на индексные дескрипторы в той же файловой системе, где расположен данный каталог. Как было сказано ранее, системный вызов rename() всего лишь оперирует содержимым списков каталога. При попытке переименовать файл с его переносом в другую файловую систему возникнет ошибка EXDEV. (Чтобы добиться желаемого результата, следует скопировать содержимое данного файла из одной файловой системы в другую, а затем удалить старый файл. Именно это выполняет команда mv.)

18.5. Работа с символическими ссылками: системные вызовы symlink() и readlink()

Теперь рассмотрим системные вызовы, которые применяются для создания символических ссылок и проверки их содержимого.

Системный вызов symlink() создает новую символическую ссылку linkpath для имени пути, указанного в аргументе filepath. (Чтобы удалить ее, используется системный вызов unlink().)

#include

int symlink(const char *filepath, const char *linkpath);

Возвращает 0 при успешном завершении или –1 при ошибке

Если имя пути, переданное в аргумент linkpath, уже существует, системный вызов завершается ошибкой (для переменной errno устанавливается значение EEXIST). Имя пути, указанное в аргументе filepath, может быть абсолютным или относительным.

Файл или каталог, указанные в аргументе filepath, могут и не существовать в момент совершения системного вызова. И даже если они существуют, ничто не препятствует их удалению впоследствии. Тогда ссылка linkpath становится зависшей и попытки ее разыменования с помощью других системных вызовов приведут к ошибке (как правило, ENOENT).

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

#include

ssize_t readlink(const char *pathname, char *buffer, size_t bufsiz);

Возвращает количество байтов, помещенных в массиве buffer, при успешном завершении или –1 при ошибке

Аргумент bufsiz является целым числом, которое используется, чтобы сообщить системному вызову readlink() количество байтов, доступных в массиве buffer.

Если не возникает ошибка, системный вызов readlink() возвращает количество байтов, фактически размещенных в массиве buffer. Если длина ссылки превышает величину bufsiz, в этот массив помещается обрезанная строка (а системный вызов readlink() возвращает размер этой строки — то есть bufsiz).

Поскольку в конце массива buffer не помещен завершающий нулевой байт, нет способа отличить обрезанную строку, возвращенную системным вызовом readlink(), от строки, которая в точности заполняет массив buffer. Один из вариантов проверки состоит в том, чтобы выделить массив buffer большего размера, а затем еще раз выполнить вызов readlink(). В другом варианте можно указать размер для имени пути с помощью константы PATH_MAX (описанной в разделе 11.1), определяющей длину самого длинного имени пути, который должна воспринимать программа.

Пример использования системного вызова readlink() приведен в листинге 18.4.

Стандарт SUSv3 определяет новое ограничение, SYMLINK_MAX, — его должна задавать конкретная реализация, чтобы указать максимальное количество байтов, которое может хранить символическая ссылка. Рекомендуемая величина данного ограничения — не менее 255 байт. На момент написания книги Linux не задает это ограничение. В основном тексте мы предлагаем использовать константу PATH_MAX, поскольку указанное ограничение должно быть по меньшей мере таким же, что и SYMLINK_MAX.

Перейти на страницу:

Похожие книги