diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/helper/slbt_realpath.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/helper/slbt_realpath.c b/src/helper/slbt_realpath.c new file mode 100644 index 0000000..4c7446e --- /dev/null +++ b/src/helper/slbt_realpath.c @@ -0,0 +1,89 @@ + +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2020 Z. Gilboa */ +/* 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_readlink_impl.h" + +#ifdef _MIDIPIX_ABI +#include <sys/fs.h> +#endif + +#ifndef ENOTSUP +#define ENOTSUP EOPNOTSUPP +#endif + +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 + + /* 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_readlink(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; +} |