Как использовать readlink с динамическим распределением памяти
Вопрос
Проблема:
На Linux-машине я хочу прочитать целевую строку ссылки.Из документации я нашел следующий образец кода (без обработки ошибок):
родовое словоПроблема в том, что sb.st_size возвращает 0 для ссылок в моей системе.
Так как же в таких системах динамически выделять память для строки чтения?
Большое спасибо!
Одно из возможных решений:
Для дальнейшего использования.Используя точку зрения Джилля:
родовое словоРешение
POSIX сообщает, что поле st_size
для символической ссылки должно быть установлено равным длине имени пути в ссылке (без кода '\0'
).Однако файловая система /proc
в Linux не совместима с POSIX.(У него больше нарушений, чем только это, например, при чтении определенных файлов по одному байту.)
Вы можете выделить буфер определенного размера, попробовать сгенерировать код и повторить попытку с большим буфером, если буфер был недостаточно велик (сгенерированный код кода вернул столько байтов, сколько поместилось в буфере), пока буфер не станет достаточно большим.
В качестве альтернативы вы можете использовать readlink()
и нарушить переносимость в системы, где он не является константой времени компиляции или где имя пути может быть длиннее этого (POSIX допускает и то).
Другие советы
В других ответах об этом не упоминается, но есть функция realpath
, которая делает именно то, что вы хотите, что указано в POSIX.1-2001.
со страницы руководства:
<цитата>realpath () раскрывает все символические ссылки и разрешает ссылки на /./, /../ и дополнительные символы '/' в строке с завершающим нулем с именем по пути для создания канонического абсолютного пути.
realpath
также обрабатывает распределение динамической памяти за вас, если вы хотите.Опять же, отрывок из справочной страницы:
Если resolved_path указано как NULL, то realpath () использует malloc (3) для выделения буфера размером до PATH_MAX байтов для хранения разрешенное имя пути и возвращает указатель на этот буфер.Звонящий должен освободить этот буфер с помощью free (3).
В качестве простого полного примера:
родовое словоst_size не дает правильный ответ на / proc.
Вместо этого вы можете указать байты PATH_MAX или pathconf (_PC_PATH_MAX).В большинстве случаев этого должно быть достаточно.Если вы хотите иметь возможность обрабатывать более длинные пути, вы можете вызвать readlink в цикле и перераспределить свой буфер, если возвращаемое значение readlink указывает, что буфер слишком короткий.Обратите внимание, что многие другие функции POSIX просто предполагают, что PATH_MAX достаточно.
Я немного озадачен, почему st_size
равен нулю. В POSIX:
Для символических ссылок член st_mode должен содержать значимую информацию при использовании с макросами типа файла. Биты режима файла в st_mode не определены. Элементы структуры st_ino, st_dev, st_uid, st_gid, st_atim, st_ctim и st_mtim должны иметь значимые значения, а значение члена st_nlink должно быть установлено равным количеству (жестких) ссылок на символическую ссылку. Значение элемента st_size должно быть установлено равным длине имени пути, содержащегося в символической ссылке, не включая завершающий нулевой байт.
Источник: http://pubs.opengroup.org/onlinepubs/9699919799/ functions / lstat.html
Если st_size
не работает, я думаю, ваш единственный вариант - динамически выделить буфер и продолжать увеличивать его размер до тех пор, пока возвращаемое значение readlink
равно размеру буфера.
На странице руководства для readlink(2)
написано, что она будет автоматически обрезаться, если буфер слишком мал.Если вы действительно хотите быть неограниченным (и не против заплатить некоторую плату за дополнительную работу), вы можете начать с заданного размера выделения и продолжать увеличивать его и повторно пробовать вызов readlink
.Вы можете остановить увеличение буфера, когда следующий вызов readlink
вернет ту же строку, что и на последней итерации.
Чего именно вы пытаетесь достичь с помощью lstat?
Вы сможете достичь цели с помощью следующих
родовое словоЕсли вы пытаетесь получить длину размера имени файла, я не думаю, что st_size - правильная переменная для этого ... Но, возможно, это другой вопрос.