diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h index de49275..ee70c79 100644 --- a/include/slibtool/slibtool.h +++ b/include/slibtool/slibtool.h @@ -300,6 +300,7 @@ slbt_api int slbt_archive_import (const struct slbt_driver_ctx *, struct slbt_api int slbt_copy_file (const struct slbt_driver_ctx *, struct slbt_exec_ctx *, char * src, char * dst); slbt_api int slbt_dump_machine (const char * compiler, char * machine, size_t bufsize); +slbt_api int slbt_realpath (int, const char *, int, char *, size_t); /* utility api */ slbt_api int slbt_main (char **, char **, diff --git a/project/common.mk b/project/common.mk index e08e900..cd653bc 100644 --- a/project/common.mk +++ b/project/common.mk @@ -4,6 +4,7 @@ API_SRCS = \ src/helper/slbt_archive_import.c \ src/helper/slbt_copy_file.c \ src/helper/slbt_dump_machine.c \ + src/helper/slbt_realpath.c \ src/logic/slbt_exec_compile.c \ src/logic/slbt_exec_ctx.c \ src/logic/slbt_exec_execute.c \ 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 +#include +#include +#include +#include +#include + +#include "slibtool_readlink_impl.h" + +#ifdef _MIDIPIX_ABI +#include +#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; +}