1*17100Sbloom /* vfs_lookup.c 6.15 84/08/29 */ 230Sbill 3*17100Sbloom #include "param.h" 4*17100Sbloom #include "systm.h" 5*17100Sbloom #include "inode.h" 6*17100Sbloom #include "fs.h" 7*17100Sbloom #include "mount.h" 8*17100Sbloom #include "dir.h" 9*17100Sbloom #include "user.h" 10*17100Sbloom #include "buf.h" 11*17100Sbloom #include "conf.h" 12*17100Sbloom #include "uio.h" 13*17100Sbloom #include "kernel.h" 1430Sbill 157605Ssam struct buf *blkatoff(); 1616681Smckusick struct buf *freenamebuf; 179166Ssam int dirchk = 0; 1815798Smckusick 1930Sbill /* 2015798Smckusick * Structures associated with name cacheing. 2115798Smckusick */ 2215798Smckusick #define NCHHASH 32 /* size of hash table */ 2315798Smckusick 2415798Smckusick #if ((NCHHASH)&((NCHHASH)-1)) != 0 2515798Smckusick #define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) % (NCHHASH)) 2615798Smckusick #else 2715798Smckusick #define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) & ((NCHHASH)-1)) 2815798Smckusick #endif 2915798Smckusick 3015798Smckusick union nchash { 3115798Smckusick union nchash *nch_head[2]; 3215798Smckusick struct nch *nch_chain[2]; 3315798Smckusick } nchash[NCHHASH]; 3415798Smckusick #define nch_forw nch_chain[0] 3515798Smckusick #define nch_back nch_chain[1] 3615798Smckusick 3715809Smckusick struct nch *nchhead, **nchtail; /* LRU chain pointers */ 3815809Smckusick struct nchstats nchstats; /* cache effectiveness statistics */ 3915798Smckusick 4015798Smckusick /* 417534Sroot * Convert a pathname into a pointer to a locked inode, 427534Sroot * with side effects usable in creating and removing files. 437534Sroot * This is a very central and rather complicated routine. 4430Sbill * 4516688Smckusick * The segflg defines whether the name is to be copied from user 4616688Smckusick * space or kernel space. 477534Sroot * 489166Ssam * The flag argument is (LOOKUP, CREATE, DELETE) depending on whether 499166Ssam * the name is to be (looked up, created, deleted). If flag has 509166Ssam * LOCKPARENT or'ed into it and the target of the pathname exists, 519166Ssam * namei returns both the target and its parent directory locked. 529166Ssam * If the file system is not maintained in a strict tree hierarchy, 539166Ssam * this can result in a deadlock situation. When creating and 549166Ssam * LOCKPARENT is specified, the target may not be ".". When deleting 559166Ssam * and LOCKPARENT is specified, the target may be ".", but the caller 569166Ssam * must check to insure it does an irele and iput instead of two iputs. 579166Ssam * 5816688Smckusick * The FOLLOW flag is set when symbolic links are to be followed 599166Ssam * when they occur at the end of the name translation process. 609166Ssam * 6115798Smckusick * Name caching works as follows: 627534Sroot * 6315798Smckusick * names found by directory scans are retained in a cache 6415798Smckusick * for future reference. It is managed LRU, so frequently 6515798Smckusick * used names will hang around. Cache is indexed by hash value 6615798Smckusick * obtained from (ino,dev,name) where ino & dev refer to the 6715798Smckusick * directory containing name. 6815798Smckusick * 6915798Smckusick * For simplicity (and economy of storage), names longer than 7015798Smckusick * some (small) maximum length are not cached, they occur 7115798Smckusick * infrequently in any case, and are almost never of interest. 7215798Smckusick * 7315798Smckusick * Upon reaching the last segment of a path, if the reference 7415798Smckusick * is for DELETE, or NOCACHE is set (rewrite), and the 7515798Smckusick * name is located in the cache, it will be dropped. 7615798Smckusick * 7715798Smckusick * We must be sure never to enter the name ".." into the cache 7815798Smckusick * because of the extremely kludgey way that rename() alters 7915798Smckusick * ".." in a situation like 8015798Smckusick * mv a/x b/x 8115798Smckusick * where x is a directory, and x/.. is the ".." in question. 8215798Smckusick * 8315798Smckusick * Overall outline of namei: 8415798Smckusick * 857534Sroot * copy in name 867534Sroot * get starting directory 877534Sroot * dirloop: 887534Sroot * check accessibility of directory 897534Sroot * dirloop2: 9016688Smckusick * copy next component of name to ndp->ni_dent 917534Sroot * handle degenerate case where name is null string 9215798Smckusick * look for name in cache, if found, then if at end of path 9315798Smckusick * and deleting or creating, drop it, else to haveino 947534Sroot * search for name in directory, to found or notfound 957534Sroot * notfound: 969166Ssam * if creating, return locked directory, leaving info on avail. slots 977534Sroot * else return error 987534Sroot * found: 997534Sroot * if at end of path and deleting, return information to allow delete 10015798Smckusick * if at end of path and rewriting (create and LOCKPARENT), lock target 1019166Ssam * inode and return info to allow rewrite 1027534Sroot * if .. and on mounted filesys, look in mount table for parent 10315798Smckusick * if not at end, if neither creating nor deleting, add name to cache 10415798Smckusick * haveino: 1057534Sroot * if symbolic link, massage name in buffer and continue at dirloop 1067534Sroot * if more components of name, do next level at dirloop 1077534Sroot * return the answer as locked inode 1089166Ssam * 1099166Ssam * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode, 1109166Ssam * but unlocked. 11130Sbill */ 11230Sbill struct inode * 11316688Smckusick namei(ndp) 11416688Smckusick register struct nameidata *ndp; 11530Sbill { 1167534Sroot register char *cp; /* pointer into pathname argument */ 1177534Sroot /* these variables refer to things which must be freed or unlocked */ 1187534Sroot register struct inode *dp = 0; /* the directory we are searching */ 11915798Smckusick register struct nch *ncp; /* cache slot for entry */ 1207534Sroot register struct fs *fs; /* file system that directory is in */ 1217534Sroot register struct buf *bp = 0; /* a buffer of directory entries */ 1227534Sroot register struct direct *ep; /* the current directory entry */ 1237534Sroot int entryoffsetinblock; /* offset of ep in bp's buffer */ 1247534Sroot register struct buf *nbp; /* buffer storing path name argument */ 1257534Sroot /* these variables hold information about the search for a slot */ 1267534Sroot enum {NONE, COMPACT, FOUND} slotstatus; 1277534Sroot int slotoffset = -1; /* offset of area with free space */ 1287534Sroot int slotsize; /* size of area at slotoffset */ 1297534Sroot int slotfreespace; /* amount of space free in slot */ 1307534Sroot int slotneeded; /* size of the entry we're seeking */ 1317534Sroot /* */ 13215660Smckusick int numdirpasses; /* strategy for directory search */ 13315660Smckusick int endsearch; /* offset to end directory search */ 13416688Smckusick int prevoff; /* ndp->ni_offset of previous entry */ 1357534Sroot int nlink = 0; /* number of symbolic links taken */ 1367534Sroot struct inode *pdp; /* saved dp during symlink work */ 13716688Smckusick int error, i; 1389166Ssam int lockparent; 13915798Smckusick int docache; 14015798Smckusick unsigned hash; /* value of name hash for entry */ 14115798Smckusick union nchash *nhp; /* cache chain head for entry */ 14215798Smckusick int isdotdot; /* != 0 if current name is ".." */ 14316688Smckusick int flag; /* op ie, LOOKUP, CREATE, or DELETE */ 14430Sbill 14516688Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 14616688Smckusick docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 14716688Smckusick flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW); 14815798Smckusick if (flag == DELETE) 14915798Smckusick docache = 0; 15030Sbill /* 1517534Sroot * Get a buffer for the name to be translated, and copy the 1527534Sroot * name into the buffer. 1535972Swnj */ 15416681Smckusick nbp = freenamebuf; 15516681Smckusick if (nbp == NULL) 15616681Smckusick nbp = geteblk(MAXPATHLEN); 15716681Smckusick else 15816681Smckusick freenamebuf = nbp->av_forw; 15916688Smckusick if (ndp->ni_segflg == UIO_SYSSPACE) 16016705Smckusick error = copystr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN, 16116705Smckusick (u_int *)0); 16216688Smckusick else 16316705Smckusick error = copyinstr(ndp->ni_dirp, nbp->b_un.b_addr, MAXPATHLEN, 16416705Smckusick (u_int *)0); 16516688Smckusick if (error) { 16616688Smckusick u.u_error = error; 16716688Smckusick goto bad; 1685972Swnj } 1697534Sroot 1705972Swnj /* 1717534Sroot * Get starting directory. 17230Sbill */ 1737534Sroot cp = nbp->b_un.b_addr; 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 */ 1857534Sroot 1867534Sroot /* 1877534Sroot * We come to dirloop to search a new directory. 1887534Sroot * The directory must be locked so that it can be 1897534Sroot * iput, and fs must be already set to dp->i_fs. 1907534Sroot */ 1916571Smckusic dirloop: 19230Sbill /* 1937534Sroot * Check accessiblity of directory. 19430Sbill */ 1957534Sroot if ((dp->i_mode&IFMT) != IFDIR) { 19630Sbill u.u_error = ENOTDIR; 1977534Sroot goto bad; 1987534Sroot } 1997534Sroot if (access(dp, IEXEC)) 2007534Sroot goto bad; 2017534Sroot 2026384Swnj dirloop2: 2037534Sroot /* 20416688Smckusick * Copy next component of name to ndp->ni_dent. 2057534Sroot */ 20615798Smckusick hash = 0; 2077534Sroot for (i = 0; *cp != 0 && *cp != '/'; cp++) { 2086571Smckusic if (i >= MAXNAMLEN) { 2095972Swnj u.u_error = ENOENT; 2107534Sroot goto bad; 2115972Swnj } 21216688Smckusick if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != DELETE) { 21316688Smckusick u.u_error = EPERM; 21416688Smckusick goto bad; 21516688Smckusick } 21616688Smckusick ndp->ni_dent.d_name[i++] = *cp; 21715798Smckusick hash += (unsigned char)*cp * i; 2185972Swnj } 21916688Smckusick ndp->ni_dent.d_namlen = i; 22016688Smckusick ndp->ni_dent.d_name[i] = '\0'; 22116658Smckusick isdotdot = (i == 2 && 22216688Smckusick ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.'); 2237534Sroot 2247534Sroot /* 2257534Sroot * Check for degenerate name (e.g. / or "") 2267534Sroot * which is a way of talking about a directory, 2277534Sroot * e.g. like "/." or ".". 2287534Sroot */ 22916688Smckusick if (ndp->ni_dent.d_name[0] == '\0') { 23015798Smckusick if (flag != LOOKUP || lockparent) { 23114937Smckusick u.u_error = EISDIR; 2327534Sroot goto bad; 2335972Swnj } 23416681Smckusick nbp->av_forw = freenamebuf; 23516681Smckusick freenamebuf = nbp; 2366571Smckusic return (dp); 2375972Swnj } 2387534Sroot 2396571Smckusic /* 24015798Smckusick * We now have a segment name to search for, and a directory to search. 24115798Smckusick * 24215798Smckusick * Before tediously performing a linear scan of the directory, 24315798Smckusick * check the name cache to see if the directory/name pair 24415798Smckusick * we are looking for is known already. We don't do this 24515798Smckusick * if the segment name is long, simply so the cache can avoid 24615798Smckusick * holding long names (which would either waste space, or 24715798Smckusick * add greatly to the complexity). 24815798Smckusick */ 24916688Smckusick if (ndp->ni_dent.d_namlen > NCHNAMLEN) { 25015798Smckusick nchstats.ncs_long++; 25115798Smckusick docache = 0; 25215798Smckusick } else { 25315798Smckusick nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)]; 25415798Smckusick for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp; 25515798Smckusick ncp = ncp->nc_forw) { 25615798Smckusick if (ncp->nc_ino == dp->i_number && 25715798Smckusick ncp->nc_dev == dp->i_dev && 25816688Smckusick ncp->nc_nlen == ndp->ni_dent.d_namlen && 25916688Smckusick !bcmp(ncp->nc_name, ndp->ni_dent.d_name, 26016688Smckusick ncp->nc_nlen)) 26115798Smckusick break; 26215798Smckusick } 26315798Smckusick 26415798Smckusick if (ncp == (struct nch *)nhp) { 26515798Smckusick nchstats.ncs_miss++; 26615798Smckusick ncp = NULL; 26715798Smckusick } else { 26816658Smckusick if (ncp->nc_id != ncp->nc_ip->i_id) { 26916643Ssam nchstats.ncs_falsehits++; 27016658Smckusick } else if (*cp == '\0' && !docache) { 27116658Smckusick nchstats.ncs_badhits++; 27216658Smckusick } else { 27315798Smckusick 27415798Smckusick /* 27515798Smckusick * move this slot to end of LRU 27615798Smckusick * chain, if not already there 27715798Smckusick */ 27815798Smckusick if (ncp->nc_nxt) { 27915798Smckusick /* remove from LRU chain */ 28015798Smckusick *ncp->nc_prev = ncp->nc_nxt; 28115798Smckusick ncp->nc_nxt->nc_prev = ncp->nc_prev; 28215798Smckusick 28315798Smckusick /* and replace at end of it */ 28415798Smckusick ncp->nc_nxt = NULL; 28515798Smckusick ncp->nc_prev = nchtail; 28615798Smckusick *nchtail = ncp; 28715798Smckusick nchtail = &ncp->nc_nxt; 28815798Smckusick } 28915798Smckusick 29016658Smckusick /* 29116658Smckusick * Get the next inode in the path. 29216666Smckusick * See comment above other `IUNLOCK' code for 29316658Smckusick * an explaination of the locking protocol. 29416658Smckusick */ 29515798Smckusick pdp = dp; 29615798Smckusick dp = ncp->nc_ip; 29715798Smckusick if (dp == NULL) 29815798Smckusick panic("nami: null cache ino"); 29916643Ssam if (pdp == dp) 30016643Ssam dp->i_count++; 30116666Smckusick else { 30216658Smckusick if (isdotdot) { 30316666Smckusick IUNLOCK(pdp); 30416658Smckusick igrab(dp); 30516658Smckusick } else { 30616658Smckusick igrab(dp); 30716666Smckusick IUNLOCK(pdp); 30816658Smckusick } 30916643Ssam } 31015798Smckusick 31116658Smckusick /* 31216658Smckusick * Verify that the inode that we got 31316658Smckusick * did not change while we were waiting 31416658Smckusick * for it to be locked. 31516658Smckusick */ 31616658Smckusick if (ncp->nc_id != ncp->nc_ip->i_id) { 31716658Smckusick iput(dp); 31816666Smckusick ILOCK(pdp); 31916658Smckusick dp = pdp; 32016658Smckusick nchstats.ncs_falsehits++; 32116658Smckusick } else { 32216688Smckusick ndp->ni_dent.d_ino = dp->i_number; 32316688Smckusick /* ni_dent.d_reclen is garbage ... */ 32416658Smckusick nchstats.ncs_goodhits++; 32516658Smckusick goto haveino; 32616658Smckusick } 32716658Smckusick } 32815798Smckusick 32915798Smckusick /* 33016643Ssam * Last component and we are renaming or deleting, 33116643Ssam * the cache entry is invalid, or otherwise don't 33216643Ssam * want cache entry to exist. 33315798Smckusick */ 33415798Smckusick 33515798Smckusick /* 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; 34115798Smckusick 34215798Smckusick /* remove from hash chain */ 34315798Smckusick remque(ncp); 34415798Smckusick 34515798Smckusick /* insert at head of LRU list (first to grab) */ 34615798Smckusick ncp->nc_nxt = nchhead; 34715798Smckusick ncp->nc_prev = &nchhead; 34815798Smckusick nchhead->nc_prev = &ncp->nc_nxt; 34915798Smckusick nchhead = ncp; 35015798Smckusick 35115798Smckusick /* and make a dummy hash chain */ 35215798Smckusick ncp->nc_forw = ncp; 35315798Smckusick ncp->nc_back = ncp; 35415798Smckusick 35515798Smckusick ncp = NULL; 35615798Smckusick } 35715798Smckusick } 35815798Smckusick 35915798Smckusick /* 3607534Sroot * Suppress search for slots unless creating 3617534Sroot * file and at end of pathname, in which case 3627534Sroot * we watch for a place to put the new file in 3637534Sroot * case it doesn't already exist. 3646571Smckusic */ 3657534Sroot slotstatus = FOUND; 3669166Ssam if (flag == CREATE && *cp == 0) { 3677534Sroot slotstatus = NONE; 3687534Sroot slotfreespace = 0; 36916688Smckusick slotneeded = DIRSIZ(&ndp->ni_dent); 3707534Sroot } 37115660Smckusick /* 37215660Smckusick * If this is the same directory that this process 37315660Smckusick * previously searched, pick up where we last left off. 37415798Smckusick * We cache only lookups as these are the most common 37515660Smckusick * and have the greatest payoff. Caching CREATE has little 37615660Smckusick * benefit as it usually must search the entire directory 37715660Smckusick * to determine that the entry does not exist. Caching the 37815660Smckusick * location of the last DELETE has not reduced profiling time 37915660Smckusick * and hence has been removed in the interest of simplicity. 38015660Smckusick */ 38115660Smckusick if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber || 38215660Smckusick dp->i_dev != u.u_ncache.nc_dev) { 38316688Smckusick ndp->ni_offset = 0; 38415660Smckusick numdirpasses = 1; 38515660Smckusick } else { 38615798Smckusick if ((dp->i_flag & ICHG) || dp->i_ctime >= u.u_ncache.nc_time) { 38715660Smckusick u.u_ncache.nc_prevoffset &= ~(DIRBLKSIZ - 1); 38815660Smckusick u.u_ncache.nc_time = time.tv_sec; 38915660Smckusick } 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); 4017534Sroot 40215660Smckusick searchloop: 40316688Smckusick while (ndp->ni_offset < endsearch) { 4045972Swnj /* 4055972Swnj * If offset is on a block boundary, 4065972Swnj * read the next directory block. 4075972Swnj * Release previous if it exists. 4085972Swnj */ 40916688Smckusick if (blkoff(fs, ndp->ni_offset) == 0) { 4105972Swnj if (bp != NULL) 4115972Swnj brelse(bp); 41216688Smckusick bp = blkatoff(dp, ndp->ni_offset, (char **)0); 4137534Sroot if (bp == 0) 4147534Sroot goto bad; 4157534Sroot entryoffsetinblock = 0; 4165972Swnj } 4177534Sroot 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 4287534Sroot /* 42916657Smckusick * Get pointer to next entry. 43016657Smckusick * Full validation checks are slow, so we only check 43116657Smckusick * enough to insure forward progress through the 43216657Smckusick * directory. Complete checks can be run by patching 43316657Smckusick * "dirchk" to be true. 4347534Sroot */ 4357534Sroot ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 43616657Smckusick if (ep->d_reclen <= 0 || 43716657Smckusick dirchk && dirbadentry(ep, entryoffsetinblock)) { 43816688Smckusick dirbad(dp, ndp->ni_offset, "mangled entry"); 43916657Smckusick i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 44016688Smckusick ndp->ni_offset += i; 4417534Sroot entryoffsetinblock += i; 4426571Smckusic continue; 4436571Smckusic } 4447534Sroot 4456571Smckusic /* 4467534Sroot * If an appropriate sized slot has not yet been found, 4476571Smckusic * check to see if one is available. Also accumulate space 4486571Smckusic * in the current block so that we can determine if 4496571Smckusic * compaction is viable. 4506571Smckusic */ 4517534Sroot if (slotstatus != FOUND) { 4527534Sroot int size = ep->d_reclen; 4537534Sroot 4546571Smckusic if (ep->d_ino != 0) 4556571Smckusic size -= DIRSIZ(ep); 4566571Smckusic if (size > 0) { 4577534Sroot if (size >= slotneeded) { 4587534Sroot slotstatus = FOUND; 45916688Smckusick slotoffset = ndp->ni_offset; 4607534Sroot slotsize = ep->d_reclen; 4617534Sroot } else if (slotstatus == NONE) { 4627534Sroot slotfreespace += size; 4637534Sroot if (slotoffset == -1) 46416688Smckusick slotoffset = ndp->ni_offset; 4657534Sroot if (slotfreespace >= slotneeded) { 4667534Sroot slotstatus = COMPACT; 46716688Smckusick slotsize = ndp->ni_offset + 46816688Smckusick ep->d_reclen - slotoffset; 4697534Sroot } 4706571Smckusic } 4716571Smckusic } 4726571Smckusic } 4737534Sroot 4746571Smckusic /* 4757534Sroot * Check for a name match. 4765972Swnj */ 4777534Sroot if (ep->d_ino) { 47816688Smckusick if (ep->d_namlen == ndp->ni_dent.d_namlen && 47916688Smckusick !bcmp(ndp->ni_dent.d_name, ep->d_name, 48016688Smckusick ep->d_namlen)) 4817534Sroot goto found; 4827534Sroot } 48316688Smckusick prevoff = ndp->ni_offset; 48416688Smckusick ndp->ni_offset += ep->d_reclen; 4857534Sroot entryoffsetinblock += ep->d_reclen; 4867534Sroot } 48715798Smckusick /* notfound: */ 48815660Smckusick /* 48915798Smckusick * If we started in the middle of the directory and failed 49015660Smckusick * to find our target, we must check the beginning as well. 49115660Smckusick */ 49215660Smckusick if (numdirpasses == 2) { 49315660Smckusick numdirpasses--; 49416688Smckusick ndp->ni_offset = 0; 49515660Smckusick endsearch = u.u_ncache.nc_prevoffset; 49615660Smckusick goto searchloop; 49715660Smckusick } 4987534Sroot /* 4997534Sroot * If creating, and at end of pathname and current 5009166Ssam * directory has not been removed, then can consider 5019166Ssam * allowing file to be created. 5027534Sroot */ 5039166Ssam if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) { 5045972Swnj /* 5057534Sroot * Access for write is interpreted as allowing 5067534Sroot * creation of files in the directory. 5075972Swnj */ 5087534Sroot if (access(dp, IWRITE)) 5097534Sroot goto bad; 5105972Swnj /* 5117534Sroot * Return an indication of where the new directory 5127534Sroot * entry should be put. If we didn't find a slot, 51316688Smckusick * then set ndp->ni_count to 0 indicating that the new 51416688Smckusick * slot belongs at the end of the directory. If we found 51516688Smckusick * a slot, then the new entry can be put in the range 51616688Smckusick * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count) 5175972Swnj */ 51815660Smckusick if (slotstatus == NONE) { 51916688Smckusick ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ); 52016688Smckusick ndp->ni_count = 0; 52115660Smckusick } else { 52216688Smckusick ndp->ni_offset = slotoffset; 52316688Smckusick ndp->ni_count = slotsize; 5245972Swnj } 5257534Sroot dp->i_flag |= IUPD|ICHG; 5267534Sroot if (bp) 5277534Sroot brelse(bp); 52816681Smckusick nbp->av_forw = freenamebuf; 52916681Smckusick freenamebuf = nbp; 5305972Swnj /* 5317534Sroot * We return with the directory locked, so that 5327534Sroot * the parameters we set up above will still be 5337534Sroot * valid if we actually decide to do a direnter(). 5347534Sroot * We return NULL to indicate that the entry doesn't 5357534Sroot * currently exist, leaving a pointer to the (locked) 53616688Smckusick * directory inode in ndp->ni_pdir. 5375972Swnj */ 53816688Smckusick ndp->ni_pdir = dp; 5397534Sroot return (NULL); 5407534Sroot } 5417534Sroot u.u_error = ENOENT; 5427534Sroot goto bad; 5437534Sroot found: 54415798Smckusick if (numdirpasses == 2) 54515798Smckusick nchstats.ncs_pass2++; 5467534Sroot /* 5477534Sroot * Check that directory length properly reflects presence 5487534Sroot * of this entry. 5497534Sroot */ 5507605Ssam if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 55116688Smckusick dirbad(dp, ndp->ni_offset, "i_size too small"); 5527605Ssam dp->i_size = entryoffsetinblock + DIRSIZ(ep); 5537534Sroot dp->i_flag |= IUPD|ICHG; 5547534Sroot } 5557534Sroot 5567534Sroot /* 55715660Smckusick * Found component in pathname. 55815798Smckusick * If the final component of path name, save information 55915660Smckusick * in the cache as to where the entry was found. 5607534Sroot */ 56115660Smckusick if (*cp == '\0' && flag == LOOKUP) { 56216688Smckusick u.u_ncache.nc_prevoffset = ndp->ni_offset; 56315660Smckusick u.u_ncache.nc_inumber = dp->i_number; 56415660Smckusick u.u_ncache.nc_dev = dp->i_dev; 56515660Smckusick u.u_ncache.nc_time = time.tv_sec; 56615660Smckusick } 56715660Smckusick /* 56816688Smckusick * Save directory entry in ndp->ni_dent, 56915660Smckusick * and release directory buffer. 57015660Smckusick */ 57116688Smckusick bcopy((caddr_t)ep, (caddr_t)&ndp->ni_dent, (u_int)DIRSIZ(ep)); 5727534Sroot brelse(bp); 5737534Sroot bp = NULL; 5747534Sroot 5757534Sroot /* 5767534Sroot * If deleting, and at end of pathname, return 5777534Sroot * parameters which can be used to remove file. 5789166Ssam * If the lockparent flag isn't set, we return only 57916688Smckusick * the directory (in ndp->ni_pdir), otherwise we go 5809166Ssam * on and lock the inode, being careful with ".". 5817534Sroot */ 5829166Ssam if (flag == DELETE && *cp == 0) { 5837534Sroot /* 5847534Sroot * Write access to directory required to delete files. 5857534Sroot */ 5867534Sroot if (access(dp, IWRITE)) 5877534Sroot goto bad; 58816688Smckusick ndp->ni_pdir = dp; /* for dirremove() */ 5897534Sroot /* 59016688Smckusick * Return pointer to current entry in ndp->ni_offset, 5917534Sroot * and distance past previous entry (if there 59216688Smckusick * is a previous entry in this block) in ndp->ni_count. 59316688Smckusick * Save directory inode pointer in ndp->ni_pdir for dirremove(). 5947534Sroot */ 59516688Smckusick if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0) 59616688Smckusick ndp->ni_count = 0; 5977534Sroot else 59816688Smckusick ndp->ni_count = ndp->ni_offset - prevoff; 5999166Ssam if (lockparent) { 60016688Smckusick if (dp->i_number == ndp->ni_dent.d_ino) 6019166Ssam dp->i_count++; 6029166Ssam else { 60316688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 6049166Ssam if (dp == NULL) { 60516688Smckusick iput(ndp->ni_pdir); 6069166Ssam goto bad; 6079166Ssam } 60815798Smckusick /* 60916046Skarels * If directory is "sticky", then user must own 61015798Smckusick * the directory, or the file in it, else he 61115798Smckusick * may not delete it (unless he's root). This 61215798Smckusick * implements append-only directories. 61315798Smckusick */ 61416688Smckusick if ((ndp->ni_pdir->i_mode & ISVTX) && 61515798Smckusick u.u_uid != 0 && 61616688Smckusick u.u_uid != ndp->ni_pdir->i_uid && 61715798Smckusick dp->i_uid != u.u_uid) { 61816688Smckusick iput(ndp->ni_pdir); 61915798Smckusick u.u_error = EPERM; 62015798Smckusick goto bad; 62115798Smckusick } 6229166Ssam } 6239166Ssam } 62416681Smckusick nbp->av_forw = freenamebuf; 62516681Smckusick freenamebuf = nbp; 6267534Sroot return (dp); 6277534Sroot } 6287534Sroot 6297534Sroot /* 6307534Sroot * Special handling for ".." allowing chdir out of mounted 6317534Sroot * file system: indirect .. in root inode to reevaluate 6327534Sroot * in directory file system was mounted on. 6337534Sroot */ 63416658Smckusick if (isdotdot) { 6357534Sroot if (dp == u.u_rdir) 63616688Smckusick ndp->ni_dent.d_ino = dp->i_number; 63716688Smckusick else if (ndp->ni_dent.d_ino == ROOTINO && 6387534Sroot dp->i_number == ROOTINO) { 6397534Sroot for (i = 1; i < NMOUNT; i++) 6407534Sroot if (mount[i].m_bufp != NULL && 6417534Sroot mount[i].m_dev == dp->i_dev) { 6426571Smckusic iput(dp); 6437534Sroot dp = mount[i].m_inodp; 64416666Smckusick ILOCK(dp); 6455972Swnj dp->i_count++; 6467534Sroot fs = dp->i_fs; 6477534Sroot cp -= 2; /* back over .. */ 6487534Sroot goto dirloop2; 6495972Swnj } 65030Sbill } 6517534Sroot } 6527534Sroot 6537534Sroot /* 6549166Ssam * If rewriting (rename), return the inode and the 6559166Ssam * information required to rewrite the present directory 6569166Ssam * Must get inode of directory entry to verify it's a 6579166Ssam * regular file, or empty directory. 6589166Ssam */ 6599166Ssam if ((flag == CREATE && lockparent) && *cp == 0) { 6609166Ssam if (access(dp, IWRITE)) 6619166Ssam goto bad; 66216688Smckusick ndp->ni_pdir = dp; /* for dirrewrite() */ 6639166Ssam /* 6649166Ssam * Careful about locking second inode. 6659166Ssam * This can only occur if the target is ".". 6669166Ssam */ 66716688Smckusick if (dp->i_number == ndp->ni_dent.d_ino) { 6689166Ssam u.u_error = EISDIR; /* XXX */ 6699166Ssam goto bad; 6709166Ssam } 67116688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 6729166Ssam if (dp == NULL) { 67316688Smckusick iput(ndp->ni_pdir); 6749166Ssam goto bad; 6759166Ssam } 67616681Smckusick nbp->av_forw = freenamebuf; 67716681Smckusick freenamebuf = nbp; 6789166Ssam return (dp); 6799166Ssam } 6809166Ssam 6819166Ssam /* 68212011Smckusick * Check for symbolic link, which may require us to massage the 68312011Smckusick * name before we continue translation. We do not `iput' the 68412011Smckusick * directory because we may need it again if the symbolic link 68512011Smckusick * is relative to the current directory. Instead we save it 68612011Smckusick * unlocked as "pdp". We must get the target inode before unlocking 68712011Smckusick * the directory to insure that the inode will not be removed 68812011Smckusick * before we get it. We prevent deadlock by always fetching 68912011Smckusick * inodes from the root, moving down the directory tree. Thus 69012011Smckusick * when following backward pointers ".." we must unlock the 69112011Smckusick * parent directory before getting the requested directory. 69212011Smckusick * There is a potential race condition here if both the current 69312011Smckusick * and parent directories are removed before the `iget' for the 69412011Smckusick * inode associated with ".." returns. We hope that this occurs 69512011Smckusick * infrequently since we cannot avoid this race condition without 69612492Ssam * implementing a sophisticated deadlock detection algorithm. 69712011Smckusick * Note also that this simple deadlock detection scheme will not 69812011Smckusick * work if the file system has any hard links other than ".." 69912011Smckusick * that point backwards in the directory structure. 7007534Sroot */ 7017534Sroot pdp = dp; 70215798Smckusick if (isdotdot) { 70316666Smckusick IUNLOCK(pdp); /* race to get the inode */ 70416688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 70512011Smckusick if (dp == NULL) 70612011Smckusick goto bad2; 70716688Smckusick } else if (dp->i_number == ndp->ni_dent.d_ino) { 70812011Smckusick dp->i_count++; /* we want ourself, ie "." */ 70912011Smckusick } else { 71016688Smckusick dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 71116666Smckusick IUNLOCK(pdp); 71212011Smckusick if (dp == NULL) 71312011Smckusick goto bad2; 71412011Smckusick } 71515798Smckusick 71615798Smckusick /* 71715798Smckusick * insert name into cache (if we want it, and it isn't "." or "..") 71815798Smckusick * 71915798Smckusick * all other cases where making a cache entry would be wrong 72015798Smckusick * have already departed from the code sequence somewhere above. 72115798Smckusick */ 72216643Ssam if (docache) { 72315798Smckusick if (ncp != NULL) 72415798Smckusick panic("nami: duplicating cache"); 72515798Smckusick 72615798Smckusick /* 72715798Smckusick * free the cache slot at head of lru chain 72815798Smckusick */ 72915798Smckusick if (ncp = nchhead) { 73015798Smckusick /* remove from lru chain */ 73115798Smckusick *ncp->nc_prev = ncp->nc_nxt; 73215798Smckusick if (ncp->nc_nxt) 73315798Smckusick ncp->nc_nxt->nc_prev = ncp->nc_prev; 73415798Smckusick else 73515798Smckusick nchtail = ncp->nc_prev; 73615798Smckusick 73715798Smckusick /* remove from old hash chain */ 73815798Smckusick remque(ncp); 73915798Smckusick 74015798Smckusick /* grab the inode we just found */ 74115798Smckusick ncp->nc_ip = dp; 74215798Smckusick 74315798Smckusick /* fill in cache info */ 74415798Smckusick ncp->nc_ino = pdp->i_number; /* parents inum */ 74515798Smckusick ncp->nc_dev = pdp->i_dev; /* & device */ 74615798Smckusick ncp->nc_idev = dp->i_dev; /* our device */ 74716643Ssam ncp->nc_id = dp->i_id; /* identifier */ 74816688Smckusick ncp->nc_nlen = ndp->ni_dent.d_namlen; 74916688Smckusick bcopy(ndp->ni_dent.d_name, ncp->nc_name, ncp->nc_nlen); 75015798Smckusick 75115798Smckusick /* link at end of lru chain */ 75215798Smckusick ncp->nc_nxt = NULL; 75315798Smckusick ncp->nc_prev = nchtail; 75415798Smckusick *nchtail = ncp; 75515798Smckusick nchtail = &ncp->nc_nxt; 75615798Smckusick 75715798Smckusick /* and insert on hash chain */ 75815798Smckusick insque(ncp, nhp); 75915798Smckusick } 76015798Smckusick } 76115798Smckusick 76215798Smckusick haveino: 7637534Sroot fs = dp->i_fs; 7647534Sroot 7657534Sroot /* 7667534Sroot * Check for symbolic link 7677534Sroot */ 76816688Smckusick if ((dp->i_mode & IFMT) == IFLNK && 76916688Smckusick ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) { 7707825Sroot u_int pathlen = strlen(cp) + 1; 7717534Sroot 7727534Sroot if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 7737534Sroot ++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, 7807825Sroot 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 * record length must not be non-negative 84516657Smckusick * entry must fit in rest of its DIRBLKSIZ block 84616657Smckusick * record must be large enough to contain entry 84716657Smckusick * name is not longer than MAXNAMLEN 84816657Smckusick * name must be as long as advertised, and null terminated 84916657Smckusick */ 85016657Smckusick dirbadentry(ep, entryoffsetinblock) 8517534Sroot register struct direct *ep; 85216657Smckusick int entryoffsetinblock; 8537534Sroot { 8547534Sroot register int i; 8557534Sroot 85616657Smckusick if ((ep->d_reclen & 0x3) != 0 || ep->d_reclen <= 0 || 85716657Smckusick ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 85816657Smckusick ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) 85916657Smckusick return (1); 8607534Sroot for (i = 0; i < ep->d_namlen; i++) 86116688Smckusick if (ep->d_name[i] == '\0') 8627534Sroot return (1); 8637534Sroot return (ep->d_name[i]); 8647534Sroot } 8657534Sroot 86630Sbill /* 8677534Sroot * Write a directory entry after a call to namei, using the parameters 8687534Sroot * which it left in the u. area. The argument ip is the inode which 86916688Smckusick * the new directory entry will refer to. The u. area field ndp->ni_pdir is 8707534Sroot * a pointer to the directory to be written, which was left locked by 87116688Smckusick * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate 8727534Sroot * how the space for the new entry is to be gotten. 8737534Sroot */ 87416688Smckusick direnter(ip, ndp) 8757534Sroot struct inode *ip; 87616688Smckusick register struct nameidata *ndp; 8775972Swnj { 8787534Sroot register struct direct *ep, *nep; 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; 89716688Smckusick error = rdwri(UIO_WRITE, ndp->ni_pdir, (caddr_t)&ndp->ni_dent, 89816688Smckusick newentrysize, ndp->ni_offset, 1, (int *)0); 89916688Smckusick iput(ndp->ni_pdir); 90010849Ssam return (error); 9017534Sroot } 9027534Sroot 9037534Sroot /* 90416688Smckusick * If ndp->ni_count is non-zero, then namei found space for the new 90516688Smckusick * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count. 9067534Sroot * in the directory. To use this space, we may have to compact 9077534Sroot * the entries located there, by copying them together towards 9087534Sroot * the beginning of the block, leaving the free space in 9097534Sroot * one usable chunk at the end. 9107534Sroot */ 9117534Sroot 9127534Sroot /* 9137534Sroot * Increase size of directory if entry eats into new space. 9147534Sroot * This should never push the size past a new multiple of 9157534Sroot * DIRBLKSIZE. 9167534Sroot */ 91716688Smckusick if (ndp->ni_offset + ndp->ni_count > ndp->ni_pdir->i_size) 91816688Smckusick ndp->ni_pdir->i_size = ndp->ni_offset + ndp->ni_count; 9197534Sroot 9207534Sroot /* 9217534Sroot * Get the block containing the space for the new directory 92210849Ssam * entry. Should return error by result instead of u.u_error. 9237534Sroot */ 92416688Smckusick bp = blkatoff(ndp->ni_pdir, ndp->ni_offset, (char **)&dirbuf); 9259166Ssam if (bp == 0) { 92616688Smckusick iput(ndp->ni_pdir); 92710849Ssam return (u.u_error); 9289166Ssam } 9297534Sroot 9307534Sroot /* 9317534Sroot * Find space for the new entry. In the simple case, the 9327534Sroot * entry at offset base will have the space. If it does 9337534Sroot * not, then namei arranged that compacting the region 93416688Smckusick * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space. 9357534Sroot */ 9367534Sroot ep = (struct direct *)dirbuf; 9377534Sroot dsize = DIRSIZ(ep); 93811639Ssam spacefree = ep->d_reclen - dsize; 93916688Smckusick for (loc = ep->d_reclen; loc < ndp->ni_count; ) { 9407534Sroot nep = (struct direct *)(dirbuf + loc); 9417534Sroot if (ep->d_ino) { 9427534Sroot /* trim the existing slot */ 9437534Sroot ep->d_reclen = dsize; 9447534Sroot ep = (struct direct *)((char *)ep + dsize); 9457534Sroot } else { 9467534Sroot /* overwrite; nothing there; header is ours */ 94711639Ssam spacefree += dsize; 9487534Sroot } 9497534Sroot dsize = DIRSIZ(nep); 95011639Ssam spacefree += nep->d_reclen - dsize; 9517534Sroot loc += nep->d_reclen; 9527825Sroot bcopy((caddr_t)nep, (caddr_t)ep, dsize); 9537534Sroot } 9547534Sroot /* 9557534Sroot * Update the pointer fields in the previous entry (if any), 9567534Sroot * copy in the new entry, and write out the block. 9577534Sroot */ 9587534Sroot if (ep->d_ino == 0) { 95911639Ssam if (spacefree + dsize < newentrysize) 9607534Sroot panic("wdir: compact1"); 96116688Smckusick ndp->ni_dent.d_reclen = spacefree + dsize; 9627534Sroot } else { 96311639Ssam if (spacefree < newentrysize) 9647534Sroot panic("wdir: compact2"); 96516688Smckusick ndp->ni_dent.d_reclen = spacefree; 9667534Sroot ep->d_reclen = dsize; 9677534Sroot ep = (struct direct *)((char *)ep + dsize); 9687534Sroot } 96916688Smckusick bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize); 9707534Sroot bwrite(bp); 97116688Smckusick ndp->ni_pdir->i_flag |= IUPD|ICHG; 97216688Smckusick iput(ndp->ni_pdir); 97310849Ssam return (error); 9745972Swnj } 9756571Smckusic 9769166Ssam /* 9779166Ssam * Remove a directory entry after a call to namei, using the 9789166Ssam * parameters which it left in the u. area. The u. entry 97916688Smckusick * ni_offset contains the offset into the directory of the 98016688Smckusick * entry to be eliminated. The ni_count field contains the 9819166Ssam * size of the previous record in the directory. If this 9829166Ssam * is 0, the first entry is being deleted, so we need only 9839166Ssam * zero the inode number to mark the entry as free. If the 9849166Ssam * entry isn't the first in the directory, we must reclaim 9859166Ssam * the space of the now empty record by adding the record size 9869166Ssam * to the size of the previous entry. 9879166Ssam */ 98816688Smckusick dirremove(ndp) 98916688Smckusick register struct nameidata *ndp; 9906571Smckusic { 99116688Smckusick register struct inode *dp = ndp->ni_pdir; 9927534Sroot register struct buf *bp; 9937534Sroot struct direct *ep; 9946571Smckusic 99516688Smckusick if (ndp->ni_count == 0) { 9967534Sroot /* 9977534Sroot * First entry in block: set d_ino to zero. 9987534Sroot */ 99916688Smckusick ndp->ni_dent.d_ino = 0; 100016688Smckusick (void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 100116688Smckusick (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0); 10029269Ssam } else { 10037534Sroot /* 10047534Sroot * Collapse new free space into previous entry. 10057534Sroot */ 100616688Smckusick bp = blkatoff(dp, (int)(ndp->ni_offset - ndp->ni_count), 100716688Smckusick (char **)&ep); 10087534Sroot if (bp == 0) 10097534Sroot return (0); 101016688Smckusick ep->d_reclen += ndp->ni_dent.d_reclen; 10117534Sroot bwrite(bp); 10127534Sroot dp->i_flag |= IUPD|ICHG; 10137534Sroot } 10147534Sroot return (1); 10156571Smckusic } 10167534Sroot 10177605Ssam /* 10189166Ssam * Rewrite an existing directory entry to point at the inode 10199166Ssam * supplied. The parameters describing the directory entry are 10209166Ssam * set up by a call to namei. 10219166Ssam */ 102216688Smckusick dirrewrite(dp, ip, ndp) 10239166Ssam struct inode *dp, *ip; 102416688Smckusick struct nameidata *ndp; 10259166Ssam { 10269166Ssam 102716688Smckusick ndp->ni_dent.d_ino = ip->i_number; 102816688Smckusick u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 102916688Smckusick (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1, (int *)0); 10309166Ssam iput(dp); 10319166Ssam } 10329166Ssam 10339166Ssam /* 10347605Ssam * Return buffer with contents of block "offset" 10357605Ssam * from the beginning of directory "ip". If "res" 10367605Ssam * is non-zero, fill it in with a pointer to the 10377605Ssam * remaining space in the directory. 10387605Ssam */ 10397534Sroot struct buf * 10407605Ssam blkatoff(ip, offset, res) 10417534Sroot struct inode *ip; 10427534Sroot off_t offset; 10437534Sroot char **res; 10447534Sroot { 10457534Sroot register struct fs *fs = ip->i_fs; 10468672Sroot daddr_t lbn = lblkno(fs, offset); 10477534Sroot int base = blkoff(fs, offset); 10487534Sroot int bsize = blksize(fs, ip, lbn); 10498672Sroot daddr_t bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize)); 10507534Sroot register struct buf *bp; 10517534Sroot 10527534Sroot if (u.u_error) 10537534Sroot return (0); 10547534Sroot bp = bread(ip->i_dev, bn, bsize); 10557534Sroot if (bp->b_flags & B_ERROR) { 10567534Sroot brelse(bp); 10577534Sroot return (0); 10587534Sroot } 10597534Sroot if (res) 10607534Sroot *res = bp->b_un.b_addr + base; 10617534Sroot return (bp); 10627534Sroot } 10639166Ssam 10649166Ssam /* 10659166Ssam * Check if a directory is empty or not. 10669166Ssam * Inode supplied must be locked. 106712817Ssam * 106812817Ssam * Using a struct dirtemplate here is not precisely 106912817Ssam * what we want, but better than using a struct direct. 107012817Ssam * 107112817Ssam * NB: does not handle corrupted directories. 10729166Ssam */ 107316777Smckusick dirempty(ip, parentino) 10749863Ssam register struct inode *ip; 107516777Smckusick ino_t parentino; 10769166Ssam { 10779166Ssam register off_t off; 107812817Ssam struct dirtemplate dbuf; 107912817Ssam register struct direct *dp = (struct direct *)&dbuf; 10809863Ssam int error, count; 108112817Ssam #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 10829166Ssam 10839166Ssam for (off = 0; off < ip->i_size; off += dp->d_reclen) { 108412817Ssam error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ, 108512817Ssam off, 1, &count); 108612817Ssam /* 108712817Ssam * Since we read MINDIRSIZ, residual must 108812817Ssam * be 0 unless we're at end of file. 108912817Ssam */ 109012817Ssam if (error || count != 0) 10919166Ssam 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; 117715798Smckusick register struct nch *ncp; 117815798Smckusick 117915798Smckusick nchhead = 0; 118015798Smckusick nchtail = &nchhead; 118115798Smckusick 118215798Smckusick for (ncp = nch; ncp < &nch[nchsize]; ncp++) { 118315798Smckusick ncp->nc_forw = ncp; /* hash chain */ 118415798Smckusick ncp->nc_back = ncp; 118515798Smckusick 118615798Smckusick ncp->nc_nxt = NULL; /* lru chain */ 118715798Smckusick *nchtail = ncp; 118815798Smckusick ncp->nc_prev = nchtail; 118915798Smckusick nchtail = &ncp->nc_nxt; 119015798Smckusick 119115798Smckusick /* all else is zero already */ 119215798Smckusick } 119315798Smckusick 119415798Smckusick for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) { 119515798Smckusick nchp->nch_head[0] = nchp; 119615798Smckusick nchp->nch_head[1] = nchp; 119715798Smckusick } 119815798Smckusick } 119915798Smckusick 120015798Smckusick /* 120115798Smckusick * Cache flush, called when filesys is umounted to 120215798Smckusick * remove entries that would now be invalid 120315798Smckusick * 120415798Smckusick * The line "nxtcp = nchhead" near the end is to avoid potential problems 120515798Smckusick * if the cache lru chain is modified while we are dumping the 120615798Smckusick * inode. This makes the algorithm O(n^2), but do you think I care? 120715798Smckusick */ 120815798Smckusick nchinval(dev) 120915798Smckusick register dev_t dev; 121015798Smckusick { 121115798Smckusick register struct nch *ncp, *nxtcp; 121215798Smckusick 121315798Smckusick for (ncp = nchhead; ncp; ncp = nxtcp) { 121415798Smckusick nxtcp = ncp->nc_nxt; 121515798Smckusick 121615798Smckusick if (ncp->nc_ip == NULL || 121715798Smckusick (ncp->nc_idev != dev && ncp->nc_dev != dev)) 121815798Smckusick continue; 121915798Smckusick 122016658Smckusick /* free the resources we had */ 122115798Smckusick ncp->nc_idev = NODEV; 122215798Smckusick ncp->nc_dev = NODEV; 122316658Smckusick ncp->nc_id = NULL; 122415798Smckusick ncp->nc_ino = 0; 122516658Smckusick ncp->nc_ip = NULL; 122615798Smckusick 122716658Smckusick 122815798Smckusick /* remove the entry from its hash chain */ 122915798Smckusick remque(ncp); 123015798Smckusick /* and make a dummy one */ 123115798Smckusick ncp->nc_forw = ncp; 123215798Smckusick ncp->nc_back = ncp; 123315798Smckusick 123415798Smckusick /* delete this entry from LRU chain */ 123515798Smckusick *ncp->nc_prev = nxtcp; 123615798Smckusick if (nxtcp) 123715798Smckusick nxtcp->nc_prev = ncp->nc_prev; 123815798Smckusick else 123915798Smckusick nchtail = ncp->nc_prev; 124015798Smckusick 124115798Smckusick /* cause rescan of list, it may have altered */ 124215798Smckusick nxtcp = nchhead; 124315798Smckusick /* 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 } 1250