123401Smckusick /* 2*29119Smckusick * 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*29119Smckusick * @(#)vfs_lookup.c 7.1 (Berkeley) 06/05/86 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 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 */ 1287534Sroot register struct buf *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 */ 16016681Smckusick nbp = freenamebuf; 16116681Smckusick if (nbp == NULL) 16216681Smckusick nbp = geteblk(MAXPATHLEN); 16316681Smckusick else 16416681Smckusick freenamebuf = nbp->av_forw; 16516688Smckusick if (ndp->ni_segflg == UIO_SYSSPACE) 16616705Smckusick error = copystr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN, 16716705Smckusick (u_int *)0); 16816688Smckusick else 16916705Smckusick error = copyinstr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN, 17016705Smckusick (u_int *)0); 17116688Smckusick if (error) { 17216688Smckusick u.u_error = error; 17316688Smckusick goto bad; 1745972Swnj } 1757534Sroot 1765972Swnj /* 1777534Sroot * Get starting directory. 17830Sbill */ 1797534Sroot cp = nbp->b_un.b_addr; 1805972Swnj if (*cp == '/') { 1815972Swnj while (*cp == '/') 1825972Swnj cp++; 18330Sbill if ((dp = u.u_rdir) == NULL) 18430Sbill dp = rootdir; 1857534Sroot } else 1867534Sroot dp = u.u_cdir; 1877534Sroot fs = dp->i_fs; 18816666Smckusick ILOCK(dp); 1895972Swnj dp->i_count++; 19016688Smckusick ndp->ni_pdir = (struct inode *)0xc0000000; /* illegal */ 19118027Smckusick ndp->ni_endoff = 0; 1927534Sroot 1937534Sroot /* 1947534Sroot * We come to dirloop to search a new directory. 1957534Sroot * The directory must be locked so that it can be 1967534Sroot * iput, and fs must be already set to dp->i_fs. 1977534Sroot */ 1986571Smckusic dirloop: 19930Sbill /* 2007534Sroot * Check accessiblity of directory. 20130Sbill */ 2027534Sroot if ((dp->i_mode&IFMT) != IFDIR) { 20330Sbill u.u_error = ENOTDIR; 2047534Sroot goto bad; 2057534Sroot } 2067534Sroot if (access(dp, IEXEC)) 2077534Sroot goto bad; 2087534Sroot 2096384Swnj dirloop2: 2107534Sroot /* 21116688Smckusick * Copy next component of name to ndp->ni_dent. 2127534Sroot */ 21315798Smckusick hash = 0; 2147534Sroot for (i = 0; *cp != 0 && *cp != '/'; cp++) { 2156571Smckusic if (i >= MAXNAMLEN) { 21621014Smckusick u.u_error = ENAMETOOLONG; 2177534Sroot goto bad; 2185972Swnj } 21921014Smckusick if (*cp & 0200) 22021014Smckusick if ((*cp&0377) == ('/'|0200) || flag != DELETE) { 22121014Smckusick u.u_error = EINVAL; 22221014Smckusick goto bad; 22321014Smckusick } 22416688Smckusick ndp->ni_dent.d_name[i++] = *cp; 22515798Smckusick hash += (unsigned char)*cp * i; 2265972Swnj } 22716688Smckusick ndp->ni_dent.d_namlen = i; 22816688Smckusick ndp->ni_dent.d_name[i] = '\0'; 22916658Smckusick isdotdot = (i == 2 && 23016688Smckusick ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.'); 23118109Smckusick makeentry = 1; 23218109Smckusick if (*cp == '\0' && docache == 0) 23318109Smckusick makeentry = 0; 2347534Sroot 2357534Sroot /* 2367534Sroot * Check for degenerate name (e.g. / or "") 2377534Sroot * which is a way of talking about a directory, 2387534Sroot * e.g. like "/." or ".". 2397534Sroot */ 24016688Smckusick if (ndp->ni_dent.d_name[0] == '\0') { 24115798Smckusick if (flag != LOOKUP || lockparent) { 24214937Smckusick u.u_error = EISDIR; 2437534Sroot goto bad; 2445972Swnj } 24516681Smckusick nbp->av_forw = freenamebuf; 24616681Smckusick freenamebuf = nbp; 2476571Smckusic return (dp); 2485972Swnj } 2497534Sroot 2506571Smckusic /* 25115798Smckusick * We now have a segment name to search for, and a directory to search. 25215798Smckusick * 25315798Smckusick * Before tediously performing a linear scan of the directory, 25415798Smckusick * check the name cache to see if the directory/name pair 25515798Smckusick * we are looking for is known already. We don't do this 25615798Smckusick * if the segment name is long, simply so the cache can avoid 25715798Smckusick * holding long names (which would either waste space, or 25815798Smckusick * add greatly to the complexity). 25915798Smckusick */ 26016688Smckusick if (ndp->ni_dent.d_namlen > NCHNAMLEN) { 26115798Smckusick nchstats.ncs_long++; 26218109Smckusick makeentry = 0; 26315798Smckusick } else { 26415798Smckusick nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)]; 26526306Skarels for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp; 26615798Smckusick ncp = ncp->nc_forw) { 26715798Smckusick if (ncp->nc_ino == dp->i_number && 26815798Smckusick ncp->nc_dev == dp->i_dev && 26916688Smckusick ncp->nc_nlen == ndp->ni_dent.d_namlen && 27016688Smckusick !bcmp(ncp->nc_name, ndp->ni_dent.d_name, 27126273Skarels (unsigned)ncp->nc_nlen)) 27215798Smckusick break; 27315798Smckusick } 27426306Skarels if (ncp == (struct namecache *)nhp) { 27515798Smckusick nchstats.ncs_miss++; 27615798Smckusick ncp = NULL; 27715798Smckusick } else { 27826306Skarels if (ncp->nc_id != ncp->nc_ip->i_id) 27916643Ssam nchstats.ncs_falsehits++; 28026306Skarels else if (!makeentry) 28116658Smckusick nchstats.ncs_badhits++; 28226306Skarels else { 28326273Skarels /* 28426273Skarels * move this slot to end of LRU 28526273Skarels * chain, if not already there 28626273Skarels */ 28715798Smckusick if (ncp->nc_nxt) { 28826273Skarels /* remove from LRU chain */ 28915798Smckusick *ncp->nc_prev = ncp->nc_nxt; 29015798Smckusick ncp->nc_nxt->nc_prev = ncp->nc_prev; 29115798Smckusick 29226273Skarels /* and replace at end of it */ 29315798Smckusick ncp->nc_nxt = NULL; 29415798Smckusick ncp->nc_prev = nchtail; 29515798Smckusick *nchtail = ncp; 29615798Smckusick nchtail = &ncp->nc_nxt; 29715798Smckusick } 29815798Smckusick 29916658Smckusick /* 30016658Smckusick * Get the next inode in the path. 30116666Smckusick * See comment above other `IUNLOCK' code for 30216658Smckusick * an explaination of the locking protocol. 30316658Smckusick */ 30415798Smckusick pdp = dp; 30518109Smckusick if (!isdotdot || dp != u.u_rdir) 30618109Smckusick dp = ncp->nc_ip; 30715798Smckusick if (dp == NULL) 30827693Smckusick panic("namei: null cache ino"); 30926306Skarels if (pdp == dp) 31016643Ssam dp->i_count++; 31126306Skarels else if (isdotdot) { 31218109Smckusick IUNLOCK(pdp); 31318109Smckusick igrab(dp); 31418109Smckusick } else { 31518109Smckusick igrab(dp); 31618109Smckusick IUNLOCK(pdp); 31716643Ssam } 31815798Smckusick 31916658Smckusick /* 32016658Smckusick * Verify that the inode that we got 32116658Smckusick * did not change while we were waiting 32216658Smckusick * for it to be locked. 32316658Smckusick */ 32416658Smckusick if (ncp->nc_id != ncp->nc_ip->i_id) { 32516658Smckusick iput(dp); 32616666Smckusick ILOCK(pdp); 32716658Smckusick dp = pdp; 32816658Smckusick nchstats.ncs_falsehits++; 32916658Smckusick } else { 33016688Smckusick ndp->ni_dent.d_ino = dp->i_number; 33116688Smckusick /* ni_dent.d_reclen is garbage ... */ 33216658Smckusick nchstats.ncs_goodhits++; 33316658Smckusick goto haveino; 33416658Smckusick } 33516658Smckusick } 33615798Smckusick 33715798Smckusick /* 33816643Ssam * Last component and we are renaming or deleting, 33916643Ssam * the cache entry is invalid, or otherwise don't 34016643Ssam * want cache entry to exist. 34115798Smckusick */ 34226273Skarels /* remove from LRU chain */ 34315798Smckusick *ncp->nc_prev = ncp->nc_nxt; 34415798Smckusick if (ncp->nc_nxt) 34515798Smckusick ncp->nc_nxt->nc_prev = ncp->nc_prev; 34615798Smckusick else 34715798Smckusick nchtail = ncp->nc_prev; 34826273Skarels remque(ncp); /* remove from hash chain */ 34926273Skarels /* insert at head of LRU list (first to grab) */ 35015798Smckusick ncp->nc_nxt = nchhead; 35115798Smckusick ncp->nc_prev = &nchhead; 35215798Smckusick nchhead->nc_prev = &ncp->nc_nxt; 35315798Smckusick nchhead = ncp; 35426273Skarels /* and make a dummy hash chain */ 35515798Smckusick ncp->nc_forw = ncp; 35615798Smckusick ncp->nc_back = ncp; 35715798Smckusick ncp = NULL; 35815798Smckusick } 35915798Smckusick } 36015798Smckusick 36115798Smckusick /* 3627534Sroot * Suppress search for slots unless creating 3637534Sroot * file and at end of pathname, in which case 3647534Sroot * we watch for a place to put the new file in 3657534Sroot * case it doesn't already exist. 3666571Smckusic */ 3677534Sroot slotstatus = FOUND; 3689166Ssam if (flag == CREATE && *cp == 0) { 3697534Sroot slotstatus = NONE; 3707534Sroot slotfreespace = 0; 37116688Smckusick slotneeded = DIRSIZ(&ndp->ni_dent); 3727534Sroot } 37315660Smckusick /* 37415660Smckusick * If this is the same directory that this process 37515660Smckusick * previously searched, pick up where we last left off. 37615798Smckusick * We cache only lookups as these are the most common 37715660Smckusick * and have the greatest payoff. Caching CREATE has little 37815660Smckusick * benefit as it usually must search the entire directory 37915660Smckusick * to determine that the entry does not exist. Caching the 38015660Smckusick * location of the last DELETE has not reduced profiling time 38115660Smckusick * and hence has been removed in the interest of simplicity. 38215660Smckusick */ 38315660Smckusick if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber || 38415660Smckusick dp->i_dev != u.u_ncache.nc_dev) { 38516688Smckusick ndp->ni_offset = 0; 38615660Smckusick numdirpasses = 1; 38715660Smckusick } else { 38827693Smckusick if (u.u_ncache.nc_prevoffset > dp->i_size) 38927693Smckusick u.u_ncache.nc_prevoffset = 0; 39016688Smckusick ndp->ni_offset = u.u_ncache.nc_prevoffset; 39116688Smckusick entryoffsetinblock = blkoff(fs, ndp->ni_offset); 39215660Smckusick if (entryoffsetinblock != 0) { 39316688Smckusick bp = blkatoff(dp, ndp->ni_offset, (char **)0); 39415660Smckusick if (bp == 0) 39515660Smckusick goto bad; 39615660Smckusick } 39715660Smckusick numdirpasses = 2; 39815798Smckusick nchstats.ncs_2passes++; 39915660Smckusick } 40015660Smckusick endsearch = roundup(dp->i_size, DIRBLKSIZ); 40118027Smckusick enduseful = 0; 4027534Sroot 40315660Smckusick searchloop: 40416688Smckusick while (ndp->ni_offset < endsearch) { 4055972Swnj /* 4065972Swnj * If offset is on a block boundary, 4075972Swnj * read the next directory block. 4085972Swnj * Release previous if it exists. 4095972Swnj */ 41016688Smckusick if (blkoff(fs, ndp->ni_offset) == 0) { 4115972Swnj if (bp != NULL) 4125972Swnj brelse(bp); 41316688Smckusick bp = blkatoff(dp, ndp->ni_offset, (char **)0); 4147534Sroot if (bp == 0) 4157534Sroot goto bad; 4167534Sroot entryoffsetinblock = 0; 4175972Swnj } 4185972Swnj /* 4197534Sroot * If still looking for a slot, and at a DIRBLKSIZE 42016657Smckusick * boundary, have to start looking for free space again. 4216571Smckusic */ 4227534Sroot if (slotstatus == NONE && 4237534Sroot (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { 4247534Sroot slotoffset = -1; 4257534Sroot slotfreespace = 0; 4267534Sroot } 4277534Sroot /* 42816657Smckusick * Get pointer to next entry. 42916657Smckusick * Full validation checks are slow, so we only check 43016657Smckusick * enough to insure forward progress through the 43116657Smckusick * directory. Complete checks can be run by patching 43216657Smckusick * "dirchk" to be true. 4337534Sroot */ 4347534Sroot ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 43526273Skarels if (ep->d_reclen == 0 || 43616657Smckusick dirchk && dirbadentry(ep, entryoffsetinblock)) { 43716688Smckusick dirbad(dp, ndp->ni_offset, "mangled entry"); 43816657Smckusick i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 43916688Smckusick ndp->ni_offset += i; 4407534Sroot entryoffsetinblock += i; 4416571Smckusic continue; 4426571Smckusic } 4437534Sroot 4446571Smckusic /* 4457534Sroot * If an appropriate sized slot has not yet been found, 4466571Smckusic * check to see if one is available. Also accumulate space 4476571Smckusic * in the current block so that we can determine if 4486571Smckusic * compaction is viable. 4496571Smckusic */ 4507534Sroot if (slotstatus != FOUND) { 4517534Sroot int size = ep->d_reclen; 4527534Sroot 4536571Smckusic if (ep->d_ino != 0) 4546571Smckusic size -= DIRSIZ(ep); 4556571Smckusic if (size > 0) { 4567534Sroot if (size >= slotneeded) { 4577534Sroot slotstatus = FOUND; 45816688Smckusick slotoffset = ndp->ni_offset; 4597534Sroot slotsize = ep->d_reclen; 4607534Sroot } else if (slotstatus == NONE) { 4617534Sroot slotfreespace += size; 4627534Sroot if (slotoffset == -1) 46316688Smckusick slotoffset = ndp->ni_offset; 4647534Sroot if (slotfreespace >= slotneeded) { 4657534Sroot slotstatus = COMPACT; 46616688Smckusick slotsize = ndp->ni_offset + 46716688Smckusick ep->d_reclen - slotoffset; 4687534Sroot } 4696571Smckusic } 4706571Smckusic } 4716571Smckusic } 4727534Sroot 4736571Smckusic /* 4747534Sroot * Check for a name match. 4755972Swnj */ 4767534Sroot if (ep->d_ino) { 47716688Smckusick if (ep->d_namlen == ndp->ni_dent.d_namlen && 47816688Smckusick !bcmp(ndp->ni_dent.d_name, ep->d_name, 47926273Skarels (unsigned)ep->d_namlen)) 4807534Sroot goto found; 4817534Sroot } 48216688Smckusick prevoff = ndp->ni_offset; 48316688Smckusick ndp->ni_offset += ep->d_reclen; 4847534Sroot entryoffsetinblock += ep->d_reclen; 48518027Smckusick if (ep->d_ino) 48618027Smckusick enduseful = ndp->ni_offset; 4877534Sroot } 48815798Smckusick /* notfound: */ 48915660Smckusick /* 49015798Smckusick * If we started in the middle of the directory and failed 49115660Smckusick * to find our target, we must check the beginning as well. 49215660Smckusick */ 49315660Smckusick if (numdirpasses == 2) { 49415660Smckusick numdirpasses--; 49516688Smckusick ndp->ni_offset = 0; 49615660Smckusick endsearch = u.u_ncache.nc_prevoffset; 49715660Smckusick goto searchloop; 49815660Smckusick } 4997534Sroot /* 5007534Sroot * If creating, and at end of pathname and current 5019166Ssam * directory has not been removed, then can consider 5029166Ssam * allowing file to be created. 5037534Sroot */ 5049166Ssam if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) { 5055972Swnj /* 5067534Sroot * Access for write is interpreted as allowing 5077534Sroot * creation of files in the directory. 5085972Swnj */ 5097534Sroot if (access(dp, IWRITE)) 5107534Sroot goto bad; 5115972Swnj /* 5127534Sroot * Return an indication of where the new directory 5137534Sroot * entry should be put. If we didn't find a slot, 51416688Smckusick * then set ndp->ni_count to 0 indicating that the new 51516688Smckusick * slot belongs at the end of the directory. If we found 51616688Smckusick * a slot, then the new entry can be put in the range 51716688Smckusick * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count) 5185972Swnj */ 51915660Smckusick if (slotstatus == NONE) { 52016688Smckusick ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ); 52116688Smckusick ndp->ni_count = 0; 52218027Smckusick enduseful = ndp->ni_offset; 52315660Smckusick } else { 52416688Smckusick ndp->ni_offset = slotoffset; 52516688Smckusick ndp->ni_count = slotsize; 52618027Smckusick if (enduseful < slotoffset + slotsize) 52718027Smckusick enduseful = slotoffset + slotsize; 5285972Swnj } 52918027Smckusick ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ); 5307534Sroot dp->i_flag |= IUPD|ICHG; 5317534Sroot if (bp) 5327534Sroot brelse(bp); 53316681Smckusick nbp->av_forw = freenamebuf; 53416681Smckusick freenamebuf = nbp; 5355972Swnj /* 5367534Sroot * We return with the directory locked, so that 5377534Sroot * the parameters we set up above will still be 5387534Sroot * valid if we actually decide to do a direnter(). 5397534Sroot * We return NULL to indicate that the entry doesn't 5407534Sroot * currently exist, leaving a pointer to the (locked) 54116688Smckusick * directory inode in ndp->ni_pdir. 5425972Swnj */ 54316688Smckusick ndp->ni_pdir = dp; 5447534Sroot return (NULL); 5457534Sroot } 5467534Sroot u.u_error = ENOENT; 5477534Sroot goto bad; 5487534Sroot found: 54915798Smckusick if (numdirpasses == 2) 55015798Smckusick nchstats.ncs_pass2++; 5517534Sroot /* 5527534Sroot * Check that directory length properly reflects presence 5537534Sroot * of this entry. 5547534Sroot */ 5557605Ssam if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 55616688Smckusick dirbad(dp, ndp->ni_offset, "i_size too small"); 5577605Ssam dp->i_size = entryoffsetinblock + DIRSIZ(ep); 5587534Sroot dp->i_flag |= IUPD|ICHG; 5597534Sroot } 5607534Sroot 5617534Sroot /* 56215660Smckusick * Found component in pathname. 56315798Smckusick * If the final component of path name, save information 56415660Smckusick * in the cache as to where the entry was found. 5657534Sroot */ 56615660Smckusick if (*cp == '\0' && flag == LOOKUP) { 56727693Smckusick u.u_ncache.nc_prevoffset = ndp->ni_offset &~ (DIRBLKSIZ - 1); 56815660Smckusick u.u_ncache.nc_inumber = dp->i_number; 56915660Smckusick u.u_ncache.nc_dev = dp->i_dev; 57015660Smckusick } 57115660Smckusick /* 57218109Smckusick * Save directory entry's inode number and reclen in ndp->ni_dent, 57315660Smckusick * and release directory buffer. 57415660Smckusick */ 57518109Smckusick ndp->ni_dent.d_ino = ep->d_ino; 57618109Smckusick ndp->ni_dent.d_reclen = ep->d_reclen; 5777534Sroot brelse(bp); 5787534Sroot bp = NULL; 5797534Sroot 5807534Sroot /* 5817534Sroot * If deleting, and at end of pathname, return 5827534Sroot * parameters which can be used to remove file. 5839166Ssam * If the lockparent flag isn't set, we return only 58416688Smckusick * the directory (in ndp->ni_pdir), otherwise we go 5859166Ssam * on and lock the inode, being careful with ".". 5867534Sroot */ 5879166Ssam if (flag == DELETE && *cp == 0) { 5887534Sroot /* 5897534Sroot * Write access to directory required to delete files. 5907534Sroot */ 5917534Sroot if (access(dp, IWRITE)) 5927534Sroot goto bad; 59316688Smckusick ndp->ni_pdir = dp; /* for dirremove() */ 5947534Sroot /* 59516688Smckusick * Return pointer to current entry in ndp->ni_offset, 5967534Sroot * and distance past previous entry (if there 59716688Smckusick * is a previous entry in this block) in ndp->ni_count. 59816688Smckusick * Save directory inode pointer in ndp->ni_pdir for dirremove(). 5997534Sroot */ 60016688Smckusick if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0) 60116688Smckusick ndp->ni_count = 0; 6027534Sroot else 60316688Smckusick ndp->ni_count = ndp->ni_offset - prevoff; 6049166Ssam if (lockparent) { 60516688Smckusick if (dp->i_number == ndp->ni_dent.d_ino) 6069166Ssam dp->i_count++; 6079166Ssam else { 60816688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 6099166Ssam if (dp == NULL) { 61016688Smckusick iput(ndp->ni_pdir); 6119166Ssam goto bad; 6129166Ssam } 61315798Smckusick /* 61416046Skarels * If directory is "sticky", then user must own 61515798Smckusick * the directory, or the file in it, else he 61615798Smckusick * may not delete it (unless he's root). This 61715798Smckusick * implements append-only directories. 61815798Smckusick */ 61916688Smckusick if ((ndp->ni_pdir->i_mode & ISVTX) && 62015798Smckusick u.u_uid != 0 && 62116688Smckusick u.u_uid != ndp->ni_pdir->i_uid && 62215798Smckusick dp->i_uid != u.u_uid) { 62316688Smckusick iput(ndp->ni_pdir); 62415798Smckusick u.u_error = EPERM; 62515798Smckusick goto bad; 62615798Smckusick } 6279166Ssam } 6289166Ssam } 62916681Smckusick nbp->av_forw = freenamebuf; 63016681Smckusick freenamebuf = nbp; 6317534Sroot return (dp); 6327534Sroot } 6337534Sroot 6347534Sroot /* 6357534Sroot * Special handling for ".." allowing chdir out of mounted 6367534Sroot * file system: indirect .. in root inode to reevaluate 6377534Sroot * in directory file system was mounted on. 6387534Sroot */ 63916658Smckusick if (isdotdot) { 64018109Smckusick if (dp == u.u_rdir) { 64116688Smckusick ndp->ni_dent.d_ino = dp->i_number; 64218109Smckusick makeentry = 0; 64318109Smckusick } else if (ndp->ni_dent.d_ino == ROOTINO && 6447534Sroot dp->i_number == ROOTINO) { 6457534Sroot for (i = 1; i < NMOUNT; i++) 6467534Sroot if (mount[i].m_bufp != NULL && 6477534Sroot mount[i].m_dev == dp->i_dev) { 6486571Smckusic iput(dp); 6497534Sroot dp = mount[i].m_inodp; 65016666Smckusick ILOCK(dp); 6515972Swnj dp->i_count++; 6527534Sroot fs = dp->i_fs; 6537534Sroot cp -= 2; /* back over .. */ 6547534Sroot goto dirloop2; 6555972Swnj } 65630Sbill } 6577534Sroot } 6587534Sroot 6597534Sroot /* 6609166Ssam * If rewriting (rename), return the inode and the 6619166Ssam * information required to rewrite the present directory 6629166Ssam * Must get inode of directory entry to verify it's a 6639166Ssam * regular file, or empty directory. 6649166Ssam */ 6659166Ssam if ((flag == CREATE && lockparent) && *cp == 0) { 6669166Ssam if (access(dp, IWRITE)) 6679166Ssam goto bad; 66816688Smckusick ndp->ni_pdir = dp; /* for dirrewrite() */ 6699166Ssam /* 6709166Ssam * Careful about locking second inode. 6719166Ssam * This can only occur if the target is ".". 6729166Ssam */ 67316688Smckusick if (dp->i_number == ndp->ni_dent.d_ino) { 6749166Ssam u.u_error = EISDIR; /* XXX */ 6759166Ssam goto bad; 6769166Ssam } 67716688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 6789166Ssam if (dp == NULL) { 67916688Smckusick iput(ndp->ni_pdir); 6809166Ssam goto bad; 6819166Ssam } 68216681Smckusick nbp->av_forw = freenamebuf; 68316681Smckusick freenamebuf = nbp; 6849166Ssam return (dp); 6859166Ssam } 6869166Ssam 6879166Ssam /* 68812011Smckusick * Check for symbolic link, which may require us to massage the 68912011Smckusick * name before we continue translation. We do not `iput' the 69012011Smckusick * directory because we may need it again if the symbolic link 69112011Smckusick * is relative to the current directory. Instead we save it 69212011Smckusick * unlocked as "pdp". We must get the target inode before unlocking 69312011Smckusick * the directory to insure that the inode will not be removed 69412011Smckusick * before we get it. We prevent deadlock by always fetching 69512011Smckusick * inodes from the root, moving down the directory tree. Thus 69612011Smckusick * when following backward pointers ".." we must unlock the 69712011Smckusick * parent directory before getting the requested directory. 69812011Smckusick * There is a potential race condition here if both the current 69912011Smckusick * and parent directories are removed before the `iget' for the 70012011Smckusick * inode associated with ".." returns. We hope that this occurs 70112011Smckusick * infrequently since we cannot avoid this race condition without 70212492Ssam * implementing a sophisticated deadlock detection algorithm. 70312011Smckusick * Note also that this simple deadlock detection scheme will not 70412011Smckusick * work if the file system has any hard links other than ".." 70512011Smckusick * that point backwards in the directory structure. 7067534Sroot */ 7077534Sroot pdp = dp; 70815798Smckusick if (isdotdot) { 70916666Smckusick IUNLOCK(pdp); /* race to get the inode */ 71016688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 71112011Smckusick if (dp == NULL) 71212011Smckusick goto bad2; 71316688Smckusick } else if (dp->i_number == ndp->ni_dent.d_ino) { 71412011Smckusick dp->i_count++; /* we want ourself, ie "." */ 71512011Smckusick } else { 71616688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 71716666Smckusick IUNLOCK(pdp); 71812011Smckusick if (dp == NULL) 71912011Smckusick goto bad2; 72012011Smckusick } 72115798Smckusick 72215798Smckusick /* 72326273Skarels * Insert name into cache if appropriate. 72415798Smckusick */ 72518109Smckusick if (makeentry) { 72615798Smckusick if (ncp != NULL) 72727693Smckusick panic("namei: duplicating cache"); 72826273Skarels /* 72926273Skarels * Free the cache slot at head of lru chain. 73026273Skarels */ 73115798Smckusick if (ncp = nchhead) { 73226273Skarels /* remove from lru chain */ 73315798Smckusick *ncp->nc_prev = ncp->nc_nxt; 73415798Smckusick if (ncp->nc_nxt) 73515798Smckusick ncp->nc_nxt->nc_prev = ncp->nc_prev; 73615798Smckusick else 73715798Smckusick nchtail = ncp->nc_prev; 73826273Skarels remque(ncp); /* remove from old hash chain */ 73926273Skarels /* grab the inode we just found */ 74015798Smckusick ncp->nc_ip = dp; 74126273Skarels /* fill in cache info */ 74215798Smckusick ncp->nc_ino = pdp->i_number; /* parents inum */ 74315798Smckusick ncp->nc_dev = pdp->i_dev; /* & device */ 74415798Smckusick ncp->nc_idev = dp->i_dev; /* our device */ 74516643Ssam ncp->nc_id = dp->i_id; /* identifier */ 74616688Smckusick ncp->nc_nlen = ndp->ni_dent.d_namlen; 74726273Skarels bcopy(ndp->ni_dent.d_name, ncp->nc_name, 74826273Skarels (unsigned)ncp->nc_nlen); 74926273Skarels /* link at end of lru chain */ 75015798Smckusick ncp->nc_nxt = NULL; 75115798Smckusick ncp->nc_prev = nchtail; 75215798Smckusick *nchtail = ncp; 75315798Smckusick nchtail = &ncp->nc_nxt; 75426273Skarels /* and insert on hash chain */ 75515798Smckusick insque(ncp, nhp); 75615798Smckusick } 75715798Smckusick } 75815798Smckusick 75915798Smckusick haveino: 7607534Sroot fs = dp->i_fs; 7617534Sroot 7627534Sroot /* 7637534Sroot * Check for symbolic link 7647534Sroot */ 76516688Smckusick if ((dp->i_mode & IFMT) == IFLNK && 76616688Smckusick ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) { 7677825Sroot u_int pathlen = strlen(cp) + 1; 7687534Sroot 76921014Smckusick if (dp->i_size + pathlen >= MAXPATHLEN - 1) { 77021014Smckusick u.u_error = ENAMETOOLONG; 77121014Smckusick goto bad2; 77221014Smckusick } 77321014Smckusick if (++nlink > MAXSYMLINKS) { 7747534Sroot u.u_error = ELOOP; 7757534Sroot goto bad2; 7767534Sroot } 7778957Sroot ovbcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 7787751Sroot u.u_error = 7799166Ssam rdwri(UIO_READ, dp, nbp->b_un.b_addr, (int)dp->i_size, 78026360Skarels (off_t)0, 1, (int *)0); 7817534Sroot if (u.u_error) 7827534Sroot goto bad2; 7837534Sroot cp = nbp->b_un.b_addr; 7847534Sroot iput(dp); 7855972Swnj if (*cp == '/') { 7867534Sroot irele(pdp); 7875972Swnj while (*cp == '/') 7885972Swnj cp++; 7897534Sroot if ((dp = u.u_rdir) == NULL) 7907534Sroot dp = rootdir; 79116666Smckusick ILOCK(dp); 7927534Sroot dp->i_count++; 7937534Sroot } else { 7947534Sroot dp = pdp; 79516666Smckusick ILOCK(dp); 7965972Swnj } 7977534Sroot fs = dp->i_fs; 7987534Sroot goto dirloop; 79930Sbill } 8007534Sroot 80130Sbill /* 8027534Sroot * Not a symbolic link. If more pathname, 8037534Sroot * continue at next component, else return. 80430Sbill */ 8057534Sroot if (*cp == '/') { 8067534Sroot while (*cp == '/') 8077534Sroot cp++; 8089166Ssam irele(pdp); 8097534Sroot goto dirloop; 81030Sbill } 81116681Smckusick nbp->av_forw = freenamebuf; 81216681Smckusick freenamebuf = nbp; 8139166Ssam if (lockparent) 81416688Smckusick ndp->ni_pdir = pdp; 8159166Ssam else 8169166Ssam irele(pdp); 8177534Sroot return (dp); 8187534Sroot bad2: 8197534Sroot irele(pdp); 8207534Sroot bad: 8217534Sroot if (bp) 8227534Sroot brelse(bp); 8237534Sroot if (dp) 8247534Sroot iput(dp); 82516681Smckusick nbp->av_forw = freenamebuf; 82616681Smckusick freenamebuf = nbp; 8276571Smckusic return (NULL); 82830Sbill } 82930Sbill 83015798Smckusick 83116688Smckusick dirbad(ip, offset, how) 8327534Sroot struct inode *ip; 83316688Smckusick off_t offset; 8347534Sroot char *how; 8357534Sroot { 8367534Sroot 8377534Sroot printf("%s: bad dir ino %d at offset %d: %s\n", 83816688Smckusick ip->i_fs->fs_fsmnt, ip->i_number, offset, how); 8397534Sroot } 8407534Sroot 84116657Smckusick /* 84216657Smckusick * Do consistency checking on a directory entry: 84316657Smckusick * record length must be multiple of 4 84416657Smckusick * entry must fit in rest of its DIRBLKSIZ block 84516657Smckusick * record must be large enough to contain entry 84616657Smckusick * name is not longer than MAXNAMLEN 84716657Smckusick * name must be as long as advertised, and null terminated 84816657Smckusick */ 84916657Smckusick dirbadentry(ep, entryoffsetinblock) 8507534Sroot register struct direct *ep; 85116657Smckusick int entryoffsetinblock; 8527534Sroot { 8537534Sroot register int i; 8547534Sroot 85526273Skarels if ((ep->d_reclen & 0x3) != 0 || 85616657Smckusick ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 85716657Smckusick ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) 85816657Smckusick return (1); 8597534Sroot for (i = 0; i < ep->d_namlen; i++) 86016688Smckusick if (ep->d_name[i] == '\0') 8617534Sroot return (1); 8627534Sroot return (ep->d_name[i]); 8637534Sroot } 8647534Sroot 86530Sbill /* 8667534Sroot * Write a directory entry after a call to namei, using the parameters 8677534Sroot * which it left in the u. area. The argument ip is the inode which 86816688Smckusick * the new directory entry will refer to. The u. area field ndp->ni_pdir is 8697534Sroot * a pointer to the directory to be written, which was left locked by 87016688Smckusick * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate 8717534Sroot * how the space for the new entry is to be gotten. 8727534Sroot */ 87316688Smckusick direnter(ip, ndp) 8747534Sroot struct inode *ip; 87516688Smckusick register struct nameidata *ndp; 8765972Swnj { 8777534Sroot register struct direct *ep, *nep; 87818027Smckusick register struct inode *dp = ndp->ni_pdir; 8797534Sroot struct buf *bp; 88011639Ssam int loc, spacefree, error = 0; 8818631Sroot u_int dsize; 8828631Sroot int newentrysize; 8837534Sroot char *dirbuf; 8845972Swnj 88516688Smckusick ndp->ni_dent.d_ino = ip->i_number; 88616688Smckusick newentrysize = DIRSIZ(&ndp->ni_dent); 88716688Smckusick if (ndp->ni_count == 0) { 8887534Sroot /* 88916688Smckusick * If ndp->ni_count is 0, then namei could find no space in the 89016688Smckusick * directory. In this case ndp->ni_offset will be on a directory 8917534Sroot * block boundary and we will write the new entry into a fresh 8927534Sroot * block. 8937534Sroot */ 89416688Smckusick if (ndp->ni_offset&(DIRBLKSIZ-1)) 8957534Sroot panic("wdir: newblk"); 89616688Smckusick ndp->ni_dent.d_reclen = DIRBLKSIZ; 89718027Smckusick error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 89816688Smckusick newentrysize, ndp->ni_offset, 1, (int *)0); 89918104Smckusick if (DIRBLKSIZ > dp->i_fs->fs_fsize) 90018104Smckusick panic("wdir: blksize"); /* XXX - should grow w/bmap() */ 90118104Smckusick else 90218104Smckusick dp->i_size = roundup(dp->i_size, DIRBLKSIZ); 90318027Smckusick iput(dp); 90410849Ssam return (error); 9057534Sroot } 9067534Sroot 9077534Sroot /* 90816688Smckusick * If ndp->ni_count is non-zero, then namei found space for the new 90916688Smckusick * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count. 9107534Sroot * in the directory. To use this space, we may have to compact 9117534Sroot * the entries located there, by copying them together towards 9127534Sroot * the beginning of the block, leaving the free space in 9137534Sroot * one usable chunk at the end. 9147534Sroot */ 9157534Sroot 9167534Sroot /* 9177534Sroot * Increase size of directory if entry eats into new space. 9187534Sroot * This should never push the size past a new multiple of 9197534Sroot * DIRBLKSIZE. 92018104Smckusick * 92118104Smckusick * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 9227534Sroot */ 92318027Smckusick if (ndp->ni_offset + ndp->ni_count > dp->i_size) 92418027Smckusick dp->i_size = ndp->ni_offset + ndp->ni_count; 9257534Sroot /* 9267534Sroot * Get the block containing the space for the new directory 92710849Ssam * entry. Should return error by result instead of u.u_error. 9287534Sroot */ 92918027Smckusick bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf); 9309166Ssam if (bp == 0) { 93118027Smckusick iput(dp); 93210849Ssam return (u.u_error); 9339166Ssam } 9347534Sroot /* 9357534Sroot * Find space for the new entry. In the simple case, the 9367534Sroot * entry at offset base will have the space. If it does 9377534Sroot * not, then namei arranged that compacting the region 93816688Smckusick * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space. 9397534Sroot */ 9407534Sroot ep = (struct direct *)dirbuf; 9417534Sroot dsize = DIRSIZ(ep); 94211639Ssam spacefree = ep->d_reclen - dsize; 94316688Smckusick for (loc = ep->d_reclen; loc < ndp->ni_count; ) { 9447534Sroot nep = (struct direct *)(dirbuf + loc); 9457534Sroot if (ep->d_ino) { 9467534Sroot /* trim the existing slot */ 9477534Sroot ep->d_reclen = dsize; 9487534Sroot ep = (struct direct *)((char *)ep + dsize); 9497534Sroot } else { 9507534Sroot /* overwrite; nothing there; header is ours */ 95111639Ssam spacefree += dsize; 9527534Sroot } 9537534Sroot dsize = DIRSIZ(nep); 95411639Ssam spacefree += nep->d_reclen - dsize; 9557534Sroot loc += nep->d_reclen; 9567825Sroot bcopy((caddr_t)nep, (caddr_t)ep, dsize); 9577534Sroot } 9587534Sroot /* 9597534Sroot * Update the pointer fields in the previous entry (if any), 9607534Sroot * copy in the new entry, and write out the block. 9617534Sroot */ 9627534Sroot if (ep->d_ino == 0) { 96311639Ssam if (spacefree + dsize < newentrysize) 9647534Sroot panic("wdir: compact1"); 96516688Smckusick ndp->ni_dent.d_reclen = spacefree + dsize; 9667534Sroot } else { 96711639Ssam if (spacefree < newentrysize) 9687534Sroot panic("wdir: compact2"); 96916688Smckusick ndp->ni_dent.d_reclen = spacefree; 9707534Sroot ep->d_reclen = dsize; 9717534Sroot ep = (struct direct *)((char *)ep + dsize); 9727534Sroot } 97316688Smckusick bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize); 9747534Sroot bwrite(bp); 97518027Smckusick dp->i_flag |= IUPD|ICHG; 97618027Smckusick if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size) 97726273Skarels itrunc(dp, (u_long)ndp->ni_endoff); 97818027Smckusick iput(dp); 97910849Ssam return (error); 9805972Swnj } 9816571Smckusic 9829166Ssam /* 9839166Ssam * Remove a directory entry after a call to namei, using the 9849166Ssam * parameters which it left in the u. area. The u. entry 98516688Smckusick * ni_offset contains the offset into the directory of the 98616688Smckusick * entry to be eliminated. The ni_count field contains the 9879166Ssam * size of the previous record in the directory. If this 9889166Ssam * is 0, the first entry is being deleted, so we need only 9899166Ssam * zero the inode number to mark the entry as free. If the 9909166Ssam * entry isn't the first in the directory, we must reclaim 9919166Ssam * the space of the now empty record by adding the record size 9929166Ssam * to the size of the previous entry. 9939166Ssam */ 99416688Smckusick dirremove(ndp) 99516688Smckusick register struct nameidata *ndp; 9966571Smckusic { 99716688Smckusick register struct inode *dp = ndp->ni_pdir; 9987534Sroot register struct buf *bp; 9997534Sroot struct direct *ep; 10006571Smckusic 100116688Smckusick if (ndp->ni_count == 0) { 10027534Sroot /* 10037534Sroot * First entry in block: set d_ino to zero. 10047534Sroot */ 100516688Smckusick ndp->ni_dent.d_ino = 0; 100616688Smckusick (void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 100716688Smckusick (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0); 10089269Ssam } else { 10097534Sroot /* 10107534Sroot * Collapse new free space into previous entry. 10117534Sroot */ 101226360Skarels bp = blkatoff(dp, ndp->ni_offset - ndp->ni_count, (char **)&ep); 10137534Sroot if (bp == 0) 10147534Sroot return (0); 101516688Smckusick ep->d_reclen += ndp->ni_dent.d_reclen; 10167534Sroot bwrite(bp); 10177534Sroot dp->i_flag |= IUPD|ICHG; 10187534Sroot } 10197534Sroot return (1); 10206571Smckusic } 10217534Sroot 10227605Ssam /* 10239166Ssam * Rewrite an existing directory entry to point at the inode 10249166Ssam * supplied. The parameters describing the directory entry are 10259166Ssam * set up by a call to namei. 10269166Ssam */ 102716688Smckusick dirrewrite(dp, ip, ndp) 10289166Ssam struct inode *dp, *ip; 102916688Smckusick struct nameidata *ndp; 10309166Ssam { 10319166Ssam 103216688Smckusick ndp->ni_dent.d_ino = ip->i_number; 103316688Smckusick u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 103416688Smckusick (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0); 10359166Ssam iput(dp); 10369166Ssam } 10379166Ssam 10389166Ssam /* 10397605Ssam * Return buffer with contents of block "offset" 10407605Ssam * from the beginning of directory "ip". If "res" 10417605Ssam * is non-zero, fill it in with a pointer to the 10427605Ssam * remaining space in the directory. 10437605Ssam */ 10447534Sroot struct buf * 10457605Ssam blkatoff(ip, offset, res) 10467534Sroot struct inode *ip; 10477534Sroot off_t offset; 10487534Sroot char **res; 10497534Sroot { 10507534Sroot register struct fs *fs = ip->i_fs; 10518672Sroot daddr_t lbn = lblkno(fs, offset); 10527534Sroot int bsize = blksize(fs, ip, lbn); 10537534Sroot register struct buf *bp; 105418663Smckusick daddr_t bn; 10557534Sroot 105618663Smckusick bn = bmap(ip, lbn, B_READ, bsize); 10577534Sroot if (u.u_error) 10587534Sroot return (0); 105918663Smckusick if (bn == (daddr_t)-1) { 106018663Smckusick dirbad(ip, offset, "hole in dir"); 106118663Smckusick return (0); 106218663Smckusick } 106318663Smckusick bp = bread(ip->i_dev, fsbtodb(fs, bn), bsize); 10647534Sroot if (bp->b_flags & B_ERROR) { 10657534Sroot brelse(bp); 10667534Sroot return (0); 10677534Sroot } 10687534Sroot if (res) 106918663Smckusick *res = bp->b_un.b_addr + blkoff(fs, offset); 10707534Sroot return (bp); 10717534Sroot } 10729166Ssam 10739166Ssam /* 10749166Ssam * Check if a directory is empty or not. 10759166Ssam * Inode supplied must be locked. 107612817Ssam * 107712817Ssam * Using a struct dirtemplate here is not precisely 107812817Ssam * what we want, but better than using a struct direct. 107912817Ssam * 108012817Ssam * NB: does not handle corrupted directories. 10819166Ssam */ 108216777Smckusick dirempty(ip, parentino) 10839863Ssam register struct inode *ip; 108416777Smckusick ino_t parentino; 10859166Ssam { 10869166Ssam register off_t off; 108712817Ssam struct dirtemplate dbuf; 108812817Ssam register struct direct *dp = (struct direct *)&dbuf; 10899863Ssam int error, count; 109012817Ssam #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 10919166Ssam 10929166Ssam for (off = 0; off < ip->i_size; off += dp->d_reclen) { 109312817Ssam error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ, 109412817Ssam off, 1, &count); 109512817Ssam /* 109612817Ssam * Since we read MINDIRSIZ, residual must 109712817Ssam * be 0 unless we're at end of file. 109812817Ssam */ 109912817Ssam if (error || count != 0) 11009166Ssam return (0); 110124534Smckusick /* avoid infinite loops */ 110226273Skarels if (dp->d_reclen == 0) 110324534Smckusick return (0); 110412817Ssam /* skip empty entries */ 11059166Ssam if (dp->d_ino == 0) 11069166Ssam continue; 110712817Ssam /* accept only "." and ".." */ 110812817Ssam if (dp->d_namlen > 2) 110912817Ssam return (0); 11109166Ssam if (dp->d_name[0] != '.') 11119166Ssam return (0); 111212817Ssam /* 111312817Ssam * At this point d_namlen must be 1 or 2. 111412817Ssam * 1 implies ".", 2 implies ".." if second 111512817Ssam * char is also "." 111612817Ssam */ 111716777Smckusick if (dp->d_namlen == 1) 11189166Ssam continue; 111916777Smckusick if (dp->d_name[1] == '.' && dp->d_ino == parentino) 112016777Smckusick continue; 11219166Ssam return (0); 11229166Ssam } 11239166Ssam return (1); 11249166Ssam } 112512815Smckusick 112612815Smckusick /* 112712815Smckusick * Check if source directory is in the path of the target directory. 112812815Smckusick * Target is supplied locked, source is unlocked. 112912815Smckusick * The target is always iput() before returning. 113012815Smckusick */ 113112815Smckusick checkpath(source, target) 113212815Smckusick struct inode *source, *target; 113312815Smckusick { 113412815Smckusick struct dirtemplate dirbuf; 113512815Smckusick register struct inode *ip; 113612815Smckusick int error = 0; 113712815Smckusick 113812815Smckusick ip = target; 113912815Smckusick if (ip->i_number == source->i_number) { 114012815Smckusick error = EEXIST; 114112815Smckusick goto out; 114212815Smckusick } 114312815Smckusick if (ip->i_number == ROOTINO) 114412815Smckusick goto out; 114512815Smckusick 114612815Smckusick for (;;) { 114712815Smckusick if ((ip->i_mode&IFMT) != IFDIR) { 114812815Smckusick error = ENOTDIR; 114912815Smckusick break; 115012815Smckusick } 115112815Smckusick error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 115212815Smckusick sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 115312815Smckusick if (error != 0) 115412815Smckusick break; 115512815Smckusick if (dirbuf.dotdot_namlen != 2 || 115616658Smckusick dirbuf.dotdot_name[0] != '.' || 115716658Smckusick dirbuf.dotdot_name[1] != '.') { 115812815Smckusick error = ENOTDIR; 115912815Smckusick break; 116012815Smckusick } 116112815Smckusick if (dirbuf.dotdot_ino == source->i_number) { 116212815Smckusick error = EINVAL; 116312815Smckusick break; 116412815Smckusick } 116512815Smckusick if (dirbuf.dotdot_ino == ROOTINO) 116612815Smckusick break; 116712815Smckusick iput(ip); 116812815Smckusick ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino); 116912815Smckusick if (ip == NULL) { 117012815Smckusick error = u.u_error; 117112815Smckusick break; 117212815Smckusick } 117312815Smckusick } 117412815Smckusick 117512815Smckusick out: 117612815Smckusick if (error == ENOTDIR) 117712815Smckusick printf("checkpath: .. not a directory\n"); 117812815Smckusick if (ip != NULL) 117912815Smckusick iput(ip); 118012815Smckusick return (error); 118112815Smckusick } 118215798Smckusick 118315798Smckusick /* 118415798Smckusick * Name cache initialization, from main() when we are booting 118515798Smckusick */ 118615798Smckusick nchinit() 118715798Smckusick { 118815798Smckusick register union nchash *nchp; 118926306Skarels register struct namecache *ncp; 119015798Smckusick 119115798Smckusick nchhead = 0; 119215798Smckusick nchtail = &nchhead; 119326306Skarels for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) { 119415798Smckusick ncp->nc_forw = ncp; /* hash chain */ 119515798Smckusick ncp->nc_back = ncp; 119615798Smckusick ncp->nc_nxt = NULL; /* lru chain */ 119715798Smckusick *nchtail = ncp; 119815798Smckusick ncp->nc_prev = nchtail; 119915798Smckusick nchtail = &ncp->nc_nxt; 120015798Smckusick /* all else is zero already */ 120115798Smckusick } 120215798Smckusick for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) { 120315798Smckusick nchp->nch_head[0] = nchp; 120415798Smckusick nchp->nch_head[1] = nchp; 120515798Smckusick } 120615798Smckusick } 120715798Smckusick 120815798Smckusick /* 120915798Smckusick * Cache flush, called when filesys is umounted to 121015798Smckusick * remove entries that would now be invalid 121115798Smckusick * 121215798Smckusick * The line "nxtcp = nchhead" near the end is to avoid potential problems 121315798Smckusick * if the cache lru chain is modified while we are dumping the 121415798Smckusick * inode. This makes the algorithm O(n^2), but do you think I care? 121515798Smckusick */ 121615798Smckusick nchinval(dev) 121715798Smckusick register dev_t dev; 121815798Smckusick { 121926306Skarels register struct namecache *ncp, *nxtcp; 122015798Smckusick 122115798Smckusick for (ncp = nchhead; ncp; ncp = nxtcp) { 122215798Smckusick nxtcp = ncp->nc_nxt; 122315798Smckusick if (ncp->nc_ip == NULL || 122415798Smckusick (ncp->nc_idev != dev && ncp->nc_dev != dev)) 122515798Smckusick continue; 122626273Skarels /* free the resources we had */ 122715798Smckusick ncp->nc_idev = NODEV; 122815798Smckusick ncp->nc_dev = NODEV; 122916658Smckusick ncp->nc_id = NULL; 123015798Smckusick ncp->nc_ino = 0; 123116658Smckusick ncp->nc_ip = NULL; 123226273Skarels remque(ncp); /* remove entry from its hash chain */ 123326273Skarels ncp->nc_forw = ncp; /* and make a dummy one */ 123415798Smckusick ncp->nc_back = ncp; 123526273Skarels /* delete this entry from LRU chain */ 123615798Smckusick *ncp->nc_prev = nxtcp; 123715798Smckusick if (nxtcp) 123815798Smckusick nxtcp->nc_prev = ncp->nc_prev; 123915798Smckusick else 124015798Smckusick nchtail = ncp->nc_prev; 124126273Skarels /* cause rescan of list, it may have altered */ 124215798Smckusick nxtcp = nchhead; 124326273Skarels /* put the now-free entry at head of LRU */ 124415798Smckusick ncp->nc_nxt = nxtcp; 124515798Smckusick ncp->nc_prev = &nchhead; 124615798Smckusick nxtcp->nc_prev = &ncp->nc_nxt; 124715798Smckusick nchhead = ncp; 124815798Smckusick } 124915798Smckusick } 125017704Smckusick 125117704Smckusick /* 125217704Smckusick * Name cache invalidation of all entries. 125317704Smckusick */ 125417704Smckusick cacheinvalall() 125517704Smckusick { 125626306Skarels register struct namecache *ncp; 125717704Smckusick 125826306Skarels for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) 125917704Smckusick ncp->nc_id = 0; 126017704Smckusick } 1261