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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/uio.h> 46 #include <sys/errno.h> 47 #include <sys/pathname.h> 48 #include <sys/kmem.h> 49 #include <sys/cred.h> 50 #include <sys/vnode.h> 51 #include <sys/debug.h> 52 53 /* 54 * Pathname utilities. 55 * 56 * In translating file names we copy each argument file 57 * name into a pathname structure where we operate on it. 58 * Each pathname structure can hold "pn_bufsize" characters 59 * including a terminating null, and operations here support 60 * allocating and freeing pathname structures, fetching 61 * strings from user space, getting the next character from 62 * a pathname, combining two pathnames (used in symbolic 63 * link processing), and peeling off the first component 64 * of a pathname. 65 */ 66 67 /* 68 * Allocate contents of pathname structure. Structure is typically 69 * an automatic variable in calling routine for convenience. 70 * 71 * May sleep in the call to kmem_alloc() and so must not be called 72 * from interrupt level. 73 */ 74 void 75 pn_alloc(struct pathname *pnp) 76 { 77 pnp->pn_path = pnp->pn_buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 78 pnp->pn_pathlen = 0; 79 pnp->pn_bufsize = MAXPATHLEN; 80 } 81 82 /* 83 * Free pathname resources. 84 */ 85 void 86 pn_free(struct pathname *pnp) 87 { 88 /* pn_bufsize is usually MAXPATHLEN, but may not be */ 89 kmem_free(pnp->pn_buf, pnp->pn_bufsize); 90 pnp->pn_path = pnp->pn_buf = NULL; 91 pnp->pn_pathlen = pnp->pn_bufsize = 0; 92 } 93 94 /* 95 * Pull a path name from user or kernel space. 96 * Called from pn_get() after allocation of a MAXPATHLEN buffer. 97 * Also called directly with a TYPICALMAXPATHLEN-size buffer 98 * on the stack as a local optimization. 99 */ 100 int 101 pn_get_buf(char *str, enum uio_seg seg, struct pathname *pnp, 102 void *buf, size_t bufsize) 103 { 104 int error; 105 106 pnp->pn_path = pnp->pn_buf = buf; 107 pnp->pn_bufsize = bufsize; 108 if (seg == UIO_USERSPACE) 109 error = copyinstr(str, pnp->pn_path, bufsize, &pnp->pn_pathlen); 110 else 111 error = copystr(str, pnp->pn_path, bufsize, &pnp->pn_pathlen); 112 if (error) 113 return (error); 114 pnp->pn_pathlen--; /* don't count null byte */ 115 return (0); 116 } 117 118 /* 119 * Pull a path name from user or kernel space. 120 */ 121 int 122 pn_get(char *str, enum uio_seg seg, struct pathname *pnp) 123 { 124 int error; 125 void *buf; 126 127 buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 128 if ((error = pn_get_buf(str, seg, pnp, buf, MAXPATHLEN)) != 0) 129 pn_free(pnp); 130 return (error); 131 } 132 133 /* 134 * Set path name to argument string. Storage has already been allocated 135 * and pn_buf points to it. 136 * 137 * On error, all fields except pn_buf will be undefined. 138 */ 139 int 140 pn_set(struct pathname *pnp, char *path) 141 { 142 int error; 143 144 pnp->pn_path = pnp->pn_buf; 145 error = copystr(path, pnp->pn_path, pnp->pn_bufsize, &pnp->pn_pathlen); 146 pnp->pn_pathlen--; /* don't count null byte */ 147 return (error); 148 } 149 150 /* 151 * Combine two argument path names by putting the second argument 152 * before the first in the first's buffer. This isn't very general; 153 * it is designed specifically for symbolic link processing. 154 * This function copies the symlink in-place in the pathname. This is to 155 * ensure that vnode path caching remains correct. At the point where this is 156 * called (from lookuppnvp), we have called pn_getcomponent(), found it is a 157 * symlink, and are now replacing the contents. The complen parameter indicates 158 * how much of the pathname to replace. If the symlink is an absolute path, 159 * then we overwrite the entire contents of the pathname. 160 */ 161 int 162 pn_insert(struct pathname *pnp, struct pathname *sympnp, size_t complen) 163 { 164 165 if (*sympnp->pn_path == '/') { 166 /* 167 * Full path, replace everything 168 */ 169 if (pnp->pn_pathlen + sympnp->pn_pathlen >= pnp->pn_bufsize) 170 return (ENAMETOOLONG); 171 if (pnp->pn_pathlen != 0) 172 ovbcopy(pnp->pn_path, pnp->pn_buf + sympnp->pn_pathlen, 173 pnp->pn_pathlen); 174 bcopy(sympnp->pn_path, pnp->pn_buf, sympnp->pn_pathlen); 175 pnp->pn_pathlen += sympnp->pn_pathlen; 176 pnp->pn_buf[pnp->pn_pathlen] = '\0'; 177 pnp->pn_path = pnp->pn_buf; 178 } else { 179 /* 180 * Partial path, replace only last component 181 */ 182 if ((pnp->pn_path - pnp->pn_buf) - complen + 183 pnp->pn_pathlen + sympnp->pn_pathlen >= pnp->pn_bufsize) 184 return (ENAMETOOLONG); 185 186 if (pnp->pn_pathlen != 0) 187 ovbcopy(pnp->pn_path, pnp->pn_path - complen + 188 sympnp->pn_pathlen, pnp->pn_pathlen + 1); 189 pnp->pn_path -= complen; 190 bcopy(sympnp->pn_path, pnp->pn_path, sympnp->pn_pathlen); 191 pnp->pn_pathlen += sympnp->pn_pathlen; 192 } 193 194 return (0); 195 } 196 197 int 198 pn_getsymlink(vnode_t *vp, struct pathname *pnp, cred_t *crp) 199 { 200 struct iovec aiov; 201 struct uio auio; 202 int error; 203 204 aiov.iov_base = pnp->pn_path = pnp->pn_buf; 205 aiov.iov_len = pnp->pn_bufsize; 206 auio.uio_iov = &aiov; 207 auio.uio_iovcnt = 1; 208 auio.uio_loffset = 0; 209 auio.uio_segflg = UIO_SYSSPACE; 210 auio.uio_extflg = UIO_COPY_CACHED; 211 auio.uio_resid = pnp->pn_bufsize; 212 if ((error = VOP_READLINK(vp, &auio, crp, NULL)) == 0) { 213 pnp->pn_pathlen = pnp->pn_bufsize - auio.uio_resid; 214 if (pnp->pn_pathlen == pnp->pn_bufsize) 215 error = ENAMETOOLONG; 216 else 217 pnp->pn_path[pnp->pn_pathlen] = '\0'; 218 } 219 return (error); 220 } 221 222 /* 223 * Get next component from a path name and leave in 224 * buffer "component" which should have room for 225 * MAXNAMELEN bytes (including a null terminator character). 226 */ 227 int 228 pn_getcomponent(struct pathname *pnp, char *component) 229 { 230 char c, *cp, *path, saved; 231 size_t pathlen; 232 233 path = pnp->pn_path; 234 pathlen = pnp->pn_pathlen; 235 if (pathlen >= MAXNAMELEN) { 236 saved = path[MAXNAMELEN]; 237 path[MAXNAMELEN] = '/'; /* guarantees loop termination */ 238 for (cp = path; (c = *cp) != '/'; cp++) 239 *component++ = c; 240 path[MAXNAMELEN] = saved; 241 if (cp - path == MAXNAMELEN) 242 return (ENAMETOOLONG); 243 } else { 244 path[pathlen] = '/'; /* guarantees loop termination */ 245 for (cp = path; (c = *cp) != '/'; cp++) 246 *component++ = c; 247 path[pathlen] = '\0'; 248 } 249 250 pnp->pn_path = cp; 251 pnp->pn_pathlen = pathlen - (cp - path); 252 *component = '\0'; 253 return (0); 254 } 255 256 /* 257 * Skip over consecutive slashes in the path name. 258 */ 259 void 260 pn_skipslash(struct pathname *pnp) 261 { 262 while (pnp->pn_pathlen > 0 && *pnp->pn_path == '/') { 263 pnp->pn_path++; 264 pnp->pn_pathlen--; 265 } 266 } 267 268 /* 269 * Sets pn_path to the last component in the pathname, updating 270 * pn_pathlen. If pathname is empty, or degenerate, leaves pn_path 271 * pointing at NULL char. The pathname is explicitly null-terminated 272 * so that any trailing slashes are effectively removed. 273 */ 274 void 275 pn_setlast(struct pathname *pnp) 276 { 277 char *buf = pnp->pn_buf; 278 char *path = pnp->pn_path + pnp->pn_pathlen - 1; 279 char *endpath; 280 281 while (path > buf && *path == '/') 282 --path; 283 endpath = path + 1; 284 while (path > buf && *path != '/') 285 --path; 286 if (*path == '/') 287 path++; 288 *endpath = '\0'; 289 pnp->pn_path = path; 290 pnp->pn_pathlen = endpath - path; 291 } 292 293 /* 294 * Eliminate any trailing slashes in the pathname. 295 * Return non-zero iff there were any trailing slashes. 296 */ 297 int 298 pn_fixslash(struct pathname *pnp) 299 { 300 char *start = pnp->pn_path; 301 char *end = start + pnp->pn_pathlen; 302 303 while (end > start && *(end - 1) == '/') 304 end--; 305 if (pnp->pn_pathlen == end - start) 306 return (0); 307 *end = '\0'; 308 pnp->pn_pathlen = end - start; 309 return (1); 310 } 311 312 /* 313 * Add a slash to the end of the pathname, if it will fit. 314 * Return ENAMETOOLONG if it won't. 315 */ 316 int 317 pn_addslash(struct pathname *pnp) 318 { 319 if (pnp->pn_path + pnp->pn_pathlen + 1 >= 320 pnp->pn_buf + pnp->pn_bufsize) { 321 if (pnp->pn_pathlen + 1 >= pnp->pn_bufsize) /* no room */ 322 return (ENAMETOOLONG); 323 /* 324 * Move the component to the start of the buffer 325 * so we have room to add the trailing slash. 326 */ 327 ovbcopy(pnp->pn_path, pnp->pn_buf, pnp->pn_pathlen); 328 pnp->pn_path = pnp->pn_buf; 329 } 330 pnp->pn_path[pnp->pn_pathlen++] = '/'; 331 pnp->pn_path[pnp->pn_pathlen] = '\0'; 332 return (0); 333 } 334