1: /* 2: * Copyright (c) 1982 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)ufs_namei.c 1.5 (2.11BSD GTE) 1997/1/30 7: */ 8: #include "param.h" 9: #include "../machine/seg.h" 10: 11: #include "systm.h" 12: #include "dir.h" 13: #include "inode.h" 14: #include "fs.h" 15: #include "mount.h" 16: #include "user.h" 17: #include "buf.h" 18: #include "namei.h" 19: 20: struct buf *blkatoff(); 21: int dirchk = 0; 22: 23: /* 24: * Structures associated with name cacheing. 25: */ 26: #define NCHHASH 16 /* size of hash table */ 27: 28: #if ((NCHHASH)&((NCHHASH)-1)) != 0 29: #define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) % (NCHHASH)) 30: #else 31: #define NHASH(h, i, d) ((unsigned)((h) + (i) + 13 * (int)(d)) & ((NCHHASH)-1)) 32: #endif 33: 34: union nchash { 35: union nchash *nch_head[2]; 36: struct namecache *nch_chain[2]; 37: } nchash[NCHHASH]; 38: #define nch_forw nch_chain[0] 39: #define nch_back nch_chain[1] 40: 41: struct namecache *nchhead, **nchtail; /* LRU chain pointers */ 42: struct nchstats nchstats; /* cache effectiveness statistics */ 43: 44: /* 45: * Convert a pathname into a pointer to a locked inode. 46: * This is a very central and rather complicated routine. 47: * If the file system is not maintained in a strict tree hierarchy, 48: * this can result in a deadlock situation (see comments in code below). 49: * 50: * The flag argument is LOOKUP, CREATE, or DELETE depending on whether 51: * the name is to be looked up, created, or deleted. When CREATE or 52: * DELETE is specified, information usable in creating or deleteing a 53: * directory entry is also calculated. If flag has LOCKPARENT or'ed 54: * into it and the target of the pathname exists, namei returns both 55: * the target and its parent directory locked. When creating and 56: * LOCKPARENT is specified, the target may not be ".". When deleting 57: * and LOCKPARENT is specified, the target may be ".", but the caller 58: * must check to insure it does an irele and iput instead of two iputs. 59: * 60: * The FOLLOW flag is set when symbolic links are to be followed 61: * when they occur at the end of the name translation process. 62: * Symbolic links are always followed for all other pathname 63: * components other than the last. 64: * 65: * Name caching works as follows: 66: * 67: * Names found by directory scans are retained in a cache 68: * for future reference. It is managed LRU, so frequently 69: * used names will hang around. Cache is indexed by hash value 70: * obtained from (ino,dev,name) where ino & dev refer to the 71: * directory containing name. 72: * 73: * For simplicity (and economy of storage), names longer than 74: * a maximum length of NCHNAMLEN are not cached; they occur 75: * infrequently in any case, and are almost never of interest. 76: * 77: * Upon reaching the last segment of a path, if the reference 78: * is for DELETE, or NOCACHE is set (rewrite), and the 79: * name is located in the cache, it will be dropped. 80: * 81: * Overall outline of namei: 82: * 83: * copy in name 84: * get starting directory 85: * dirloop: 86: * check accessibility of directory 87: * dirloop2: 88: * copy next component of name to ndp->ni_dent 89: * handle degenerate case where name is null string 90: * look for name in cache, if found, then if at end of path 91: * and deleting or creating, drop it, else to haveino 92: * search for name in directory, to found or notfound 93: * notfound: 94: * if creating, return locked directory, leaving info on avail. slots 95: * else return error 96: * found: 97: * if at end of path and deleting, return information to allow delete 98: * if at end of path and rewriting (CREATE and LOCKPARENT), lock target 99: * inode and return info to allow rewrite 100: * if .. and on mounted filesys, look in mount table for parent 101: * if not at end, add name to cache; if at end and neither creating 102: * nor deleting, add name to cache 103: * haveino: 104: * if symbolic link, massage name in buffer and continue at dirloop 105: * if more components of name, do next level at dirloop 106: * return the answer as locked inode 107: * 108: * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode, 109: * but unlocked. 110: */ 111: struct inode * 112: namei(ndp) 113: register struct nameidata *ndp; 114: { 115: register char *cp; /* pointer into pathname argument */ 116: /* these variables refer to things which must be freed or unlocked */ 117: struct inode *dp = 0; /* the directory we are searching */ 118: struct namecache *ncp; /* cache slot for entry */ 119: struct fs *fs; /* file system that directory is in */ 120: struct buf *bp = 0; /* a buffer of directory entries */ 121: struct direct *ep; /* the current directory entry */ 122: int entryoffsetinblock; /* offset of ep in bp's buffer */ 123: /* these variables hold information about the search for a slot */ 124: enum {NONE, COMPACT, FOUND} slotstatus; 125: off_t slotoffset = -1; /* offset of area with free space */ 126: int slotsize; /* size of area at slotoffset */ 127: int slotfreespace; /* amount of space free in slot */ 128: int slotneeded; /* size of the entry we're seeking */ 129: /* */ 130: int numdirpasses; /* strategy for directory search */ 131: off_t endsearch; /* offset to end directory search */ 132: off_t prevoff; /* ndp->ni_offset of previous entry */ 133: int nlink = 0; /* number of symbolic links taken */ 134: struct inode *pdp; /* saved dp during symlink work */ 135: register int i; 136: int error; 137: int lockparent; 138: int docache; /* == 0 do not cache last component */ 139: int makeentry; /* != 0 if name to be added to cache */ 140: unsigned hash; /* value of name hash for entry */ 141: union nchash *nhp; /* cache chain head for entry */ 142: int isdotdot; /* != 0 if current name is ".." */ 143: int flag; /* op ie, LOOKUP, CREATE, or DELETE */ 144: off_t enduseful; /* pointer past last used dir slot */ 145: char path[MAXPATHLEN]; /* current path */ 146: segm seg5; /* save area for kernel seg5 */ 147: 148: lockparent = ndp->ni_nameiop & LOCKPARENT; 149: docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 150: flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW); 151: if (flag == DELETE || lockparent) 152: docache = 0; 153: /* 154: * Copy the name into the buffer. 155: */ 156: if (ndp->ni_segflg == UIO_SYSSPACE) 157: error = copystr(ndp->ni_dirp, path, MAXPATHLEN, 158: (u_int *)0); 159: else 160: error = copyinstr(ndp->ni_dirp, path, MAXPATHLEN, 161: (u_int *)0); 162: if (error) { 163: u.u_error = error; 164: goto retNULL; 165: } 166: 167: /* 168: * Get starting directory. 169: */ 170: cp = path; 171: if (*cp == '/') { 172: while (*cp == '/') 173: cp++; 174: if ((dp = u.u_rdir) == NULL) 175: dp = rootdir; 176: } else 177: dp = u.u_cdir; 178: fs = dp->i_fs; 179: ILOCK(dp); 180: dp->i_count++; 181: ndp->ni_endoff = 0; 182: 183: /* 184: * We come to dirloop to search a new directory. 185: * The directory must be locked so that it can be 186: * iput, and fs must be already set to dp->i_fs. 187: */ 188: dirloop: 189: /* 190: * Check accessibility of directory. 191: */ 192: if ((dp->i_mode&IFMT) != IFDIR) { 193: u.u_error = ENOTDIR; 194: goto bad; 195: } 196: if (access(dp, IEXEC)) 197: goto bad; 198: 199: dirloop2: 200: /* 201: * Copy next component of name to ndp->ni_dent. 202: */ 203: hash = 0; 204: for (i = 0; *cp != 0 && *cp != '/'; cp++) { 205: if (i >= MAXNAMLEN) { 206: u.u_error = ENAMETOOLONG; 207: goto bad; 208: } 209: if (*cp & 0200) 210: if ((*cp&0377) == ('/'|0200) || flag != DELETE) { 211: u.u_error = EINVAL; 212: goto bad; 213: } 214: ndp->ni_dent.d_name[i++] = *cp; 215: hash += (unsigned char)*cp * i; 216: } 217: ndp->ni_dent.d_namlen = i; 218: ndp->ni_dent.d_name[i] = '\0'; 219: isdotdot = (i == 2 && 220: ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.'); 221: makeentry = 1; 222: if (*cp == '\0' && docache == 0) 223: makeentry = 0; 224: 225: /* 226: * Check for degenerate name (e.g. / or "") 227: * which is a way of talking about a directory, 228: * e.g. like "/." or ".". 229: */ 230: if (ndp->ni_dent.d_name[0] == '\0') { 231: if (flag != LOOKUP || lockparent) { 232: u.u_error = EISDIR; 233: goto bad; 234: } 235: goto retDP; 236: } 237: 238: /* 239: * We now have a segment name to search for, and a directory to search. 240: * 241: * Before tediously performing a linear scan of the directory, 242: * check the name cache to see if the directory/name pair 243: * we are looking for is known already. We don't do this 244: * if the segment name is long, simply so the cache can avoid 245: * holding long names (which would either waste space, or 246: * add greatly to the complexity). 247: */ 248: saveseg5(seg5); 249: mapseg5(nmidesc.se_addr, nmidesc.se_desc); 250: if (ndp->ni_dent.d_namlen > NCHNAMLEN) { 251: nchstats.ncs_long++; 252: makeentry = 0; 253: } else { 254: nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)]; 255: for (ncp = nhp->nch_forw; ncp != (struct namecache *)nhp; 256: ncp = ncp->nc_forw) { 257: if (ncp->nc_ino == dp->i_number && 258: ncp->nc_dev == dp->i_dev && 259: ncp->nc_nlen == ndp->ni_dent.d_namlen && 260: !bcmp(ncp->nc_name, ndp->ni_dent.d_name, 261: (unsigned)ncp->nc_nlen)) 262: break; 263: } 264: if (ncp == (struct namecache *)nhp) { 265: nchstats.ncs_miss++; 266: ncp = NULL; 267: } else { 268: if (ncp->nc_id != ncp->nc_ip->i_id) 269: nchstats.ncs_falsehits++; 270: else if (!makeentry) 271: nchstats.ncs_badhits++; 272: else { 273: /* 274: * move this slot to end of LRU 275: * chain, if not already there 276: */ 277: if (ncp->nc_nxt) { 278: /* remove from LRU chain */ 279: *ncp->nc_prev = ncp->nc_nxt; 280: ncp->nc_nxt->nc_prev = ncp->nc_prev; 281: 282: /* and replace at end of it */ 283: ncp->nc_nxt = NULL; 284: ncp->nc_prev = nchtail; 285: *nchtail = ncp; 286: nchtail = &ncp->nc_nxt; 287: } 288: 289: /* 290: * Get the next inode in the path. 291: * See comment above other `IUNLOCK' code for 292: * an explaination of the locking protocol. 293: */ 294: pdp = dp; 295: if (!isdotdot || dp != u.u_rdir) 296: dp = ncp->nc_ip; 297: if (dp == NULL) 298: panic("namei: null cache ino"); 299: if (pdp == dp) 300: dp->i_count++; 301: else if (isdotdot) { 302: restorseg5(seg5); 303: IUNLOCK(pdp); 304: igrab(dp); 305: mapseg5(nmidesc.se_addr,nmidesc.se_desc); 306: } else { 307: restorseg5(seg5); 308: igrab(dp); 309: IUNLOCK(pdp); 310: mapseg5(nmidesc.se_addr,nmidesc.se_desc); 311: } 312: 313: /* 314: * Verify that the inode that we got 315: * did not change while we were waiting 316: * for it to be locked. 317: */ 318: if (ncp->nc_id != ncp->nc_ip->i_id) { 319: restorseg5(seg5); 320: iput(dp); 321: ILOCK(pdp); 322: mapseg5(nmidesc.se_addr,nmidesc.se_desc); 323: dp = pdp; 324: nchstats.ncs_falsehits++; 325: } else { 326: ndp->ni_dent.d_ino = dp->i_number; 327: /* ni_dent.d_reclen is garbage ... */ 328: nchstats.ncs_goodhits++; 329: restorseg5(seg5); 330: goto haveino; 331: } 332: } 333: 334: /* 335: * Last component and we are renaming or deleting, 336: * the cache entry is invalid, or otherwise don't 337: * want cache entry to exist. 338: */ 339: /* remove from LRU chain */ 340: *ncp->nc_prev = ncp->nc_nxt; 341: if (ncp->nc_nxt) 342: ncp->nc_nxt->nc_prev = ncp->nc_prev; 343: else 344: nchtail = ncp->nc_prev; 345: remque(ncp); /* remove from hash chain */ 346: /* insert at head of LRU list (first to grab) */ 347: ncp->nc_nxt = nchhead; 348: ncp->nc_prev = &nchhead; 349: nchhead->nc_prev = &ncp->nc_nxt; 350: nchhead = ncp; 351: /* and make a dummy hash chain */ 352: ncp->nc_forw = ncp; 353: ncp->nc_back = ncp; 354: ncp = NULL; 355: } 356: } 357: restorseg5(seg5); 358: 359: /* 360: * Suppress search for slots unless creating 361: * file and at end of pathname, in which case 362: * we watch for a place to put the new file in 363: * case it doesn't already exist. 364: */ 365: slotstatus = FOUND; 366: if (flag == CREATE && *cp == 0) { 367: slotstatus = NONE; 368: slotfreespace = 0; 369: slotneeded = DIRSIZ(&ndp->ni_dent); 370: } 371: /* 372: * If this is the same directory that this process 373: * previously searched, pick up where we last left off. 374: * We cache only lookups as these are the most common 375: * and have the greatest payoff. Caching CREATE has little 376: * benefit as it usually must search the entire directory 377: * to determine that the entry does not exist. Caching the 378: * location of the last DELETE has not reduced profiling time 379: * and hence has been removed in the interest of simplicity. 380: */ 381: if (flag != LOOKUP || dp->i_number != u.u_ncache.nc_inumber || 382: dp->i_dev != u.u_ncache.nc_dev) { 383: ndp->ni_offset = 0; 384: numdirpasses = 1; 385: } else { 386: if (u.u_ncache.nc_prevoffset > dp->i_size) 387: u.u_ncache.nc_prevoffset = 0; 388: ndp->ni_offset = u.u_ncache.nc_prevoffset; 389: entryoffsetinblock = blkoff(ndp->ni_offset); 390: if (entryoffsetinblock != 0) { 391: bp = blkatoff(dp, ndp->ni_offset, (char **)0); 392: if (bp == 0) 393: goto bad; 394: } 395: numdirpasses = 2; 396: nchstats.ncs_2passes++; 397: } 398: endsearch = roundup(dp->i_size, DIRBLKSIZ); 399: enduseful = 0; 400: 401: searchloop: 402: while (ndp->ni_offset < endsearch) { 403: /* 404: * If offset is on a block boundary, 405: * read the next directory block. 406: * Release previous if it exists. 407: */ 408: if (blkoff(ndp->ni_offset) == 0) { 409: if (bp != NULL) { 410: mapout(bp); 411: brelse(bp); 412: } 413: bp = blkatoff(dp, ndp->ni_offset, (char **)0); 414: if (bp == 0) 415: goto bad; 416: entryoffsetinblock = 0; 417: } 418: /* 419: * If still looking for a slot, and at a DIRBLKSIZE 420: * boundary, have to start looking for free space again. 421: */ 422: if (slotstatus == NONE && 423: (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { 424: slotoffset = -1; 425: slotfreespace = 0; 426: } 427: /* 428: * Get pointer to next entry. 429: * Full validation checks are slow, so we only check 430: * enough to insure forward progress through the 431: * directory. Complete checks can be run by patching 432: * "dirchk" to be true. 433: */ 434: mapout(bp); /* XXX - avoid double mapin */ 435: ep = (struct direct *)((caddr_t)mapin(bp)+ entryoffsetinblock); 436: if (ep->d_reclen == 0 || 437: dirchk && dirbadentry(ep, entryoffsetinblock)) { 438: dirbad(dp, ndp->ni_offset, "mangled entry"); 439: i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 440: ndp->ni_offset += i; 441: entryoffsetinblock += i; 442: continue; 443: } 444: 445: /* 446: * If an appropriate sized slot has not yet been found, 447: * check to see if one is available. Also accumulate space 448: * in the current block so that we can determine if 449: * compaction is viable. 450: */ 451: if (slotstatus != FOUND) { 452: int size = ep->d_reclen; 453: 454: if (ep->d_ino != 0) 455: size -= DIRSIZ(ep); 456: if (size > 0) { 457: if (size >= slotneeded) { 458: slotstatus = FOUND; 459: slotoffset = ndp->ni_offset; 460: slotsize = ep->d_reclen; 461: } else if (slotstatus == NONE) { 462: slotfreespace += size; 463: if (slotoffset == -1) 464: slotoffset = ndp->ni_offset; 465: if (slotfreespace >= slotneeded) { 466: slotstatus = COMPACT; 467: slotsize = ndp->ni_offset + 468: ep->d_reclen - slotoffset; 469: } 470: } 471: } 472: } 473: 474: /* 475: * Check for a name match. 476: */ 477: if (ep->d_ino) { 478: if (ep->d_namlen == ndp->ni_dent.d_namlen && 479: !bcmp(ndp->ni_dent.d_name, ep->d_name, 480: (unsigned)ep->d_namlen)) 481: goto found; 482: } 483: prevoff = ndp->ni_offset; 484: ndp->ni_offset += ep->d_reclen; 485: entryoffsetinblock += ep->d_reclen; 486: if (ep->d_ino) 487: enduseful = ndp->ni_offset; 488: } 489: /* notfound: */ 490: /* 491: * If we started in the middle of the directory and failed 492: * to find our target, we must check the beginning as well. 493: */ 494: if (numdirpasses == 2) { 495: numdirpasses--; 496: ndp->ni_offset = 0; 497: endsearch = u.u_ncache.nc_prevoffset; 498: goto searchloop; 499: } 500: /* 501: * If creating, and at end of pathname and current 502: * directory has not been removed, then can consider 503: * allowing file to be created. 504: */ 505: if (flag == CREATE && *cp == 0 && dp->i_nlink != 0) { 506: /* 507: * Access for write is interpreted as allowing 508: * creation of files in the directory. 509: */ 510: if (access(dp, IWRITE)) 511: goto bad; 512: /* 513: * Return an indication of where the new directory 514: * entry should be put. If we didn't find a slot, 515: * then set ndp->ni_count to 0 indicating that the new 516: * slot belongs at the end of the directory. If we found 517: * a slot, then the new entry can be put in the range 518: * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count) 519: */ 520: if (slotstatus == NONE) { 521: ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ); 522: ndp->ni_count = 0; 523: enduseful = ndp->ni_offset; 524: } else { 525: ndp->ni_offset = slotoffset; 526: ndp->ni_count = slotsize; 527: if (enduseful < slotoffset + slotsize) 528: enduseful = slotoffset + slotsize; 529: } 530: ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ); 531: dp->i_flag |= IUPD|ICHG; 532: if (bp) { 533: mapout(bp); 534: brelse(bp); 535: } 536: /* 537: * We return with the directory locked, so that 538: * the parameters we set up above will still be 539: * valid if we actually decide to do a direnter(). 540: * We return NULL to indicate that the entry doesn't 541: * currently exist, leaving a pointer to the (locked) 542: * directory inode in ndp->ni_pdir. 543: */ 544: ndp->ni_pdir = dp; 545: goto retNULL; 546: } 547: u.u_error = ENOENT; 548: goto bad; 549: found: 550: if (numdirpasses == 2) 551: nchstats.ncs_pass2++; 552: /* 553: * Check that directory length properly reflects presence 554: * of this entry. 555: */ 556: if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) { 557: dirbad(dp, ndp->ni_offset, "i_size too small"); 558: dp->i_size = entryoffsetinblock + DIRSIZ(ep); 559: dp->i_flag |= IUPD|ICHG; 560: } 561: 562: /* 563: * Found component in pathname. 564: * If the final component of path name, save information 565: * in the cache as to where the entry was found. 566: */ 567: if (*cp == '\0' && flag == LOOKUP) { 568: u.u_ncache.nc_prevoffset = ndp->ni_offset &~ (DIRBLKSIZ - 1); 569: u.u_ncache.nc_inumber = dp->i_number; 570: u.u_ncache.nc_dev = dp->i_dev; 571: } 572: /* 573: * Save directory entry's inode number and reclen in ndp->ni_dent, 574: * and release directory buffer. 575: */ 576: ndp->ni_dent.d_ino = ep->d_ino; 577: ndp->ni_dent.d_reclen = ep->d_reclen; 578: mapout(bp); 579: brelse(bp); 580: bp = NULL; 581: 582: /* 583: * If deleting, and at end of pathname, return 584: * parameters which can be used to remove file. 585: * If the lockparent flag isn't set, we return only 586: * the directory (in ndp->ni_pdir), otherwise we go 587: * on and lock the inode, being careful with ".". 588: */ 589: if (flag == DELETE && *cp == 0) { 590: /* 591: * Write access to directory required to delete files. 592: */ 593: if (access(dp, IWRITE)) 594: goto bad; 595: ndp->ni_pdir = dp; /* for dirremove() */ 596: /* 597: * Return pointer to current entry in ndp->ni_offset, 598: * and distance past previous entry (if there 599: * is a previous entry in this block) in ndp->ni_count. 600: * Save directory inode pointer in ndp->ni_pdir for dirremove(). 601: */ 602: if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0) 603: ndp->ni_count = 0; 604: else 605: ndp->ni_count = ndp->ni_offset - prevoff; 606: if (lockparent) { 607: if (dp->i_number == ndp->ni_dent.d_ino) 608: dp->i_count++; 609: else { 610: dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 611: if (dp == NULL) { 612: iput(ndp->ni_pdir); 613: goto bad; 614: } 615: /* 616: * If directory is "sticky", then user must own 617: * the directory, or the file in it, else he 618: * may not delete it (unless he's root). This 619: * implements append-only directories. 620: */ 621: if ((ndp->ni_pdir->i_mode & ISVTX) && 622: u.u_uid != 0 && 623: u.u_uid != ndp->ni_pdir->i_uid && 624: dp->i_uid != u.u_uid) { 625: iput(ndp->ni_pdir); 626: u.u_error = EPERM; 627: goto bad; 628: } 629: } 630: } 631: goto retDP; 632: } 633: 634: /* 635: * Special handling for ".." allowing chdir out of mounted 636: * file system: indirect .. in root inode to reevaluate 637: * in directory file system was mounted on. 638: */ 639: if (isdotdot) { 640: if (dp == u.u_rdir) { 641: ndp->ni_dent.d_ino = dp->i_number; 642: makeentry = 0; 643: } else if (ndp->ni_dent.d_ino == ROOTINO && 644: dp->i_number == ROOTINO) { 645: register struct mount *mp; 646: register dev_t d; 647: 648: d = dp->i_dev; 649: for (mp = &mount[1]; mp < &mount[NMOUNT]; mp++) 650: if (mp->m_inodp && mp->m_dev == d) { 651: iput(dp); 652: dp = mp->m_inodp; 653: ILOCK(dp); 654: dp->i_count++; 655: fs = dp->i_fs; 656: cp -= 2; /* back over .. */ 657: goto dirloop2; 658: } 659: } 660: } 661: 662: /* 663: * If rewriting (rename), return the inode and the 664: * information required to rewrite the present directory 665: * Must get inode of directory entry to verify it's a 666: * regular file, or empty directory. 667: */ 668: if ((flag == CREATE && lockparent) && *cp == 0) { 669: if (access(dp, IWRITE)) 670: goto bad; 671: ndp->ni_pdir = dp; /* for dirrewrite() */ 672: /* 673: * Careful about locking second inode. 674: * This can only occur if the target is ".". 675: */ 676: if (dp->i_number == ndp->ni_dent.d_ino) { 677: u.u_error = EISDIR; /* XXX */ 678: goto bad; 679: } 680: dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 681: if (dp == NULL) { 682: iput(ndp->ni_pdir); 683: goto bad; 684: } 685: goto retDP; 686: } 687: 688: /* 689: * Check for symbolic link, which may require us to massage the 690: * name before we continue translation. We do not `iput' the 691: * directory because we may need it again if the symbolic link 692: * is relative to the current directory. Instead we save it 693: * unlocked as "pdp". We must get the target inode before unlocking 694: * the directory to insure that the inode will not be removed 695: * before we get it. We prevent deadlock by always fetching 696: * inodes from the root, moving down the directory tree. Thus 697: * when following backward pointers ".." we must unlock the 698: * parent directory before getting the requested directory. 699: * There is a potential race condition here if both the current 700: * and parent directories are removed before the `iget' for the 701: * inode associated with ".." returns. We hope that this occurs 702: * infrequently since we cannot avoid this race condition without 703: * implementing a sophisticated deadlock detection algorithm. 704: * Note also that this simple deadlock detection scheme will not 705: * work if the file system has any hard links other than ".." 706: * that point backwards in the directory structure. 707: */ 708: pdp = dp; 709: if (isdotdot) { 710: IUNLOCK(pdp); /* race to get the inode */ 711: dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 712: if (dp == NULL) 713: goto bad2; 714: } else if (dp->i_number == ndp->ni_dent.d_ino) { 715: dp->i_count++; /* we want ourself, ie "." */ 716: } else { 717: dp = iget(dp->i_dev, fs, ndp->ni_dent.d_ino); 718: IUNLOCK(pdp); 719: if (dp == NULL) 720: goto bad2; 721: } 722: 723: /* 724: * Insert name into cache if appropriate. 725: */ 726: if (makeentry) { 727: if (ncp != NULL) 728: panic("namei: duplicating cache"); 729: /* 730: * Free the cache slot at head of lru chain. 731: */ 732: if (ncp = nchhead) { 733: saveseg5(seg5); 734: mapseg5(nmidesc.se_addr, nmidesc.se_desc); 735: /* remove from lru chain */ 736: *ncp->nc_prev = ncp->nc_nxt; 737: if (ncp->nc_nxt) 738: ncp->nc_nxt->nc_prev = ncp->nc_prev; 739: else 740: nchtail = ncp->nc_prev; 741: remque(ncp); /* remove from old hash chain */ 742: /* grab the inode we just found */ 743: ncp->nc_ip = dp; 744: /* fill in cache info */ 745: ncp->nc_ino = pdp->i_number; /* parents inum */ 746: ncp->nc_dev = pdp->i_dev; /* & device */ 747: ncp->nc_idev = dp->i_dev; /* our device */ 748: ncp->nc_id = dp->i_id; /* identifier */ 749: ncp->nc_nlen = ndp->ni_dent.d_namlen; 750: bcopy(ndp->ni_dent.d_name, ncp->nc_name, 751: (unsigned)ncp->nc_nlen); 752: /* link at end of lru chain */ 753: ncp->nc_nxt = NULL; 754: ncp->nc_prev = nchtail; 755: *nchtail = ncp; 756: nchtail = &ncp->nc_nxt; 757: /* and insert on hash chain */ 758: insque(ncp, nhp); 759: restorseg5(seg5); 760: } 761: } 762: 763: haveino: 764: fs = dp->i_fs; 765: 766: /* 767: * Check for symbolic link 768: */ 769: if ((dp->i_mode & IFMT) == IFLNK && 770: ((ndp->ni_nameiop & FOLLOW) || *cp == '/')) { 771: u_int pathlen = strlen(cp) + 1; 772: 773: if (dp->i_size + pathlen >= MAXPATHLEN - 1) { 774: u.u_error = ENAMETOOLONG; 775: goto bad2; 776: } 777: if (++nlink > MAXSYMLINKS) { 778: u.u_error = ELOOP; 779: goto bad2; 780: } 781: 782: bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ, 0)); 783: if (bp->b_flags & B_ERROR) { 784: brelse(bp); 785: bp = NULL; 786: goto bad2; 787: } 788: /* 789: * Shift the rest of path further down the buffer, then 790: * copy link path into the first part of the buffer. 791: */ 792: bcopy(cp, path + (u_int)dp->i_size, pathlen); 793: bcopy(mapin(bp), path, (u_int)dp->i_size); 794: mapout(bp); 795: brelse(bp); 796: bp = NULL; 797: cp = path; 798: iput(dp); 799: if (*cp == '/') { 800: irele(pdp); 801: while (*cp == '/') 802: cp++; 803: if ((dp = u.u_rdir) == NULL) 804: dp = rootdir; 805: ILOCK(dp); 806: dp->i_count++; 807: } else { 808: dp = pdp; 809: ILOCK(dp); 810: } 811: fs = dp->i_fs; 812: goto dirloop; 813: } 814: 815: /* 816: * Not a symbolic link. If more pathname, 817: * continue at next component, else return. 818: */ 819: if (*cp == '/') { 820: while (*cp == '/') 821: cp++; 822: irele(pdp); 823: goto dirloop; 824: } 825: if (lockparent) 826: ndp->ni_pdir = pdp; 827: else 828: irele(pdp); 829: retDP: 830: ndp->ni_ip = dp; 831: return (dp); 832: 833: bad2: 834: irele(pdp); 835: bad: 836: if (bp) { 837: mapout(bp); 838: brelse(bp); 839: } 840: if (dp) 841: iput(dp); 842: retNULL: 843: ndp->ni_ip = NULL; 844: return (NULL); 845: } 846: 847: dirbad(ip, offset, how) 848: struct inode *ip; 849: off_t offset; 850: char *how; 851: { 852: 853: printf("%s: bad dir I=%u off %ld: %s\n", 854: ip->i_fs->fs_fsmnt, ip->i_number, offset, how); 855: } 856: 857: /* 858: * Do consistency checking on a directory entry: 859: * record length must be multiple of 4 860: * entry must fit in rest of its DIRBLKSIZ block 861: * record must be large enough to contain entry 862: * name is not longer than MAXNAMLEN 863: * name must be as long as advertised, and null terminated 864: */ 865: dirbadentry(ep, entryoffsetinblock) 866: register struct direct *ep; 867: int entryoffsetinblock; 868: { 869: register int i; 870: 871: if ((ep->d_reclen & 0x3) != 0 || 872: ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 873: ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN) 874: return (1); 875: for (i = 0; i < ep->d_namlen; i++) 876: if (ep->d_name[i] == '\0') 877: return (1); 878: return (ep->d_name[i]); 879: } 880: 881: /* 882: * Write a directory entry after a call to namei, using the parameters 883: * which it left in the u. area. The argument ip is the inode which 884: * the new directory entry will refer to. The u. area field ndp->ni_pdir is 885: * a pointer to the directory to be written, which was left locked by 886: * namei. Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate 887: * how the space for the new entry is to be gotten. 888: */ 889: direnter(ip, ndp) 890: struct inode *ip; 891: register struct nameidata *ndp; 892: { 893: register struct direct *ep, *nep; 894: register struct inode *dp = ndp->ni_pdir; 895: struct buf *bp; 896: int loc, spacefree, error = 0; 897: u_int dsize; 898: int newentrysize; 899: char *dirbuf; 900: 901: ndp->ni_dent.d_ino = ip->i_number; 902: newentrysize = DIRSIZ(&ndp->ni_dent); 903: if (ndp->ni_count == 0) { 904: /* 905: * If ndp->ni_count is 0, then namei could find no space in the 906: * directory. In this case ndp->ni_offset will be on a directory 907: * block boundary and we will write the new entry into a fresh 908: * block. 909: */ 910: if (ndp->ni_offset&(DIRBLKSIZ-1)) 911: panic("wdir: newblk"); 912: ndp->ni_dent.d_reclen = DIRBLKSIZ; 913: error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 914: newentrysize, ndp->ni_offset, UIO_SYSSPACE, 915: IO_UNIT|IO_SYNC, (int *)0); 916: dp->i_size = roundup(dp->i_size, DIRBLKSIZ); 917: iput(dp); 918: return (error); 919: } 920: 921: /* 922: * If ndp->ni_count is non-zero, then namei found space for the new 923: * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count. 924: * in the directory. To use this space, we may have to compact 925: * the entries located there, by copying them together towards 926: * the beginning of the block, leaving the free space in 927: * one usable chunk at the end. 928: */ 929: 930: /* 931: * Increase size of directory if entry eats into new space. 932: * This should never push the size past a new multiple of 933: * DIRBLKSIZE. 934: * 935: * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 936: */ 937: if (ndp->ni_offset + ndp->ni_count > dp->i_size) 938: dp->i_size = ndp->ni_offset + ndp->ni_count; 939: /* 940: * Get the block containing the space for the new directory 941: * entry. Should return error by result instead of u.u_error. 942: */ 943: bp = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf); 944: if (bp == 0) { 945: iput(dp); 946: return (u.u_error); 947: } 948: /* 949: * Find space for the new entry. In the simple case, the 950: * entry at offset base will have the space. If it does 951: * not, then namei arranged that compacting the region 952: * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space. 953: */ 954: ep = (struct direct *)dirbuf; 955: dsize = DIRSIZ(ep); 956: spacefree = ep->d_reclen - dsize; 957: for (loc = ep->d_reclen; loc < ndp->ni_count; ) { 958: nep = (struct direct *)(dirbuf + loc); 959: if (ep->d_ino) { 960: /* trim the existing slot */ 961: ep->d_reclen = dsize; 962: ep = (struct direct *)((char *)ep + dsize); 963: } else { 964: /* overwrite; nothing there; header is ours */ 965: spacefree += dsize; 966: } 967: dsize = DIRSIZ(nep); 968: spacefree += nep->d_reclen - dsize; 969: loc += nep->d_reclen; 970: bcopy((caddr_t)nep, (caddr_t)ep, dsize); 971: } 972: /* 973: * Update the pointer fields in the previous entry (if any), 974: * copy in the new entry, and write out the block. 975: */ 976: if (ep->d_ino == 0) { 977: if (spacefree + dsize < newentrysize) 978: panic("wdir: compact1"); 979: ndp->ni_dent.d_reclen = spacefree + dsize; 980: } else { 981: if (spacefree < newentrysize) 982: panic("wdir: compact2"); 983: ndp->ni_dent.d_reclen = spacefree; 984: ep->d_reclen = dsize; 985: ep = (struct direct *)((char *)ep + dsize); 986: } 987: bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize); 988: mapout(bp); 989: bwrite(bp); 990: dp->i_flag |= IUPD|ICHG; 991: if (ndp->ni_endoff && ndp->ni_endoff < dp->i_size) 992: itrunc(dp, (u_long)ndp->ni_endoff, 0); 993: iput(dp); 994: return (error); 995: } 996: 997: /* 998: * Remove a directory entry after a call to namei, using the 999: * parameters which it left in the u. area. The u. entry 1000: * ni_offset contains the offset into the directory of the 1001: * entry to be eliminated. The ni_count field contains the 1002: * size of the previous record in the directory. If this 1003: * is 0, the first entry is being deleted, so we need only 1004: * zero the inode number to mark the entry as free. If the 1005: * entry isn't the first in the directory, we must reclaim 1006: * the space of the now empty record by adding the record size 1007: * to the size of the previous entry. 1008: */ 1009: dirremove(ndp) 1010: register struct nameidata *ndp; 1011: { 1012: register struct inode *dp = ndp->ni_pdir; 1013: register struct buf *bp; 1014: struct direct *ep; 1015: 1016: if (ndp->ni_count == 0) { 1017: /* 1018: * First entry in block: set d_ino to zero. 1019: */ 1020: ndp->ni_dent.d_ino = 0; 1021: (void) rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 1022: (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1023: UIO_SYSSPACE, IO_UNIT|IO_SYNC, (int *)0); 1024: } else { 1025: /* 1026: * Collapse new free space into previous entry. 1027: */ 1028: bp = blkatoff(dp, ndp->ni_offset - ndp->ni_count, (char **)&ep); 1029: if (bp == 0) 1030: return (0); 1031: ep->d_reclen += ndp->ni_dent.d_reclen; 1032: mapout(bp); 1033: bwrite(bp); 1034: dp->i_flag |= IUPD|ICHG; 1035: } 1036: return (1); 1037: } 1038: 1039: /* 1040: * Rewrite an existing directory entry to point at the inode 1041: * supplied. The parameters describing the directory entry are 1042: * set up by a call to namei. 1043: */ 1044: dirrewrite(dp, ip, ndp) 1045: register struct inode *dp; 1046: struct inode *ip; 1047: register struct nameidata *ndp; 1048: { 1049: 1050: ndp->ni_dent.d_ino = ip->i_number; 1051: u.u_error = rdwri(UIO_WRITE, dp, (caddr_t)&ndp->ni_dent, 1052: (int)DIRSIZ(&ndp->ni_dent), ndp->ni_offset, 1053: UIO_SYSSPACE, IO_UNIT|IO_SYNC, (int *)0); 1054: iput(dp); 1055: } 1056: 1057: /* 1058: * Return buffer with contents of block "offset" 1059: * from the beginning of directory "ip". If "res" 1060: * is non-zero, fill it in with a pointer to the 1061: * remaining space in the directory. 1062: * 1063: * A mapin() of the buffer is done even if "res" is zero so that the 1064: * mapout() done later will have something to work with. 1065: */ 1066: struct buf * 1067: blkatoff(ip, offset, res) 1068: struct inode *ip; 1069: off_t offset; 1070: char **res; 1071: { 1072: register struct fs *fs = ip->i_fs; 1073: daddr_t lbn = lblkno(offset); 1074: register struct buf *bp; 1075: daddr_t bn; 1076: char *junk; 1077: 1078: bn = bmap(ip, lbn, B_READ, 0); 1079: if (u.u_error) 1080: return (0); 1081: if (bn == (daddr_t)-1) { 1082: dirbad(ip, offset, "hole in dir"); 1083: return (0); 1084: } 1085: bp = bread(ip->i_dev, bn); 1086: if (bp->b_flags & B_ERROR) { 1087: brelse(bp); 1088: return (0); 1089: } 1090: junk = (caddr_t)mapin(bp); 1091: if (res) 1092: *res = junk + (u_int)blkoff(offset); 1093: return (bp); 1094: } 1095: 1096: /* 1097: * Check if a directory is empty or not. 1098: * Inode supplied must be locked. 1099: * 1100: * Using a struct dirtemplate here is not precisely 1101: * what we want, but better than using a struct direct. 1102: * 1103: * NB: does not handle corrupted directories. 1104: */ 1105: dirempty(ip, parentino) 1106: register struct inode *ip; 1107: ino_t parentino; 1108: { 1109: register off_t off; 1110: struct dirtemplate dbuf; 1111: register struct direct *dp = (struct direct *)&dbuf; 1112: int error, count; 1113: #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 1114: 1115: for (off = 0; off < ip->i_size; off += dp->d_reclen) { 1116: error = rdwri(UIO_READ, ip, (caddr_t)dp, MINDIRSIZ, 1117: off, UIO_SYSSPACE, IO_UNIT, &count); 1118: /* 1119: * Since we read MINDIRSIZ, residual must 1120: * be 0 unless we're at end of file. 1121: */ 1122: if (error || count != 0) 1123: return (0); 1124: /* avoid infinite loops */ 1125: if (dp->d_reclen == 0) 1126: return (0); 1127: /* skip empty entries */ 1128: if (dp->d_ino == 0) 1129: continue; 1130: /* accept only "." and ".." */ 1131: if (dp->d_namlen > 2) 1132: return (0); 1133: if (dp->d_name[0] != '.') 1134: return (0); 1135: /* 1136: * At this point d_namlen must be 1 or 2. 1137: * 1 implies ".", 2 implies ".." if second 1138: * char is also "." 1139: */ 1140: if (dp->d_namlen == 1) 1141: continue; 1142: if (dp->d_name[1] == '.' && dp->d_ino == parentino) 1143: continue; 1144: return (0); 1145: } 1146: return (1); 1147: } 1148: 1149: /* 1150: * Check if source directory is in the path of the target directory. 1151: * Target is supplied locked, source is unlocked. 1152: * The target is always iput() before returning. 1153: */ 1154: checkpath(source, target) 1155: struct inode *source, *target; 1156: { 1157: struct dirtemplate dirbuf; 1158: register struct inode *ip; 1159: register int error = 0; 1160: 1161: ip = target; 1162: if (ip->i_number == source->i_number) { 1163: error = EEXIST; 1164: goto out; 1165: } 1166: if (ip->i_number == ROOTINO) 1167: goto out; 1168: 1169: for (;;) { 1170: if ((ip->i_mode&IFMT) != IFDIR) { 1171: error = ENOTDIR; 1172: break; 1173: } 1174: error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 1175: sizeof(struct dirtemplate), (off_t)0, 1176: UIO_SYSSPACE, IO_UNIT, (int *)0); 1177: if (error != 0) 1178: break; 1179: if (dirbuf.dotdot_namlen != 2 || 1180: dirbuf.dotdot_name[0] != '.' || 1181: dirbuf.dotdot_name[1] != '.') { 1182: error = ENOTDIR; 1183: break; 1184: } 1185: if (dirbuf.dotdot_ino == source->i_number) { 1186: error = EINVAL; 1187: break; 1188: } 1189: if (dirbuf.dotdot_ino == ROOTINO) 1190: break; 1191: iput(ip); 1192: ip = iget(ip->i_dev, ip->i_fs, dirbuf.dotdot_ino); 1193: if (ip == NULL) { 1194: error = u.u_error; 1195: break; 1196: } 1197: } 1198: 1199: out: 1200: if (error == ENOTDIR) 1201: printf("checkpath: .. !dir\n"); 1202: if (ip != NULL) 1203: iput(ip); 1204: return (error); 1205: } 1206: 1207: /* 1208: * Name cache initialization, from main() when we are booting 1209: */ 1210: nchinit() 1211: { 1212: register union nchash *nchp; 1213: register struct namecache *ncp; 1214: segm seg5; 1215: 1216: saveseg5(seg5); 1217: mapseg5(nmidesc.se_addr,nmidesc.se_desc); 1218: nchhead = 0; 1219: nchtail = &nchhead; 1220: for (ncp = namecache; ncp < &namecache[nchsize]; ncp++) { 1221: ncp->nc_forw = ncp; /* hash chain */ 1222: ncp->nc_back = ncp; 1223: ncp->nc_nxt = NULL; /* lru chain */ 1224: *nchtail = ncp; 1225: ncp->nc_prev = nchtail; 1226: nchtail = &ncp->nc_nxt; 1227: /* all else is zero already */ 1228: } 1229: for (nchp = nchash; nchp < &nchash[NCHHASH]; nchp++) { 1230: nchp->nch_head[0] = nchp; 1231: nchp->nch_head[1] = nchp; 1232: } 1233: restorseg5(seg5); 1234: } 1235: 1236: /* 1237: * Cache flush, called when filesys is umounted to 1238: * remove entries that would now be invalid 1239: * 1240: * The line "nxtcp = nchhead" near the end is to avoid potential problems 1241: * if the cache lru chain is modified while we are dumping the 1242: * inode. This makes the algorithm O(n^2), but do you think I care? 1243: */ 1244: nchinval(dev) 1245: register dev_t dev; 1246: { 1247: register struct namecache *ncp, *nxtcp; 1248: segm seg5; 1249: 1250: saveseg5(seg5); 1251: mapseg5(nmidesc.se_addr,nmidesc.se_desc); 1252: for (ncp = nchhead; ncp; ncp = nxtcp) { 1253: nxtcp = ncp->nc_nxt; 1254: if (ncp->nc_ip == NULL || 1255: (ncp->nc_idev != dev && ncp->nc_dev != dev)) 1256: continue; 1257: /* free the resources we had */ 1258: ncp->nc_idev = NODEV; 1259: ncp->nc_dev = NODEV; 1260: ncp->nc_id = NULL; 1261: ncp->nc_ino = 0; 1262: ncp->nc_ip = NULL; 1263: remque(ncp); /* remove entry from its hash chain */ 1264: ncp->nc_forw = ncp; /* and make a dummy one */ 1265: ncp->nc_back = ncp; 1266: /* delete this entry from LRU chain */ 1267: *ncp->nc_prev = nxtcp; 1268: if (nxtcp) 1269: nxtcp->nc_prev = ncp->nc_prev; 1270: else 1271: nchtail = ncp->nc_prev; 1272: /* cause rescan of list, it may have altered */ 1273: nxtcp = nchhead; 1274: /* put the now-free entry at head of LRU */ 1275: ncp->nc_nxt = nxtcp; 1276: ncp->nc_prev = &nchhead; 1277: nxtcp->nc_prev = &ncp->nc_nxt; 1278: nchhead = ncp; 1279: } 1280: restorseg5(seg5); 1281: } 1282: 1283: /* 1284: * Name cache invalidation of all entries. 1285: */ 1286: cacheinvalall() 1287: { 1288: register struct namecache *ncp, *encp = &namecache[nchsize]; 1289: segm seg5; 1290: 1291: saveseg5(seg5); 1292: mapseg5(nmidesc.se_addr, nmidesc.se_desc); 1293: for (ncp = namecache; ncp < encp; ncp++) 1294: ncp->nc_id = 0; 1295: restorseg5(seg5); 1296: }