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 |