From 4320f0d6b6f9de1e83a047954372aaad8d499b24 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 16 Sep 2026 12:24:12 +0200 Subject: [PATCH] Add absolutepath helper for paths that may not exist --- os/mingw.c | 34 ++++++++++++++++++++++++++++++++++ os/os.h | 12 ++++++++++++ os/unix.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/os/mingw.c b/os/mingw.c index 044cb4c2..d6c4e2d4 100644 --- a/os/mingw.c +++ b/os/mingw.c @@ -2408,6 +2408,40 @@ char* windows_realpath(const char* path, char* resolved_path) /****************************************************************************/ /* fs */ +char* absolutepath(const char* restrict path, char* restrict resolved_path) +{ + if (path == 0 || path[0] == 0 || resolved_path == 0) { + errno = EINVAL; + return 0; + } + + wchar_t wpath[CONV_MAX]; + wchar_t wfull[CONV_MAX]; + + if (!u8tou16_mayfail(wpath, CONV_MAX, path, strlen(path) + 1, 0)) { + errno = EINVAL; + return 0; + } + + DWORD len = GetFullPathNameW(wpath, CONV_MAX, wfull, 0); + if (len == 0) { + windows_errno(GetLastError()); + return 0; + } + + if (len >= CONV_MAX) { + errno = ENAMETOOLONG; + return 0; + } + + if (!u16tou8_mayfail(resolved_path, CONV_MAX, wfull, len + 1, 0)) { + errno = ENAMETOOLONG; + return 0; + } + + return resolved_path; +} + static BOOL GetFilePhysicalOffset(HANDLE h, uint64_t* physical) { STARTING_VCN_INPUT_BUFFER svib; diff --git a/os/os.h b/os/os.h index 4fcb9800..80aecbbd 100644 --- a/os/os.h +++ b/os/os.h @@ -273,6 +273,18 @@ int os_validate_exec_input(const char* str); /****************************************************************************/ /* fs */ +/** + * Make a pathname absolute using the current working directory. + * + * The pathname is not required to exist and symbolic links are not resolved. + * The resolved_path buffer must be at least PATH_MAX bytes and must not overlap path. + * + * \param path Input pathname. + * \param resolved_path Destination buffer. + * \return resolved_path on success, 0 on failure with errno set. + */ +char* absolutepath(const char* restrict path, char* restrict resolved_path); + /** * Invalid inode number. * diff --git a/os/unix.c b/os/unix.c index 2fdf0007..c7d5d694 100644 --- a/os/unix.c +++ b/os/unix.c @@ -122,6 +122,42 @@ const char* os_signal_name(int sig) /****************************************************************************/ /* fs */ +char* absolutepath(const char* restrict path, char* restrict resolved_path) +{ + if (path == 0 || path[0] == 0 || resolved_path == 0) { + errno = EINVAL; + return 0; + } + + size_t path_len = strlen(path); + if (path_len >= PATH_MAX) { + errno = ENAMETOOLONG; + return 0; + } + + if (path[0] == '/') { + memcpy(resolved_path, path, path_len + 1); + return resolved_path; + } + + if (getcwd(resolved_path, PATH_MAX) == 0) + return 0; + + size_t resolved_len = strlen(resolved_path); + int separator = resolved_len != 0 && resolved_path[resolved_len - 1] != '/'; + + if (resolved_len + separator + path_len + 1 > PATH_MAX) { + errno = ENAMETOOLONG; + return 0; + } + + if (separator) + resolved_path[resolved_len++] = '/'; + memcpy(resolved_path + resolved_len, path, path_len + 1); + + return resolved_path; +} + #if !HAVE_EACCESS int eaccess(const char* pathname, int mode) {