|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* ! 25: * Copyright (c) 1989, 1993 ! 26: * The Regents of the University of California. All rights reserved. ! 27: * (c) UNIX System Laboratories, Inc. ! 28: * All or some portions of this file are derived from material licensed ! 29: * to the University of California by American Telephone and Telegraph ! 30: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 31: * the permission of UNIX System Laboratories, Inc. ! 32: * ! 33: * Redistribution and use in source and binary forms, with or without ! 34: * modification, are permitted provided that the following conditions ! 35: * are met: ! 36: * 1. Redistributions of source code must retain the above copyright ! 37: * notice, this list of conditions and the following disclaimer. ! 38: * 2. Redistributions in binary form must reproduce the above copyright ! 39: * notice, this list of conditions and the following disclaimer in the ! 40: * documentation and/or other materials provided with the distribution. ! 41: * 3. All advertising materials mentioning features or use of this software ! 42: * must display the following acknowledgement: ! 43: * This product includes software developed by the University of ! 44: * California, Berkeley and its contributors. ! 45: * 4. Neither the name of the University nor the names of its contributors ! 46: * may be used to endorse or promote products derived from this software ! 47: * without specific prior written permission. ! 48: * ! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 59: * SUCH DAMAGE. ! 60: * ! 61: * @(#)hfs_lookup.c 1.0 ! 62: * derived from @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 ! 63: * ! 64: * (c) 1998 Apple Computer, Inc. All Rights Reserved ! 65: * (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved ! 66: * ! 67: * ! 68: * hfs_lookup.c -- code to handle directory traversal on HFS/HFS+ volume ! 69: * ! 70: * MODIFICATION HISTORY: ! 71: * 25-Feb-1999 Clark Warner Fixed the error case of VFS_VGGET when ! 72: * processing DotDot (..) to relock parent ! 73: * 23-Feb-1999 Pat Dirks Finish cleanup around Don's last fix in "." and ".." handling. ! 74: * 11-Nov-1998 Don Brady Take out VFS_VGET that got added as part of previous fix. ! 75: * 14-Oct-1998 Don Brady Fix locking policy volation in hfs_lookup for ".." case ! 76: * (radar #2279902). ! 77: * 4-Jun-1998 Pat Dirks Split off from hfs_vnodeops.c ! 78: */ ! 79: ! 80: #include <sys/param.h> ! 81: #include <sys/systm.h> ! 82: #include <sys/resourcevar.h> ! 83: #include <sys/kernel.h> ! 84: #include <sys/file.h> ! 85: #include <sys/stat.h> ! 86: #include <sys/buf.h> ! 87: #include <sys/proc.h> ! 88: #include <sys/conf.h> ! 89: #include <sys/mount.h> ! 90: #include <mach/machine/vm_types.h> ! 91: #include <sys/vnode.h> ! 92: //#include <sys/vnode_if.h> ! 93: #include <sys/malloc.h> ! 94: #include <sys/namei.h> ! 95: #include <sys/signalvar.h> ! 96: #include <sys/uio.h> ! 97: #include <sys/time.h> ! 98: #include <sys/attr.h> ! 99: #include <miscfs/specfs/specdev.h> ! 100: ! 101: #include <sys/vm.h> ! 102: #include <libkern/libkern.h> ! 103: #include <mach/machine/simple_lock.h> ! 104: #include <machine/spl.h> ! 105: ! 106: #include "hfs.h" ! 107: #include "hfs_dbg.h" ! 108: #include "hfscommon/headers/FileMgrInternal.h" ! 109: #include "hfscommon/headers/CatalogPrivate.h" ! 110: ! 111: extern void cache_purge (struct vnode *vp); ! 112: extern int cache_lookup (struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); ! 113: extern void cache_enter (struct vnode *dvp, struct vnode *vpp, struct componentname *cnp); ! 114: ! 115: #if DBG_VOP_TEST_LOCKS ! 116: extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, char *funcname); ! 117: #endif ! 118: ! 119: /***************************************************************************** ! 120: * ! 121: * Operations on vnodes ! 122: * ! 123: *****************************************************************************/ ! 124: ! 125: /* From FreeBSD 2.2 MSDOS_LOOKUP ! 126: * When we search a directory the blocks containing directory entries are ! 127: * read and examined. The directory entries contain information that would ! 128: * normally be in the hfsnode of a unix filesystem. This means that some of ! 129: * a directory's contents may also be in memory resident denodes (sort of ! 130: * an hfsnode). This can cause problems if we are searching while some other ! 131: * process is modifying a directory. To prevent one process from accessing ! 132: * incompletely modified directory information we depend upon being the ! 133: * soul owner of a directory block. bread/brelse provide this service. ! 134: * This being the case, when a process modifies a directory it must first ! 135: * acquire the disk block that contains the directory entry to be modified. ! 136: * Then update the disk block and the denode, and then write the disk block ! 137: * out to disk. This way disk blocks containing directory entries and in ! 138: * memory denode's will be in synch. ! 139: */ ! 140: ! 141: /* FROM UNIX 63 ! 142: * Convert a component of a pathname into a pointer to a locked hfsnode. ! 143: * This is a very central and rather complicated routine. ! 144: * If the file system is not maintained in a strict tree hierarchy, ! 145: * this can result in a deadlock situation (see comments in code below). ! 146: * ! 147: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on ! 148: * whether the name is to be looked up, created, renamed, or deleted. ! 149: * When CREATE, RENAME, or DELETE is specified, information usable in ! 150: * creating, renaming, or deleting a directory entry may be calculated. ! 151: * If flag has LOCKPARENT or'ed into it, the parent directory is returned ! 152: * locked. If flag has WANTPARENT or'ed into it, the parent directory is ! 153: * returned unlocked. Otherwise the parent directory is not returned. If ! 154: * the target of the pathname exists and LOCKLEAF is or'ed into the flag ! 155: * the target is returned locked, otherwise it is returned unlocked. ! 156: * When creating or renaming and LOCKPARENT is specified, the target may not ! 157: * be ".". When deleting and LOCKPARENT is specified, the target may be ".". ! 158: * ! 159: * Overall outline of hfs_lookup: ! 160: * ! 161: * check accessibility of directory ! 162: * look for name in cache, if found, then if at end of path ! 163: * and deleting or creating, drop it, else return name ! 164: * search for name in directory, to found or notfound ! 165: * DoesntExist: ! 166: * if creating, return locked directory, leaving info on available slots ! 167: * else return retval ! 168: * Exists: ! 169: * if at end of path and deleting, return information to allow delete ! 170: * if at end of path and rewriting (RENAME and LOCKPARENT), lock target ! 171: * hfsnode and return info to allow rewrite ! 172: * if not at end, add name to cache; if at end and neither creating ! 173: * nor deleting, add name to cache ! 174: * ! 175: * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent hfsnode unlocked. ! 176: */ ! 177: ! 178: /* ! 179: * Lookup *nm in directory *pvp, return it in *a_vpp. ! 180: * **a_vpp is held on exit. ! 181: * We create a hfsnode for the file, but we do NOT open the file here. ! 182: ! 183: #% lookup dvp L ? ? ! 184: #% lookup vpp - L - ! 185: ! 186: IN struct vnode *dvp - Parent node of file; ! 187: INOUT struct vnode **vpp - node of target file, its a new node if the target vnode did not exist; ! 188: IN struct componentname *cnp - Name of file; ! 189: ! 190: * When should we lock parent_hp in here ?? ! 191: */ ! 192: ! 193: int ! 194: hfs_lookup(ap) ! 195: struct vop_lookup_args /* { ! 196: struct vnode *a_dvp; ! 197: struct vnode **a_vpp; ! 198: struct componentname *a_cnp; ! 199: } */ *ap; ! 200: { ! 201: struct vnode *parent_vp; ! 202: struct vnode *target_vp; ! 203: struct vnode *tparent_vp; ! 204: struct hfsnode *parent_hp; /* parent */ ! 205: struct hfsnode *target_hp; /* target */ ! 206: struct hfsmount *parent_hfs; ! 207: struct componentname *cnp; ! 208: struct ucred *cred; ! 209: struct proc *p; ! 210: struct hfsCatalogInfo catInfo; ! 211: u_long parent_id; ! 212: u_long lockparent; /* !0 => lockparent flag is set */ ! 213: u_long wantparent; /* !0 => wantparent or lockparent flag */ ! 214: u_short targetLen; ! 215: int nameiop; ! 216: int retval; ! 217: u_char isDot, isDotDot; ! 218: UInt32 nodeID; ! 219: UInt16 forkType; ! 220: DBG_FUNC_NAME("lookup"); ! 221: DBG_VOP_LOCKS_DECL(2); ! 222: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); ! 223: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); ! 224: DBG_VOP_PRINT_FUNCNAME(); ! 225: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);DBG_VOP_CONT(("\n")); ! 226: DBG_VOP_PRINT_FUNCNAME(); ! 227: DBG_VOP_CONT(("\tTarget: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 228: DBG_HFS_NODE_CHECK(ap->a_dvp); ! 229: DBG_ASSERT(ap->a_dvp!=NULL); ! 230: ! 231: ! 232: /* ! 233: * Do initial setup ! 234: */ ! 235: parent_vp = ap->a_dvp; ! 236: cnp = ap->a_cnp; ! 237: parent_hp = VTOH(parent_vp); /* parent */ ! 238: target_vp = NULL; ! 239: parent_hfs = VTOHFS(parent_vp); ! 240: targetLen = cnp->cn_namelen; ! 241: nameiop = cnp->cn_nameiop; ! 242: cred = cnp->cn_cred; ! 243: p = cnp->cn_proc; ! 244: lockparent = cnp->cn_flags & LOCKPARENT; ! 245: wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT); ! 246: parent_id = H_FILEID(parent_hp); ! 247: nodeID = kUnknownID; ! 248: isDot = FALSE; ! 249: isDotDot = cnp->cn_flags & ISDOTDOT; ! 250: catInfo.hint = 0; ! 251: retval = E_NONE; ! 252: forkType = kDirCmplx; ! 253: ! 254: ! 255: /* ! 256: * Check accessiblity of directory. ! 257: */ ! 258: if ((parent_vp->v_type != VDIR) && (parent_vp->v_type != VCPLX)) { ! 259: DBG_ERR(("%s: Parent VNode '%s' is not a directory, its %d\n",funcname, H_NAME(parent_hp), parent_vp->v_type)); ! 260: retval = ENOTDIR; ! 261: goto Err_Exit; ! 262: }; ! 263: ! 264: /* ! 265: * Check accessiblity of directory. Only if it is non complex, since it would of been checked ! 266: * when looking up the complex node. The 'first' lookup's parent should alsways be a directory ! 267: */ ! 268: if ((parent_vp->v_type != VCPLX) && ((retval = VOP_ACCESS(parent_vp, VEXEC, cred, p)) != E_NONE)) { ! 269: DBG_ERR(("%s: No acces to parent %s, %s\n",funcname, H_NAME(parent_hp), ap->a_cnp->cn_nameptr)); ! 270: goto Err_Exit; ! 271: }; ! 272: ! 273: /* Check for accessibility of the file...is this a read-only volume */ ! 274: if ((cnp->cn_flags & ISLASTCN) && (VTOVFS(parent_vp)->mnt_flag & MNT_RDONLY) && ! 275: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { ! 276: DBG_ERR(("%s: Invalid cn_nameiop for read-only volume %s, %s\n",funcname, H_NAME(parent_hp), ap->a_cnp->cn_nameptr)); ! 277: retval = EROFS; ! 278: goto Err_Exit; ! 279: }; ! 280: ! 281: /* ! 282: * We now have a segment name to search for, and a directory to search. ! 283: * ! 284: * Before tediously performing a linear scan of the directory, ! 285: * check the name cache to see if the directory/name pair ! 286: * we are looking for is known already. ! 287: */ ! 288: retval = cache_lookup(parent_vp, &target_vp, cnp); ! 289: if (retval != E_NONE) { ! 290: u_long vpid; /* capability number of vnode */ ! 291: ! 292: DBG_VOP(("\tFound in name cache: ")); ! 293: if (retval == ENOENT) { ! 294: DBG_VOP_CONT((" As a non-entry\n")); ! 295: goto Err_Exit; ! 296: } ! 297: DBG_VOP_PRINT_VNODE_INFO(target_vp);DBG_VOP_CONT(("\n")); ! 298: /* ! 299: * Get the next vnode in the path. ! 300: * See comment below starting `Step through' for ! 301: * an explaination of the locking protocol. ! 302: */ ! 303: tparent_vp = parent_vp; ! 304: parent_vp = target_vp; ! 305: vpid = target_vp->v_id; ! 306: if (tparent_vp == parent_vp) { /* Lookup on '.' */ ! 307: VREF(parent_vp); ! 308: retval = E_NONE; ! 309: } else if (cnp->cn_flags & ISDOTDOT) { /* If getting our parent */ ! 310: VOP_UNLOCK(tparent_vp, 0, p); ! 311: retval = vget(parent_vp, LK_EXCLUSIVE, p); ! 312: if (!retval && lockparent && (cnp->cn_flags & ISLASTCN)) ! 313: retval = vn_lock(tparent_vp, LK_EXCLUSIVE, p); ! 314: } else { ! 315: retval = vget(parent_vp, LK_EXCLUSIVE, p); ! 316: if ((!retval) && (parent_vp->v_type == VCPLX) && (cnp->cn_flags & ISLASTCN)) { ! 317: target_vp = VTOH(parent_vp)->h_relative; ! 318: VPUT(parent_vp); ! 319: if (target_vp == NULL) { ! 320: parent_vp = tparent_vp; ! 321: goto Skip_NameCache; ! 322: } ! 323: parent_vp = target_vp; /* do the 'skipping' */ ! 324: vpid = parent_vp->v_id; ! 325: retval = vget(parent_vp, LK_EXCLUSIVE, p); ! 326: }; ! 327: if (!lockparent || retval || !(cnp->cn_flags & ISLASTCN)) ! 328: VOP_UNLOCK(tparent_vp, 0, p); ! 329: }; ! 330: ! 331: /* ! 332: * Check that the node number did not change ! 333: * while we were waiting for the lock. ! 334: */ ! 335: if (retval == E_NONE) { ! 336: if (vpid == parent_vp->v_id) { ! 337: goto Err_Exit; /* Did not change, Success! We have the node..we are finished */ ! 338: }; ! 339: ! 340: VPUT(parent_vp); ! 341: if (lockparent && tparent_vp != parent_vp && (cnp->cn_flags & ISLASTCN)) ! 342: VOP_UNLOCK(tparent_vp, 0, p); ! 343: }; ! 344: ! 345: retval = vn_lock(tparent_vp, LK_EXCLUSIVE, p); ! 346: if (retval) goto Err_Exit; ! 347: ! 348: parent_vp = tparent_vp; ! 349: target_vp = NULL; ! 350: }; ! 351: ! 352: Skip_NameCache: ; ! 353: ! 354: ! 355: /* ! 356: * Trivial cases for current and parent directories ! 357: */ ! 358: if(cnp->cn_nameptr[0] == (char)'.') { ! 359: /* . */ ! 360: if(targetLen == 1) { /* self */ ! 361: target_vp = parent_vp; ! 362: nodeID = H_FILEID(parent_hp); ! 363: isDot = TRUE; ! 364: catInfo.nodeData.nodeType = kCatalogFolderNode; ! 365: goto Exists; ! 366: }; ! 367: ! 368: /* .. */ ! 369: if((cnp->cn_nameptr[1] == '.') && (targetLen == 2)) { /* parent */ ! 370: isDotDot = TRUE; /* XXX Make doubly-sure this is set for now */ ! 371: nodeID = H_DIRID(parent_hp); ! 372: VOP_UNLOCK(parent_vp, 0, p); ! 373: retval = VFS_VGET(HTOVFS(parent_hp), &nodeID, &target_vp); ! 374: if (retval) { ! 375: vn_lock(parent_vp, LK_EXCLUSIVE | LK_RETRY, p); ! 376: goto Err_Exit; ! 377: } ! 378: ! 379: if (lockparent && (cnp->cn_flags & ISLASTCN)) { ! 380: retval = vn_lock(parent_vp, LK_EXCLUSIVE, p); ! 381: if (retval) { ! 382: VPUT(target_vp); ! 383: goto Err_Exit; ! 384: } ! 385: } ! 386: ! 387: if (target_vp == NULL) { ! 388: DBG_ERR(("%s: VFS_VGET FAILED on getting dir %ld: %d\n",funcname, H_DIRID(parent_hp), retval)); ! 389: goto Err_Exit; ! 390: } else { ! 391: target_hp = VTOH(target_vp); ! 392: nodeID = H_FILEID(target_hp); ! 393: catInfo.nodeData.nodeType = kCatalogFolderNode; ! 394: goto Exists; ! 395: }; ! 396: }; ! 397: }; ! 398: ! 399: ! 400: /* ! 401: * The file is not in the cache, nor is it a dot (or dot-dot), so do a hfs lookup ! 402: */ ! 403: ! 404: /* lock catalog b-tree */ ! 405: retval = hfs_metafilelocking(parent_hfs, kHFSCatalogFileID, LK_SHARED, p); /*XXX p might be wrongone! */ ! 406: if (retval) ! 407: goto Err_Exit; ! 408: ! 409: if (parent_vp->v_type == VCPLX) { ! 410: retval = hfsLookup (HFSTOVCB(parent_hfs), H_DIRID(parent_hp), H_NAME(parent_hp), -1, H_HINT(parent_hp), &catInfo); ! 411: } ! 412: else { ! 413: retval = hfsLookup (HFSTOVCB(parent_hfs), parent_id, cnp->cn_nameptr, targetLen, kNoHint, &catInfo); ! 414: } ! 415: ! 416: /* unlock catalog b-tree */ ! 417: (void) hfs_metafilelocking(parent_hfs, kHFSCatalogFileID, LK_RELEASE, p); ! 418: ! 419: nodeID = catInfo.nodeData.nodeID; ! 420: if (retval == E_NONE) { ! 421: goto Exists; ! 422: } else { ! 423: goto DoesntExist; ! 424: }; ! 425: ! 426: ! 427: DoesntExist: ; ! 428: ! 429: /* ! 430: * If we get here we didn't find the entry we were looking for. But ! 431: * that's ok if we are creating or renaming and are at the end of ! 432: * the pathname and the directory hasn't been removed. ! 433: */ ! 434: retval = E_NONE; ! 435: if ((nameiop == CREATE || nameiop == RENAME) && (cnp->cn_flags & ISLASTCN)) { ! 436: retval = VOP_ACCESS(parent_vp, VWRITE, cred, p); ! 437: if (retval) ! 438: goto Err_Exit; ! 439: ! 440: cnp->cn_flags |= SAVENAME; ! 441: if (!lockparent)/* leave searched dir locked? */ ! 442: VOP_UNLOCK(parent_vp, 0, p); ! 443: retval = EJUSTRETURN; ! 444: goto Err_Exit; ! 445: } ! 446: ! 447: /* ! 448: * XXX SER - Here we would store the name in cache as non-existant if not trying to create it, but, ! 449: * the name cache IS case-sensitive, thus maybe showing a negative hit, when the name ! 450: * is only different by case. So hfs does not support negative caching. Something to look at. ! 451: * (See radar 2293594 for a failed example) ! 452: */ ! 453: ! 454: retval = ENOENT; ! 455: goto Err_Exit; ! 456: ! 457: ! 458: Exists: ; ! 459: ! 460: DBG_ASSERT(nodeID != kUnknownID); ! 461: retval = E_NONE; ! 462: ! 463: if (target_vp) { ! 464: forkType = H_FORKTYPE(VTOH(target_vp)); ! 465: } else { ! 466: /* ! 467: * Here we have to decide what type of vnode to create ! 468: * If the parent is a directory, then the child can be one of four types: ! 469: * 1. VDIR, nodeType is kCatalogFolderNode, forkType will be kDirCmplx ! 470: * 2. VLINK, nodeType is kCatalogFileNode, forkType will be kDataFork ! 471: * 3. VREG, nodeType is kCatalogFileNode, forkType will be kDataFork ! 472: * 4. VCPLX, nodeType is kCatalogFileNode, forkType will be kDirCmplx ! 473: * To determine which of the latter three, we can use this algorithm: ! 474: * a. VREG iff ISLASTCN is set (as in the case of the default fork e.g. data/foo). ! 475: * b. VLINK iff the mode is IFLNK (esp. if it is a link to a directory e.g. bar/link/foo) ! 476: * c. VCPLX iff it is followed by a valid fork name. (foo/data) ! 477: * If the parent is a complex, then the child must have a valid fork name ! 478: */ ! 479: ! 480: if (parent_vp->v_type == VDIR) { ! 481: if (catInfo.nodeData.nodeType == kCatalogFolderNode) ! 482: forkType = kDirCmplx; ! 483: else if ((cnp->cn_flags & ISLASTCN) || ((catInfo.nodeData.permissions.permissions & IFMT)==IFLNK)) { ! 484: forkType = kDataFork; /* The defualt */ ! 485: //cnp->cn_flags &= ~MAKEENTRY; ! 486: } ! 487: else ! 488: forkType = kDirCmplx; /* complex */ ! 489: } ! 490: else if (parent_vp->v_type == VCPLX) { ! 491: if (! strcmp(cnp->cn_nameptr, kDataForkNameStr)) ! 492: forkType = kDataFork; ! 493: else if (! strcmp(cnp->cn_nameptr, kRsrcForkNameStr)) ! 494: forkType = kRsrcFork; ! 495: else { ! 496: if (!lockparent) /* leave parent dir locked? */ ! 497: VOP_UNLOCK(parent_vp, 0, p); ! 498: DBG_ERR(("%s: Searching for an illegal fork: %s\n", funcname, cnp->cn_nameptr)); ! 499: retval = ENOENT; ! 500: goto Err_Exit; ! 501: } ! 502: } ! 503: else ! 504: panic("Unexpected parent type for lookup"); ! 505: DBG_VOP(("\tExists: Parent v_type:%d, forkType:%d, target nodeType:0x%x\n", parent_vp->v_type, forkType, (u_int)catInfo.nodeData.nodeType)); ! 506: }; ! 507: ! 508: ! 509: /* ! 510: * If deleting and at the end of the path, then if we matched on ! 511: * "." then don't hfsget() Otherwise ! 512: * hfsget() the directory entry. ! 513: */ ! 514: /* ! 515: * If deleting, and at end of pathname, return ! 516: * parameters which can be used to remove file. ! 517: * If the wantparent flag isn't set, we return only ! 518: * the directory (in ndp->ndvp), otherwise we go ! 519: * on and lock the hfsnode, being careful with ".". ! 520: */ ! 521: if (nameiop == DELETE && (cnp->cn_flags & ISLASTCN)) { ! 522: /* ! 523: * Write access to directory required to delete files. ! 524: */ ! 525: retval = VOP_ACCESS(parent_vp, VWRITE, cred, p); ! 526: if (retval) ! 527: goto Err_Exit; ! 528: ! 529: if (isDot) { ! 530: VREF(parent_vp); ! 531: target_vp = parent_vp; ! 532: goto Err_Exit; ! 533: } ! 534: else if (target_vp == NULL) { ! 535: target_vp = hfs_vhashget(parent_hp->h_dev, nodeID, forkType); ! 536: if (target_vp == NULL) ! 537: retval = hfsGet (HTOVCB(parent_hp), &catInfo, forkType, parent_vp, &target_vp); ! 538: if (retval != E_NONE) ! 539: goto Err_Exit; ! 540: } ! 541: /* ! 542: * If directory is "sticky", then user must own ! 543: * the directory, or the file in it, else she ! 544: * may not delete it (unless she's root). This ! 545: * implements append-only directories. ! 546: */ ! 547: if ((parent_hp->h_meta->h_mode & ISVTX) && ! 548: cred->cr_uid != 0 && ! 549: cred->cr_uid != parent_hp->h_meta->h_uid && ! 550: target_vp->v_type != VLNK && ! 551: VTOH(target_vp)->h_meta->h_uid != cred->cr_uid) { ! 552: VPUT(target_vp); ! 553: retval = EPERM; ! 554: goto Err_Exit; ! 555: } ! 556: ! 557: if (!lockparent && !isDotDot) ! 558: VOP_UNLOCK(parent_vp, 0, p); ! 559: goto Err_Exit; ! 560: }; ! 561: ! 562: /* ! 563: * If rewriting 'RENAME', return the hfsnode and the ! 564: * information required to rewrite the present directory ! 565: */ ! 566: if (nameiop == RENAME && wantparent && (cnp->cn_flags & ISLASTCN)) { ! 567: ! 568: /* cant change root */ ! 569: if ((parent_id == kRootDirID) && isDot) { ! 570: retval = EISDIR; ! 571: goto Err_Exit; ! 572: }; ! 573: ! 574: if (target_vp == NULL) { ! 575: ! 576: /* Make sure that this is the correct name ie. same case */ ! 577: if (strncmp(cnp->cn_nameptr, catInfo.spec.name, targetLen)) { ! 578: if (!lockparent)/* leave searched dir locked? */ ! 579: VOP_UNLOCK(parent_vp, 0, p); ! 580: retval = EJUSTRETURN; ! 581: goto Err_Exit; ! 582: }; ! 583: ! 584: /* Create the vnode, looking in the cache first */ ! 585: target_vp = hfs_vhashget(parent_hp->h_dev, nodeID, forkType); ! 586: if (target_vp == NULL) ! 587: retval = hfsGet (HTOVCB(parent_hp), &catInfo, forkType, parent_vp, &target_vp); ! 588: if (retval != E_NONE) ! 589: goto Err_Exit; ! 590: }; ! 591: ! 592: if (!lockparent && !isDotDot) VOP_UNLOCK(parent_vp, 0, p); ! 593: cnp->cn_flags |= SAVENAME; ! 594: goto Err_Exit; ! 595: /* Finished...all is well, goto the end */ ! 596: }; ! 597: ! 598: /* ! 599: * Step through the translation in the name. We do not `vput' the ! 600: * directory because we may need it again if a symbolic link ! 601: * is relative to the current directory. Instead we save it ! 602: * unlocked as "tparent_vp". We must get the target hfsnode before unlocking ! 603: * the directory to insure that the hfsnode will not be removed ! 604: * before we get it. We prevent deadlock by always fetching ! 605: * inodes from the root, moving down the directory tree. Thus ! 606: * when following backward pointers ".." we must unlock the ! 607: * parent directory before getting the requested directory. ! 608: * There is a potential race condition here if both the current ! 609: * and parent directories are removed before the VFS_VGET for the ! 610: * hfsnode associated with ".." returns. We hope that this occurs ! 611: * infrequently since we cannot avoid this race condition without ! 612: * implementing a sophisticated deadlock detection algorithm. ! 613: * Note also that this simple deadlock detection scheme will not ! 614: * work if the file system has any hard links other than ".." ! 615: * that point backwards in the directory structure. ! 616: */ ! 617: ! 618: tparent_vp = parent_vp; ! 619: if (cnp->cn_flags & ISDOTDOT) { ! 620: #if 0 ! 621: VOP_UNLOCK(tparent_vp, 0, p); ! 622: /* radar #2286192 ! 623: * UFS does a VFS_VGET here but the code below is causing a hang so ! 624: * I'm taking it back out for now - DJB ! 625: */ ! 626: if ((retval = VFS_VGET(parent_vp->v_mount, &H_FILEID(parent_hp), &target_vp))) { ! 627: vn_lock(tparent_vp, LK_EXCLUSIVE | LK_RETRY, p); ! 628: goto Err_Exit; ! 629: } ! 630: if (lockparent && (cnp->cn_flags & ISLASTCN) ! 631: && (retval = vn_lock(tparent_vp, LK_EXCLUSIVE | LK_RETRY, p))) { ! 632: VPUT(target_vp); ! 633: goto Err_Exit; ! 634: } ! 635: #endif ! 636: } else if (isDot) { /* "." */ ! 637: VREF(parent_vp); ! 638: target_vp = parent_vp; ! 639: } else { ! 640: if (target_vp == NULL) ! 641: target_vp = hfs_vhashget(parent_hp->h_dev, nodeID, forkType); ! 642: if (target_vp == NULL) ! 643: retval = hfsGet(HTOVCB(parent_hp), &catInfo, forkType, parent_vp, &target_vp); ! 644: if (retval) ! 645: goto Err_Exit; ! 646: if (!lockparent || !(cnp->cn_flags & ISLASTCN)) ! 647: VOP_UNLOCK(tparent_vp, 0, p); ! 648: } ! 649: ! 650: /* ! 651: * Insert name in cache if wanted. ! 652: */ ! 653: if (cnp->cn_flags & MAKEENTRY) { ! 654: struct vnode *tp; ! 655: ! 656: /* If this is bypassing the complex vnode, get it, so we only store complex vnodes */ ! 657: if (target_vp->v_type != VREG) { ! 658: tp = target_vp; ! 659: } else { ! 660: if (parent_vp->v_type == VDIR) { ! 661: tp = VTOH(target_vp)->h_relative; ! 662: } else { ! 663: /* Parent node is complex node [already cached in earlier lookup]; ! 664: don't add anything else in the cache now. ! 665: ! 666: XXX Someday we may want to enter data/rsrc fork vnodes in the name cache... ! 667: */ ! 668: tp = NULL; ! 669: }; ! 670: }; ! 671: if (tp) { ! 672: DBG_ASSERT((tp->v_type==VDIR) || (tp->v_type==VCPLX) || (tp->v_type==VLNK)); ! 673: DBG_VOP(("\tStoring into name cache: target: 0x%x ", (u_int)target_vp)); DBG_VOP_PRINT_CPN_INFO(cnp); ! 674: DBG_VOP_CONT((" parent: "));DBG_VOP_PRINT_VNODE_INFO(parent_vp); DBG_VOP_CONT(("\n")); ! 675: cache_enter(parent_vp, tp, cnp); ! 676: }; ! 677: }; ! 678: ! 679: Err_Exit: ! 680: ! 681: *ap->a_vpp = target_vp; ! 682: ! 683: DBG_VOP_UPDATE_VP(1, *ap->a_vpp); ! 684: DBG_VOP_LOOKUP_TEST (funcname, cnp, parent_vp, target_vp); ! 685: DBG_VOP_LOCKS_TEST(E_NONE); ! 686: DBG_VOP_PRINT_FUNCNAME(); ! 687: if (retval == E_NONE) { ! 688: DBG_VOP_CONT(("Success\n")); ! 689: } else { ! 690: DBG_VOP_CONT(("Fails\n")); ! 691: } ! 692: ! 693: return (retval); ! 694: } ! 695: ! 696: ! 697: ! 698: ! 699: #if DBG_VOP_TEST_LOCKS ! 700: ! 701: void DbgLookupTest( char *funcname, struct componentname *cnp, struct vnode *dvp, struct vnode *vp) ! 702: { ! 703: int flags = cnp->cn_flags; ! 704: int nameiop = cnp->cn_nameiop; ! 705: ! 706: kprintf ("%X: %s: Action is: ", CURRENT_PROC->p_pid, funcname); ! 707: switch (nameiop) ! 708: { ! 709: case LOOKUP: ! 710: kprintf ("LOOKUP"); ! 711: break; ! 712: case CREATE: ! 713: kprintf ("CREATE"); ! 714: break; ! 715: case DELETE: ! 716: kprintf ("DELETE"); ! 717: break; ! 718: case RENAME: ! 719: kprintf ("RENAME"); ! 720: break; ! 721: default: ! 722: DBG_ERR (("!!!UNKNOWN!!!!")); ! 723: break; ! 724: } ! 725: kprintf (" flags: 0x%x ",flags ); ! 726: if (flags & LOCKPARENT) ! 727: kprintf (" LOCKPARENT"); ! 728: if (flags & ISLASTCN) ! 729: kprintf (" ISLASTCN"); ! 730: kprintf ("\n"); ! 731: ! 732: if (dvp) { ! 733: kprintf ("%X: %s: Parent vnode exited ", CURRENT_PROC->p_pid, funcname); ! 734: if (lockstatus(&VTOH(dvp)->h_lock)) { ! 735: kprintf ("LOCKED\n"); ! 736: } ! 737: else { ! 738: kprintf ("UNLOCKED\n"); ! 739: } ! 740: } ! 741: ! 742: if (vp) { ! 743: if (vp==dvp) ! 744: { ! 745: kprintf ("%X: %s: Target and Parent are the same\n", CURRENT_PROC->p_pid, funcname); ! 746: } ! 747: else { ! 748: kprintf ("%X: %s: Found vnode exited ", CURRENT_PROC->p_pid, funcname); ! 749: if (lockstatus(&VTOH(vp)->h_lock)) { ! 750: kprintf ("LOCKED\n"); ! 751: } ! 752: else { ! 753: kprintf ("UNLOCKED\n"); ! 754: } ! 755: } ! 756: kprintf ("%X: %s: Found vnode 0x%x has vtype of %d\n ", CURRENT_PROC->p_pid, funcname, (u_int)vp, vp->v_type); ! 757: } ! 758: else ! 759: kprintf ("%X: %s: Found vnode exited NULL\n", CURRENT_PROC->p_pid, funcname); ! 760: ! 761: ! 762: } ! 763: ! 764: #endif /* DBG_VOP_TEST_LOCKS */ ! 765:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.