2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1989, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1988 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A#include "lint.h"
2N/A#include <sys/fcntl.h>
2N/A#include <sys/param.h>
2N/A#include <sys/syscall.h>
2N/A#include <errno.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A
2N/A/*
2N/A * Call the kernel implementation of *realpath. It either takes
2N/A * a path (with fd = AT_FDCWD) or a file descriptor.
2N/A * If no buffer is passed in, we allocate a properly sized buffer.
2N/A * If the buffer size is 0, we will grow it until the kernel will
2N/A * returns a value or an error other than ERANGE.
2N/A */
2N/Astatic char *
2N/Akrealpath_impl(int fd, const char *path, char *buf, size_t bufsize)
2N/A{
2N/A int ret;
2N/A char *kbuf;
2N/A size_t mysize = bufsize;
2N/A char sbuf[MAXPATHLEN];
2N/A
2N/A if (buf == NULL) {
2N/A if (bufsize <= sizeof (sbuf)) {
2N/A kbuf = sbuf;
2N/A if (bufsize == 0)
2N/A mysize = sizeof (sbuf);
2N/A } else {
2N/A kbuf = malloc(bufsize);
2N/A if (kbuf == NULL)
2N/A return (NULL);
2N/A }
2N/A } else {
2N/A kbuf = buf;
2N/A }
2N/A do {
2N/A ret = syscall(SYS_frealpathat, fd, path, kbuf, mysize);
2N/A
2N/A if (ret == 0 || buf != NULL || bufsize != 0 || errno != ERANGE)
2N/A break;
2N/A
2N/A mysize *= 2;
2N/A if (buf != sbuf)
2N/A free(kbuf);
2N/A kbuf = malloc(mysize);
2N/A } while (kbuf != NULL);
2N/A
2N/A if (ret != 0 || kbuf == NULL) {
2N/A if (buf != kbuf && kbuf != sbuf)
2N/A free(kbuf);
2N/A /* Standard requires ENAMETOOLONG and EINVAL. */
2N/A if (errno == ERANGE)
2N/A errno = ENAMETOOLONG;
2N/A else if (errno == EFAULT)
2N/A errno = EINVAL;
2N/A return (NULL);
2N/A }
2N/A if (buf == NULL) {
2N/A buf = strdup(kbuf);
2N/A if (kbuf != sbuf)
2N/A free(kbuf);
2N/A }
2N/A return (buf);
2N/A}
2N/A
2N/A/*
2N/A * Canonicalize the path given in file_name, resolving away all symbolic link
2N/A * components. Store the result into the buffer named by resolved_name, which
2N/A * must be long enough. If no buffer is given, there is no limit. Returns NULL
2N/A * on failure and resolved_name on success. On failure, to maintain
2N/A * compatibility with the past, the contents of file_name will be copied
2N/A * into resolved_name.
2N/A */
2N/Achar *
2N/Arealpath(const char *file_name, char *resolved_name)
2N/A{
2N/A char *ret;
2N/A
2N/A ret = krealpath_impl(AT_FDCWD, file_name, resolved_name,
2N/A resolved_name == NULL ? 0 : MAXPATHLEN);
2N/A
2N/A /*
2N/A * EINVAL was likely mapped from EFAULT;
2N/A * we cannot dereference file_name or resolved_name.
2N/A */
2N/A if (ret == NULL && resolved_name != NULL && errno != EINVAL)
2N/A (void) strlcpy(resolved_name, file_name, MAXPATHLEN);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * frealpath() is similar to realpath but requires specifying the a size of
2N/A * the buffer; if no buffer is given, one will be allocated. If the size is 0,
2N/A * the system tries to allocate a buffer large enough to store the result.
2N/A * There is no limit to what this function will return in that case.
2N/A */
2N/Achar *
2N/Afrealpath(int fd, char *resolved_name, size_t bufsize)
2N/A{
2N/A return (krealpath_impl(fd, NULL, resolved_name, bufsize));
2N/A}
2N/A
2N/A/*
2N/A * GNU extension. No limit in what we return.
2N/A */
2N/Achar *
2N/Acanonicalize_file_name(const char *path)
2N/A{
2N/A return (krealpath_impl(AT_FDCWD, path, NULL, 0));
2N/A}