Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / sys / kern / vfs_nlookup.c
1 /*
2  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
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
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/kern/vfs_nlookup.c,v 1.25 2008/07/19 04:43:33 dillon Exp $
35  */
36 /*
37  * nlookup() is the 'new' namei interface.  Rather then return directory and
38  * leaf vnodes (in various lock states) the new interface instead deals in
39  * namecache records.  Namecache records may represent both a positive or
40  * a negative hit.  The namespace is locked via the namecache record instead
41  * of via the vnode, and only the leaf namecache record (representing the
42  * filename) needs to be locked.
43  *
44  * This greatly improves filesystem parallelism and is a huge simplification
45  * of the API verses the old vnode locking / namei scheme.
46  *
47  * Filesystems must actively control the caching aspects of the namecache,
48  * and since namecache pointers are used as handles they are non-optional
49  * even for filesystems which do not generally wish to cache things.  It is
50  * intended that a separate cache coherency API will be constructed to handle
51  * these issues.
52  */
53
54 #include "opt_ktrace.h"
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/kernel.h>
59 #include <sys/vnode.h>
60 #include <sys/mount.h>
61 #include <sys/filedesc.h>
62 #include <sys/proc.h>
63 #include <sys/namei.h>
64 #include <sys/nlookup.h>
65 #include <sys/malloc.h>
66 #include <sys/stat.h>
67 #include <sys/objcache.h>
68
69 #ifdef KTRACE
70 #include <sys/ktrace.h>
71 #endif
72
73 static int naccess_va(struct vattr *va, int vmode, struct ucred *cred);
74
75 /*
76  * Initialize a nlookup() structure, early error return for copyin faults
77  * or a degenerate empty string (which is not allowed).
78  *
79  * The first process proc0's credentials are used if the calling thread
80  * is not associated with a process context.
81  */
82 int
83 nlookup_init(struct nlookupdata *nd, 
84              const char *path, enum uio_seg seg, int flags)
85 {
86     size_t pathlen;
87     struct proc *p;
88     thread_t td;
89     int error;
90
91     td = curthread;
92     p = td->td_proc;
93
94     /*
95      * note: the pathlen set by copy*str() includes the terminating \0.
96      */
97     bzero(nd, sizeof(struct nlookupdata));
98     nd->nl_path = objcache_get(namei_oc, M_WAITOK);
99     nd->nl_flags |= NLC_HASBUF;
100     if (seg == UIO_SYSSPACE) 
101         error = copystr(path, nd->nl_path, MAXPATHLEN, &pathlen);
102     else
103         error = copyinstr(path, nd->nl_path, MAXPATHLEN, &pathlen);
104
105     /*
106      * Don't allow empty pathnames.
107      * POSIX.1 requirement: "" is not a vaild file name.
108      */
109     if (error == 0 && pathlen <= 1)
110         error = ENOENT;
111
112     if (error == 0) {
113         if (p && p->p_fd) {
114             cache_copy(&p->p_fd->fd_ncdir, &nd->nl_nch);
115             cache_copy(&p->p_fd->fd_nrdir, &nd->nl_rootnch);
116             if (p->p_fd->fd_njdir.ncp)
117                 cache_copy(&p->p_fd->fd_njdir, &nd->nl_jailnch);
118             nd->nl_cred = crhold(p->p_ucred);
119         } else {
120             cache_copy(&rootnch, &nd->nl_nch);
121             cache_copy(&nd->nl_nch, &nd->nl_rootnch);
122             cache_copy(&nd->nl_nch, &nd->nl_jailnch);
123             nd->nl_cred = crhold(proc0.p_ucred);
124         }
125         nd->nl_td = td;
126         nd->nl_flags |= flags;
127     } else {
128         nlookup_done(nd);
129     }
130     return(error);
131 }
132
133 /*
134  * This works similarly to nlookup_init() but does not assume a process
135  * context.  rootnch is always chosen for the root directory and the cred
136  * and starting directory are supplied in arguments.
137  */
138 int
139 nlookup_init_raw(struct nlookupdata *nd, 
140              const char *path, enum uio_seg seg, int flags,
141              struct ucred *cred, struct nchandle *ncstart)
142 {
143     size_t pathlen;
144     thread_t td;
145     int error;
146
147     td = curthread;
148
149     bzero(nd, sizeof(struct nlookupdata));
150     nd->nl_path = objcache_get(namei_oc, M_WAITOK);
151     nd->nl_flags |= NLC_HASBUF;
152     if (seg == UIO_SYSSPACE) 
153         error = copystr(path, nd->nl_path, MAXPATHLEN, &pathlen);
154     else
155         error = copyinstr(path, nd->nl_path, MAXPATHLEN, &pathlen);
156
157     /*
158      * Don't allow empty pathnames.
159      * POSIX.1 requirement: "" is not a vaild file name.
160      */
161     if (error == 0 && pathlen <= 1)
162         error = ENOENT;
163
164     if (error == 0) {
165         cache_copy(ncstart, &nd->nl_nch);
166         cache_copy(&rootnch, &nd->nl_rootnch);
167         cache_copy(&rootnch, &nd->nl_jailnch);
168         nd->nl_cred = crhold(cred);
169         nd->nl_td = td;
170         nd->nl_flags |= flags;
171     } else {
172         nlookup_done(nd);
173     }
174     return(error);
175 }
176
177 /*
178  * Set a different credential; this credential will be used by future
179  * operations performed on nd.nl_open_vp and nlookupdata structure.
180  */
181 void
182 nlookup_set_cred(struct nlookupdata *nd, struct ucred *cred)
183 {
184         KKASSERT(nd->nl_cred != NULL);
185
186         if (nd->nl_cred != cred) {
187                 cred = crhold(cred);
188                 crfree(nd->nl_cred);
189                 nd->nl_cred = cred;
190         }
191 }
192
193 /*
194  * Cleanup a nlookupdata structure after we are through with it.  This may
195  * be called on any nlookupdata structure initialized with nlookup_init().
196  * Calling nlookup_done() is mandatory in all cases except where nlookup_init()
197  * returns an error, even if as a consumer you believe you have taken all
198  * dynamic elements out of the nlookupdata structure.
199  */
200 void
201 nlookup_done(struct nlookupdata *nd)
202 {
203     if (nd->nl_nch.ncp) {
204         if (nd->nl_flags & NLC_NCPISLOCKED) {
205             nd->nl_flags &= ~NLC_NCPISLOCKED;
206             cache_unlock(&nd->nl_nch);
207         }
208         cache_drop(&nd->nl_nch);
209     }
210     if (nd->nl_rootnch.ncp)
211         cache_drop(&nd->nl_rootnch);
212     if (nd->nl_jailnch.ncp)
213         cache_drop(&nd->nl_jailnch);
214     if ((nd->nl_flags & NLC_HASBUF) && nd->nl_path) {
215         objcache_put(namei_oc, nd->nl_path);
216         nd->nl_path = NULL;
217     }
218     if (nd->nl_cred) {
219         crfree(nd->nl_cred);
220         nd->nl_cred = NULL;
221     }
222     if (nd->nl_open_vp) {
223         if (nd->nl_flags & NLC_LOCKVP) {
224                 vn_unlock(nd->nl_open_vp);
225                 nd->nl_flags &= ~NLC_LOCKVP;
226         }
227         vn_close(nd->nl_open_vp, nd->nl_vp_fmode);
228         nd->nl_open_vp = NULL;
229     }
230     if (nd->nl_dvp) {
231         vrele(nd->nl_dvp);
232         nd->nl_dvp = NULL;
233     }
234     nd->nl_flags = 0;   /* clear remaining flags (just clear everything) */
235 }
236
237 void
238 nlookup_zero(struct nlookupdata *nd)
239 {
240     bzero(nd, sizeof(struct nlookupdata));
241 }
242
243 /*
244  * Simple all-in-one nlookup.  Returns a locked namecache structure or NULL
245  * if an error occured. 
246  *
247  * Note that the returned ncp is not checked for permissions, though VEXEC
248  * is checked on the directory path leading up to the result.  The caller
249  * must call naccess() to check the permissions of the returned leaf.
250  */
251 struct nchandle
252 nlookup_simple(const char *str, enum uio_seg seg,
253                int niflags, int *error)
254 {
255     struct nlookupdata nd;
256     struct nchandle nch;
257
258     *error = nlookup_init(&nd, str, seg, niflags);
259     if (*error == 0) {
260             if ((*error = nlookup(&nd)) == 0) {
261                     nch = nd.nl_nch;    /* keep hold ref from structure */
262                     cache_zero(&nd.nl_nch); /* and NULL out */
263             } else {
264                     cache_zero(&nch);
265             }
266             nlookup_done(&nd);
267     } else {
268             cache_zero(&nch);
269     }
270     return(nch);
271 }
272
273 /*
274  * Do a generic nlookup.  Note that the passed nd is not nlookup_done()'d
275  * on return, even if an error occurs.  If no error occurs the returned
276  * nl_nch is always referenced and locked, otherwise it may or may not be.
277  *
278  * Intermediate directory elements, including the current directory, require
279  * execute (search) permission.  nlookup does not examine the access 
280  * permissions on the returned element.
281  *
282  * If NLC_CREATE is set the last directory must allow node creation,
283  * and an error code of 0 will be returned for a non-existant
284  * target (not ENOENT).
285  *
286  * If NLC_RENAME is set the last directory mut allow node deletion,
287  * plus the sticky check is made, and an error code of 0 will be returned
288  * for a non-existant target (not ENOENT).  NLC_RENAME is set used for
289  * the rename target.
290  *
291  * If NLC_DELETE is set the last directory mut allow node deletion,
292  * plus the sticky check is made.
293  *
294  * If NLC_REFDVP is set nd->nl_dvp will be set to the directory vnode
295  * of the returned entry.  The vnode will be referenced, but not locked,
296  * and will be released by nlookup_done() along with everything else.
297  */
298 int
299 nlookup(struct nlookupdata *nd)
300 {
301     struct nlcomponent nlc;
302     struct nchandle nch;
303     struct mount *mp;
304     int wasdotordotdot;
305     char *ptr;
306     char *xptr;
307     int error;
308     int len;
309
310 #ifdef KTRACE
311     if (KTRPOINT(nd->nl_td, KTR_NAMEI))
312         ktrnamei(nd->nl_td->td_lwp, nd->nl_path);
313 #endif
314     bzero(&nlc, sizeof(nlc));
315
316     /*
317      * Setup for the loop.  The current working namecache element must
318      * be in a refd + unlocked state.  This typically the case on entry except
319      * when stringing nlookup()'s along in a chain, since nlookup() always
320      * returns nl_nch in a locked state.
321      */
322     nd->nl_loopcnt = 0;
323     if (nd->nl_flags & NLC_NCPISLOCKED) {
324         nd->nl_flags &= ~NLC_NCPISLOCKED;
325         cache_unlock(&nd->nl_nch);
326     }
327     if (nd->nl_dvp ) {
328         vrele(nd->nl_dvp);
329         nd->nl_dvp = NULL;
330     }
331     ptr = nd->nl_path;
332
333     /*
334      * Loop on the path components.  At the top of the loop nd->nl_nch
335      * is ref'd and unlocked and represents our current position.
336      */
337     for (;;) {
338         /*
339          * Check if the root directory should replace the current
340          * directory.  This is done at the start of a translation
341          * or after a symbolic link has been found.  In other cases
342          * ptr will never be pointing at a '/'.
343          */
344         if (*ptr == '/') {
345             do {
346                 ++ptr;
347             } while (*ptr == '/');
348             cache_copy(&nd->nl_rootnch, &nch);
349             cache_drop(&nd->nl_nch);
350             nd->nl_nch = nch;
351
352             /*
353              * Fast-track termination.  There is no parent directory of
354              * the root in the same mount from the point of view of
355              * the caller so return EPERM if NLC_REFDVP is specified.
356              * e.g. 'rmdir /' is not allowed.
357              */
358             if (*ptr == 0) {
359                 if (nd->nl_flags & NLC_REFDVP) {
360                         error = EPERM;
361                 } else {
362                         cache_lock(&nd->nl_nch);
363                         nd->nl_flags |= NLC_NCPISLOCKED;
364                         error = 0;
365                 }
366                 break;
367             }
368             continue;
369         }
370
371         /*
372          * Check directory search permissions.
373          */
374         if ((error = naccess(&nd->nl_nch, VEXEC, nd->nl_cred, NULL)) != 0)
375             break;
376
377         /*
378          * Extract the path component
379          */
380         nlc.nlc_nameptr = ptr;
381         while (*ptr && *ptr != '/')
382             ++ptr;
383         nlc.nlc_namelen = ptr - nlc.nlc_nameptr;
384
385         /*
386          * Lookup the path component in the cache, creating an unresolved
387          * entry if necessary.  We have to handle "." and ".." as special
388          * cases.
389          *
390          * When handling ".." we have to detect a traversal back through a
391          * mount point.   If we are at the root, ".." just returns the root.
392          *
393          * This subsection returns a locked, refd 'nch' unless it errors out.
394          * The namecache topology is not allowed to be disconnected, so 
395          * encountering a NULL parent will generate EINVAL.  This typically
396          * occurs when a directory is removed out from under a process.
397          */
398         if (nlc.nlc_namelen == 1 && nlc.nlc_nameptr[0] == '.') {
399             cache_get(&nd->nl_nch, &nch);
400             wasdotordotdot = 1;
401         } else if (nlc.nlc_namelen == 2 && 
402                    nlc.nlc_nameptr[0] == '.' && nlc.nlc_nameptr[1] == '.') {
403             if (nd->nl_nch.mount == nd->nl_rootnch.mount &&
404                 nd->nl_nch.ncp == nd->nl_rootnch.ncp
405             ) {
406                 /*
407                  * ".." at the root returns the root
408                  */
409                 cache_get(&nd->nl_nch, &nch);
410             } else {
411                 /*
412                  * Locate the parent ncp.  If we are at the root of a
413                  * filesystem mount we have to skip to the mounted-on
414                  * point in the underlying filesystem.
415                  */
416                 nch = nd->nl_nch;
417                 while (nch.ncp == nch.mount->mnt_ncmountpt.ncp)
418                         nch = nch.mount->mnt_ncmounton;
419                 nch.ncp = nch.ncp->nc_parent;
420                 KKASSERT(nch.ncp != NULL);
421                 cache_get(&nch, &nch);
422             }
423             wasdotordotdot = 1;
424         } else {
425             nch = cache_nlookup(&nd->nl_nch, &nlc);
426             while ((error = cache_resolve(&nch, nd->nl_cred)) == EAGAIN) {
427                 kprintf("[diagnostic] nlookup: relookup %*.*s\n", 
428                         nch.ncp->nc_nlen, nch.ncp->nc_nlen, nch.ncp->nc_name);
429                 cache_put(&nch);
430                 nch = cache_nlookup(&nd->nl_nch, &nlc);
431             }
432             wasdotordotdot = 0;
433         }
434         /*
435          * [end of subsection] ncp is locked and ref'd.  nd->nl_nch is ref'd
436          */
437
438         /*
439          * Resolve the namespace if necessary.  The ncp returned by
440          * cache_nlookup() is referenced and locked.
441          *
442          * XXX neither '.' nor '..' should return EAGAIN since they were
443          * previously resolved and thus cannot be newly created ncp's.
444          */
445         if (nch.ncp->nc_flag & NCF_UNRESOLVED) {
446             error = cache_resolve(&nch, nd->nl_cred);
447             KKASSERT(error != EAGAIN);
448         } else {
449             error = nch.ncp->nc_error;
450         }
451
452         /*
453          * Early completion.  ENOENT is not an error if this is the last
454          * component and NLC_CREATE or NLC_RENAME (rename target) was
455          * requested.  Note that ncp->nc_error is left as ENOENT in that
456          * case, which we check later on.
457          *
458          * NOTE: For NLC_RENAME in the ENOENT case we do a VCREATE test,
459          *       same as for NLC_CREATE.
460          *
461          * Also handle invalid '.' or '..' components terminating a path
462          * for a create/rename/delete.  The standard requires this and pax
463          * pretty stupidly depends on it.
464          */
465         for (xptr = ptr; *xptr == '/'; ++xptr)
466                 ;
467         if (*xptr == 0) {
468             if (error == ENOENT && (nd->nl_flags & (NLC_CREATE | NLC_RENAME))) {
469                 if (nd->nl_flags & NLC_NFS_RDONLY)
470                         error = EROFS;
471                 else
472                         error = naccess(&nch, VCREATE, nd->nl_cred, NULL);
473             }
474             if (error == 0 && wasdotordotdot &&
475                 (nd->nl_flags & (NLC_CREATE | NLC_RENAME | NLC_DELETE))) {
476                 error = EINVAL;
477             }
478         }
479
480         /*
481          * Early completion on error.
482          */
483         if (error) {
484             cache_put(&nch);
485             break;
486         }
487
488         /*
489          * If the element is a symlink and it is either not the last
490          * element or it is the last element and we are allowed to
491          * follow symlinks, resolve the symlink.
492          */
493         if ((nch.ncp->nc_flag & NCF_ISSYMLINK) &&
494             (*ptr || (nd->nl_flags & NLC_FOLLOW))
495         ) {
496             if (nd->nl_loopcnt++ >= MAXSYMLINKS) {
497                 error = ELOOP;
498                 cache_put(&nch);
499                 break;
500             }
501             error = nreadsymlink(nd, &nch, &nlc);
502             cache_put(&nch);
503             if (error)
504                 break;
505
506             /*
507              * Concatenate trailing path elements onto the returned symlink.
508              * Note that if the path component (ptr) is not exhausted, it
509              * will being with a '/', so we do not have to add another one.
510              *
511              * The symlink may not be empty.
512              */
513             len = strlen(ptr);
514             if (nlc.nlc_namelen == 0 || nlc.nlc_namelen + len >= MAXPATHLEN) {
515                 error = nlc.nlc_namelen ? ENAMETOOLONG : ENOENT;
516                 objcache_put(namei_oc, nlc.nlc_nameptr);
517                 break;
518             }
519             bcopy(ptr, nlc.nlc_nameptr + nlc.nlc_namelen, len + 1);
520             if (nd->nl_flags & NLC_HASBUF)
521                 objcache_put(namei_oc, nd->nl_path);
522             nd->nl_path = nlc.nlc_nameptr;
523             nd->nl_flags |= NLC_HASBUF;
524             ptr = nd->nl_path;
525
526             /*
527              * Go back up to the top to resolve any initial '/'s in the
528              * symlink.
529              */
530             continue;
531         }
532
533         /*
534          * If the element is a directory and we are crossing a mount point,
535          * Locate the mount.
536          */
537         while ((nch.ncp->nc_flag & NCF_ISMOUNTPT) && 
538             (nd->nl_flags & NLC_NOCROSSMOUNT) == 0 &&
539             (mp = cache_findmount(&nch)) != NULL
540         ) {
541             struct vnode *tdp;
542
543             cache_put(&nch);
544             cache_get(&mp->mnt_ncmountpt, &nch);
545
546             if (nch.ncp->nc_flag & NCF_UNRESOLVED) {
547                 while (vfs_busy(mp, 0))
548                     ;
549                 error = VFS_ROOT(mp, &tdp);
550                 vfs_unbusy(mp);
551                 if (error)
552                     break;
553                 cache_setvp(&nch, tdp);
554                 vput(tdp);
555             }
556         }
557         if (error) {
558             cache_put(&nch);
559             break;
560         }
561             
562         /*
563          * Skip any slashes to get to the next element.  If there 
564          * are any slashes at all the current element must be a
565          * directory or, in the create case, intended to become a directory.
566          * If it isn't we break without incrementing ptr and fall through
567          * to the failure case below.
568          */
569         while (*ptr == '/') {
570             if ((nch.ncp->nc_flag & NCF_ISDIR) == 0 && 
571                 !(nd->nl_flags & NLC_WILLBEDIR)
572             ) {
573                 break;
574             }
575             ++ptr;
576         }
577
578         /*
579          * Continuation case: additional elements and the current
580          * element is a directory.
581          */
582         if (*ptr && (nch.ncp->nc_flag & NCF_ISDIR)) {
583             cache_drop(&nd->nl_nch);
584             cache_unlock(&nch);
585             nd->nl_nch = nch;
586             continue;
587         }
588
589         /*
590          * Failure case: additional elements and the current element
591          * is not a directory
592          */
593         if (*ptr) {
594             cache_put(&nch);
595             error = ENOTDIR;
596             break;
597         }
598
599         /*
600          * Successful lookup of last element.
601          *
602          * Check directory permissions if a deletion or rename (target)
603          * is specified.  This also handles the sticky test.
604          *
605          * We already checked permissions for creates in the early
606          * termination code above.
607          */
608         if (*ptr == 0 && (nd->nl_flags & (NLC_DELETE | NLC_RENAME))) {
609             if (nd->nl_flags & NLC_DELETE)
610                 error = naccess(&nch, VDELETE, nd->nl_cred, NULL);
611             else
612                 error = naccess(&nch, VRENAME, nd->nl_cred, NULL);
613             if (error) {
614                 cache_put(&nch);
615                 break;
616             }
617         }
618
619         /*
620          * Termination: no more elements.  If NLC_CREATE was set the
621          * ncp may represent a negative hit (ncp->nc_error will be ENOENT),
622          * but we still return an error code of 0.
623          *
624          * If NLC_REFDVP is set acquire a referenced parent dvp.
625          */
626         if (nd->nl_flags & NLC_REFDVP) {
627                 error = cache_vref(&nd->nl_nch, nd->nl_cred, &nd->nl_dvp);
628                 if (error) {
629                         kprintf("NLC_REFDVP: Cannot ref dvp of %p\n", nch.ncp);
630                         cache_put(&nch);
631                         break;
632                 }
633         }
634         cache_drop(&nd->nl_nch);
635         nd->nl_nch = nch;
636         nd->nl_flags |= NLC_NCPISLOCKED;
637         error = 0;
638         break;
639     }
640     return(error);
641 }
642
643 /*
644  * Resolve a mount point's glue ncp.  This ncp connects creates the illusion
645  * of continuity in the namecache tree by connecting the ncp related to the
646  * vnode under the mount to the ncp related to the mount's root vnode.
647  *
648  * If no error occured a locked, ref'd ncp is stored in *ncpp.
649  */
650 int
651 nlookup_mp(struct mount *mp, struct nchandle *nch)
652 {
653     struct vnode *vp;
654     int error;
655
656     error = 0;
657     cache_get(&mp->mnt_ncmountpt, nch);
658     if (nch->ncp->nc_flag & NCF_UNRESOLVED) {
659         while (vfs_busy(mp, 0))
660             ;
661         error = VFS_ROOT(mp, &vp);
662         vfs_unbusy(mp);
663         if (error) {
664             cache_put(nch);
665         } else {
666             cache_setvp(nch, vp);
667             vput(vp);
668         }
669     }
670     return(error);
671 }
672
673 /*
674  * Read the contents of a symlink, allocate a path buffer out of the
675  * namei_oc and initialize the supplied nlcomponent with the result.
676  *
677  * If an error occurs no buffer will be allocated or returned in the nlc.
678  */
679 int
680 nreadsymlink(struct nlookupdata *nd, struct nchandle *nch, 
681                 struct nlcomponent *nlc)
682 {
683     struct vnode *vp;
684     struct iovec aiov;
685     struct uio auio;
686     int linklen;
687     int error;
688     char *cp;
689
690     nlc->nlc_nameptr = NULL;
691     nlc->nlc_namelen = 0;
692     if (nch->ncp->nc_vp == NULL)
693         return(ENOENT);
694     if ((error = cache_vget(nch, nd->nl_cred, LK_SHARED, &vp)) != 0)
695         return(error);
696     cp = objcache_get(namei_oc, M_WAITOK);
697     aiov.iov_base = cp;
698     aiov.iov_len = MAXPATHLEN;
699     auio.uio_iov = &aiov;
700     auio.uio_iovcnt = 1;
701     auio.uio_offset = 0;
702     auio.uio_rw = UIO_READ;
703     auio.uio_segflg = UIO_SYSSPACE;
704     auio.uio_td = nd->nl_td;
705     auio.uio_resid = MAXPATHLEN - 1;
706     error = VOP_READLINK(vp, &auio, nd->nl_cred);
707     if (error)
708         goto fail;
709     linklen = MAXPATHLEN - 1 - auio.uio_resid;
710     if (varsym_enable) {
711         linklen = varsymreplace(cp, linklen, MAXPATHLEN - 1);
712         if (linklen < 0) {
713             error = ENAMETOOLONG;
714             goto fail;
715         }
716     }
717     cp[linklen] = 0;
718     nlc->nlc_nameptr = cp;
719     nlc->nlc_namelen = linklen;
720     vput(vp);
721     return(0);
722 fail:
723     objcache_put(namei_oc, cp);
724     vput(vp);
725     return(error);
726 }
727
728 /*
729  * Check access [XXX cache vattr!] [XXX quota]
730  *
731  * Generally check the V* access bits from sys/vnode.h.  All specified bits
732  * must pass for this function to return 0.
733  *
734  * The file does not have to exist when checking VCREATE or VRENAME access.
735  *
736  * The file must not exist if VEXCL is specified.
737  *
738  * Directory permissions in general are tested for VCREATE if the file
739  * does not exist, VDELETE if the file does exist, and VRENAME whether
740  * the file exists or not.
741  *
742  * The directory sticky bit is tested for VDELETE and VRENAME.  NOTE: For
743  * VRENAME we only care if the target exists.
744  *
745  * The passed ncp may or may not be locked.  The caller should use a
746  * locked ncp on leaf lookups, especially for VCREATE, VRENAME, VDELETE,
747  * and VEXCL checks.
748  */
749 int
750 naccess(struct nchandle *nch, int vmode, struct ucred *cred, int *stickyp)
751 {
752     struct nchandle par;
753     struct vnode *vp;
754     struct vattr va;
755     int error;
756     int sticky;
757
758     if (nch->ncp->nc_flag & NCF_UNRESOLVED) {
759         cache_lock(nch);
760         cache_resolve(nch, cred);
761         cache_unlock(nch);
762     }
763     error = nch->ncp->nc_error;
764     sticky = 0;
765
766     /*
767      * Directory permissions and VEXCL checks.  Do a precursor conditional
768      * to reduce overhead since most access checks are for read-only.
769      */
770     if (vmode & (VDELETE|VRENAME|VCREATE|VEXCL)) {
771         if (((vmode & VCREATE) && nch->ncp->nc_vp == NULL) ||
772             ((vmode & VDELETE) && nch->ncp->nc_vp != NULL) ||
773             (vmode & VRENAME)
774         ) {
775             if ((par.ncp = nch->ncp->nc_parent) == NULL) {
776                 if (error != EAGAIN)
777                         error = EINVAL;
778             } else {
779                 par.mount = nch->mount;
780                 cache_hold(&par);
781                 error = naccess(&par, VWRITE, cred, &sticky);
782                 if ((vmode & (VDELETE | VRENAME)) && sticky)
783                     vmode |= VSVTX;
784                 cache_drop(&par);
785             }
786         }
787         if ((vmode & VEXCL) && nch->ncp->nc_vp != NULL)
788             error = EEXIST;
789     }
790     if (error == 0) {
791         error = cache_vget(nch, cred, LK_SHARED, &vp);
792         if (error == ENOENT) {
793             if (vmode & (VCREATE | VRENAME))
794                 error = 0;
795         } else if (error == 0) {
796             /* XXX cache the va in the namecache or in the vnode */
797             if ((error = VOP_GETATTR(vp, &va)) == 0) {
798                 if ((vmode & VWRITE) && vp->v_mount) {
799                     if (vp->v_mount->mnt_flag & MNT_RDONLY)
800                         error = EROFS;
801                 }
802             }
803             vput(vp);
804
805             if (error == 0) {
806                 /*
807                  * Set the returned (*stickyp) if VSVTX is set and the uid
808                  * is not the owner of the directory.  The caller uses this
809                  * disallow deletions of files not owned by the user if the
810                  * user also does not own the directory and the sticky bit
811                  * is set on the directory.  Weird, I know.
812                  */
813                 if (stickyp && va.va_uid != cred->cr_uid)
814                     *stickyp = (va.va_mode & VSVTX);
815
816                 /*
817                  * Process general access.
818                  */
819                 error = naccess_va(&va, vmode, cred);
820             }
821         }
822     }
823     return(error);
824 }
825
826 /*
827  * Check the requested access against the given vattr using cred.
828  */
829 static
830 int
831 naccess_va(struct vattr *va, int vmode, struct ucred *cred)
832 {
833     int i;
834
835     /*
836      * Test the immutable bit for files, directories, and softlinks.
837      *
838      * NOTE: Only called for VRENAME if the target exists.
839      */
840     if (vmode & (VWRITE|VDELETE|VRENAME)) {
841         if (va->va_type == VDIR || va->va_type == VLNK || va->va_type == VREG) {
842             if (va->va_flags & IMMUTABLE)
843                 return (EPERM);
844         }
845     }
846
847     /*
848      * root gets universal access
849      */
850     if (cred->cr_uid == 0)
851         return(0);
852
853     /*
854      * Check owner perms.
855      *
856      * If VOWN is set the owner of the file is allowed no matter when
857      * the owner-mode bits say (utimes).
858      */
859     if (cred->cr_uid == va->va_uid) {
860         if ((vmode & VOWN) == 0) {
861             vmode &= S_IRWXU;
862             if ((vmode & va->va_mode) != vmode)
863                 return(EACCES);
864         }
865         return(0);
866     }
867
868     /*
869      * If VSVTX is set only the owner may create or delete the file.
870      * This bit is typically set for VDELETE checks from unlink or
871      * the source file in a rename, and for VCREATE checks from the
872      * target file in a rename.
873      *
874      * Note that other V bits are not typically set in the VSVTX case.
875      * For creations and deletions we usually just care about directory
876      * permissions, not file permissions.  So if this test passes the
877      * return value winds up being 0.
878      */
879     if (vmode & VSVTX)
880         return(EACCES);
881
882     /*
883      * Check group perms
884      */
885     vmode &= S_IRWXU;
886     vmode >>= 3;
887     for (i = 0; i < cred->cr_ngroups; ++i) {
888         if (va->va_gid == cred->cr_groups[i]) {
889             if ((vmode & va->va_mode) != vmode)
890                 return(EACCES);
891             return(0);
892         }
893     }
894
895     /*
896      * Check world perms
897      */
898     vmode >>= 3;
899     if ((vmode & va->va_mode) != vmode)
900         return(EACCES);
901     return(0);
902 }
903