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