diff options
author | midipix <writeonce@midipix.org> | 2024-02-19 01:54:51 +0000 |
---|---|---|
committer | midipix <writeonce@midipix.org> | 2024-02-19 02:59:31 +0000 |
commit | 8dc63ddc326ec54709c580a400536fcc4ef62622 (patch) | |
tree | 2a019207f3ea1ae39273fa8246c0cae7e6341ca4 /src/util/slbt_realpath.c | |
parent | 51c276fbf1686c340588660a754ea04e6099cd37 (diff) | |
download | slibtool-8dc63ddc326ec54709c580a400536fcc4ef62622.tar.bz2 slibtool-8dc63ddc326ec54709c580a400536fcc4ef62622.tar.xz |
library api's: _util_ (utility helper interfaces) namespace overhaul.
Diffstat (limited to 'src/util/slbt_realpath.c')
-rw-r--r-- | src/util/slbt_realpath.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/util/slbt_realpath.c b/src/util/slbt_realpath.c new file mode 100644 index 0000000..3929e04 --- /dev/null +++ b/src/util/slbt_realpath.c @@ -0,0 +1,101 @@ +/*******************************************************************/ +/* 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" + +#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 + +int slbt_util_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; +} |