vfs_lookup.c

来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 350 行

C
350
字号
#ifndef lintstatic        char sccsid[] = "@(#)vfs_lookup.c 1.1 92/07/30 Copyr 1986 Sun Micro";#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. */#include <mon/sunromvec.h>#include <sys/param.h>#include <sys/user.h>#include <sys/uio.h>#include <sys/vfs.h>#include "boot/vnode.h"#include <sys/dir.h>#include <sys/pathname.h>#ifdef	NFSDEBUGstatic	int	nfsdebug = 10;#endif	NFSDEBUG#undef uextern struct user u;/* * lookup the user file name, * Handle allocation and freeing of pathname buffer, return error. */lookupname(fnamep, seg, followlink, dirvpp, compvpp)        char *fnamep;                   /* user pathname */        int seg;                        /* addr space that name is in */        enum symfollow followlink;      /* follow sym links */        struct vnode **dirvpp;          /* ret for ptr to parent dir vnode */        struct vnode **compvpp;         /* ret for ptr to component vnode */{        struct pathname lookpn;        register int error;#ifdef	NFSDEBUG	dprint(nfsdebug, 6,		"lookupname(fnamep '%s' seg 0x%x followlink 0x%x dirvpp 0x%x compvpp 0x%x)\n",		fnamep, seg, followlink, dirvpp, compvpp);#endif	NFSDEBUG        error = pn_get(fnamep, seg, &lookpn);        if (error)	{		printf("Boot:  lookupname: pn_get failed: ");		errno_print(error);		printf("\n");                return (error);	}        error = lookuppn(&lookpn, followlink, dirvpp, compvpp);	if (error) {		printf("Boot:  lookuppn failed: ");		errno_print(error);		printf("\n");	}        pn_free(&lookpn);        return (error);}/* * Starting at current directory, translate pathname pnp to end. * Leave pathname of final component in pnp, return the vnode * for the final component in *compvpp, and return the vnode * for the parent of the final component in dirvpp. * * This is the central routine in pathname translation and handles * multiple components in pathnames, separating them at /'s.  It also * implements mounted file systems and processes symbolic links. */lookuppn(pnp, followlink, dirvpp, compvpp)        register struct pathname *pnp;          /* pathaname to lookup */        enum symfollow followlink;              /* (don't) follow sym links */        struct vnode **dirvpp;                  /* ptr for parent vnode */        struct vnode **compvpp;                 /* ptr for entry vnode */{        register struct vnode *vp;              /* current directory vp */        register struct vnode *cvp;             /* current component vp */	struct vnode *tvp;                      /* non-reg temp ptr */        char component[MAXNAMLEN+1];            /* buffer for component */        register int error;        register int nlink;        nlink = 0;        cvp = (struct vnode *)0;        /*         * start at current directory.         */        vp = u.u_cdir;        VN_HOLD(vp);	/*	 * This is a 'toy' version of lookuppn, which assumes a	 * single-element filename starting in the current	 * directory, which is always, in this version, the	 * root directory.   We assume on entry that u.u_cdir	 * does indeed point ot the root vnode.	 */#ifdef	NFSDEBUG	dprint(nfsdebug, 6, "lookuppn: u_rdir 0x%x\n", u.u_rdir);#endif	NFSDEBUGbegin:        /*         * Each time we begin a new name interpretation (e.g.         * when first called and after each symbolic link is         * substituted), we allow the search to start at the         * root directory if the name starts with a '/', otherwise         * continuing from the current directory.         */        component[0] = 0;        if (pn_peekchar(pnp) == '/') {#ifdef	NFSDEBUG		dprint(nfsdebug, 6, "lookuppn: unnecessary /\n");#endif	NFSDEBUG                VN_RELE(vp);                pn_skipslash(pnp);                if (u.u_rdir)                        vp = u.u_rdir;                else                        vp = rootdir;                VN_HOLD(vp);        }next:        /*         * Make sure we have a directory.         */        if (vp->v_type != VDIR) {#ifdef	NFSDEBUG		dprint(nfsdebug, 10, "lookuppn: not directory 0x%x type 0x%x\n",			vp, vp->v_type);#endif	NFSDEBUG                error = ENOTDIR;                goto bad;        }	/*         * Process the next component of the pathname.         */        error = pn_getcomponent(pnp, component);        if (error)                goto bad;#ifdef	NFSDEBUG	dprint(nfsdebug, 6, "lookuppn: component '%s'\n", component);#endif	NFSDEBUG	/*         * Check for degenerate name (e.g. / or "")         * which is a way of talking about a directory,         * e.g. "/." or ".".         */        if (component[0] == 0) {#ifdef	NFSDEBUG		dprint(nfsdebug, 6, "lookuppn: null name\n");#endif	NFSDEBUG		/*                 * If the caller was interested in the parent then                 * return an error since we don't have the real parent                 */		if (dirvpp != (struct vnode **)0) {#ifdef	NFSDEBUG			dprint(nfsdebug, 10,				"lookuppn: no parent!\n");#endif	NFSDEBUG                        VN_RELE(vp);                        return(EINVAL);                }                (void) pn_set(pnp, ".");                if (compvpp != (struct vnode **)0) {                        *compvpp = vp;#ifdef	NFSDEBUG			dprint(nfsdebug, 6,				"lookuppn: compvpp 0x%x\n", *compvpp);#endif	NFSDEBUG                } else {#ifdef	NFSDEBUG			dprint(nfsdebug, 10,				"lookuppn: vacuous\n");#endif	NFSDEBUG                        VN_RELE(vp);                }		return(0);	}	/*         * Handle "..": two special cases.         * 1. If at root directory (e.g. after chroot)         *    then ignore it so can't get out.         * 2. If this vnode is the root of a mounted         *    file system, then replace it with the         *    vnode which was mounted on so we take the         *    .. in the other file system.         */        if (strcmp(component, "..") == 0) {checkforroot:                if ((vp == u.u_rdir) || (vp == rootdir)) {                        cvp = vp;                        VN_HOLD(cvp);                        goto skip;                }                if (vp->v_flag & VROOT) {                        cvp = vp;                        vp = vp->v_vfsp->vfs_vnodecovered;                        VN_HOLD(vp);                        VN_RELE(cvp);                        cvp = (struct vnode *)0;                        goto checkforroot;                }	}	/*         * Perform a lookup in the current directory.         */	error = VOP_LOOKUP(vp, component, &tvp, u.u_cred);        cvp = tvp;        if (error) {		if (error != ENOENT)#ifdef	NFSDEBUG			dprint(nfsdebug, 10, "lookuppn: lookup error 0x%x\n", error);#endif	NFSDEBUG                cvp = (struct vnode *)0;		goto bad;	}	/*         * If we hit a symbolic link and there is more path to be         * translated or this operation does not wish to apply         * to a link, then place the contents of the link at the         * front of the remaining pathname.         */        if (cvp->v_type == VLNK &&            ((followlink == FOLLOW_LINK) || pn_pathleft(pnp))) {                struct pathname linkpath;                 nlink++;                if (nlink > MAXSYMLINKS) {                        error = ELOOP;                        goto bad;                }                error = getsymlink(cvp, &linkpath);                if (error)                        goto bad;                if (pn_pathleft(&linkpath) == 0)                        (void) pn_set(&linkpath, ".");                error = pn_combine(pnp, &linkpath);     /* linkpath before pn */                pn_free(&linkpath);                if (error)                        goto bad;                VN_RELE(cvp);                cvp = (struct vnode *)0;                goto begin;        }skip:        /*         * Skip to next component of the pathname.         * If no more components, return last directory (if wanted)  and         * last component (if wanted).         */        if (pn_pathleft(pnp) == 0) {                (void) pn_set(pnp, component);                if (dirvpp != (struct vnode **)0) {                        /*                         * check that we have the real parent and not                         * an alias of the last component                         */                        if (vp == cvp) {                                VN_RELE(vp);                                VN_RELE(cvp);#ifdef	NFSDEBUG				dprint(nfsdebug, 0, "lookuppn: EINVAL\n");#endif	NFSDEBUG                                return(EINVAL);                        }                        *dirvpp = vp;                } else {                        VN_RELE(vp);                }                if (compvpp != (struct vnode **)0) {                        *compvpp = cvp;                } else {                        VN_RELE(cvp);                }#ifdef	NFSDEBUG		dprint(nfsdebug, 6, "lookuppn: normal return\n");#endif	/* NFSDEBUG */                return (0);        }        /*         * skip over slashes from end of last component         */        pn_skipslash(pnp);                 /*         * Searched through another level of directory:         * release previous directory handle and save new (result         * of lookup) as current directory.         */        VN_RELE(vp);        vp = cvp;        cvp = (struct vnode *)0;        goto next; bad:        /*         * Error. Release vnodes and return.         */	if (error != ENOENT)#ifdef	NFSDEBUG		dprint(nfsdebug, 10, "lookuppn: error 0x%x\n", error);#endif	NFSDEBUG        if (cvp)                VN_RELE(cvp);        VN_RELE(vp);        return (error);}/* * Gets symbolic link into pathname. */static intgetsymlink(vp, pnp)        struct vnode *vp;        struct pathname *pnp;{        struct iovec aiov;        struct uio auio;        register int error;#ifdef	 NFSDEBUG	dprint(nfsdebug, 6, "getsymlink(vp, pnp)\n", vp, pnp);#endif	 /* NFSDEBUG */        pn_alloc(pnp);        aiov.iov_base = pnp->pn_buf;        aiov.iov_len = MAXPATHLEN;        auio.uio_iov = &aiov;        auio.uio_iovcnt = 1;        auio.uio_offset = 0;        auio.uio_seg = UIOSEG_KERNEL;        auio.uio_resid = MAXPATHLEN;        error = VOP_READLINK(vp, &auio, u.u_cred);        if (error)                pn_free(pnp);        pnp->pn_pathlen = MAXPATHLEN - auio.uio_resid;#ifdef	 NFSDEBUG	dprint(nfsdebug, 6, "getsymlink: error 0x%x\n", error);#endif	 /* NFSDEBUG */        return (error);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?