1*7534Sroot /* vfs_lookup.c 4.19 82/07/25 */ 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*7534Sroot struct buf *batoffset(); 18*7534Sroot int dirchk = 1; 1930Sbill /* 20*7534Sroot * Convert a pathname into a pointer to a locked inode, 21*7534Sroot * with side effects usable in creating and removing files. 22*7534Sroot * This is a very central and rather complicated routine. 2330Sbill * 24*7534Sroot * The func argument gives the routine which returns successive 25*7534Sroot * characters of the name to be translated. The flag 26*7534Sroot * argument is (0, 1, 2) depending on whether the name is to be 27*7534Sroot * (looked up, created, deleted). The follow argument is 1 when 28*7534Sroot * symbolic links are to be followed when they occur at the end of 29*7534Sroot * the name translation process. 30*7534Sroot * 31*7534Sroot * Overall outline: 32*7534Sroot * 33*7534Sroot * copy in name 34*7534Sroot * get starting directory 35*7534Sroot * dirloop: 36*7534Sroot * check accessibility of directory 37*7534Sroot * dirloop2: 38*7534Sroot * copy next component of name to u.u_dent 39*7534Sroot * handle degenerate case where name is null string 40*7534Sroot * search for name in directory, to found or notfound 41*7534Sroot * notfound: 42*7534Sroot * if creating, return locked inode, leaving information on avail. slots 43*7534Sroot * else return error 44*7534Sroot * found: 45*7534Sroot * if at end of path and deleting, return information to allow delete 46*7534Sroot * if .. and on mounted filesys, look in mount table for parent 47*7534Sroot * if symbolic link, massage name in buffer and continue at dirloop 48*7534Sroot * if more components of name, do next level at dirloop 49*7534Sroot * return the answer as locked inode 5030Sbill */ 5130Sbill struct inode * 525972Swnj namei(func, flag, follow) 535972Swnj int (*func)(), flag, follow; 5430Sbill { 55*7534Sroot register char *cp; /* pointer into pathname argument */ 56*7534Sroot /* these variables refer to things which must be freed or unlocked */ 57*7534Sroot register struct inode *dp = 0; /* the directory we are searching */ 58*7534Sroot register struct fs *fs; /* file system that directory is in */ 59*7534Sroot register struct buf *bp = 0; /* a buffer of directory entries */ 60*7534Sroot register struct direct *ep; /* the current directory entry */ 61*7534Sroot int entryoffsetinblock; /* offset of ep in bp's buffer */ 62*7534Sroot register struct buf *nbp; /* buffer storing path name argument */ 63*7534Sroot /* these variables hold information about the search for a slot */ 64*7534Sroot enum {NONE, COMPACT, FOUND} slotstatus; 65*7534Sroot int slotoffset = -1; /* offset of area with free space */ 66*7534Sroot int slotsize; /* size of area at slotoffset */ 67*7534Sroot int slotfreespace; /* amount of space free in slot */ 68*7534Sroot int slotneeded; /* size of the entry we're seeking */ 69*7534Sroot /* */ 70*7534Sroot int dirsize; 71*7534Sroot int prevoff; /* u.u_offset of previous entry */ 72*7534Sroot int nlink = 0; /* number of symbolic links taken */ 73*7534Sroot struct inode *pdp; /* saved dp during symlink work */ 74*7534Sroot int i; 7530Sbill 7630Sbill /* 77*7534Sroot * Get a buffer for the name to be translated, and copy the 78*7534Sroot * name into the buffer. 795972Swnj */ 806571Smckusic nbp = geteblk(MAXPATHLEN); 81*7534Sroot for (cp = nbp->b_un.b_addr; *cp = (*func)(); ) { 82*7534Sroot if ((*cp&0377) == ('/'|0200) || (*cp&0200) && flag != 2) { 836066Sroot u.u_error = EPERM; 84*7534Sroot goto bad; 856066Sroot } 866066Sroot cp++; 876571Smckusic if (cp >= nbp->b_un.b_addr + MAXPATHLEN) { 885972Swnj u.u_error = ENOENT; 89*7534Sroot goto bad; 905972Swnj } 915972Swnj } 92*7534Sroot if (u.u_error) 93*7534Sroot goto bad; 94*7534Sroot 955972Swnj /* 96*7534Sroot * Get starting directory. 9730Sbill */ 98*7534Sroot cp = nbp->b_un.b_addr; 995972Swnj if (*cp == '/') { 1005972Swnj while (*cp == '/') 1015972Swnj cp++; 10230Sbill if ((dp = u.u_rdir) == NULL) 10330Sbill dp = rootdir; 104*7534Sroot } else 105*7534Sroot dp = u.u_cdir; 106*7534Sroot fs = dp->i_fs; 1075972Swnj ilock(dp); 1085972Swnj dp->i_count++; 109*7534Sroot u.u_pdir = (struct inode *)0xc0000000; /* illegal */ 110*7534Sroot 111*7534Sroot /* 112*7534Sroot * We come to dirloop to search a new directory. 113*7534Sroot * The directory must be locked so that it can be 114*7534Sroot * iput, and fs must be already set to dp->i_fs. 115*7534Sroot */ 1166571Smckusic dirloop: 11730Sbill /* 118*7534Sroot * 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 126*7534Sroot if ((dp->i_mode&IFMT) != IFDIR) { 12730Sbill u.u_error = ENOTDIR; 128*7534Sroot goto bad; 129*7534Sroot } 130*7534Sroot if (access(dp, IEXEC)) 131*7534Sroot goto bad; 132*7534Sroot 1336384Swnj dirloop2: 134*7534Sroot /* 135*7534Sroot * Copy next component of name to u.u_dent. 136*7534Sroot */ 137*7534Sroot for (i = 0; *cp != 0 && *cp != '/'; cp++) { 1386571Smckusic if (i >= MAXNAMLEN) { 1395972Swnj u.u_error = ENOENT; 140*7534Sroot goto bad; 1415972Swnj } 142*7534Sroot u.u_dent.d_name[i++] = *cp; 1435972Swnj } 1446571Smckusic u.u_dent.d_namlen = i; 145*7534Sroot u.u_dent.d_name[i] = 0; 146*7534Sroot 147*7534Sroot /* 148*7534Sroot * Check for degenerate name (e.g. / or "") 149*7534Sroot * which is a way of talking about a directory, 150*7534Sroot * e.g. like "/." or ".". 151*7534Sroot */ 152*7534Sroot if (u.u_dent.d_name[0] == 0) { 153*7534Sroot if (flag) { 1545972Swnj u.u_error = ENOENT; 155*7534Sroot goto bad; 1565972Swnj } 1576571Smckusic brelse(nbp); 1586571Smckusic return (dp); 1595972Swnj } 160*7534Sroot 1616571Smckusic /* 162*7534Sroot * Suppress search for slots unless creating 163*7534Sroot * file and at end of pathname, in which case 164*7534Sroot * we watch for a place to put the new file in 165*7534Sroot * case it doesn't already exist. 1666571Smckusic */ 167*7534Sroot slotstatus = FOUND; 168*7534Sroot if (flag == 1 && *cp == 0) { 169*7534Sroot slotstatus = NONE; 170*7534Sroot slotfreespace = 0; 171*7534Sroot slotneeded = DIRSIZ(&u.u_dent); 172*7534Sroot } 173*7534Sroot 174*7534Sroot dirsize = roundup(dp->i_size, DIRBLKSIZ); 1756571Smckusic u.u_offset = 0; 176*7534Sroot 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*7534Sroot bp = batoffset(dp, u.u_offset, (char **)0); 186*7534Sroot if (bp == 0) 187*7534Sroot goto bad; 188*7534Sroot entryoffsetinblock = 0; 1895972Swnj } 190*7534Sroot 1915972Swnj /* 192*7534Sroot * If still looking for a slot, and at a DIRBLKSIZE 193*7534Sroot * boundary, have to start looking for free space 194*7534Sroot * again. 1956571Smckusic */ 196*7534Sroot if (slotstatus == NONE && 197*7534Sroot (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { 198*7534Sroot slotoffset = -1; 199*7534Sroot slotfreespace = 0; 200*7534Sroot } 201*7534Sroot 202*7534Sroot /* 203*7534Sroot * Get pointer to next entry, and do consistency checking: 204*7534Sroot * record length must be multiple of 4 205*7534Sroot * entry must fit in rest of this DIRBLKSIZ block 206*7534Sroot * record must be large enough to contain name 207*7534Sroot * name must be as long as advertised, and null terminated 208*7534Sroot * Checking last condition is expensive, it is done only 209*7534Sroot * when dirchk is set. 210*7534Sroot */ 211*7534Sroot ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 212*7534Sroot i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 213*7534Sroot if ((ep->d_reclen & 0x3) || ep->d_reclen > i || 214*7534Sroot DIRSIZ(ep) > ep->d_reclen || dirchk && dirbadname(ep)) { 215*7534Sroot dirbad(dp, "mangled entry"); 2166571Smckusic u.u_offset += i; 217*7534Sroot entryoffsetinblock += i; 2186571Smckusic continue; 2196571Smckusic } 220*7534Sroot 2216571Smckusic /* 222*7534Sroot * If an appropriate sized slot has not yet been found, 2236571Smckusic * check to see if one is available. Also accumulate space 2246571Smckusic * in the current block so that we can determine if 2256571Smckusic * compaction is viable. 2266571Smckusic */ 227*7534Sroot if (slotstatus != FOUND) { 228*7534Sroot int size = ep->d_reclen; 229*7534Sroot 2306571Smckusic if (ep->d_ino != 0) 2316571Smckusic size -= DIRSIZ(ep); 2326571Smckusic if (size > 0) { 233*7534Sroot if (size >= slotneeded) { 234*7534Sroot slotstatus = FOUND; 235*7534Sroot slotoffset = u.u_offset; 236*7534Sroot slotsize = ep->d_reclen; 237*7534Sroot } else if (slotstatus == NONE) { 238*7534Sroot slotfreespace += size; 239*7534Sroot if (slotoffset == -1) 240*7534Sroot slotoffset = u.u_offset; 241*7534Sroot if (slotfreespace >= slotneeded) { 242*7534Sroot slotstatus = COMPACT; 243*7534Sroot slotsize = 244*7534Sroot u.u_offset+ep->d_reclen - 245*7534Sroot slotoffset; 246*7534Sroot } 2476571Smckusic } 2486571Smckusic } 2496571Smckusic } 250*7534Sroot 2516571Smckusic /* 252*7534Sroot * Check for a name match. 2535972Swnj */ 254*7534Sroot if (ep->d_ino) { 255*7534Sroot if (ep->d_namlen == u.u_dent.d_namlen && 256*7534Sroot !bcmp(u.u_dent.d_name, ep->d_name, ep->d_namlen)) 257*7534Sroot goto found; 258*7534Sroot } 259*7534Sroot prevoff = u.u_offset; 2606571Smckusic u.u_offset += ep->d_reclen; 261*7534Sroot entryoffsetinblock += ep->d_reclen; 262*7534Sroot } 263*7534Sroot /* notfound: */ 264*7534Sroot /* 265*7534Sroot * If creating, and at end of pathname and current 266*7534Sroot * directory has not been removed, then can consider allowing 267*7534Sroot * file to be created. 268*7534Sroot */ 269*7534Sroot if (flag == 1 && *cp == 0 && dp->i_nlink != 0) { 2705972Swnj /* 271*7534Sroot * Access for write is interpreted as allowing 272*7534Sroot * creation of files in the directory. 2735972Swnj */ 274*7534Sroot if (access(dp, IWRITE)) 275*7534Sroot goto bad; 2765972Swnj /* 277*7534Sroot * Return an indication of where the new directory 278*7534Sroot * entry should be put. If we didn't find a slot, 279*7534Sroot * then set u.u_count to 0 indicating that the 280*7534Sroot * new slot belongs at the end of the directory. 281*7534Sroot * If we found a slot, then the new entry can be 282*7534Sroot * put in the range [u.u_offset..u.u_offset+u.u_count) 2835972Swnj */ 284*7534Sroot if (slotstatus == NONE) 285*7534Sroot u.u_count = 0; 286*7534Sroot else { 287*7534Sroot u.u_offset = slotoffset; 288*7534Sroot u.u_count = slotsize; 2895972Swnj } 290*7534Sroot dp->i_flag |= IUPD|ICHG; 291*7534Sroot if (bp) 292*7534Sroot brelse(bp); 293*7534Sroot brelse(nbp); 2945972Swnj /* 295*7534Sroot * We return with the directory locked, so that 296*7534Sroot * the parameters we set up above will still be 297*7534Sroot * valid if we actually decide to do a direnter(). 298*7534Sroot * We return NULL to indicate that the entry doesn't 299*7534Sroot * currently exist, leaving a pointer to the (locked) 300*7534Sroot * directory inode in u.u_pdir. 3015972Swnj */ 302*7534Sroot u.u_pdir = dp; 303*7534Sroot return (NULL); 304*7534Sroot } 305*7534Sroot u.u_error = ENOENT; 306*7534Sroot goto bad; 307*7534Sroot found: 308*7534Sroot /* 309*7534Sroot * Check that directory length properly reflects presence 310*7534Sroot * of this entry. 311*7534Sroot */ 312*7534Sroot if (entryoffsetinblock + ep->d_reclen > dp->i_size) { 313*7534Sroot dirbad(dp, "i_size too small"); 314*7534Sroot dp->i_size = entryoffsetinblock + ep->d_reclen; 315*7534Sroot dp->i_flag |= IUPD|ICHG; 316*7534Sroot } 317*7534Sroot 318*7534Sroot /* 319*7534Sroot * Found component in pathname; save directory 320*7534Sroot * entry in u.u_dent, and release directory buffer. 321*7534Sroot */ 322*7534Sroot bcopy((caddr_t)ep, (caddr_t)&u.u_dent, DIRSIZ(ep)); 323*7534Sroot brelse(bp); 324*7534Sroot bp = NULL; 325*7534Sroot 326*7534Sroot /* 327*7534Sroot * If deleting, and at end of pathname, return 328*7534Sroot * parameters which can be used to remove file. 329*7534Sroot * Note that in this case we return the directory 330*7534Sroot * inode, not the inode of the file being deleted. 331*7534Sroot */ 332*7534Sroot if (flag == 2 && *cp == 0) { 333*7534Sroot /* 334*7534Sroot * Write access to directory required to delete files. 335*7534Sroot */ 336*7534Sroot if (access(dp, IWRITE)) 337*7534Sroot goto bad; 338*7534Sroot /* 339*7534Sroot * Return pointer to current entry in u.u_offset, 340*7534Sroot * and distance past previous entry (if there 341*7534Sroot * is a previous entry in this block) in u.u_count. 342*7534Sroot * Save directory inode pointer in u.u_pdir for dirremove(). 343*7534Sroot */ 344*7534Sroot if ((u.u_offset&(DIRBLKSIZ-1)) == 0) 345*7534Sroot u.u_count = 0; 346*7534Sroot else 347*7534Sroot u.u_count = u.u_offset - prevoff; 348*7534Sroot brelse(nbp); 349*7534Sroot u.u_pdir = dp; /* for dirremove() */ 350*7534Sroot return (dp); 351*7534Sroot } 352*7534Sroot 353*7534Sroot /* 354*7534Sroot * Special handling for ".." allowing chdir out of mounted 355*7534Sroot * file system: indirect .. in root inode to reevaluate 356*7534Sroot * in directory file system was mounted on. 357*7534Sroot */ 358*7534Sroot if (u.u_dent.d_name[0] == '.' && u.u_dent.d_name[1] == '.' && 359*7534Sroot u.u_dent.d_name[2] == '\0') { 360*7534Sroot if (dp == u.u_rdir) 361*7534Sroot u.u_dent.d_ino = dp->i_number; 362*7534Sroot else if (u.u_dent.d_ino == ROOTINO && 363*7534Sroot dp->i_number == ROOTINO) { 364*7534Sroot for (i = 1; i < NMOUNT; i++) 365*7534Sroot if (mount[i].m_bufp != NULL && 366*7534Sroot mount[i].m_dev == dp->i_dev) { 3676571Smckusic iput(dp); 368*7534Sroot dp = mount[i].m_inodp; 3695972Swnj ilock(dp); 3705972Swnj dp->i_count++; 371*7534Sroot fs = dp->i_fs; 372*7534Sroot cp -= 2; /* back over .. */ 373*7534Sroot goto dirloop2; 3745972Swnj } 37530Sbill } 376*7534Sroot } 377*7534Sroot 378*7534Sroot /* 379*7534Sroot * Check for symbolic link, which may require us 380*7534Sroot * to massage the name before we continue translation. 381*7534Sroot * To avoid deadlock have to unlock the current directory, 382*7534Sroot * but don't iput it because we may need it again (if 383*7534Sroot * the symbolic link is relative to .). Instead save 384*7534Sroot * it (unlocked) as pdp. 385*7534Sroot */ 386*7534Sroot pdp = dp; 387*7534Sroot iunlock(pdp); 388*7534Sroot dp = iget(dp->i_dev, fs, u.u_dent.d_ino); 389*7534Sroot if (dp == NULL) 390*7534Sroot goto bad2; 391*7534Sroot fs = dp->i_fs; 392*7534Sroot 393*7534Sroot /* 394*7534Sroot * Check for symbolic link 395*7534Sroot */ 396*7534Sroot if ((dp->i_mode & IFMT) == IFLNK && (follow || *cp == '/')) { 397*7534Sroot int pathlen = strlen(cp) + 1; 398*7534Sroot int bn; 399*7534Sroot 400*7534Sroot if (dp->i_size + pathlen >= MAXPATHLEN - 1 || 401*7534Sroot ++nlink > MAXSYMLINKS) { 402*7534Sroot u.u_error = ELOOP; 403*7534Sroot goto bad2; 404*7534Sroot } 405*7534Sroot bcopy(cp, nbp->b_un.b_addr + dp->i_size, pathlen); 406*7534Sroot u.u_segflg = 1; 407*7534Sroot u.u_base = nbp->b_un.b_addr; 408*7534Sroot u.u_count = dp->i_size; 409*7534Sroot readi(dp); 410*7534Sroot if (u.u_error) 411*7534Sroot goto bad2; 412*7534Sroot cp = nbp->b_un.b_addr; 413*7534Sroot iput(dp); 4145972Swnj if (*cp == '/') { 415*7534Sroot irele(pdp); 4165972Swnj while (*cp == '/') 4175972Swnj cp++; 418*7534Sroot if ((dp = u.u_rdir) == NULL) 419*7534Sroot dp = rootdir; 420*7534Sroot ilock(dp); 421*7534Sroot dp->i_count++; 422*7534Sroot } else { 423*7534Sroot dp = pdp; 424*7534Sroot ilock(dp); 4255972Swnj } 426*7534Sroot fs = dp->i_fs; 427*7534Sroot goto dirloop; 42830Sbill } 429*7534Sroot irele(pdp); 430*7534Sroot 43130Sbill /* 432*7534Sroot * Not a symbolic link. If more pathname, 433*7534Sroot * continue at next component, else return. 43430Sbill */ 435*7534Sroot if (*cp == '/') { 436*7534Sroot while (*cp == '/') 437*7534Sroot cp++; 438*7534Sroot goto dirloop; 43930Sbill } 4405972Swnj brelse(nbp); 441*7534Sroot return (dp); 442*7534Sroot bad2: 443*7534Sroot irele(pdp); 444*7534Sroot bad: 445*7534Sroot if (bp) 446*7534Sroot brelse(bp); 447*7534Sroot if (dp) 448*7534Sroot iput(dp); 449*7534Sroot brelse(nbp); 4506571Smckusic return (NULL); 45130Sbill } 45230Sbill 453*7534Sroot dirbad(ip, how) 454*7534Sroot struct inode *ip; 455*7534Sroot char *how; 456*7534Sroot { 457*7534Sroot 458*7534Sroot printf("%s: bad dir ino %d at offset %d: %s\n", 459*7534Sroot ip->i_fs->fs_fsmnt, ip->i_number, u.u_offset, how); 460*7534Sroot } 461*7534Sroot 462*7534Sroot dirbadname(ep) 463*7534Sroot register struct direct *ep; 464*7534Sroot { 465*7534Sroot register char *cp; 466*7534Sroot register int i; 467*7534Sroot 468*7534Sroot for (i = 0; i < ep->d_namlen; i++) 469*7534Sroot if (ep->d_name[i] == 0) 470*7534Sroot return (1); 471*7534Sroot return (ep->d_name[i]); 472*7534Sroot } 473*7534Sroot 47430Sbill /* 47530Sbill * Return the next character from the 47630Sbill * kernel string pointed at by dirp. 47730Sbill */ 47830Sbill schar() 47930Sbill { 48030Sbill 4815972Swnj return (*u.u_dirp++ & 0377); 48230Sbill } 48330Sbill 48430Sbill /* 48530Sbill * Return the next character from the 48630Sbill * user string pointed at by dirp. 48730Sbill */ 48830Sbill uchar() 48930Sbill { 49030Sbill register c; 49130Sbill 49230Sbill c = fubyte(u.u_dirp++); 4935972Swnj if (c == -1) { 49430Sbill u.u_error = EFAULT; 4955972Swnj c = 0; 4965972Swnj } 4975972Swnj return (c); 49830Sbill } 4995972Swnj 500*7534Sroot /* 501*7534Sroot * Write a directory entry after a call to namei, using the parameters 502*7534Sroot * which it left in the u. area. The argument ip is the inode which 503*7534Sroot * the new directory entry will refer to. The u. area field u.u_pdir is 504*7534Sroot * a pointer to the directory to be written, which was left locked by 505*7534Sroot * namei. Remaining parameters (u.u_offset, u.u_count) indicate 506*7534Sroot * how the space for the new entry is to be gotten. 507*7534Sroot */ 508*7534Sroot direnter(ip) 509*7534Sroot struct inode *ip; 5105972Swnj { 511*7534Sroot register struct direct *ep, *nep; 512*7534Sroot struct fs *fs; 513*7534Sroot struct buf *bp; 514*7534Sroot int loc, dsize, freespace, newentrysize; 515*7534Sroot char *dirbuf; 5165972Swnj 517*7534Sroot u.u_dent.d_ino = ip->i_number; 518*7534Sroot u.u_segflg = 1; 519*7534Sroot newentrysize = DIRSIZ(&u.u_dent); 520*7534Sroot if (u.u_count == 0) { 521*7534Sroot /* 522*7534Sroot * If u.u_count is 0, then namei could find no space in the 523*7534Sroot * directory. In this case u.u_offset will be on a directory 524*7534Sroot * block boundary and we will write the new entry into a fresh 525*7534Sroot * block. 526*7534Sroot */ 527*7534Sroot if (u.u_offset&(DIRBLKSIZ-1)) 528*7534Sroot panic("wdir: newblk"); 529*7534Sroot u.u_dent.d_reclen = DIRBLKSIZ; 530*7534Sroot u.u_count = newentrysize; 531*7534Sroot u.u_base = (caddr_t)&u.u_dent; 532*7534Sroot u.u_segflg = 1; 533*7534Sroot writei(u.u_pdir); 534*7534Sroot iput(u.u_pdir); 535*7534Sroot return; 536*7534Sroot } 537*7534Sroot 538*7534Sroot /* 539*7534Sroot * If u.u_count is non-zero, then namei found space for the 540*7534Sroot * new entry in the range u.u_offset to u.u_offset+u.u_count. 541*7534Sroot * in the directory. To use this space, we may have to compact 542*7534Sroot * the entries located there, by copying them together towards 543*7534Sroot * the beginning of the block, leaving the free space in 544*7534Sroot * one usable chunk at the end. 545*7534Sroot */ 546*7534Sroot 547*7534Sroot /* 548*7534Sroot * Increase size of directory if entry eats into new space. 549*7534Sroot * This should never push the size past a new multiple of 550*7534Sroot * DIRBLKSIZE. 551*7534Sroot */ 552*7534Sroot if (u.u_offset+u.u_count > u.u_pdir->i_size) { 553*7534Sroot if (((u.u_offset+u.u_count-1)&~(DIRBLKSIZ-1)) != 554*7534Sroot ((u.u_pdir->i_size-1)&~(DIRBLKSIZ-1))) { 555*7534Sroot printf("wdir i_size dir %s/%d (of=%d,cnt=%d,psz=%d))\n", 556*7534Sroot u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number,u.u_offset, 557*7534Sroot u.u_count,u.u_pdir->i_size); 558*7534Sroot panic("wdir: span"); 559*7534Sroot } 560*7534Sroot u.u_pdir->i_size = u.u_offset + u.u_count; 561*7534Sroot } 562*7534Sroot 563*7534Sroot /* 564*7534Sroot * Get the block containing the space for the new directory 565*7534Sroot * entry. 566*7534Sroot */ 567*7534Sroot bp = batoffset(u.u_pdir, u.u_offset, (char **)&dirbuf); 568*7534Sroot if (bp == 0) 569*7534Sroot return; 570*7534Sroot printf("direnter u.u_offset %d u.u_count %d, bpaddr %x, dirbuf %x\n", 571*7534Sroot u.u_offset, u.u_count, bp->b_un.b_addr, dirbuf); 572*7534Sroot 573*7534Sroot /* 574*7534Sroot * Find space for the new entry. In the simple case, the 575*7534Sroot * entry at offset base will have the space. If it does 576*7534Sroot * not, then namei arranged that compacting the region 577*7534Sroot * u.u_offset to u.u_offset+u.u_count would yield the space. 578*7534Sroot */ 579*7534Sroot ep = (struct direct *)dirbuf; 580*7534Sroot dsize = DIRSIZ(ep); 581*7534Sroot freespace = ep->d_reclen - dsize; 582*7534Sroot for (loc = ep->d_reclen; loc < u.u_count; ) { 583*7534Sroot nep = (struct direct *)(dirbuf + loc); 584*7534Sroot if (ep->d_ino) { 585*7534Sroot /* trim the existing slot */ 586*7534Sroot ep->d_reclen = dsize; 587*7534Sroot ep = (struct direct *)((char *)ep + dsize); 588*7534Sroot } else { 589*7534Sroot /* overwrite; nothing there; header is ours */ 590*7534Sroot freespace += dsize; 591*7534Sroot } 592*7534Sroot dsize = DIRSIZ(nep); 593*7534Sroot freespace += nep->d_reclen - dsize; 594*7534Sroot loc += nep->d_reclen; 595*7534Sroot /*ZZ*/if((loc&~0x1ff)!=(loc+nep->d_reclen-1&~0x1ff)) 596*7534Sroot /*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,nep->d_reclen, 597*7534Sroot /*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number); 598*7534Sroot bcopy(nep, ep, dsize); 599*7534Sroot } 600*7534Sroot /* 601*7534Sroot * Update the pointer fields in the previous entry (if any), 602*7534Sroot * copy in the new entry, and write out the block. 603*7534Sroot */ 604*7534Sroot if (ep->d_ino == 0) { 605*7534Sroot if (freespace + dsize < newentrysize) 606*7534Sroot panic("wdir: compact1"); 607*7534Sroot /*ZZ*/if(freespace+dsize>512)panic("wdir: compact screwup"); 608*7534Sroot u.u_dent.d_reclen = freespace + dsize; 609*7534Sroot } else { 610*7534Sroot if (freespace < newentrysize) 611*7534Sroot panic("wdir: compact2"); 612*7534Sroot u.u_dent.d_reclen = freespace; 613*7534Sroot /*ZZ*/if ((((char *)ep-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen"); 614*7534Sroot ep->d_reclen = dsize; 615*7534Sroot ep = (struct direct *)((char *)ep + dsize); 616*7534Sroot } 617*7534Sroot /*ZZ*/if((((char*)ep-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch"); 618*7534Sroot bcopy(&u.u_dent, ep, newentrysize); 619*7534Sroot bwrite(bp); 620*7534Sroot u.u_pdir->i_flag |= IUPD|ICHG; 621*7534Sroot iput(u.u_pdir); 6225972Swnj } 6236571Smckusic 624*7534Sroot dirremove() 6256571Smckusic { 626*7534Sroot register struct inode *dp = u.u_pdir; 627*7534Sroot register struct fs *fs = dp->i_fs; 628*7534Sroot register struct buf *bp; 629*7534Sroot struct direct *ep; 6306571Smckusic 631*7534Sroot printf("dirremove u.u_offset %d u.u_count %d\n", u.u_offset, u.u_count); 632*7534Sroot if (u.u_count == 0) { 633*7534Sroot /* 634*7534Sroot * First entry in block: set d_ino to zero. 635*7534Sroot */ 636*7534Sroot /*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n" 637*7534Sroot /*ZZ*/,dp->i_fs->fs_fsmnt,dp->i_number,u.u_offset,u.u_dent.d_name); 638*7534Sroot u.u_base = (caddr_t)&u.u_dent; 639*7534Sroot u.u_count = DIRSIZ(&u.u_dent); 640*7534Sroot u.u_dent.d_ino = 0; 641*7534Sroot writei(dp); 642*7534Sroot } else { 643*7534Sroot /* 644*7534Sroot * Collapse new free space into previous entry. 645*7534Sroot */ 646*7534Sroot bp = batoffset(dp, u.u_offset - u.u_count, (char **)&ep); 647*7534Sroot if (bp == 0) 648*7534Sroot return (0); 649*7534Sroot ep->d_reclen += u.u_dent.d_reclen; 650*7534Sroot /*ZZ*/if((((char *)ep - bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen > 512) 651*7534Sroot /*ZZ*/ panic("unlink: reclen"); 652*7534Sroot bwrite(bp); 653*7534Sroot dp->i_flag |= IUPD|ICHG; 654*7534Sroot } 655*7534Sroot return (1); 6566571Smckusic } 657*7534Sroot 658*7534Sroot struct buf * 659*7534Sroot batoffset(ip, offset, res) 660*7534Sroot struct inode *ip; 661*7534Sroot off_t offset; 662*7534Sroot char **res; 663*7534Sroot { 664*7534Sroot register struct fs *fs = ip->i_fs; 665*7534Sroot int lbn = lblkno(fs, offset); 666*7534Sroot int base = blkoff(fs, offset); 667*7534Sroot int bsize = blksize(fs, ip, lbn); 668*7534Sroot int bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, base, bsize)); 669*7534Sroot register struct buf *bp; 670*7534Sroot 671*7534Sroot if (u.u_error) 672*7534Sroot return (0); 673*7534Sroot bp = bread(ip->i_dev, bn, bsize); 674*7534Sroot if (bp->b_flags & B_ERROR) { 675*7534Sroot brelse(bp); 676*7534Sroot return (0); 677*7534Sroot } 678*7534Sroot if (res) 679*7534Sroot *res = bp->b_un.b_addr + base; 680*7534Sroot printf("b_addr %x res pointer %x\n", bp->b_un.b_addr, *res); 681*7534Sroot return (bp); 682*7534Sroot } 683