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