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

Defined functions

chdir defined in line 27; used 2 times
chdirec defined in line 72; used 2 times
chflags defined in line 487; used 2 times
chflags1 defined in line 522; used 2 times
chmod defined in line 536; used 2 times
chmod1 defined in line 582; used 1 times
chown defined in line 606; used 2 times
chown1 defined in line 656; used 1 times
chroot defined in line 62; used 2 times
copen defined in line 120; used 2 times
fchdir defined in line 33; used 2 times
fchflags defined in line 507; used 2 times
fchmod defined in line 560; used 2 times
fchown defined in line 632; used 2 times
ftruncate defined in line 737; used 2 times
getinode defined in line 1345; used 7 times
link defined in line 240; used 2 times
lstat defined in line 427; used 2 times
mkdir defined in line 1150; used 2 times
mknod defined in line 194; used 2 times
open defined in line 105; used 2 times
readlink defined in line 457; used 2 times
rename defined in line 788; used 2 times
rmdir defined in line 1264; used 2 times
saccess defined in line 383; used 2 times
stat defined in line 418; used 2 times
stat1 defined in line 433; used 2 times
symlink defined in line 294; used 2 times
truncate defined in line 710; used 2 times
unlink defined in line 339; used 2 times

Defined variables

mastertemplate defined in line 1142; used 1 times

Defined struct's

a defined in line 1266; used 42 times
Last modified: 2000-02-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 9057
Valid CSS Valid XHTML 1.0 Strict