1*8672Sroot /* vfs_lookup.c 4.28 82/10/19 */ 230Sbill 330Sbill #include "../h/param.h" 430Sbill #include "../h/systm.h" 530Sbill #include "../h/inode.h" 66571Smckusic #include "../h/fs.h" 730Sbill #include "../h/mount.h" 830Sbill #include "../h/dir.h" 930Sbill #include "../h/user.h" 1030Sbill #include "../h/buf.h" 112275Swnj #include "../h/conf.h" 127825Sroot #include "../h/uio.h" 1330Sbill 147605Ssam struct buf *blkatoff(); 157534Sroot int dirchk = 1; 1630Sbill /* 177534Sroot * Convert a pathname into a pointer to a locked inode, 187534Sroot * with side effects usable in creating and removing files. 197534Sroot * This is a very central and rather complicated routine. 2030Sbill * 217534Sroot * The func argument gives the routine which returns successive 227534Sroot * characters of the name to be translated. The flag 237534Sroot * argument is (0, 1, 2) depending on whether the name is to be 247534Sroot * (looked up, created, deleted). The follow argument is 1 when 257534Sroot * symbolic links are to be followed when they occur at the end of 267534Sroot * the name translation process. 277534Sroot * 287534Sroot * Overall outline: 297534Sroot * 307534Sroot * copy in name 317534Sroot * get starting directory 327534Sroot * dirloop: 337534Sroot * check accessibility of directory 347534Sroot * dirloop2: 357534Sroot * copy next component of name to u.u_dent 367534Sroot * handle degenerate case where name is null string 377534Sroot * search for name in directory, to found or notfound 387534Sroot * notfound: 397534Sroot * if creating, return locked inode, leaving information on avail. slots 407534Sroot * else return error 417534Sroot * found: 427534Sroot * if at end of path and deleting, return information to allow delete 437534Sroot * if .. and on mounted filesys, look in mount table for parent 447534Sroot * if symbolic link, massage name in buffer and continue at dirloop 457534Sroot * if more components of name, do next level at dirloop 467534Sroot * return the answer as locked inode 4730Sbill */ 4830Sbill struct inode * 495972Swnj namei(func, flag, follow) 505972Swnj int (*func)(), flag, follow; 5130Sbill { 527534Sroot register char *cp; /* pointer into pathname argument */ 537534Sroot /* these variables refer to things which must be freed or unlocked */ 547534Sroot register struct inode *dp = 0; /* the directory we are searching */ 557534Sroot register struct fs *fs; /* file system that directory is in */ 567534Sroot register struct buf *bp = 0; /* a buffer of directory entries */ 577534Sroot register struct direct *ep; /* the current directory entry */ 587534Sroot int entryoffsetinblock; /* offset of ep in bp's buffer */ 597534Sroot register struct buf *nbp; /* buffer storing path name argument */ 607534Sroot /* these variables hold information about the search for a slot */ 617534Sroot enum {NONE, COMPACT, FOUND} slotstatus; 627534Sroot int slotoffset = -1; /* offset of area with free space */ 637534Sroot int slotsize; /* size of area at slotoffset */ 647534Sroot int slotfreespace; /* amount of space free in slot */ 657534Sroot int slotneeded; /* size of the entry we're seeking */ 667534Sroot /* */ 677534Sroot int dirsize; 687534Sroot int prevoff; /* u.u_offset of previous entry */ 697534Sroot int nlink = 0; /* number of symbolic links taken */ 707534Sroot struct inode *pdp; /* saved dp during symlink work */ 717534Sroot int i; 7230Sbill 7330Sbill /* 747534Sroot * Get a buffer for the name to be translated, and copy the 757534Sroot * name into the buffer. 765972Swnj */ 776571Smckusic nbp = geteblk(MAXPATHLEN); 787534Sroot for (cp = nbp->b_un.b_addr; *cp = (*func)(); ) { 797534Sroot if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != 2) { 806066Sroot u.u_error = EPERM; 817534Sroot goto bad; 826066Sroot } 836066Sroot cp++; 846571Smckusic if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { 855972Swnj u.u_error = ENOENT; 867534Sroot goto bad; 875972Swnj } 885972Swnj } 897534Sroot if (u.u_error) 907534Sroot goto bad; 917534Sroot 925972Swnj /* 937534Sroot * Get starting directory. 9430Sbill */ 957534Sroot cp = nbp->b_un.b_addr; 965972Swnj if (*cp == '/') { 975972Swnj while (*cp == '/') 985972Swnj cp++; 9930Sbill if ((dp = u.u_rdir) == NULL) 10030Sbill dp = rootdir; 1017534Sroot } else 1027534Sroot dp = u.u_cdir; 1037534Sroot fs = dp->i_fs; 1045972Swnj ilock(dp); 1055972Swnj dp->i_count++; 1067534Sroot u.u_pdir = (struct inode *)0xc0000000; /* illegal */ 1077534Sroot 1087534Sroot /* 1097534Sroot * We come to dirloop to search a new directory. 1107534Sroot * The directory must be locked so that it can be 1117534Sroot * iput, and fs must be already set to dp->i_fs. 1127534Sroot */ 1136571Smckusic dirloop: 11430Sbill /* 1157534Sroot * Check accessiblity of directory. 11630Sbill */ 1177534Sroot if ((dp->i_mode&IFMT) != IFDIR) { 11830Sbill u.u_error = ENOTDIR; 1197534Sroot goto bad; 1207534Sroot } 1217534Sroot if (access(dp, IEXEC)) 1227534Sroot goto bad; 1237534Sroot 1246384Swnj dirloop2: 1257534Sroot /* 1267534Sroot * Copy next component of name to u.u_dent. 1277534Sroot */ 1287534Sroot for (i = 0; *cp != 0 && *cp != '/'; cp++) { 1296571Smckusic if (i >= MAXNAMLEN) { 1305972Swnj u.u_error = ENOENT; 1317534Sroot goto bad; 1325972Swnj } 1337534Sroot u.u_dent.d_name[i++] = *cp; 1345972Swnj } 1356571Smckusic u.u_dent.d_namlen = i; 1367534Sroot u.u_dent.d_name[i] = 0; 1377534Sroot 1387534Sroot /* 1397534Sroot * Check for degenerate name (e.g. / or "") 1407534Sroot * which is a way of talking about a directory, 1417534Sroot * e.g. like "/." or ".". 1427534Sroot */ 1437534Sroot if (u.u_dent.d_name[0] == 0) { 1447534Sroot if (flag) { 1455972Swnj u.u_error = ENOENT; 1467534Sroot goto bad; 1475972Swnj } 1486571Smckusic brelse(nbp); 1496571Smckusic return (dp); 1505972Swnj } 1517534Sroot 1526571Smckusic /* 1537534Sroot * Suppress search for slots unless creating 1547534Sroot * file and at end of pathname, in which case 1557534Sroot * we watch for a place to put the new file in 1567534Sroot * case it doesn't already exist. 1576571Smckusic */ 1587534Sroot slotstatus = FOUND; 1597534Sroot if (flag == 1 && *cp == 0) { 1607534Sroot slotstatus = NONE; 1617534Sroot slotfreespace = 0; 1627534Sroot slotneeded = DIRSIZ(&u.u_dent); 1637534Sroot } 1647534Sroot 1657534Sroot dirsize = roundup(dp->i_size, DIRBLKSIZ); 1666571Smckusic u.u_offset = 0; 1677534Sroot while (u.u_offset < dirsize) { 1685972Swnj /* 1695972Swnj * If offset is on a block boundary, 1705972Swnj * read the next directory block. 1715972Swnj * Release previous if it exists. 1725972Swnj */ 1736571Smckusic if (blkoff(fs, u.u_offset) == 0) { 1745972Swnj if (bp != NULL) 1755972Swnj brelse(bp); 1767605Ssam bp = blkatoff(dp, u.u_offset, (char **)0); 1777534Sroot if (bp == 0) 1787534Sroot goto bad; 1797534Sroot entryoffsetinblock = 0; 1805972Swnj } 1817534Sroot 1825972Swnj /* 1837534Sroot * If still looking for a slot, and at a DIRBLKSIZE 1847534Sroot * boundary, have to start looking for free space 1857534Sroot * again. 1866571Smckusic */ 1877534Sroot if (slotstatus == NONE && 1887534Sroot (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { 1897534Sroot slotoffset = -1; 1907534Sroot slotfreespace = 0; 1917534Sroot } 1927534Sroot 1937534Sroot /* 1947534Sroot * Get pointer to next entry, and do consistency checking: 1957534Sroot * record length must be multiple of 4 1967605Ssam * record length must not be zero 1977534Sroot * entry must fit in rest of this DIRBLKSIZ block 1987534Sroot * record must be large enough to contain name 1997605Ssam * When dirchk is set we also check: 2007605Ssam * name is not longer than MAXNAMLEN 2017534Sroot * name must be as long as advertised, and null terminated 2027605Ssam * Checking last two conditions is done only when dirchk is 2037605Ssam * set, to save time. 2047534Sroot */ 2057534Sroot ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 2067534Sroot i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 2077605Ssam if ((ep->d_reclen & 0x3) || ep->d_reclen == 0 || 2087605Ssam ep->d_reclen > i || DIRSIZ(ep) > ep->d_reclen || 2097605Ssam dirchk && (ep->d_namlen > MAXNAMLEN || dirbadname(ep))) { 2107534Sroot dirbad(dp, "mangled entry"); 2116571Smckusic u.u_offset += i; 2127534Sroot entryoffsetinblock += i; 2136571Smckusic continue; 2146571Smckusic } 2157534Sroot 2166571Smckusic /* 2177534Sroot * If an appropriate sized slot has not yet been found, 2186571Smckusic * check to see if one is available. Also accumulate space 2196571Smckusic * in the current block so that we can determine if 2206571Smckusic * compaction is viable. 2216571Smckusic */ 2227534Sroot if (slotstatus != FOUND) { 2237534Sroot int size = ep->d_reclen; 2247534Sroot 2256571Smckusic if (ep->d_ino != 0) 2266571Smckusic size -= DIRSIZ(ep); 2276571Smckusic if (size > 0) { 2287534Sroot if (size >= slotneeded) { 2297534Sroot slotstatus = FOUND; 2307534Sroot slotoffset = u.u_offset; 2317534Sroot slotsize = ep->d_reclen; 2327534Sroot } else if (slotstatus == NONE) { 2337534Sroot slotfreespace += size; 2347534Sroot if (slotoffset == -1) 2357534Sroot slotoffset = u.u_offset; 2367534Sroot if (slotfreespace >= slotneeded) { 2377534Sroot slotstatus = COMPACT; 2387534Sroot slotsize = 2397534Sroot u.u_offset+ep->d_reclen - 2407534Sroot slotoffset; 2417534Sroot } 2426571Smckusic } 2436571Smckusic } 2446571Smckusic } 2457534Sroot 2466571Smckusic /* 2477534Sroot * Check for a name match. 2485972Swnj */ 2497534Sroot if (ep->d_ino) { 2507534Sroot if (ep->d_namlen == u.u_dent.d_namlen && 2517534Sroot !bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen)) 2527534Sroot goto found; 2537534Sroot } 2547534Sroot prevoff = u.u_offset; 2556571Smckusic u.u_offset += ep->d_reclen; 2567534Sroot entryoffsetinblock += ep->d_reclen; 2577534Sroot } 2587534Sroot /* notfound: */ 2597534Sroot /* 2607534Sroot * If creating, and at end of pathname and current 2617534Sroot * directory has not been removed, then can consider allowing 2627534Sroot * file to be created. 2637534Sroot */ 2647534Sroot if (flag == 1 && *cp == 0 && dp->i_nlink != 0) { 2655972Swnj /* 2667534Sroot * Access for write is interpreted as allowing 2677534Sroot * creation of files in the directory. 2685972Swnj */ 2697534Sroot if (access(dp, IWRITE)) 2707534Sroot goto bad; 2715972Swnj /* 2727534Sroot * Return an indication of where the new directory 2737534Sroot * entry should be put. If we didn't find a slot, 2747534Sroot * then set u.u_count to 0 indicating that the 2757534Sroot * new slot belongs at the end of the directory. 2767534Sroot * If we found a slot, then the new entry can be 2777534Sroot * put in the range [u.u_offset..u.u_offset+u.u_count) 2785972Swnj */ 2797534Sroot if (slotstatus == NONE) 2807534Sroot u.u_count = 0; 2817534Sroot else { 2827534Sroot u.u_offset = slotoffset; 2837534Sroot u.u_count = slotsize; 2845972Swnj } 2857534Sroot dp->i_flag |= IUPD|ICHG; 2867534Sroot if (bp) 2877534Sroot brelse(bp); 2887534Sroot brelse(nbp); 2895972Swnj /* 2907534Sroot * We return with the directory locked, so that 2917534Sroot * the parameters we set up above will still be 2927534Sroot * valid if we actually decide to do a direnter(). 2937534Sroot * We return NULL to indicate that the entry doesn't 2947534Sroot * currently exist, leaving a pointer to the (locked) 2957534Sroot * directory inode in u.u_pdir. 2965972Swnj */ 2977534Sroot u.u_pdir = dp; 2987534Sroot return (NULL); 2997534Sroot } 3007534Sroot u.u_error = ENOENT; 3017534Sroot goto bad; 3027534Sroot found: 3037534Sroot /* 3047534Sroot * Check that directory length properly reflects presence 3057534Sroot * of this entry. 3067534Sroot */ 3077605Ssam if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 3087534Sroot dirbad(dp, "i_size too small"); 3097605Ssam dp->i_size = entryoffsetinblock + DIRSIZ(ep); 3107534Sroot dp->i_flag |= IUPD|ICHG; 3117534Sroot } 3127534Sroot 3137534Sroot /* 3147534Sroot * Found component in pathname; save directory 3157534Sroot * entry in u.u_dent, and release directory buffer. 3167534Sroot */ 3177825Sroot bcopy((caddr_t)ep, (caddr_t)&u.u_dent, (u_int)DIRSIZ(ep)); 3187534Sroot brelse(bp); 3197534Sroot bp = NULL; 3207534Sroot 3217534Sroot /* 3227534Sroot * If deleting, and at end of pathname, return 3237534Sroot * parameters which can be used to remove file. 3247534Sroot * Note that in this case we return the directory 3257534Sroot * inode, not the inode of the file being deleted. 3267534Sroot */ 3277534Sroot if (flag == 2 && *cp == 0) { 3287534Sroot /* 3297534Sroot * Write access to directory required to delete files. 3307534Sroot */ 3317534Sroot if (access(dp, IWRITE)) 3327534Sroot goto bad; 3337534Sroot /* 3347534Sroot * Return pointer to current entry in u.u_offset, 3357534Sroot * and distance past previous entry (if there 3367534Sroot * is a previous entry in this block) in u.u_count. 3377534Sroot * Save directory inode pointer in u.u_pdir for dirremove(). 3387534Sroot */ 3397534Sroot if ((u.u_offset&(DIRBLKSIZ-1)) == 0) 3407534Sroot u.u_count = 0; 3417534Sroot else 3427534Sroot u.u_count = u.u_offset - prevoff; 3437534Sroot brelse(nbp); 3447534Sroot u.u_pdir = dp; /* for dirremove() */ 3457534Sroot return (dp); 3467534Sroot } 3477534Sroot 3487534Sroot /* 3497534Sroot * Special handling for ".." allowing chdir out of mounted 3507534Sroot * file system: indirect .. in root inode to reevaluate 3517534Sroot * in directory file system was mounted on. 3527534Sroot */ 3537534Sroot if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && 3547534Sroot u.u_dent.d_name[2] == '\0') { 3557534Sroot if (dp == u.u_rdir) 3567534Sroot u.u_dent.d_ino = dp->i_number; 3577534Sroot else if (u.u_dent.d_ino == ROOTINO && 3587534Sroot dp->i_number == ROOTINO) { 3597534Sroot for (i = 1; i < NMOUNT; i++) 3607534Sroot if (mount[i].m_bufp != NULL && 3617534Sroot mount[i].m_dev == dp->i_dev) { 3626571Smckusic iput(dp); 3637534Sroot dp = mount[i].m_inodp; 3645972Swnj ilock(dp); 3655972Swnj dp->i_count++; 3667534Sroot fs = dp->i_fs; 3677534Sroot cp -= 2; /* back over .. */ 3687534Sroot goto dirloop2; 3695972Swnj } 37030Sbill } 3717534Sroot } 3727534Sroot 3737534Sroot /* 3747534Sroot * Check for symbolic link, which may require us 3757534Sroot * to massage the name before we continue translation. 3767534Sroot * To avoid deadlock have to unlock the current directory, 3777534Sroot * but don't iput it because we may need it again (if 3787534Sroot * the symbolic link is relative to .). Instead save 3797534Sroot * it (unlocked) as pdp. 3807534Sroot */ 3817534Sroot pdp = dp; 3827534Sroot iunlock(pdp); 3837534Sroot dp = iget(dp->i_dev, fs, u.u_dent.d_ino); 3847534Sroot if (dp == NULL) 3857534Sroot goto bad2; 3867534Sroot fs = dp->i_fs; 3877534Sroot 3887534Sroot /* 3897534Sroot * Check for symbolic link 3907534Sroot */ 3917534Sroot if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) { 3927825Sroot u_int pathlen = strlen(cp) + 1; 3937534Sroot 3947534Sroot if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 3957534Sroot ++nlink > MAXSYMLINKS) { 3967534Sroot u.u_error = ELOOP; 3977534Sroot goto bad2; 3987534Sroot } 3997534Sroot bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 4007751Sroot u.u_error = 4017825Sroot rdwri(UIO_READ, dp, nbp->b_un.b_addr, dp->i_size, 4027825Sroot 0, 1, (int *)0); 4037534Sroot if (u.u_error) 4047534Sroot goto bad2; 4057534Sroot cp = nbp->b_un.b_addr; 4067534Sroot iput(dp); 4075972Swnj if (*cp == '/') { 4087534Sroot irele(pdp); 4095972Swnj while (*cp == '/') 4105972Swnj cp++; 4117534Sroot if ((dp = u.u_rdir) == NULL) 4127534Sroot dp = rootdir; 4137534Sroot ilock(dp); 4147534Sroot dp->i_count++; 4157534Sroot } else { 4167534Sroot dp = pdp; 4177534Sroot ilock(dp); 4185972Swnj } 4197534Sroot fs = dp->i_fs; 4207534Sroot goto dirloop; 42130Sbill } 4227534Sroot irele(pdp); 4237534Sroot 42430Sbill /* 4257534Sroot * Not a symbolic link. If more pathname, 4267534Sroot * continue at next component, else return. 42730Sbill */ 4287534Sroot if (*cp == '/') { 4297534Sroot while (*cp == '/') 4307534Sroot cp++; 4317534Sroot goto dirloop; 43230Sbill } 4335972Swnj brelse(nbp); 4347534Sroot return (dp); 4357534Sroot bad2: 4367534Sroot irele(pdp); 4377534Sroot bad: 4387534Sroot if (bp) 4397534Sroot brelse(bp); 4407534Sroot if (dp) 4417534Sroot iput(dp); 4427534Sroot brelse(nbp); 4436571Smckusic return (NULL); 44430Sbill } 44530Sbill 4467534Sroot dirbad(ip, how) 4477534Sroot struct inode *ip; 4487534Sroot char *how; 4497534Sroot { 4507534Sroot 4517534Sroot printf("%s: bad dir ino %d at offset %d: %s\n", 4527534Sroot ip->i_fs->fs_fsmnt, ip->i_number, u.u_offset, how); 4537534Sroot } 4547534Sroot 4557534Sroot dirbadname(ep) 4567534Sroot register struct direct *ep; 4577534Sroot { 4587534Sroot register int i; 4597534Sroot 4607534Sroot for (i = 0; i < ep->d_namlen; i++) 4617534Sroot if (ep->d_name[i] == 0) 4627534Sroot return (1); 4637534Sroot return (ep->d_name[i]); 4647534Sroot } 4657534Sroot 46630Sbill /* 4677534Sroot * Write a directory entry after a call to namei, using the parameters 4687534Sroot * which it left in the u. area. The argument ip is the inode which 4697534Sroot * the new directory entry will refer to. The u. area field u.u_pdir is 4707534Sroot * a pointer to the directory to be written, which was left locked by 4717534Sroot * namei. Remaining parameters (u.u_offset, u.u_count) indicate 4727534Sroot * how the space for the new entry is to be gotten. 4737534Sroot */ 4747534Sroot direnter(ip) 4757534Sroot struct inode *ip; 4765972Swnj { 4777534Sroot register struct direct *ep, *nep; 4787534Sroot struct buf *bp; 4797825Sroot int loc, freespace; 4808631Sroot u_int dsize; 4818631Sroot int newentrysize; 4827534Sroot char *dirbuf; 4835972Swnj 4847534Sroot u.u_dent.d_ino = ip->i_number; 4857534Sroot u.u_segflg = 1; 4867534Sroot newentrysize = DIRSIZ(&u.u_dent); 4877534Sroot if (u.u_count == 0) { 4887534Sroot /* 4897534Sroot * If u.u_count is 0, then namei could find no space in the 4907534Sroot * directory. In this case u.u_offset will be on a directory 4917534Sroot * block boundary and we will write the new entry into a fresh 4927534Sroot * block. 4937534Sroot */ 4947534Sroot if (u.u_offset&(DIRBLKSIZ-1)) 4957534Sroot panic("wdir: newblk"); 4967534Sroot u.u_dent.d_reclen = DIRBLKSIZ; 4978631Sroot (void) rdwri(UIO_WRITE, u.u_pdir, (caddr_t)&u.u_dent, 4988631Sroot newentrysize, u.u_offset, 1, (int *)0); 4997534Sroot iput(u.u_pdir); 5007534Sroot return; 5017534Sroot } 5027534Sroot 5037534Sroot /* 5047534Sroot * If u.u_count is non-zero, then namei found space for the 5057534Sroot * new entry in the range u.u_offset to u.u_offset+u.u_count. 5067534Sroot * in the directory. To use this space, we may have to compact 5077534Sroot * the entries located there, by copying them together towards 5087534Sroot * the beginning of the block, leaving the free space in 5097534Sroot * one usable chunk at the end. 5107534Sroot */ 5117534Sroot 5127534Sroot /* 5137534Sroot * Increase size of directory if entry eats into new space. 5147534Sroot * This should never push the size past a new multiple of 5157534Sroot * DIRBLKSIZE. 5167534Sroot */ 5178631Sroot if (u.u_offset+u.u_count > u.u_pdir->i_size) 5187534Sroot u.u_pdir->i_size = u.u_offset + u.u_count; 5197534Sroot 5207534Sroot /* 5217534Sroot * Get the block containing the space for the new directory 5227534Sroot * entry. 5237534Sroot */ 5247605Ssam bp = blkatoff(u.u_pdir, u.u_offset, (char **)&dirbuf); 5257534Sroot if (bp == 0) 5267534Sroot return; 5277534Sroot 5287534Sroot /* 5297534Sroot * Find space for the new entry. In the simple case, the 5307534Sroot * entry at offset base will have the space. If it does 5317534Sroot * not, then namei arranged that compacting the region 5327534Sroot * u.u_offset to u.u_offset+u.u_count would yield the space. 5337534Sroot */ 5347534Sroot ep = (struct direct *)dirbuf; 5357534Sroot dsize = DIRSIZ(ep); 5367534Sroot freespace = ep->d_reclen - dsize; 5377534Sroot for (loc = ep->d_reclen; loc < u.u_count; ) { 5387534Sroot nep = (struct direct *)(dirbuf + loc); 5397534Sroot if (ep->d_ino) { 5407534Sroot /* trim the existing slot */ 5417534Sroot ep->d_reclen = dsize; 5427534Sroot ep = (struct direct *)((char *)ep + dsize); 5437534Sroot } else { 5447534Sroot /* overwrite; nothing there; header is ours */ 5457534Sroot freespace += dsize; 5467534Sroot } 5477534Sroot dsize = DIRSIZ(nep); 5487534Sroot freespace += nep->d_reclen - dsize; 5497534Sroot loc += nep->d_reclen; 5507825Sroot bcopy((caddr_t)nep, (caddr_t)ep, dsize); 5517534Sroot } 5527534Sroot /* 5537534Sroot * Update the pointer fields in the previous entry (if any), 5547534Sroot * copy in the new entry, and write out the block. 5557534Sroot */ 5567534Sroot if (ep->d_ino == 0) { 5577534Sroot if (freespace + dsize < newentrysize) 5587534Sroot panic("wdir: compact1"); 5597534Sroot u.u_dent.d_reclen = freespace + dsize; 5607534Sroot } else { 5617534Sroot if (freespace < newentrysize) 5627534Sroot panic("wdir: compact2"); 5637534Sroot u.u_dent.d_reclen = freespace; 5647534Sroot ep->d_reclen = dsize; 5657534Sroot ep = (struct direct *)((char *)ep + dsize); 5667534Sroot } 567*8672Sroot bcopy((caddr_t)&u.u_dent, (caddr_t)ep, (u_int)newentrysize); 5687534Sroot bwrite(bp); 5697534Sroot u.u_pdir->i_flag |= IUPD|ICHG; 5707534Sroot iput(u.u_pdir); 5715972Swnj } 5726571Smckusic 5737534Sroot dirremove() 5746571Smckusic { 5757534Sroot register struct inode *dp = u.u_pdir; 5767534Sroot register struct buf *bp; 5777534Sroot struct direct *ep; 5786571Smckusic 5797534Sroot if (u.u_count == 0) { 5807534Sroot /* 5817534Sroot * First entry in block: set d_ino to zero. 5827534Sroot */ 5837534Sroot u.u_dent.d_ino = 0; 5848619Sroot (void) rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent, 5858631Sroot (int)DIRSIZ(&u.u_dent), u.u_offset, 1, (int *)0); 5867534Sroot } else { 5877534Sroot /* 5887534Sroot * Collapse new free space into previous entry. 5897534Sroot */ 5907825Sroot bp = blkatoff(dp, (int)(u.u_offset - u.u_count), (char **)&ep); 5917534Sroot if (bp == 0) 5927534Sroot return (0); 5937534Sroot ep->d_reclen += u.u_dent.d_reclen; 5947534Sroot bwrite(bp); 5957534Sroot dp->i_flag |= IUPD|ICHG; 5967534Sroot } 5977534Sroot return (1); 5986571Smckusic } 5997534Sroot 6007605Ssam /* 6017605Ssam * Return buffer with contents of block "offset" 6027605Ssam * from the beginning of directory "ip". If "res" 6037605Ssam * is non-zero, fill it in with a pointer to the 6047605Ssam * remaining space in the directory. 6057605Ssam */ 6067534Sroot struct buf * 6077605Ssam blkatoff(ip, offset, res) 6087534Sroot struct inode *ip; 6097534Sroot off_t offset; 6107534Sroot char **res; 6117534Sroot { 6127534Sroot register struct fs *fs = ip->i_fs; 613*8672Sroot daddr_t lbn = lblkno(fs, offset); 6147534Sroot int base = blkoff(fs, offset); 6157534Sroot int bsize = blksize(fs, ip, lbn); 616*8672Sroot daddr_t bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize)); 6177534Sroot register struct buf *bp; 6187534Sroot 6197534Sroot if (u.u_error) 6207534Sroot return (0); 6217534Sroot bp = bread(ip->i_dev, bn, bsize); 6227534Sroot if (bp->b_flags & B_ERROR) { 6237534Sroot brelse(bp); 6247534Sroot return (0); 6257534Sroot } 6267534Sroot if (res) 6277534Sroot *res = bp->b_un.b_addr + base; 6287534Sroot return (bp); 6297534Sroot } 630