1b819cea2SGordon Ross /* 2b819cea2SGordon Ross * CDDL HEADER START 3b819cea2SGordon Ross * 4b819cea2SGordon Ross * The contents of this file are subject to the terms of the 5b819cea2SGordon Ross * Common Development and Distribution License (the "License"). 6b819cea2SGordon Ross * You may not use this file except in compliance with the License. 7b819cea2SGordon Ross * 8b819cea2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9b819cea2SGordon Ross * or http://www.opensolaris.org/os/licensing. 10b819cea2SGordon Ross * See the License for the specific language governing permissions 11b819cea2SGordon Ross * and limitations under the License. 12b819cea2SGordon Ross * 13b819cea2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14b819cea2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15b819cea2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16b819cea2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17b819cea2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18b819cea2SGordon Ross * 19b819cea2SGordon Ross * CDDL HEADER END 20b819cea2SGordon Ross */ 21b819cea2SGordon Ross 22b819cea2SGordon Ross /* 23b819cea2SGordon Ross * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 24b819cea2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25b819cea2SGordon Ross */ 26b819cea2SGordon Ross 27b819cea2SGordon Ross /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28b819cea2SGordon Ross /* All Rights Reserved */ 29b819cea2SGordon Ross 30b819cea2SGordon Ross /* 31b819cea2SGordon Ross * University Copyright- Copyright (c) 1982, 1986, 1988 32b819cea2SGordon Ross * The Regents of the University of California 33b819cea2SGordon Ross * All Rights Reserved 34b819cea2SGordon Ross * 35b819cea2SGordon Ross * University Acknowledgment- Portions of this document are derived from 36b819cea2SGordon Ross * software developed by the University of California, Berkeley, and its 37b819cea2SGordon Ross * contributors. 38b819cea2SGordon Ross */ 39b819cea2SGordon Ross 40b819cea2SGordon Ross #include <sys/types.h> 41b819cea2SGordon Ross #include <sys/param.h> 42b819cea2SGordon Ross #include <sys/systm.h> 43b819cea2SGordon Ross #include <sys/file.h> 44b819cea2SGordon Ross #include <sys/errno.h> 45b819cea2SGordon Ross #include <sys/cred.h> 46b819cea2SGordon Ross #include <sys/user.h> 47b819cea2SGordon Ross #include <sys/uio.h> 48b819cea2SGordon Ross #include <sys/vfs.h> 49b819cea2SGordon Ross #include <sys/vnode.h> 50b819cea2SGordon Ross #include <sys/pathname.h> 51b819cea2SGordon Ross #include <sys/proc.h> 52b819cea2SGordon Ross #include <sys/vtrace.h> 53b819cea2SGordon Ross #include <sys/sysmacros.h> 54b819cea2SGordon Ross #include <sys/debug.h> 55b819cea2SGordon Ross #include <sys/dirent.h> 56b819cea2SGordon Ross #include <sys/zone.h> 57b819cea2SGordon Ross #include <sys/dnlc.h> 58b819cea2SGordon Ross #include <sys/fs/snode.h> 59b819cea2SGordon Ross 60b819cea2SGordon Ross /* 61b819cea2SGordon Ross * Starting at current directory, translate pathname pnp to end. 62b819cea2SGordon Ross * Leave pathname of final component in pnp, return the vnode 63b819cea2SGordon Ross * for the final component in *compvpp, and return the vnode 64b819cea2SGordon Ross * for the parent of the final component in dirvpp. 65b819cea2SGordon Ross * 66b819cea2SGordon Ross * This is the central routine in pathname translation and handles 67b819cea2SGordon Ross * multiple components in pathnames, separating them at /'s. It also 68b819cea2SGordon Ross * implements mounted file systems and processes symbolic links. 69b819cea2SGordon Ross * 70b819cea2SGordon Ross * vp is the vnode where the directory search should start. 71b819cea2SGordon Ross * 72b819cea2SGordon Ross * Reference counts: vp must be held prior to calling this function. rootvp 73b819cea2SGordon Ross * should only be held if rootvp != rootdir. 74b819cea2SGordon Ross */ 75b819cea2SGordon Ross int 76b819cea2SGordon Ross lookuppnvp( 77b819cea2SGordon Ross struct pathname *pnp, /* pathname to lookup */ 78b819cea2SGordon Ross struct pathname *rpnp, /* if non-NULL, return resolved path */ 79b819cea2SGordon Ross int flags, /* follow symlinks */ 80b819cea2SGordon Ross vnode_t **dirvpp, /* ptr for parent vnode */ 81b819cea2SGordon Ross vnode_t **compvpp, /* ptr for entry vnode */ 82b819cea2SGordon Ross vnode_t *rootvp, /* rootvp */ 83b819cea2SGordon Ross vnode_t *vp, /* directory to start search at */ 84b819cea2SGordon Ross cred_t *cr) /* user's credential */ 85b819cea2SGordon Ross { 86b819cea2SGordon Ross vnode_t *cvp; /* current component vp */ 87b819cea2SGordon Ross vnode_t *tvp; /* addressable temp ptr */ 88b819cea2SGordon Ross char component[MAXNAMELEN]; /* buffer for component (incl null) */ 89b819cea2SGordon Ross int error; 90b819cea2SGordon Ross int nlink; 91b819cea2SGordon Ross int lookup_flags; 92b819cea2SGordon Ross struct pathname presrvd; /* case preserved name */ 93b819cea2SGordon Ross struct pathname *pp = NULL; 94b819cea2SGordon Ross vnode_t *startvp; 95b819cea2SGordon Ross int must_be_directory = 0; 96b819cea2SGordon Ross boolean_t retry_with_kcred; 97b819cea2SGordon Ross 98b819cea2SGordon Ross nlink = 0; 99b819cea2SGordon Ross cvp = NULL; 100b819cea2SGordon Ross if (rpnp) 101b819cea2SGordon Ross rpnp->pn_pathlen = 0; 102b819cea2SGordon Ross 103b819cea2SGordon Ross lookup_flags = dirvpp ? LOOKUP_DIR : 0; 104b819cea2SGordon Ross if (flags & FIGNORECASE) { 105b819cea2SGordon Ross lookup_flags |= FIGNORECASE; 106b819cea2SGordon Ross pn_alloc(&presrvd); 107b819cea2SGordon Ross pp = &presrvd; 108b819cea2SGordon Ross } 109b819cea2SGordon Ross 110b819cea2SGordon Ross /* 111b819cea2SGordon Ross * Eliminate any trailing slashes in the pathname. 112b819cea2SGordon Ross * If there are any, we must follow all symlinks. 113b819cea2SGordon Ross * Also, we must guarantee that the last component is a directory. 114b819cea2SGordon Ross */ 115b819cea2SGordon Ross if (pn_fixslash(pnp)) { 116b819cea2SGordon Ross flags |= FOLLOW; 117b819cea2SGordon Ross must_be_directory = 1; 118b819cea2SGordon Ross } 119b819cea2SGordon Ross 120b819cea2SGordon Ross startvp = vp; 121b819cea2SGordon Ross next: 122b819cea2SGordon Ross retry_with_kcred = B_FALSE; 123b819cea2SGordon Ross 124b819cea2SGordon Ross /* 125b819cea2SGordon Ross * Make sure we have a directory. 126b819cea2SGordon Ross */ 127b819cea2SGordon Ross if (vp->v_type != VDIR) { 128b819cea2SGordon Ross error = ENOTDIR; 129b819cea2SGordon Ross goto bad; 130b819cea2SGordon Ross } 131b819cea2SGordon Ross 132b819cea2SGordon Ross if (rpnp && VN_CMP(vp, rootvp)) 133b819cea2SGordon Ross (void) pn_set(rpnp, "/"); 134b819cea2SGordon Ross 135b819cea2SGordon Ross /* 136b819cea2SGordon Ross * Process the next component of the pathname. 137b819cea2SGordon Ross */ 138*54026d5aSGordon Ross if ((error = pn_getcomponent(pnp, component)) != 0) { 139b819cea2SGordon Ross goto bad; 140b819cea2SGordon Ross } 141b819cea2SGordon Ross 142b819cea2SGordon Ross /* 143b819cea2SGordon Ross * Handle "..": two special cases. 144b819cea2SGordon Ross * 1. If we're at the root directory (e.g. after chroot or 145b819cea2SGordon Ross * zone_enter) then change ".." to "." so we can't get 146b819cea2SGordon Ross * out of this subtree. 147b819cea2SGordon Ross * 2. If this vnode is the root of a mounted file system, 148b819cea2SGordon Ross * then replace it with the vnode that was mounted on 149b819cea2SGordon Ross * so that we take the ".." in the other file system. 150b819cea2SGordon Ross */ 151b819cea2SGordon Ross if (component[0] == '.' && component[1] == '.' && component[2] == 0) { 152b819cea2SGordon Ross checkforroot: 153b819cea2SGordon Ross if (VN_CMP(vp, rootvp)) { 154b819cea2SGordon Ross component[1] = '\0'; 155b819cea2SGordon Ross } else if (vp->v_flag & VROOT) { 156b819cea2SGordon Ross vfs_t *vfsp; 157b819cea2SGordon Ross cvp = vp; 158b819cea2SGordon Ross 159b819cea2SGordon Ross /* 160b819cea2SGordon Ross * While we deal with the vfs pointer from the vnode 161b819cea2SGordon Ross * the filesystem could have been forcefully unmounted 162b819cea2SGordon Ross * and the vnode's v_vfsp could have been invalidated 163b819cea2SGordon Ross * by VFS_UNMOUNT. Hence, we cache v_vfsp and use it 164b819cea2SGordon Ross * with vfs_rlock_wait/vfs_unlock. 165b819cea2SGordon Ross * It is safe to use the v_vfsp even it is freed by 166b819cea2SGordon Ross * VFS_UNMOUNT because vfs_rlock_wait/vfs_unlock 167b819cea2SGordon Ross * do not dereference v_vfsp. It is just used as a 168b819cea2SGordon Ross * magic cookie. 169b819cea2SGordon Ross * One more corner case here is the memory getting 170b819cea2SGordon Ross * reused for another vfs structure. In this case 171b819cea2SGordon Ross * lookuppnvp's vfs_rlock_wait will succeed, domount's 172b819cea2SGordon Ross * vfs_lock will fail and domount will bail out with an 173b819cea2SGordon Ross * error (EBUSY). 174b819cea2SGordon Ross */ 175b819cea2SGordon Ross vfsp = cvp->v_vfsp; 176b819cea2SGordon Ross 177b819cea2SGordon Ross /* 178b819cea2SGordon Ross * This lock is used to synchronize 179b819cea2SGordon Ross * mounts/unmounts and lookups. 180b819cea2SGordon Ross * Threads doing mounts/unmounts hold the 181b819cea2SGordon Ross * writers version vfs_lock_wait(). 182b819cea2SGordon Ross */ 183b819cea2SGordon Ross 184b819cea2SGordon Ross vfs_rlock_wait(vfsp); 185b819cea2SGordon Ross 186b819cea2SGordon Ross /* 187b819cea2SGordon Ross * If this vnode is on a file system that 188b819cea2SGordon Ross * has been forcibly unmounted, 189b819cea2SGordon Ross * we can't proceed. Cancel this operation 190b819cea2SGordon Ross * and return EIO. 191b819cea2SGordon Ross * 192b819cea2SGordon Ross * vfs_vnodecovered is NULL if unmounted. 193b819cea2SGordon Ross * Currently, nfs uses VFS_UNMOUNTED to 194b819cea2SGordon Ross * check if it's a forced-umount. Keep the 195b819cea2SGordon Ross * same checking here as well even though it 196b819cea2SGordon Ross * may not be needed. 197b819cea2SGordon Ross */ 198b819cea2SGordon Ross if (((vp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 199b819cea2SGordon Ross (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 200b819cea2SGordon Ross vfs_unlock(vfsp); 201b819cea2SGordon Ross VN_RELE(cvp); 202b819cea2SGordon Ross if (pp) 203b819cea2SGordon Ross pn_free(pp); 204b819cea2SGordon Ross return (EIO); 205b819cea2SGordon Ross } 206b819cea2SGordon Ross VN_HOLD(vp); 207b819cea2SGordon Ross vfs_unlock(vfsp); 208b819cea2SGordon Ross VN_RELE(cvp); 209b819cea2SGordon Ross cvp = NULL; 210b819cea2SGordon Ross /* 211b819cea2SGordon Ross * Crossing mount points. For eg: We are doing 212b819cea2SGordon Ross * a lookup of ".." for file systems root vnode 213b819cea2SGordon Ross * mounted here, and VOP_LOOKUP() (with covered vnode) 214b819cea2SGordon Ross * will be on underlying file systems mount point 215b819cea2SGordon Ross * vnode. Set retry_with_kcred flag as we might end 216b819cea2SGordon Ross * up doing VOP_LOOKUP() with kcred if required. 217b819cea2SGordon Ross */ 218b819cea2SGordon Ross retry_with_kcred = B_TRUE; 219b819cea2SGordon Ross goto checkforroot; 220b819cea2SGordon Ross } 221b819cea2SGordon Ross } 222b819cea2SGordon Ross 223b819cea2SGordon Ross /* 224b819cea2SGordon Ross * Perform a lookup in the current directory. 225b819cea2SGordon Ross */ 226b819cea2SGordon Ross error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags, 227b819cea2SGordon Ross rootvp, cr, NULL, NULL, pp); 228b819cea2SGordon Ross 229b819cea2SGordon Ross /* 230b819cea2SGordon Ross * Retry with kcred - If crossing mount points & error is EACCES. 231b819cea2SGordon Ross * 232b819cea2SGordon Ross * If we are crossing mount points here and doing ".." lookup, 233b819cea2SGordon Ross * VOP_LOOKUP() might fail if the underlying file systems 234b819cea2SGordon Ross * mount point has no execute permission. In cases like these, 235b819cea2SGordon Ross * we retry VOP_LOOKUP() by giving as much privilage as possible 236b819cea2SGordon Ross * by passing kcred credentials. 237b819cea2SGordon Ross * 238b819cea2SGordon Ross * In case of hierarchical file systems, passing kcred still may 239b819cea2SGordon Ross * or may not work. 240b819cea2SGordon Ross * For eg: UFS FS --> Mount NFS FS --> Again mount UFS on some 241b819cea2SGordon Ross * directory inside NFS FS. 242b819cea2SGordon Ross */ 243b819cea2SGordon Ross if ((error == EACCES) && retry_with_kcred) 244b819cea2SGordon Ross error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags, 245b819cea2SGordon Ross rootvp, zone_kcred(), NULL, NULL, pp); 246b819cea2SGordon Ross 247b819cea2SGordon Ross cvp = tvp; 248b819cea2SGordon Ross if (error) { 249b819cea2SGordon Ross cvp = NULL; 250b819cea2SGordon Ross /* 251b819cea2SGordon Ross * On error, return hard error if 252b819cea2SGordon Ross * (a) we're not at the end of the pathname yet, or 253b819cea2SGordon Ross * (b) the caller didn't want the parent directory, or 254b819cea2SGordon Ross * (c) we failed for some reason other than a missing entry. 255b819cea2SGordon Ross */ 256b819cea2SGordon Ross if (pn_pathleft(pnp) || dirvpp == NULL || error != ENOENT) 257b819cea2SGordon Ross goto bad; 258b819cea2SGordon Ross 259b819cea2SGordon Ross pn_setlast(pnp); 260b819cea2SGordon Ross /* 261b819cea2SGordon Ross * We inform the caller that the desired entry must be 262b819cea2SGordon Ross * a directory by adding a '/' to the component name. 263b819cea2SGordon Ross */ 264b819cea2SGordon Ross if (must_be_directory && (error = pn_addslash(pnp)) != 0) 265b819cea2SGordon Ross goto bad; 266b819cea2SGordon Ross *dirvpp = vp; 267b819cea2SGordon Ross if (compvpp != NULL) 268b819cea2SGordon Ross *compvpp = NULL; 269b819cea2SGordon Ross if (rootvp != rootdir) 270b819cea2SGordon Ross VN_RELE(rootvp); 271b819cea2SGordon Ross if (pp) 272b819cea2SGordon Ross pn_free(pp); 273b819cea2SGordon Ross return (0); 274b819cea2SGordon Ross } 275b819cea2SGordon Ross 276b819cea2SGordon Ross /* 277b819cea2SGordon Ross * Traverse mount points. 278b819cea2SGordon Ross */ 279b819cea2SGordon Ross if (vn_mountedvfs(cvp) != NULL) { 280b819cea2SGordon Ross tvp = cvp; 281b819cea2SGordon Ross if ((error = traverse(&tvp)) != 0) { 282b819cea2SGordon Ross /* 283b819cea2SGordon Ross * It is required to assign cvp here, because 284b819cea2SGordon Ross * traverse() will return a held vnode which 285b819cea2SGordon Ross * may different than the vnode that was passed 286b819cea2SGordon Ross * in (even in the error case). If traverse() 287b819cea2SGordon Ross * changes the vnode it releases the original, 288b819cea2SGordon Ross * and holds the new one. 289b819cea2SGordon Ross */ 290b819cea2SGordon Ross cvp = tvp; 291b819cea2SGordon Ross goto bad; 292b819cea2SGordon Ross } 293b819cea2SGordon Ross cvp = tvp; 294b819cea2SGordon Ross } 295b819cea2SGordon Ross 296b819cea2SGordon Ross /* 297b819cea2SGordon Ross * If we hit a symbolic link and there is more path to be 298b819cea2SGordon Ross * translated or this operation does not wish to apply 299b819cea2SGordon Ross * to a link, then place the contents of the link at the 300b819cea2SGordon Ross * front of the remaining pathname. 301b819cea2SGordon Ross */ 302b819cea2SGordon Ross if (cvp->v_type == VLNK && ((flags & FOLLOW) || pn_pathleft(pnp))) { 303b819cea2SGordon Ross struct pathname linkpath; 304b819cea2SGordon Ross 305b819cea2SGordon Ross if (++nlink > MAXSYMLINKS) { 306b819cea2SGordon Ross error = ELOOP; 307b819cea2SGordon Ross goto bad; 308b819cea2SGordon Ross } 309b819cea2SGordon Ross pn_alloc(&linkpath); 310*54026d5aSGordon Ross if ((error = pn_getsymlink(cvp, &linkpath, cr)) != 0) { 311b819cea2SGordon Ross pn_free(&linkpath); 312b819cea2SGordon Ross goto bad; 313b819cea2SGordon Ross } 314b819cea2SGordon Ross 315b819cea2SGordon Ross if (pn_pathleft(&linkpath) == 0) 316b819cea2SGordon Ross (void) pn_set(&linkpath, "."); 317b819cea2SGordon Ross error = pn_insert(pnp, &linkpath, strlen(component)); 318b819cea2SGordon Ross pn_free(&linkpath); 319b819cea2SGordon Ross if (error) 320b819cea2SGordon Ross goto bad; 321b819cea2SGordon Ross VN_RELE(cvp); 322b819cea2SGordon Ross cvp = NULL; 323b819cea2SGordon Ross if (pnp->pn_pathlen == 0) { 324b819cea2SGordon Ross error = ENOENT; 325b819cea2SGordon Ross goto bad; 326b819cea2SGordon Ross } 327b819cea2SGordon Ross if (pnp->pn_path[0] == '/') { 328b819cea2SGordon Ross do { 329b819cea2SGordon Ross pnp->pn_path++; 330b819cea2SGordon Ross pnp->pn_pathlen--; 331b819cea2SGordon Ross } while (pnp->pn_path[0] == '/'); 332b819cea2SGordon Ross VN_RELE(vp); 333b819cea2SGordon Ross vp = rootvp; 334b819cea2SGordon Ross VN_HOLD(vp); 335b819cea2SGordon Ross } 336b819cea2SGordon Ross if (pn_fixslash(pnp)) { 337b819cea2SGordon Ross flags |= FOLLOW; 338b819cea2SGordon Ross must_be_directory = 1; 339b819cea2SGordon Ross } 340b819cea2SGordon Ross goto next; 341b819cea2SGordon Ross } 342b819cea2SGordon Ross 343b819cea2SGordon Ross /* 344b819cea2SGordon Ross * If rpnp is non-NULL, remember the resolved path name therein. 345b819cea2SGordon Ross * Do not include "." components. Collapse occurrences of 346b819cea2SGordon Ross * "previous/..", so long as "previous" is not itself "..". 347b819cea2SGordon Ross * Exhausting rpnp results in error ENAMETOOLONG. 348b819cea2SGordon Ross */ 349b819cea2SGordon Ross if (rpnp && strcmp(component, ".") != 0) { 350b819cea2SGordon Ross size_t len; 351b819cea2SGordon Ross 352b819cea2SGordon Ross if (strcmp(component, "..") == 0 && 353b819cea2SGordon Ross rpnp->pn_pathlen != 0 && 354b819cea2SGordon Ross !((rpnp->pn_pathlen > 2 && 355b819cea2SGordon Ross strncmp(rpnp->pn_path+rpnp->pn_pathlen-3, "/..", 3) == 0) || 356b819cea2SGordon Ross (rpnp->pn_pathlen == 2 && 357b819cea2SGordon Ross strncmp(rpnp->pn_path, "..", 2) == 0))) { 358b819cea2SGordon Ross while (rpnp->pn_pathlen && 359b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen-1] != '/') 360b819cea2SGordon Ross rpnp->pn_pathlen--; 361b819cea2SGordon Ross if (rpnp->pn_pathlen > 1) 362b819cea2SGordon Ross rpnp->pn_pathlen--; 363b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen] = '\0'; 364b819cea2SGordon Ross } else { 365b819cea2SGordon Ross if (rpnp->pn_pathlen != 0 && 366b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen-1] != '/') 367b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen++] = '/'; 368b819cea2SGordon Ross if (flags & FIGNORECASE) { 369b819cea2SGordon Ross /* 370b819cea2SGordon Ross * Return the case-preserved name 371b819cea2SGordon Ross * within the resolved path. 372b819cea2SGordon Ross */ 373b819cea2SGordon Ross error = copystr(pp->pn_buf, 374b819cea2SGordon Ross rpnp->pn_path + rpnp->pn_pathlen, 375b819cea2SGordon Ross rpnp->pn_bufsize - rpnp->pn_pathlen, &len); 376b819cea2SGordon Ross } else { 377b819cea2SGordon Ross error = copystr(component, 378b819cea2SGordon Ross rpnp->pn_path + rpnp->pn_pathlen, 379b819cea2SGordon Ross rpnp->pn_bufsize - rpnp->pn_pathlen, &len); 380b819cea2SGordon Ross } 381b819cea2SGordon Ross if (error) /* copystr() returns ENAMETOOLONG */ 382b819cea2SGordon Ross goto bad; 383b819cea2SGordon Ross rpnp->pn_pathlen += (len - 1); 384b819cea2SGordon Ross ASSERT(rpnp->pn_bufsize > rpnp->pn_pathlen); 385b819cea2SGordon Ross } 386b819cea2SGordon Ross } 387b819cea2SGordon Ross 388b819cea2SGordon Ross /* 389b819cea2SGordon Ross * If no more components, return last directory (if wanted) and 390b819cea2SGordon Ross * last component (if wanted). 391b819cea2SGordon Ross */ 392b819cea2SGordon Ross if (pn_pathleft(pnp) == 0) { 393b819cea2SGordon Ross /* 394b819cea2SGordon Ross * If there was a trailing slash in the pathname, 395b819cea2SGordon Ross * make sure the last component is a directory. 396b819cea2SGordon Ross */ 397b819cea2SGordon Ross if (must_be_directory && cvp->v_type != VDIR) { 398b819cea2SGordon Ross error = ENOTDIR; 399b819cea2SGordon Ross goto bad; 400b819cea2SGordon Ross } 401b819cea2SGordon Ross if (dirvpp != NULL) { 402b819cea2SGordon Ross /* 403b819cea2SGordon Ross * Check that we have the real parent and not 404b819cea2SGordon Ross * an alias of the last component. 405b819cea2SGordon Ross */ 406b819cea2SGordon Ross if (vn_compare(vp, cvp)) { 407b819cea2SGordon Ross pn_setlast(pnp); 408b819cea2SGordon Ross VN_RELE(vp); 409b819cea2SGordon Ross VN_RELE(cvp); 410b819cea2SGordon Ross if (rootvp != rootdir) 411b819cea2SGordon Ross VN_RELE(rootvp); 412b819cea2SGordon Ross if (pp) 413b819cea2SGordon Ross pn_free(pp); 414b819cea2SGordon Ross return (EINVAL); 415b819cea2SGordon Ross } 416b819cea2SGordon Ross *dirvpp = vp; 417b819cea2SGordon Ross } else 418b819cea2SGordon Ross VN_RELE(vp); 419b819cea2SGordon Ross if (pnp->pn_path == pnp->pn_buf) 420b819cea2SGordon Ross (void) pn_set(pnp, "."); 421b819cea2SGordon Ross else 422b819cea2SGordon Ross pn_setlast(pnp); 423b819cea2SGordon Ross if (rpnp) { 424b819cea2SGordon Ross if (VN_CMP(cvp, rootvp)) 425b819cea2SGordon Ross (void) pn_set(rpnp, "/"); 426b819cea2SGordon Ross else if (rpnp->pn_pathlen == 0) 427b819cea2SGordon Ross (void) pn_set(rpnp, "."); 428b819cea2SGordon Ross } 429b819cea2SGordon Ross 430b819cea2SGordon Ross if (compvpp != NULL) 431b819cea2SGordon Ross *compvpp = cvp; 432b819cea2SGordon Ross else 433b819cea2SGordon Ross VN_RELE(cvp); 434b819cea2SGordon Ross if (rootvp != rootdir) 435b819cea2SGordon Ross VN_RELE(rootvp); 436b819cea2SGordon Ross if (pp) 437b819cea2SGordon Ross pn_free(pp); 438b819cea2SGordon Ross return (0); 439b819cea2SGordon Ross } 440b819cea2SGordon Ross 441b819cea2SGordon Ross /* 442b819cea2SGordon Ross * Skip over slashes from end of last component. 443b819cea2SGordon Ross */ 444b819cea2SGordon Ross while (pnp->pn_path[0] == '/') { 445b819cea2SGordon Ross pnp->pn_path++; 446b819cea2SGordon Ross pnp->pn_pathlen--; 447b819cea2SGordon Ross } 448b819cea2SGordon Ross 449b819cea2SGordon Ross /* 450b819cea2SGordon Ross * Searched through another level of directory: 451b819cea2SGordon Ross * release previous directory handle and save new (result 452b819cea2SGordon Ross * of lookup) as current directory. 453b819cea2SGordon Ross */ 454b819cea2SGordon Ross VN_RELE(vp); 455b819cea2SGordon Ross vp = cvp; 456b819cea2SGordon Ross cvp = NULL; 457b819cea2SGordon Ross goto next; 458b819cea2SGordon Ross 459b819cea2SGordon Ross bad: 460b819cea2SGordon Ross /* 461b819cea2SGordon Ross * Error. Release vnodes and return. 462b819cea2SGordon Ross */ 463b819cea2SGordon Ross if (cvp) 464b819cea2SGordon Ross VN_RELE(cvp); 465b819cea2SGordon Ross /* 466b819cea2SGordon Ross * If the error was ESTALE and the current directory to look in 467b819cea2SGordon Ross * was the root for this lookup, the root for a mounted file 468b819cea2SGordon Ross * system, or the starting directory for lookups, then 469b819cea2SGordon Ross * return ENOENT instead of ESTALE. In this case, no recovery 470b819cea2SGordon Ross * is possible by the higher level. If ESTALE was returned for 471b819cea2SGordon Ross * some intermediate directory along the path, then recovery 472b819cea2SGordon Ross * is potentially possible and retrying from the higher level 473b819cea2SGordon Ross * will either correct the situation by purging stale cache 474b819cea2SGordon Ross * entries or eventually get back to the point where no recovery 475b819cea2SGordon Ross * is possible. 476b819cea2SGordon Ross */ 477b819cea2SGordon Ross if (error == ESTALE && 478b819cea2SGordon Ross (VN_CMP(vp, rootvp) || (vp->v_flag & VROOT) || vp == startvp)) 479b819cea2SGordon Ross error = ENOENT; 480b819cea2SGordon Ross VN_RELE(vp); 481b819cea2SGordon Ross if (rootvp != rootdir) 482b819cea2SGordon Ross VN_RELE(rootvp); 483b819cea2SGordon Ross if (pp) 484b819cea2SGordon Ross pn_free(pp); 485b819cea2SGordon Ross return (error); 486b819cea2SGordon Ross } 487b819cea2SGordon Ross 488b819cea2SGordon Ross /* 489b819cea2SGordon Ross * Traverse a mount point. Routine accepts a vnode pointer as a reference 490b819cea2SGordon Ross * parameter and performs the indirection, releasing the original vnode. 491b819cea2SGordon Ross */ 492b819cea2SGordon Ross int 493b819cea2SGordon Ross traverse(vnode_t **cvpp) 494b819cea2SGordon Ross { 495b819cea2SGordon Ross int error = 0; 496b819cea2SGordon Ross vnode_t *cvp; 497b819cea2SGordon Ross vnode_t *tvp; 498b819cea2SGordon Ross vfs_t *vfsp; 499b819cea2SGordon Ross 500b819cea2SGordon Ross cvp = *cvpp; 501b819cea2SGordon Ross 502b819cea2SGordon Ross /* 503b819cea2SGordon Ross * If this vnode is mounted on, then we transparently indirect 504b819cea2SGordon Ross * to the vnode which is the root of the mounted file system. 505b819cea2SGordon Ross * Before we do this we must check that an unmount is not in 506b819cea2SGordon Ross * progress on this vnode. 507b819cea2SGordon Ross */ 508b819cea2SGordon Ross 509b819cea2SGordon Ross for (;;) { 510b819cea2SGordon Ross /* 511b819cea2SGordon Ross * Used to try to read lock the vnode here. 512b819cea2SGordon Ross */ 513b819cea2SGordon Ross 514b819cea2SGordon Ross /* 515b819cea2SGordon Ross * Reached the end of the mount chain? 516b819cea2SGordon Ross */ 517b819cea2SGordon Ross vfsp = vn_mountedvfs(cvp); 518b819cea2SGordon Ross if (vfsp == NULL) { 519b819cea2SGordon Ross break; 520b819cea2SGordon Ross } 521b819cea2SGordon Ross 522b819cea2SGordon Ross /* 523b819cea2SGordon Ross * The read lock must be held across the call to VFS_ROOT() to 524b819cea2SGordon Ross * prevent a concurrent unmount from destroying the vfs. 525b819cea2SGordon Ross */ 526b819cea2SGordon Ross error = VFS_ROOT(vfsp, &tvp); 527b819cea2SGordon Ross if (error) 528b819cea2SGordon Ross break; 529b819cea2SGordon Ross 530b819cea2SGordon Ross VN_RELE(cvp); 531b819cea2SGordon Ross 532b819cea2SGordon Ross cvp = tvp; 533b819cea2SGordon Ross } 534b819cea2SGordon Ross 535b819cea2SGordon Ross *cvpp = cvp; 536b819cea2SGordon Ross return (error); 537b819cea2SGordon Ross } 538b819cea2SGordon Ross 539b819cea2SGordon Ross /* 540b819cea2SGordon Ross * Get the vnode path, relative to the passed rootvp. 541b819cea2SGordon Ross * Our vncache always fills in v_path, so this is easy. 542b819cea2SGordon Ross */ 543b819cea2SGordon Ross /* ARGSUSED */ 544b819cea2SGordon Ross int 545b819cea2SGordon Ross vnodetopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr) 546b819cea2SGordon Ross { 547b819cea2SGordon Ross int len, rvp_len = 0; 548b819cea2SGordon Ross const char *p = vp->v_path; 549b819cea2SGordon Ross 550b819cea2SGordon Ross if (vrootp) 551b819cea2SGordon Ross rvp_len = strlen(vrootp->v_path); 552b819cea2SGordon Ross len = strlen(p); 553b819cea2SGordon Ross if (rvp_len < len) 554b819cea2SGordon Ross p += rvp_len; 555b819cea2SGordon Ross else 556b819cea2SGordon Ross p = "/"; 557b819cea2SGordon Ross 558b819cea2SGordon Ross (void) strlcpy(buf, p, buflen); 559b819cea2SGordon Ross return (0); 560b819cea2SGordon Ross } 561