1*7605Ssam /* vfs_lookup.c 4.20 82/07/30 */ 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" 1230Sbill 137441Sroot #ifdef EFS 147441Sroot extern int efs_major; 157441Sroot #endif 167441Sroot 17*7605Ssam struct buf *blkatoff(); 187534Sroot int dirchk = 1; 1930Sbill /* 207534Sroot * Convert a pathname into a pointer to a locked inode, 217534Sroot * with side effects usable in creating and removing files. 227534Sroot * This is a very central and rather complicated routine. 2330Sbill * 247534Sroot * The func argument gives the routine which returns successive 257534Sroot * characters of the name to be translated. The flag 267534Sroot * argument is (0, 1, 2) depending on whether the name is to be 277534Sroot * (looked up, created, deleted). The follow argument is 1 when 287534Sroot * symbolic links are to be followed when they occur at the end of 297534Sroot * the name translation process. 307534Sroot * 317534Sroot * Overall outline: 327534Sroot * 337534Sroot * copy in name 347534Sroot * get starting directory 357534Sroot * dirloop: 367534Sroot * check accessibility of directory 377534Sroot * dirloop2: 387534Sroot * copy next component of name to u.u_dent 397534Sroot * handle degenerate case where name is null string 407534Sroot * search for name in directory, to found or notfound 417534Sroot * notfound: 427534Sroot * if creating, return locked inode, leaving information on avail. slots 437534Sroot * else return error 447534Sroot * found: 457534Sroot * if at end of path and deleting, return information to allow delete 467534Sroot * if .. and on mounted filesys, look in mount table for parent 477534Sroot * if symbolic link, massage name in buffer and continue at dirloop 487534Sroot * if more components of name, do next level at dirloop 497534Sroot * return the answer as locked inode 5030Sbill */ 5130Sbill struct inode * 525972Swnj namei(func, flag, follow) 535972Swnj int (*func)(), flag, follow; 5430Sbill { 557534Sroot register char *cp; /* pointer into pathname argument */ 567534Sroot /* these variables refer to things which must be freed or unlocked */ 577534Sroot register struct inode *dp = 0; /* the directory we are searching */ 587534Sroot register struct fs *fs; /* file system that directory is in */ 597534Sroot register struct buf *bp = 0; /* a buffer of directory entries */ 607534Sroot register struct direct *ep; /* the current directory entry */ 617534Sroot int entryoffsetinblock; /* offset of ep in bp's buffer */ 627534Sroot register struct buf *nbp; /* buffer storing path name argument */ 637534Sroot /* these variables hold information about the search for a slot */ 647534Sroot enum {NONE, COMPACT, FOUND} slotstatus; 657534Sroot int slotoffset = -1; /* offset of area with free space */ 667534Sroot int slotsize; /* size of area at slotoffset */ 677534Sroot int slotfreespace; /* amount of space free in slot */ 687534Sroot int slotneeded; /* size of the entry we're seeking */ 697534Sroot /* */ 707534Sroot int dirsize; 717534Sroot int prevoff; /* u.u_offset of previous entry */ 727534Sroot int nlink = 0; /* number of symbolic links taken */ 737534Sroot struct inode *pdp; /* saved dp during symlink work */ 747534Sroot int i; 7530Sbill 7630Sbill /* 777534Sroot * Get a buffer for the name to be translated, and copy the 787534Sroot * name into the buffer. 795972Swnj */ 806571Smckusic nbp = geteblk(MAXPATHLEN); 817534Sroot for (cp = nbp->b_un.b_addr; *cp = (*func)(); ) { 827534Sroot if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != 2) { 836066Sroot u.u_error = EPERM; 847534Sroot goto bad; 856066Sroot } 866066Sroot cp++; 876571Smckusic if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { 885972Swnj u.u_error = ENOENT; 897534Sroot goto bad; 905972Swnj } 915972Swnj } 927534Sroot if (u.u_error) 937534Sroot goto bad; 947534Sroot 955972Swnj /* 967534Sroot * Get starting directory. 9730Sbill */ 987534Sroot cp = nbp->b_un.b_addr; 995972Swnj if (*cp == '/') { 1005972Swnj while (*cp == '/') 1015972Swnj cp++; 10230Sbill if ((dp = u.u_rdir) == NULL) 10330Sbill dp = rootdir; 1047534Sroot } else 1057534Sroot dp = u.u_cdir; 1067534Sroot fs = dp->i_fs; 1075972Swnj ilock(dp); 1085972Swnj dp->i_count++; 1097534Sroot u.u_pdir = (struct inode *)0xc0000000; /* illegal */ 1107534Sroot 1117534Sroot /* 1127534Sroot * We come to dirloop to search a new directory. 1137534Sroot * The directory must be locked so that it can be 1147534Sroot * iput, and fs must be already set to dp->i_fs. 1157534Sroot */ 1166571Smckusic dirloop: 11730Sbill /* 1187534Sroot * Check accessiblity of directory. 11930Sbill */ 1207441Sroot #ifdef EFS 1217441Sroot if ((dp->i_mode & IFMT) == IFCHR && major(dp->i_rdev) == efs_major) { 1227441Sroot brelse(nbp); 1237441Sroot return(dp); 1247441Sroot } 1257441Sroot #endif 1267534Sroot if ((dp->i_mode&IFMT) != IFDIR) { 12730Sbill u.u_error = ENOTDIR; 1287534Sroot goto bad; 1297534Sroot } 1307534Sroot if (access(dp, IEXEC)) 1317534Sroot goto bad; 1327534Sroot 1336384Swnj dirloop2: 1347534Sroot /* 1357534Sroot * Copy next component of name to u.u_dent. 1367534Sroot */ 1377534Sroot for (i = 0; *cp != 0 && *cp != '/'; cp++) { 1386571Smckusic if (i >= MAXNAMLEN) { 1395972Swnj u.u_error = ENOENT; 1407534Sroot goto bad; 1415972Swnj } 1427534Sroot u.u_dent.d_name[i++] = *cp; 1435972Swnj } 1446571Smckusic u.u_dent.d_namlen = i; 1457534Sroot u.u_dent.d_name[i] = 0; 1467534Sroot 1477534Sroot /* 1487534Sroot * Check for degenerate name (e.g. / or "") 1497534Sroot * which is a way of talking about a directory, 1507534Sroot * e.g. like "/." or ".". 1517534Sroot */ 1527534Sroot if (u.u_dent.d_name[0] == 0) { 1537534Sroot if (flag) { 1545972Swnj u.u_error = ENOENT; 1557534Sroot goto bad; 1565972Swnj } 1576571Smckusic brelse(nbp); 1586571Smckusic return (dp); 1595972Swnj } 1607534Sroot 1616571Smckusic /* 1627534Sroot * Suppress search for slots unless creating 1637534Sroot * file and at end of pathname, in which case 1647534Sroot * we watch for a place to put the new file in 1657534Sroot * case it doesn't already exist. 1666571Smckusic */ 1677534Sroot slotstatus = FOUND; 1687534Sroot if (flag == 1 && *cp == 0) { 1697534Sroot slotstatus = NONE; 1707534Sroot slotfreespace = 0; 1717534Sroot slotneeded = DIRSIZ(&u.u_dent); 1727534Sroot } 1737534Sroot 1747534Sroot dirsize = roundup(dp->i_size, DIRBLKSIZ); 1756571Smckusic u.u_offset = 0; 1767534Sroot while (u.u_offset < dirsize) { 1775972Swnj /* 1785972Swnj * If offset is on a block boundary, 1795972Swnj * read the next directory block. 1805972Swnj * Release previous if it exists. 1815972Swnj */ 1826571Smckusic if (blkoff(fs, u.u_offset) == 0) { 1835972Swnj if (bp != NULL) 1845972Swnj brelse(bp); 185*7605Ssam bp = blkatoff(dp, u.u_offset, (char **)0); 1867534Sroot if (bp == 0) 1877534Sroot goto bad; 1887534Sroot entryoffsetinblock = 0; 1895972Swnj } 1907534Sroot 1915972Swnj /* 1927534Sroot * If still looking for a slot, and at a DIRBLKSIZE 1937534Sroot * boundary, have to start looking for free space 1947534Sroot * again. 1956571Smckusic */ 1967534Sroot if (slotstatus == NONE && 1977534Sroot (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { 1987534Sroot slotoffset = -1; 1997534Sroot slotfreespace = 0; 2007534Sroot } 2017534Sroot 2027534Sroot /* 2037534Sroot * Get pointer to next entry, and do consistency checking: 2047534Sroot * record length must be multiple of 4 205*7605Ssam * record length must not be zero 2067534Sroot * entry must fit in rest of this DIRBLKSIZ block 2077534Sroot * record must be large enough to contain name 208*7605Ssam * When dirchk is set we also check: 209*7605Ssam * name is not longer than MAXNAMLEN 2107534Sroot * name must be as long as advertised, and null terminated 211*7605Ssam * Checking last two conditions is done only when dirchk is 212*7605Ssam * set, to save time. 2137534Sroot */ 2147534Sroot ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 2157534Sroot i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 216*7605Ssam if ((ep->d_reclen & 0x3) || ep->d_reclen == 0 || 217*7605Ssam ep->d_reclen > i || DIRSIZ(ep) > ep->d_reclen || 218*7605Ssam dirchk && (ep->d_namlen > MAXNAMLEN || dirbadname(ep))) { 2197534Sroot dirbad(dp, "mangled entry"); 2206571Smckusic u.u_offset += i; 2217534Sroot entryoffsetinblock += i; 2226571Smckusic continue; 2236571Smckusic } 2247534Sroot 2256571Smckusic /* 2267534Sroot * If an appropriate sized slot has not yet been found, 2276571Smckusic * check to see if one is available. Also accumulate space 2286571Smckusic * in the current block so that we can determine if 2296571Smckusic * compaction is viable. 2306571Smckusic */ 2317534Sroot if (slotstatus != FOUND) { 2327534Sroot int size = ep->d_reclen; 2337534Sroot 2346571Smckusic if (ep->d_ino != 0) 2356571Smckusic size -= DIRSIZ(ep); 2366571Smckusic if (size > 0) { 2377534Sroot if (size >= slotneeded) { 2387534Sroot slotstatus = FOUND; 2397534Sroot slotoffset = u.u_offset; 2407534Sroot slotsize = ep->d_reclen; 2417534Sroot } else if (slotstatus == NONE) { 2427534Sroot slotfreespace += size; 2437534Sroot if (slotoffset == -1) 2447534Sroot slotoffset = u.u_offset; 2457534Sroot if (slotfreespace >= slotneeded) { 2467534Sroot slotstatus = COMPACT; 2477534Sroot slotsize = 2487534Sroot u.u_offset+ep->d_reclen - 2497534Sroot slotoffset; 2507534Sroot } 2516571Smckusic } 2526571Smckusic } 2536571Smckusic } 2547534Sroot 2556571Smckusic /* 2567534Sroot * Check for a name match. 2575972Swnj */ 2587534Sroot if (ep->d_ino) { 2597534Sroot if (ep->d_namlen == u.u_dent.d_namlen && 2607534Sroot !bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen)) 2617534Sroot goto found; 2627534Sroot } 2637534Sroot prevoff = u.u_offset; 2646571Smckusic u.u_offset += ep->d_reclen; 2657534Sroot entryoffsetinblock += ep->d_reclen; 2667534Sroot } 2677534Sroot /* notfound: */ 2687534Sroot /* 2697534Sroot * If creating, and at end of pathname and current 2707534Sroot * directory has not been removed, then can consider allowing 2717534Sroot * file to be created. 2727534Sroot */ 2737534Sroot if (flag == 1 && *cp == 0 && dp->i_nlink != 0) { 2745972Swnj /* 2757534Sroot * Access for write is interpreted as allowing 2767534Sroot * creation of files in the directory. 2775972Swnj */ 2787534Sroot if (access(dp, IWRITE)) 2797534Sroot goto bad; 2805972Swnj /* 2817534Sroot * Return an indication of where the new directory 2827534Sroot * entry should be put. If we didn't find a slot, 2837534Sroot * then set u.u_count to 0 indicating that the 2847534Sroot * new slot belongs at the end of the directory. 2857534Sroot * If we found a slot, then the new entry can be 2867534Sroot * put in the range [u.u_offset..u.u_offset+u.u_count) 2875972Swnj */ 2887534Sroot if (slotstatus == NONE) 2897534Sroot u.u_count = 0; 2907534Sroot else { 2917534Sroot u.u_offset = slotoffset; 2927534Sroot u.u_count = slotsize; 2935972Swnj } 2947534Sroot dp->i_flag |= IUPD|ICHG; 2957534Sroot if (bp) 2967534Sroot brelse(bp); 2977534Sroot brelse(nbp); 2985972Swnj /* 2997534Sroot * We return with the directory locked, so that 3007534Sroot * the parameters we set up above will still be 3017534Sroot * valid if we actually decide to do a direnter(). 3027534Sroot * We return NULL to indicate that the entry doesn't 3037534Sroot * currently exist, leaving a pointer to the (locked) 3047534Sroot * directory inode in u.u_pdir. 3055972Swnj */ 3067534Sroot u.u_pdir = dp; 3077534Sroot return (NULL); 3087534Sroot } 3097534Sroot u.u_error = ENOENT; 3107534Sroot goto bad; 3117534Sroot found: 3127534Sroot /* 3137534Sroot * Check that directory length properly reflects presence 3147534Sroot * of this entry. 3157534Sroot */ 316*7605Ssam if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 3177534Sroot dirbad(dp, "i_size too small"); 318*7605Ssam dp->i_size = entryoffsetinblock + DIRSIZ(ep); 3197534Sroot dp->i_flag |= IUPD|ICHG; 3207534Sroot } 3217534Sroot 3227534Sroot /* 3237534Sroot * Found component in pathname; save directory 3247534Sroot * entry in u.u_dent, and release directory buffer. 3257534Sroot */ 3267534Sroot bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep)); 3277534Sroot brelse(bp); 3287534Sroot bp = NULL; 3297534Sroot 3307534Sroot /* 3317534Sroot * If deleting, and at end of pathname, return 3327534Sroot * parameters which can be used to remove file. 3337534Sroot * Note that in this case we return the directory 3347534Sroot * inode, not the inode of the file being deleted. 3357534Sroot */ 3367534Sroot if (flag == 2 && *cp == 0) { 3377534Sroot /* 3387534Sroot * Write access to directory required to delete files. 3397534Sroot */ 3407534Sroot if (access(dp, IWRITE)) 3417534Sroot goto bad; 3427534Sroot /* 3437534Sroot * Return pointer to current entry in u.u_offset, 3447534Sroot * and distance past previous entry (if there 3457534Sroot * is a previous entry in this block) in u.u_count. 3467534Sroot * Save directory inode pointer in u.u_pdir for dirremove(). 3477534Sroot */ 3487534Sroot if ((u.u_offset&(DIRBLKSIZ-1)) == 0) 3497534Sroot u.u_count = 0; 3507534Sroot else 3517534Sroot u.u_count = u.u_offset - prevoff; 3527534Sroot brelse(nbp); 3537534Sroot u.u_pdir = dp; /* for dirremove() */ 3547534Sroot return (dp); 3557534Sroot } 3567534Sroot 3577534Sroot /* 3587534Sroot * Special handling for ".." allowing chdir out of mounted 3597534Sroot * file system: indirect .. in root inode to reevaluate 3607534Sroot * in directory file system was mounted on. 3617534Sroot */ 3627534Sroot if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && 3637534Sroot u.u_dent.d_name[2] == '\0') { 3647534Sroot if (dp == u.u_rdir) 3657534Sroot u.u_dent.d_ino = dp->i_number; 3667534Sroot else if (u.u_dent.d_ino == ROOTINO && 3677534Sroot dp->i_number == ROOTINO) { 3687534Sroot for (i = 1; i < NMOUNT; i++) 3697534Sroot if (mount[i].m_bufp != NULL && 3707534Sroot mount[i].m_dev == dp->i_dev) { 3716571Smckusic iput(dp); 3727534Sroot dp = mount[i].m_inodp; 3735972Swnj ilock(dp); 3745972Swnj dp->i_count++; 3757534Sroot fs = dp->i_fs; 3767534Sroot cp -= 2; /* back over .. */ 3777534Sroot goto dirloop2; 3785972Swnj } 37930Sbill } 3807534Sroot } 3817534Sroot 3827534Sroot /* 3837534Sroot * Check for symbolic link, which may require us 3847534Sroot * to massage the name before we continue translation. 3857534Sroot * To avoid deadlock have to unlock the current directory, 3867534Sroot * but don't iput it because we may need it again (if 3877534Sroot * the symbolic link is relative to .). Instead save 3887534Sroot * it (unlocked) as pdp. 3897534Sroot */ 3907534Sroot pdp = dp; 3917534Sroot iunlock(pdp); 3927534Sroot dp = iget(dp->i_dev, fs, u.u_dent.d_ino); 3937534Sroot if (dp == NULL) 3947534Sroot goto bad2; 3957534Sroot fs = dp->i_fs; 3967534Sroot 3977534Sroot /* 3987534Sroot * Check for symbolic link 3997534Sroot */ 4007534Sroot if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) { 4017534Sroot int pathlen = strlen(cp) + 1; 4027534Sroot int bn; 4037534Sroot 4047534Sroot if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 4057534Sroot ++nlink > MAXSYMLINKS) { 4067534Sroot u.u_error = ELOOP; 4077534Sroot goto bad2; 4087534Sroot } 4097534Sroot bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 4107534Sroot u.u_segflg = 1; 4117534Sroot u.u_base = nbp->b_un.b_addr; 4127534Sroot u.u_count = dp->i_size; 413*7605Ssam u.u_offset = 0; 4147534Sroot readi(dp); 4157534Sroot if (u.u_error) 4167534Sroot goto bad2; 4177534Sroot cp = nbp->b_un.b_addr; 4187534Sroot iput(dp); 4195972Swnj if (*cp == '/') { 4207534Sroot irele(pdp); 4215972Swnj while (*cp == '/') 4225972Swnj cp++; 4237534Sroot if ((dp = u.u_rdir) == NULL) 4247534Sroot dp = rootdir; 4257534Sroot ilock(dp); 4267534Sroot dp->i_count++; 4277534Sroot } else { 4287534Sroot dp = pdp; 4297534Sroot ilock(dp); 4305972Swnj } 4317534Sroot fs = dp->i_fs; 4327534Sroot goto dirloop; 43330Sbill } 4347534Sroot irele(pdp); 4357534Sroot 43630Sbill /* 4377534Sroot * Not a symbolic link. If more pathname, 4387534Sroot * continue at next component, else return. 43930Sbill */ 4407534Sroot if (*cp == '/') { 4417534Sroot while (*cp == '/') 4427534Sroot cp++; 4437534Sroot goto dirloop; 44430Sbill } 4455972Swnj brelse(nbp); 4467534Sroot return (dp); 4477534Sroot bad2: 4487534Sroot irele(pdp); 4497534Sroot bad: 4507534Sroot if (bp) 4517534Sroot brelse(bp); 4527534Sroot if (dp) 4537534Sroot iput(dp); 4547534Sroot brelse(nbp); 4556571Smckusic return (NULL); 45630Sbill } 45730Sbill 4587534Sroot dirbad(ip, how) 4597534Sroot struct inode *ip; 4607534Sroot char *how; 4617534Sroot { 4627534Sroot 4637534Sroot printf("%s: bad dir ino %d at offset %d: %s\n", 4647534Sroot ip->i_fs->fs_fsmnt, ip->i_number, u.u_offset, how); 4657534Sroot } 4667534Sroot 4677534Sroot dirbadname(ep) 4687534Sroot register struct direct *ep; 4697534Sroot { 4707534Sroot register char *cp; 4717534Sroot register int i; 4727534Sroot 4737534Sroot for (i = 0; i < ep->d_namlen; i++) 4747534Sroot if (ep->d_name[i] == 0) 4757534Sroot return (1); 4767534Sroot return (ep->d_name[i]); 4777534Sroot } 4787534Sroot 47930Sbill /* 4807534Sroot * Write a directory entry after a call to namei, using the parameters 4817534Sroot * which it left in the u. area. The argument ip is the inode which 4827534Sroot * the new directory entry will refer to. The u. area field u.u_pdir is 4837534Sroot * a pointer to the directory to be written, which was left locked by 4847534Sroot * namei. Remaining parameters (u.u_offset, u.u_count) indicate 4857534Sroot * how the space for the new entry is to be gotten. 4867534Sroot */ 4877534Sroot direnter(ip) 4887534Sroot struct inode *ip; 4895972Swnj { 4907534Sroot register struct direct *ep, *nep; 4917534Sroot struct fs *fs; 4927534Sroot struct buf *bp; 4937534Sroot int loc, dsize, freespace, newentrysize; 4947534Sroot char *dirbuf; 4955972Swnj 4967534Sroot u.u_dent.d_ino = ip->i_number; 4977534Sroot u.u_segflg = 1; 4987534Sroot newentrysize = DIRSIZ(&u.u_dent); 4997534Sroot if (u.u_count == 0) { 5007534Sroot /* 5017534Sroot * If u.u_count is 0, then namei could find no space in the 5027534Sroot * directory. In this case u.u_offset will be on a directory 5037534Sroot * block boundary and we will write the new entry into a fresh 5047534Sroot * block. 5057534Sroot */ 5067534Sroot if (u.u_offset&(DIRBLKSIZ-1)) 5077534Sroot panic("wdir: newblk"); 5087534Sroot u.u_dent.d_reclen = DIRBLKSIZ; 5097534Sroot u.u_count = newentrysize; 5107534Sroot u.u_base = (caddr_t)&u.u_dent; 5117534Sroot u.u_segflg = 1; 5127534Sroot writei(u.u_pdir); 5137534Sroot iput(u.u_pdir); 5147534Sroot return; 5157534Sroot } 5167534Sroot 5177534Sroot /* 5187534Sroot * If u.u_count is non-zero, then namei found space for the 5197534Sroot * new entry in the range u.u_offset to u.u_offset+u.u_count. 5207534Sroot * in the directory. To use this space, we may have to compact 5217534Sroot * the entries located there, by copying them together towards 5227534Sroot * the beginning of the block, leaving the free space in 5237534Sroot * one usable chunk at the end. 5247534Sroot */ 5257534Sroot 5267534Sroot /* 5277534Sroot * Increase size of directory if entry eats into new space. 5287534Sroot * This should never push the size past a new multiple of 5297534Sroot * DIRBLKSIZE. 5307534Sroot */ 5317534Sroot if (u.u_offset+u.u_count > u.u_pdir->i_size) { 532*7605Ssam /*ZZ*/ if (((u.u_offset+u.u_count-1)&~(DIRBLKSIZ-1)) != 533*7605Ssam /*ZZ*/ ((u.u_pdir->i_size-1)&~(DIRBLKSIZ-1))) { 534*7605Ssam /*ZZ*/ panic("wdir: span"); 535*7605Ssam /*ZZ*/ } 5367534Sroot u.u_pdir->i_size = u.u_offset + u.u_count; 5377534Sroot } 5387534Sroot 5397534Sroot /* 5407534Sroot * Get the block containing the space for the new directory 5417534Sroot * entry. 5427534Sroot */ 543*7605Ssam bp = blkatoff(u.u_pdir, u.u_offset, (char **)&dirbuf); 5447534Sroot if (bp == 0) 5457534Sroot return; 5467534Sroot 5477534Sroot /* 5487534Sroot * Find space for the new entry. In the simple case, the 5497534Sroot * entry at offset base will have the space. If it does 5507534Sroot * not, then namei arranged that compacting the region 5517534Sroot * u.u_offset to u.u_offset+u.u_count would yield the space. 5527534Sroot */ 5537534Sroot ep = (struct direct *)dirbuf; 5547534Sroot dsize = DIRSIZ(ep); 5557534Sroot freespace = ep->d_reclen - dsize; 5567534Sroot for (loc = ep->d_reclen; loc < u.u_count; ) { 5577534Sroot nep = (struct direct *)(dirbuf + loc); 5587534Sroot if (ep->d_ino) { 5597534Sroot /* trim the existing slot */ 5607534Sroot ep->d_reclen = dsize; 5617534Sroot ep = (struct direct *)((char *)ep + dsize); 5627534Sroot } else { 5637534Sroot /* overwrite; nothing there; header is ours */ 5647534Sroot freespace += dsize; 5657534Sroot } 5667534Sroot dsize = DIRSIZ(nep); 5677534Sroot freespace += nep->d_reclen - dsize; 5687534Sroot loc += nep->d_reclen; 5697534Sroot /*ZZ*/if((loc&~0x1ff)!=(loc+nep->d_reclen-1&~0x1ff)) 5707534Sroot /*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,nep->d_reclen, 5717534Sroot /*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number); 5727534Sroot bcopy(nep, ep, dsize); 5737534Sroot } 5747534Sroot /* 5757534Sroot * Update the pointer fields in the previous entry (if any), 5767534Sroot * copy in the new entry, and write out the block. 5777534Sroot */ 5787534Sroot if (ep->d_ino == 0) { 5797534Sroot if (freespace + dsize < newentrysize) 5807534Sroot panic("wdir: compact1"); 5817534Sroot /*ZZ*/if(freespace+dsize>512)panic("wdir: compact screwup"); 5827534Sroot u.u_dent.d_reclen = freespace + dsize; 5837534Sroot } else { 5847534Sroot if (freespace < newentrysize) 5857534Sroot panic("wdir: compact2"); 5867534Sroot u.u_dent.d_reclen = freespace; 5877534Sroot /*ZZ*/if ((((char *)ep-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen"); 5887534Sroot ep->d_reclen = dsize; 5897534Sroot ep = (struct direct *)((char *)ep + dsize); 5907534Sroot } 5917534Sroot /*ZZ*/if((((char*)ep-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch"); 5927534Sroot bcopy(&u.u_dent, ep, newentrysize); 5937534Sroot bwrite(bp); 5947534Sroot u.u_pdir->i_flag |= IUPD|ICHG; 5957534Sroot iput(u.u_pdir); 5965972Swnj } 5976571Smckusic 5987534Sroot dirremove() 5996571Smckusic { 6007534Sroot register struct inode *dp = u.u_pdir; 6017534Sroot register struct fs *fs = dp->i_fs; 6027534Sroot register struct buf *bp; 6037534Sroot struct direct *ep; 6046571Smckusic 6057534Sroot if (u.u_count == 0) { 6067534Sroot /* 6077534Sroot * First entry in block: set d_ino to zero. 6087534Sroot */ 6097534Sroot /*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n" 6107534Sroot /*ZZ*/,dp->i_fs->fs_fsmnt,dp->i_number,u.u_offset,u.u_dent.d_name); 6117534Sroot u.u_base = (caddr_t)&u.u_dent; 6127534Sroot u.u_count = DIRSIZ(&u.u_dent); 613*7605Ssam u.u_segflg = 1; 6147534Sroot u.u_dent.d_ino = 0; 6157534Sroot writei(dp); 6167534Sroot } else { 6177534Sroot /* 6187534Sroot * Collapse new free space into previous entry. 6197534Sroot */ 620*7605Ssam bp = blkatoff(dp, u.u_offset - u.u_count, (char **)&ep); 6217534Sroot if (bp == 0) 6227534Sroot return (0); 6237534Sroot ep->d_reclen += u.u_dent.d_reclen; 6247534Sroot /*ZZ*/if((((char *)ep - bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen > 512) 6257534Sroot /*ZZ*/ panic("unlink: reclen"); 6267534Sroot bwrite(bp); 6277534Sroot dp->i_flag |= IUPD|ICHG; 6287534Sroot } 6297534Sroot return (1); 6306571Smckusic } 6317534Sroot 632*7605Ssam /* 633*7605Ssam * Return buffer with contents of block "offset" 634*7605Ssam * from the beginning of directory "ip". If "res" 635*7605Ssam * is non-zero, fill it in with a pointer to the 636*7605Ssam * remaining space in the directory. 637*7605Ssam */ 6387534Sroot struct buf * 639*7605Ssam blkatoff(ip, offset, res) 6407534Sroot struct inode *ip; 6417534Sroot off_t offset; 6427534Sroot char **res; 6437534Sroot { 6447534Sroot register struct fs *fs = ip->i_fs; 6457534Sroot int lbn = lblkno(fs, offset); 6467534Sroot int base = blkoff(fs, offset); 6477534Sroot int bsize = blksize(fs, ip, lbn); 6487534Sroot int bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize)); 6497534Sroot register struct buf *bp; 6507534Sroot 6517534Sroot if (u.u_error) 6527534Sroot return (0); 6537534Sroot bp = bread(ip->i_dev, bn, bsize); 6547534Sroot if (bp->b_flags & B_ERROR) { 6557534Sroot brelse(bp); 6567534Sroot return (0); 6577534Sroot } 6587534Sroot if (res) 6597534Sroot *res = bp->b_un.b_addr + base; 6607534Sroot return (bp); 6617534Sroot } 662