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