|
|
1.1 ! root 1: /* $Header: /newbits/286_KERNEL/USRSRC/coh/RCS/fs1.c,v 1.2 92/01/09 13:27:53 bin Exp Locker: bin $ */ ! 2: /* (lgl- ! 3: * The information contained herein is a trade secret of Mark Williams ! 4: * Company, and is confidential information. It is provided under a ! 5: * license agreement, and may be copied or disclosed only under the ! 6: * terms of that agreement. Any reproduction or disclosure of this ! 7: * material without the express written authorization of Mark Williams ! 8: * Company or persuant to the license agreement is unlawful. ! 9: * ! 10: * COHERENT Version 2.3.37 ! 11: * Copyright (c) 1982, 1983, 1984. ! 12: * An unpublished work by Mark Williams Company, Chicago. ! 13: * All rights reserved. ! 14: -lgl) */ ! 15: /* ! 16: * Coherent. ! 17: * Filesystem (mostly handling of in core inodes). ! 18: * ! 19: * $Log: fs1.c,v $ ! 20: * Revision 1.2 92/01/09 13:27:53 bin ! 21: * new sources provided by hal as new kit designed for 386 sources to be ! 22: * included. ! 23: * ! 24: * Revision 1.1 88/03/24 16:13:47 src ! 25: * Initial revision ! 26: * ! 27: * 87/11/25 Allan Cornish /usr/src/sys/coh/fs1.c ! 28: * vaddr_t bp->b_vaddr --> faddr_t bp->b_faddr. ! 29: * ! 30: * 86/12/13 Allan Cornish /usr/src/sys/coh/fs1.c ! 31: * isync() no longer updates the disk image of a character device inode. ! 32: * ! 33: * 86/11/19 Allan Cornish /usr/src/sys/coh/fs1.c ! 34: * idirent() initializes the (new) (IO).io_flag field to 0. ! 35: */ ! 36: #include <sys/coherent.h> ! 37: #include <sys/buf.h> ! 38: #include <canon.h> ! 39: #include <sys/dir.h> ! 40: #include <errno.h> ! 41: #include <sys/filsys.h> ! 42: #include <sys/ino.h> ! 43: #include <sys/inode.h> ! 44: #include <sys/io.h> ! 45: #include <sys/mount.h>> ! 46: #include <sys/stat.h> ! 47: #include <sys/uproc.h> ! 48: ! 49: /* ! 50: * Get character for `ftoi' depending on what space the characters are ! 51: * coming from. ! 52: */ ! 53: #define ftoic(p) (u.u_io.io_seg==IOSYS ? *p : getubd(p)) ! 54: ! 55: /* ! 56: * Map the given filename to an inode. If an error is encountered, ! 57: * `u.u_error' is set. `u.u_error' is always returned. As this routine ! 58: * needs to set several things, depending on the type of access, `t', ! 59: * there are places in the processes' user area reserved for this routine ! 60: * to set. These are defined in the user process structure. The seek ! 61: * position is always set to the position of the directory entry of the ! 62: * child if the child exists or the first free position if it doesn't. ! 63: * 'r' => Reference. A pointer to the child's inode is returned locked. ! 64: * 'c' => Create. If the child exists, a pointer to the inode is returned ! 65: * locked. Otherwise if the parent directory exists, a pointer to ! 66: * the parent directory is returned locked. Otherwise, an error. ! 67: * 'u' => Unlink. The parent directory is returned unlocked. The child's ! 68: * inode number is returned. The seek position is also set. ! 69: */ ! 70: ftoi(np, t) ! 71: char *np; ! 72: { ! 73: register INODE *cip; ! 74: register char *cp; ! 75: register int c; ! 76: register struct direct *dp; ! 77: register BUF *bp; ! 78: fsize_t cseek, fseek, s; ! 79: int fflag, mflag; ! 80: dev_t dev; ! 81: ino_t ino; ! 82: daddr_t b; ! 83: ! 84: u.u_cdirn = 0; ! 85: u.u_cdiri = NULL; ! 86: u.u_pdiri = NULL; ! 87: if ((c=ftoic(np++)) != '/') ! 88: cip = u.u_cdir; ! 89: else { ! 90: c = ftoic(np++); ! 91: cip = u.u_rdir; ! 92: } ! 93: while (c == '/') ! 94: c = ftoic(np++); ! 95: ilock(cip); ! 96: cip->i_refc++; ! 97: if (c == '\0') { ! 98: if (t == 'r') { ! 99: u.u_cdiri = cip; ! 100: return (u.u_error); ! 101: } ! 102: u.u_error = ENOENT; ! 103: idetach(cip); ! 104: return (u.u_error); ! 105: } ! 106: for (;;) { ! 107: cp = u.u_direct.d_name; ! 108: while (c!='/' && c!='\0') { ! 109: if (cp < &u.u_direct.d_name[DIRSIZ]) ! 110: *cp++ = c; ! 111: c = ftoic(np++); ! 112: } ! 113: while (c == '/') ! 114: c = ftoic(np++); ! 115: while (cp < &u.u_direct.d_name[DIRSIZ]) ! 116: *cp++ = '\0'; ! 117: if ((cip->i_mode&IFMT) != IFDIR) ! 118: u.u_error = ENOTDIR; ! 119: else ! 120: iaccess(cip, IPE); ! 121: if (u.u_error) { ! 122: idetach(cip); ! 123: return (u.u_error); ! 124: } ! 125: cp = u.u_direct.d_name; ! 126: if (cip->i_ino==ROOTIN && cip->i_dev!=rootdev) ! 127: if (*cp++=='.' && *cp++=='.' && *cp++=='\0') ! 128: cip = ftoim(cip); ! 129: b = 0; ! 130: fflag = 0; ! 131: mflag = 0; ! 132: cseek = 0; ! 133: s = cip->i_size; ! 134: while (s > 0) { ! 135: if ((bp=vread(cip, b++)) == NULL) { ! 136: idetach(cip); ! 137: return (u.u_error); ! 138: } ! 139: dp = FP_OFF(bp->b_faddr); ! 140: while (dp < FP_OFF(bp->b_faddr)+BSIZE) { ! 141: if ((s-=sizeof(*dp)) < 0) ! 142: break; ! 143: if ((ino=dp->d_ino) == 0) { ! 144: if (fflag == 0) { ! 145: fflag++; ! 146: fseek = cseek; ! 147: } ! 148: } else { ! 149: if (direq(dp)) { ! 150: canino(ino); ! 151: mflag = 1; ! 152: s = 0; ! 153: break; ! 154: } ! 155: } ! 156: cseek += sizeof(*dp); ! 157: dp++; ! 158: } ! 159: brelease(bp); ! 160: } ! 161: dev = cip->i_dev; ! 162: if (fflag == 0) ! 163: fseek = cseek; ! 164: if (mflag == 0) { ! 165: if (c=='\0' && t=='c') { ! 166: u.u_pdiri = cip; ! 167: u.u_io.io_seek = fseek; ! 168: } else { ! 169: u.u_error = ENOENT; ! 170: idetach(cip); ! 171: } ! 172: return (u.u_error); ! 173: } ! 174: if (c == '\0') { ! 175: if (t == 'u') { ! 176: u.u_cdirn = ino; ! 177: u.u_pdiri = cip; ! 178: u.u_io.io_seek = cseek; ! 179: return (u.u_error); ! 180: } ! 181: idetach(cip); ! 182: u.u_cdiri = iattach(dev, ino); ! 183: return (u.u_error); ! 184: } ! 185: idetach(cip); ! 186: if ((cip=iattach(dev, ino)) == NULL) ! 187: return (u.u_error); ! 188: } ! 189: } ! 190: ! 191: /* ! 192: * Given an inode which is the root of a file system, return the inode ! 193: * on which the file system was mounted. ! 194: */ ! 195: INODE * ! 196: ftoim(ip) ! 197: register INODE *ip; ! 198: { ! 199: register MOUNT *mp; ! 200: ! 201: for (mp=mountp; mp!=NULL; mp=mp->m_next) { ! 202: if (mp->m_dev == ip->i_dev) { ! 203: idetach(ip); ! 204: ip = mp->m_ip; ! 205: ilock(ip); ! 206: ip->i_refc++; ! 207: break; ! 208: } ! 209: } ! 210: return (ip); ! 211: } ! 212: ! 213: /* ! 214: * Compare the string in `u.u_direct.d_name' with the name in the ! 215: * given directory pointer. ! 216: */ ! 217: direq(dp) ! 218: struct direct *dp; ! 219: { ! 220: register char *cp1, *cp2; ! 221: register unsigned n; ! 222: ! 223: if (dp->d_ino == 0) ! 224: return (0); ! 225: cp1 = dp->d_name; ! 226: cp2 = u.u_direct.d_name; ! 227: n = DIRSIZ; ! 228: do { ! 229: if (*cp1++ != *cp2++) ! 230: return (0); ! 231: } while (--n); ! 232: return (1); ! 233: } ! 234: ! 235: /* ! 236: * Make an inode of the given mode and device. The parent directory, ! 237: * name and such stuff is set by ftoi. ! 238: */ ! 239: INODE * ! 240: imake(mode, rdev) ! 241: unsigned mode; ! 242: dev_t rdev; ! 243: { ! 244: register INODE *ip; ! 245: ! 246: ip = NULL; ! 247: mode &= ~u.u_umask; ! 248: if ((mode&ISVTXT)!=0 && super()==0) ! 249: goto det; ! 250: if (iaccess(u.u_pdiri, IPW) == 0) ! 251: goto det; ! 252: if ((ip=ialloc(u.u_pdiri->i_dev, mode)) == NULL) ! 253: goto det; ! 254: ip->i_nlink = 1; ! 255: ip->i_a.i_rdev = rdev; ! 256: idirent(ip->i_ino); ! 257: iamc(ip); /* creat/mknod - atime/mtime/ctime */ ! 258: det: ! 259: idetach(u.u_pdiri); ! 260: return (ip); ! 261: } ! 262: ! 263: /* ! 264: * Write a directory entry out. Everything necessary has been conveniently ! 265: * set by `ftoi', except the new inode number of this directory entry. ! 266: */ ! 267: idirent(ino) ! 268: { ! 269: u.u_direct.d_ino = ino; ! 270: canino(u.u_direct.d_ino); ! 271: u.u_io.io_ioc = sizeof (struct direct); ! 272: u.u_io.io_base = &u.u_direct; ! 273: u.u_io.io_seg = IOSYS; ! 274: u.u_io.io_flag = 0; ! 275: iwrite(u.u_pdiri, &u.u_io); ! 276: } ! 277: ! 278: /* ! 279: * Return a pointer to a locked inode in core containing the given ! 280: * inode number and device. ! 281: */ ! 282: INODE * ! 283: iattach(dev, ino) ! 284: { ! 285: register INODE *ip; ! 286: register INODE *fip; ! 287: register unsigned lrt; ! 288: register MOUNT *mp; ! 289: ! 290: for (;;) { ! 291: fip = NULL; ! 292: for (ip=&inodep[NINODE-1]; ip>=inodep; --ip) { ! 293: if (ip->i_ino==ino && ip->i_dev==dev) ! 294: break; ! 295: if (ip->i_refc == 0) { ! 296: if (fip==NULL || ip->i_lrt<lrt) { ! 297: fip = ip; ! 298: lrt = ip->i_lrt; ! 299: } ! 300: } ! 301: } ! 302: if (ip < inodep) { ! 303: if ((ip=fip) == NULL) { ! 304: devmsg(dev, "Inode table overflow"); ! 305: /*DEBUG*/ ! 306: { char cmd[11];int i; ! 307: for(i=0;i<10&&u.u_comm[i];i++) ! 308: cmd[i]=u.u_comm[i]; ! 309: cmd[i]='\0'; ! 310: printf("cmd=%s time=%lu\n",cmd, u.u_btime); ! 311: } ! 312: u.u_error = ENFILE; ! 313: return (NULL); ! 314: } ! 315: ilock(ip); ! 316: if (ip->i_refc != 0) { ! 317: iunlock(ip); ! 318: continue; ! 319: } ! 320: ip->i_dev = dev; ! 321: ip->i_ino = ino; ! 322: ip->i_refc = 1; ! 323: ip->i_lrt = timer.t_time; ! 324: if (icopydm(ip) == 0) { ! 325: ip->i_ino = 0; ! 326: ip->i_refc = 0; ! 327: iunlock(ip); ! 328: return (NULL); ! 329: } ! 330: return (ip); ! 331: } ! 332: if ((ip->i_flag&IFMNT) != 0) { ! 333: for (mp=mountp; mp!=NULL; mp=mp->m_next) { ! 334: if (mp->m_ip == ip) { ! 335: ino = ROOTIN; ! 336: dev = mp->m_dev; ! 337: break; ! 338: } ! 339: } ! 340: continue; ! 341: } ! 342: ilock(ip); ! 343: if (ip->i_ino!=ino || ip->i_dev!=dev) { ! 344: iunlock(ip); ! 345: continue; ! 346: } ! 347: if (ip->i_refc < 0) ! 348: panic("ialloc(%p), ip"); ! 349: ip->i_refc++; ! 350: ip->i_lrt = timer.t_time; ! 351: return (ip); ! 352: } ! 353: } ! 354: ! 355: /* ! 356: * Given a locked inode, deaccess it. ! 357: */ ! 358: idetach(ip) ! 359: register INODE *ip; ! 360: { ! 361: if (ilocked(ip)==0 || ip->i_refc<=0) ! 362: panic("idetach(%p)", ip); ! 363: if (--ip->i_refc == 0) { ! 364: if ((ip->i_flag&(IFACC|IFMOD|IFCRT)) != 0 ! 365: || ip->i_nlink == 0) ! 366: icopymd(ip); ! 367: } ! 368: iunlock(ip); ! 369: } ! 370: ! 371: /* ! 372: * Given a inode which isn't locked, lock it and then deaccess. ! 373: */ ! 374: ldetach(ip) ! 375: register INODE *ip; ! 376: { ! 377: ilock(ip); ! 378: idetach(ip); ! 379: } ! 380: ! 381: /* ! 382: * A specialized routine for finding whether the given inode may be unlinked. ! 383: * Quite simple you say, but we already have an inode locked and could run ! 384: * into gating problems if we were to lock another. So we look through the ! 385: * cache to see if the inode is there. If it is, we can easily tell. If it ! 386: * isn't, `icopydm' is called with a static. This routine is only used by ! 387: * `uunlink'. ! 388: */ ! 389: iucheck(dev, ino) ! 390: register dev_t dev; ! 391: register ino_t ino; ! 392: { ! 393: register INODE *ip; ! 394: INODE inode; ! 395: ! 396: for (ip=&inodep[NINODE-1]; ip>=inodep; --ip) { ! 397: if (ip->i_ino==ino && ip->i_dev==dev) ! 398: break; ! 399: } ! 400: if (ip < inodep) { ! 401: ip = &inode; ! 402: ip->i_dev = dev; ! 403: ip->i_ino = ino; ! 404: if (icopydm(ip) == 0) ! 405: return (0); ! 406: } ! 407: if ((ip->i_mode&IFMT) == IFDIR) { ! 408: if (super() == 0) ! 409: return (0); ! 410: } ! 411: return (1); ! 412: } ! 413: ! 414: /* ! 415: * Copy an inode from disk to memory performing canonization. ! 416: */ ! 417: icopydm(ip) ! 418: register INODE *ip; ! 419: { ! 420: register struct dinode *dip; ! 421: register BUF *bp; ! 422: register ino_t ino; ! 423: struct dinode dinode; ! 424: vaddr_t v; ! 425: ! 426: ip->i_flag = 0; ! 427: ino = ip->i_ino; ! 428: ! 429: if ((bp=bread(ip->i_dev, (daddr_t)iblockn(ino), 1)) == NULL) ! 430: return (0); ! 431: ! 432: dip = &dinode; ! 433: v = (char *)((struct dinode *)FP_OFF(bp->b_faddr) + iblocko(ino)); ! 434: kkcopy( v, dip, sizeof(dinode)); ! 435: brelease(bp); ! 436: ip->i_mode = dip->di_mode; ! 437: canshort(ip->i_mode); ! 438: ip->i_nlink = dip->di_nlink; ! 439: canshort(ip->i_nlink); ! 440: ip->i_uid = dip->di_uid; ! 441: canshort(ip->i_uid); ! 442: ip->i_gid = dip->di_gid; ! 443: canshort(ip->i_gid); ! 444: ip->i_size = dip->di_size; ! 445: cansize(ip->i_size); ! 446: ! 447: switch (ip->i_mode&IFMT) { ! 448: case IFBLK: ! 449: case IFCHR: ! 450: ip->i_a.i_rdev = dip->di_a.di_rdev; ! 451: candev(ip->i_a.i_rdev); ! 452: break; ! 453: case IFREG: ! 454: case IFDIR: ! 455: l3tol(ip->i_a.i_addr, dip->di_a.di_addb, NADDR); ! 456: break; ! 457: case IFPIPE: ! 458: l3tol(ip->i_pipe, dip->di_addp, ND); ! 459: ip->i_pnc = dip->di_pnc; ! 460: canint(ip->i_pnc); ! 461: ip->i_prx = dip->di_prx; ! 462: canint(ip->i_prx); ! 463: ip->i_pwx = dip->di_pwx; ! 464: canint(ip->i_pwx); ! 465: break; ! 466: default: ! 467: kclear(&ip->i_a, sizeof(ip->i_a)); ! 468: break; ! 469: } ! 470: ! 471: ip->i_atime = dip->di_atime; ! 472: cantime(ip->i_atime); ! 473: ip->i_mtime = dip->di_mtime; ! 474: cantime(ip->i_mtime); ! 475: ip->i_ctime = dip->di_ctime; ! 476: cantime(ip->i_ctime); ! 477: return (1); ! 478: } ! 479: ! 480: /* ! 481: * Copy an inode from memory back on to disk performing canonization. ! 482: */ ! 483: icopymd(ip) ! 484: register INODE *ip; ! 485: { ! 486: register struct dinode *dip; ! 487: register BUF *bp; ! 488: register ino_t ino; ! 489: struct dinode dinode; ! 490: vaddr_t v; ! 491: ! 492: if (getment(ip->i_dev, 0) == NULL) ! 493: return; ! 494: ! 495: ino = ip->i_ino; ! 496: if (ip->i_refc==0 && ip->i_nlink==0 && ino!=BADFIN && ino!=ROOTIN) { ! 497: iclear(ip); ! 498: ip->i_lrt = 0; ! 499: ip->i_mode = 0; ! 500: ifree(ip->i_dev, ino); ! 501: } ! 502: ! 503: dip = &dinode; ! 504: dip->di_mode = ip->i_mode; ! 505: canshort(dip->di_mode); ! 506: dip->di_nlink = ip->i_nlink; ! 507: canshort(dip->di_nlink); ! 508: dip->di_uid = ip->i_uid; ! 509: canshort(dip->di_uid); ! 510: dip->di_gid = ip->i_gid; ! 511: canshort(dip->di_gid); ! 512: dip->di_size = ip->i_size; ! 513: cansize(dip->di_size); ! 514: ! 515: switch (ip->i_mode&IFMT) { ! 516: case IFBLK: ! 517: case IFCHR: ! 518: dip->di_a.di_rdev = ip->i_a.i_rdev; ! 519: candev(dip->di_a.di_rdev); ! 520: break; ! 521: case IFREG: ! 522: case IFDIR: ! 523: ltol3(dip->di_addr, ip->i_a.i_addr, NADDR); ! 524: break; ! 525: case IFPIPE: ! 526: ltol3(dip->di_addp, ip->i_pipe, ND); ! 527: dip->di_pnc = ip->i_pnc; ! 528: canshort(dip->di_pnc); ! 529: dip->di_prx = ip->i_prx; ! 530: canshort(dip->di_prx); ! 531: dip->di_pwx = ip->i_pwx; ! 532: canshort(dip->di_pwx); ! 533: break; ! 534: default: ! 535: kclear(&dip->di_a, sizeof(dip->di_a)); ! 536: break; ! 537: } ! 538: ! 539: dip->di_atime = ip->i_atime; ! 540: cantime(dip->di_atime); ! 541: dip->di_mtime = ip->i_mtime; ! 542: cantime(dip->di_mtime); ! 543: dip->di_ctime = ip->i_ctime; ! 544: cantime(dip->di_ctime); ! 545: ! 546: if ((bp=bread(ip->i_dev, (daddr_t)iblockn(ino), 1)) == NULL) ! 547: return; ! 548: ! 549: v = (char *)((struct dinode *)FP_OFF(bp->b_faddr) + iblocko(ino)); ! 550: kkcopy(dip, v, sizeof(dinode)); ! 551: bp->b_flag |= BFMOD; ! 552: brelease(bp); ! 553: ip->i_flag &= ~(IFACC|IFMOD|IFCRT); ! 554: } ! 555: ! 556: /* ! 557: * Copy all relevant inodes out on device `dev'. ! 558: */ ! 559: isync(dev) ! 560: register dev_t dev; ! 561: { ! 562: register INODE *ip; ! 563: ! 564: for (ip=&inodep[NINODE-1]; ip>=inodep; --ip) { ! 565: if (ip->i_refc == 0) ! 566: continue; ! 567: if (ip->i_dev != dev) ! 568: continue; ! 569: if ( (ip->i_mode & IFMT) == IFCHR ) ! 570: continue; ! 571: if ((ip->i_flag&(IFACC|IFMOD|IFCRT)) == 0) ! 572: continue; ! 573: icopymd(ip); ! 574: } ! 575: } ! 576: ! 577: /* ! 578: * Clear the given inode and all space associated with it. ! 579: */ ! 580: iclear(ip) ! 581: register INODE *ip; ! 582: { ! 583: register int n; ! 584: register daddr_t b; ! 585: ! 586: switch (ip->i_mode&IFMT) { ! 587: case IFPIPE: ! 588: ip->i_pnc = 0; ! 589: ip->i_prx = 0; ! 590: ip->i_pwx = 0; ! 591: n = ND; ! 592: break; ! 593: case IFDIR: ! 594: case IFREG: ! 595: n = NADDR; ! 596: break; ! 597: default: ! 598: return; ! 599: } ! 600: while (n > ND) { ! 601: if ((b=ip->i_a.i_addr[--n]) != 0) ! 602: indfree(ip->i_dev, b, 1+n-ND); ! 603: } ! 604: while (n > 0) { ! 605: if ((b=ip->i_a.i_addr[--n]) != 0) ! 606: bfree(ip->i_dev, b); ! 607: } ! 608: ip->i_size = 0; ! 609: kclear(ip->i_a.i_addr, sizeof(ip->i_a.i_addr)); ! 610: iamc(ip); /* creat/pipe - atime/mtime/ctime */ ! 611: } ! 612: ! 613: /* ! 614: * Copy the appropriate information from the inode to the stat buffer. ! 615: */ ! 616: istat(ip, sbp) ! 617: register INODE *ip; ! 618: register struct stat *sbp; ! 619: { ! 620: sbp->st_dev = ip->i_dev; ! 621: sbp->st_ino = ip->i_ino; ! 622: sbp->st_mode = ip->i_mode; ! 623: sbp->st_nlink = ip->i_nlink; ! 624: sbp->st_uid = ip->i_uid; ! 625: sbp->st_gid = ip->i_gid; ! 626: sbp->st_rdev = NODEV; ! 627: sbp->st_size = ip->i_size; ! 628: sbp->st_atime = ip->i_atime; ! 629: sbp->st_mtime = ip->i_mtime; ! 630: sbp->st_ctime = ip->i_ctime; ! 631: switch (ip->i_mode&IFMT) { ! 632: case IFBLK: ! 633: case IFCHR: ! 634: sbp->st_rdev = ip->i_a.i_rdev; ! 635: sbp->st_size = 0; ! 636: break; ! 637: case IFPIPE: ! 638: sbp->st_size = ip->i_pnc; ! 639: break; ! 640: } ! 641: } ! 642: ! 643: /* ! 644: * See if it is possible to access the given inode with the bits in ! 645: * the given mode. ! 646: * If the mode includes writing, and i_refc is > 1, then check for ! 647: * shared text problems. ! 648: */ ! 649: iaccess(ip, mode) ! 650: register INODE *ip; ! 651: register int mode; ! 652: { ! 653: if ((imode(ip, u.u_uid, u.u_gid)&mode) != mode) { ! 654: u.u_error = EACCES; ! 655: return (0); ! 656: } ! 657: if ((mode&IPW) != 0 && ip->i_refc > 1 && sbusy(ip)) { ! 658: u.u_error = ETXTBSY; ! 659: return (0); ! 660: } ! 661: return (1); ! 662: } ! 663: ! 664: /* ! 665: * Get the maximum allowable mode on a file. ! 666: */ ! 667: imode(ip, uid, gid) ! 668: register INODE *ip; ! 669: { ! 670: if (uid == 0) ! 671: return (IPR|IPW|IPE); ! 672: if (uid == ip->i_uid) ! 673: return ((ip->i_mode>>6)&07); ! 674: if (gid == ip->i_gid) ! 675: return ((ip->i_mode>>3)&07); ! 676: return (ip->i_mode&07); ! 677: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.