Blame src/helper/slbt_realpath.c

9ca35b
9ca35b
/*******************************************************************/
9ca35b
/*  slibtool: a skinny libtool implementation, written in C        */
05face
/*  Copyright (C) 2016--2021  Z. Gilboa                            */
9ca35b
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
9ca35b
/*******************************************************************/
9ca35b
9ca35b
#include <fcntl.h>
9ca35b
#include <stdlib.h>
9ca35b
#include <limits.h>
9ca35b
#include <errno.h>
9ca35b
#include <sys/stat.h>
9ca35b
#include <slibtool/slibtool.h>
9ca35b
c81d16
#include "slibtool_driver_impl.h"
9ca35b
#include "slibtool_readlink_impl.h"
9ca35b
fbce8b
#ifdef __unix__
fbce8b
#include <sys/syscall.h>
fbce8b
#endif
fbce8b
9ca35b
#ifdef _MIDIPIX_ABI
9ca35b
#include <sys/fs.h>
9ca35b
#endif
9ca35b
9ca35b
#ifndef ENOTSUP
9ca35b
#define ENOTSUP EOPNOTSUPP
9ca35b
#endif
9ca35b
fbce8b
#ifdef SYS___realpathat
fbce8b
extern long syscall(int, ...);
fbce8b
#endif
fbce8b
9ca35b
int slbt_realpath(
9ca35b
	int             fdat,
9ca35b
	const char *    path,
9ca35b
	int             options,
9ca35b
	char *          buf,
9ca35b
	size_t          buflen)
9ca35b
{
9ca35b
	int             ret;
9ca35b
	int             fd;
9ca35b
	int             fdproc;
9ca35b
	struct stat     st;
9ca35b
	struct stat     stproc;
9ca35b
	char    procfspath[36];
9ca35b
9ca35b
	/* common validation */
9ca35b
	if (!buf || (options & O_CREAT)) {
9ca35b
		errno = EINVAL;
9ca35b
		return -1;
9ca35b
	}
9ca35b
9ca35b
	/* framework-based wrapper */
9ca35b
#ifdef _MIDIPIX_ABI
9ca35b
	return __fs_rpath(fdat,path,options,buf,buflen);
9ca35b
#endif
9ca35b
fbce8b
#ifdef SYS___realpathat
fbce8b
	return syscall(SYS___realpathat,fdat,path,buf,buflen,0);
fbce8b
#endif
fbce8b
9ca35b
	/* buflen */
9ca35b
	if (buflen < PATH_MAX) {
9ca35b
		errno = ENOBUFS;
9ca35b
		return -1;
9ca35b
	}
9ca35b
9ca35b
	/* AT_FDCWD */
9ca35b
	if (fdat == AT_FDCWD) {
9ca35b
		return realpath(path,buf) ? 0 : -1;
9ca35b
	}
9ca35b
9ca35b
	/* /proc/self/fd */
9ca35b
	if ((fd = openat(fdat,path,options,0)) < 0)
9ca35b
		return -1;
9ca35b
9ca35b
	sprintf(procfspath,"/proc/self/fd/%d",fd);
9ca35b
c81d16
	if (slbt_readlinkat(fdat,procfspath,buf,buflen)) {
9ca35b
		close(fd);
9ca35b
		return -1;
9ca35b
	}
9ca35b
9ca35b
	if ((fdproc = openat(AT_FDCWD,buf,options|O_NOFOLLOW,0)) < 0) {
9ca35b
		close(fd);
9ca35b
		errno = ELOOP;
9ca35b
		return -1;
9ca35b
	}
9ca35b
9ca35b
	ret = fstat(fd,&st) || fstat(fdproc,&stproc);
9ca35b
9ca35b
	close(fd);
9ca35b
	close(fdproc);
9ca35b
9ca35b
	if (ret || (st.st_dev != stproc.st_dev) || (st.st_ino != stproc.st_ino)) {
9ca35b
		errno = ENOTSUP;
9ca35b
		return -1;
9ca35b
	}
9ca35b
9ca35b
	return 0;
9ca35b
}