|
|
1.1 ! root 1: /* ! 2: * namei code for fs filesystem ! 3: */ ! 4: ! 5: #include "sys/param.h" ! 6: #include "sys/systm.h" ! 7: #include "sys/inode.h" ! 8: #include "sys/buf.h" ! 9: #include "sys/filsys.h" ! 10: #include "sys/dir.h" ! 11: #include "sys/user.h" ! 12: ! 13: struct dent { ! 14: struct direct dir; ! 15: off_t off; ! 16: int nentry; ! 17: }; ! 18: ! 19: fsnami(p, flagp, follow) ! 20: struct nx *p; ! 21: register struct argnamei *flagp; ! 22: { ! 23: register struct inode *dp; ! 24: register char *cp; ! 25: register struct buf *bp; ! 26: register struct inode *dip; ! 27: register int i; ! 28: struct dent dent; ! 29: struct inode *domkfile(); ! 30: ino_t dsearch(); ! 31: ! 32: cp = p->cp; ! 33: dp = p->dp; ! 34: ! 35: /* ! 36: * dp is the inode to search; cp is the pathname to find. ! 37: * dp must be a directory, with execute permissions. ! 38: * (this test is done too early; it forbids a filesystem ! 39: * consisting of a single file with i-number ROOTINO) ! 40: */ ! 41: dirloop: ! 42: if((dp->i_mode&IFMT) != IFDIR) { ! 43: u.u_error = ENOTDIR; ! 44: goto outnull; ! 45: } ! 46: if (access(dp, IEXEC)) ! 47: goto outnull; ! 48: for (i=0; *cp!='\0' && *cp!='/'; i++) { ! 49: if (i >= DIRSIZ) { ! 50: u.u_error = ENOENT; ! 51: goto outnull; ! 52: } ! 53: dent.dir.d_name[i] = *cp++; ! 54: } ! 55: while (i < DIRSIZ) ! 56: dent.dir.d_name[i++] = '\0'; ! 57: while (*cp == '/') ! 58: cp++; ! 59: if (dent.dir.d_name[0] == '\0') { /* null name, e.g. "/" or "" */ ! 60: if (flagp->flag != NI_SEARCH) { ! 61: u.u_error = ENOENT; ! 62: goto outnull; ! 63: } ! 64: /* ! 65: * should pass NI_CREAT too, but dp is known to be a directory ! 66: */ ! 67: goto out; ! 68: } ! 69: u.u_segflg = SEGSYS; /* for various routines that write directories */ ! 70: if (dsearch(dp, &dent) == 0) { ! 71: if (u.u_error) ! 72: goto outnull; ! 73: /* ! 74: * name not found ! 75: * if we wanted to create or link, that's OK ! 76: */ ! 77: if (*cp == 0) switch (flagp->flag) { ! 78: case NI_CREAT: ! 79: case NI_NXCREAT: ! 80: case NI_MKDIR: ! 81: case NI_LINK: ! 82: dip = dp; ! 83: dp = domkfile(dip, flagp, &dent); ! 84: iput(dip); ! 85: goto out; ! 86: } ! 87: u.u_error = ENOENT; ! 88: goto outnull; ! 89: } ! 90: /* ! 91: * name found ! 92: * did we want to remove it? ! 93: * (do before ".." check) ! 94: */ ! 95: if(flagp->flag == NI_DEL && *cp == 0) { ! 96: dormfile(dp, &dent); ! 97: goto outnull; ! 98: } ! 99: if(flagp->flag == NI_RMDIR && *cp == 0) { ! 100: dormdir(dp, &dent); ! 101: goto outnull; ! 102: } ! 103: /* ! 104: * special code for ".." in a root directory ! 105: */ ! 106: if (dent.dir.d_name[0] == '.' ! 107: && dent.dir.d_name[1] == '.' ! 108: && dent.dir.d_name[2] == '\0') { ! 109: if (dp == rootdir || dp == u.u_rdir) ! 110: goto dirloop; ! 111: if (dent.dir.d_ino == ROOTINO && dp->i_number == ROOTINO) { ! 112: dip = dp->i_mpoint; ! 113: i = dp->i_fstyp; ! 114: iput(dp); ! 115: dp = dip; ! 116: plock(dp); ! 117: dp->i_count++; ! 118: while (*--cp == '/') ! 119: ; ! 120: cp--; /* skip over ".." and / */ ! 121: if (dp->i_fstyp != i) ! 122: goto outmore; ! 123: goto dirloop; ! 124: } ! 125: } ! 126: /* ! 127: * fetch the inode for the filename we found ! 128: */ ! 129: dip = dp; ! 130: prele(dip); ! 131: dp = iget(dip, dip->i_dev, dent.dir.d_ino); ! 132: if (dp == NULL) { ! 133: idec(dip); ! 134: goto out; /* sic */ ! 135: } ! 136: if (dp->i_count == 1 && fsiread(dip, dp) < 0) { ! 137: idec(dip); ! 138: dp = NULL; /* fsiread iput it */ ! 139: goto out; ! 140: } ! 141: if(dip->i_fstyp != dp->i_fstyp) { ! 142: idec(dip); ! 143: goto outmore; ! 144: } ! 145: /* ! 146: * symlink? If so and if wanted, follow. ! 147: */ ! 148: if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp!='\0')) { ! 149: char *ocp; ! 150: ! 151: ocp = cp; ! 152: while (*cp++) ! 153: ; ! 154: i = cp - ocp; /* strlen(ocp) + 1 for NUL */ ! 155: if (dp->i_size > BSIZE(dp->i_dev) ! 156: || dp->i_size + 1 + i > p->nlen /* +1 for '/' */ ! 157: || ++p->nlink>8) { ! 158: u.u_error = ELOOP; ! 159: idec(dip); ! 160: goto outnull; ! 161: } ! 162: cp = p->nbuf; ! 163: if (i == 1) /* empty pathname, just put NUL there */ ! 164: cp[dp->i_size] = 0; ! 165: else { ! 166: bcopy(ocp, cp + dp->i_size + 1, i); /* remaining pathname */ ! 167: cp[dp->i_size] = '/'; ! 168: } ! 169: bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ)); ! 170: if (bp->b_flags & B_ERROR) { ! 171: brelse(bp); ! 172: idec(dip); ! 173: goto outnull; ! 174: } ! 175: bcopy(bp->b_un.b_addr, cp, dp->i_size); /* new prefix */ ! 176: brelse(bp); ! 177: i = dp->i_fstyp; ! 178: iput(dp); ! 179: if (*cp != '/') ! 180: dp = dip; ! 181: else { ! 182: idec(dip); ! 183: while (*cp == '/') ! 184: cp++; ! 185: if ((dp = u.u_rdir) == NULL) ! 186: dp = rootdir; ! 187: plock(dp); ! 188: dp->i_count++; ! 189: } ! 190: if (i != dp->i_fstyp) ! 191: goto outmore; ! 192: goto dirloop; ! 193: } ! 194: idec(dip); ! 195: /* ! 196: * more pathname to walk? ! 197: */ ! 198: if (*cp) ! 199: goto dirloop; ! 200: /* ! 201: * final checks before returning: ! 202: * -- some operations are in error if filename exists ! 203: * -- save last piece of filename for accounting ! 204: */ ! 205: if (flagp->flag == NI_LINK || flagp->flag == NI_NXCREAT ! 206: || flagp->flag == NI_MKDIR) { ! 207: u.u_error = EEXIST; ! 208: goto outnull; ! 209: } ! 210: if(flagp->flag == NI_SEARCH && flagp->un.buf) ! 211: bcopy(dent.dir.d_name, flagp->un.buf, ! 212: MIN(flagp->len, sizeof(dent.dir.d_name))); ! 213: ! 214: /* ! 215: * here to return the inode in dp ! 216: */ ! 217: out: ! 218: p->dp = dp; ! 219: return(0); ! 220: ! 221: /* ! 222: * here to discard dp and return NULL ! 223: */ ! 224: outnull: ! 225: iput(dp); ! 226: p->dp = NULL; ! 227: return (0); ! 228: ! 229: /* ! 230: * here if we crossed into another filesystem's domain: ! 231: * return dp (the first inode in that filesystem) ! 232: * and cp (the remainder of the pathname) ! 233: * and value 1, so namei knows it should continue ! 234: */ ! 235: outmore: ! 236: p->cp = cp; ! 237: p->dp = dp; ! 238: return (1); ! 239: } ! 240: ! 241: /* ! 242: * create a new file of some sort in directory dp ! 243: * name is in dent->d_name ! 244: * offset is in dent->d_off ! 245: * return inode if it is needed ! 246: */ ! 247: struct inode * ! 248: domkfile(dp, flagp, dent) ! 249: register struct inode *dp; ! 250: struct argnamei *flagp; ! 251: struct dent *dent; ! 252: { ! 253: register struct inode *dip; ! 254: struct direct x[2]; ! 255: register i; ! 256: ! 257: if(access(dp, IWRITE)) ! 258: return(NULL); ! 259: if (dp->i_nlink == 0) { ! 260: u.u_error = EINVAL; ! 261: return (NULL); ! 262: } ! 263: u.u_count = sizeof(struct direct); ! 264: u.u_base = (caddr_t)&dent->dir; ! 265: u.u_offset = ltoL(dent->off); ! 266: switch(flagp->flag) { ! 267: ! 268: case NI_CREAT: /* create a new file */ ! 269: case NI_NXCREAT: ! 270: dip = ialloc(dp); ! 271: if(dip == NULL) ! 272: return(NULL); ! 273: dip->i_flag |= IACC|IUPD|ICHG; ! 274: dip->i_mode = flagp->un.mode; ! 275: if((dip->i_mode & IFMT) == 0) ! 276: dip->i_mode |= IFREG; ! 277: dip->i_nlink = 1; ! 278: dip->i_uid = u.u_uid; ! 279: dip->i_gid = dp->i_mode & ISGID ? u.u_gid : dp->i_gid; ! 280: if (u.u_uid && !groupmember(dip->i_gid)) ! 281: dip->i_mode &= ~ISGID; ! 282: fsiupdat(dip, &time, &time, 1); ! 283: dent->dir.d_ino = dip->i_number; ! 284: flagp->un.mode = ~flagp->un.mode; ! 285: writei(dp); ! 286: return(dip); ! 287: ! 288: case NI_MKDIR: /* make a new directory */ ! 289: dip = ialloc(dp); ! 290: if(dip == NULL) ! 291: return(NULL); ! 292: dent->dir.d_ino = dip->i_number; ! 293: dip->i_mode = flagp->un.mode; ! 294: dip->i_nlink = 1; ! 295: dip->i_uid = u.u_uid; ! 296: dip->i_gid = dp->i_gid; ! 297: dip->i_flag |= IACC|IUPD|ICHG; ! 298: x[0].d_ino = dip->i_number; ! 299: x[1].d_ino = dp->i_number; ! 300: for(i = 0; i < DIRSIZ; i++) ! 301: x[0].d_name[i] = x[1].d_name[i] = 0; ! 302: x[0].d_name[0] = x[1].d_name[0] = x[1].d_name[1] = '.'; ! 303: u.u_count = sizeof(x); ! 304: u.u_base = (caddr_t)x; ! 305: u.u_offset = ltoL(0); ! 306: u.u_segflg = SEGSYS; ! 307: writei(dip); ! 308: if (u.u_error) { ! 309: dip->i_nlink--; ! 310: iput(dip); ! 311: return(NULL); ! 312: } ! 313: dip->i_nlink++; ! 314: dp->i_nlink++; ! 315: fsiupdat(dip, &time, &time, 1); ! 316: u.u_count = sizeof(struct direct); ! 317: u.u_base = (caddr_t)&dent->dir; ! 318: u.u_offset = ltoL(dent->off); ! 319: writei(dp); ! 320: iput(dip); ! 321: return(NULL); ! 322: ! 323: case NI_LINK: /* make a link */ ! 324: if(dp->i_dev != flagp->un.il->i_dev) { ! 325: u.u_error = EXDEV; ! 326: return(NULL); ! 327: } ! 328: dent->dir.d_ino = flagp->un.il->i_number; ! 329: writei(dp); ! 330: return(NULL); ! 331: } ! 332: panic("domkfile"); ! 333: } ! 334: ! 335: /* ! 336: * delete a non-directory file ! 337: */ ! 338: dormfile(dp, dent) ! 339: register struct inode *dp; ! 340: register struct dent *dent; ! 341: { ! 342: register struct inode *dip; ! 343: ! 344: if(access(dp, IWRITE)) ! 345: return; ! 346: if(dp->i_number == dent->dir.d_ino) { /* for '.' */ ! 347: dip = dp; ! 348: dp->i_count++; ! 349: } else { ! 350: dip = iget(dp, dp->i_dev, dent->dir.d_ino); ! 351: if (dip == NULL) ! 352: return; ! 353: if (dip->i_count == 1 && fsiread(dp, dip) < 0) ! 354: return; ! 355: } ! 356: if(dip->i_mpoint != dp->i_mpoint) { ! 357: u.u_error = EBUSY; ! 358: iput(dip); ! 359: return; ! 360: } ! 361: if((dip->i_mode&IFMT) == IFDIR && !suser()) { ! 362: iput(dip); ! 363: return; ! 364: } ! 365: if(dip->i_flag&ITEXT) ! 366: xrele(dip); /* free busy text */ ! 367: u.u_base = (caddr_t)&dent->dir; ! 368: u.u_count = sizeof(struct direct); ! 369: u.u_offset = ltoL(dent->off); ! 370: dent->dir.d_ino = 0; ! 371: writei(dp); /* segflg already set*/ ! 372: dip->i_nlink--; ! 373: dip->i_flag |= ICHG; ! 374: iput(dip); ! 375: } ! 376: ! 377: /* ! 378: * remove a directory (fsnami) ! 379: * dp is inode of containing directory ! 380: * dent->dir is the entry (which exists) ! 381: * u.u_offset is the offset in containing directory of this entry ! 382: */ ! 383: dormdir(dp, dent) ! 384: register struct inode *dp; ! 385: register struct dent *dent; ! 386: { ! 387: register struct inode *dip; ! 388: register int nentry; ! 389: struct dent tdent; ! 390: ino_t dotino, dotdotino; ! 391: ino_t dsearch(); ! 392: ! 393: if(access(dp, IWRITE)) ! 394: return; ! 395: if(dp->i_number == dent->dir.d_ino ! 396: || strncmp(dent->dir.d_name, "..", DIRSIZ)==0) { /* gets "." and "" */ ! 397: u.u_error = EINVAL; ! 398: return; ! 399: } ! 400: if((dip = iget(dp, dp->i_dev, dent->dir.d_ino)) == NULL) ! 401: return; ! 402: if(dip->i_number == ROOTINO) { ! 403: u.u_error = EINVAL; ! 404: iput(dip); ! 405: return; ! 406: } ! 407: if(dip->i_mpoint != dp->i_mpoint) { ! 408: u.u_error = EBUSY; ! 409: iput(dip); ! 410: return; ! 411: } ! 412: if (dip->i_count == 1 && fsiread(dp, dip) < 0) ! 413: return; ! 414: if((dip->i_mode & IFMT) != IFDIR) { ! 415: u.u_error = ENOTDIR; ! 416: iput(dip); ! 417: return; ! 418: } ! 419: /* search for ., .., other entries in dir */ ! 420: cpdirent("/", &tdent); /* cannot be found; just count entries */ ! 421: dsearch(dip, &tdent); ! 422: nentry = tdent.nentry; ! 423: tdent.dir.d_name[0] = '.'; ! 424: if (dotino = dsearch(dip, &tdent)) ! 425: nentry--; ! 426: tdent.dir.d_name[1] = '.'; ! 427: if(dotdotino = dsearch(dip, &tdent)) ! 428: nentry--; ! 429: if (nentry > 0) { ! 430: u.u_error = EHASF; /* removing nonempty directory */ ! 431: iput(dip); ! 432: return; ! 433: } ! 434: if (dotino) { ! 435: if (dip->i_number == dotino) ! 436: dip->i_nlink--; ! 437: /* else error? */ ! 438: } ! 439: if (dotdotino) { ! 440: if (dp->i_number == dotdotino) ! 441: dp->i_nlink--; ! 442: /* else error? */ ! 443: } ! 444: u.u_base = (caddr_t)&dent->dir; ! 445: u.u_count = sizeof(struct direct); ! 446: u.u_offset = ltoL(dent->off); ! 447: dent->dir.d_ino = 0; ! 448: writei(dp); ! 449: dp->i_flag |= ICHG; ! 450: fsiupdat(dp, &time, &time, 1); ! 451: dip->i_nlink--; ! 452: dip->i_flag |= ICHG; ! 453: iput(dip); ! 454: } ! 455: ! 456: cpdirent(s, dent) ! 457: register char *s; ! 458: register struct dent *dent; ! 459: { ! 460: register char *dp = dent->dir.d_name; ! 461: ! 462: while (dp < &dent->dir.d_name[DIRSIZ]) { ! 463: *dp++ = *s; ! 464: if (*s) ! 465: s++; ! 466: } ! 467: } ! 468: ! 469: /* ! 470: * search directory ip for entry dent->dir.d_name ! 471: * success: return ino, leave dent->dir with copy of entry, ! 472: * dent->off pointing at entry ! 473: * dent->nentry with count of entries ! 474: * fail: return 0, leave dent->off pointing at empty slot ! 475: */ ! 476: ino_t ! 477: dsearch(ip, dent) ! 478: struct inode *ip; ! 479: struct dent *dent; ! 480: { ! 481: register struct direct *dp, *dpe; ! 482: register char *nm; ! 483: register off_t off; ! 484: struct buf *bp; ! 485: register int bsize; ! 486: register daddr_t n, nblock; ! 487: ! 488: dent->dir.d_ino = 0; ! 489: nm = dent->dir.d_name; ! 490: bsize = BSIZE(ip->i_dev); ! 491: dent->nentry = 0; ! 492: bp = NULL; ! 493: dent->off = -1; ! 494: nblock = (ip->i_size+bsize-1) / bsize; ! 495: ! 496: for (n=0, off=0; n<nblock; n++) { ! 497: if (bp) ! 498: brelse(bp); ! 499: bp = bread(ip->i_dev, bmap(ip, n, B_READ)); ! 500: if (bp->b_flags & B_ERROR) { ! 501: u.u_error = EIO; ! 502: goto out; ! 503: } ! 504: dp = (struct direct *)bp->b_un.b_addr; ! 505: dpe = &dp[min(bsize, ip->i_size-off) / sizeof(struct direct)]; ! 506: for (; dp < dpe; dp++, off+=sizeof(struct direct)) { ! 507: if (dp->d_ino == 0) { ! 508: if (dent->off<0) ! 509: dent->off = off; ! 510: continue; ! 511: } ! 512: dent->nentry++; ! 513: if (nm[2]==dp->d_name[2] /* hash */ ! 514: && strncmp(nm, dp->d_name, DIRSIZ) == 0) { ! 515: dent->off = off; ! 516: dent->dir.d_ino = dp->d_ino; ! 517: goto out; ! 518: } ! 519: } ! 520: } ! 521: out: ! 522: if (dent->off<0) ! 523: dent->off = off; ! 524: if (bp) ! 525: brelse(bp); ! 526: return(dent->dir.d_ino); ! 527: } ! 528:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.