xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 31650)
123401Smckusick /*
229119Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323401Smckusick  * All rights reserved.  The Berkeley software License Agreement
423401Smckusick  * specifies the terms and conditions for redistribution.
523401Smckusick  *
6*31650Smckusick  *	@(#)vfs_lookup.c	7.3 (Berkeley) 06/20/87
723401Smckusick  */
830Sbill 
917100Sbloom #include "param.h"
1017100Sbloom #include "systm.h"
1117100Sbloom #include "inode.h"
1217100Sbloom #include "fs.h"
1317100Sbloom #include "mount.h"
1417100Sbloom #include "dir.h"
1517100Sbloom #include "user.h"
1617100Sbloom #include "buf.h"
1717100Sbloom #include "conf.h"
1817100Sbloom #include "uio.h"
1917100Sbloom #include "kernel.h"
20*31650Smckusick #include "malloc.h"
2130Sbill 
227605Ssam struct	buf *blkatoff();
239166Ssam int	dirchk = 0;
2415798Smckusick 
2530Sbill /*
2615798Smckusick  * Structures associated with name cacheing.
2715798Smckusick  */
2815798Smckusick #define	NCHHASH		32	/* size of hash table */
2915798Smckusick 
3015798Smckusick #if	((NCHHASH)&((NCHHASH)-1)) != 0
3115798Smckusick #define	NHASH(h, i, d)	((unsigned)((h) + (i) + 13 * (int)(d)) % (NCHHASH))
3215798Smckusick #else
3315798Smckusick #define	NHASH(h, i, d)	((unsigned)((h) + (i) + 13 * (int)(d)) & ((NCHHASH)-1))
3415798Smckusick #endif
3515798Smckusick 
3626273Skarels union nchash {
3726273Skarels 	union	nchash *nch_head[2];
3826306Skarels 	struct	namecache *nch_chain[2];
3915798Smckusick } nchash[NCHHASH];
4015798Smckusick #define	nch_forw	nch_chain[0]
4115798Smckusick #define	nch_back	nch_chain[1]
4215798Smckusick 
4326306Skarels struct	namecache *nchhead, **nchtail;	/* LRU chain pointers */
4415809Smckusick struct	nchstats nchstats;		/* cache effectiveness statistics */
4515798Smckusick 
4615798Smckusick /*
4727268Smckusick  * Convert a pathname into a pointer to a locked inode.
487534Sroot  * This is a very central and rather complicated routine.
4927268Smckusick  * If the file system is not maintained in a strict tree hierarchy,
5027268Smckusick  * this can result in a deadlock situation (see comments in code below).
5130Sbill  *
5227268Smckusick  * The flag argument is LOOKUP, CREATE, or DELETE depending on whether
5327268Smckusick  * the name is to be looked up, created, or deleted. When CREATE or
5427268Smckusick  * DELETE is specified, information usable in creating or deleteing a
5527268Smckusick  * directory entry is also calculated. If flag has LOCKPARENT or'ed
5627268Smckusick  * into it and the target of the pathname exists, namei returns both
5727268Smckusick  * the target and its parent directory locked. When creating and
589166Ssam  * LOCKPARENT is specified, the target may not be ".".  When deleting
599166Ssam  * and LOCKPARENT is specified, the target may be ".", but the caller
609166Ssam  * must check to insure it does an irele and iput instead of two iputs.
619166Ssam  *
6216688Smckusick  * The FOLLOW flag is set when symbolic links are to be followed
639166Ssam  * when they occur at the end of the name translation process.
6427268Smckusick  * Symbolic links are always followed for all other pathname
6527268Smckusick  * components other than the last.
669166Ssam  *
6727268Smckusick  * The segflg defines whether the name is to be copied from user
6827268Smckusick  * space or kernel space.
6927268Smckusick  *
7015798Smckusick  * Name caching works as follows:
717534Sroot  *
7226273Skarels  * Names found by directory scans are retained in a cache
7326273Skarels  * for future reference.  It is managed LRU, so frequently
7426273Skarels  * used names will hang around.  Cache is indexed by hash value
7526273Skarels  * obtained from (ino,dev,name) where ino & dev refer to the
7626273Skarels  * directory containing name.
7715798Smckusick  *
7826273Skarels  * For simplicity (and economy of storage), names longer than
7927268Smckusick  * a maximum length of NCHNAMLEN are not cached; they occur
8026273Skarels  * infrequently in any case, and are almost never of interest.
8115798Smckusick  *
8226273Skarels  * Upon reaching the last segment of a path, if the reference
8326273Skarels  * is for DELETE, or NOCACHE is set (rewrite), and the
8426273Skarels  * name is located in the cache, it will be dropped.
8515798Smckusick  *
8615798Smckusick  * Overall outline of namei:
8715798Smckusick  *
887534Sroot  *	copy in name
897534Sroot  *	get starting directory
907534Sroot  * dirloop:
917534Sroot  *	check accessibility of directory
927534Sroot  * dirloop2:
9316688Smckusick  *	copy next component of name to ndp->ni_dent
947534Sroot  *	handle degenerate case where name is null string
9515798Smckusick  *	look for name in cache, if found, then if at end of path
9615798Smckusick  *	  and deleting or creating, drop it, else to haveino
977534Sroot  *	search for name in directory, to found or notfound
987534Sroot  * notfound:
999166Ssam  *	if creating, return locked directory, leaving info on avail. slots
1007534Sroot  *	else return error
1017534Sroot  * found:
1027534Sroot  *	if at end of path and deleting, return information to allow delete
10327268Smckusick  *	if at end of path and rewriting (CREATE and LOCKPARENT), lock target
1049166Ssam  *	  inode and return info to allow rewrite
1057534Sroot  *	if .. and on mounted filesys, look in mount table for parent
10627268Smckusick  *	if not at end, add name to cache; if at end and neither creating
10727268Smckusick  *	  nor deleting, add name to cache
10815798Smckusick  * haveino:
1097534Sroot  *	if symbolic link, massage name in buffer and continue at dirloop
1107534Sroot  *	if more components of name, do next level at dirloop
1117534Sroot  *	return the answer as locked inode
1129166Ssam  *
1139166Ssam  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode,
1149166Ssam  *	 but unlocked.
11530Sbill  */
11630Sbill struct inode *
11716688Smckusick namei(ndp)
11816688Smckusick 	register struct nameidata *ndp;
11930Sbill {
1207534Sroot 	register char *cp;		/* pointer into pathname argument */
1217534Sroot /* these variables refer to things which must be freed or unlocked */
1227534Sroot 	register struct inode *dp = 0;	/* the directory we are searching */
12326306Skarels 	register struct namecache *ncp;	/* cache slot for entry */
1247534Sroot 	register struct fs *fs;		/* file system that directory is in */
1257534Sroot 	register struct buf *bp = 0;	/* a buffer of directory entries */
1267534Sroot 	register struct direct *ep;	/* the current directory entry */
1277534Sroot 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
128*31650Smckusick 	register caddr_t nbp;		/* buffer storing path name argument */
1297534Sroot /* these variables hold information about the search for a slot */
1307534Sroot 	enum {NONE, COMPACT, FOUND} slotstatus;
1317534Sroot 	int slotoffset = -1;		/* offset of area with free space */
1327534Sroot 	int slotsize;			/* size of area at slotoffset */
1337534Sroot 	int slotfreespace;		/* amount of space free in slot */
1347534Sroot 	int slotneeded;			/* size of the entry we're seeking */
1357534Sroot /* */
13615660Smckusick 	int numdirpasses;		/* strategy for directory search */
13715660Smckusick 	int endsearch;			/* offset to end directory search */
13816688Smckusick 	int prevoff;			/* ndp->ni_offset of previous entry */
1397534Sroot 	int nlink = 0;			/* number of symbolic links taken */
1407534Sroot 	struct inode *pdp;		/* saved dp during symlink work */
14116688Smckusick 	int error, i;
1429166Ssam 	int lockparent;
14318109Smckusick 	int docache;			/* == 0 do not cache last component */
14418109Smckusick 	int makeentry;			/* != 0 if name to be added to cache */
14515798Smckusick 	unsigned hash;			/* value of name hash for entry */
14615798Smckusick 	union nchash *nhp;		/* cache chain head for entry */
14715798Smckusick 	int isdotdot;			/* != 0 if current name is ".." */
14816688Smckusick 	int flag;			/* op ie, LOOKUP, CREATE, or DELETE */
14918027Smckusick 	off_t enduseful;		/* pointer past last used dir slot */
15030Sbill 
15116688Smckusick 	lockparent = ndp->ni_nameiop & LOCKPARENT;
15216688Smckusick 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
15316688Smckusick 	flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW);
15418109Smckusick 	if (flag == DELETE || lockparent)
15515798Smckusick 		docache = 0;
15630Sbill 	/*
1577534Sroot 	 * Get a buffer for the name to be translated, and copy the
1587534Sroot 	 * name into the buffer.
1595972Swnj 	 */
160*31650Smckusick 	MALLOC(nbp, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
16116688Smckusick 	if (ndp->ni_segflg == UIO_SYSSPACE)
162*31650Smckusick 		error = copystr(ndp->ni_dirp, nbp, MAXPATHLEN, (u_int *)0);
16316688Smckusick 	else
164*31650Smckusick 		error = copyinstr(ndp->ni_dirp, nbp, MAXPATHLEN, (u_int *)0);
16516688Smckusick 	if (error) {
16616688Smckusick 		u.u_error = error;
16716688Smckusick 		goto bad;
1685972Swnj 	}
1697534Sroot 
1705972Swnj 	/*
1717534Sroot 	 * Get starting directory.
17230Sbill 	 */
173*31650Smckusick 	cp = nbp;
1745972Swnj 	if (*cp == '/') {
1755972Swnj 		while (*cp == '/')
1765972Swnj 			cp++;
17730Sbill 		if ((dp = u.u_rdir) == NULL)
17830Sbill 			dp = rootdir;
1797534Sroot 	} else
1807534Sroot 		dp = u.u_cdir;
1817534Sroot 	fs = dp->i_fs;
18216666Smckusick 	ILOCK(dp);
1835972Swnj 	dp->i_count++;
18416688Smckusick 	ndp->ni_pdir = (struct inode *)0xc0000000;		/* illegal */
18518027Smckusick 	ndp->ni_endoff = 0;
1867534Sroot 
1877534Sroot 	/*
1887534Sroot 	 * We come to dirloop to search a new directory.
1897534Sroot 	 * The directory must be locked so that it can be
1907534Sroot 	 * iput, and fs must be already set to dp->i_fs.
1917534Sroot 	 */
1926571Smckusic dirloop:
19330Sbill 	/*
1947534Sroot 	 * Check accessiblity of directory.
19530Sbill 	 */
1967534Sroot 	if ((dp->i_mode&IFMT) != IFDIR) {
19730Sbill 		u.u_error = ENOTDIR;
1987534Sroot 		goto bad;
1997534Sroot 	}
2007534Sroot 	if (access(dp, IEXEC))
2017534Sroot 		goto bad;
2027534Sroot 
2036384Swnj dirloop2:
2047534Sroot 	/*
20516688Smckusick 	 * Copy next component of name to ndp->ni_dent.
2067534Sroot 	 */
20715798Smckusick 	hash = 0;
2087534Sroot 	for (i = 0; *cp != 0 && *cp != '/'; cp++) {
2096571Smckusic 		if (i >= MAXNAMLEN) {
21021014Smckusick 			u.u_error = ENAMETOOLONG;
2117534Sroot 			goto bad;
2125972Swnj 		}
21321014Smckusick 		if (*cp & 0200)
21421014Smckusick 			if ((*cp&0377) == ('/'|0200) || flag != DELETE) {
21521014Smckusick 				u.u_error = EINVAL;
21621014Smckusick 				goto bad;
21721014Smckusick 			}
21816688Smckusick 		ndp->ni_dent.d_name[i++] = *cp;
21915798Smckusick 		hash += (unsigned char)*cp * i;
2205972Swnj 	}
22116688Smckusick 	ndp->ni_dent.d_namlen = i;
22216688Smckusick 	ndp->ni_dent.d_name[i] = '\0';
22316658Smckusick 	isdotdot = (i == 2 &&
22416688Smckusick 		ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.');
22518109Smckusick 	makeentry = 1;
22618109Smckusick 	if (*cp == '\0' && docache == 0)
22718109Smckusick 		makeentry = 0;
2287534Sroot 
2297534Sroot 	/*
2307534Sroot 	 * Check for degenerate name (e.g. / or "")
2317534Sroot 	 * which is a way of talking about a directory,
2327534Sroot 	 * e.g. like "/." or ".".
2337534Sroot 	 */
23416688Smckusick 	if (ndp->ni_dent.d_name[0] == '\0') {
23515798Smckusick 		if (flag != LOOKUP || lockparent) {
23614937Smckusick 			u.u_error = EISDIR;
2377534Sroot 			goto bad;
2385972Swnj 		}
239*31650Smckusick 		FREE(nbp, M_NAMEI);
2406571Smckusic 		return (dp);
2415972Swnj 	}
2427534Sroot 
2436571Smckusic 	/*
24415798Smckusick 	 * We now have a segment name to search for, and a directory to search.
24515798Smckusick 	 *
24615798Smckusick 	 * Before tediously performing a linear scan of the directory,
24715798Smckusick 	 * check the name cache to see if the directory/name pair
24815798Smckusick 	 * we are looking for is known already.  We don't do this
24915798Smckusick 	 * if the segment name is long, simply so the cache can avoid
25015798Smckusick 	 * holding long names (which would either waste space, or
25115798Smckusick 	 * add greatly to the complexity).
25215798Smckusick 	 */
25316688Smckusick 	if (ndp->ni_dent.d_namlen > NCHNAMLEN) {
25415798Smckusick 		nchstats.ncs_long++;
25518109Smckusick 		makeentry = 0;
25615798Smckusick 	} else {
25715798Smckusick 		nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)];
25826306Skarels 		for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp;
25915798Smckusick 		    ncp = ncp->nc_forw) {
26015798Smckusick 			if (ncp->nc_ino == dp->i_number &&
26115798Smckusick 			    ncp->nc_dev == dp->i_dev &&
26216688Smckusick 			    ncp->nc_nlen == ndp->ni_dent.d_namlen &&
26316688Smckusick 			    !bcmp(ncp->nc_name, ndp->ni_dent.d_name,
26426273Skarels 				(unsigned)ncp->nc_nlen))
26515798Smckusick 				break;
26615798Smckusick 		}
26726306Skarels 		if (ncp == (struct namecache *)nhp) {
26815798Smckusick 			nchstats.ncs_miss++;
26915798Smckusick 			ncp = NULL;
27015798Smckusick 		} else {
27126306Skarels 			if (ncp->nc_id != ncp->nc_ip->i_id)
27216643Ssam 				nchstats.ncs_falsehits++;
27326306Skarels 			else if (!makeentry)
27416658Smckusick 				nchstats.ncs_badhits++;
27526306Skarels 			else {
27626273Skarels 				/*
27726273Skarels 				 * move this slot to end of LRU
27826273Skarels 				 * chain, if not already there
27926273Skarels 				 */
28015798Smckusick 				if (ncp->nc_nxt) {
28126273Skarels 					/* remove from LRU chain */
28215798Smckusick 					*ncp->nc_prev = ncp->nc_nxt;
28315798Smckusick 					ncp->nc_nxt->nc_prev = ncp->nc_prev;
28415798Smckusick 
28526273Skarels 					/* and replace at end of it */
28615798Smckusick 					ncp->nc_nxt = NULL;
28715798Smckusick 					ncp->nc_prev = nchtail;
28815798Smckusick 					*nchtail = ncp;
28915798Smckusick 					nchtail = &ncp->nc_nxt;
29015798Smckusick 				}
29115798Smckusick 
29216658Smckusick 				/*
29316658Smckusick 				 * Get the next inode in the path.
29416666Smckusick 				 * See comment above other `IUNLOCK' code for
29516658Smckusick 				 * an explaination of the locking protocol.
29616658Smckusick 				 */
29715798Smckusick 				pdp = dp;
29818109Smckusick 				if (!isdotdot || dp != u.u_rdir)
29918109Smckusick 					dp = ncp->nc_ip;
30015798Smckusick 				if (dp == NULL)
30127693Smckusick 					panic("namei: null cache ino");
30226306Skarels 				if (pdp == dp)
30316643Ssam 					dp->i_count++;
30426306Skarels 				else if (isdotdot) {
30518109Smckusick 					IUNLOCK(pdp);
30618109Smckusick 					igrab(dp);
30718109Smckusick 				} else {
30818109Smckusick 					igrab(dp);
30918109Smckusick 					IUNLOCK(pdp);
31016643Ssam 				}
31115798Smckusick 
31216658Smckusick 				/*
31316658Smckusick 				 * Verify that the inode that we got
31416658Smckusick 				 * did not change while we were waiting
31516658Smckusick 				 * for it to be locked.
31616658Smckusick 				 */
31716658Smckusick 				if (ncp->nc_id != ncp->nc_ip->i_id) {
31816658Smckusick 					iput(dp);
31916666Smckusick 					ILOCK(pdp);
32016658Smckusick 					dp = pdp;
32116658Smckusick 					nchstats.ncs_falsehits++;
32216658Smckusick 				} else {
32316688Smckusick 					ndp->ni_dent.d_ino = dp->i_number;
32416688Smckusick 					/* ni_dent.d_reclen is garbage ... */
32516658Smckusick 					nchstats.ncs_goodhits++;
32616658Smckusick 					goto haveino;
32716658Smckusick 				}
32816658Smckusick 			}
32915798Smckusick 
33015798Smckusick 			/*
33116643Ssam 			 * Last component and we are renaming or deleting,
33216643Ssam 			 * the cache entry is invalid, or otherwise don't
33316643Ssam 			 * want cache entry to exist.
33415798Smckusick 			 */
33526273Skarels 			/* remove from LRU chain */
33615798Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
33715798Smckusick 			if (ncp->nc_nxt)
33815798Smckusick 				ncp->nc_nxt->nc_prev = ncp->nc_prev;
33915798Smckusick 			else
34015798Smckusick 				nchtail = ncp->nc_prev;
34126273Skarels 			remque(ncp);		/* remove from hash chain */
34226273Skarels 			/* insert at head of LRU list (first to grab) */
34315798Smckusick 			ncp->nc_nxt = nchhead;
34415798Smckusick 			ncp->nc_prev = &nchhead;
34515798Smckusick 			nchhead->nc_prev = &ncp->nc_nxt;
34615798Smckusick 			nchhead = ncp;
34726273Skarels 			/* and make a dummy hash chain */
34815798Smckusick 			ncp->nc_forw = ncp;
34915798Smckusick 			ncp->nc_back = ncp;
35015798Smckusick 			ncp = NULL;
35115798Smckusick 		}
35215798Smckusick 	}
35315798Smckusick 
35415798Smckusick 	/*
3557534Sroot 	 * Suppress search for slots unless creating
3567534Sroot 	 * file and at end of pathname, in which case
3577534Sroot 	 * we watch for a place to put the new file in
3587534Sroot 	 * case it doesn't already exist.
3596571Smckusic 	 */
3607534Sroot 	slotstatus = FOUND;
3619166Ssam 	if (flag == CREATE && *cp == 0) {
3627534Sroot 		slotstatus = NONE;
3637534Sroot 		slotfreespace = 0;
36416688Smckusick 		slotneeded = DIRSIZ(&ndp->ni_dent);
3657534Sroot 	}
36615660Smckusick 	/*
36715660Smckusick 	 * If this is the same directory that this process
36815660Smckusick 	 * previously searched, pick up where we last left off.
36915798Smckusick 	 * We cache only lookups as these are the most common
37015660Smckusick 	 * and have the greatest payoff. Caching CREATE has little
37115660Smckusick 	 * benefit as it usually must search the entire directory
37215660Smckusick 	 * to determine that the entry does not exist. Caching the
37315660Smckusick 	 * location of the last DELETE has not reduced profiling time
37415660Smckusick 	 * and hence has been removed in the interest of simplicity.
37515660Smckusick 	 */
37615660Smckusick 	if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber ||
37715660Smckusick 	    dp->i_dev != u.u_ncache.nc_dev) {
37816688Smckusick 		ndp->ni_offset = 0;
37915660Smckusick 		numdirpasses = 1;
38015660Smckusick 	} else {
38127693Smckusick 		if (u.u_ncache.nc_prevoffset > dp->i_size)
38227693Smckusick 			u.u_ncache.nc_prevoffset = 0;
38316688Smckusick 		ndp->ni_offset = u.u_ncache.nc_prevoffset;
38416688Smckusick 		entryoffsetinblock = blkoff(fs, ndp->ni_offset);
38515660Smckusick 		if (entryoffsetinblock != 0) {
38616688Smckusick 			bp = blkatoff(dp, ndp->ni_offset, (char **)0);
38715660Smckusick 			if (bp == 0)
38815660Smckusick 				goto bad;
38915660Smckusick 		}
39015660Smckusick 		numdirpasses = 2;
39115798Smckusick 		nchstats.ncs_2passes++;
39215660Smckusick 	}
39315660Smckusick 	endsearch = roundup(dp->i_size, DIRBLKSIZ);
39418027Smckusick 	enduseful = 0;
3957534Sroot 
39615660Smckusick searchloop:
39716688Smckusick 	while (ndp->ni_offset < endsearch) {
3985972Swnj 		/*
3995972Swnj 		 * If offset is on a block boundary,
4005972Swnj 		 * read the next directory block.
4015972Swnj 		 * Release previous if it exists.
4025972Swnj 		 */
40316688Smckusick 		if (blkoff(fs, ndp->ni_offset) == 0) {
4045972Swnj 			if (bp != NULL)
4055972Swnj 				brelse(bp);
40616688Smckusick 			bp = blkatoff(dp, ndp->ni_offset, (char **)0);
4077534Sroot 			if (bp == 0)
4087534Sroot 				goto bad;
4097534Sroot 			entryoffsetinblock = 0;
4105972Swnj 		}
4115972Swnj 		/*
4127534Sroot 		 * If still looking for a slot, and at a DIRBLKSIZE
41316657Smckusick 		 * boundary, have to start looking for free space again.
4146571Smckusic 		 */
4157534Sroot 		if (slotstatus == NONE &&
4167534Sroot 		    (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
4177534Sroot 			slotoffset = -1;
4187534Sroot 			slotfreespace = 0;
4197534Sroot 		}
4207534Sroot 		/*
42116657Smckusick 		 * Get pointer to next entry.
42216657Smckusick 		 * Full validation checks are slow, so we only check
42316657Smckusick 		 * enough to insure forward progress through the
42416657Smckusick 		 * directory. Complete checks can be run by patching
42516657Smckusick 		 * "dirchk" to be true.
4267534Sroot 		 */
4277534Sroot 		ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
42826273Skarels 		if (ep->d_reclen == 0 ||
42916657Smckusick 		    dirchk && dirbadentry(ep, entryoffsetinblock)) {
43016688Smckusick 			dirbad(dp, ndp->ni_offset, "mangled entry");
43116657Smckusick 			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
43216688Smckusick 			ndp->ni_offset += i;
4337534Sroot 			entryoffsetinblock += i;
4346571Smckusic 			continue;
4356571Smckusic 		}
4367534Sroot 
4376571Smckusic 		/*
4387534Sroot 		 * If an appropriate sized slot has not yet been found,
4396571Smckusic 		 * check to see if one is available. Also accumulate space
4406571Smckusic 		 * in the current block so that we can determine if
4416571Smckusic 		 * compaction is viable.
4426571Smckusic 		 */
4437534Sroot 		if (slotstatus != FOUND) {
4447534Sroot 			int size = ep->d_reclen;
4457534Sroot 
4466571Smckusic 			if (ep->d_ino != 0)
4476571Smckusic 				size -= DIRSIZ(ep);
4486571Smckusic 			if (size > 0) {
4497534Sroot 				if (size >= slotneeded) {
4507534Sroot 					slotstatus = FOUND;
45116688Smckusick 					slotoffset = ndp->ni_offset;
4527534Sroot 					slotsize = ep->d_reclen;
4537534Sroot 				} else if (slotstatus == NONE) {
4547534Sroot 					slotfreespace += size;
4557534Sroot 					if (slotoffset == -1)
45616688Smckusick 						slotoffset = ndp->ni_offset;
4577534Sroot 					if (slotfreespace >= slotneeded) {
4587534Sroot 						slotstatus = COMPACT;
45916688Smckusick 						slotsize = ndp->ni_offset +
46016688Smckusick 						      ep->d_reclen - slotoffset;
4617534Sroot 					}
4626571Smckusic 				}
4636571Smckusic 			}
4646571Smckusic 		}
4657534Sroot 
4666571Smckusic 		/*
4677534Sroot 		 * Check for a name match.
4685972Swnj 		 */
4697534Sroot 		if (ep->d_ino) {
47016688Smckusick 			if (ep->d_namlen == ndp->ni_dent.d_namlen &&
47116688Smckusick 			    !bcmp(ndp->ni_dent.d_name, ep->d_name,
47226273Skarels 				(unsigned)ep->d_namlen))
4737534Sroot 				goto found;
4747534Sroot 		}
47516688Smckusick 		prevoff = ndp->ni_offset;
47616688Smckusick 		ndp->ni_offset += ep->d_reclen;
4777534Sroot 		entryoffsetinblock += ep->d_reclen;
47818027Smckusick 		if (ep->d_ino)
47918027Smckusick 			enduseful = ndp->ni_offset;
4807534Sroot 	}
48115798Smckusick /* notfound: */
48215660Smckusick 	/*
48315798Smckusick 	 * If we started in the middle of the directory and failed
48415660Smckusick 	 * to find our target, we must check the beginning as well.
48515660Smckusick 	 */
48615660Smckusick 	if (numdirpasses == 2) {
48715660Smckusick 		numdirpasses--;
48816688Smckusick 		ndp->ni_offset = 0;
48915660Smckusick 		endsearch = u.u_ncache.nc_prevoffset;
49015660Smckusick 		goto searchloop;
49115660Smckusick 	}
4927534Sroot 	/*
4937534Sroot 	 * If creating, and at end of pathname and current
4949166Ssam 	 * directory has not been removed, then can consider
4959166Ssam 	 * allowing file to be created.
4967534Sroot 	 */
4979166Ssam 	if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) {
4985972Swnj 		/*
4997534Sroot 		 * Access for write is interpreted as allowing
5007534Sroot 		 * creation of files in the directory.
5015972Swnj 		 */
5027534Sroot 		if (access(dp, IWRITE))
5037534Sroot 			goto bad;
5045972Swnj 		/*
5057534Sroot 		 * Return an indication of where the new directory
5067534Sroot 		 * entry should be put.  If we didn't find a slot,
50716688Smckusick 		 * then set ndp->ni_count to 0 indicating that the new
50816688Smckusick 		 * slot belongs at the end of the directory. If we found
50916688Smckusick 		 * a slot, then the new entry can be put in the range
51016688Smckusick 		 * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count)
5115972Swnj 		 */
51215660Smckusick 		if (slotstatus == NONE) {
51316688Smckusick 			ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ);
51416688Smckusick 			ndp->ni_count = 0;
51518027Smckusick 			enduseful = ndp->ni_offset;
51615660Smckusick 		} else {
51716688Smckusick 			ndp->ni_offset = slotoffset;
51816688Smckusick 			ndp->ni_count = slotsize;
51918027Smckusick 			if (enduseful < slotoffset + slotsize)
52018027Smckusick 				enduseful = slotoffset + slotsize;
5215972Swnj 		}
52218027Smckusick 		ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ);
5237534Sroot 		dp->i_flag |= IUPD|ICHG;
5247534Sroot 		if (bp)
5257534Sroot 			brelse(bp);
526*31650Smckusick 		FREE(nbp, M_NAMEI);
5275972Swnj 		/*
5287534Sroot 		 * We return with the directory locked, so that
5297534Sroot 		 * the parameters we set up above will still be
5307534Sroot 		 * valid if we actually decide to do a direnter().
5317534Sroot 		 * We return NULL to indicate that the entry doesn't
5327534Sroot 		 * currently exist, leaving a pointer to the (locked)
53316688Smckusick 		 * directory inode in ndp->ni_pdir.
5345972Swnj 		 */
53516688Smckusick 		ndp->ni_pdir = dp;
5367534Sroot 		return (NULL);
5377534Sroot 	}
5387534Sroot 	u.u_error = ENOENT;
5397534Sroot 	goto bad;
5407534Sroot found:
54115798Smckusick 	if (numdirpasses == 2)
54215798Smckusick 		nchstats.ncs_pass2++;
5437534Sroot 	/*
5447534Sroot 	 * Check that directory length properly reflects presence
5457534Sroot 	 * of this entry.
5467534Sroot 	 */
5477605Ssam 	if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
54816688Smckusick 		dirbad(dp, ndp->ni_offset, "i_size too small");
5497605Ssam 		dp->i_size = entryoffsetinblock + DIRSIZ(ep);
5507534Sroot 		dp->i_flag |= IUPD|ICHG;
5517534Sroot 	}
5527534Sroot 
5537534Sroot 	/*
55415660Smckusick 	 * Found component in pathname.
55515798Smckusick 	 * If the final component of path name, save information
55615660Smckusick 	 * in the cache as to where the entry was found.
5577534Sroot 	 */
55815660Smckusick 	if (*cp == '\0' && flag == LOOKUP) {
55927693Smckusick 		u.u_ncache.nc_prevoffset = ndp->ni_offset &~ (DIRBLKSIZ - 1);
56015660Smckusick 		u.u_ncache.nc_inumber = dp->i_number;
56115660Smckusick 		u.u_ncache.nc_dev = dp->i_dev;
56215660Smckusick 	}
56315660Smckusick 	/*
56418109Smckusick 	 * Save directory entry's inode number and reclen in ndp->ni_dent,
56515660Smckusick 	 * and release directory buffer.
56615660Smckusick 	 */
56718109Smckusick 	ndp->ni_dent.d_ino = ep->d_ino;
56818109Smckusick 	ndp->ni_dent.d_reclen = ep->d_reclen;
5697534Sroot 	brelse(bp);
5707534Sroot 	bp = NULL;
5717534Sroot 
5727534Sroot 	/*
5737534Sroot 	 * If deleting, and at end of pathname, return
5747534Sroot 	 * parameters which can be used to remove file.
5759166Ssam 	 * If the lockparent flag isn't set, we return only
57616688Smckusick 	 * the directory (in ndp->ni_pdir), otherwise we go
5779166Ssam 	 * on and lock the inode, being careful with ".".
5787534Sroot 	 */
5799166Ssam 	if (flag == DELETE && *cp == 0) {
5807534Sroot 		/*
5817534Sroot 		 * Write access to directory required to delete files.
5827534Sroot 		 */
5837534Sroot 		if (access(dp, IWRITE))
5847534Sroot 			goto bad;
58516688Smckusick 		ndp->ni_pdir = dp;		/* for dirremove() */
5867534Sroot 		/*
58716688Smckusick 		 * Return pointer to current entry in ndp->ni_offset,
5887534Sroot 		 * and distance past previous entry (if there
58916688Smckusick 		 * is a previous entry in this block) in ndp->ni_count.
59016688Smckusick 		 * Save directory inode pointer in ndp->ni_pdir for dirremove().
5917534Sroot 		 */
59216688Smckusick 		if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0)
59316688Smckusick 			ndp->ni_count = 0;
5947534Sroot 		else
59516688Smckusick 			ndp->ni_count = ndp->ni_offset - prevoff;
5969166Ssam 		if (lockparent) {
59716688Smckusick 			if (dp->i_number == ndp->ni_dent.d_ino)
5989166Ssam 				dp->i_count++;
5999166Ssam 			else {
60016688Smckusick 				dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
6019166Ssam 				if (dp == NULL) {
60216688Smckusick 					iput(ndp->ni_pdir);
6039166Ssam 					goto bad;
6049166Ssam 				}
60515798Smckusick 				/*
60616046Skarels 				 * If directory is "sticky", then user must own
60715798Smckusick 				 * the directory, or the file in it, else he
60815798Smckusick 				 * may not delete it (unless he's root). This
60915798Smckusick 				 * implements append-only directories.
61015798Smckusick 				 */
61116688Smckusick 				if ((ndp->ni_pdir->i_mode & ISVTX) &&
61215798Smckusick 				    u.u_uid != 0 &&
61316688Smckusick 				    u.u_uid != ndp->ni_pdir->i_uid &&
61415798Smckusick 				    dp->i_uid != u.u_uid) {
61516688Smckusick 					iput(ndp->ni_pdir);
61615798Smckusick 					u.u_error = EPERM;
61715798Smckusick 					goto bad;
61815798Smckusick 				}
6199166Ssam 			}
6209166Ssam 		}
621*31650Smckusick 		FREE(nbp, M_NAMEI);
6227534Sroot 		return (dp);
6237534Sroot 	}
6247534Sroot 
6257534Sroot 	/*
6267534Sroot 	 * Special handling for ".." allowing chdir out of mounted
6277534Sroot 	 * file system: indirect .. in root inode to reevaluate
6287534Sroot 	 * in directory file system was mounted on.
6297534Sroot 	 */
63016658Smckusick 	if (isdotdot) {
63118109Smckusick 		if (dp == u.u_rdir) {
63216688Smckusick 			ndp->ni_dent.d_ino = dp->i_number;
63318109Smckusick 			makeentry = 0;
63418109Smckusick 		} else if (ndp->ni_dent.d_ino == ROOTINO &&
6357534Sroot 		   dp->i_number == ROOTINO) {
6367534Sroot 			for (i = 1; i < NMOUNT; i++)
6377534Sroot 			if (mount[i].m_bufp != NULL &&
6387534Sroot 			   mount[i].m_dev == dp->i_dev) {
6396571Smckusic 				iput(dp);
6407534Sroot 				dp = mount[i].m_inodp;
64116666Smckusick 				ILOCK(dp);
6425972Swnj 				dp->i_count++;
6437534Sroot 				fs = dp->i_fs;
6447534Sroot 				cp -= 2;     /* back over .. */
6457534Sroot 				goto dirloop2;
6465972Swnj 			}
64730Sbill 		}
6487534Sroot 	}
6497534Sroot 
6507534Sroot 	/*
6519166Ssam 	 * If rewriting (rename), return the inode and the
6529166Ssam 	 * information required to rewrite the present directory
6539166Ssam 	 * Must get inode of directory entry to verify it's a
6549166Ssam 	 * regular file, or empty directory.
6559166Ssam 	 */
6569166Ssam 	if ((flag == CREATE && lockparent) && *cp == 0) {
6579166Ssam 		if (access(dp, IWRITE))
6589166Ssam 			goto bad;
65916688Smckusick 		ndp->ni_pdir = dp;		/* for dirrewrite() */
6609166Ssam 		/*
6619166Ssam 		 * Careful about locking second inode.
6629166Ssam 		 * This can only occur if the target is ".".
6639166Ssam 		 */
66416688Smckusick 		if (dp->i_number == ndp->ni_dent.d_ino) {
6659166Ssam 			u.u_error = EISDIR;		/* XXX */
6669166Ssam 			goto bad;
6679166Ssam 		}
66816688Smckusick 		dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
6699166Ssam 		if (dp == NULL) {
67016688Smckusick 			iput(ndp->ni_pdir);
6719166Ssam 			goto bad;
6729166Ssam 		}
673*31650Smckusick 		FREE(nbp, M_NAMEI);
6749166Ssam 		return (dp);
6759166Ssam 	}
6769166Ssam 
6779166Ssam 	/*
67812011Smckusick 	 * Check for symbolic link, which may require us to massage the
67912011Smckusick 	 * name before we continue translation.  We do not `iput' the
68012011Smckusick 	 * directory because we may need it again if the symbolic link
68112011Smckusick 	 * is relative to the current directory.  Instead we save it
68212011Smckusick 	 * unlocked as "pdp".  We must get the target inode before unlocking
68312011Smckusick 	 * the directory to insure that the inode will not be removed
68412011Smckusick 	 * before we get it.  We prevent deadlock by always fetching
68512011Smckusick 	 * inodes from the root, moving down the directory tree. Thus
68612011Smckusick 	 * when following backward pointers ".." we must unlock the
68712011Smckusick 	 * parent directory before getting the requested directory.
68812011Smckusick 	 * There is a potential race condition here if both the current
68912011Smckusick 	 * and parent directories are removed before the `iget' for the
69012011Smckusick 	 * inode associated with ".." returns.  We hope that this occurs
69112011Smckusick 	 * infrequently since we cannot avoid this race condition without
69212492Ssam 	 * implementing a sophisticated deadlock detection algorithm.
69312011Smckusick 	 * Note also that this simple deadlock detection scheme will not
69412011Smckusick 	 * work if the file system has any hard links other than ".."
69512011Smckusick 	 * that point backwards in the directory structure.
6967534Sroot 	 */
6977534Sroot 	pdp = dp;
69815798Smckusick 	if (isdotdot) {
69916666Smckusick 		IUNLOCK(pdp);	/* race to get the inode */
70016688Smckusick 		dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
70112011Smckusick 		if (dp == NULL)
70212011Smckusick 			goto bad2;
70316688Smckusick 	} else if (dp->i_number == ndp->ni_dent.d_ino) {
70412011Smckusick 		dp->i_count++;	/* we want ourself, ie "." */
70512011Smckusick 	} else {
70616688Smckusick 		dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
70716666Smckusick 		IUNLOCK(pdp);
70812011Smckusick 		if (dp == NULL)
70912011Smckusick 			goto bad2;
71012011Smckusick 	}
71115798Smckusick 
71215798Smckusick 	/*
71326273Skarels 	 * Insert name into cache if appropriate.
71415798Smckusick 	 */
71518109Smckusick 	if (makeentry) {
71615798Smckusick 		if (ncp != NULL)
71727693Smckusick 			panic("namei: duplicating cache");
71826273Skarels 		/*
71926273Skarels 		 * Free the cache slot at head of lru chain.
72026273Skarels 		 */
72115798Smckusick 		if (ncp = nchhead) {
72226273Skarels 			/* remove from lru chain */
72315798Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
72415798Smckusick 			if (ncp->nc_nxt)
72515798Smckusick 				ncp->nc_nxt->nc_prev = ncp->nc_prev;
72615798Smckusick 			else
72715798Smckusick 				nchtail = ncp->nc_prev;
72826273Skarels 			remque(ncp);		/* remove from old hash chain */
72926273Skarels 			/* grab the inode we just found */
73015798Smckusick 			ncp->nc_ip = dp;
73126273Skarels 			/* fill in cache info */
73215798Smckusick 			ncp->nc_ino = pdp->i_number;	/* parents inum */
73315798Smckusick 			ncp->nc_dev = pdp->i_dev;	/* & device */
73415798Smckusick 			ncp->nc_idev = dp->i_dev;	/* our device */
73516643Ssam 			ncp->nc_id = dp->i_id;		/* identifier */
73616688Smckusick 			ncp->nc_nlen = ndp->ni_dent.d_namlen;
73726273Skarels 			bcopy(ndp->ni_dent.d_name, ncp->nc_name,
73826273Skarels 			    (unsigned)ncp->nc_nlen);
73926273Skarels 			/* link at end of lru chain */
74015798Smckusick 			ncp->nc_nxt = NULL;
74115798Smckusick 			ncp->nc_prev = nchtail;
74215798Smckusick 			*nchtail = ncp;
74315798Smckusick 			nchtail = &ncp->nc_nxt;
74426273Skarels 			/* and insert on hash chain */
74515798Smckusick 			insque(ncp, nhp);
74615798Smckusick 		}
74715798Smckusick 	}
74815798Smckusick 
74915798Smckusick haveino:
7507534Sroot 	fs = dp->i_fs;
7517534Sroot 
7527534Sroot 	/*
7537534Sroot 	 * Check for symbolic link
7547534Sroot 	 */
75516688Smckusick 	if ((dp->i_mode & IFMT) == IFLNK &&
75616688Smckusick 	    ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) {
7577825Sroot 		u_int pathlen = strlen(cp) + 1;
7587534Sroot 
75921014Smckusick 		if (dp->i_size + pathlen >= MAXPATHLEN - 1) {
76021014Smckusick 			u.u_error = ENAMETOOLONG;
76121014Smckusick 			goto bad2;
76221014Smckusick 		}
76321014Smckusick 		if (++nlink > MAXSYMLINKS) {
7647534Sroot 			u.u_error = ELOOP;
7657534Sroot 			goto bad2;
7667534Sroot 		}
767*31650Smckusick 		ovbcopy(cp, nbp + dp->i_size, pathlen);
7687751Sroot 		u.u_error =
769*31650Smckusick 		    rdwri(UIO_READ, dp, nbp, (int)dp->i_size,
77026360Skarels 			(off_t)0, 1, (int *)0);
7717534Sroot 		if (u.u_error)
7727534Sroot 			goto bad2;
773*31650Smckusick 		cp = nbp;
7747534Sroot 		iput(dp);
7755972Swnj 		if (*cp == '/') {
7767534Sroot 			irele(pdp);
7775972Swnj 			while (*cp == '/')
7785972Swnj 				cp++;
7797534Sroot 			if ((dp = u.u_rdir) == NULL)
7807534Sroot 				dp = rootdir;
78116666Smckusick 			ILOCK(dp);
7827534Sroot 			dp->i_count++;
7837534Sroot 		} else {
7847534Sroot 			dp = pdp;
78516666Smckusick 			ILOCK(dp);
7865972Swnj 		}
7877534Sroot 		fs = dp->i_fs;
7887534Sroot 		goto dirloop;
78930Sbill 	}
7907534Sroot 
79130Sbill 	/*
7927534Sroot 	 * Not a symbolic link.  If more pathname,
7937534Sroot 	 * continue at next component, else return.
79430Sbill 	 */
7957534Sroot 	if (*cp == '/') {
7967534Sroot 		while (*cp == '/')
7977534Sroot 			cp++;
7989166Ssam 		irele(pdp);
7997534Sroot 		goto dirloop;
80030Sbill 	}
801*31650Smckusick 	FREE(nbp, M_NAMEI);
8029166Ssam 	if (lockparent)
80316688Smckusick 		ndp->ni_pdir = pdp;
8049166Ssam 	else
8059166Ssam 		irele(pdp);
8067534Sroot 	return (dp);
8077534Sroot bad2:
8087534Sroot 	irele(pdp);
8097534Sroot bad:
8107534Sroot 	if (bp)
8117534Sroot 		brelse(bp);
8127534Sroot 	if (dp)
8137534Sroot 		iput(dp);
814*31650Smckusick 	FREE(nbp, M_NAMEI);
8156571Smckusic 	return (NULL);
81630Sbill }
81730Sbill 
81815798Smckusick 
81916688Smckusick dirbad(ip, offset, how)
8207534Sroot 	struct inode *ip;
82116688Smckusick 	off_t offset;
8227534Sroot 	char *how;
8237534Sroot {
8247534Sroot 
8257534Sroot 	printf("%s: bad dir ino %d at offset %d: %s\n",
82616688Smckusick 	    ip->i_fs->fs_fsmnt, ip->i_number, offset, how);
8277534Sroot }
8287534Sroot 
82916657Smckusick /*
83016657Smckusick  * Do consistency checking on a directory entry:
83116657Smckusick  *	record length must be multiple of 4
83216657Smckusick  *	entry must fit in rest of its DIRBLKSIZ block
83316657Smckusick  *	record must be large enough to contain entry
83416657Smckusick  *	name is not longer than MAXNAMLEN
83516657Smckusick  *	name must be as long as advertised, and null terminated
83616657Smckusick  */
83716657Smckusick dirbadentry(ep, entryoffsetinblock)
8387534Sroot 	register struct direct *ep;
83916657Smckusick 	int entryoffsetinblock;
8407534Sroot {
8417534Sroot 	register int i;
8427534Sroot 
84326273Skarels 	if ((ep->d_reclen & 0x3) != 0 ||
84416657Smckusick 	    ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
84516657Smckusick 	    ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN)
84616657Smckusick 		return (1);
8477534Sroot 	for (i = 0; i < ep->d_namlen; i++)
84816688Smckusick 		if (ep->d_name[i] == '\0')
8497534Sroot 			return (1);
8507534Sroot 	return (ep->d_name[i]);
8517534Sroot }
8527534Sroot 
85330Sbill /*
8547534Sroot  * Write a directory entry after a call to namei, using the parameters
8557534Sroot  * which it left in the u. area.  The argument ip is the inode which
85616688Smckusick  * the new directory entry will refer to.  The u. area field ndp->ni_pdir is
8577534Sroot  * a pointer to the directory to be written, which was left locked by
85816688Smckusick  * namei.  Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate
8597534Sroot  * how the space for the new entry is to be gotten.
8607534Sroot  */
86116688Smckusick direnter(ip, ndp)
8627534Sroot 	struct inode *ip;
86316688Smckusick 	register struct nameidata *ndp;
8645972Swnj {
8657534Sroot 	register struct direct *ep, *nep;
86618027Smckusick 	register struct inode *dp = ndp->ni_pdir;
8677534Sroot 	struct buf *bp;
86811639Ssam 	int loc, spacefree, error = 0;
8698631Sroot 	u_int dsize;
8708631Sroot 	int newentrysize;
8717534Sroot 	char *dirbuf;
8725972Swnj 
87316688Smckusick 	ndp->ni_dent.d_ino = ip->i_number;
87416688Smckusick 	newentrysize = DIRSIZ(&ndp->ni_dent);
87516688Smckusick 	if (ndp->ni_count == 0) {
8767534Sroot 		/*
87716688Smckusick 		 * If ndp->ni_count is 0, then namei could find no space in the
87816688Smckusick 		 * directory. In this case ndp->ni_offset will be on a directory
8797534Sroot 		 * block boundary and we will write the new entry into a fresh
8807534Sroot 		 * block.
8817534Sroot 		 */
88216688Smckusick 		if (ndp->ni_offset&(DIRBLKSIZ-1))
8837534Sroot 			panic("wdir: newblk");
88416688Smckusick 		ndp->ni_dent.d_reclen = DIRBLKSIZ;
88518027Smckusick 		error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
88616688Smckusick 		    newentrysize, ndp->ni_offset, 1, (int *)0);
88718104Smckusick 		if (DIRBLKSIZ > dp->i_fs->fs_fsize)
88818104Smckusick 			panic("wdir: blksize"); /* XXX - should grow w/bmap() */
88918104Smckusick 		else
89018104Smckusick 			dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
89118027Smckusick 		iput(dp);
89210849Ssam 		return (error);
8937534Sroot 	}
8947534Sroot 
8957534Sroot 	/*
89616688Smckusick 	 * If ndp->ni_count is non-zero, then namei found space for the new
89716688Smckusick 	 * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count.
8987534Sroot 	 * in the directory.  To use this space, we may have to compact
8997534Sroot 	 * the entries located there, by copying them together towards
9007534Sroot 	 * the beginning of the block, leaving the free space in
9017534Sroot 	 * one usable chunk at the end.
9027534Sroot 	 */
9037534Sroot 
9047534Sroot 	/*
9057534Sroot 	 * Increase size of directory if entry eats into new space.
9067534Sroot 	 * This should never push the size past a new multiple of
9077534Sroot 	 * DIRBLKSIZE.
90818104Smckusick 	 *
90918104Smckusick 	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
9107534Sroot 	 */
91118027Smckusick 	if (ndp->ni_offset + ndp->ni_count > dp->i_size)
91218027Smckusick 		dp->i_size = ndp->ni_offset + ndp->ni_count;
9137534Sroot 	/*
9147534Sroot 	 * Get the block containing the space for the new directory
91510849Ssam 	 * entry.  Should return error by result instead of u.u_error.
9167534Sroot 	 */
91718027Smckusick 	bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf);
9189166Ssam 	if (bp == 0) {
91918027Smckusick 		iput(dp);
92010849Ssam 		return (u.u_error);
9219166Ssam 	}
9227534Sroot 	/*
9237534Sroot 	 * Find space for the new entry.  In the simple case, the
9247534Sroot 	 * entry at offset base will have the space.  If it does
9257534Sroot 	 * not, then namei arranged that compacting the region
92616688Smckusick 	 * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space.
9277534Sroot 	 */
9287534Sroot 	ep = (struct direct *)dirbuf;
9297534Sroot 	dsize = DIRSIZ(ep);
93011639Ssam 	spacefree = ep->d_reclen - dsize;
93116688Smckusick 	for (loc = ep->d_reclen; loc < ndp->ni_count; ) {
9327534Sroot 		nep = (struct direct *)(dirbuf + loc);
9337534Sroot 		if (ep->d_ino) {
9347534Sroot 			/* trim the existing slot */
9357534Sroot 			ep->d_reclen = dsize;
9367534Sroot 			ep = (struct direct *)((char *)ep + dsize);
9377534Sroot 		} else {
9387534Sroot 			/* overwrite; nothing there; header is ours */
93911639Ssam 			spacefree += dsize;
9407534Sroot 		}
9417534Sroot 		dsize = DIRSIZ(nep);
94211639Ssam 		spacefree += nep->d_reclen - dsize;
9437534Sroot 		loc += nep->d_reclen;
9447825Sroot 		bcopy((caddr_t)nep, (caddr_t)ep, dsize);
9457534Sroot 	}
9467534Sroot 	/*
9477534Sroot 	 * Update the pointer fields in the previous entry (if any),
9487534Sroot 	 * copy in the new entry, and write out the block.
9497534Sroot 	 */
9507534Sroot 	if (ep->d_ino == 0) {
95111639Ssam 		if (spacefree + dsize < newentrysize)
9527534Sroot 			panic("wdir: compact1");
95316688Smckusick 		ndp->ni_dent.d_reclen = spacefree + dsize;
9547534Sroot 	} else {
95511639Ssam 		if (spacefree < newentrysize)
9567534Sroot 			panic("wdir: compact2");
95716688Smckusick 		ndp->ni_dent.d_reclen = spacefree;
9587534Sroot 		ep->d_reclen = dsize;
9597534Sroot 		ep = (struct direct *)((char *)ep + dsize);
9607534Sroot 	}
96116688Smckusick 	bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize);
9627534Sroot 	bwrite(bp);
96318027Smckusick 	dp->i_flag |= IUPD|ICHG;
96418027Smckusick 	if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size)
96526273Skarels 		itrunc(dp, (u_long)ndp->ni_endoff);
96618027Smckusick 	iput(dp);
96710849Ssam 	return (error);
9685972Swnj }
9696571Smckusic 
9709166Ssam /*
9719166Ssam  * Remove a directory entry after a call to namei, using the
9729166Ssam  * parameters which it left in the u. area.  The u. entry
97316688Smckusick  * ni_offset contains the offset into the directory of the
97416688Smckusick  * entry to be eliminated.  The ni_count field contains the
9759166Ssam  * size of the previous record in the directory.  If this
9769166Ssam  * is 0, the first entry is being deleted, so we need only
9779166Ssam  * zero the inode number to mark the entry as free.  If the
9789166Ssam  * entry isn't the first in the directory, we must reclaim
9799166Ssam  * the space of the now empty record by adding the record size
9809166Ssam  * to the size of the previous entry.
9819166Ssam  */
98216688Smckusick dirremove(ndp)
98316688Smckusick 	register struct nameidata *ndp;
9846571Smckusic {
98516688Smckusick 	register struct inode *dp = ndp->ni_pdir;
9867534Sroot 	register struct buf *bp;
9877534Sroot 	struct direct *ep;
9886571Smckusic 
98916688Smckusick 	if (ndp->ni_count == 0) {
9907534Sroot 		/*
9917534Sroot 		 * First entry in block: set d_ino to zero.
9927534Sroot 		 */
99316688Smckusick 		ndp->ni_dent.d_ino = 0;
99416688Smckusick 		(void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
99516688Smckusick 		    (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);
9969269Ssam 	} else {
9977534Sroot 		/*
9987534Sroot 		 * Collapse new free space into previous entry.
9997534Sroot 		 */
100026360Skarels 		bp = blkatoff(dp, ndp->ni_offset - ndp->ni_count, (char **)&ep);
10017534Sroot 		if (bp == 0)
10027534Sroot 			return (0);
100316688Smckusick 		ep->d_reclen += ndp->ni_dent.d_reclen;
10047534Sroot 		bwrite(bp);
10057534Sroot 		dp->i_flag |= IUPD|ICHG;
10067534Sroot 	}
10077534Sroot 	return (1);
10086571Smckusic }
10097534Sroot 
10107605Ssam /*
10119166Ssam  * Rewrite an existing directory entry to point at the inode
10129166Ssam  * supplied.  The parameters describing the directory entry are
10139166Ssam  * set up by a call to namei.
10149166Ssam  */
101516688Smckusick dirrewrite(dp, ip, ndp)
10169166Ssam 	struct inode *dp, *ip;
101716688Smckusick 	struct nameidata *ndp;
10189166Ssam {
10199166Ssam 
102016688Smckusick 	ndp->ni_dent.d_ino = ip->i_number;
102116688Smckusick 	u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
102216688Smckusick 		(int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);
10239166Ssam 	iput(dp);
10249166Ssam }
10259166Ssam 
10269166Ssam /*
10277605Ssam  * Return buffer with contents of block "offset"
10287605Ssam  * from the beginning of directory "ip".  If "res"
10297605Ssam  * is non-zero, fill it in with a pointer to the
10307605Ssam  * remaining space in the directory.
10317605Ssam  */
10327534Sroot struct buf *
10337605Ssam blkatoff(ip, offset, res)
10347534Sroot 	struct inode *ip;
10357534Sroot 	off_t offset;
10367534Sroot 	char **res;
10377534Sroot {
10387534Sroot 	register struct fs *fs = ip->i_fs;
10398672Sroot 	daddr_t lbn = lblkno(fs, offset);
10407534Sroot 	int bsize = blksize(fs, ip, lbn);
10417534Sroot 	register struct buf *bp;
104218663Smckusick 	daddr_t bn;
10437534Sroot 
104418663Smckusick 	bn = bmap(ip, lbn, B_READ, bsize);
10457534Sroot 	if (u.u_error)
10467534Sroot 		return (0);
104718663Smckusick 	if (bn == (daddr_t)-1) {
104818663Smckusick 		dirbad(ip, offset, "hole in dir");
104918663Smckusick 		return (0);
105018663Smckusick 	}
105118663Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, bn), bsize);
10527534Sroot 	if (bp->b_flags & B_ERROR) {
10537534Sroot 		brelse(bp);
10547534Sroot 		return (0);
10557534Sroot 	}
10567534Sroot 	if (res)
105718663Smckusick 		*res = bp->b_un.b_addr + blkoff(fs, offset);
10587534Sroot 	return (bp);
10597534Sroot }
10609166Ssam 
10619166Ssam /*
10629166Ssam  * Check if a directory is empty or not.
10639166Ssam  * Inode supplied must be locked.
106412817Ssam  *
106512817Ssam  * Using a struct dirtemplate here is not precisely
106612817Ssam  * what we want, but better than using a struct direct.
106712817Ssam  *
106812817Ssam  * NB: does not handle corrupted directories.
10699166Ssam  */
107016777Smckusick dirempty(ip, parentino)
10719863Ssam 	register struct inode *ip;
107216777Smckusick 	ino_t parentino;
10739166Ssam {
10749166Ssam 	register off_t off;
107512817Ssam 	struct dirtemplate dbuf;
107612817Ssam 	register struct direct *dp = (struct direct *)&dbuf;
10779863Ssam 	int error, count;
107812817Ssam #define	MINDIRSIZ (sizeof (struct dirtemplate) / 2)
10799166Ssam 
10809166Ssam 	for (off = 0; off < ip->i_size; off += dp->d_reclen) {
108112817Ssam 		error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ,
108212817Ssam 		    off, 1, &count);
108312817Ssam 		/*
108412817Ssam 		 * Since we read MINDIRSIZ, residual must
108512817Ssam 		 * be 0 unless we're at end of file.
108612817Ssam 		 */
108712817Ssam 		if (error || count != 0)
10889166Ssam 			return (0);
108924534Smckusick 		/* avoid infinite loops */
109026273Skarels 		if (dp->d_reclen == 0)
109124534Smckusick 			return (0);
109212817Ssam 		/* skip empty entries */
10939166Ssam 		if (dp->d_ino == 0)
10949166Ssam 			continue;
109512817Ssam 		/* accept only "." and ".." */
109612817Ssam 		if (dp->d_namlen > 2)
109712817Ssam 			return (0);
10989166Ssam 		if (dp->d_name[0] != '.')
10999166Ssam 			return (0);
110012817Ssam 		/*
110112817Ssam 		 * At this point d_namlen must be 1 or 2.
110212817Ssam 		 * 1 implies ".", 2 implies ".." if second
110312817Ssam 		 * char is also "."
110412817Ssam 		 */
110516777Smckusick 		if (dp->d_namlen == 1)
11069166Ssam 			continue;
110716777Smckusick 		if (dp->d_name[1] == '.' && dp->d_ino == parentino)
110816777Smckusick 			continue;
11099166Ssam 		return (0);
11109166Ssam 	}
11119166Ssam 	return (1);
11129166Ssam }
111312815Smckusick 
111412815Smckusick /*
111512815Smckusick  * Check if source directory is in the path of the target directory.
111612815Smckusick  * Target is supplied locked, source is unlocked.
111712815Smckusick  * The target is always iput() before returning.
111812815Smckusick  */
111912815Smckusick checkpath(source, target)
112012815Smckusick 	struct inode *source, *target;
112112815Smckusick {
112212815Smckusick 	struct dirtemplate dirbuf;
112312815Smckusick 	register struct inode *ip;
112412815Smckusick 	int error = 0;
112512815Smckusick 
112612815Smckusick 	ip = target;
112712815Smckusick 	if (ip->i_number == source->i_number) {
112812815Smckusick 		error = EEXIST;
112912815Smckusick 		goto out;
113012815Smckusick 	}
113112815Smckusick 	if (ip->i_number == ROOTINO)
113212815Smckusick 		goto out;
113312815Smckusick 
113412815Smckusick 	for (;;) {
113512815Smckusick 		if ((ip->i_mode&IFMT) != IFDIR) {
113612815Smckusick 			error = ENOTDIR;
113712815Smckusick 			break;
113812815Smckusick 		}
113912815Smckusick 		error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
114012815Smckusick 			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
114112815Smckusick 		if (error != 0)
114212815Smckusick 			break;
114312815Smckusick 		if (dirbuf.dotdot_namlen != 2 ||
114416658Smckusick 		    dirbuf.dotdot_name[0] != '.' ||
114516658Smckusick 		    dirbuf.dotdot_name[1] != '.') {
114612815Smckusick 			error = ENOTDIR;
114712815Smckusick 			break;
114812815Smckusick 		}
114912815Smckusick 		if (dirbuf.dotdot_ino == source->i_number) {
115012815Smckusick 			error = EINVAL;
115112815Smckusick 			break;
115212815Smckusick 		}
115312815Smckusick 		if (dirbuf.dotdot_ino == ROOTINO)
115412815Smckusick 			break;
115512815Smckusick 		iput(ip);
115612815Smckusick 		ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino);
115712815Smckusick 		if (ip == NULL) {
115812815Smckusick 			error = u.u_error;
115912815Smckusick 			break;
116012815Smckusick 		}
116112815Smckusick 	}
116212815Smckusick 
116312815Smckusick out:
116412815Smckusick 	if (error == ENOTDIR)
116512815Smckusick 		printf("checkpath: .. not a directory\n");
116612815Smckusick 	if (ip != NULL)
116712815Smckusick 		iput(ip);
116812815Smckusick 	return (error);
116912815Smckusick }
117015798Smckusick 
117115798Smckusick /*
117215798Smckusick  * Name cache initialization, from main() when we are booting
117315798Smckusick  */
117415798Smckusick nchinit()
117515798Smckusick {
117615798Smckusick 	register union nchash *nchp;
117726306Skarels 	register struct namecache *ncp;
117815798Smckusick 
117915798Smckusick 	nchhead = 0;
118015798Smckusick 	nchtail = &nchhead;
118126306Skarels 	for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) {
118215798Smckusick 		ncp->nc_forw = ncp;			/* hash chain */
118315798Smckusick 		ncp->nc_back = ncp;
118415798Smckusick 		ncp->nc_nxt = NULL;			/* lru chain */
118515798Smckusick 		*nchtail = ncp;
118615798Smckusick 		ncp->nc_prev = nchtail;
118715798Smckusick 		nchtail = &ncp->nc_nxt;
118815798Smckusick 		/* all else is zero already */
118915798Smckusick 	}
119015798Smckusick 	for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) {
119115798Smckusick 		nchp->nch_head[0] = nchp;
119215798Smckusick 		nchp->nch_head[1] = nchp;
119315798Smckusick 	}
119415798Smckusick }
119515798Smckusick 
119615798Smckusick /*
119715798Smckusick  * Cache flush, called when filesys is umounted to
119815798Smckusick  * remove entries that would now be invalid
119915798Smckusick  *
120015798Smckusick  * The line "nxtcp = nchhead" near the end is to avoid potential problems
120115798Smckusick  * if the cache lru chain is modified while we are dumping the
120215798Smckusick  * inode.  This makes the algorithm O(n^2), but do you think I care?
120315798Smckusick  */
120415798Smckusick nchinval(dev)
120515798Smckusick 	register dev_t dev;
120615798Smckusick {
120726306Skarels 	register struct namecache *ncp, *nxtcp;
120815798Smckusick 
120915798Smckusick 	for (ncp = nchhead; ncp; ncp = nxtcp) {
121015798Smckusick 		nxtcp = ncp->nc_nxt;
121115798Smckusick 		if (ncp->nc_ip == NULL ||
121215798Smckusick 		    (ncp->nc_idev != dev && ncp->nc_dev != dev))
121315798Smckusick 			continue;
121426273Skarels 		/* free the resources we had */
121515798Smckusick 		ncp->nc_idev = NODEV;
121615798Smckusick 		ncp->nc_dev = NODEV;
121716658Smckusick 		ncp->nc_id = NULL;
121815798Smckusick 		ncp->nc_ino = 0;
121916658Smckusick 		ncp->nc_ip = NULL;
122026273Skarels 		remque(ncp);		/* remove entry from its hash chain */
122126273Skarels 		ncp->nc_forw = ncp;	/* and make a dummy one */
122215798Smckusick 		ncp->nc_back = ncp;
122326273Skarels 		/* delete this entry from LRU chain */
122415798Smckusick 		*ncp->nc_prev = nxtcp;
122515798Smckusick 		if (nxtcp)
122615798Smckusick 			nxtcp->nc_prev = ncp->nc_prev;
122715798Smckusick 		else
122815798Smckusick 			nchtail = ncp->nc_prev;
122926273Skarels 		/* cause rescan of list, it may have altered */
123015798Smckusick 		nxtcp = nchhead;
123126273Skarels 		/* put the now-free entry at head of LRU */
123215798Smckusick 		ncp->nc_nxt = nxtcp;
123315798Smckusick 		ncp->nc_prev = &nchhead;
123415798Smckusick 		nxtcp->nc_prev = &ncp->nc_nxt;
123515798Smckusick 		nchhead = ncp;
123615798Smckusick 	}
123715798Smckusick }
123817704Smckusick 
123917704Smckusick /*
124017704Smckusick  * Name cache invalidation of all entries.
124117704Smckusick  */
124217704Smckusick cacheinvalall()
124317704Smckusick {
124426306Skarels 	register struct namecache *ncp;
124517704Smckusick 
124626306Skarels 	for (ncp = namecache; ncp < &namecache[nchsize]; ncp++)
124717704Smckusick 		ncp->nc_id = 0;
124817704Smckusick }
1249