1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1988 AT&T */ 27 /* All Rights Reserved */ 28 29 #include "lint.h" 30 #include <sys/types.h> 31 #include <dirent.h> 32 #include <sys/param.h> 33 #include <limits.h> 34 #include <errno.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <string.h> 38 39 /* 40 * Canonicalize the path given in file_name, resolving away all symbolic link 41 * components. Store the result into the buffer named by resolved_name, which 42 * must be long enough (PATH_MAX bytes will suffice). Returns NULL 43 * on failure and resolved_name on success. On failure, to maintain 44 * compatibility with the past, the contents of file_name will be copied 45 * into resolved_name. 46 */ 47 static char * 48 realpath_impl(const char *file_name, char *resolved_name) 49 { 50 char cwd[PATH_MAX]; 51 int len; 52 53 if (file_name == NULL) { 54 errno = EINVAL; 55 return (NULL); 56 } 57 58 /* 59 * Call resolvepath() to resolve all the symlinks in file_name, 60 * eliminate embedded "." components, and collapse embedded ".." 61 * components. We may be left with leading ".." components. 62 */ 63 if ((len = resolvepath(file_name, resolved_name, PATH_MAX)) < 0) { 64 (void) strlcpy(resolved_name, file_name, PATH_MAX); 65 return (NULL); /* errno set by resolvepath() */ 66 } 67 68 if (len >= PATH_MAX) /* "can't happen" */ 69 len = PATH_MAX - 1; 70 resolved_name[len] = '\0'; 71 72 if (*resolved_name == '/') /* nothing more to do */ 73 return (resolved_name); 74 75 /* 76 * Prepend the current working directory to the relative path. 77 * If the relative path is not empty (or "."), collapse all of the 78 * resulting embedded ".." components with trailing cwd components. 79 * We know that getcwd() returns a path name free of symlinks. 80 */ 81 if (getcwd(cwd, sizeof (cwd)) == NULL) { 82 (void) strlcpy(resolved_name, file_name, PATH_MAX); 83 return (NULL); /* errno set by getcwd() */ 84 } 85 86 if (len != 0 && strcmp(resolved_name, ".") != 0) { 87 char *relpath = resolved_name; 88 char *endcwd = cwd + strlen(cwd); 89 90 /* 91 * Eliminate ".." components from the relative path 92 * left-to-right, components from cwd right-to-left. 93 */ 94 relpath[len++] = '/'; 95 while (len >= 3 && strncmp(relpath, "../", 3) == 0) { 96 relpath += 3; 97 len -= 3; 98 while (*--endcwd != '/') 99 continue; 100 } 101 if (len == 0) { 102 /* the relative path was all ".." components */ 103 *endcwd = '\0'; 104 } else { 105 /* there are non-null components on both sides */ 106 relpath[--len] = '\0'; 107 *endcwd++ = '/'; 108 if (endcwd + len >= cwd + PATH_MAX) { 109 (void) strlcpy(resolved_name, 110 file_name, PATH_MAX); 111 errno = ENAMETOOLONG; 112 return (NULL); 113 } 114 (void) strcpy(endcwd, relpath); 115 } 116 } 117 118 (void) strcpy(resolved_name, cwd); 119 return (resolved_name); 120 } 121 122 /* 123 * Canonicalize the path given in file_name, resolving away all symbolic link 124 * components. If resolved_name is a null pointer, return a malloc()d 125 * buffer containing the result, else store the result into resolved_name 126 * and return resolved_name. Return NULL on failure. 127 */ 128 char * 129 realpath(const char *file_name, char *resolved_name) 130 { 131 char buffer[PATH_MAX]; 132 133 if (resolved_name != NULL) 134 return (realpath_impl(file_name, resolved_name)); 135 136 if (realpath_impl(file_name, buffer) != NULL) 137 return (strdup(buffer)); 138 139 return (NULL); 140 } 141 142 /* 143 * GNU extension. 144 */ 145 char * 146 canonicalize_file_name(const char *path) 147 { 148 return (realpath(path, NULL)); 149 } 150