| READLINK(2) | Руководство программиста Linux | READLINK(2) | 
readlink, readlinkat - считывает значение символьной ссылки
#include <unistd.h>
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); #include <fcntl.h> /* определения констант of AT_* */ #include <unistd.h>
ssize_t readlinkat(int dirfd, const char *pathname,
                   char *buf, size_t bufsiz);
Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):
readlink():
readlinkat():
Вызов readlink() помещает содержимое символьной ссылки pathname в буфер buf размером bufsiz. readlink() не добавляет в buf байт null. Если буфер слишком мал для хранения всего содержимого, то содержимое будет урезано (без выдачи ошибки, до длины в bufsiz символов).
Системный вызов readlinkat() работает также как системный вызов readlink(), за исключением случаев, описанных здесь.
Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в readlink()).
Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как readlink()).
Если в pathname задан абсолютный путь, то dirfd игнорируется.
Начиная с Linux .6.39, pathname может быть пустой строкой; при этом вызов выполняет действие с символьной ссылкой, на которую ссылается dirfd (должна получаться с помощью вызова open(2) с флагами O_PATH и O_NOFOLLOW).
Смотрите в openat(2) объяснение необходимости readlinkat().
При успешном выполнении эти вызовы возвращают количество байт, помещённых в buf (если возвращаемое значение равно bufsiz, то возможно произошло обрезание). В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.
В readlinkat() дополнительно могут возникнуть следующие ошибки:
Системный вызов readlinkat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.
readlink(): 4.4BSD (readlink() появился в 4.2BSD), POSIX.1-2001, POSIX.1-2008.
readlinkat(): POSIX.1-2008.
В версиях glibc до glibc 2.4 включительно, тип результата readlink() был объявлен как int. В настоящее время типом возвращаемого результата является ssize_t, как (теперь) это требуется по POSIX.1-2001.
Буфера с фиксированным размером может не хватить для хранения содержимого символьной ссылки. Требуемый размер буфера можно получить как значение stat.st_size, возвращаемое на ссылку вызовом lstat(2). Однако, количество байт, записанное readlink() и readlinkat(), должно быть проверено, так как требуется убедиться, что размер символьной ссылки не увеличился между вызовами. Динамическое выделение буфера для readlink() и readlinkat() также поможет решить проблему с переносимостью, которая возникает, когда для размера буфера используется PATH_MAX, но согласно POSIX для этой константы не гарантируется, что она определена , если система не имеет такого ограничения.
В старых ядрах, где readlinkat() отсутствует, обёрточная функция glibc использует readlink(). Если pathname является относительным путём, то glibc собирает путь относительно символической ссылки в /proc/self/fd, которая соответствует аргументу dirfd.
Следующая программа динамически выделяет буфер, необходимый readlink(), из информации, предоставленной lstat(2), или использует буфер размером PATH_MAX, если lstat(2) вернул нулевой размер.
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
    struct stat sb;
    char *buf;
    ssize_t nbytes, bufsiz;
    if (argc != 2) {
        fprintf(stderr, "Использование: %s <путь>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if (lstat(argv[1], &sb) == -1) {
        perror("lstat");
        exit(EXIT_FAILURE);
    }
    /* Добавляем единицу к размеру ссылки, так чтобы можно было определить
       обрезанность буфера, возвращаемого readlink(). */
    bufsiz = sb.st_size + 1;
    /* У некоторых символьных ссылок в (например) /proc и /sys
       значение 'st_size' равно нулю. В этом случае используется
       PATH_MAX как «достаточный» размер. */
    if (sb.st_size == 0)
        bufsiz = PATH_MAX;
    buf = malloc(bufsiz);
    if (buf == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    nbytes = readlink(argv[1], buf, bufsiz);
    if (nbytes == -1) {
        perror("readlink");
        exit(EXIT_FAILURE);
    }
    printf("'%s' указывает на '%.*s'\n", argv[1], (int) nbytes, buf);
    /* Если возвращаемое значение равно размеру буфера, то
       ссылка назначения больше чем ожидалось (возможно, из-за того,
       что цель изменилась между вызовом lstat() и readlink()).
       Предупреждаем пользователя о том, что цель может быть
       обрезана. */
    if (nbytes == bufsiz)
        printf("(Возвращённый буфер мог быть обрезан)\n");
    free(buf);
    exit(EXIT_SUCCESS);
}
readlink(1), lstat(2), stat(2), symlink(2), realpath(3), path_resolution(7), symlink(7)
| 2019-03-06 | Linux |