xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 24534)
123401Smckusick /*
223401Smckusick  * Copyright (c) 1982 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*24534Smckusick  *	@(#)vfs_lookup.c	6.25 (Berkeley) 09/04/85
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"
2030Sbill 
217605Ssam struct	buf *blkatoff();
2216681Smckusick struct	buf *freenamebuf;
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 
3615798Smckusick union	nchash	{
3715798Smckusick 	union	nchash	*nch_head[2];
3815798Smckusick 	struct	nch	*nch_chain[2];
3915798Smckusick } nchash[NCHHASH];
4015798Smckusick #define	nch_forw	nch_chain[0]
4115798Smckusick #define	nch_back	nch_chain[1]
4215798Smckusick 
4315809Smckusick struct	nch	*nchhead, **nchtail;	/* LRU chain pointers */
4415809Smckusick struct	nchstats nchstats;		/* cache effectiveness statistics */
4515798Smckusick 
4615798Smckusick /*
477534Sroot  * Convert a pathname into a pointer to a locked inode,
487534Sroot  * with side effects usable in creating and removing files.
497534Sroot  * This is a very central and rather complicated routine.
5030Sbill  *
5116688Smckusick  * The segflg defines whether the name is to be copied from user
5216688Smckusick  * space or kernel space.
537534Sroot  *
549166Ssam  * The flag argument is (LOOKUP, CREATE, DELETE) depending on whether
559166Ssam  * the name is to be (looked up, created, deleted).  If flag has
569166Ssam  * LOCKPARENT or'ed into it and the target of the pathname exists,
579166Ssam  * namei returns both the target and its parent directory locked.
589166Ssam  * If the file system is not maintained in a strict tree hierarchy,
599166Ssam  * this can result in a deadlock situation.  When creating and
609166Ssam  * LOCKPARENT is specified, the target may not be ".".  When deleting
619166Ssam  * and LOCKPARENT is specified, the target may be ".", but the caller
629166Ssam  * must check to insure it does an irele and iput instead of two iputs.
639166Ssam  *
6416688Smckusick  * The FOLLOW flag is set when symbolic links are to be followed
659166Ssam  * when they occur at the end of the name translation process.
669166Ssam  *
6715798Smckusick  * Name caching works as follows:
687534Sroot  *
6915798Smckusick  *	names found by directory scans are retained in a cache
7015798Smckusick  *	for future reference.  It is managed LRU, so frequently
7115798Smckusick  *	used names will hang around.  Cache is indexed by hash value
7215798Smckusick  *	obtained from (ino,dev,name) where ino & dev refer to the
7315798Smckusick  *	directory containing name.
7415798Smckusick  *
7515798Smckusick  *	For simplicity (and economy of storage), names longer than
7615798Smckusick  *	some (small) maximum length are not cached, they occur
7715798Smckusick  *	infrequently in any case, and are almost never of interest.
7815798Smckusick  *
7915798Smckusick  *	Upon reaching the last segment of a path, if the reference
8015798Smckusick  *	is for DELETE, or NOCACHE is set (rewrite), and the
8115798Smckusick  *	name is located in the cache, it will be dropped.
8215798Smckusick  *
8315798Smckusick  *	We must be sure never to enter the name ".." into the cache
8415798Smckusick  *	because of the extremely kludgey way that rename() alters
8515798Smckusick  *	".." in a situation like
8615798Smckusick  *		mv a/x b/x
8715798Smckusick  *	where x is a directory, and x/.. is the ".." in question.
8815798Smckusick  *
8915798Smckusick  * Overall outline of namei:
9015798Smckusick  *
917534Sroot  *	copy in name
927534Sroot  *	get starting directory
937534Sroot  * dirloop:
947534Sroot  *	check accessibility of directory
957534Sroot  * dirloop2:
9616688Smckusick  *	copy next component of name to ndp->ni_dent
977534Sroot  *	handle degenerate case where name is null string
9815798Smckusick  *	look for name in cache, if found, then if at end of path
9915798Smckusick  *	  and deleting or creating, drop it, else to haveino
1007534Sroot  *	search for name in directory, to found or notfound
1017534Sroot  * notfound:
1029166Ssam  *	if creating, return locked directory, leaving info on avail. slots
1037534Sroot  *	else return error
1047534Sroot  * found:
1057534Sroot  *	if at end of path and deleting, return information to allow delete
10615798Smckusick  *	if at end of path and rewriting (create and LOCKPARENT), lock target
1079166Ssam  *	  inode and return info to allow rewrite
1087534Sroot  *	if .. and on mounted filesys, look in mount table for parent
10915798Smckusick  *	if not at end, if neither creating nor deleting, add name to cache
11015798Smckusick  * haveino:
1117534Sroot  *	if symbolic link, massage name in buffer and continue at dirloop
1127534Sroot  *	if more components of name, do next level at dirloop
1137534Sroot  *	return the answer as locked inode
1149166Ssam  *
1159166Ssam  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode,
1169166Ssam  *	 but unlocked.
11730Sbill  */
11830Sbill struct inode *
11916688Smckusick namei(ndp)
12016688Smckusick 	register struct nameidata *ndp;
12130Sbill {
1227534Sroot 	register char *cp;		/* pointer into pathname argument */
1237534Sroot /* these variables refer to things which must be freed or unlocked */
1247534Sroot 	register struct inode *dp = 0;	/* the directory we are searching */
12515798Smckusick 	register struct nch *ncp;	/* cache slot for entry */
1267534Sroot 	register struct fs *fs;		/* file system that directory is in */
1277534Sroot 	register struct buf *bp = 0;	/* a buffer of directory entries */
1287534Sroot 	register struct direct *ep;	/* the current directory entry */
1297534Sroot 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
1307534Sroot 	register struct buf *nbp;	/* buffer storing path name argument */
1317534Sroot /* these variables hold information about the search for a slot */
1327534Sroot 	enum {NONE, COMPACT, FOUND} slotstatus;
1337534Sroot 	int slotoffset = -1;		/* offset of area with free space */
1347534Sroot 	int slotsize;			/* size of area at slotoffset */
1357534Sroot 	int slotfreespace;		/* amount of space free in slot */
1367534Sroot 	int slotneeded;			/* size of the entry we're seeking */
1377534Sroot /* */
13815660Smckusick 	int numdirpasses;		/* strategy for directory search */
13915660Smckusick 	int endsearch;			/* offset to end directory search */
14016688Smckusick 	int prevoff;			/* ndp->ni_offset of previous entry */
1417534Sroot 	int nlink = 0;			/* number of symbolic links taken */
1427534Sroot 	struct inode *pdp;		/* saved dp during symlink work */
14316688Smckusick 	int error, i;
1449166Ssam 	int lockparent;
14518109Smckusick 	int docache;			/* == 0 do not cache last component */
14618109Smckusick 	int makeentry;			/* != 0 if name to be added to cache */
14715798Smckusick 	unsigned hash;			/* value of name hash for entry */
14815798Smckusick 	union nchash *nhp;		/* cache chain head for entry */
14915798Smckusick 	int isdotdot;			/* != 0 if current name is ".." */
15016688Smckusick 	int flag;			/* op ie, LOOKUP, CREATE, or DELETE */
15118027Smckusick 	off_t enduseful;		/* pointer past last used dir slot */
15230Sbill 
15316688Smckusick 	lockparent = ndp->ni_nameiop & LOCKPARENT;
15416688Smckusick 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
15516688Smckusick 	flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW);
15618109Smckusick 	if (flag == DELETE || lockparent)
15715798Smckusick 		docache = 0;
15830Sbill 	/*
1597534Sroot 	 * Get a buffer for the name to be translated, and copy the
1607534Sroot 	 * name into the buffer.
1615972Swnj 	 */
16216681Smckusick 	nbp = freenamebuf;
16316681Smckusick 	if (nbp == NULL)
16416681Smckusick 		nbp = geteblk(MAXPATHLEN);
16516681Smckusick 	else
16616681Smckusick 		freenamebuf = nbp->av_forw;
16716688Smckusick 	if (ndp->ni_segflg == UIO_SYSSPACE)
16816705Smckusick 		error = copystr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN,
16916705Smckusick 		    (u_int *)0);
17016688Smckusick 	else
17116705Smckusick 		error = copyinstr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN,
17216705Smckusick 		    (u_int *)0);
17316688Smckusick 	if (error) {
17416688Smckusick 		u.u_error = error;
17516688Smckusick 		goto bad;
1765972Swnj 	}
1777534Sroot 
1785972Swnj 	/*
1797534Sroot 	 * Get starting directory.
18030Sbill 	 */
1817534Sroot 	cp = nbp->b_un.b_addr;
1825972Swnj 	if (*cp == '/') {
1835972Swnj 		while (*cp == '/')
1845972Swnj 			cp++;
18530Sbill 		if ((dp = u.u_rdir) == NULL)
18630Sbill 			dp = rootdir;
1877534Sroot 	} else
1887534Sroot 		dp = u.u_cdir;
1897534Sroot 	fs = dp->i_fs;
19016666Smckusick 	ILOCK(dp);
1915972Swnj 	dp->i_count++;
19216688Smckusick 	ndp->ni_pdir = (struct inode *)0xc0000000;		/* illegal */
19318027Smckusick 	ndp->ni_endoff = 0;
1947534Sroot 
1957534Sroot 	/*
1967534Sroot 	 * We come to dirloop to search a new directory.
1977534Sroot 	 * The directory must be locked so that it can be
1987534Sroot 	 * iput, and fs must be already set to dp->i_fs.
1997534Sroot 	 */
2006571Smckusic dirloop:
20130Sbill 	/*
2027534Sroot 	 * Check accessiblity of directory.
20330Sbill 	 */
2047534Sroot 	if ((dp->i_mode&IFMT) != IFDIR) {
20530Sbill 		u.u_error = ENOTDIR;
2067534Sroot 		goto bad;
2077534Sroot 	}
2087534Sroot 	if (access(dp, IEXEC))
2097534Sroot 		goto bad;
2107534Sroot 
2116384Swnj dirloop2:
2127534Sroot 	/*
21316688Smckusick 	 * Copy next component of name to ndp->ni_dent.
2147534Sroot 	 */
21515798Smckusick 	hash = 0;
2167534Sroot 	for (i = 0; *cp != 0 && *cp != '/'; cp++) {
2176571Smckusic 		if (i >= MAXNAMLEN) {
21821014Smckusick 			u.u_error = ENAMETOOLONG;
2197534Sroot 			goto bad;
2205972Swnj 		}
22121014Smckusick 		if (*cp & 0200)
22221014Smckusick 			if ((*cp&0377) == ('/'|0200) || flag != DELETE) {
22321014Smckusick 				u.u_error = EINVAL;
22421014Smckusick 				goto bad;
22521014Smckusick 			}
22616688Smckusick 		ndp->ni_dent.d_name[i++] = *cp;
22715798Smckusick 		hash += (unsigned char)*cp * i;
2285972Swnj 	}
22916688Smckusick 	ndp->ni_dent.d_namlen = i;
23016688Smckusick 	ndp->ni_dent.d_name[i] = '\0';
23116658Smckusick 	isdotdot = (i == 2 &&
23216688Smckusick 		ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.');
23318109Smckusick 	makeentry = 1;
23418109Smckusick 	if (*cp == '\0' && docache == 0)
23518109Smckusick 		makeentry = 0;
2367534Sroot 
2377534Sroot 	/*
2387534Sroot 	 * Check for degenerate name (e.g. / or "")
2397534Sroot 	 * which is a way of talking about a directory,
2407534Sroot 	 * e.g. like "/." or ".".
2417534Sroot 	 */
24216688Smckusick 	if (ndp->ni_dent.d_name[0] == '\0') {
24315798Smckusick 		if (flag != LOOKUP || lockparent) {
24414937Smckusick 			u.u_error = EISDIR;
2457534Sroot 			goto bad;
2465972Swnj 		}
24716681Smckusick 		nbp->av_forw = freenamebuf;
24816681Smckusick 		freenamebuf = nbp;
2496571Smckusic 		return (dp);
2505972Swnj 	}
2517534Sroot 
2526571Smckusic 	/*
25315798Smckusick 	 * We now have a segment name to search for, and a directory to search.
25415798Smckusick 	 *
25515798Smckusick 	 * Before tediously performing a linear scan of the directory,
25615798Smckusick 	 * check the name cache to see if the directory/name pair
25715798Smckusick 	 * we are looking for is known already.  We don't do this
25815798Smckusick 	 * if the segment name is long, simply so the cache can avoid
25915798Smckusick 	 * holding long names (which would either waste space, or
26015798Smckusick 	 * add greatly to the complexity).
26115798Smckusick 	 */
26216688Smckusick 	if (ndp->ni_dent.d_namlen > NCHNAMLEN) {
26315798Smckusick 		nchstats.ncs_long++;
26418109Smckusick 		makeentry = 0;
26515798Smckusick 	} else {
26615798Smckusick 		nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)];
26715798Smckusick 		for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp;
26815798Smckusick 		    ncp = ncp->nc_forw) {
26915798Smckusick 			if (ncp->nc_ino == dp->i_number &&
27015798Smckusick 			    ncp->nc_dev == dp->i_dev &&
27116688Smckusick 			    ncp->nc_nlen == ndp->ni_dent.d_namlen &&
27216688Smckusick 			    !bcmp(ncp->nc_name, ndp->ni_dent.d_name,
27316688Smckusick 				ncp->nc_nlen))
27415798Smckusick 				break;
27515798Smckusick 		}
27615798Smckusick 
27715798Smckusick 		if (ncp == (struct nch *)nhp) {
27815798Smckusick 			nchstats.ncs_miss++;
27915798Smckusick 			ncp = NULL;
28015798Smckusick 		} else {
28116658Smckusick 			if (ncp->nc_id != ncp->nc_ip->i_id) {
28216643Ssam 				nchstats.ncs_falsehits++;
28318109Smckusick 			} else if (!makeentry) {
28416658Smckusick 				nchstats.ncs_badhits++;
28516658Smckusick 			} else {
28615798Smckusick 
28715798Smckusick 					/*
28815798Smckusick 					 * move this slot to end of LRU
28915798Smckusick 					 * chain, if not already there
29015798Smckusick 					 */
29115798Smckusick 				if (ncp->nc_nxt) {
29215798Smckusick 						/* remove from LRU chain */
29315798Smckusick 					*ncp->nc_prev = ncp->nc_nxt;
29415798Smckusick 					ncp->nc_nxt->nc_prev = ncp->nc_prev;
29515798Smckusick 
29615798Smckusick 						/* and replace at end of it */
29715798Smckusick 					ncp->nc_nxt = NULL;
29815798Smckusick 					ncp->nc_prev = nchtail;
29915798Smckusick 					*nchtail = ncp;
30015798Smckusick 					nchtail = &ncp->nc_nxt;
30115798Smckusick 				}
30215798Smckusick 
30316658Smckusick 				/*
30416658Smckusick 				 * Get the next inode in the path.
30516666Smckusick 				 * See comment above other `IUNLOCK' code for
30616658Smckusick 				 * an explaination of the locking protocol.
30716658Smckusick 				 */
30815798Smckusick 				pdp = dp;
30918109Smckusick 				if (!isdotdot || dp != u.u_rdir)
31018109Smckusick 					dp = ncp->nc_ip;
31115798Smckusick 				if (dp == NULL)
31215798Smckusick 					panic("nami: null cache ino");
31318109Smckusick 				if (pdp == dp) {
31416643Ssam 					dp->i_count++;
31518109Smckusick 				} else if (isdotdot) {
31618109Smckusick 					IUNLOCK(pdp);
31718109Smckusick 					igrab(dp);
31818109Smckusick 				} else {
31918109Smckusick 					igrab(dp);
32018109Smckusick 					IUNLOCK(pdp);
32116643Ssam 				}
32215798Smckusick 
32316658Smckusick 				/*
32416658Smckusick 				 * Verify that the inode that we got
32516658Smckusick 				 * did not change while we were waiting
32616658Smckusick 				 * for it to be locked.
32716658Smckusick 				 */
32816658Smckusick 				if (ncp->nc_id != ncp->nc_ip->i_id) {
32916658Smckusick 					iput(dp);
33016666Smckusick 					ILOCK(pdp);
33116658Smckusick 					dp = pdp;
33216658Smckusick 					nchstats.ncs_falsehits++;
33316658Smckusick 				} else {
33416688Smckusick 					ndp->ni_dent.d_ino = dp->i_number;
33516688Smckusick 					/* ni_dent.d_reclen is garbage ... */
33616658Smckusick 					nchstats.ncs_goodhits++;
33716658Smckusick 					goto haveino;
33816658Smckusick 				}
33916658Smckusick 			}
34015798Smckusick 
34115798Smckusick 			/*
34216643Ssam 			 * Last component and we are renaming or deleting,
34316643Ssam 			 * the cache entry is invalid, or otherwise don't
34416643Ssam 			 * want cache entry to exist.
34515798Smckusick 			 */
34615798Smckusick 
34715798Smckusick 				/* remove from LRU chain */
34815798Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
34915798Smckusick 			if (ncp->nc_nxt)
35015798Smckusick 				ncp->nc_nxt->nc_prev = ncp->nc_prev;
35115798Smckusick 			else
35215798Smckusick 				nchtail = ncp->nc_prev;
35315798Smckusick 
35415798Smckusick 				/* remove from hash chain */
35515798Smckusick 			remque(ncp);
35615798Smckusick 
35715798Smckusick 				/* insert at head of LRU list (first to grab) */
35815798Smckusick 			ncp->nc_nxt = nchhead;
35915798Smckusick 			ncp->nc_prev = &nchhead;
36015798Smckusick 			nchhead->nc_prev = &ncp->nc_nxt;
36115798Smckusick 			nchhead = ncp;
36215798Smckusick 
36315798Smckusick 				/* and make a dummy hash chain */
36415798Smckusick 			ncp->nc_forw = ncp;
36515798Smckusick 			ncp->nc_back = ncp;
36615798Smckusick 
36715798Smckusick 			ncp = NULL;
36815798Smckusick 		}
36915798Smckusick 	}
37015798Smckusick 
37115798Smckusick 	/*
3727534Sroot 	 * Suppress search for slots unless creating
3737534Sroot 	 * file and at end of pathname, in which case
3747534Sroot 	 * we watch for a place to put the new file in
3757534Sroot 	 * case it doesn't already exist.
3766571Smckusic 	 */
3777534Sroot 	slotstatus = FOUND;
3789166Ssam 	if (flag == CREATE && *cp == 0) {
3797534Sroot 		slotstatus = NONE;
3807534Sroot 		slotfreespace = 0;
38116688Smckusick 		slotneeded = DIRSIZ(&ndp->ni_dent);
3827534Sroot 	}
38315660Smckusick 	/*
38415660Smckusick 	 * If this is the same directory that this process
38515660Smckusick 	 * previously searched, pick up where we last left off.
38615798Smckusick 	 * We cache only lookups as these are the most common
38715660Smckusick 	 * and have the greatest payoff. Caching CREATE has little
38815660Smckusick 	 * benefit as it usually must search the entire directory
38915660Smckusick 	 * to determine that the entry does not exist. Caching the
39015660Smckusick 	 * location of the last DELETE has not reduced profiling time
39115660Smckusick 	 * and hence has been removed in the interest of simplicity.
39215660Smckusick 	 */
39315660Smckusick 	if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber ||
39415660Smckusick 	    dp->i_dev != u.u_ncache.nc_dev) {
39516688Smckusick 		ndp->ni_offset = 0;
39615660Smckusick 		numdirpasses = 1;
39715660Smckusick 	} else {
39815798Smckusick 		if ((dp->i_flag & ICHG) || dp->i_ctime >= u.u_ncache.nc_time) {
39917698Smckusick 			if (u.u_ncache.nc_prevoffset > dp->i_size)
40017698Smckusick 				u.u_ncache.nc_prevoffset = 0;
40117698Smckusick 			else
40217698Smckusick 				u.u_ncache.nc_prevoffset &= ~(DIRBLKSIZ - 1);
40315660Smckusick 			u.u_ncache.nc_time = time.tv_sec;
40415660Smckusick 		}
40516688Smckusick 		ndp->ni_offset = u.u_ncache.nc_prevoffset;
40616688Smckusick 		entryoffsetinblock = blkoff(fs, ndp->ni_offset);
40715660Smckusick 		if (entryoffsetinblock != 0) {
40816688Smckusick 			bp = blkatoff(dp, ndp->ni_offset, (char **)0);
40915660Smckusick 			if (bp == 0)
41015660Smckusick 				goto bad;
41115660Smckusick 		}
41215660Smckusick 		numdirpasses = 2;
41315798Smckusick 		nchstats.ncs_2passes++;
41415660Smckusick 	}
41515660Smckusick 	endsearch = roundup(dp->i_size, DIRBLKSIZ);
41618027Smckusick 	enduseful = 0;
4177534Sroot 
41815660Smckusick searchloop:
41916688Smckusick 	while (ndp->ni_offset < endsearch) {
4205972Swnj 		/*
4215972Swnj 		 * If offset is on a block boundary,
4225972Swnj 		 * read the next directory block.
4235972Swnj 		 * Release previous if it exists.
4245972Swnj 		 */
42516688Smckusick 		if (blkoff(fs, ndp->ni_offset) == 0) {
4265972Swnj 			if (bp != NULL)
4275972Swnj 				brelse(bp);
42816688Smckusick 			bp = blkatoff(dp, ndp->ni_offset, (char **)0);
4297534Sroot 			if (bp == 0)
4307534Sroot 				goto bad;
4317534Sroot 			entryoffsetinblock = 0;
4325972Swnj 		}
4337534Sroot 
4345972Swnj 		/*
4357534Sroot 		 * If still looking for a slot, and at a DIRBLKSIZE
43616657Smckusick 		 * boundary, have to start looking for free space again.
4376571Smckusic 		 */
4387534Sroot 		if (slotstatus == NONE &&
4397534Sroot 		    (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) {
4407534Sroot 			slotoffset = -1;
4417534Sroot 			slotfreespace = 0;
4427534Sroot 		}
4437534Sroot 
4447534Sroot 		/*
44516657Smckusick 		 * Get pointer to next entry.
44616657Smckusick 		 * Full validation checks are slow, so we only check
44716657Smckusick 		 * enough to insure forward progress through the
44816657Smckusick 		 * directory. Complete checks can be run by patching
44916657Smckusick 		 * "dirchk" to be true.
4507534Sroot 		 */
4517534Sroot 		ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
45216657Smckusick 		if (ep->d_reclen <= 0 ||
45316657Smckusick 		    dirchk && dirbadentry(ep, entryoffsetinblock)) {
45416688Smckusick 			dirbad(dp, ndp->ni_offset, "mangled entry");
45516657Smckusick 			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
45616688Smckusick 			ndp->ni_offset += i;
4577534Sroot 			entryoffsetinblock += i;
4586571Smckusic 			continue;
4596571Smckusic 		}
4607534Sroot 
4616571Smckusic 		/*
4627534Sroot 		 * If an appropriate sized slot has not yet been found,
4636571Smckusic 		 * check to see if one is available. Also accumulate space
4646571Smckusic 		 * in the current block so that we can determine if
4656571Smckusic 		 * compaction is viable.
4666571Smckusic 		 */
4677534Sroot 		if (slotstatus != FOUND) {
4687534Sroot 			int size = ep->d_reclen;
4697534Sroot 
4706571Smckusic 			if (ep->d_ino != 0)
4716571Smckusic 				size -= DIRSIZ(ep);
4726571Smckusic 			if (size > 0) {
4737534Sroot 				if (size >= slotneeded) {
4747534Sroot 					slotstatus = FOUND;
47516688Smckusick 					slotoffset = ndp->ni_offset;
4767534Sroot 					slotsize = ep->d_reclen;
4777534Sroot 				} else if (slotstatus == NONE) {
4787534Sroot 					slotfreespace += size;
4797534Sroot 					if (slotoffset == -1)
48016688Smckusick 						slotoffset = ndp->ni_offset;
4817534Sroot 					if (slotfreespace >= slotneeded) {
4827534Sroot 						slotstatus = COMPACT;
48316688Smckusick 						slotsize = ndp->ni_offset +
48416688Smckusick 						      ep->d_reclen - slotoffset;
4857534Sroot 					}
4866571Smckusic 				}
4876571Smckusic 			}
4886571Smckusic 		}
4897534Sroot 
4906571Smckusic 		/*
4917534Sroot 		 * Check for a name match.
4925972Swnj 		 */
4937534Sroot 		if (ep->d_ino) {
49416688Smckusick 			if (ep->d_namlen == ndp->ni_dent.d_namlen &&
49516688Smckusick 			    !bcmp(ndp->ni_dent.d_name, ep->d_name,
49616688Smckusick 				ep->d_namlen))
4977534Sroot 				goto found;
4987534Sroot 		}
49916688Smckusick 		prevoff = ndp->ni_offset;
50016688Smckusick 		ndp->ni_offset += ep->d_reclen;
5017534Sroot 		entryoffsetinblock += ep->d_reclen;
50218027Smckusick 		if (ep->d_ino)
50318027Smckusick 			enduseful = ndp->ni_offset;
5047534Sroot 	}
50515798Smckusick /* notfound: */
50615660Smckusick 	/*
50715798Smckusick 	 * If we started in the middle of the directory and failed
50815660Smckusick 	 * to find our target, we must check the beginning as well.
50915660Smckusick 	 */
51015660Smckusick 	if (numdirpasses == 2) {
51115660Smckusick 		numdirpasses--;
51216688Smckusick 		ndp->ni_offset = 0;
51315660Smckusick 		endsearch = u.u_ncache.nc_prevoffset;
51415660Smckusick 		goto searchloop;
51515660Smckusick 	}
5167534Sroot 	/*
5177534Sroot 	 * If creating, and at end of pathname and current
5189166Ssam 	 * directory has not been removed, then can consider
5199166Ssam 	 * allowing file to be created.
5207534Sroot 	 */
5219166Ssam 	if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) {
5225972Swnj 		/*
5237534Sroot 		 * Access for write is interpreted as allowing
5247534Sroot 		 * creation of files in the directory.
5255972Swnj 		 */
5267534Sroot 		if (access(dp, IWRITE))
5277534Sroot 			goto bad;
5285972Swnj 		/*
5297534Sroot 		 * Return an indication of where the new directory
5307534Sroot 		 * entry should be put.  If we didn't find a slot,
53116688Smckusick 		 * then set ndp->ni_count to 0 indicating that the new
53216688Smckusick 		 * slot belongs at the end of the directory. If we found
53316688Smckusick 		 * a slot, then the new entry can be put in the range
53416688Smckusick 		 * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count)
5355972Swnj 		 */
53615660Smckusick 		if (slotstatus == NONE) {
53716688Smckusick 			ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ);
53816688Smckusick 			ndp->ni_count = 0;
53918027Smckusick 			enduseful = ndp->ni_offset;
54015660Smckusick 		} else {
54116688Smckusick 			ndp->ni_offset = slotoffset;
54216688Smckusick 			ndp->ni_count = slotsize;
54318027Smckusick 			if (enduseful < slotoffset + slotsize)
54418027Smckusick 				enduseful = slotoffset + slotsize;
5455972Swnj 		}
54618027Smckusick 		ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ);
5477534Sroot 		dp->i_flag |= IUPD|ICHG;
5487534Sroot 		if (bp)
5497534Sroot 			brelse(bp);
55016681Smckusick 		nbp->av_forw = freenamebuf;
55116681Smckusick 		freenamebuf = nbp;
5525972Swnj 		/*
5537534Sroot 		 * We return with the directory locked, so that
5547534Sroot 		 * the parameters we set up above will still be
5557534Sroot 		 * valid if we actually decide to do a direnter().
5567534Sroot 		 * We return NULL to indicate that the entry doesn't
5577534Sroot 		 * currently exist, leaving a pointer to the (locked)
55816688Smckusick 		 * directory inode in ndp->ni_pdir.
5595972Swnj 		 */
56016688Smckusick 		ndp->ni_pdir = dp;
5617534Sroot 		return (NULL);
5627534Sroot 	}
5637534Sroot 	u.u_error = ENOENT;
5647534Sroot 	goto bad;
5657534Sroot found:
56615798Smckusick 	if (numdirpasses == 2)
56715798Smckusick 		nchstats.ncs_pass2++;
5687534Sroot 	/*
5697534Sroot 	 * Check that directory length properly reflects presence
5707534Sroot 	 * of this entry.
5717534Sroot 	 */
5727605Ssam 	if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
57316688Smckusick 		dirbad(dp, ndp->ni_offset, "i_size too small");
5747605Ssam 		dp->i_size = entryoffsetinblock + DIRSIZ(ep);
5757534Sroot 		dp->i_flag |= IUPD|ICHG;
5767534Sroot 	}
5777534Sroot 
5787534Sroot 	/*
57915660Smckusick 	 * Found component in pathname.
58015798Smckusick 	 * If the final component of path name, save information
58115660Smckusick 	 * in the cache as to where the entry was found.
5827534Sroot 	 */
58315660Smckusick 	if (*cp == '\0' && flag == LOOKUP) {
58416688Smckusick 		u.u_ncache.nc_prevoffset = ndp->ni_offset;
58515660Smckusick 		u.u_ncache.nc_inumber = dp->i_number;
58615660Smckusick 		u.u_ncache.nc_dev = dp->i_dev;
58715660Smckusick 		u.u_ncache.nc_time = time.tv_sec;
58815660Smckusick 	}
58915660Smckusick 	/*
59018109Smckusick 	 * Save directory entry's inode number and reclen in ndp->ni_dent,
59115660Smckusick 	 * and release directory buffer.
59215660Smckusick 	 */
59318109Smckusick 	ndp->ni_dent.d_ino = ep->d_ino;
59418109Smckusick 	ndp->ni_dent.d_reclen = ep->d_reclen;
5957534Sroot 	brelse(bp);
5967534Sroot 	bp = NULL;
5977534Sroot 
5987534Sroot 	/*
5997534Sroot 	 * If deleting, and at end of pathname, return
6007534Sroot 	 * parameters which can be used to remove file.
6019166Ssam 	 * If the lockparent flag isn't set, we return only
60216688Smckusick 	 * the directory (in ndp->ni_pdir), otherwise we go
6039166Ssam 	 * on and lock the inode, being careful with ".".
6047534Sroot 	 */
6059166Ssam 	if (flag == DELETE && *cp == 0) {
6067534Sroot 		/*
6077534Sroot 		 * Write access to directory required to delete files.
6087534Sroot 		 */
6097534Sroot 		if (access(dp, IWRITE))
6107534Sroot 			goto bad;
61116688Smckusick 		ndp->ni_pdir = dp;		/* for dirremove() */
6127534Sroot 		/*
61316688Smckusick 		 * Return pointer to current entry in ndp->ni_offset,
6147534Sroot 		 * and distance past previous entry (if there
61516688Smckusick 		 * is a previous entry in this block) in ndp->ni_count.
61616688Smckusick 		 * Save directory inode pointer in ndp->ni_pdir for dirremove().
6177534Sroot 		 */
61816688Smckusick 		if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0)
61916688Smckusick 			ndp->ni_count = 0;
6207534Sroot 		else
62116688Smckusick 			ndp->ni_count = ndp->ni_offset - prevoff;
6229166Ssam 		if (lockparent) {
62316688Smckusick 			if (dp->i_number == ndp->ni_dent.d_ino)
6249166Ssam 				dp->i_count++;
6259166Ssam 			else {
62616688Smckusick 				dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
6279166Ssam 				if (dp == NULL) {
62816688Smckusick 					iput(ndp->ni_pdir);
6299166Ssam 					goto bad;
6309166Ssam 				}
63115798Smckusick 				/*
63216046Skarels 				 * If directory is "sticky", then user must own
63315798Smckusick 				 * the directory, or the file in it, else he
63415798Smckusick 				 * may not delete it (unless he's root). This
63515798Smckusick 				 * implements append-only directories.
63615798Smckusick 				 */
63716688Smckusick 				if ((ndp->ni_pdir->i_mode & ISVTX) &&
63815798Smckusick 				    u.u_uid != 0 &&
63916688Smckusick 				    u.u_uid != ndp->ni_pdir->i_uid &&
64015798Smckusick 				    dp->i_uid != u.u_uid) {
64116688Smckusick 					iput(ndp->ni_pdir);
64215798Smckusick 					u.u_error = EPERM;
64315798Smckusick 					goto bad;
64415798Smckusick 				}
6459166Ssam 			}
6469166Ssam 		}
64716681Smckusick 		nbp->av_forw = freenamebuf;
64816681Smckusick 		freenamebuf = nbp;
6497534Sroot 		return (dp);
6507534Sroot 	}
6517534Sroot 
6527534Sroot 	/*
6537534Sroot 	 * Special handling for ".." allowing chdir out of mounted
6547534Sroot 	 * file system: indirect .. in root inode to reevaluate
6557534Sroot 	 * in directory file system was mounted on.
6567534Sroot 	 */
65716658Smckusick 	if (isdotdot) {
65818109Smckusick 		if (dp == u.u_rdir) {
65916688Smckusick 			ndp->ni_dent.d_ino = dp->i_number;
66018109Smckusick 			makeentry = 0;
66118109Smckusick 		} else if (ndp->ni_dent.d_ino == ROOTINO &&
6627534Sroot 		   dp->i_number == ROOTINO) {
6637534Sroot 			for (i = 1; i < NMOUNT; i++)
6647534Sroot 			if (mount[i].m_bufp != NULL &&
6657534Sroot 			   mount[i].m_dev == dp->i_dev) {
6666571Smckusic 				iput(dp);
6677534Sroot 				dp = mount[i].m_inodp;
66816666Smckusick 				ILOCK(dp);
6695972Swnj 				dp->i_count++;
6707534Sroot 				fs = dp->i_fs;
6717534Sroot 				cp -= 2;     /* back over .. */
6727534Sroot 				goto dirloop2;
6735972Swnj 			}
67430Sbill 		}
6757534Sroot 	}
6767534Sroot 
6777534Sroot 	/*
6789166Ssam 	 * If rewriting (rename), return the inode and the
6799166Ssam 	 * information required to rewrite the present directory
6809166Ssam 	 * Must get inode of directory entry to verify it's a
6819166Ssam 	 * regular file, or empty directory.
6829166Ssam 	 */
6839166Ssam 	if ((flag == CREATE && lockparent) && *cp == 0) {
6849166Ssam 		if (access(dp, IWRITE))
6859166Ssam 			goto bad;
68616688Smckusick 		ndp->ni_pdir = dp;		/* for dirrewrite() */
6879166Ssam 		/*
6889166Ssam 		 * Careful about locking second inode.
6899166Ssam 		 * This can only occur if the target is ".".
6909166Ssam 		 */
69116688Smckusick 		if (dp->i_number == ndp->ni_dent.d_ino) {
6929166Ssam 			u.u_error = EISDIR;		/* XXX */
6939166Ssam 			goto bad;
6949166Ssam 		}
69516688Smckusick 		dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
6969166Ssam 		if (dp == NULL) {
69716688Smckusick 			iput(ndp->ni_pdir);
6989166Ssam 			goto bad;
6999166Ssam 		}
70016681Smckusick 		nbp->av_forw = freenamebuf;
70116681Smckusick 		freenamebuf = nbp;
7029166Ssam 		return (dp);
7039166Ssam 	}
7049166Ssam 
7059166Ssam 	/*
70612011Smckusick 	 * Check for symbolic link, which may require us to massage the
70712011Smckusick 	 * name before we continue translation.  We do not `iput' the
70812011Smckusick 	 * directory because we may need it again if the symbolic link
70912011Smckusick 	 * is relative to the current directory.  Instead we save it
71012011Smckusick 	 * unlocked as "pdp".  We must get the target inode before unlocking
71112011Smckusick 	 * the directory to insure that the inode will not be removed
71212011Smckusick 	 * before we get it.  We prevent deadlock by always fetching
71312011Smckusick 	 * inodes from the root, moving down the directory tree. Thus
71412011Smckusick 	 * when following backward pointers ".." we must unlock the
71512011Smckusick 	 * parent directory before getting the requested directory.
71612011Smckusick 	 * There is a potential race condition here if both the current
71712011Smckusick 	 * and parent directories are removed before the `iget' for the
71812011Smckusick 	 * inode associated with ".." returns.  We hope that this occurs
71912011Smckusick 	 * infrequently since we cannot avoid this race condition without
72012492Ssam 	 * implementing a sophisticated deadlock detection algorithm.
72112011Smckusick 	 * Note also that this simple deadlock detection scheme will not
72212011Smckusick 	 * work if the file system has any hard links other than ".."
72312011Smckusick 	 * that point backwards in the directory structure.
7247534Sroot 	 */
7257534Sroot 	pdp = dp;
72615798Smckusick 	if (isdotdot) {
72716666Smckusick 		IUNLOCK(pdp);	/* race to get the inode */
72816688Smckusick 		dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
72912011Smckusick 		if (dp == NULL)
73012011Smckusick 			goto bad2;
73116688Smckusick 	} else if (dp->i_number == ndp->ni_dent.d_ino) {
73212011Smckusick 		dp->i_count++;	/* we want ourself, ie "." */
73312011Smckusick 	} else {
73416688Smckusick 		dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino);
73516666Smckusick 		IUNLOCK(pdp);
73612011Smckusick 		if (dp == NULL)
73712011Smckusick 			goto bad2;
73812011Smckusick 	}
73915798Smckusick 
74015798Smckusick 	/*
74121014Smckusick 	 * insert name into cache if appropriate
74215798Smckusick 	 */
74318109Smckusick 	if (makeentry) {
74415798Smckusick 		if (ncp != NULL)
74515798Smckusick 			panic("nami: duplicating cache");
74615798Smckusick 
74715798Smckusick 			/*
74815798Smckusick 			 * free the cache slot at head of lru chain
74915798Smckusick 			 */
75015798Smckusick 		if (ncp = nchhead) {
75115798Smckusick 				/* remove from lru chain */
75215798Smckusick 			*ncp->nc_prev = ncp->nc_nxt;
75315798Smckusick 			if (ncp->nc_nxt)
75415798Smckusick 				ncp->nc_nxt->nc_prev = ncp->nc_prev;
75515798Smckusick 			else
75615798Smckusick 				nchtail = ncp->nc_prev;
75715798Smckusick 
75815798Smckusick 				/* remove from old hash chain */
75915798Smckusick 			remque(ncp);
76015798Smckusick 
76115798Smckusick 				/* grab the inode we just found */
76215798Smckusick 			ncp->nc_ip = dp;
76315798Smckusick 
76415798Smckusick 				/* fill in cache info */
76515798Smckusick 			ncp->nc_ino = pdp->i_number;	/* parents inum */
76615798Smckusick 			ncp->nc_dev = pdp->i_dev;	/* & device */
76715798Smckusick 			ncp->nc_idev = dp->i_dev;	/* our device */
76816643Ssam 			ncp->nc_id = dp->i_id;		/* identifier */
76916688Smckusick 			ncp->nc_nlen = ndp->ni_dent.d_namlen;
77016688Smckusick 			bcopy(ndp->ni_dent.d_name, ncp->nc_name, ncp->nc_nlen);
77115798Smckusick 
77215798Smckusick 				/* link at end of lru chain */
77315798Smckusick 			ncp->nc_nxt = NULL;
77415798Smckusick 			ncp->nc_prev = nchtail;
77515798Smckusick 			*nchtail = ncp;
77615798Smckusick 			nchtail = &ncp->nc_nxt;
77715798Smckusick 
77815798Smckusick 				/* and insert on hash chain */
77915798Smckusick 			insque(ncp, nhp);
78015798Smckusick 		}
78115798Smckusick 	}
78215798Smckusick 
78315798Smckusick haveino:
7847534Sroot 	fs = dp->i_fs;
7857534Sroot 
7867534Sroot 	/*
7877534Sroot 	 * Check for symbolic link
7887534Sroot 	 */
78916688Smckusick 	if ((dp->i_mode & IFMT) == IFLNK &&
79016688Smckusick 	    ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) {
7917825Sroot 		u_int pathlen = strlen(cp) + 1;
7927534Sroot 
79321014Smckusick 		if (dp->i_size + pathlen >= MAXPATHLEN - 1) {
79421014Smckusick 			u.u_error = ENAMETOOLONG;
79521014Smckusick 			goto bad2;
79621014Smckusick 		}
79721014Smckusick 		if (++nlink > MAXSYMLINKS) {
7987534Sroot 			u.u_error = ELOOP;
7997534Sroot 			goto bad2;
8007534Sroot 		}
8018957Sroot 		ovbcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen);
8027751Sroot 		u.u_error =
8039166Ssam 		    rdwri(UIO_READ, dp, nbp->b_un.b_addr, (int)dp->i_size,
8047825Sroot 			0, 1, (int *)0);
8057534Sroot 		if (u.u_error)
8067534Sroot 			goto bad2;
8077534Sroot 		cp = nbp->b_un.b_addr;
8087534Sroot 		iput(dp);
8095972Swnj 		if (*cp == '/') {
8107534Sroot 			irele(pdp);
8115972Swnj 			while (*cp == '/')
8125972Swnj 				cp++;
8137534Sroot 			if ((dp = u.u_rdir) == NULL)
8147534Sroot 				dp = rootdir;
81516666Smckusick 			ILOCK(dp);
8167534Sroot 			dp->i_count++;
8177534Sroot 		} else {
8187534Sroot 			dp = pdp;
81916666Smckusick 			ILOCK(dp);
8205972Swnj 		}
8217534Sroot 		fs = dp->i_fs;
8227534Sroot 		goto dirloop;
82330Sbill 	}
8247534Sroot 
82530Sbill 	/*
8267534Sroot 	 * Not a symbolic link.  If more pathname,
8277534Sroot 	 * continue at next component, else return.
82830Sbill 	 */
8297534Sroot 	if (*cp == '/') {
8307534Sroot 		while (*cp == '/')
8317534Sroot 			cp++;
8329166Ssam 		irele(pdp);
8337534Sroot 		goto dirloop;
83430Sbill 	}
83516681Smckusick 	nbp->av_forw = freenamebuf;
83616681Smckusick 	freenamebuf = nbp;
8379166Ssam 	if (lockparent)
83816688Smckusick 		ndp->ni_pdir = pdp;
8399166Ssam 	else
8409166Ssam 		irele(pdp);
8417534Sroot 	return (dp);
8427534Sroot bad2:
8437534Sroot 	irele(pdp);
8447534Sroot bad:
8457534Sroot 	if (bp)
8467534Sroot 		brelse(bp);
8477534Sroot 	if (dp)
8487534Sroot 		iput(dp);
84916681Smckusick 	nbp->av_forw = freenamebuf;
85016681Smckusick 	freenamebuf = nbp;
8516571Smckusic 	return (NULL);
85230Sbill }
85330Sbill 
85415798Smckusick 
85516688Smckusick dirbad(ip, offset, how)
8567534Sroot 	struct inode *ip;
85716688Smckusick 	off_t offset;
8587534Sroot 	char *how;
8597534Sroot {
8607534Sroot 
8617534Sroot 	printf("%s: bad dir ino %d at offset %d: %s\n",
86216688Smckusick 	    ip->i_fs->fs_fsmnt, ip->i_number, offset, how);
8637534Sroot }
8647534Sroot 
86516657Smckusick /*
86616657Smckusick  * Do consistency checking on a directory entry:
86716657Smckusick  *	record length must be multiple of 4
86816657Smckusick  *	record length must not be non-negative
86916657Smckusick  *	entry must fit in rest of its DIRBLKSIZ block
87016657Smckusick  *	record must be large enough to contain entry
87116657Smckusick  *	name is not longer than MAXNAMLEN
87216657Smckusick  *	name must be as long as advertised, and null terminated
87316657Smckusick  */
87416657Smckusick dirbadentry(ep, entryoffsetinblock)
8757534Sroot 	register struct direct *ep;
87616657Smckusick 	int entryoffsetinblock;
8777534Sroot {
8787534Sroot 	register int i;
8797534Sroot 
88016657Smckusick 	if ((ep->d_reclen & 0x3) != 0 || ep->d_reclen <= 0 ||
88116657Smckusick 	    ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
88216657Smckusick 	    ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN)
88316657Smckusick 		return (1);
8847534Sroot 	for (i = 0; i < ep->d_namlen; i++)
88516688Smckusick 		if (ep->d_name[i] == '\0')
8867534Sroot 			return (1);
8877534Sroot 	return (ep->d_name[i]);
8887534Sroot }
8897534Sroot 
89030Sbill /*
8917534Sroot  * Write a directory entry after a call to namei, using the parameters
8927534Sroot  * which it left in the u. area.  The argument ip is the inode which
89316688Smckusick  * the new directory entry will refer to.  The u. area field ndp->ni_pdir is
8947534Sroot  * a pointer to the directory to be written, which was left locked by
89516688Smckusick  * namei.  Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate
8967534Sroot  * how the space for the new entry is to be gotten.
8977534Sroot  */
89816688Smckusick direnter(ip, ndp)
8997534Sroot 	struct inode *ip;
90016688Smckusick 	register struct nameidata *ndp;
9015972Swnj {
9027534Sroot 	register struct direct *ep, *nep;
90318027Smckusick 	register struct inode *dp = ndp->ni_pdir;
9047534Sroot 	struct buf *bp;
90511639Ssam 	int loc, spacefree, error = 0;
9068631Sroot 	u_int dsize;
9078631Sroot 	int newentrysize;
9087534Sroot 	char *dirbuf;
9095972Swnj 
91016688Smckusick 	ndp->ni_dent.d_ino = ip->i_number;
91116688Smckusick 	newentrysize = DIRSIZ(&ndp->ni_dent);
91216688Smckusick 	if (ndp->ni_count == 0) {
9137534Sroot 		/*
91416688Smckusick 		 * If ndp->ni_count is 0, then namei could find no space in the
91516688Smckusick 		 * directory. In this case ndp->ni_offset will be on a directory
9167534Sroot 		 * block boundary and we will write the new entry into a fresh
9177534Sroot 		 * block.
9187534Sroot 		 */
91916688Smckusick 		if (ndp->ni_offset&(DIRBLKSIZ-1))
9207534Sroot 			panic("wdir: newblk");
92116688Smckusick 		ndp->ni_dent.d_reclen = DIRBLKSIZ;
92218027Smckusick 		error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
92316688Smckusick 		    newentrysize, ndp->ni_offset, 1, (int *)0);
92418104Smckusick 		if (DIRBLKSIZ > dp->i_fs->fs_fsize)
92518104Smckusick 			panic("wdir: blksize"); /* XXX - should grow w/bmap() */
92618104Smckusick 		else
92718104Smckusick 			dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
92818027Smckusick 		iput(dp);
92910849Ssam 		return (error);
9307534Sroot 	}
9317534Sroot 
9327534Sroot 	/*
93316688Smckusick 	 * If ndp->ni_count is non-zero, then namei found space for the new
93416688Smckusick 	 * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count.
9357534Sroot 	 * in the directory.  To use this space, we may have to compact
9367534Sroot 	 * the entries located there, by copying them together towards
9377534Sroot 	 * the beginning of the block, leaving the free space in
9387534Sroot 	 * one usable chunk at the end.
9397534Sroot 	 */
9407534Sroot 
9417534Sroot 	/*
9427534Sroot 	 * Increase size of directory if entry eats into new space.
9437534Sroot 	 * This should never push the size past a new multiple of
9447534Sroot 	 * DIRBLKSIZE.
94518104Smckusick 	 *
94618104Smckusick 	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
9477534Sroot 	 */
94818027Smckusick 	if (ndp->ni_offset + ndp->ni_count > dp->i_size)
94918027Smckusick 		dp->i_size = ndp->ni_offset + ndp->ni_count;
9507534Sroot 
9517534Sroot 	/*
9527534Sroot 	 * Get the block containing the space for the new directory
95310849Ssam 	 * entry.  Should return error by result instead of u.u_error.
9547534Sroot 	 */
95518027Smckusick 	bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf);
9569166Ssam 	if (bp == 0) {
95718027Smckusick 		iput(dp);
95810849Ssam 		return (u.u_error);
9599166Ssam 	}
9607534Sroot 
9617534Sroot 	/*
9627534Sroot 	 * Find space for the new entry.  In the simple case, the
9637534Sroot 	 * entry at offset base will have the space.  If it does
9647534Sroot 	 * not, then namei arranged that compacting the region
96516688Smckusick 	 * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space.
9667534Sroot 	 */
9677534Sroot 	ep = (struct direct *)dirbuf;
9687534Sroot 	dsize = DIRSIZ(ep);
96911639Ssam 	spacefree = ep->d_reclen - dsize;
97016688Smckusick 	for (loc = ep->d_reclen; loc < ndp->ni_count; ) {
9717534Sroot 		nep = (struct direct *)(dirbuf + loc);
9727534Sroot 		if (ep->d_ino) {
9737534Sroot 			/* trim the existing slot */
9747534Sroot 			ep->d_reclen = dsize;
9757534Sroot 			ep = (struct direct *)((char *)ep + dsize);
9767534Sroot 		} else {
9777534Sroot 			/* overwrite; nothing there; header is ours */
97811639Ssam 			spacefree += dsize;
9797534Sroot 		}
9807534Sroot 		dsize = DIRSIZ(nep);
98111639Ssam 		spacefree += nep->d_reclen - dsize;
9827534Sroot 		loc += nep->d_reclen;
9837825Sroot 		bcopy((caddr_t)nep, (caddr_t)ep, dsize);
9847534Sroot 	}
9857534Sroot 	/*
9867534Sroot 	 * Update the pointer fields in the previous entry (if any),
9877534Sroot 	 * copy in the new entry, and write out the block.
9887534Sroot 	 */
9897534Sroot 	if (ep->d_ino == 0) {
99011639Ssam 		if (spacefree + dsize < newentrysize)
9917534Sroot 			panic("wdir: compact1");
99216688Smckusick 		ndp->ni_dent.d_reclen = spacefree + dsize;
9937534Sroot 	} else {
99411639Ssam 		if (spacefree < newentrysize)
9957534Sroot 			panic("wdir: compact2");
99616688Smckusick 		ndp->ni_dent.d_reclen = spacefree;
9977534Sroot 		ep->d_reclen = dsize;
9987534Sroot 		ep = (struct direct *)((char *)ep + dsize);
9997534Sroot 	}
100016688Smckusick 	bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize);
10017534Sroot 	bwrite(bp);
100218027Smckusick 	dp->i_flag |= IUPD|ICHG;
100318027Smckusick 	if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size)
100418027Smckusick 		itrunc(dp, ndp->ni_endoff);
100518027Smckusick 	iput(dp);
100610849Ssam 	return (error);
10075972Swnj }
10086571Smckusic 
10099166Ssam /*
10109166Ssam  * Remove a directory entry after a call to namei, using the
10119166Ssam  * parameters which it left in the u. area.  The u. entry
101216688Smckusick  * ni_offset contains the offset into the directory of the
101316688Smckusick  * entry to be eliminated.  The ni_count field contains the
10149166Ssam  * size of the previous record in the directory.  If this
10159166Ssam  * is 0, the first entry is being deleted, so we need only
10169166Ssam  * zero the inode number to mark the entry as free.  If the
10179166Ssam  * entry isn't the first in the directory, we must reclaim
10189166Ssam  * the space of the now empty record by adding the record size
10199166Ssam  * to the size of the previous entry.
10209166Ssam  */
102116688Smckusick dirremove(ndp)
102216688Smckusick 	register struct nameidata *ndp;
10236571Smckusic {
102416688Smckusick 	register struct inode *dp = ndp->ni_pdir;
10257534Sroot 	register struct buf *bp;
10267534Sroot 	struct direct *ep;
10276571Smckusic 
102816688Smckusick 	if (ndp->ni_count == 0) {
10297534Sroot 		/*
10307534Sroot 		 * First entry in block: set d_ino to zero.
10317534Sroot 		 */
103216688Smckusick 		ndp->ni_dent.d_ino = 0;
103316688Smckusick 		(void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
103416688Smckusick 		    (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);
10359269Ssam 	} else {
10367534Sroot 		/*
10377534Sroot 		 * Collapse new free space into previous entry.
10387534Sroot 		 */
103916688Smckusick 		bp = blkatoff(dp, (int)(ndp->ni_offset - ndp->ni_count),
104016688Smckusick 			(char **)&ep);
10417534Sroot 		if (bp == 0)
10427534Sroot 			return (0);
104316688Smckusick 		ep->d_reclen += ndp->ni_dent.d_reclen;
10447534Sroot 		bwrite(bp);
10457534Sroot 		dp->i_flag |= IUPD|ICHG;
10467534Sroot 	}
10477534Sroot 	return (1);
10486571Smckusic }
10497534Sroot 
10507605Ssam /*
10519166Ssam  * Rewrite an existing directory entry to point at the inode
10529166Ssam  * supplied.  The parameters describing the directory entry are
10539166Ssam  * set up by a call to namei.
10549166Ssam  */
105516688Smckusick dirrewrite(dp, ip, ndp)
10569166Ssam 	struct inode *dp, *ip;
105716688Smckusick 	struct nameidata *ndp;
10589166Ssam {
10599166Ssam 
106016688Smckusick 	ndp->ni_dent.d_ino = ip->i_number;
106116688Smckusick 	u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent,
106216688Smckusick 		(int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0);
10639166Ssam 	iput(dp);
10649166Ssam }
10659166Ssam 
10669166Ssam /*
10677605Ssam  * Return buffer with contents of block "offset"
10687605Ssam  * from the beginning of directory "ip".  If "res"
10697605Ssam  * is non-zero, fill it in with a pointer to the
10707605Ssam  * remaining space in the directory.
10717605Ssam  */
10727534Sroot struct buf *
10737605Ssam blkatoff(ip, offset, res)
10747534Sroot 	struct inode *ip;
10757534Sroot 	off_t offset;
10767534Sroot 	char **res;
10777534Sroot {
10787534Sroot 	register struct fs *fs = ip->i_fs;
10798672Sroot 	daddr_t lbn = lblkno(fs, offset);
10807534Sroot 	int bsize = blksize(fs, ip, lbn);
10817534Sroot 	register struct buf *bp;
108218663Smckusick 	daddr_t bn;
10837534Sroot 
108418663Smckusick 	bn = bmap(ip, lbn, B_READ, bsize);
10857534Sroot 	if (u.u_error)
10867534Sroot 		return (0);
108718663Smckusick 	if (bn == (daddr_t)-1) {
108818663Smckusick 		dirbad(ip, offset, "hole in dir");
108918663Smckusick 		return (0);
109018663Smckusick 	}
109118663Smckusick 	bp = bread(ip->i_dev, fsbtodb(fs, bn), bsize);
10927534Sroot 	if (bp->b_flags & B_ERROR) {
10937534Sroot 		brelse(bp);
10947534Sroot 		return (0);
10957534Sroot 	}
10967534Sroot 	if (res)
109718663Smckusick 		*res = bp->b_un.b_addr + blkoff(fs, offset);
10987534Sroot 	return (bp);
10997534Sroot }
11009166Ssam 
11019166Ssam /*
11029166Ssam  * Check if a directory is empty or not.
11039166Ssam  * Inode supplied must be locked.
110412817Ssam  *
110512817Ssam  * Using a struct dirtemplate here is not precisely
110612817Ssam  * what we want, but better than using a struct direct.
110712817Ssam  *
110812817Ssam  * NB: does not handle corrupted directories.
11099166Ssam  */
111016777Smckusick dirempty(ip, parentino)
11119863Ssam 	register struct inode *ip;
111216777Smckusick 	ino_t parentino;
11139166Ssam {
11149166Ssam 	register off_t off;
111512817Ssam 	struct dirtemplate dbuf;
111612817Ssam 	register struct direct *dp = (struct direct *)&dbuf;
11179863Ssam 	int error, count;
111812817Ssam #define	MINDIRSIZ (sizeof (struct dirtemplate) / 2)
11199166Ssam 
11209166Ssam 	for (off = 0; off < ip->i_size; off += dp->d_reclen) {
112112817Ssam 		error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ,
112212817Ssam 		    off, 1, &count);
112312817Ssam 		/*
112412817Ssam 		 * Since we read MINDIRSIZ, residual must
112512817Ssam 		 * be 0 unless we're at end of file.
112612817Ssam 		 */
112712817Ssam 		if (error || count != 0)
11289166Ssam 			return (0);
1129*24534Smckusick 		/* avoid infinite loops */
1130*24534Smckusick 		if (dp->d_reclen <= 0)
1131*24534Smckusick 			return (0);
113212817Ssam 		/* skip empty entries */
11339166Ssam 		if (dp->d_ino == 0)
11349166Ssam 			continue;
113512817Ssam 		/* accept only "." and ".." */
113612817Ssam 		if (dp->d_namlen > 2)
113712817Ssam 			return (0);
11389166Ssam 		if (dp->d_name[0] != '.')
11399166Ssam 			return (0);
114012817Ssam 		/*
114112817Ssam 		 * At this point d_namlen must be 1 or 2.
114212817Ssam 		 * 1 implies ".", 2 implies ".." if second
114312817Ssam 		 * char is also "."
114412817Ssam 		 */
114516777Smckusick 		if (dp->d_namlen == 1)
11469166Ssam 			continue;
114716777Smckusick 		if (dp->d_name[1] == '.' && dp->d_ino == parentino)
114816777Smckusick 			continue;
11499166Ssam 		return (0);
11509166Ssam 	}
11519166Ssam 	return (1);
11529166Ssam }
115312815Smckusick 
115412815Smckusick /*
115512815Smckusick  * Check if source directory is in the path of the target directory.
115612815Smckusick  * Target is supplied locked, source is unlocked.
115712815Smckusick  * The target is always iput() before returning.
115812815Smckusick  */
115912815Smckusick checkpath(source, target)
116012815Smckusick 	struct inode *source, *target;
116112815Smckusick {
116212815Smckusick 	struct dirtemplate dirbuf;
116312815Smckusick 	register struct inode *ip;
116412815Smckusick 	int error = 0;
116512815Smckusick 
116612815Smckusick 	ip = target;
116712815Smckusick 	if (ip->i_number == source->i_number) {
116812815Smckusick 		error = EEXIST;
116912815Smckusick 		goto out;
117012815Smckusick 	}
117112815Smckusick 	if (ip->i_number == ROOTINO)
117212815Smckusick 		goto out;
117312815Smckusick 
117412815Smckusick 	for (;;) {
117512815Smckusick 		if ((ip->i_mode&IFMT) != IFDIR) {
117612815Smckusick 			error = ENOTDIR;
117712815Smckusick 			break;
117812815Smckusick 		}
117912815Smckusick 		error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
118012815Smckusick 			sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
118112815Smckusick 		if (error != 0)
118212815Smckusick 			break;
118312815Smckusick 		if (dirbuf.dotdot_namlen != 2 ||
118416658Smckusick 		    dirbuf.dotdot_name[0] != '.' ||
118516658Smckusick 		    dirbuf.dotdot_name[1] != '.') {
118612815Smckusick 			error = ENOTDIR;
118712815Smckusick 			break;
118812815Smckusick 		}
118912815Smckusick 		if (dirbuf.dotdot_ino == source->i_number) {
119012815Smckusick 			error = EINVAL;
119112815Smckusick 			break;
119212815Smckusick 		}
119312815Smckusick 		if (dirbuf.dotdot_ino == ROOTINO)
119412815Smckusick 			break;
119512815Smckusick 		iput(ip);
119612815Smckusick 		ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino);
119712815Smckusick 		if (ip == NULL) {
119812815Smckusick 			error = u.u_error;
119912815Smckusick 			break;
120012815Smckusick 		}
120112815Smckusick 	}
120212815Smckusick 
120312815Smckusick out:
120412815Smckusick 	if (error == ENOTDIR)
120512815Smckusick 		printf("checkpath: .. not a directory\n");
120612815Smckusick 	if (ip != NULL)
120712815Smckusick 		iput(ip);
120812815Smckusick 	return (error);
120912815Smckusick }
121015798Smckusick 
121115798Smckusick /*
121215798Smckusick  * Name cache initialization, from main() when we are booting
121315798Smckusick  */
121415798Smckusick nchinit()
121515798Smckusick {
121615798Smckusick 	register union nchash *nchp;
121715798Smckusick 	register struct nch *ncp;
121815798Smckusick 
121915798Smckusick 	nchhead = 0;
122015798Smckusick 	nchtail = &nchhead;
122115798Smckusick 
122215798Smckusick 	for (ncp = nch; ncp < &nch[nchsize]; ncp++) {
122315798Smckusick 		ncp->nc_forw = ncp;			/* hash chain */
122415798Smckusick 		ncp->nc_back = ncp;
122515798Smckusick 
122615798Smckusick 		ncp->nc_nxt = NULL;			/* lru chain */
122715798Smckusick 		*nchtail = ncp;
122815798Smckusick 		ncp->nc_prev = nchtail;
122915798Smckusick 		nchtail = &ncp->nc_nxt;
123015798Smckusick 
123115798Smckusick 		/* all else is zero already */
123215798Smckusick 	}
123315798Smckusick 
123415798Smckusick 	for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) {
123515798Smckusick 		nchp->nch_head[0] = nchp;
123615798Smckusick 		nchp->nch_head[1] = nchp;
123715798Smckusick 	}
123815798Smckusick }
123915798Smckusick 
124015798Smckusick /*
124115798Smckusick  * Cache flush, called when filesys is umounted to
124215798Smckusick  * remove entries that would now be invalid
124315798Smckusick  *
124415798Smckusick  * The line "nxtcp = nchhead" near the end is to avoid potential problems
124515798Smckusick  * if the cache lru chain is modified while we are dumping the
124615798Smckusick  * inode.  This makes the algorithm O(n^2), but do you think I care?
124715798Smckusick  */
124815798Smckusick nchinval(dev)
124915798Smckusick 	register dev_t dev;
125015798Smckusick {
125115798Smckusick 	register struct nch *ncp, *nxtcp;
125215798Smckusick 
125315798Smckusick 	for (ncp = nchhead; ncp; ncp = nxtcp) {
125415798Smckusick 		nxtcp = ncp->nc_nxt;
125515798Smckusick 
125615798Smckusick 		if (ncp->nc_ip == NULL ||
125715798Smckusick 		    (ncp->nc_idev != dev && ncp->nc_dev != dev))
125815798Smckusick 			continue;
125915798Smckusick 
126016658Smckusick 			/* free the resources we had */
126115798Smckusick 		ncp->nc_idev = NODEV;
126215798Smckusick 		ncp->nc_dev = NODEV;
126316658Smckusick 		ncp->nc_id = NULL;
126415798Smckusick 		ncp->nc_ino = 0;
126516658Smckusick 		ncp->nc_ip = NULL;
126615798Smckusick 
126716658Smckusick 
126815798Smckusick 			/* remove the entry from its hash chain */
126915798Smckusick 		remque(ncp);
127015798Smckusick 			/* and make a dummy one */
127115798Smckusick 		ncp->nc_forw = ncp;
127215798Smckusick 		ncp->nc_back = ncp;
127315798Smckusick 
127415798Smckusick 			/* delete this entry from LRU chain */
127515798Smckusick 		*ncp->nc_prev = nxtcp;
127615798Smckusick 		if (nxtcp)
127715798Smckusick 			nxtcp->nc_prev = ncp->nc_prev;
127815798Smckusick 		else
127915798Smckusick 			nchtail = ncp->nc_prev;
128015798Smckusick 
128115798Smckusick 			/* cause rescan of list, it may have altered */
128215798Smckusick 		nxtcp = nchhead;
128315798Smckusick 			/* put the now-free entry at head of LRU */
128415798Smckusick 		ncp->nc_nxt = nxtcp;
128515798Smckusick 		ncp->nc_prev = &nchhead;
128615798Smckusick 		nxtcp->nc_prev = &ncp->nc_nxt;
128715798Smckusick 		nchhead = ncp;
128815798Smckusick 	}
128915798Smckusick }
129017704Smckusick 
129117704Smckusick /*
129217704Smckusick  * Name cache invalidation of all entries.
129317704Smckusick  */
129417704Smckusick cacheinvalall()
129517704Smckusick {
129617704Smckusick 	register struct nch *ncp;
129717704Smckusick 
129817704Smckusick 	for (ncp = nch; ncp < &nch[nchsize]; ncp++) {
129917704Smckusick 		ncp->nc_id = 0;
130017704Smckusick 	}
130117704Smckusick }
1302