]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_lookup.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_lookup.c
index c4013f4c36418df98da9cfabeab40fa445133ae4..d707d1b18b2c22b313a58d08d622267a8bff0139 100644 (file)
@@ -1,24 +1,21 @@
 /*
- * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
@@ -274,16 +271,15 @@ notfound:
                        retval = EJUSTRETURN;
                        goto exit;
                }
-       
+
                /*
                 * Insert name into cache (as non-existent) if appropriate.
                 *
-                * Disable negative caching since HFS is case-insensitive.
+                * Only done for case-sensitive HFS+ volumes.
                 */
-#if 0
-               if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
+               if ((hfsmp->hfs_flags & HFS_CASE_SENSITIVE) &&
+                   (cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
                        cache_enter(dvp, *vpp, cnp);
-#endif
                retval = ENOENT;
                goto exit;
        }
@@ -456,6 +452,34 @@ found:
                cache_enter(dvp, *vpp, cnp);
        }
 
+
+       //
+       // have to patch up the resource fork name because
+       // it won't happen properly in the layers above us.
+       //
+       if (wantrsrc) {
+           if (VTOC(*vpp)->c_vp == NULL) {
+               if (VNAME(*vpp) == NULL) {
+                   VNAME(*vpp) = add_name(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, 0);
+               }
+               if (VPARENT(*vpp) == NULL) {
+                   vget(dvp, 0, p);
+                   VPARENT(*vpp) = dvp;
+               }
+           } else {
+               if (VNAME(*vpp) == NULL) {
+                   // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec
+                   // and to not count the trailing null byte at the end of the string.
+                   VNAME(*vpp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0);
+               }
+               if (VPARENT(*vpp) == NULL && *vpp != VTOC(*vpp)->c_vp) {
+                   VPARENT(*vpp) = VTOC(*vpp)->c_vp;
+                   VTOC(*vpp)->c_flag |= C_VPREFHELD;
+                   vget(VTOC(*vpp)->c_vp, 0, p);
+               }
+           }
+       }
+
 exit:
        cat_releasedesc(&desc);
        return (retval);
@@ -483,6 +507,8 @@ exit:
  *
  */
 
+#define        S_IXALL 0000111
+
 __private_extern__
 int
 hfs_cache_lookup(ap)
@@ -495,16 +521,15 @@ hfs_cache_lookup(ap)
        struct vnode *dvp;
        struct vnode *vp;
        struct cnode *cp;
+       struct cnode *dcp;
        int lockparent; 
        int error;
        struct vnode **vpp = ap->a_vpp;
        struct componentname *cnp = ap->a_cnp;
-       struct ucred *cred = cnp->cn_cred;
        int flags = cnp->cn_flags;
        struct proc *p = cnp->cn_proc;
        u_long vpid;    /* capability number of vnode */
 
-       *vpp = NULL;
        dvp = ap->a_dvp;
        lockparent = flags & LOCKPARENT;
 
@@ -514,11 +539,17 @@ hfs_cache_lookup(ap)
        if (dvp->v_type != VDIR)
                return (ENOTDIR);
        if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
-           (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
-               return (EROFS);
-       if ((error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc)))
-               return (error);
+           (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
+               error = EROFS;
+               goto err_exit;
+       }
+       dcp = VTOC(dvp);
 
+       if (((dcp->c_mode & S_IXALL) != S_IXALL) && (cnp->cn_cred->cr_uid != 0)) {
+               if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) {
+                       goto err_exit;
+               }
+       }
        /*
         * Lookup an entry in the cache
         * If the lookup succeeds, the vnode is returned in *vpp, and a status of -1 is
@@ -527,14 +558,15 @@ hfs_cache_lookup(ap)
         * fails, a status of zero is returned.
         */
        error = cache_lookup(dvp, vpp, cnp);
-       if (error == 0)  {              /* Unsuccessfull */
-               error = hfs_lookup(ap);
-               return (error);
+       if (error != -1) {
+               if (error == 0)  {              /* Unsuccessfull */
+                       goto lookup;
+               }
+               
+               if (error == ENOENT) {
+                       goto err_exit;
+               }
        }
-       
-       if (error == ENOENT)
-               return (error);
-       
        /* We have a name that matched */
        vp = *vpp;
        vpid = vp->v_id;
@@ -583,20 +615,51 @@ hfs_cache_lookup(ap)
                        int wantrsrc = 0;
 
                        cnp->cn_consume = forkcomponent(cnp, &wantrsrc);
-                       
-                       /* Fork names are only for lookups */
-                       if (cnp->cn_consume &&
-                           (cnp->cn_nameiop != LOOKUP && cnp->cn_nameiop != CREATE))
-                               return (EPERM);
-                       /* 
-                        * We only store data forks in the name cache.
-                        */                              
-                       if (wantrsrc)
-                               return (hfs_lookup(ap));
+                       if (cnp->cn_consume) {
+                               flags |= ISLASTCN;
+                               /* Fork names are only for lookups */
+                               if (cnp->cn_nameiop != LOOKUP &&
+                                   cnp->cn_nameiop != CREATE) {
+                                       error = EPERM;
+
+                                       goto err_exit;
+                               }
+                       }
+
+                       if (wantrsrc) {
+                               /* Use cnode's rsrcfork vnode (if available) */
+                               if (cp->c_rsrc_vp != NULL) {
+                                       *vpp = vp = cp->c_rsrc_vp;
+                                       if (VNAME(vp) == NULL) {
+                                           // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec
+                                           // and to not count the trailing null byte at the end of the string.
+                                           VNAME(vp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0);
+                                       }
+                                       if (VPARENT(vp) == NULL) {
+                                           vget(cp->c_vp, 0, p);
+                                           VPARENT(vp) = cp->c_vp;
+                                       }
+                                       vpid = vp->v_id;
+                               } else {
+                                       goto lookup;
+                               }
+                       }
+               }
+               error = vget(vp, 0, p);
+               if (error == 0) {
+                       if (VTOC(vp) == NULL || vp->v_data != (void *)cp) {
+                               panic("hfs: cache lookup: my cnode disappeared/went bad! vp 0x%x 0x%x 0x%x\n",
+                                         vp, vp->v_data, cp);
+                       }
+                       if (cnp->cn_nameiop == LOOKUP &&
+                           (!(flags & ISLASTCN) || (flags & SHAREDLEAF)))
+                               error = lockmgr(&VTOC(vp)->c_lock, LK_SHARED, NULL, p);
+                       else
+                               error = lockmgr(&VTOC(vp)->c_lock, LK_EXCLUSIVE, NULL, p);
+               }
+               if (!lockparent || error || !(flags & ISLASTCN)) {
+                       (void) lockmgr(&dcp->c_lock, LK_RELEASE, NULL, p);
                }
-               error = vget(vp, LK_EXCLUSIVE, p);
-               if (!lockparent || error || !(flags & ISLASTCN))
-                       VOP_UNLOCK(dvp, 0, p);
        }
        /*
         * Check that the capability number did not change
@@ -616,8 +679,12 @@ hfs_cache_lookup(ap)
 
        if ((error = vn_lock(dvp, LK_EXCLUSIVE, p)))
                return (error);
-
+lookup:
        return (hfs_lookup(ap));
+
+err_exit:
+       *vpp = NULL;
+       return (error);
 }