10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*6812Sraf * Common Development and Distribution License (the "License"). 6*6812Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*6812Sraf 220Sstevel@tonic-gate /* 23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 30*6812Sraf #pragma ident "%Z%%M% %I% %E% SMI" 310Sstevel@tonic-gate 32*6812Sraf #include "lint.h" 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <dirent.h> 350Sstevel@tonic-gate #include <sys/param.h> 360Sstevel@tonic-gate #include <limits.h> 370Sstevel@tonic-gate #include <errno.h> 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <unistd.h> 400Sstevel@tonic-gate #include <string.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate /* 430Sstevel@tonic-gate * Canonicalize the path given in file_name, resolving away all symbolic link 440Sstevel@tonic-gate * components. Store the result into the buffer named by resolved_name, which 450Sstevel@tonic-gate * must be long enough (MAXPATHLEN bytes will suffice). Returns NULL 460Sstevel@tonic-gate * on failure and resolved_name on success. On failure, to maintain 470Sstevel@tonic-gate * compatibility with the past, the contents of file_name will be copied 480Sstevel@tonic-gate * into resolved_name. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate char * 510Sstevel@tonic-gate realpath(const char *file_name, char *resolved_name) 520Sstevel@tonic-gate { 530Sstevel@tonic-gate char cwd[PATH_MAX]; 540Sstevel@tonic-gate int len; 550Sstevel@tonic-gate 560Sstevel@tonic-gate if (file_name == NULL || resolved_name == NULL) { 570Sstevel@tonic-gate errno = EINVAL; 580Sstevel@tonic-gate return (NULL); 590Sstevel@tonic-gate } 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* 620Sstevel@tonic-gate * Call resolvepath() to resolve all the symlinks in file_name, 630Sstevel@tonic-gate * eliminate embedded "." components, and collapse embedded ".." 640Sstevel@tonic-gate * components. We may be left with leading ".." components. 650Sstevel@tonic-gate */ 660Sstevel@tonic-gate if ((len = resolvepath(file_name, resolved_name, PATH_MAX)) < 0) { 670Sstevel@tonic-gate (void) strlcpy(resolved_name, file_name, PATH_MAX); 680Sstevel@tonic-gate return (NULL); /* errno set by resolvepath() */ 690Sstevel@tonic-gate } 700Sstevel@tonic-gate 710Sstevel@tonic-gate if (len >= PATH_MAX) /* "can't happen" */ 720Sstevel@tonic-gate len = PATH_MAX - 1; 730Sstevel@tonic-gate resolved_name[len] = '\0'; 740Sstevel@tonic-gate 750Sstevel@tonic-gate if (*resolved_name == '/') /* nothing more to do */ 760Sstevel@tonic-gate return (resolved_name); 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * Prepend the current working directory to the relative path. 800Sstevel@tonic-gate * If the relative path is not empty (or "."), collapse all of the 810Sstevel@tonic-gate * resulting embedded ".." components with trailing cwd components. 820Sstevel@tonic-gate * We know that getcwd() returns a path name free of symlinks. 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate if (getcwd(cwd, sizeof (cwd)) == NULL) { 850Sstevel@tonic-gate (void) strlcpy(resolved_name, file_name, PATH_MAX); 860Sstevel@tonic-gate return (NULL); /* errno set by getcwd() */ 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate if (len != 0 && strcmp(resolved_name, ".") != 0) { 900Sstevel@tonic-gate char *relpath = resolved_name; 910Sstevel@tonic-gate char *endcwd = cwd + strlen(cwd); 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * Eliminate ".." components from the relative path 950Sstevel@tonic-gate * left-to-right, components from cwd right-to-left. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate relpath[len++] = '/'; 980Sstevel@tonic-gate while (len >= 3 && strncmp(relpath, "../", 3) == 0) { 990Sstevel@tonic-gate relpath += 3; 1000Sstevel@tonic-gate len -= 3; 1010Sstevel@tonic-gate while (*--endcwd != '/') 1020Sstevel@tonic-gate continue; 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate if (len == 0) { 1050Sstevel@tonic-gate /* the relative path was all ".." components */ 1060Sstevel@tonic-gate *endcwd = '\0'; 1070Sstevel@tonic-gate } else { 1080Sstevel@tonic-gate /* there are non-null components on both sides */ 1090Sstevel@tonic-gate relpath[--len] = '\0'; 1100Sstevel@tonic-gate *endcwd++ = '/'; 1110Sstevel@tonic-gate if (endcwd + len >= cwd + PATH_MAX) { 1120Sstevel@tonic-gate (void) strlcpy(resolved_name, 1130Sstevel@tonic-gate file_name, PATH_MAX); 1140Sstevel@tonic-gate errno = ENAMETOOLONG; 1150Sstevel@tonic-gate return (NULL); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate (void) strcpy(endcwd, relpath); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate (void) strcpy(resolved_name, cwd); 1220Sstevel@tonic-gate return (resolved_name); 1230Sstevel@tonic-gate } 124