1*13043Ssam /* vfs_syscalls.c 4.60 83/06/12 */ 237Sbill 337Sbill #include "../h/param.h" 437Sbill #include "../h/systm.h" 537Sbill #include "../h/dir.h" 637Sbill #include "../h/user.h" 78040Sroot #include "../h/kernel.h" 86254Sroot #include "../h/file.h" 96574Smckusic #include "../h/stat.h" 1037Sbill #include "../h/inode.h" 116574Smckusic #include "../h/fs.h" 126254Sroot #include "../h/buf.h" 136254Sroot #include "../h/proc.h" 147482Skre #include "../h/quota.h" 157826Sroot #include "../h/uio.h" 167826Sroot #include "../h/socket.h" 178632Sroot #include "../h/socketvar.h" 189167Ssam #include "../h/nami.h" 1912756Ssam #include "../h/mount.h" 2037Sbill 2112756Ssam extern struct fileops inodeops; 2212756Ssam struct file *getinode(); 2312756Ssam 249167Ssam /* 259167Ssam * Change current working directory (``.''). 269167Ssam */ 276254Sroot chdir() 286254Sroot { 296254Sroot 306254Sroot chdirec(&u.u_cdir); 316254Sroot } 326254Sroot 339167Ssam /* 349167Ssam * Change notion of root (``/'') directory. 359167Ssam */ 366254Sroot chroot() 376254Sroot { 386254Sroot 396254Sroot if (suser()) 406254Sroot chdirec(&u.u_rdir); 416254Sroot } 426254Sroot 439167Ssam /* 449167Ssam * Common routine for chroot and chdir. 459167Ssam */ 466254Sroot chdirec(ipp) 477701Ssam register struct inode **ipp; 486254Sroot { 496254Sroot register struct inode *ip; 506254Sroot struct a { 516254Sroot char *fname; 526254Sroot }; 536254Sroot 549167Ssam ip = namei(uchar, LOOKUP, 1); 559167Ssam if (ip == NULL) 566254Sroot return; 579167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 586254Sroot u.u_error = ENOTDIR; 596254Sroot goto bad; 606254Sroot } 619167Ssam if (access(ip, IEXEC)) 626254Sroot goto bad; 637122Smckusick iunlock(ip); 647142Smckusick if (*ipp) 657142Smckusick irele(*ipp); 666254Sroot *ipp = ip; 676254Sroot return; 686254Sroot 696254Sroot bad: 706254Sroot iput(ip); 716254Sroot } 726254Sroot 7337Sbill /* 746254Sroot * Open system call. 756254Sroot */ 766254Sroot open() 776254Sroot { 7812756Ssam struct a { 796254Sroot char *fname; 807701Ssam int mode; 8112756Ssam int crtmode; 8212756Ssam } *uap = (struct a *) u.u_ap; 836254Sroot 8412756Ssam copen(uap->mode-FOPEN, uap->crtmode); 856254Sroot } 866254Sroot 876254Sroot /* 886254Sroot * Creat system call. 896254Sroot */ 9012756Ssam creat() 916254Sroot { 9212756Ssam struct a { 936254Sroot char *fname; 946254Sroot int fmode; 9512756Ssam } *uap = (struct a *)u.u_ap; 966254Sroot 9712756Ssam copen(FWRITE|FCREAT|FTRUNC, uap->fmode); 986254Sroot } 996254Sroot 1006254Sroot /* 1016254Sroot * Common code for open and creat. 10212756Ssam * Check permissions, allocate an open file structure, 10312756Ssam * and call the device open routine if any. 1046254Sroot */ 10512756Ssam copen(mode, arg) 10612756Ssam register int mode; 10712756Ssam int arg; 10812756Ssam { 1096254Sroot register struct inode *ip; 1106254Sroot register struct file *fp; 11112756Ssam int i; 1126254Sroot 11312756Ssam #ifdef notdef 11412756Ssam if ((mode&(FREAD|FWRITE)) == 0) { 11512756Ssam u.u_error = EINVAL; 11612756Ssam return; 11712756Ssam } 11812756Ssam #endif 11912756Ssam if (mode&FCREAT) { 12012756Ssam ip = namei(uchar, CREATE, 1); 12112756Ssam if (ip == NULL) { 12212756Ssam if (u.u_error) 12312756Ssam return; 12412756Ssam ip = maknode(arg&07777&(~ISVTX)); 12512756Ssam if (ip == NULL) 12612756Ssam return; 12712756Ssam mode &= ~FTRUNC; 12812756Ssam } else { 12912756Ssam if (mode&FEXCL) { 13012756Ssam u.u_error = EEXIST; 13112756Ssam iput(ip); 13212756Ssam return; 13312756Ssam } 13412756Ssam mode &= ~FCREAT; 13512756Ssam } 13612756Ssam } else { 13712756Ssam ip = namei(uchar, LOOKUP, 1); 13812756Ssam if (ip == NULL) 13912756Ssam return; 14012756Ssam } 14112756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 14212756Ssam u.u_error = EOPNOTSUPP; 14312756Ssam goto bad; 14412756Ssam } 14512756Ssam if ((mode&FCREAT) == 0) { 1466254Sroot if (mode&FREAD) 1477701Ssam if (access(ip, IREAD)) 1487701Ssam goto bad; 1496254Sroot if (mode&FWRITE) { 1507701Ssam if (access(ip, IWRITE)) 1517701Ssam goto bad; 1527701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1536254Sroot u.u_error = EISDIR; 1547701Ssam goto bad; 1557701Ssam } 1566254Sroot } 1576254Sroot } 15812756Ssam fp = falloc(); 15912756Ssam if (fp == NULL) 16012756Ssam goto bad; 16112756Ssam if (mode&FTRUNC) 1629167Ssam itrunc(ip, (u_long)0); 1637122Smckusick iunlock(ip); 16412756Ssam fp->f_flag = mode&FMASK; 16512756Ssam fp->f_type = DTYPE_INODE; 16612756Ssam fp->f_ops = &inodeops; 16712756Ssam fp->f_data = (caddr_t)ip; 1686254Sroot i = u.u_r.r_val1; 16912756Ssam #ifdef notdef 17012756Ssam if (setjmp(&u.u_qsave)) { 17112756Ssam if (u.u_error == 0) 17212756Ssam u.u_error = EINTR; 17312756Ssam u.u_ofile[i] = NULL; 17412756Ssam closef(fp); 17512756Ssam return; 17612756Ssam } 17712756Ssam #endif 1788559Sroot u.u_error = openi(ip, mode); 17912756Ssam if (u.u_error == 0) 1806254Sroot return; 1816254Sroot u.u_ofile[i] = NULL; 1826254Sroot fp->f_count--; 1837142Smckusick irele(ip); 1847701Ssam return; 1857701Ssam bad: 1867701Ssam iput(ip); 1876254Sroot } 1886254Sroot 1896254Sroot /* 1906254Sroot * Mknod system call 1916254Sroot */ 1926254Sroot mknod() 1936254Sroot { 1946254Sroot register struct inode *ip; 1956254Sroot register struct a { 1966254Sroot char *fname; 1976254Sroot int fmode; 1986254Sroot int dev; 1996254Sroot } *uap; 2006254Sroot 2016254Sroot uap = (struct a *)u.u_ap; 20212756Ssam if (!suser()) 20312756Ssam return; 20412756Ssam ip = namei(uchar, CREATE, 0); 20512756Ssam if (ip != NULL) { 20612756Ssam u.u_error = EEXIST; 20712756Ssam goto out; 2086254Sroot } 2096254Sroot if (u.u_error) 2106254Sroot return; 2116254Sroot ip = maknode(uap->fmode); 2126254Sroot if (ip == NULL) 2136254Sroot return; 21412756Ssam switch (ip->i_mode & IFMT) { 21512756Ssam 21612756Ssam case IFCHR: 21712756Ssam case IFBLK: 21812756Ssam if (uap->dev) { 21912756Ssam /* 22012756Ssam * Want to be able to use this to make badblock 22112756Ssam * inodes, so don't truncate the dev number. 22212756Ssam */ 22312756Ssam ip->i_rdev = uap->dev; 22412756Ssam ip->i_flag |= IACC|IUPD|ICHG; 22512756Ssam } 2266254Sroot } 2276254Sroot 2286254Sroot out: 2296254Sroot iput(ip); 2306254Sroot } 2316254Sroot 2326254Sroot /* 2336254Sroot * link system call 2346254Sroot */ 2356254Sroot link() 2366254Sroot { 2376254Sroot register struct inode *ip, *xp; 2386254Sroot register struct a { 2396254Sroot char *target; 2406254Sroot char *linkname; 2416254Sroot } *uap; 2426254Sroot 2436254Sroot uap = (struct a *)u.u_ap; 2449167Ssam ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */ 2456254Sroot if (ip == NULL) 2466254Sroot return; 2479167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2487439Sroot iput(ip); 2497439Sroot return; 2507439Sroot } 2516254Sroot ip->i_nlink++; 2526254Sroot ip->i_flag |= ICHG; 2538673Sroot iupdat(ip, &time, &time, 1); 2547122Smckusick iunlock(ip); 2556254Sroot u.u_dirp = (caddr_t)uap->linkname; 2569167Ssam xp = namei(uchar, CREATE, 0); 2576254Sroot if (xp != NULL) { 2586254Sroot u.u_error = EEXIST; 2596254Sroot iput(xp); 2606254Sroot goto out; 2616254Sroot } 2626254Sroot if (u.u_error) 2636254Sroot goto out; 2646254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2656254Sroot iput(u.u_pdir); 2666254Sroot u.u_error = EXDEV; 2676254Sroot goto out; 2686254Sroot } 26910850Ssam u.u_error = direnter(ip); 2706254Sroot out: 2716254Sroot if (u.u_error) { 2726254Sroot ip->i_nlink--; 2736254Sroot ip->i_flag |= ICHG; 2746254Sroot } 2757142Smckusick irele(ip); 2766254Sroot } 2776254Sroot 2786254Sroot /* 2796254Sroot * symlink -- make a symbolic link 2806254Sroot */ 2816254Sroot symlink() 2826254Sroot { 2836254Sroot register struct a { 2846254Sroot char *target; 2856254Sroot char *linkname; 2866254Sroot } *uap; 2876254Sroot register struct inode *ip; 2886254Sroot register char *tp; 2896254Sroot register c, nc; 2906254Sroot 2916254Sroot uap = (struct a *)u.u_ap; 2926254Sroot tp = uap->target; 2936254Sroot nc = 0; 2946254Sroot while (c = fubyte(tp)) { 2956254Sroot if (c < 0) { 2966254Sroot u.u_error = EFAULT; 2976254Sroot return; 2986254Sroot } 2996254Sroot tp++; 3006254Sroot nc++; 3016254Sroot } 3026254Sroot u.u_dirp = uap->linkname; 3039167Ssam ip = namei(uchar, CREATE, 0); 3046254Sroot if (ip) { 3056254Sroot iput(ip); 3066254Sroot u.u_error = EEXIST; 3076254Sroot return; 3086254Sroot } 3096254Sroot if (u.u_error) 3106254Sroot return; 3116254Sroot ip = maknode(IFLNK | 0777); 3126254Sroot if (ip == NULL) 3136254Sroot return; 3147826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3159167Ssam /* handle u.u_error != 0 */ 3166254Sroot iput(ip); 3176254Sroot } 3186254Sroot 3196254Sroot /* 3206254Sroot * Unlink system call. 3216254Sroot * Hard to avoid races here, especially 3226254Sroot * in unlinking directories. 3236254Sroot */ 3246254Sroot unlink() 3256254Sroot { 3266254Sroot struct a { 3276254Sroot char *fname; 3286254Sroot }; 3299167Ssam register struct inode *ip, *dp; 3306254Sroot 3319167Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 3329167Ssam if (ip == NULL) 3336254Sroot return; 3349167Ssam dp = u.u_pdir; 3359167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3366254Sroot goto out; 3376254Sroot /* 3386254Sroot * Don't unlink a mounted file. 3396254Sroot */ 3409167Ssam if (ip->i_dev != dp->i_dev) { 3416254Sroot u.u_error = EBUSY; 3426254Sroot goto out; 3436254Sroot } 3446254Sroot if (ip->i_flag&ITEXT) 3456254Sroot xrele(ip); /* try once to free text */ 3467535Sroot if (dirremove()) { 3477535Sroot ip->i_nlink--; 3487535Sroot ip->i_flag |= ICHG; 3496254Sroot } 3506254Sroot out: 3519167Ssam if (dp == ip) 3527142Smckusick irele(ip); 3537142Smckusick else 3547142Smckusick iput(ip); 3559167Ssam iput(dp); 3566254Sroot } 3576254Sroot 3586254Sroot /* 3596254Sroot * Seek system call 3606254Sroot */ 3618040Sroot lseek() 3626254Sroot { 3636254Sroot register struct file *fp; 3646254Sroot register struct a { 3657701Ssam int fd; 3666254Sroot off_t off; 3676254Sroot int sbase; 3686254Sroot } *uap; 3696254Sroot 3706254Sroot uap = (struct a *)u.u_ap; 37112756Ssam fp = getinode(uap->fd); 3726254Sroot if (fp == NULL) 3736254Sroot return; 37412756Ssam if (uap->sbase == L_INCR) 3756254Sroot uap->off += fp->f_offset; 37612756Ssam else if (uap->sbase == L_XTND) 37712756Ssam uap->off += ((struct inode *)fp->f_data)->i_size; 3786254Sroot fp->f_offset = uap->off; 3796254Sroot u.u_r.r_off = uap->off; 3806254Sroot } 3816254Sroot 3826254Sroot /* 3836254Sroot * Access system call 3846254Sroot */ 3856254Sroot saccess() 3866254Sroot { 3876254Sroot register svuid, svgid; 3886254Sroot register struct inode *ip; 3896254Sroot register struct a { 3906254Sroot char *fname; 3916254Sroot int fmode; 3926254Sroot } *uap; 3936254Sroot 3946254Sroot uap = (struct a *)u.u_ap; 3956254Sroot svuid = u.u_uid; 3966254Sroot svgid = u.u_gid; 3976254Sroot u.u_uid = u.u_ruid; 3986254Sroot u.u_gid = u.u_rgid; 3999167Ssam ip = namei(uchar, LOOKUP, 1); 4006254Sroot if (ip != NULL) { 40112756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4027701Ssam goto done; 40312756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4047701Ssam goto done; 40512756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4067701Ssam goto done; 4077701Ssam done: 4086254Sroot iput(ip); 4096254Sroot } 4106254Sroot u.u_uid = svuid; 4116254Sroot u.u_gid = svgid; 4126254Sroot } 4136254Sroot 4146254Sroot /* 4156574Smckusic * Stat system call. This version follows links. 41637Sbill */ 41737Sbill stat() 41837Sbill { 41937Sbill 42012756Ssam stat1(1); 42137Sbill } 42237Sbill 42337Sbill /* 4246574Smckusic * Lstat system call. This version does not follow links. 4255992Swnj */ 4265992Swnj lstat() 4275992Swnj { 42812756Ssam 42912756Ssam stat1(0); 43012756Ssam } 43112756Ssam 43212756Ssam stat1(follow) 43312756Ssam int follow; 43412756Ssam { 4355992Swnj register struct inode *ip; 4365992Swnj register struct a { 4375992Swnj char *fname; 43812756Ssam struct stat *ub; 4395992Swnj } *uap; 44012756Ssam struct stat sb; 4415992Swnj 4425992Swnj uap = (struct a *)u.u_ap; 44312756Ssam ip = namei(uchar, LOOKUP, follow); 4445992Swnj if (ip == NULL) 4455992Swnj return; 446*13043Ssam (void) ino_stat(ip, &sb); 4475992Swnj iput(ip); 44812756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4495992Swnj } 4505992Swnj 4515992Swnj /* 4525992Swnj * Return target name of a symbolic link 45337Sbill */ 4545992Swnj readlink() 4555992Swnj { 4565992Swnj register struct inode *ip; 4575992Swnj register struct a { 4585992Swnj char *name; 4595992Swnj char *buf; 4605992Swnj int count; 4617826Sroot } *uap = (struct a *)u.u_ap; 4627826Sroot int resid; 4635992Swnj 4649167Ssam ip = namei(uchar, LOOKUP, 0); 4655992Swnj if (ip == NULL) 4665992Swnj return; 4675992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 4685992Swnj u.u_error = ENXIO; 4695992Swnj goto out; 4705992Swnj } 4717826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 4725992Swnj out: 4735992Swnj iput(ip); 4747826Sroot u.u_r.r_val1 = uap->count - resid; 4755992Swnj } 4765992Swnj 4779167Ssam /* 4789167Ssam * Change mode of a file given path name. 4799167Ssam */ 4806254Sroot chmod() 4815992Swnj { 4827701Ssam struct inode *ip; 4837701Ssam struct a { 4846254Sroot char *fname; 4856254Sroot int fmode; 4865992Swnj } *uap; 4875992Swnj 4885992Swnj uap = (struct a *)u.u_ap; 4896254Sroot if ((ip = owner(1)) == NULL) 4905992Swnj return; 4917701Ssam chmod1(ip, uap->fmode); 4929167Ssam iput(ip); 4937701Ssam } 4947439Sroot 4959167Ssam /* 4969167Ssam * Change mode of a file given a file descriptor. 4979167Ssam */ 4987701Ssam fchmod() 4997701Ssam { 5007701Ssam struct a { 5017701Ssam int fd; 5027701Ssam int fmode; 5037701Ssam } *uap; 5047701Ssam register struct inode *ip; 5057701Ssam register struct file *fp; 5067701Ssam 5077701Ssam uap = (struct a *)u.u_ap; 50812756Ssam fp = getinode(uap->fd); 5097701Ssam if (fp == NULL) 5107701Ssam return; 51112756Ssam ip = (struct inode *)fp->f_data; 5129167Ssam if (u.u_uid != ip->i_uid && !suser()) 5139167Ssam return; 5147701Ssam ilock(ip); 5157701Ssam chmod1(ip, uap->fmode); 5169167Ssam iunlock(ip); 5177701Ssam } 5187701Ssam 5199167Ssam /* 5209167Ssam * Change the mode on a file. 5219167Ssam * Inode must be locked before calling. 5229167Ssam */ 5237701Ssam chmod1(ip, mode) 5247701Ssam register struct inode *ip; 5257701Ssam register int mode; 5267701Ssam { 5277868Sroot 5286254Sroot ip->i_mode &= ~07777; 5297439Sroot if (u.u_uid) { 5307701Ssam mode &= ~ISVTX; 53111811Ssam if (!groupmember(ip->i_gid)) 53211811Ssam mode &= ~ISGID; 5337439Sroot } 5347701Ssam ip->i_mode |= mode&07777; 5356254Sroot ip->i_flag |= ICHG; 5366254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5376254Sroot xrele(ip); 5385992Swnj } 5395992Swnj 5409167Ssam /* 5419167Ssam * Set ownership given a path name. 5429167Ssam */ 5436254Sroot chown() 54437Sbill { 5457701Ssam struct inode *ip; 5467701Ssam struct a { 5476254Sroot char *fname; 5486254Sroot int uid; 5496254Sroot int gid; 55037Sbill } *uap; 55137Sbill 55237Sbill uap = (struct a *)u.u_ap; 55311821Ssam if (!suser() || (ip = owner(0)) == NULL) 55437Sbill return; 55511811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5569167Ssam iput(ip); 5577701Ssam } 5587439Sroot 5599167Ssam /* 5609167Ssam * Set ownership given a file descriptor. 5619167Ssam */ 5627701Ssam fchown() 5637701Ssam { 5647701Ssam struct a { 5657701Ssam int fd; 5667701Ssam int uid; 5677701Ssam int gid; 5687701Ssam } *uap; 5697701Ssam register struct inode *ip; 5707701Ssam register struct file *fp; 5717701Ssam 5727701Ssam uap = (struct a *)u.u_ap; 57312756Ssam fp = getinode(uap->fd); 5747701Ssam if (fp == NULL) 5757701Ssam return; 57612756Ssam ip = (struct inode *)fp->f_data; 57711821Ssam if (!suser()) 5789167Ssam return; 5797701Ssam ilock(ip); 58011811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5819167Ssam iunlock(ip); 5827701Ssam } 5837701Ssam 5847701Ssam /* 5857701Ssam * Perform chown operation on inode ip; 5867701Ssam * inode must be locked prior to call. 5877701Ssam */ 5887701Ssam chown1(ip, uid, gid) 5897701Ssam register struct inode *ip; 5907701Ssam int uid, gid; 5917701Ssam { 5927701Ssam #ifdef QUOTA 5937701Ssam register long change; 59411811Ssam #endif 5957701Ssam 59611811Ssam if (uid == -1) 59711811Ssam uid = ip->i_uid; 59811811Ssam if (gid == -1) 59911811Ssam gid = ip->i_gid; 60011811Ssam #ifdef QUOTA 60112646Ssam if (ip->i_uid != uid) /* this just speeds things a little */ 6027482Skre change = 0; 60312646Ssam else 60412646Ssam change = ip->i_blocks; 60512646Ssam (void) chkdq(ip, -change, 1); 60612646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6077482Skre dqrele(ip->i_dquot); 6087482Skre #endif 60911811Ssam ip->i_uid = uid; 61011811Ssam ip->i_gid = gid; 6116254Sroot ip->i_flag |= ICHG; 6126254Sroot if (u.u_ruid != 0) 6136254Sroot ip->i_mode &= ~(ISUID|ISGID); 6147701Ssam #ifdef QUOTA 6157482Skre ip->i_dquot = inoquota(ip); 61612646Ssam (void) chkdq(ip, change, 1); 61712646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 61812646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 61912646Ssam #else 62012646Ssam return (0); 6217482Skre #endif 62237Sbill } 62337Sbill 62411811Ssam utimes() 62511811Ssam { 62611811Ssam register struct a { 62711811Ssam char *fname; 62811811Ssam struct timeval *tptr; 62911811Ssam } *uap = (struct a *)u.u_ap; 63011811Ssam register struct inode *ip; 63111811Ssam struct timeval tv[2]; 63211811Ssam 63311811Ssam if ((ip = owner(1)) == NULL) 63411811Ssam return; 63511811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 63611811Ssam if (u.u_error == 0) { 63711811Ssam ip->i_flag |= IACC|IUPD|ICHG; 63811811Ssam iupdat(ip, &tv[0], &tv[1], 0); 63911811Ssam } 64011811Ssam iput(ip); 64111811Ssam } 64211811Ssam 6439167Ssam /* 6449167Ssam * Flush any pending I/O. 6459167Ssam */ 6466254Sroot sync() 64737Sbill { 64837Sbill 6498673Sroot update(); 65037Sbill } 6517535Sroot 6529167Ssam /* 6539167Ssam * Truncate a file given its path name. 6549167Ssam */ 6557701Ssam truncate() 6567701Ssam { 6577701Ssam struct a { 6587701Ssam char *fname; 6599167Ssam u_long length; 6607826Sroot } *uap = (struct a *)u.u_ap; 6617701Ssam struct inode *ip; 6627701Ssam 6639167Ssam ip = namei(uchar, LOOKUP, 1); 6647701Ssam if (ip == NULL) 6657701Ssam return; 6667701Ssam if (access(ip, IWRITE)) 6677701Ssam goto bad; 6687701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 6697701Ssam u.u_error = EISDIR; 6707701Ssam goto bad; 6717701Ssam } 6727701Ssam itrunc(ip, uap->length); 6737701Ssam bad: 6747701Ssam iput(ip); 6757701Ssam } 6767701Ssam 6779167Ssam /* 6789167Ssam * Truncate a file given a file descriptor. 6799167Ssam */ 6807701Ssam ftruncate() 6817701Ssam { 6827701Ssam struct a { 6837701Ssam int fd; 6849167Ssam u_long length; 6857826Sroot } *uap = (struct a *)u.u_ap; 6867701Ssam struct inode *ip; 6877701Ssam struct file *fp; 6887701Ssam 68912756Ssam fp = getinode(uap->fd); 6907701Ssam if (fp == NULL) 6917701Ssam return; 6927701Ssam if ((fp->f_flag&FWRITE) == 0) { 6937701Ssam u.u_error = EINVAL; 6947701Ssam return; 6957701Ssam } 69612756Ssam ip = (struct inode *)fp->f_data; 6977701Ssam ilock(ip); 6987701Ssam itrunc(ip, uap->length); 6999167Ssam iunlock(ip); 7007701Ssam } 7017701Ssam 7029167Ssam /* 7039167Ssam * Synch an open file. 7049167Ssam */ 7059167Ssam fsync() 7069167Ssam { 7079167Ssam struct a { 7089167Ssam int fd; 7099167Ssam } *uap = (struct a *)u.u_ap; 7109167Ssam struct inode *ip; 7119167Ssam struct file *fp; 7129167Ssam 71312756Ssam fp = getinode(uap->fd); 7149167Ssam if (fp == NULL) 7159167Ssam return; 71612756Ssam ip = (struct inode *)fp->f_data; 7179167Ssam ilock(ip); 7189167Ssam syncip(ip); 7199167Ssam iunlock(ip); 7209167Ssam } 7219167Ssam 7229167Ssam /* 7239167Ssam * Rename system call. 7249167Ssam * rename("foo", "bar"); 7259167Ssam * is essentially 7269167Ssam * unlink("bar"); 7279167Ssam * link("foo", "bar"); 7289167Ssam * unlink("foo"); 7299167Ssam * but ``atomically''. Can't do full commit without saving state in the 7309167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7319167Ssam * always guarantee the target exists. 7329167Ssam * 7339167Ssam * Basic algorithm is: 7349167Ssam * 7359167Ssam * 1) Bump link count on source while we're linking it to the 7369167Ssam * target. This also insure the inode won't be deleted out 7379167Ssam * from underneath us while we work. 7389167Ssam * 2) Link source to destination. If destination already exists, 7399167Ssam * delete it first. 7409167Ssam * 3) Unlink source reference to inode if still around. 7419167Ssam * 4) If a directory was moved and the parent of the destination 7429167Ssam * is different from the source, patch the ".." entry in the 7439167Ssam * directory. 7449167Ssam * 7459167Ssam * Source and destination must either both be directories, or both 7469167Ssam * not be directories. If target is a directory, it must be empty. 7479167Ssam */ 7487701Ssam rename() 7497701Ssam { 7507701Ssam struct a { 7517701Ssam char *from; 7527701Ssam char *to; 7537701Ssam } *uap; 7549167Ssam register struct inode *ip, *xp, *dp; 7559167Ssam int oldparent, parentdifferent, doingdirectory; 75610051Ssam int error = 0; 7577701Ssam 7589167Ssam uap = (struct a *)u.u_ap; 75911641Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 7609167Ssam if (ip == NULL) 7619167Ssam return; 7629167Ssam dp = u.u_pdir; 7639167Ssam oldparent = 0, doingdirectory = 0; 7649167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7659167Ssam register struct direct *d; 7669167Ssam 7679167Ssam d = &u.u_dent; 7689167Ssam /* 76911641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7709167Ssam */ 77111641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 77211641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 77311641Ssam (dp == ip)) { 77411641Ssam iput(dp); 77511641Ssam if (dp == ip) 77611641Ssam irele(ip); 77711641Ssam else 77810051Ssam iput(ip); 77911641Ssam u.u_error = EINVAL; 78011641Ssam return; 7819167Ssam } 7829167Ssam oldparent = dp->i_number; 7839167Ssam doingdirectory++; 7849167Ssam } 78511641Ssam iput(dp); 7869167Ssam 7879167Ssam /* 7889167Ssam * 1) Bump link count while we're moving stuff 7899167Ssam * around. If we crash somewhere before 7909167Ssam * completing our work, the link count 7919167Ssam * may be wrong, but correctable. 7929167Ssam */ 7939167Ssam ip->i_nlink++; 7949167Ssam ip->i_flag |= ICHG; 7959167Ssam iupdat(ip, &time, &time, 1); 7969167Ssam iunlock(ip); 7979167Ssam 7989167Ssam /* 7999167Ssam * When the target exists, both the directory 8009167Ssam * and target inodes are returned locked. 8019167Ssam */ 8029167Ssam u.u_dirp = (caddr_t)uap->to; 8039167Ssam xp = namei(uchar, CREATE | LOCKPARENT, 0); 80410051Ssam if (u.u_error) { 80510051Ssam error = u.u_error; 8069167Ssam goto out; 80710051Ssam } 8089167Ssam dp = u.u_pdir; 8099167Ssam /* 81011641Ssam * If ".." must be changed (ie the directory gets a new 81112816Smckusick * parent) then the source directory must not be in the 81212816Smckusick * directory heirarchy above the target, as this would 81312816Smckusick * orphan everything below the source directory. Also 81412816Smckusick * the user must have write permission in the source so 81512816Smckusick * as to be able to change "..". We must repeat the call 81612816Smckusick * to namei, as the parent directory is unlocked by the 81712816Smckusick * call to checkpath(). 81811641Ssam */ 81911641Ssam parentdifferent = oldparent != dp->i_number; 82012816Smckusick if (doingdirectory && parentdifferent) { 82112816Smckusick if (access(ip, IWRITE)) 82212816Smckusick goto bad; 82312816Smckusick do { 82412816Smckusick dp = u.u_pdir; 82512816Smckusick if (xp != NULL) 82612816Smckusick iput(xp); 82712816Smckusick u.u_error = checkpath(ip, dp); 82812816Smckusick if (u.u_error) 82912816Smckusick goto out; 83012816Smckusick u.u_dirp = (caddr_t)uap->to; 83112816Smckusick xp = namei(uchar, CREATE | LOCKPARENT, 0); 83212816Smckusick if (u.u_error) { 83312816Smckusick error = u.u_error; 83412816Smckusick goto out; 83512816Smckusick } 83612816Smckusick } while (dp != u.u_pdir); 83712816Smckusick } 83811641Ssam /* 8399167Ssam * 2) If target doesn't exist, link the target 8409167Ssam * to the source and unlink the source. 8419167Ssam * Otherwise, rewrite the target directory 8429167Ssam * entry to reference the source inode and 8439167Ssam * expunge the original entry's existence. 8449167Ssam */ 8459167Ssam if (xp == NULL) { 8469167Ssam if (dp->i_dev != ip->i_dev) { 84710051Ssam error = EXDEV; 8489167Ssam goto bad; 8499167Ssam } 8509167Ssam /* 8519167Ssam * Account for ".." in directory. 8529167Ssam * When source and destination have the 8539167Ssam * same parent we don't fool with the 8549167Ssam * link count -- this isn't required 8559167Ssam * because we do a similar check below. 8569167Ssam */ 8579167Ssam if (doingdirectory && parentdifferent) { 8589167Ssam dp->i_nlink++; 8599167Ssam dp->i_flag |= ICHG; 8609167Ssam iupdat(dp, &time, &time, 1); 8619167Ssam } 86210850Ssam error = direnter(ip); 86310850Ssam if (error) 8649167Ssam goto out; 8659167Ssam } else { 8669167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 86710051Ssam error = EXDEV; 8689167Ssam goto bad; 8699167Ssam } 8709167Ssam /* 87110590Ssam * Short circuit rename(foo, foo). 87210590Ssam */ 87310590Ssam if (xp->i_number == ip->i_number) 87410590Ssam goto bad; 87510590Ssam /* 87610051Ssam * Target must be empty if a directory 87710051Ssam * and have no links to it. 8789167Ssam * Also, insure source and target are 8799167Ssam * compatible (both directories, or both 8809167Ssam * not directories). 8819167Ssam */ 8829167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 88310051Ssam if (!dirempty(xp) || xp->i_nlink > 2) { 88410051Ssam error = ENOTEMPTY; 8859167Ssam goto bad; 8869167Ssam } 8879167Ssam if (!doingdirectory) { 88810051Ssam error = ENOTDIR; 8899167Ssam goto bad; 8909167Ssam } 8919167Ssam } else if (doingdirectory) { 89210051Ssam error = EISDIR; 8939167Ssam goto bad; 8949167Ssam } 8959167Ssam dirrewrite(dp, ip); 89610051Ssam if (u.u_error) { 89710051Ssam error = u.u_error; 8989167Ssam goto bad1; 89910051Ssam } 9009167Ssam /* 90110051Ssam * Adjust the link count of the target to 90210051Ssam * reflect the dirrewrite above. If this is 90310051Ssam * a directory it is empty and there are 90410051Ssam * no links to it, so we can squash the inode and 90510051Ssam * any space associated with it. We disallowed 90610051Ssam * renaming over top of a directory with links to 90710051Ssam * it above, as we've no way to determine if 90810051Ssam * we've got a link or the directory itself, and 90910051Ssam * if we get a link, then ".." will be screwed up. 9109167Ssam */ 91110051Ssam xp->i_nlink--; 9129167Ssam if (doingdirectory) { 91310051Ssam if (--xp->i_nlink != 0) 91410051Ssam panic("rename: linked directory"); 9159167Ssam itrunc(xp, (u_long)0); 91610051Ssam } 9179167Ssam xp->i_flag |= ICHG; 9189167Ssam iput(xp); 91910246Ssam xp = NULL; 9209167Ssam } 9219167Ssam 9229167Ssam /* 9239167Ssam * 3) Unlink the source. 9249167Ssam */ 9259167Ssam u.u_dirp = uap->from; 9269167Ssam dp = namei(uchar, DELETE, 0); 9279167Ssam /* 9289167Ssam * Insure directory entry still exists and 9299167Ssam * has not changed since the start of all 9309167Ssam * this. If either has occured, forget about 9319167Ssam * about deleting the original entry and just 9329167Ssam * adjust the link count in the inode. 9339167Ssam */ 9349167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 9359167Ssam ip->i_nlink--; 9369167Ssam ip->i_flag |= ICHG; 9379167Ssam } else { 9389167Ssam /* 9399167Ssam * If source is a directory, must adjust 9409167Ssam * link count of parent directory also. 9419167Ssam * If target didn't exist and source and 9429167Ssam * target have the same parent, then we 9439167Ssam * needn't touch the link count, it all 9449167Ssam * balances out in the end. Otherwise, we 9459167Ssam * must do so to reflect deletion of ".." 9469167Ssam * done above. 9479167Ssam */ 9489167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9499167Ssam dp->i_nlink--; 9509167Ssam dp->i_flag |= ICHG; 9519167Ssam } 9529167Ssam if (dirremove()) { 9539167Ssam ip->i_nlink--; 9549167Ssam ip->i_flag |= ICHG; 9559167Ssam } 95610051Ssam if (error == 0) /* conservative */ 95710051Ssam error = u.u_error; 9589167Ssam } 9599167Ssam irele(ip); 9609167Ssam if (dp) 9619167Ssam iput(dp); 9629167Ssam 9639167Ssam /* 9649167Ssam * 4) Renaming a directory with the parent 9659167Ssam * different requires ".." to be rewritten. 9669167Ssam * The window is still there for ".." to 9679167Ssam * be inconsistent, but this is unavoidable, 9689167Ssam * and a lot shorter than when it was done 9699167Ssam * in a user process. 9709167Ssam */ 97110051Ssam if (doingdirectory && parentdifferent && error == 0) { 9729167Ssam struct dirtemplate dirbuf; 9739167Ssam 9749167Ssam u.u_dirp = uap->to; 9759167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 9769167Ssam if (ip == NULL) { 9779167Ssam printf("rename: .. went away\n"); 9789167Ssam return; 9799167Ssam } 9809167Ssam dp = u.u_pdir; 9819167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 9829167Ssam printf("rename: .. not a directory\n"); 9839167Ssam goto stuck; 9849167Ssam } 98510051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 9869167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 98710051Ssam if (error == 0) { 9889167Ssam dirbuf.dotdot_ino = dp->i_number; 9899167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 9909167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 9919167Ssam } 9929167Ssam stuck: 9939167Ssam irele(dp); 9949167Ssam iput(ip); 9959167Ssam } 99610051Ssam goto done; 99710051Ssam 9989167Ssam bad: 99910246Ssam iput(dp); 10009167Ssam bad1: 10019167Ssam if (xp) 100210246Ssam iput(xp); 10039167Ssam out: 10049167Ssam ip->i_nlink--; 10059167Ssam ip->i_flag |= ICHG; 10069167Ssam irele(ip); 100710051Ssam done: 100810051Ssam if (error) 100910051Ssam u.u_error = error; 10107701Ssam } 10117701Ssam 10127535Sroot /* 10137535Sroot * Make a new file. 10147535Sroot */ 10157535Sroot struct inode * 10167535Sroot maknode(mode) 10177535Sroot int mode; 10187535Sroot { 10197535Sroot register struct inode *ip; 10207535Sroot ino_t ipref; 10217535Sroot 10227535Sroot if ((mode & IFMT) == IFDIR) 10237535Sroot ipref = dirpref(u.u_pdir->i_fs); 10247535Sroot else 10257535Sroot ipref = u.u_pdir->i_number; 10267535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10277535Sroot if (ip == NULL) { 10287535Sroot iput(u.u_pdir); 10297701Ssam return (NULL); 10307535Sroot } 10317701Ssam #ifdef QUOTA 10327535Sroot if (ip->i_dquot != NODQUOT) 10337535Sroot panic("maknode: dquot"); 10347535Sroot #endif 10357535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10367535Sroot if ((mode & IFMT) == 0) 10377535Sroot mode |= IFREG; 10387535Sroot ip->i_mode = mode & ~u.u_cmask; 10397535Sroot ip->i_nlink = 1; 10407535Sroot ip->i_uid = u.u_uid; 10417535Sroot ip->i_gid = u.u_pdir->i_gid; 104211811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 104311811Ssam ip->i_mode &= ~ISGID; 10447701Ssam #ifdef QUOTA 10457535Sroot ip->i_dquot = inoquota(ip); 10467535Sroot #endif 10477535Sroot 10487535Sroot /* 10497535Sroot * Make sure inode goes to disk before directory entry. 10507535Sroot */ 10518673Sroot iupdat(ip, &time, &time, 1); 105210850Ssam u.u_error = direnter(ip); 10537535Sroot if (u.u_error) { 10547535Sroot /* 105510850Ssam * Write error occurred trying to update directory 105610850Ssam * so must deallocate the inode. 10577535Sroot */ 10587535Sroot ip->i_nlink = 0; 10597535Sroot ip->i_flag |= ICHG; 10607535Sroot iput(ip); 10617701Ssam return (NULL); 10627535Sroot } 10637701Ssam return (ip); 10647535Sroot } 106512756Ssam 106612756Ssam /* 106712756Ssam * A virgin directory (no blushing please). 106812756Ssam */ 106912756Ssam struct dirtemplate mastertemplate = { 107012756Ssam 0, 12, 1, ".", 107112756Ssam 0, DIRBLKSIZ - 12, 2, ".." 107212756Ssam }; 107312756Ssam 107412756Ssam /* 107512756Ssam * Mkdir system call 107612756Ssam */ 107712756Ssam mkdir() 107812756Ssam { 107912756Ssam struct a { 108012756Ssam char *name; 108112756Ssam int dmode; 108212756Ssam } *uap; 108312756Ssam register struct inode *ip, *dp; 108412756Ssam struct dirtemplate dirtemplate; 108512756Ssam 108612756Ssam uap = (struct a *)u.u_ap; 108712756Ssam ip = namei(uchar, CREATE, 0); 108812756Ssam if (u.u_error) 108912756Ssam return; 109012756Ssam if (ip != NULL) { 109112756Ssam iput(ip); 109212756Ssam u.u_error = EEXIST; 109312756Ssam return; 109412756Ssam } 109512756Ssam dp = u.u_pdir; 109612756Ssam uap->dmode &= 0777; 109712756Ssam uap->dmode |= IFDIR; 109812756Ssam /* 109912756Ssam * Must simulate part of maknode here 110012756Ssam * in order to acquire the inode, but 110112756Ssam * not have it entered in the parent 110212756Ssam * directory. The entry is made later 110312756Ssam * after writing "." and ".." entries out. 110412756Ssam */ 110512756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 110612756Ssam if (ip == NULL) { 110712756Ssam iput(dp); 110812756Ssam return; 110912756Ssam } 111012756Ssam #ifdef QUOTA 111112756Ssam if (ip->i_dquot != NODQUOT) 111212756Ssam panic("mkdir: dquot"); 111312756Ssam #endif 111412756Ssam ip->i_flag |= IACC|IUPD|ICHG; 111512756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 111612756Ssam ip->i_nlink = 2; 111712756Ssam ip->i_uid = u.u_uid; 111812756Ssam ip->i_gid = dp->i_gid; 111912756Ssam #ifdef QUOTA 112012756Ssam ip->i_dquot = inoquota(ip); 112112756Ssam #endif 112212756Ssam iupdat(ip, &time, &time, 1); 112312756Ssam 112412756Ssam /* 112512756Ssam * Bump link count in parent directory 112612756Ssam * to reflect work done below. Should 112712756Ssam * be done before reference is created 112812756Ssam * so reparation is possible if we crash. 112912756Ssam */ 113012756Ssam dp->i_nlink++; 113112756Ssam dp->i_flag |= ICHG; 113212756Ssam iupdat(dp, &time, &time, 1); 113312756Ssam 113412756Ssam /* 113512756Ssam * Initialize directory with "." 113612756Ssam * and ".." from static template. 113712756Ssam */ 113812756Ssam dirtemplate = mastertemplate; 113912756Ssam dirtemplate.dot_ino = ip->i_number; 114012756Ssam dirtemplate.dotdot_ino = dp->i_number; 114112756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 114212756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 114312756Ssam if (u.u_error) { 114412756Ssam dp->i_nlink--; 114512756Ssam dp->i_flag |= ICHG; 114612756Ssam goto bad; 114712756Ssam } 114812756Ssam /* 114912756Ssam * Directory all set up, now 115012756Ssam * install the entry for it in 115112756Ssam * the parent directory. 115212756Ssam */ 115312756Ssam u.u_error = direnter(ip); 115412756Ssam dp = NULL; 115512756Ssam if (u.u_error) { 115612756Ssam u.u_dirp = uap->name; 115712756Ssam dp = namei(uchar, LOOKUP, 0); 115812756Ssam if (dp) { 115912756Ssam dp->i_nlink--; 116012756Ssam dp->i_flag |= ICHG; 116112756Ssam } 116212756Ssam } 116312756Ssam bad: 116412756Ssam /* 116512756Ssam * No need to do an explicit itrunc here, 116612756Ssam * irele will do this for us because we set 116712756Ssam * the link count to 0. 116812756Ssam */ 116912756Ssam if (u.u_error) { 117012756Ssam ip->i_nlink = 0; 117112756Ssam ip->i_flag |= ICHG; 117212756Ssam } 117312756Ssam if (dp) 117412756Ssam iput(dp); 117512756Ssam iput(ip); 117612756Ssam } 117712756Ssam 117812756Ssam /* 117912756Ssam * Rmdir system call. 118012756Ssam */ 118112756Ssam rmdir() 118212756Ssam { 118312756Ssam struct a { 118412756Ssam char *name; 118512756Ssam }; 118612756Ssam register struct inode *ip, *dp; 118712756Ssam 118812756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 118912756Ssam if (ip == NULL) 119012756Ssam return; 119112756Ssam dp = u.u_pdir; 119212756Ssam /* 119312756Ssam * No rmdir "." please. 119412756Ssam */ 119512756Ssam if (dp == ip) { 119612756Ssam irele(dp); 119712756Ssam iput(ip); 119812756Ssam u.u_error = EINVAL; 119912756Ssam return; 120012756Ssam } 120112756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 120212756Ssam u.u_error = ENOTDIR; 120312756Ssam goto out; 120412756Ssam } 120512756Ssam /* 120612756Ssam * Don't remove a mounted on directory. 120712756Ssam */ 120812756Ssam if (ip->i_dev != dp->i_dev) { 120912756Ssam u.u_error = EBUSY; 121012756Ssam goto out; 121112756Ssam } 121212756Ssam /* 121312756Ssam * Verify the directory is empty (and valid). 121412756Ssam * (Rmdir ".." won't be valid since 121512756Ssam * ".." will contain a reference to 121612756Ssam * the current directory and thus be 121712756Ssam * non-empty.) 121812756Ssam */ 121912756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 122012756Ssam u.u_error = ENOTEMPTY; 122112756Ssam goto out; 122212756Ssam } 122312756Ssam /* 122412756Ssam * Delete reference to directory before purging 122512756Ssam * inode. If we crash in between, the directory 122612756Ssam * will be reattached to lost+found, 122712756Ssam */ 122812756Ssam if (dirremove() == 0) 122912756Ssam goto out; 123012756Ssam dp->i_nlink--; 123112756Ssam dp->i_flag |= ICHG; 123212756Ssam iput(dp); 123312756Ssam dp = NULL; 123412756Ssam /* 123512756Ssam * Truncate inode. The only stuff left 123612756Ssam * in the directory is "." and "..". The 123712756Ssam * "." reference is inconsequential since 123812756Ssam * we're quashing it. The ".." reference 123912756Ssam * has already been adjusted above. We've 124012756Ssam * removed the "." reference and the reference 124112756Ssam * in the parent directory, but there may be 124212756Ssam * other hard links so decrement by 2 and 124312756Ssam * worry about them later. 124412756Ssam */ 124512756Ssam ip->i_nlink -= 2; 124612756Ssam itrunc(ip, (u_long)0); 124712756Ssam out: 124812756Ssam if (dp) 124912756Ssam iput(dp); 125012756Ssam iput(ip); 125112756Ssam } 125212756Ssam 125312756Ssam struct file * 125412756Ssam getinode(fdes) 125512756Ssam int fdes; 125612756Ssam { 125712756Ssam register struct file *fp; 125812756Ssam 125912756Ssam fp = getf(fdes); 126012756Ssam if (fp == 0) 126112756Ssam return (0); 126212756Ssam if (fp->f_type != DTYPE_INODE) { 126312756Ssam u.u_error = EINVAL; 126412756Ssam return (0); 126512756Ssam } 126612756Ssam return (fp); 126712756Ssam } 126812756Ssam 126912756Ssam /* 127012756Ssam * mode mask for creation of files 127112756Ssam */ 127212756Ssam umask() 127312756Ssam { 127412756Ssam register struct a { 127512756Ssam int mask; 127612756Ssam } *uap; 127712756Ssam 127812756Ssam uap = (struct a *)u.u_ap; 127912756Ssam u.u_r.r_val1 = u.u_cmask; 128012756Ssam u.u_cmask = uap->mask & 07777; 128112756Ssam } 1282