Linux программирование в примерах
•
будетS_ISLNK(sbuf.st_mode).true•
содержит число байтов в имени указываемого файла.sbuf.st_sizeМы уже видели, что системный вызов
создает символическую ссылку. Но если дана существующая символическая ссылка, как можно получить имя файла, на которую она указывает? (Очевидно,symlink()может получить это имя; поэтому мы должны быть способны это сделать.)lsОткрывание ссылки с помощью
для чтения ее с использованиемopen()не будет работать,read()следует по ссылке на указываемый файл. Таким образом, символические ссылки сделали необходимым дополнительный системный вызов, который называетсяopen():readlink()#include <unistd.h> /* POSIX */int readlink(const char *path, char *buf, size_t bufsiz);помещает содержимое символической ссылки, на имя которой указываетreadlink(), в буфер, на который указываетpath. Копируется не болееbufсимволов. Возвращаемое значение равно числу символов, помещенных вbufsiz, либо -1, если возникла ошибка,bufне вставляет завершающий нулевой байт.readlink()Обратите внимание, что если буфер, переданный
, слишком маленький, информация будет потеряна; полное имя указываемого файла будет недоступно. Чтобы использоватьreadlink()должным образом, вы должны делать следующее:readlink()1. Используйте
, чтобы убедиться, что это символическая ссылка.lstat()2. Убедитесь, что ваш буфер для содержимого символической ссылки составляет по крайней мере '
' байтов; 'sbuf.st_size + 1' нужно для завершающего нулевого байта, чтобы сделать буфер годной к употреблению строкой С.+ 13. Вызовите
. Не мешает проверить, что возвращенное значение равноreadlink().sbuf.st_size4. Добавьте '
' к байту после содержимого ссылки, чтобы превратить его в строку С. Код для всего этого мог бы выглядеть примерно так:\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()в GNU Coreutils делает именно это. Он читает содержимое символической ссылки в память, выделеннуюlib/xreadlink.c. Мы покажем здесь саму функцию, большая часть файла представляет собой стереотипные определения. Номера строк относятся к началу файла:malloc()55 /* Вызвать readlink для получения значения ссылки FILENAME.56 Вернуть указатель на завершенную NUL строку в выделенной malloc памяти.57 При ошибке readlink вернуть NULL (использовать errno для диагноза).58 При ошибке realloc или если значение ссылки больше SIZE_MAX,59 выдать диагностику и выйти. */6061 char*62 xreadlink(char const* filename)63 {64 /* Начальный размер буфера для ссылки. Степень 2 обнаруживает65 арифметическое переполнение раньше, но не рекомендуется. */66 size_t buf_size = 128;6768 while(1)69 {70 char *buffer = xmalloc(buf_size);71 ssize_t link_length = readlink(filename, buffer, buf_size);7273 if (link_length < 0)74 {75 int saved_errno = errno;76 free(buffer);77 errno = saved_errno;78 return NULL;79 }8081 if ((size_t)link_length < buf_size)82 {83 buffer[link_length] = 0;84 return buffer;85 }8687 free(buffer);88 buf_size *= 2;89 if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0))90 xalloc_die();91 }92 }Тело функции состоит из бесконечного цикла (строки 68–91), разрываемого в строке 84, которая возвращает выделенный буфер. Цикл начинается выделением первоначального буфера (строка 70) и чтения ссылки (строка 71). Строки 73–79 обрабатывают случай ошибки, сохраняя и восстанавливая errno таким образом, что она может корректно использоваться вызывающим кодом.