diff options
Diffstat (limited to 'src/internal')
-rw-r--r-- | src/internal/slibtool_lconf_impl.c | 5 | ||||
-rw-r--r-- | src/internal/slibtool_realpath_impl.c | 103 | ||||
-rw-r--r-- | src/internal/slibtool_realpath_impl.h | 13 |
3 files changed, 119 insertions, 2 deletions
diff --git a/src/internal/slibtool_lconf_impl.c b/src/internal/slibtool_lconf_impl.c index 82904d2..298cb12 100644 --- a/src/internal/slibtool_lconf_impl.c +++ b/src/internal/slibtool_lconf_impl.c @@ -18,6 +18,7 @@ #include "slibtool_errinfo_impl.h" #include "slibtool_symlink_impl.h" #include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" #include "slibtool_visibility_impl.h" enum slbt_lconf_opt { @@ -387,7 +388,7 @@ static int slbt_lconf_trace_result_plain( fderr = slbt_driver_fderr(dctx); - cpath = !(slbt_util_real_path(fdat,lconf,0,path,sizeof(path))) + cpath = !(slbt_realpath(fdat,lconf,0,path,sizeof(path))) ? path : lconf; switch (err) { @@ -435,7 +436,7 @@ static int slbt_lconf_trace_result_annotated( fderr = slbt_driver_fderr(dctx); - cpath = !(slbt_util_real_path(fdat,lconf,0,path,sizeof(path))) + cpath = !(slbt_realpath(fdat,lconf,0,path,sizeof(path))) ? path : lconf; switch (err) { diff --git a/src/internal/slibtool_realpath_impl.c b/src/internal/slibtool_realpath_impl.c new file mode 100644 index 0000000..e1e47b5 --- /dev/null +++ b/src/internal/slibtool_realpath_impl.c @@ -0,0 +1,103 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <fcntl.h> +#include <stdlib.h> +#include <limits.h> +#include <errno.h> +#include <sys/stat.h> +#include <slibtool/slibtool.h> + +#include "slibtool_driver_impl.h" +#include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_visibility_impl.h" + +#ifdef HAVE_SYS_SYSCALL_H +#include <sys/syscall.h> +#endif + +#ifdef _MIDIPIX_ABI +#include <sys/fs.h> +#endif + +#ifndef ENOTSUP +#define ENOTSUP EOPNOTSUPP +#endif + +#ifdef SYS___realpathat +extern long syscall(int, ...); +#endif + +slbt_hidden int slbt_realpath( + int fdat, + const char * path, + int options, + char * buf, + size_t buflen) +{ + int ret; + int fd; + int fdproc; + struct stat st; + struct stat stproc; + char procfspath[36]; + + /* common validation */ + if (!buf || (options & O_CREAT)) { + errno = EINVAL; + return -1; + } + + /* framework-based wrapper */ +#ifdef _MIDIPIX_ABI + return __fs_rpath(fdat,path,options,buf,buflen); +#endif + +#ifdef SYS___realpathat + return syscall(SYS___realpathat,fdat,path,buf,buflen,0); +#endif + + /* buflen */ + if (buflen < PATH_MAX) { + errno = ENOBUFS; + return -1; + } + + /* AT_FDCWD */ + if (fdat == AT_FDCWD) { + return realpath(path,buf) ? 0 : -1; + } + + /* /proc/self/fd */ + if ((fd = openat(fdat,path,options,0)) < 0) + return -1; + + sprintf(procfspath,"/proc/self/fd/%d",fd); + + if (slbt_readlinkat(fdat,procfspath,buf,buflen)) { + close(fd); + return -1; + } + + if ((fdproc = openat(AT_FDCWD,buf,options|O_NOFOLLOW,0)) < 0) { + close(fd); + errno = ELOOP; + return -1; + } + + ret = fstat(fd,&st) || fstat(fdproc,&stproc); + + close(fd); + close(fdproc); + + if (ret || (st.st_dev != stproc.st_dev) || (st.st_ino != stproc.st_ino)) { + errno = ENOTSUP; + return -1; + } + + return 0; +} diff --git a/src/internal/slibtool_realpath_impl.h b/src/internal/slibtool_realpath_impl.h new file mode 100644 index 0000000..01df1c1 --- /dev/null +++ b/src/internal/slibtool_realpath_impl.h @@ -0,0 +1,13 @@ +#ifndef SLIBTOOL_REALPATH_IMPL_H +#define SLIBTOOL_REALPATH_IMPL_H + +#include <stdlib.h> + +int slbt_realpath( + int fdat, + const char * path, + int options, + char * buf, + size_t buflen); + +#endif |