util_libc: Add util_readlink() and util_readlinkat() helpers

Introduce util_readlinkat() to read symbolic links relative to a
directory file descriptor, and util_readlink() as a convenience wrapper
using AT_FDCWD.

util_readlink() delegates to util_readlinkat() instead of duplicating
logic, ensuring a single implementation for both interfaces.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Polensky <japo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Jan Polensky
2025-09-29 17:17:26 +02:00
committed by Jan Höppner
parent 789b097d3a
commit 365be71dfc
2 changed files with 56 additions and 0 deletions

View File

@@ -12,6 +12,7 @@
#ifndef LIB_UTIL_LIBC_H
#define LIB_UTIL_LIBC_H
#include <fcntl.h>
#include <stdio.h>
#ifdef __cplusplus
@@ -124,6 +125,29 @@ do { \
va_end(ap); \
} while (0)
/**
* Reads the target of a symbolic link at the given path.
*
* @param[in] path Path to the symbolic link
* @return Newly allocated string with the link target, or NULL on error
*/
#define util_readlink(path) __util_readlinkat(__func__, __FILE__, __LINE__, AT_FDCWD, path)
/**
* Reads the target of a symbolic link relative to a directory file descriptor.
*
* Semantics:
* - If path is absolute, dirfd is ignored, per readlinkat semantics.
* - If path is relative, it is resolved relative to dirfd.
*
* @param[in] dirfd Directory file descriptor or AT_FDCWD
* @param[in] path Path to the symbolic link
* @return Newly allocated string with the link target, or NULL on error
*/
#define util_readlinkat(dirfd, path) __util_readlinkat(__func__, __FILE__, __LINE__, dirfd, path)
char *__util_readlinkat(const char *func, const char *file, int line, int dirfd, const char *path);
int __util_vsprintf(const char *func, const char *file, int line,
char *str, const char *fmt, va_list ap);
char *util_strcat_realloc(char *str1, const char *str2);

View File

@@ -10,11 +10,15 @@
*/
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
@@ -295,3 +299,31 @@ size_t util_strlcpy(char *dest, const char *src, size_t size)
return str_len;
}
char *__util_readlinkat(const char *func, const char *file, int line, int dirfd, const char *path)
{
ssize_t link_len = PATH_MAX;
struct stat st;
char *linkdir;
ssize_t len;
if (fstatat(dirfd, path, &st, AT_SYMLINK_NOFOLLOW) == 0 && st.st_size > 0)
link_len = st.st_size + 1;
linkdir = __util_malloc(func, file, line, link_len);
len = readlinkat(dirfd, path, linkdir, link_len);
if (len == -1) {
free(linkdir);
return NULL;
}
if (len >= link_len) {
warnx("%s: Link target too long", path);
free(linkdir);
return NULL;
}
linkdir[len] = '\0';
return __util_realloc(func, file, line, linkdir, (size_t)len + 1);
}