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