1: /*
   2:  * Copyright (c) 1982, 1986 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_syscalls.c	7.1 (Berkeley) 6/5/86
   7:  */
   8: 
   9: #include "param.h"
  10: #include "systm.h"
  11: #include "dir.h"
  12: #include "user.h"
  13: #include "kernel.h"
  14: #include "file.h"
  15: #include "stat.h"
  16: #include "inode.h"
  17: #include "fs.h"
  18: #include "buf.h"
  19: #include "proc.h"
  20: #include "quota.h"
  21: #include "uio.h"
  22: #include "socket.h"
  23: #include "socketvar.h"
  24: #include "mount.h"
  25: 
  26: extern  struct fileops inodeops;
  27: struct  file *getinode();
  28: 
  29: /*
  30:  * Change current working directory (``.'').
  31:  */
  32: chdir()
  33: {
  34: 
  35:     chdirec(&u.u_cdir);
  36: }
  37: 
  38: /*
  39:  * Change notion of root (``/'') directory.
  40:  */
  41: chroot()
  42: {
  43: 
  44:     if (suser())
  45:         chdirec(&u.u_rdir);
  46: }
  47: 
  48: /*
  49:  * Common routine for chroot and chdir.
  50:  */
  51: chdirec(ipp)
  52:     register struct inode **ipp;
  53: {
  54:     register struct inode *ip;
  55:     struct a {
  56:         char    *fname;
  57:     } *uap = (struct a *)u.u_ap;
  58:     register struct nameidata *ndp = &u.u_nd;
  59: 
  60:     ndp->ni_nameiop = LOOKUP | FOLLOW;
  61:     ndp->ni_segflg = UIO_USERSPACE;
  62:     ndp->ni_dirp = uap->fname;
  63:     ip = namei(ndp);
  64:     if (ip == NULL)
  65:         return;
  66:     if ((ip->i_mode&IFMT) != IFDIR) {
  67:         u.u_error = ENOTDIR;
  68:         goto bad;
  69:     }
  70:     if (access(ip, IEXEC))
  71:         goto bad;
  72:     IUNLOCK(ip);
  73:     if (*ipp)
  74:         irele(*ipp);
  75:     *ipp = ip;
  76:     return;
  77: 
  78: bad:
  79:     iput(ip);
  80: }
  81: 
  82: /*
  83:  * Open system call.
  84:  */
  85: open()
  86: {
  87:     struct a {
  88:         char    *fname;
  89:         int mode;
  90:         int crtmode;
  91:     } *uap = (struct a *) u.u_ap;
  92: 
  93:     copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
  94: }
  95: 
  96: /*
  97:  * Creat system call.
  98:  */
  99: creat()
 100: {
 101:     struct a {
 102:         char    *fname;
 103:         int fmode;
 104:     } *uap = (struct a *)u.u_ap;
 105: 
 106:     copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
 107: }
 108: 
 109: /*
 110:  * Common code for open and creat.
 111:  * Check permissions, allocate an open file structure,
 112:  * and call the device open routine if any.
 113:  */
 114: copen(mode, arg, fname)
 115:     register int mode;
 116:     int arg;
 117:     caddr_t fname;
 118: {
 119:     register struct inode *ip;
 120:     register struct file *fp;
 121:     register struct nameidata *ndp = &u.u_nd;
 122:     int indx;
 123: 
 124:     fp = falloc();
 125:     if (fp == NULL)
 126:         return;
 127:     indx = u.u_r.r_val1;
 128:     ndp->ni_segflg = UIO_USERSPACE;
 129:     ndp->ni_dirp = fname;
 130:     if (mode&FCREAT) {
 131:         if (mode & FEXCL)
 132:             ndp->ni_nameiop = CREATE;
 133:         else
 134:             ndp->ni_nameiop = CREATE | FOLLOW;
 135:         ip = namei(ndp);
 136:         if (ip == NULL) {
 137:             if (u.u_error)
 138:                 goto bad1;
 139:             ip = maknode(arg&07777&(~ISVTX), ndp);
 140:             if (ip == NULL)
 141:                 goto bad1;
 142:             mode &= ~FTRUNC;
 143:         } else {
 144:             if (mode&FEXCL) {
 145:                 u.u_error = EEXIST;
 146:                 goto bad;
 147:             }
 148:             mode &= ~FCREAT;
 149:         }
 150:     } else {
 151:         ndp->ni_nameiop = LOOKUP | FOLLOW;
 152:         ip = namei(ndp);
 153:         if (ip == NULL)
 154:             goto bad1;
 155:     }
 156:     if ((ip->i_mode & IFMT) == IFSOCK) {
 157:         u.u_error = EOPNOTSUPP;
 158:         goto bad;
 159:     }
 160:     if ((mode&FCREAT) == 0) {
 161:         if (mode&FREAD)
 162:             if (access(ip, IREAD))
 163:                 goto bad;
 164:         if (mode&(FWRITE|FTRUNC)) {
 165:             if (access(ip, IWRITE))
 166:                 goto bad;
 167:             if ((ip->i_mode&IFMT) == IFDIR) {
 168:                 u.u_error = EISDIR;
 169:                 goto bad;
 170:             }
 171:         }
 172:     }
 173:     if (mode&FTRUNC)
 174:         itrunc(ip, (u_long)0);
 175:     IUNLOCK(ip);
 176:     fp->f_flag = mode&FMASK;
 177:     fp->f_type = DTYPE_INODE;
 178:     fp->f_ops = &inodeops;
 179:     fp->f_data = (caddr_t)ip;
 180:     if (setjmp(&u.u_qsave)) {
 181:         if (u.u_error == 0)
 182:             u.u_error = EINTR;
 183:         u.u_ofile[indx] = NULL;
 184:         closef(fp);
 185:         return;
 186:     }
 187:     u.u_error = openi(ip, mode);
 188:     if (u.u_error == 0)
 189:         return;
 190:     ILOCK(ip);
 191: bad:
 192:     iput(ip);
 193: bad1:
 194:     u.u_ofile[indx] = NULL;
 195:     fp->f_count--;
 196: }
 197: 
 198: /*
 199:  * Mknod system call
 200:  */
 201: mknod()
 202: {
 203:     register struct inode *ip;
 204:     register struct a {
 205:         char    *fname;
 206:         int fmode;
 207:         int dev;
 208:     } *uap = (struct a *)u.u_ap;
 209:     register struct nameidata *ndp = &u.u_nd;
 210: 
 211:     if (!suser())
 212:         return;
 213:     ndp->ni_nameiop = CREATE;
 214:     ndp->ni_segflg = UIO_USERSPACE;
 215:     ndp->ni_dirp = uap->fname;
 216:     ip = namei(ndp);
 217:     if (ip != NULL) {
 218:         u.u_error = EEXIST;
 219:         goto out;
 220:     }
 221:     if (u.u_error)
 222:         return;
 223:     ip = maknode(uap->fmode, ndp);
 224:     if (ip == NULL)
 225:         return;
 226:     switch (ip->i_mode & IFMT) {
 227: 
 228:     case IFMT:  /* used by badsect to flag bad sectors */
 229:     case IFCHR:
 230:     case IFBLK:
 231:         if (uap->dev) {
 232:             /*
 233: 			 * Want to be able to use this to make badblock
 234: 			 * inodes, so don't truncate the dev number.
 235: 			 */
 236:             ip->i_rdev = uap->dev;
 237:             ip->i_flag |= IACC|IUPD|ICHG;
 238:         }
 239:     }
 240: 
 241: out:
 242:     iput(ip);
 243: }
 244: 
 245: /*
 246:  * link system call
 247:  */
 248: link()
 249: {
 250:     register struct inode *ip, *xp;
 251:     register struct a {
 252:         char    *target;
 253:         char    *linkname;
 254:     } *uap = (struct a *)u.u_ap;
 255:     register struct nameidata *ndp = &u.u_nd;
 256: 
 257:     ndp->ni_nameiop = LOOKUP | FOLLOW;
 258:     ndp->ni_segflg = UIO_USERSPACE;
 259:     ndp->ni_dirp = uap->target;
 260:     ip = namei(ndp);    /* well, this routine is doomed anyhow */
 261:     if (ip == NULL)
 262:         return;
 263:     if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
 264:         iput(ip);
 265:         return;
 266:     }
 267:     ip->i_nlink++;
 268:     ip->i_flag |= ICHG;
 269:     iupdat(ip, &time, &time, 1);
 270:     IUNLOCK(ip);
 271:     ndp->ni_nameiop = CREATE;
 272:     ndp->ni_segflg = UIO_USERSPACE;
 273:     ndp->ni_dirp = (caddr_t)uap->linkname;
 274:     xp = namei(ndp);
 275:     if (xp != NULL) {
 276:         u.u_error = EEXIST;
 277:         iput(xp);
 278:         goto out;
 279:     }
 280:     if (u.u_error)
 281:         goto out;
 282:     if (ndp->ni_pdir->i_dev != ip->i_dev) {
 283:         iput(ndp->ni_pdir);
 284:         u.u_error = EXDEV;
 285:         goto out;
 286:     }
 287:     u.u_error = direnter(ip, ndp);
 288: out:
 289:     if (u.u_error) {
 290:         ip->i_nlink--;
 291:         ip->i_flag |= ICHG;
 292:     }
 293:     irele(ip);
 294: }
 295: 
 296: /*
 297:  * symlink -- make a symbolic link
 298:  */
 299: symlink()
 300: {
 301:     register struct a {
 302:         char    *target;
 303:         char    *linkname;
 304:     } *uap = (struct a *)u.u_ap;
 305:     register struct inode *ip;
 306:     register char *tp;
 307:     register c, nc;
 308:     register struct nameidata *ndp = &u.u_nd;
 309: 
 310:     tp = uap->target;
 311:     nc = 0;
 312:     while (c = fubyte(tp)) {
 313:         if (c < 0) {
 314:             u.u_error = EFAULT;
 315:             return;
 316:         }
 317:         tp++;
 318:         nc++;
 319:     }
 320:     ndp->ni_nameiop = CREATE;
 321:     ndp->ni_segflg = UIO_USERSPACE;
 322:     ndp->ni_dirp = uap->linkname;
 323:     ip = namei(ndp);
 324:     if (ip) {
 325:         iput(ip);
 326:         u.u_error = EEXIST;
 327:         return;
 328:     }
 329:     if (u.u_error)
 330:         return;
 331:     ip = maknode(IFLNK | 0777, ndp);
 332:     if (ip == NULL)
 333:         return;
 334:     u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
 335:         (int *)0);
 336:     /* handle u.u_error != 0 */
 337:     iput(ip);
 338: }
 339: 
 340: /*
 341:  * Unlink system call.
 342:  * Hard to avoid races here, especially
 343:  * in unlinking directories.
 344:  */
 345: unlink()
 346: {
 347:     struct a {
 348:         char    *fname;
 349:     } *uap = (struct a *)u.u_ap;
 350:     register struct inode *ip, *dp;
 351:     register struct nameidata *ndp = &u.u_nd;
 352: 
 353:     ndp->ni_nameiop = DELETE | LOCKPARENT;
 354:     ndp->ni_segflg = UIO_USERSPACE;
 355:     ndp->ni_dirp = uap->fname;
 356:     ip = namei(ndp);
 357:     if (ip == NULL)
 358:         return;
 359:     dp = ndp->ni_pdir;
 360:     if ((ip->i_mode&IFMT) == IFDIR && !suser())
 361:         goto out;
 362:     /*
 363: 	 * Don't unlink a mounted file.
 364: 	 */
 365:     if (ip->i_dev != dp->i_dev) {
 366:         u.u_error = EBUSY;
 367:         goto out;
 368:     }
 369:     if (ip->i_flag&ITEXT)
 370:         xrele(ip);  /* try once to free text */
 371:     if (dirremove(ndp)) {
 372:         ip->i_nlink--;
 373:         ip->i_flag |= ICHG;
 374:     }
 375: out:
 376:     if (dp == ip)
 377:         irele(ip);
 378:     else
 379:         iput(ip);
 380:     iput(dp);
 381: }
 382: 
 383: /*
 384:  * Seek system call
 385:  */
 386: lseek()
 387: {
 388:     register struct file *fp;
 389:     register struct a {
 390:         int fd;
 391:         off_t   off;
 392:         int sbase;
 393:     } *uap = (struct a *)u.u_ap;
 394: 
 395:     GETF(fp, uap->fd);
 396:     if (fp->f_type != DTYPE_INODE) {
 397:         u.u_error = ESPIPE;
 398:         return;
 399:     }
 400:     switch (uap->sbase) {
 401: 
 402:     case L_INCR:
 403:         fp->f_offset += uap->off;
 404:         break;
 405: 
 406:     case L_XTND:
 407:         fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
 408:         break;
 409: 
 410:     case L_SET:
 411:         fp->f_offset = uap->off;
 412:         break;
 413: 
 414:     default:
 415:         u.u_error = EINVAL;
 416:         return;
 417:     }
 418:     u.u_r.r_off = fp->f_offset;
 419: }
 420: 
 421: /*
 422:  * Access system call
 423:  */
 424: saccess()
 425: {
 426:     register svuid, svgid;
 427:     register struct inode *ip;
 428:     register struct a {
 429:         char    *fname;
 430:         int fmode;
 431:     } *uap = (struct a *)u.u_ap;
 432:     register struct nameidata *ndp = &u.u_nd;
 433: 
 434:     svuid = u.u_uid;
 435:     svgid = u.u_gid;
 436:     u.u_uid = u.u_ruid;
 437:     u.u_gid = u.u_rgid;
 438:     ndp->ni_nameiop = LOOKUP | FOLLOW;
 439:     ndp->ni_segflg = UIO_USERSPACE;
 440:     ndp->ni_dirp = uap->fname;
 441:     ip = namei(ndp);
 442:     if (ip != NULL) {
 443:         if ((uap->fmode&R_OK) && access(ip, IREAD))
 444:             goto done;
 445:         if ((uap->fmode&W_OK) && access(ip, IWRITE))
 446:             goto done;
 447:         if ((uap->fmode&X_OK) && access(ip, IEXEC))
 448:             goto done;
 449: done:
 450:         iput(ip);
 451:     }
 452:     u.u_uid = svuid;
 453:     u.u_gid = svgid;
 454: }
 455: 
 456: /*
 457:  * Stat system call.  This version follows links.
 458:  */
 459: stat()
 460: {
 461: 
 462:     stat1(FOLLOW);
 463: }
 464: 
 465: /*
 466:  * Lstat system call.  This version does not follow links.
 467:  */
 468: lstat()
 469: {
 470: 
 471:     stat1(NOFOLLOW);
 472: }
 473: 
 474: stat1(follow)
 475:     int follow;
 476: {
 477:     register struct inode *ip;
 478:     register struct a {
 479:         char    *fname;
 480:         struct stat *ub;
 481:     } *uap = (struct a *)u.u_ap;
 482:     struct stat sb;
 483:     register struct nameidata *ndp = &u.u_nd;
 484: 
 485:     ndp->ni_nameiop = LOOKUP | follow;
 486:     ndp->ni_segflg = UIO_USERSPACE;
 487:     ndp->ni_dirp = uap->fname;
 488:     ip = namei(ndp);
 489:     if (ip == NULL)
 490:         return;
 491:     (void) ino_stat(ip, &sb);
 492:     iput(ip);
 493:     u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
 494: }
 495: 
 496: /*
 497:  * Return target name of a symbolic link
 498:  */
 499: readlink()
 500: {
 501:     register struct inode *ip;
 502:     register struct a {
 503:         char    *name;
 504:         char    *buf;
 505:         int count;
 506:     } *uap = (struct a *)u.u_ap;
 507:     register struct nameidata *ndp = &u.u_nd;
 508:     int resid;
 509: 
 510:     ndp->ni_nameiop = LOOKUP;
 511:     ndp->ni_segflg = UIO_USERSPACE;
 512:     ndp->ni_dirp = uap->name;
 513:     ip = namei(ndp);
 514:     if (ip == NULL)
 515:         return;
 516:     if ((ip->i_mode&IFMT) != IFLNK) {
 517:         u.u_error = EINVAL;
 518:         goto out;
 519:     }
 520:     u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
 521:         &resid);
 522: out:
 523:     iput(ip);
 524:     u.u_r.r_val1 = uap->count - resid;
 525: }
 526: 
 527: /*
 528:  * Change mode of a file given path name.
 529:  */
 530: chmod()
 531: {
 532:     struct inode *ip;
 533:     struct a {
 534:         char    *fname;
 535:         int fmode;
 536:     } *uap = (struct a *)u.u_ap;
 537: 
 538:     if ((ip = owner(uap->fname, FOLLOW)) == NULL)
 539:         return;
 540:     u.u_error = chmod1(ip, uap->fmode);
 541:     iput(ip);
 542: }
 543: 
 544: /*
 545:  * Change mode of a file given a file descriptor.
 546:  */
 547: fchmod()
 548: {
 549:     struct a {
 550:         int fd;
 551:         int fmode;
 552:     } *uap = (struct a *)u.u_ap;
 553:     register struct inode *ip;
 554:     register struct file *fp;
 555: 
 556:     fp = getinode(uap->fd);
 557:     if (fp == NULL)
 558:         return;
 559:     ip = (struct inode *)fp->f_data;
 560:     if (u.u_uid != ip->i_uid && !suser())
 561:         return;
 562:     ILOCK(ip);
 563:     u.u_error = chmod1(ip, uap->fmode);
 564:     IUNLOCK(ip);
 565: }
 566: 
 567: /*
 568:  * Change the mode on a file.
 569:  * Inode must be locked before calling.
 570:  */
 571: chmod1(ip, mode)
 572:     register struct inode *ip;
 573:     register int mode;
 574: {
 575: 
 576:     if (ip->i_fs->fs_ronly)
 577:         return (EROFS);
 578:     ip->i_mode &= ~07777;
 579:     if (u.u_uid) {
 580:         if ((ip->i_mode & IFMT) != IFDIR)
 581:             mode &= ~ISVTX;
 582:         if (!groupmember(ip->i_gid))
 583:             mode &= ~ISGID;
 584:     }
 585:     ip->i_mode |= mode&07777;
 586:     ip->i_flag |= ICHG;
 587:     if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
 588:         xrele(ip);
 589:     return (0);
 590: }
 591: 
 592: /*
 593:  * Set ownership given a path name.
 594:  */
 595: chown()
 596: {
 597:     struct inode *ip;
 598:     struct a {
 599:         char    *fname;
 600:         int uid;
 601:         int gid;
 602:     } *uap = (struct a *)u.u_ap;
 603: 
 604:     if ((ip = owner(uap->fname, NOFOLLOW)) == NULL)
 605:         return;
 606:     u.u_error = chown1(ip, uap->uid, uap->gid);
 607:     iput(ip);
 608: }
 609: 
 610: /*
 611:  * Set ownership given a file descriptor.
 612:  */
 613: fchown()
 614: {
 615:     struct a {
 616:         int fd;
 617:         int uid;
 618:         int gid;
 619:     } *uap = (struct a *)u.u_ap;
 620:     register struct inode *ip;
 621:     register struct file *fp;
 622: 
 623:     fp = getinode(uap->fd);
 624:     if (fp == NULL)
 625:         return;
 626:     ip = (struct inode *)fp->f_data;
 627:     ILOCK(ip);
 628:     u.u_error = chown1(ip, uap->uid, uap->gid);
 629:     IUNLOCK(ip);
 630: }
 631: 
 632: /*
 633:  * Perform chown operation on inode ip;
 634:  * inode must be locked prior to call.
 635:  */
 636: chown1(ip, uid, gid)
 637:     register struct inode *ip;
 638:     int uid, gid;
 639: {
 640: #ifdef QUOTA
 641:     register long change;
 642: #endif
 643: 
 644:     if (ip->i_fs->fs_ronly)
 645:         return (EROFS);
 646:     if (uid == -1)
 647:         uid = ip->i_uid;
 648:     if (gid == -1)
 649:         gid = ip->i_gid;
 650:     if (uid != ip->i_uid && !suser())
 651:         return (u.u_error);
 652:     if (gid != ip->i_gid && !groupmember((gid_t)gid) && !suser())
 653:         return (u.u_error);
 654: #ifdef QUOTA
 655:     if (ip->i_uid == uid)       /* this just speeds things a little */
 656:         change = 0;
 657:     else
 658:         change = ip->i_blocks;
 659:     (void) chkdq(ip, -change, 1);
 660:     (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
 661:     dqrele(ip->i_dquot);
 662: #endif
 663:     ip->i_uid = uid;
 664:     ip->i_gid = gid;
 665:     ip->i_flag |= ICHG;
 666:     if (u.u_ruid != 0)
 667:         ip->i_mode &= ~(ISUID|ISGID);
 668: #ifdef QUOTA
 669:     ip->i_dquot = inoquota(ip);
 670:     (void) chkdq(ip, change, 1);
 671:     (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
 672:     return (u.u_error);     /* should == 0 ALWAYS !! */
 673: #else
 674:     return (0);
 675: #endif
 676: }
 677: 
 678: utimes()
 679: {
 680:     register struct a {
 681:         char    *fname;
 682:         struct  timeval *tptr;
 683:     } *uap = (struct a *)u.u_ap;
 684:     register struct inode *ip;
 685:     struct timeval tv[2];
 686: 
 687:     if ((ip = owner(uap->fname, FOLLOW)) == NULL)
 688:         return;
 689:     if (ip->i_fs->fs_ronly) {
 690:         u.u_error = EROFS;
 691:         iput(ip);
 692:         return;
 693:     }
 694:     u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
 695:     if (u.u_error == 0) {
 696:         ip->i_flag |= IACC|IUPD|ICHG;
 697:         iupdat(ip, &tv[0], &tv[1], 0);
 698:     }
 699:     iput(ip);
 700: }
 701: 
 702: /*
 703:  * Flush any pending I/O.
 704:  */
 705: sync()
 706: {
 707: 
 708:     update();
 709: }
 710: 
 711: /*
 712:  * Truncate a file given its path name.
 713:  */
 714: truncate()
 715: {
 716:     struct a {
 717:         char    *fname;
 718:         off_t   length;
 719:     } *uap = (struct a *)u.u_ap;
 720:     struct inode *ip;
 721:     register struct nameidata *ndp = &u.u_nd;
 722: 
 723:     ndp->ni_nameiop = LOOKUP | FOLLOW;
 724:     ndp->ni_segflg = UIO_USERSPACE;
 725:     ndp->ni_dirp = uap->fname;
 726:     ip = namei(ndp);
 727:     if (ip == NULL)
 728:         return;
 729:     if (access(ip, IWRITE))
 730:         goto bad;
 731:     if ((ip->i_mode&IFMT) == IFDIR) {
 732:         u.u_error = EISDIR;
 733:         goto bad;
 734:     }
 735:     itrunc(ip, (u_long)uap->length);
 736: bad:
 737:     iput(ip);
 738: }
 739: 
 740: /*
 741:  * Truncate a file given a file descriptor.
 742:  */
 743: ftruncate()
 744: {
 745:     struct a {
 746:         int fd;
 747:         off_t   length;
 748:     } *uap = (struct a *)u.u_ap;
 749:     struct inode *ip;
 750:     struct file *fp;
 751: 
 752:     fp = getinode(uap->fd);
 753:     if (fp == NULL)
 754:         return;
 755:     if ((fp->f_flag&FWRITE) == 0) {
 756:         u.u_error = EINVAL;
 757:         return;
 758:     }
 759:     ip = (struct inode *)fp->f_data;
 760:     ILOCK(ip);
 761:     itrunc(ip, (u_long)uap->length);
 762:     IUNLOCK(ip);
 763: }
 764: 
 765: /*
 766:  * Synch an open file.
 767:  */
 768: fsync()
 769: {
 770:     struct a {
 771:         int fd;
 772:     } *uap = (struct a *)u.u_ap;
 773:     struct inode *ip;
 774:     struct file *fp;
 775: 
 776:     fp = getinode(uap->fd);
 777:     if (fp == NULL)
 778:         return;
 779:     ip = (struct inode *)fp->f_data;
 780:     ILOCK(ip);
 781:     syncip(ip);
 782:     IUNLOCK(ip);
 783: }
 784: 
 785: /*
 786:  * Rename system call.
 787:  * 	rename("foo", "bar");
 788:  * is essentially
 789:  *	unlink("bar");
 790:  *	link("foo", "bar");
 791:  *	unlink("foo");
 792:  * but ``atomically''.  Can't do full commit without saving state in the
 793:  * inode on disk which isn't feasible at this time.  Best we can do is
 794:  * always guarantee the target exists.
 795:  *
 796:  * Basic algorithm is:
 797:  *
 798:  * 1) Bump link count on source while we're linking it to the
 799:  *    target.  This also insure the inode won't be deleted out
 800:  *    from underneath us while we work (it may be truncated by
 801:  *    a concurrent `trunc' or `open' for creation).
 802:  * 2) Link source to destination.  If destination already exists,
 803:  *    delete it first.
 804:  * 3) Unlink source reference to inode if still around. If a
 805:  *    directory was moved and the parent of the destination
 806:  *    is different from the source, patch the ".." entry in the
 807:  *    directory.
 808:  *
 809:  * Source and destination must either both be directories, or both
 810:  * not be directories.  If target is a directory, it must be empty.
 811:  */
 812: rename()
 813: {
 814:     struct a {
 815:         char    *from;
 816:         char    *to;
 817:     } *uap = (struct a *)u.u_ap;
 818:     register struct inode *ip, *xp, *dp;
 819:     struct dirtemplate dirbuf;
 820:     int doingdirectory = 0, oldparent = 0, newparent = 0;
 821:     register struct nameidata *ndp = &u.u_nd;
 822:     int error = 0;
 823: 
 824:     ndp->ni_nameiop = DELETE | LOCKPARENT;
 825:     ndp->ni_segflg = UIO_USERSPACE;
 826:     ndp->ni_dirp = uap->from;
 827:     ip = namei(ndp);
 828:     if (ip == NULL)
 829:         return;
 830:     dp = ndp->ni_pdir;
 831:     if ((ip->i_mode&IFMT) == IFDIR) {
 832:         register struct direct *d;
 833: 
 834:         d = &ndp->ni_dent;
 835:         /*
 836: 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
 837: 		 */
 838:         if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
 839:             (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
 840:             (dp == ip) || (ip->i_flag & IRENAME)) {
 841:             iput(dp);
 842:             if (dp == ip)
 843:                 irele(ip);
 844:             else
 845:                 iput(ip);
 846:             u.u_error = EINVAL;
 847:             return;
 848:         }
 849:         ip->i_flag |= IRENAME;
 850:         oldparent = dp->i_number;
 851:         doingdirectory++;
 852:     }
 853:     iput(dp);
 854: 
 855:     /*
 856: 	 * 1) Bump link count while we're moving stuff
 857: 	 *    around.  If we crash somewhere before
 858: 	 *    completing our work, the link count
 859: 	 *    may be wrong, but correctable.
 860: 	 */
 861:     ip->i_nlink++;
 862:     ip->i_flag |= ICHG;
 863:     iupdat(ip, &time, &time, 1);
 864:     IUNLOCK(ip);
 865: 
 866:     /*
 867: 	 * When the target exists, both the directory
 868: 	 * and target inodes are returned locked.
 869: 	 */
 870:     ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
 871:     ndp->ni_dirp = (caddr_t)uap->to;
 872:     xp = namei(ndp);
 873:     if (u.u_error) {
 874:         error = u.u_error;
 875:         goto out;
 876:     }
 877:     dp = ndp->ni_pdir;
 878:     /*
 879: 	 * If ".." must be changed (ie the directory gets a new
 880: 	 * parent) then the source directory must not be in the
 881: 	 * directory heirarchy above the target, as this would
 882: 	 * orphan everything below the source directory. Also
 883: 	 * the user must have write permission in the source so
 884: 	 * as to be able to change "..". We must repeat the call
 885: 	 * to namei, as the parent directory is unlocked by the
 886: 	 * call to checkpath().
 887: 	 */
 888:     if (oldparent != dp->i_number)
 889:         newparent = dp->i_number;
 890:     if (doingdirectory && newparent) {
 891:         if (access(ip, IWRITE))
 892:             goto bad;
 893:         do {
 894:             dp = ndp->ni_pdir;
 895:             if (xp != NULL)
 896:                 iput(xp);
 897:             u.u_error = checkpath(ip, dp);
 898:             if (u.u_error)
 899:                 goto out;
 900:             xp = namei(ndp);
 901:             if (u.u_error) {
 902:                 error = u.u_error;
 903:                 goto out;
 904:             }
 905:         } while (dp != ndp->ni_pdir);
 906:     }
 907:     /*
 908: 	 * 2) If target doesn't exist, link the target
 909: 	 *    to the source and unlink the source.
 910: 	 *    Otherwise, rewrite the target directory
 911: 	 *    entry to reference the source inode and
 912: 	 *    expunge the original entry's existence.
 913: 	 */
 914:     if (xp == NULL) {
 915:         if (dp->i_dev != ip->i_dev) {
 916:             error = EXDEV;
 917:             goto bad;
 918:         }
 919:         /*
 920: 		 * Account for ".." in new directory.
 921: 		 * When source and destination have the same
 922: 		 * parent we don't fool with the link count.
 923: 		 */
 924:         if (doingdirectory && newparent) {
 925:             dp->i_nlink++;
 926:             dp->i_flag |= ICHG;
 927:             iupdat(dp, &time, &time, 1);
 928:         }
 929:         error = direnter(ip, ndp);
 930:         if (error)
 931:             goto out;
 932:     } else {
 933:         if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
 934:             error = EXDEV;
 935:             goto bad;
 936:         }
 937:         /*
 938: 		 * Short circuit rename(foo, foo).
 939: 		 */
 940:         if (xp->i_number == ip->i_number)
 941:             goto bad;
 942:         /*
 943: 		 * If the parent directory is "sticky", then the user must
 944: 		 * own the parent directory, or the destination of the rename,
 945: 		 * otherwise the destination may not be changed (except by
 946: 		 * root). This implements append-only directories.
 947: 		 */
 948:         if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
 949:             u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
 950:             error = EPERM;
 951:             goto bad;
 952:         }
 953:         /*
 954: 		 * Target must be empty if a directory
 955: 		 * and have no links to it.
 956: 		 * Also, insure source and target are
 957: 		 * compatible (both directories, or both
 958: 		 * not directories).
 959: 		 */
 960:         if ((xp->i_mode&IFMT) == IFDIR) {
 961:             if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
 962:                 error = ENOTEMPTY;
 963:                 goto bad;
 964:             }
 965:             if (!doingdirectory) {
 966:                 error = ENOTDIR;
 967:                 goto bad;
 968:             }
 969:             cacheinval(dp);
 970:         } else if (doingdirectory) {
 971:             error = EISDIR;
 972:             goto bad;
 973:         }
 974:         dirrewrite(dp, ip, ndp);
 975:         if (u.u_error) {
 976:             error = u.u_error;
 977:             goto bad1;
 978:         }
 979:         /*
 980: 		 * Adjust the link count of the target to
 981: 		 * reflect the dirrewrite above.  If this is
 982: 		 * a directory it is empty and there are
 983: 		 * no links to it, so we can squash the inode and
 984: 		 * any space associated with it.  We disallowed
 985: 		 * renaming over top of a directory with links to
 986: 		 * it above, as the remaining link would point to
 987: 		 * a directory without "." or ".." entries.
 988: 		 */
 989:         xp->i_nlink--;
 990:         if (doingdirectory) {
 991:             if (--xp->i_nlink != 0)
 992:                 panic("rename: linked directory");
 993:             itrunc(xp, (u_long)0);
 994:         }
 995:         xp->i_flag |= ICHG;
 996:         iput(xp);
 997:         xp = NULL;
 998:     }
 999: 
1000:     /*
1001: 	 * 3) Unlink the source.
1002: 	 */
1003:     ndp->ni_nameiop = DELETE | LOCKPARENT;
1004:     ndp->ni_segflg = UIO_USERSPACE;
1005:     ndp->ni_dirp = uap->from;
1006:     xp = namei(ndp);
1007:     if (xp != NULL)
1008:         dp = ndp->ni_pdir;
1009:     else
1010:         dp = NULL;
1011:     /*
1012: 	 * Insure that the directory entry still exists and has not
1013: 	 * changed while the new name has been entered. If the source is
1014: 	 * a file then the entry may have been unlinked or renamed. In
1015: 	 * either case there is no further work to be done. If the source
1016: 	 * is a directory then it cannot have been rmdir'ed; its link
1017: 	 * count of three would cause a rmdir to fail with ENOTEMPTY.
1018: 	 * The IRENAME flag insures that it cannot be moved by another
1019: 	 * rename.
1020: 	 */
1021:     if (xp != ip) {
1022:         if (doingdirectory)
1023:             panic("rename: lost dir entry");
1024:     } else {
1025:         /*
1026: 		 * If the source is a directory with a
1027: 		 * new parent, the link count of the old
1028: 		 * parent directory must be decremented
1029: 		 * and ".." set to point to the new parent.
1030: 		 */
1031:         if (doingdirectory && newparent) {
1032:             dp->i_nlink--;
1033:             dp->i_flag |= ICHG;
1034:             error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
1035:                 sizeof (struct dirtemplate), (off_t)0, 1,
1036:                 (int *)0);
1037:             if (error == 0) {
1038:                 if (dirbuf.dotdot_namlen != 2 ||
1039:                     dirbuf.dotdot_name[0] != '.' ||
1040:                     dirbuf.dotdot_name[1] != '.') {
1041:                     printf("rename: mangled dir\n");
1042:                 } else {
1043:                     dirbuf.dotdot_ino = newparent;
1044:                     (void) rdwri(UIO_WRITE, xp,
1045:                         (caddr_t)&dirbuf,
1046:                         sizeof (struct dirtemplate),
1047:                         (off_t)0, 1, (int *)0);
1048:                     cacheinval(dp);
1049:                 }
1050:             }
1051:         }
1052:         if (dirremove(ndp)) {
1053:             xp->i_nlink--;
1054:             xp->i_flag |= ICHG;
1055:         }
1056:         xp->i_flag &= ~IRENAME;
1057:         if (error == 0)     /* XXX conservative */
1058:             error = u.u_error;
1059:     }
1060:     if (dp)
1061:         iput(dp);
1062:     if (xp)
1063:         iput(xp);
1064:     irele(ip);
1065:     if (error)
1066:         u.u_error = error;
1067:     return;
1068: 
1069: bad:
1070:     iput(dp);
1071: bad1:
1072:     if (xp)
1073:         iput(xp);
1074: out:
1075:     ip->i_nlink--;
1076:     ip->i_flag |= ICHG;
1077:     irele(ip);
1078:     if (error)
1079:         u.u_error = error;
1080: }
1081: 
1082: /*
1083:  * Make a new file.
1084:  */
1085: struct inode *
1086: maknode(mode, ndp)
1087:     int mode;
1088:     register struct nameidata *ndp;
1089: {
1090:     register struct inode *ip;
1091:     register struct inode *pdir = ndp->ni_pdir;
1092:     ino_t ipref;
1093: 
1094:     if ((mode & IFMT) == IFDIR)
1095:         ipref = dirpref(pdir->i_fs);
1096:     else
1097:         ipref = pdir->i_number;
1098:     ip = ialloc(pdir, ipref, mode);
1099:     if (ip == NULL) {
1100:         iput(pdir);
1101:         return (NULL);
1102:     }
1103: #ifdef QUOTA
1104:     if (ip->i_dquot != NODQUOT)
1105:         panic("maknode: dquot");
1106: #endif
1107:     ip->i_flag |= IACC|IUPD|ICHG;
1108:     if ((mode & IFMT) == 0)
1109:         mode |= IFREG;
1110:     ip->i_mode = mode & ~u.u_cmask;
1111:     ip->i_nlink = 1;
1112:     ip->i_uid = u.u_uid;
1113:     ip->i_gid = pdir->i_gid;
1114:     if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
1115:         ip->i_mode &= ~ISGID;
1116: #ifdef QUOTA
1117:     ip->i_dquot = inoquota(ip);
1118: #endif
1119: 
1120:     /*
1121: 	 * Make sure inode goes to disk before directory entry.
1122: 	 */
1123:     iupdat(ip, &time, &time, 1);
1124:     u.u_error = direnter(ip, ndp);
1125:     if (u.u_error) {
1126:         /*
1127: 		 * Write error occurred trying to update directory
1128: 		 * so must deallocate the inode.
1129: 		 */
1130:         ip->i_nlink = 0;
1131:         ip->i_flag |= ICHG;
1132:         iput(ip);
1133:         return (NULL);
1134:     }
1135:     return (ip);
1136: }
1137: 
1138: /*
1139:  * A virgin directory (no blushing please).
1140:  */
1141: struct dirtemplate mastertemplate = {
1142:     0, 12, 1, ".",
1143:     0, DIRBLKSIZ - 12, 2, ".."
1144: };
1145: 
1146: /*
1147:  * Mkdir system call
1148:  */
1149: mkdir()
1150: {
1151:     struct a {
1152:         char    *name;
1153:         int dmode;
1154:     } *uap = (struct a *)u.u_ap;
1155:     register struct inode *ip, *dp;
1156:     struct dirtemplate dirtemplate;
1157:     register struct nameidata *ndp = &u.u_nd;
1158: 
1159:     ndp->ni_nameiop = CREATE;
1160:     ndp->ni_segflg = UIO_USERSPACE;
1161:     ndp->ni_dirp = uap->name;
1162:     ip = namei(ndp);
1163:     if (u.u_error)
1164:         return;
1165:     if (ip != NULL) {
1166:         iput(ip);
1167:         u.u_error = EEXIST;
1168:         return;
1169:     }
1170:     dp = ndp->ni_pdir;
1171:     uap->dmode &= 0777;
1172:     uap->dmode |= IFDIR;
1173:     /*
1174: 	 * Must simulate part of maknode here
1175: 	 * in order to acquire the inode, but
1176: 	 * not have it entered in the parent
1177: 	 * directory.  The entry is made later
1178: 	 * after writing "." and ".." entries out.
1179: 	 */
1180:     ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1181:     if (ip == NULL) {
1182:         iput(dp);
1183:         return;
1184:     }
1185: #ifdef QUOTA
1186:     if (ip->i_dquot != NODQUOT)
1187:         panic("mkdir: dquot");
1188: #endif
1189:     ip->i_flag |= IACC|IUPD|ICHG;
1190:     ip->i_mode = uap->dmode & ~u.u_cmask;
1191:     ip->i_nlink = 2;
1192:     ip->i_uid = u.u_uid;
1193:     ip->i_gid = dp->i_gid;
1194: #ifdef QUOTA
1195:     ip->i_dquot = inoquota(ip);
1196: #endif
1197:     iupdat(ip, &time, &time, 1);
1198: 
1199:     /*
1200: 	 * Bump link count in parent directory
1201: 	 * to reflect work done below.  Should
1202: 	 * be done before reference is created
1203: 	 * so reparation is possible if we crash.
1204: 	 */
1205:     dp->i_nlink++;
1206:     dp->i_flag |= ICHG;
1207:     iupdat(dp, &time, &time, 1);
1208: 
1209:     /*
1210: 	 * Initialize directory with "."
1211: 	 * and ".." from static template.
1212: 	 */
1213:     dirtemplate = mastertemplate;
1214:     dirtemplate.dot_ino = ip->i_number;
1215:     dirtemplate.dotdot_ino = dp->i_number;
1216:     u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1217:         sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1218:     if (u.u_error) {
1219:         dp->i_nlink--;
1220:         dp->i_flag |= ICHG;
1221:         goto bad;
1222:     }
1223:     if (DIRBLKSIZ > ip->i_fs->fs_fsize)
1224:         panic("mkdir: blksize");     /* XXX - should grow with bmap() */
1225:     else
1226:         ip->i_size = DIRBLKSIZ;
1227:     /*
1228: 	 * Directory all set up, now
1229: 	 * install the entry for it in
1230: 	 * the parent directory.
1231: 	 */
1232:     u.u_error = direnter(ip, ndp);
1233:     dp = NULL;
1234:     if (u.u_error) {
1235:         ndp->ni_nameiop = LOOKUP | NOCACHE;
1236:         ndp->ni_segflg = UIO_USERSPACE;
1237:         ndp->ni_dirp = uap->name;
1238:         dp = namei(ndp);
1239:         if (dp) {
1240:             dp->i_nlink--;
1241:             dp->i_flag |= ICHG;
1242:         }
1243:     }
1244: bad:
1245:     /*
1246: 	 * No need to do an explicit itrunc here,
1247: 	 * irele will do this for us because we set
1248: 	 * the link count to 0.
1249: 	 */
1250:     if (u.u_error) {
1251:         ip->i_nlink = 0;
1252:         ip->i_flag |= ICHG;
1253:     }
1254:     if (dp)
1255:         iput(dp);
1256:     iput(ip);
1257: }
1258: 
1259: /*
1260:  * Rmdir system call.
1261:  */
1262: rmdir()
1263: {
1264:     struct a {
1265:         char    *name;
1266:     } *uap = (struct a *)u.u_ap;
1267:     register struct inode *ip, *dp;
1268:     register struct nameidata *ndp = &u.u_nd;
1269: 
1270:     ndp->ni_nameiop = DELETE | LOCKPARENT;
1271:     ndp->ni_segflg = UIO_USERSPACE;
1272:     ndp->ni_dirp = uap->name;
1273:     ip = namei(ndp);
1274:     if (ip == NULL)
1275:         return;
1276:     dp = ndp->ni_pdir;
1277:     /*
1278: 	 * No rmdir "." please.
1279: 	 */
1280:     if (dp == ip) {
1281:         irele(dp);
1282:         iput(ip);
1283:         u.u_error = EINVAL;
1284:         return;
1285:     }
1286:     if ((ip->i_mode&IFMT) != IFDIR) {
1287:         u.u_error = ENOTDIR;
1288:         goto out;
1289:     }
1290:     /*
1291: 	 * Don't remove a mounted on directory.
1292: 	 */
1293:     if (ip->i_dev != dp->i_dev) {
1294:         u.u_error = EBUSY;
1295:         goto out;
1296:     }
1297:     /*
1298: 	 * Verify the directory is empty (and valid).
1299: 	 * (Rmdir ".." won't be valid since
1300: 	 *  ".." will contain a reference to
1301: 	 *  the current directory and thus be
1302: 	 *  non-empty.)
1303: 	 */
1304:     if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
1305:         u.u_error = ENOTEMPTY;
1306:         goto out;
1307:     }
1308:     /*
1309: 	 * Delete reference to directory before purging
1310: 	 * inode.  If we crash in between, the directory
1311: 	 * will be reattached to lost+found,
1312: 	 */
1313:     if (dirremove(ndp) == 0)
1314:         goto out;
1315:     dp->i_nlink--;
1316:     dp->i_flag |= ICHG;
1317:     cacheinval(dp);
1318:     iput(dp);
1319:     dp = NULL;
1320:     /*
1321: 	 * Truncate inode.  The only stuff left
1322: 	 * in the directory is "." and "..".  The
1323: 	 * "." reference is inconsequential since
1324: 	 * we're quashing it.  The ".." reference
1325: 	 * has already been adjusted above.  We've
1326: 	 * removed the "." reference and the reference
1327: 	 * in the parent directory, but there may be
1328: 	 * other hard links so decrement by 2 and
1329: 	 * worry about them later.
1330: 	 */
1331:     ip->i_nlink -= 2;
1332:     itrunc(ip, (u_long)0);
1333:     cacheinval(ip);
1334: out:
1335:     if (dp)
1336:         iput(dp);
1337:     iput(ip);
1338: }
1339: 
1340: struct file *
1341: getinode(fdes)
1342:     int fdes;
1343: {
1344:     struct file *fp;
1345: 
1346:     if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
1347:         u.u_error = EBADF;
1348:         return ((struct file *)0);
1349:     }
1350:     if (fp->f_type != DTYPE_INODE) {
1351:         u.u_error = EINVAL;
1352:         return ((struct file *)0);
1353:     }
1354:     return (fp);
1355: }
1356: 
1357: /*
1358:  * mode mask for creation of files
1359:  */
1360: umask()
1361: {
1362:     register struct a {
1363:         int mask;
1364:     } *uap = (struct a *)u.u_ap;
1365: 
1366:     u.u_r.r_val1 = u.u_cmask;
1367:     u.u_cmask = uap->mask & 07777;
1368: }

Defined functions

chdir defined in line 32; used 2 times
chdirec defined in line 51; used 2 times
chmod defined in line 530; used 4 times
chmod1 defined in line 571; used 2 times
chown defined in line 595; used 2 times
chown1 defined in line 636; used 2 times
chroot defined in line 41; used 2 times
copen defined in line 114; used 2 times
creat defined in line 99; used 2 times
fchmod defined in line 547; used 2 times
fchown defined in line 613; used 2 times
fsync defined in line 768; used 2 times
ftruncate defined in line 743; used 2 times
getinode defined in line 1340; used 9 times
link defined in line 248; used 2 times
lseek defined in line 386; never used
lstat defined in line 468; used 2 times
maknode defined in line 1085; used 6 times
mkdir defined in line 1149; used 2 times
mknod defined in line 201; used 2 times
open defined in line 85; never used
readlink defined in line 499; used 2 times
rename defined in line 812; used 2 times
rmdir defined in line 1262; used 2 times
saccess defined in line 424; used 2 times
stat defined in line 459; used 4 times
stat1 defined in line 474; used 2 times
symlink defined in line 299; used 2 times
sync defined in line 705; used 2 times
truncate defined in line 714; used 2 times
umask defined in line 1360; used 2 times
unlink defined in line 345; used 2 times
utimes defined in line 678; used 2 times

Defined variables

mastertemplate defined in line 1141; used 1 times

Defined struct's

a defined in line 1362; used 46 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2878
Valid CSS Valid XHTML 1.0 Strict