Module Name:    src
Committed By:   dholland
Date:           Mon Apr 11 01:37:43 UTC 2011

Modified Files:
        src/sys/kern: vfs_lookup.c

Log Message:
ZZmsg


To generate a diff of this commit:
cvs rdiff -u -r1.138 -r1.139 src/sys/kern/vfs_lookup.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/vfs_lookup.c
diff -u src/sys/kern/vfs_lookup.c:1.138 src/sys/kern/vfs_lookup.c:1.139
--- src/sys/kern/vfs_lookup.c:1.138	Mon Apr 11 01:37:14 2011
+++ src/sys/kern/vfs_lookup.c	Mon Apr 11 01:37:43 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.138 2011/04/11 01:37:14 dholland Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.139 2011/04/11 01:37:43 dholland Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.138 2011/04/11 01:37:14 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.139 2011/04/11 01:37:43 dholland Exp $");
 
 #include "opt_magiclinks.h"
 
@@ -415,7 +415,6 @@
 	int slashes;
 
 	unsigned attempt_retry:1;	/* true if error allows emul retry */
-	unsigned lookup_terminal:1;	/* flag returned from lookup */
 };
 
 
@@ -641,7 +640,8 @@
 static inline int
 namei_atsymlink(struct namei_state *state)
 {
-	return (state->cnp->cn_flags & ISSYMLINK) != 0;
+	return (state->dp->v_type == VLNK) &&
+		(state->cnp->cn_flags & (FOLLOW|REQUIREDIR));
 }
 
 /*
@@ -775,67 +775,6 @@
  *	    if LOCKPARENT set, return locked parent in ni_dvp
  */
 
-/*
- * Begin lookup().
- */
-static int
-lookup_start(struct namei_state *state, struct vnode *startdir)
-{
-	const char *cp;			/* pointer into pathname argument */
-
-	struct componentname *cnp = state->cnp;
-	struct nameidata *ndp = state->ndp;
-
-	KASSERT(cnp == &ndp->ni_cnd);
-
-	state->lookup_alldone = 0;
-	state->dp = NULL;
-
-	/*
-	 * Setup: break out flag bits into variables.
-	 */
-	state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
-	if (cnp->cn_nameiop == DELETE)
-		state->docache = 0;
-	state->rdonly = cnp->cn_flags & RDONLY;
-	ndp->ni_dvp = NULL;
-	cnp->cn_flags &= ~ISSYMLINK;
-	state->dp = startdir;
-
-	/*
-	 * If we have a leading string of slashes, remove them, and just make
-	 * sure the current node is a directory.
-	 */
-	cp = cnp->cn_nameptr;
-	if (*cp == '/') {
-		do {
-			cp++;
-		} while (*cp == '/');
-		ndp->ni_pathlen -= cp - cnp->cn_nameptr;
-		cnp->cn_nameptr = cp;
-
-		if (state->dp->v_type != VDIR) {
-			vput(state->dp);
-			return ENOTDIR;
-		}
-
-		/*
-		 * If we've exhausted the path name, then just return the
-		 * current node.
-		 */
-		if (cnp->cn_nameptr[0] == '\0') {
-			ndp->ni_vp = state->dp;
-			cnp->cn_flags |= ISLASTCN;
-
-			/* bleh */
-			state->lookup_alldone = 1;
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
 static int
 lookup_parsepath(struct namei_state *state)
 {
@@ -1102,6 +1041,7 @@
 {
 	struct nameidata *ndp = state->ndp;
 	struct componentname *cnp = state->cnp;
+	const char *cp;
 	int error;
 
 	error = namei_start(state, forcecwd);
@@ -1110,8 +1050,17 @@
 	}
 
 	/*
+	 * Setup: break out flag bits into variables.
+	 */
+	state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
+	if (cnp->cn_nameiop == DELETE)
+		state->docache = 0;
+	state->rdonly = cnp->cn_flags & RDONLY;
+
+	/*
 	 * Keep going until we run out of path components.
 	 */
+	cnp->cn_nameptr = ndp->ni_pnbuf;
 	for (;;) {
 
 		/*
@@ -1127,190 +1076,98 @@
 		 * Look up the next path component.
 		 * (currently, this may consume more than one)
 		 */
-		cnp->cn_nameptr = ndp->ni_pnbuf;
-
-		error = lookup_start(state, state->namei_startdir);
-		if (error) {
-			ndp->ni_vp = NULL;
-			return (error);
-		}
 
-		// XXX: this case should not be necessary given proper handling
-		// of slashes elsewhere.
-		if (state->lookup_alldone) {
-			state->lookup_terminal = 1;
-			error = 0;
-		} else {
-
-	    dirloop:
-			error = lookup_parsepath(state);
-			if (error) {
-				state->lookup_terminal = 0;
-				ndp->ni_vp = NULL;
-				goto lookup_out;
-			}
+		state->lookup_alldone = 0;
 
-			error = lookup_once(state);
-			if (error) {
-				state->lookup_terminal = 0;
-				ndp->ni_vp = NULL;
-				goto lookup_out;
-			}
-			// XXX ought to be able to avoid this case too
-			if (state->lookup_alldone) {
-				/* this should NOT set lookup_terminal */
-				state->lookup_terminal = 0;
-				error = 0;
-				goto lookup_out;
-			}
+		ndp->ni_dvp = NULL;
+		cnp->cn_flags &= ~ISSYMLINK;
+		state->dp = state->namei_startdir;
 
-			/*
-			 * Check for symbolic link.  Back up over any
-			 * slashes that we skipped, as we will need
-			 * them again.
-			 */
-			if ((state->dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
-				ndp->ni_pathlen += state->slashes;
-				ndp->ni_next -= state->slashes;
-				cnp->cn_flags |= ISSYMLINK;
-				state->lookup_terminal = 0;
-				error = 0;
-				goto lookup_out;
-			}
+    dirloop:
+		/*
+		 * If we have a leading string of slashes, remove
+		 * them, and just make sure the current node is a
+		 * directory.
+		 */
+		cp = cnp->cn_nameptr;
+		if (*cp == '/') {
+			do {
+				cp++;
+			} while (*cp == '/');
+			ndp->ni_pathlen -= cp - cnp->cn_nameptr;
+			cnp->cn_nameptr = cp;
 
-			/*
-			 * Check for directory, if the component was
-			 * followed by a series of slashes.
-			 */
-			if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
-				error = ENOTDIR;
-				KASSERT(state->dp != ndp->ni_dvp);
+			if (state->dp->v_type != VDIR) {
 				vput(state->dp);
-				state->lookup_terminal = 0;
 				ndp->ni_vp = NULL;
-				goto lookup_out;
-			}
-
-			/*
-			 * Not a symbolic link.  If this was not the
-			 * last component, then continue at the next
-			 * component, else return.
-			 */
-			if (!(cnp->cn_flags & ISLASTCN)) {
-				cnp->cn_nameptr = ndp->ni_next;
-				if (ndp->ni_dvp == state->dp) {
-					vrele(ndp->ni_dvp);
-				} else {
+				/* XXX this should use namei_end() */
+				if (ndp->ni_dvp) {
 					vput(ndp->ni_dvp);
 				}
-				goto dirloop;
+				state->attempt_retry = 1;
+				return ENOTDIR;
 			}
+		}
 
-			state->lookup_terminal = 1;
-			error = 0;
-			goto lookup_out;
-	    lookup_out:
-			;
+		/*
+		 * If we've exhausted the path name, then just return the
+		 * current node.
+		 */
+		if (cnp->cn_nameptr[0] == '\0') {
+			ndp->ni_vp = state->dp;
+			cnp->cn_flags |= ISLASTCN;
+
+			/* bleh */
+			goto terminal;
 		}
-		if (error != 0) {
+
+		error = lookup_parsepath(state);
+		if (error) {
+			ndp->ni_vp = NULL;
 			/* XXX this should use namei_end() */
 			if (ndp->ni_dvp) {
 				vput(ndp->ni_dvp);
 			}
-			/*
-			 * Note that if we're doing TRYEMULROOT we can
-			 * retry with the normal root. Setting this
-			 * here matches previous practice, but the
-			 * previous practice didn't make much sense
-			 * and somebody should sit down and figure out
-			 * which cases should cause retry and which
-			 * shouldn't. XXX.
-			 */
 			state->attempt_retry = 1;
 			return (error);
 		}
-		if (state->lookup_terminal) {
 
-			if (state->dp == ndp->ni_erootdir) {
-				/*
-				 * We are about to return the
-				 * emulation root.  This isn't a good
-				 * idea because code might repeatedly
-				 * lookup ".." until the file matches
-				 * that returned for "/" and loop
-				 * forever.  So convert it to the real
-				 * root.
-				 */
-				if (ndp->ni_dvp == state->dp)
-					vrele(state->dp);
-				else
-					if (ndp->ni_dvp != NULL)
-						vput(ndp->ni_dvp);
-				ndp->ni_dvp = NULL;
-				vput(state->dp);
-				state->dp = ndp->ni_rootdir;
-				vref(state->dp);
-				vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
-				ndp->ni_vp = state->dp;
-			}
-
-			/*
-			 * If the caller requested the parent node
-			 * (i.e.  it's a CREATE, DELETE, or RENAME),
-			 * and we don't have one (because this is the
-			 * root directory), then we must fail.
-			 */
-			if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
-				switch (cnp->cn_nameiop) {
-				    case CREATE:
-					error = EEXIST;
-					break;
-				    case DELETE:
-				    case RENAME:
-					error = EBUSY;
-					break;
-				    default:
-					KASSERT(0);
-				}
-				vput(state->dp);
-				ndp->ni_vp = NULL;
-				goto lookup_terminal_fail;
+		error = lookup_once(state);
+		if (error) {
+			ndp->ni_vp = NULL;
+			/* XXX this should use namei_end() */
+			if (ndp->ni_dvp) {
+				vput(ndp->ni_dvp);
 			}
-
 			/*
-			 * Disallow directory write attempts on
-			 * read-only lookups. Prefers EEXIST over
-			 * EROFS for the CREATE case.
+			 * Note that if we're doing TRYEMULROOT we can
+			 * retry with the normal root. Where this is
+			 * currently set matches previous practice,
+			 * but the previous practice didn't make much
+			 * sense and somebody should sit down and
+			 * figure out which cases should cause retry
+			 * and which shouldn't. XXX.
 			 */
-			if (state->rdonly &&
-			    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
-				error = EROFS;
-				if (state->dp != ndp->ni_dvp) {
-					vput(state->dp);
-				}
-				ndp->ni_vp = NULL;
-				goto lookup_terminal_fail;
-			}
-			if ((cnp->cn_flags & LOCKLEAF) == 0) {
-				VOP_UNLOCK(state->dp);
-			}
-
-			if (0) {
-		    lookup_terminal_fail:
-				/* XXX this should use namei_end() */
-				if (ndp->ni_dvp) {
-					vput(ndp->ni_dvp);
-				}
-				state->attempt_retry = 1;
-				return (error);
-			}
+			state->attempt_retry = 1;
+			return (error);
+		}
+		// XXX ought to be able to avoid this case too
+		if (state->lookup_alldone) {
+			error = 0;
+			/* break out of main loop */
+			break;
 		}
 
 		/*
-		 * If we've reached a symbolic link, follow it, unless we
-		 * aren't supposed to.
+		 * Check for symbolic link. If we've reached one,
+		 * follow it, unless we aren't supposed to. Back up
+		 * over any slashes that we skipped, as we will need
+		 * them again.
 		 */
 		if (namei_atsymlink(state)) {
+			ndp->ni_pathlen += state->slashes;
+			ndp->ni_next -= state->slashes;
+			cnp->cn_flags |= ISSYMLINK;
 			if (neverfollow) {
 				error = EINVAL;
 			} else {
@@ -1323,10 +1180,116 @@
 				ndp->ni_vp = NULL;
 				return error;
 			}
+			cnp->cn_nameptr = ndp->ni_pnbuf;
+			continue;
 		}
-		else {
-			break;
+
+		/*
+		 * Check for directory, if the component was
+		 * followed by a series of slashes.
+		 */
+		if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
+			KASSERT(state->dp != ndp->ni_dvp);
+			vput(state->dp);
+			ndp->ni_vp = NULL;
+			/* XXX this should use namei_end() */
+			if (ndp->ni_dvp) {
+				vput(ndp->ni_dvp);
+			}
+			state->attempt_retry = 1;
+			return ENOTDIR;
+		}
+
+		/*
+		 * Not a symbolic link.  If this was not the
+		 * last component, then continue at the next
+		 * component, else return.
+		 */
+		if (!(cnp->cn_flags & ISLASTCN)) {
+			cnp->cn_nameptr = ndp->ni_next;
+			if (ndp->ni_dvp == state->dp) {
+				vrele(ndp->ni_dvp);
+			} else {
+				vput(ndp->ni_dvp);
+			}
+			ndp->ni_dvp = NULL;
+			goto dirloop;
+		}
+
+    terminal:
+		error = 0;
+		if (state->dp == ndp->ni_erootdir) {
+			/*
+			 * We are about to return the emulation root.
+			 * This isn't a good idea because code might
+			 * repeatedly lookup ".." until the file
+			 * matches that returned for "/" and loop
+			 * forever.  So convert it to the real root.
+			 */
+			if (ndp->ni_dvp == state->dp)
+				vrele(state->dp);
+			else
+				if (ndp->ni_dvp != NULL)
+					vput(ndp->ni_dvp);
+			ndp->ni_dvp = NULL;
+			vput(state->dp);
+			state->dp = ndp->ni_rootdir;
+			vref(state->dp);
+			vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+			ndp->ni_vp = state->dp;
 		}
+
+		/*
+		 * If the caller requested the parent node
+		 * (i.e.  it's a CREATE, DELETE, or RENAME),
+		 * and we don't have one (because this is the
+		 * root directory), then we must fail.
+		 */
+		if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
+			switch (cnp->cn_nameiop) {
+			    case CREATE:
+				error = EEXIST;
+				break;
+			    case DELETE:
+			    case RENAME:
+				error = EBUSY;
+				break;
+			    default:
+				KASSERT(0);
+			}
+			vput(state->dp);
+			ndp->ni_vp = NULL;
+			/* XXX this should use namei_end() */
+			if (ndp->ni_dvp) {
+				vput(ndp->ni_dvp);
+			}
+			state->attempt_retry = 1;
+			return (error);
+		}
+
+		/*
+		 * Disallow directory write attempts on read-only lookups.
+		 * Prefers EEXIST over EROFS for the CREATE case.
+		 */
+		if (state->rdonly &&
+		    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
+			error = EROFS;
+			if (state->dp != ndp->ni_dvp) {
+				vput(state->dp);
+			}
+			ndp->ni_vp = NULL;
+			/* XXX this should use namei_end() */
+			if (ndp->ni_dvp) {
+				vput(ndp->ni_dvp);
+			}
+			state->attempt_retry = 1;
+			return (error);
+		}
+		if ((cnp->cn_flags & LOCKLEAF) == 0) {
+			VOP_UNLOCK(state->dp);
+		}
+
+		break;
 	}
 
 	/*

Reply via email to