1 /* ffs_vnops.c 4.30 82/07/24 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/file.h" 8 #include "../h/stat.h" 9 #include "../h/inode.h" 10 #include "../h/fs.h" 11 #include "../h/buf.h" 12 #include "../h/proc.h" 13 #include "../h/inline.h" 14 #ifdef EFS 15 #include "../net/in.h" 16 #include "../h/efs.h" 17 #endif 18 #include "../h/quota.h" 19 #include "../h/descrip.h" 20 21 chdir() 22 { 23 24 chdirec(&u.u_cdir); 25 } 26 27 chroot() 28 { 29 30 if (suser()) 31 chdirec(&u.u_rdir); 32 } 33 34 chdirec(ipp) 35 register struct inode **ipp; 36 { 37 register struct inode *ip; 38 struct a { 39 char *fname; 40 }; 41 42 ip = namei(uchar, 0, 1); 43 if(ip == NULL) 44 return; 45 if((ip->i_mode&IFMT) != IFDIR) { 46 u.u_error = ENOTDIR; 47 goto bad; 48 } 49 if(access(ip, IEXEC)) 50 goto bad; 51 iunlock(ip); 52 if (*ipp) 53 irele(*ipp); 54 *ipp = ip; 55 return; 56 57 bad: 58 iput(ip); 59 } 60 61 /* 62 * Open system call. 63 */ 64 open() 65 { 66 register struct inode *ip; 67 register struct a { 68 char *fname; 69 int rwmode; 70 } *uap; 71 72 uap = (struct a *)u.u_ap; 73 ip = namei(uchar, 0, 1); 74 if (ip == NULL) 75 return; 76 open1(ip, ++uap->rwmode, 0); 77 } 78 79 /* 80 * Creat system call. 81 */ 82 ocreat() 83 { 84 register struct inode *ip; 85 register struct a { 86 char *fname; 87 int fmode; 88 } *uap; 89 90 uap = (struct a *)u.u_ap; 91 ip = namei(uchar, 1, 1); 92 if (ip == NULL) { 93 if (u.u_error) 94 return; 95 ip = maknode(uap->fmode&07777&(~ISVTX)); 96 if (ip==NULL) 97 return; 98 open1(ip, FWRITE, 2); 99 } else 100 open1(ip, FWRITE, 1); 101 } 102 103 /* 104 * Common code for open and creat. 105 * Check permissions, allocate an open file structure, 106 * and call the device open routine if any. 107 */ 108 open1(ip, mode, trf) 109 register struct inode *ip; 110 register mode; 111 { 112 register struct file *fp; 113 int i; 114 115 if (trf != 2) { 116 if (mode&FREAD) 117 (void) access(ip, IREAD); 118 if (mode&FWRITE) { 119 (void) access(ip, IWRITE); 120 if ((ip->i_mode&IFMT) == IFDIR) 121 u.u_error = EISDIR; 122 } 123 } 124 if (u.u_error) { 125 iput(ip); 126 return; 127 } 128 if (trf == 1) 129 itrunc(ip); 130 iunlock(ip); 131 if ((fp = falloc()) == NULL) 132 goto out; 133 fp->f_flag = mode&(FREAD|FWRITE); 134 fp->f_type = DTYPE_FILE; 135 i = u.u_r.r_val1; 136 fp->f_inode = ip; 137 #ifdef EFS 138 openi(ip, mode&(FREAD|FWRITE), trf); 139 #else 140 openi(ip, mode&(FREAD|FWRITE)); 141 #endif 142 if (u.u_error == 0) 143 return; 144 u.u_ofile[i] = NULL; 145 fp->f_count--; 146 out: 147 irele(ip); 148 } 149 150 /* 151 * Mknod system call 152 */ 153 mknod() 154 { 155 register struct inode *ip; 156 register struct a { 157 char *fname; 158 int fmode; 159 int dev; 160 } *uap; 161 162 uap = (struct a *)u.u_ap; 163 if (suser()) { 164 ip = namei(uchar, 1, 0); 165 if (ip != NULL) { 166 u.u_error = EEXIST; 167 goto out; 168 } 169 } 170 if (u.u_error) 171 return; 172 ip = maknode(uap->fmode); 173 if (ip == NULL) 174 return; 175 if (uap->dev) { 176 /* 177 * Want to be able to use this to make badblock 178 * inodes, so don't truncate the dev number. 179 */ 180 ip->i_rdev = uap->dev; 181 ip->i_flag |= IACC|IUPD|ICHG; 182 } 183 184 out: 185 iput(ip); 186 } 187 188 /* 189 * link system call 190 */ 191 link() 192 { 193 register struct inode *ip, *xp; 194 register struct a { 195 char *target; 196 char *linkname; 197 } *uap; 198 199 uap = (struct a *)u.u_ap; 200 ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */ 201 if (ip == NULL) 202 return; 203 if ((ip->i_mode&IFMT)==IFDIR && !suser()) { 204 iput(ip); 205 return; 206 } 207 ip->i_nlink++; 208 ip->i_flag |= ICHG; 209 iupdat(ip, &time, &time, 1); 210 iunlock(ip); 211 u.u_dirp = (caddr_t)uap->linkname; 212 xp = namei(uchar, 1, 0); 213 if (xp != NULL) { 214 u.u_error = EEXIST; 215 iput(xp); 216 goto out; 217 } 218 if (u.u_error) 219 goto out; 220 if (u.u_pdir->i_dev != ip->i_dev) { 221 iput(u.u_pdir); 222 u.u_error = EXDEV; 223 goto out; 224 } 225 wdir(ip); 226 out: 227 if (u.u_error) { 228 ip->i_nlink--; 229 ip->i_flag |= ICHG; 230 } 231 out1: 232 irele(ip); 233 } 234 235 /* 236 * symlink -- make a symbolic link 237 */ 238 symlink() 239 { 240 register struct a { 241 char *target; 242 char *linkname; 243 } *uap; 244 register struct inode *ip; 245 register char *tp; 246 register c, nc; 247 248 uap = (struct a *)u.u_ap; 249 tp = uap->target; 250 nc = 0; 251 while (c = fubyte(tp)) { 252 if (c < 0) { 253 u.u_error = EFAULT; 254 return; 255 } 256 tp++; 257 nc++; 258 } 259 u.u_dirp = uap->linkname; 260 ip = namei(uchar, 1, 0); 261 if (ip) { 262 iput(ip); 263 u.u_error = EEXIST; 264 return; 265 } 266 if (u.u_error) 267 return; 268 ip = maknode(IFLNK | 0777); 269 if (ip == NULL) 270 return; 271 u.u_base = uap->target; 272 u.u_count = nc; 273 u.u_offset = 0; 274 u.u_segflg = 0; 275 writei(ip); 276 iput(ip); 277 } 278 279 /* 280 * Unlink system call. 281 * Hard to avoid races here, especially 282 * in unlinking directories. 283 */ 284 unlink() 285 { 286 register struct inode *ip, *pp; 287 struct a { 288 char *fname; 289 }; 290 struct fs *fs; 291 struct buf *bp; 292 int lbn, bn, base; 293 int unlinkingdot = 0; 294 295 pp = namei(uchar, 2, 0); 296 if(pp == NULL) 297 return; 298 #ifdef EFS 299 /* divert to extended file system if off machine. */ 300 if (efsinode(pp)) { 301 dev_t ndev = pp->i_rdev; 302 303 iput(pp); /* avoid recursive hang on inode */ 304 efsunlink(ndev); 305 if (u.u_error != EEXIST) 306 return; 307 308 /* 309 * If a null pathname remainder, then do 310 * the unlink locally after restoring state. 311 */ 312 u.u_error = 0; 313 u.u_dirp = (caddr_t)u.u_arg[0]; 314 pp = namei(uchar, 2, 0); 315 } 316 #endif 317 318 /* 319 * Check for unlink(".") 320 * to avoid hanging on the iget 321 */ 322 if (pp->i_number == u.u_dent.d_ino) { 323 ip = pp; 324 ip->i_count++; 325 unlinkingdot++; 326 } else 327 ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino); 328 if(ip == NULL) 329 goto out1; 330 if((ip->i_mode&IFMT)==IFDIR && !suser()) 331 goto out; 332 /* 333 * Don't unlink a mounted file. 334 */ 335 if (ip->i_dev != pp->i_dev) { 336 u.u_error = EBUSY; 337 goto out; 338 } 339 if (ip->i_flag&ITEXT) 340 xrele(ip); /* try once to free text */ 341 /* 342 if ((ip->i_flag&ITEXT) && ip->i_nlink==1) { 343 u.u_error = ETXTBSY; 344 goto out; 345 } 346 */ 347 if (u.u_count == 0) { 348 /* 349 * first entry in block, so set d_ino to zero. 350 */ 351 /*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n" 352 /*ZZ*/,pp->i_fs->fs_fsmnt,pp->i_number,u.u_offset,u.u_dent.d_name); 353 u.u_base = (caddr_t)&u.u_dent; 354 u.u_count = DIRSIZ(&u.u_dent); 355 u.u_dent.d_ino = 0; 356 writei(pp); 357 } else { 358 /* 359 * updating preceeding entry to skip over current entry. 360 */ 361 fs = pp->i_fs; 362 lbn = lblkno(fs, u.u_offset); 363 base = blkoff(fs, u.u_offset); 364 bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count)); 365 bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn)); 366 if (bp->b_flags & B_ERROR) { 367 brelse(bp); 368 goto out; 369 } 370 ((struct direct *)(bp->b_un.b_addr + base))->d_reclen += 371 u.u_dent.d_reclen; 372 /*ZZ*/if(((int)(bp->b_un.b_addr + base)&0x1ff)+u.u_dent.d_reclen>512) 373 /*ZZ*/ panic("unlink: reclen"); 374 bwrite(bp); 375 pp->i_flag |= IUPD|ICHG; 376 } 377 ip->i_nlink--; 378 ip->i_flag |= ICHG; 379 380 out: 381 if (unlinkingdot) 382 irele(ip); 383 else 384 iput(ip); 385 out1: 386 iput(pp); 387 } 388 389 /* 390 * Seek system call 391 */ 392 seek() 393 { 394 register struct file *fp; 395 register struct a { 396 int fdes; 397 off_t off; 398 int sbase; 399 } *uap; 400 401 uap = (struct a *)u.u_ap; 402 fp = getf(uap->fdes); 403 if (fp == NULL) 404 return; 405 if (fp->f_type == DTYPE_SOCKET) { 406 u.u_error = ESPIPE; 407 return; 408 } 409 if (uap->sbase == 1) 410 uap->off += fp->f_offset; 411 else if (uap->sbase == 2) { 412 #ifdef EFS 413 struct inode *ip = fp->f_inode; 414 uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size; 415 #else 416 uap->off += fp->f_inode->i_size; 417 #endif 418 } 419 fp->f_offset = uap->off; 420 u.u_r.r_off = uap->off; 421 } 422 423 /* 424 * Access system call 425 */ 426 saccess() 427 { 428 register svuid, svgid; 429 register struct inode *ip; 430 register struct a { 431 char *fname; 432 int fmode; 433 } *uap; 434 435 uap = (struct a *)u.u_ap; 436 svuid = u.u_uid; 437 svgid = u.u_gid; 438 u.u_uid = u.u_ruid; 439 u.u_gid = u.u_rgid; 440 ip = namei(uchar, 0, 1); 441 #ifdef EFS 442 if (efsinode(ip)) { 443 dev_t ndev = ip->i_rdev; 444 445 iput(ip); 446 efssaccess(ndev); 447 if (u.u_error != EEXIST) 448 return; 449 u.u_error = 0; 450 u.u_dirp = (caddr_t)u.u_arg[0]; 451 ip = namei(uchar, 0, 1); 452 } 453 #endif 454 if (ip != NULL) { 455 if (uap->fmode&(IREAD>>6)) 456 (void) access(ip, IREAD); 457 if (uap->fmode&(IWRITE>>6)) 458 (void) access(ip, IWRITE); 459 if (uap->fmode&(IEXEC>>6)) 460 (void) access(ip, IEXEC); 461 iput(ip); 462 } 463 u.u_uid = svuid; 464 u.u_gid = svgid; 465 } 466 467 /* 468 * the fstat system call. 469 */ 470 fstat() 471 { 472 register struct file *fp; 473 register struct a { 474 int fdes; 475 struct stat *sb; 476 } *uap; 477 478 uap = (struct a *)u.u_ap; 479 fp = getf(uap->fdes); 480 if (fp == NULL) 481 return; 482 #ifdef EFS 483 if (efsinode(fp->f_inode)) { 484 efsfstat(fp->f_inode->i_rdev, fp); 485 return; 486 } 487 #endif 488 if (fp->f_type == DTYPE_SOCKET) 489 u.u_error = sostat(fp->f_socket, uap->sb); 490 else 491 stat1(fp->f_inode, uap->sb); 492 } 493 494 /* 495 * Stat system call. This version follows links. 496 */ 497 stat() 498 { 499 register struct inode *ip; 500 register struct a { 501 char *fname; 502 struct stat *sb; 503 } *uap; 504 505 uap = (struct a *)u.u_ap; 506 ip = namei(uchar, 0, 1); 507 if (ip == NULL) 508 return; 509 #ifdef EFS 510 if (efsinode(ip)) { 511 dev_t ndev = ip->i_rdev; 512 513 iput(ip); 514 efsstat(ndev); 515 if (u.u_error != EEXIST) 516 return; 517 u.u_error = 0; 518 u.u_dirp = (caddr_t)u.u_arg[0]; 519 ip = namei(uchar, 0, 1); 520 } 521 #endif 522 stat1(ip, uap->sb); 523 iput(ip); 524 } 525 526 /* 527 * Lstat system call. This version does not follow links. 528 */ 529 lstat() 530 { 531 register struct inode *ip; 532 register struct a { 533 char *fname; 534 struct stat *sb; 535 } *uap; 536 537 uap = (struct a *)u.u_ap; 538 ip = namei(uchar, 0, 0); 539 if (ip == NULL) 540 return; 541 #ifdef EFS 542 if (efsinode(ip)) { 543 dev_t ndev = ip->i_rdev; 544 545 iput(ip); 546 efslstat(ndev); 547 if (u.u_error != EEXIST) 548 return; 549 u.u_error = 0; 550 u.u_dirp = (caddr_t)u.u_arg[0]; 551 ip = namei(uchar, 0, 0); 552 } 553 #endif 554 stat1(ip, uap->sb); 555 iput(ip); 556 } 557 558 /* 559 * The basic routine for fstat and stat: 560 * get the inode and pass appropriate parts back. 561 */ 562 stat1(ip, ub) 563 register struct inode *ip; 564 struct stat *ub; 565 { 566 struct stat ds; 567 568 IUPDAT(ip, &time, &time, 0); 569 /* 570 * Copy from inode table 571 */ 572 ds.st_dev = ip->i_dev; 573 ds.st_ino = ip->i_number; 574 ds.st_mode = ip->i_mode; 575 ds.st_nlink = ip->i_nlink; 576 ds.st_uid = ip->i_uid; 577 ds.st_gid = ip->i_gid; 578 ds.st_rdev = (dev_t)ip->i_rdev; 579 ds.st_size = ip->i_size; 580 ds.st_atime = ip->i_atime; 581 ds.st_mtime = ip->i_mtime; 582 ds.st_ctime = ip->i_ctime; 583 ds.st_blksize = ip->i_fs->fs_bsize; 584 if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) 585 u.u_error = EFAULT; 586 } 587 588 /* 589 * Return target name of a symbolic link 590 */ 591 readlink() 592 { 593 register struct inode *ip; 594 register struct a { 595 char *name; 596 char *buf; 597 int count; 598 } *uap; 599 600 ip = namei(uchar, 0, 0); 601 if (ip == NULL) 602 return; 603 #ifdef EFS 604 if (efsinode(ip)) { 605 dev_t ndev = ip->i_rdev; 606 607 iput(ip); 608 efsreadlink(ndev); 609 if (u.u_error != EEXIST) 610 return; 611 u.u_error = 0; 612 u.u_dirp = (caddr_t)u.u_arg[0]; 613 ip = namei(uchar, 0, 0); 614 return (0); 615 } 616 #endif 617 if ((ip->i_mode&IFMT) != IFLNK) { 618 u.u_error = ENXIO; 619 goto out; 620 } 621 uap = (struct a *)u.u_ap; 622 u.u_offset = 0; 623 u.u_base = uap->buf; 624 u.u_count = uap->count; 625 u.u_segflg = 0; 626 readi(ip); 627 out: 628 iput(ip); 629 u.u_r.r_val1 = uap->count - u.u_count; 630 } 631 632 chmod() 633 { 634 register struct inode *ip; 635 register struct a { 636 char *fname; 637 int fmode; 638 } *uap; 639 640 uap = (struct a *)u.u_ap; 641 if ((ip = owner(1)) == NULL) 642 return; 643 #ifdef EFS 644 if (efsinode(ip)) { 645 dev_t ndev = ip->i_rdev; 646 647 iput(ip); 648 efschmod(ndev); 649 if (u.u_error != EEXIST) 650 return; 651 u.u_error = 0; 652 u.u_dirp = (caddr_t)u.u_arg[0]; 653 ip = owner(1); 654 } 655 #endif 656 ip->i_mode &= ~07777; 657 if (u.u_uid) { 658 uap->fmode &= ~ISVTX; 659 if (ip->i_gid >= NGRPS || 660 (u.u_grps[ip->i_gid/(sizeof(int)*8)] & 661 (1 << ip->i_gid%(sizeof(int)*8))) == 0) 662 uap->fmode &= ~ISGID; 663 #if MUSH 664 if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 && 665 (ip->i_mode & IFMT) != IFCHR) 666 uap->fmode &= ~u.u_cmask; 667 #endif 668 } 669 ip->i_mode |= uap->fmode&07777; 670 ip->i_flag |= ICHG; 671 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 672 xrele(ip); 673 #ifdef MELB 674 if ((ip->i_mode & ISUID) && ip->i_uid == 0) 675 printf("%s: ino %d (%s) setuid root\n" 676 , getfs(ip->i_dev)->s_fsmnt 677 , ip->i_number 678 , u.u_dent.d_name 679 ); 680 #endif 681 iput(ip); 682 } 683 684 chown() 685 { 686 register struct inode *ip; 687 register struct a { 688 char *fname; 689 int uid; 690 int gid; 691 } *uap; 692 #if QUOTA 693 register long change; 694 #endif 695 696 uap = (struct a *)u.u_ap; 697 if (!suser() || (ip = owner(0)) == NULL) 698 return; 699 #ifdef EFS 700 if (efsinode(ip)) { 701 dev_t ndev = ip->i_rdev; 702 703 iput(ip); 704 efschown(ndev); 705 if (u.u_error != EEXIST) 706 return; 707 u.u_error = 0; 708 u.u_dirp = (caddr_t)u.u_arg[0]; 709 ip = owner(0); 710 } 711 #endif 712 #if QUOTA 713 /* 714 * This doesn't allow for holes in files (which hopefully don't 715 * happen often in files that we chown), and is not accurate anyway 716 * (eg: it totally ignores 3 level indir blk files - but hopefully 717 * noone who can make a file that big will have a quota) 718 */ 719 if (ip->i_uid == uap->uid) 720 change = 0; 721 else { 722 register struct fs *fs = ip->i_fs; 723 724 if (ip->i_size > (change = NDADDR * fs->fs_bsize)) { 725 register off_t size; 726 727 size = blkroundup(fs, ip->i_size) - change; 728 change += size; 729 change += fs->fs_bsize; 730 /* This assumes NIADDR <= 2 */ 731 if (size > NINDIR(fs) * fs->fs_bsize) 732 change += fs->fs_bsize; 733 } else 734 change = fragroundup(fs, ip->i_size); 735 change /= DEV_BSIZE; 736 } 737 chkdq(ip, -change, 1); 738 chkiq(ip->i_dev, ip, ip->i_uid, 1); 739 dqrele(ip->i_dquot); 740 #endif 741 /* 742 * keep uid/gid's in sane range - no err, so chown(file, uid, -1) 743 * will do something useful 744 */ 745 if (uap->uid >= 0 && uap->uid <= 32767) /* should have a const */ 746 ip->i_uid = uap->uid; 747 if (uap->gid >= 0 && uap->gid <= 32767) /* same here */ 748 ip->i_gid = uap->gid; 749 ip->i_flag |= ICHG; 750 if (u.u_ruid != 0) 751 ip->i_mode &= ~(ISUID|ISGID); 752 #if QUOTA 753 ip->i_dquot = inoquota(ip); 754 chkdq(ip, change, 1); 755 chkiq(ip->i_dev, NULL, uap->uid, 1); 756 #endif 757 iput(ip); 758 } 759 760 /* 761 * Set IUPD and IACC times on file. 762 * Can't set ICHG. 763 */ 764 utime() 765 { 766 register struct a { 767 char *fname; 768 time_t *tptr; 769 } *uap; 770 register struct inode *ip; 771 time_t tv[2]; 772 773 uap = (struct a *)u.u_ap; 774 if ((ip = owner(1)) == NULL) 775 return; 776 if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { 777 u.u_error = EFAULT; 778 } else { 779 #ifdef EFS 780 if (efsinode(ip)) { 781 dev_t ndev = ip->i_rdev; 782 783 iput(ip); 784 efsutime(ndev, uap->fname, tv); 785 if (u.u_error != EEXIST) 786 return; 787 u.u_error = 0; 788 u.u_dirp = (caddr_t)u.u_arg[0]; 789 ip = owner(1); 790 } 791 #endif 792 ip->i_flag |= IACC|IUPD|ICHG; 793 iupdat(ip, &tv[0], &tv[1], 0); 794 } 795 iput(ip); 796 } 797 798 sync() 799 { 800 801 update(0); 802 } 803