Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / fs / adosfs / adlookup.c
blob3f819415e9605fc4dc1ac4ee3df62c76b3659456
1 /* $NetBSD: adlookup.c,v 1.12 2009/03/14 21:04:23 dsl Exp $ */
3 /*
4 * Copyright (c) 1994 Christian E. Hopps
5 * Copyright (c) 1996 Matthias Scheler
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Christian E. Hopps.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: adlookup.c,v 1.12 2009/03/14 21:04:23 dsl Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/vnode.h>
40 #include <sys/namei.h>
41 #include <sys/mount.h>
42 #include <sys/time.h>
43 #include <sys/queue.h>
44 #include <fs/adosfs/adosfs.h>
46 #ifdef ADOSFS_EXACTMATCH
47 #define strmatch(s1, l1, s2, l2, i) \
48 ((l1) == (l2) && memcmp((s1), (s2), (l1)) == 0)
49 #else
50 #define strmatch(s1, l1, s2, l2, i) \
51 ((l1) == (l2) && adoscaseequ((s1), (s2), (l1), (i)))
52 #endif
55 * adosfs lookup. enters with:
56 * pvp (parent vnode) referenced and locked.
57 * exit with:
58 * target vp referenced and locked.
59 * parent pvp locked.
60 * special cases:
61 * pvp == vp, just ref pvp, pvp already holds a ref and lock from
62 * caller, this will not occur with RENAME or CREATE.
64 int
65 adosfs_lookup(void *v)
67 struct vop_lookup_args /* {
68 struct vnode *a_dvp;
69 struct vnode **a_vpp;
70 struct componentname *a_cnp;
71 } */ *sp = v;
72 int nameiop, last, flags, error, nocache, i;
73 struct componentname *cnp;
74 struct vnode **vpp; /* place to store result */
75 struct anode *ap; /* anode to find */
76 struct vnode *vdp; /* vnode of search dir */
77 struct anode *adp; /* anode of search dir */
78 kauth_cred_t ucp; /* lookup credentials */
79 u_long bn, plen, hval;
80 const u_char *pelt;
82 #ifdef ADOSFS_DIAGNOSTIC
83 advopprint(sp);
84 #endif
85 cnp = sp->a_cnp;
86 vdp = sp->a_dvp;
87 adp = VTOA(vdp);
88 vpp = sp->a_vpp;
89 *vpp = NULL;
90 ucp = cnp->cn_cred;
91 nameiop = cnp->cn_nameiop;
92 flags = cnp->cn_flags;
93 last = flags & ISLASTCN;
94 pelt = (const u_char *)cnp->cn_nameptr;
95 plen = cnp->cn_namelen;
96 nocache = 0;
99 * Check accessiblity of directory.
101 if ((error = VOP_ACCESS(vdp, VEXEC, ucp)) != 0)
102 return (error);
104 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
105 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
106 return (EROFS);
109 * Before tediously performing a linear scan of the directory,
110 * check the name cache to see if the directory/name pair
111 * we are looking for is known already.
113 if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
114 return (error);
117 * fake a '.'
119 if (plen == 1 && pelt[0] == '.') {
120 /* see special cases in prologue. */
121 *vpp = vdp;
122 goto found;
125 * fake a ".."
127 if (flags & ISDOTDOT) {
128 if (vdp->v_type == VDIR && (vdp->v_vflag & VV_ROOT))
129 panic("adosfs .. attempted through root");
131 * cannot get `..' while `vdp' is locked
132 * e.g. procA holds lock on `..' and waits for `vdp'
133 * we wait for `..' and hold lock on `vdp'. deadlock.
134 * because `vdp' may have been achieved through symlink
135 * fancy detection code that decreases the race
136 * window size is not reasonably possible.
138 * basically unlock the parent, try and lock the child (..)
139 * if that fails relock the parent (ignoring error) and
140 * fail. Otherwise we have the child (..), attempt to
141 * relock the parent. If that fails unlock the child (..)
142 * and fail. Otherwise we have succeded.
145 VOP_UNLOCK(vdp, 0); /* race */
146 error = VFS_VGET(vdp->v_mount, (ino_t)adp->pblock, vpp);
147 vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
148 if (error) {
149 *vpp = NULL;
150 return (error);
152 goto found_lockdone;
156 * hash the name and grab the first block in chain
157 * then walk the chain. if chain has not been fully
158 * walked before, track the count in `tabi'
160 hval = adoshash(pelt, plen, adp->ntabent, IS_INTER(adp->amp));
161 bn = adp->tab[hval];
162 i = min(adp->tabi[hval], 0);
163 while (bn != 0) {
164 if ((error = VFS_VGET(vdp->v_mount, (ino_t)bn, vpp
165 )) != 0) {
166 #ifdef ADOSFS_DIAGNOSTIC
167 printf("[aget] %d)", error);
168 #endif
169 return(error);
171 ap = VTOA(*vpp);
172 if (i <= 0) {
173 if (--i < adp->tabi[hval])
174 adp->tabi[hval] = i;
176 * last header in chain lock count down by
177 * negating it to positive
179 if (ap->hashf == 0) {
180 #ifdef DEBUG
181 if (i != adp->tabi[hval])
182 panic("adlookup: wrong chain count");
183 #endif
184 adp->tabi[hval] = -adp->tabi[hval];
187 if (strmatch(pelt, plen, ap->name, strlen(ap->name),
188 IS_INTER(adp->amp)))
189 goto found;
190 bn = ap->hashf;
191 vput(*vpp);
193 *vpp = NULL;
195 * not found
197 if ((nameiop == CREATE || nameiop == RENAME) && last) {
199 if (vdp->v_mount->mnt_flag & MNT_RDONLY)
200 return (EROFS);
202 if ((error = VOP_ACCESS(vdp, VWRITE, ucp)) != 0) {
203 #ifdef ADOSFS_DIAGNOSTIC
204 printf("[VOP_ACCESS] %d)", error);
205 #endif
206 return (error);
208 cnp->cn_nameiop |= SAVENAME;
209 #ifdef ADOSFS_DIAGNOSTIC
210 printf("EJUSTRETURN)");
211 #endif
212 return(EJUSTRETURN);
214 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
215 cache_enter(vdp, NULL, cnp);
216 #ifdef ADOSFS_DIAGNOSTIC
217 printf("ENOENT)");
218 #endif
219 return(ENOENT);
221 found:
222 if (nameiop == DELETE && last) {
223 if ((error = VOP_ACCESS(vdp, VWRITE, ucp)) != 0) {
224 if (vdp != *vpp)
225 vput(*vpp);
226 *vpp = NULL;
227 return (error);
229 nocache = 1;
231 if (nameiop == RENAME && last) {
232 if (vdp == *vpp)
233 return(EISDIR);
234 if ((error = VOP_ACCESS(vdp, VWRITE, ucp)) != 0) {
235 vput(*vpp);
236 *vpp = NULL;
237 return (error);
239 cnp->cn_flags |= SAVENAME;
240 nocache = 1;
242 if (vdp == *vpp)
243 vref(vdp);
244 found_lockdone:
245 if ((cnp->cn_flags & MAKEENTRY) && nocache == 0)
246 cache_enter(vdp, *vpp, cnp);
248 #ifdef ADOSFS_DIAGNOSTIC
249 printf("0)\n");
250 #endif
251 return(0);