, слишком маленький, информация будет потеряна; полное имя указываемого файла будет недоступно. Чтобы использовать
readlink
должным образом, вы должны делать следующее:
1. Используйте
lstat
, чтобы убедиться, что это символическая ссылка.
2. Убедитесь, что ваш буфер для содержимого символической ссылки составляет по крайней мере '
sbuf.st_size + 1
' байтов; '
+ 1
' нужно для завершающего нулевого байта, чтобы сделать буфер годной к употреблению строкой С.
3. Вызовите
readlink
. Не мешает проверить, что возвращенное значение равно
sbuf.st_size
.
4. Добавьте '
\0
'
к байту после содержимого ссылки, чтобы превратить его в строку С. Код для всего этого мог бы выглядеть примерно так:
/* Проверка ошибок для краткости опущена */
int count;
char linkfile[PATH_MAX], realfile[PATH_MAX]; /* PATH_MAX в <limits.h> */
strut stat sbuf;
/* ...поместить в linkfile путь к нужной символической ссылке... */
lstat(linkfile, &sbuf); /* Получить сведения от stat */
if (!S_ISLNK(sbuf.st_mode)) /* Проверить, что это ссылка */
/* не символическая ссылка, обработать это */
if (sbuf.st_size + 1 > PATH_МАХ) /* Проверить размер буфера */
/* обработать проблемы с размером буфера */
count = readlink(linkfile, realfile, PATH_MAX);
/* Прочесть ссылку */
if (count != sbuf.st_size)
/* происходит что-то странное, обработать это */
realfile(count) = '\0'; /* Составить строку С */
Данный пример для простоты представления использует буферы фиксированного размера. Реальный код мог бы использовать для выделения буфера нужного размера
malloc
, поскольку массивы фиксированного размера могли бы оказаться слишком маленькими. Файл
lib/xreadlink.c
в GNU Coreutils делает именно это. Он читает содержимое символической ссылки в память, выделенную
malloc
. Мы покажем здесь саму функцию, большая часть файла представляет собой стереотипные определения. Номера строк относятся к началу файла:
55 /* Вызвать readlink для получения значения ссылки FILENAME.
56 Вернуть указатель на завершенную NUL строку в выделенной malloc памяти.
57 При ошибке readlink вернуть NULL (использовать errno для диагноза).
58 При ошибке realloc или если значение ссылки больше SIZE_MAX,
59 выдать диагностику и выйти. */
60
61 char*
62 xreadlink(char const* filename)
63 {
64 /* Начальный размер буфера для ссылки. Степень 2 обнаруживает
65 арифметическое переполнение раньше, но не рекомендуется. */
функции состоит из бесконечного цикла (строки 68–91), разрываемого в строке 84, которая возвращает выделенный буфер. Цикл начинается выделением первоначального буфера (строка 70) и чтения ссылки (строка 71). Строки 73–79 обрабатывают случай ошибки, сохраняя и восстанавливая errno таким образом, что она может корректно использоваться вызывающим кодом.
Строки 81–85 обрабатывают случай «успеха», при котором размер содержимого ссылки меньше размера буфера. В этом случае добавляется завершающий ноль (строка 83), а затем буфер возвращается, прерывая бесконечный цикл. Это гарантирует, что в буфер помещено все содержимое ссылки, поскольку у
readlink
нет возможности сообщить о «недостаточном размере буфера».
Строки 87–88 освобождают буфер и удваивают размер буфера для следующей попытки в начале цикла. Строки 89–90 обрабатывают случай, при котором размер ссылки слишком велик:
buf_size
больше, чем
SSIZE_MAX
, или
SSIZE_MAX
больше, чем значение, которое может быть представлено в знаковом целом того же размера, который использовался для хранения
SIZE_MAX
, и
buf_size
обернулся в ноль. (Это маловероятные условия, но странные вещи все же случаются.) Если одно из этих условий верно, программа завершается с сообщением об ошибке. В противном случае функция возвращается в начало цикла, чтобы сделать еще одну попытку выделить буфер и прочесть ссылку.
Некоторое дополнительное разъяснение: условие '
SIZE_MAX / 2 < SSIZE_MAX
' верно лишь на системах, в которых '
SIZE_MAX < 2 * SSIZE_MAX
'; мы не знаем таких, но лишь на таких системах
buf_size
может обернуться в ноль. Поскольку на практике это условие не может быть истинным, компилятор может оптимизировать все выражение, включив следующую проверку '
buf_size == 0
'. После прочтения этого кода вы можете спросить: «Почему не использовать
lstat
для получения размера символической ссылки, не выделить буфер нужного размера с помощью
Спасибо Джиму Мейерингу (Jim Meyering) за объяснение проблем — Примеч. автора.
•
lstat
является системным вызовом — лучше избежать накладных расходов по его вызову, поскольку содержимое большинства символических ссылок поместится в первоначальный размер буфера в 128.
• Вызов
lstat
создает условие состязания: ссылка может измениться между исполнением
lstat
и
readlink
, в любом случае вынуждая повторение.
• Некоторые системы не заполняют должным образом член
st_size
для символической ссылки. (Печально, но верно.) Сходным образом, как мы увидим в разделе 8.4.2 «Получение текущего каталога:
getcwd
», Linux в
/proc
предоставляет специальные символические ссылки, у которых