1*16652Ssam /* vfs_syscalls.c 6.8 84/06/30 */ 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; 14916032Skarels if (mode&(FWRITE|FTRUNC)) { 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 if (setjmp(&u.u_qsave)) { 17012756Ssam if (u.u_error == 0) 17112756Ssam u.u_error = EINTR; 17212756Ssam u.u_ofile[i] = NULL; 17312756Ssam closef(fp); 17412756Ssam return; 17512756Ssam } 1768559Sroot u.u_error = openi(ip, mode); 17712756Ssam if (u.u_error == 0) 1786254Sroot return; 1796254Sroot u.u_ofile[i] = NULL; 1806254Sroot fp->f_count--; 1817142Smckusick irele(ip); 1827701Ssam return; 1837701Ssam bad: 1847701Ssam iput(ip); 1856254Sroot } 1866254Sroot 1876254Sroot /* 1886254Sroot * Mknod system call 1896254Sroot */ 1906254Sroot mknod() 1916254Sroot { 1926254Sroot register struct inode *ip; 1936254Sroot register struct a { 1946254Sroot char *fname; 1956254Sroot int fmode; 1966254Sroot int dev; 1976254Sroot } *uap; 1986254Sroot 1996254Sroot uap = (struct a *)u.u_ap; 20012756Ssam if (!suser()) 20112756Ssam return; 20212756Ssam ip = namei(uchar, CREATE, 0); 20312756Ssam if (ip != NULL) { 20412756Ssam u.u_error = EEXIST; 20512756Ssam goto out; 2066254Sroot } 2076254Sroot if (u.u_error) 2086254Sroot return; 2096254Sroot ip = maknode(uap->fmode); 2106254Sroot if (ip == NULL) 2116254Sroot return; 21212756Ssam switch (ip->i_mode & IFMT) { 21312756Ssam 21415093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 21512756Ssam case IFCHR: 21612756Ssam case IFBLK: 21712756Ssam if (uap->dev) { 21812756Ssam /* 21912756Ssam * Want to be able to use this to make badblock 22012756Ssam * inodes, so don't truncate the dev number. 22112756Ssam */ 22212756Ssam ip->i_rdev = uap->dev; 22312756Ssam ip->i_flag |= IACC|IUPD|ICHG; 22412756Ssam } 2256254Sroot } 2266254Sroot 2276254Sroot out: 2286254Sroot iput(ip); 2296254Sroot } 2306254Sroot 2316254Sroot /* 2326254Sroot * link system call 2336254Sroot */ 2346254Sroot link() 2356254Sroot { 2366254Sroot register struct inode *ip, *xp; 2376254Sroot register struct a { 2386254Sroot char *target; 2396254Sroot char *linkname; 2406254Sroot } *uap; 2416254Sroot 2426254Sroot uap = (struct a *)u.u_ap; 2439167Ssam ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */ 2446254Sroot if (ip == NULL) 2456254Sroot return; 2469167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2477439Sroot iput(ip); 2487439Sroot return; 2497439Sroot } 2506254Sroot ip->i_nlink++; 2516254Sroot ip->i_flag |= ICHG; 2528673Sroot iupdat(ip, &time, &time, 1); 2537122Smckusick iunlock(ip); 2546254Sroot u.u_dirp = (caddr_t)uap->linkname; 2559167Ssam xp = namei(uchar, CREATE, 0); 2566254Sroot if (xp != NULL) { 2576254Sroot u.u_error = EEXIST; 2586254Sroot iput(xp); 2596254Sroot goto out; 2606254Sroot } 2616254Sroot if (u.u_error) 2626254Sroot goto out; 2636254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2646254Sroot iput(u.u_pdir); 2656254Sroot u.u_error = EXDEV; 2666254Sroot goto out; 2676254Sroot } 26810850Ssam u.u_error = direnter(ip); 2696254Sroot out: 2706254Sroot if (u.u_error) { 2716254Sroot ip->i_nlink--; 2726254Sroot ip->i_flag |= ICHG; 2736254Sroot } 2747142Smckusick irele(ip); 2756254Sroot } 2766254Sroot 2776254Sroot /* 2786254Sroot * symlink -- make a symbolic link 2796254Sroot */ 2806254Sroot symlink() 2816254Sroot { 2826254Sroot register struct a { 2836254Sroot char *target; 2846254Sroot char *linkname; 2856254Sroot } *uap; 2866254Sroot register struct inode *ip; 2876254Sroot register char *tp; 2886254Sroot register c, nc; 2896254Sroot 2906254Sroot uap = (struct a *)u.u_ap; 2916254Sroot tp = uap->target; 2926254Sroot nc = 0; 2936254Sroot while (c = fubyte(tp)) { 2946254Sroot if (c < 0) { 2956254Sroot u.u_error = EFAULT; 2966254Sroot return; 2976254Sroot } 2986254Sroot tp++; 2996254Sroot nc++; 3006254Sroot } 3016254Sroot u.u_dirp = uap->linkname; 3029167Ssam ip = namei(uchar, CREATE, 0); 3036254Sroot if (ip) { 3046254Sroot iput(ip); 3056254Sroot u.u_error = EEXIST; 3066254Sroot return; 3076254Sroot } 3086254Sroot if (u.u_error) 3096254Sroot return; 3106254Sroot ip = maknode(IFLNK | 0777); 3116254Sroot if (ip == NULL) 3126254Sroot return; 3137826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3149167Ssam /* handle u.u_error != 0 */ 3156254Sroot iput(ip); 3166254Sroot } 3176254Sroot 3186254Sroot /* 3196254Sroot * Unlink system call. 3206254Sroot * Hard to avoid races here, especially 3216254Sroot * in unlinking directories. 3226254Sroot */ 3236254Sroot unlink() 3246254Sroot { 3256254Sroot struct a { 3266254Sroot char *fname; 3276254Sroot }; 3289167Ssam register struct inode *ip, *dp; 3296254Sroot 3309167Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 3319167Ssam if (ip == NULL) 3326254Sroot return; 3339167Ssam dp = u.u_pdir; 3349167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3356254Sroot goto out; 3366254Sroot /* 3376254Sroot * Don't unlink a mounted file. 3386254Sroot */ 3399167Ssam if (ip->i_dev != dp->i_dev) { 3406254Sroot u.u_error = EBUSY; 3416254Sroot goto out; 3426254Sroot } 3436254Sroot if (ip->i_flag&ITEXT) 3446254Sroot xrele(ip); /* try once to free text */ 3457535Sroot if (dirremove()) { 3467535Sroot ip->i_nlink--; 3477535Sroot ip->i_flag |= ICHG; 3486254Sroot } 3496254Sroot out: 3509167Ssam if (dp == ip) 3517142Smckusick irele(ip); 3527142Smckusick else 3537142Smckusick iput(ip); 3549167Ssam iput(dp); 3556254Sroot } 3566254Sroot 3576254Sroot /* 3586254Sroot * Seek system call 3596254Sroot */ 3608040Sroot lseek() 3616254Sroot { 3626254Sroot register struct file *fp; 3636254Sroot register struct a { 3647701Ssam int fd; 3656254Sroot off_t off; 3666254Sroot int sbase; 3676254Sroot } *uap; 3686254Sroot 3696254Sroot uap = (struct a *)u.u_ap; 37016540Ssam GETF(fp, uap->fd); 37116540Ssam if (fp->f_type != DTYPE_INODE) { 37216540Ssam u.u_error = ESPIPE; 3736254Sroot return; 37416540Ssam } 37513878Ssam switch (uap->sbase) { 37613878Ssam 37713878Ssam case L_INCR: 37813878Ssam fp->f_offset += uap->off; 37913878Ssam break; 38013878Ssam 38113878Ssam case L_XTND: 38213878Ssam fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; 38313878Ssam break; 38413878Ssam 38513878Ssam case L_SET: 38613878Ssam fp->f_offset = uap->off; 38713878Ssam break; 38813878Ssam 38913878Ssam default: 39013878Ssam u.u_error = EINVAL; 39113878Ssam return; 39213878Ssam } 39313878Ssam u.u_r.r_off = fp->f_offset; 3946254Sroot } 3956254Sroot 3966254Sroot /* 3976254Sroot * Access system call 3986254Sroot */ 3996254Sroot saccess() 4006254Sroot { 4016254Sroot register svuid, svgid; 4026254Sroot register struct inode *ip; 4036254Sroot register struct a { 4046254Sroot char *fname; 4056254Sroot int fmode; 4066254Sroot } *uap; 4076254Sroot 4086254Sroot uap = (struct a *)u.u_ap; 4096254Sroot svuid = u.u_uid; 4106254Sroot svgid = u.u_gid; 4116254Sroot u.u_uid = u.u_ruid; 4126254Sroot u.u_gid = u.u_rgid; 4139167Ssam ip = namei(uchar, LOOKUP, 1); 4146254Sroot if (ip != NULL) { 41512756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4167701Ssam goto done; 41712756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4187701Ssam goto done; 41912756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4207701Ssam goto done; 4217701Ssam done: 4226254Sroot iput(ip); 4236254Sroot } 4246254Sroot u.u_uid = svuid; 4256254Sroot u.u_gid = svgid; 4266254Sroot } 4276254Sroot 4286254Sroot /* 4296574Smckusic * Stat system call. This version follows links. 43037Sbill */ 43137Sbill stat() 43237Sbill { 43337Sbill 43412756Ssam stat1(1); 43537Sbill } 43637Sbill 43737Sbill /* 4386574Smckusic * Lstat system call. This version does not follow links. 4395992Swnj */ 4405992Swnj lstat() 4415992Swnj { 44212756Ssam 44312756Ssam stat1(0); 44412756Ssam } 44512756Ssam 44612756Ssam stat1(follow) 44712756Ssam int follow; 44812756Ssam { 4495992Swnj register struct inode *ip; 4505992Swnj register struct a { 4515992Swnj char *fname; 45212756Ssam struct stat *ub; 4535992Swnj } *uap; 45412756Ssam struct stat sb; 4555992Swnj 4565992Swnj uap = (struct a *)u.u_ap; 45712756Ssam ip = namei(uchar, LOOKUP, follow); 4585992Swnj if (ip == NULL) 4595992Swnj return; 46013043Ssam (void) ino_stat(ip, &sb); 4615992Swnj iput(ip); 46212756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4635992Swnj } 4645992Swnj 4655992Swnj /* 4665992Swnj * Return target name of a symbolic link 46737Sbill */ 4685992Swnj readlink() 4695992Swnj { 4705992Swnj register struct inode *ip; 4715992Swnj register struct a { 4725992Swnj char *name; 4735992Swnj char *buf; 4745992Swnj int count; 4757826Sroot } *uap = (struct a *)u.u_ap; 4767826Sroot int resid; 4775992Swnj 4789167Ssam ip = namei(uchar, LOOKUP, 0); 4795992Swnj if (ip == NULL) 4805992Swnj return; 4815992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 4825992Swnj u.u_error = ENXIO; 4835992Swnj goto out; 4845992Swnj } 4857826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 4865992Swnj out: 4875992Swnj iput(ip); 4887826Sroot u.u_r.r_val1 = uap->count - resid; 4895992Swnj } 4905992Swnj 4919167Ssam /* 4929167Ssam * Change mode of a file given path name. 4939167Ssam */ 4946254Sroot chmod() 4955992Swnj { 4967701Ssam struct inode *ip; 4977701Ssam struct a { 4986254Sroot char *fname; 4996254Sroot int fmode; 5005992Swnj } *uap; 5015992Swnj 5025992Swnj uap = (struct a *)u.u_ap; 5036254Sroot if ((ip = owner(1)) == NULL) 5045992Swnj return; 5057701Ssam chmod1(ip, uap->fmode); 5069167Ssam iput(ip); 5077701Ssam } 5087439Sroot 5099167Ssam /* 5109167Ssam * Change mode of a file given a file descriptor. 5119167Ssam */ 5127701Ssam fchmod() 5137701Ssam { 5147701Ssam struct a { 5157701Ssam int fd; 5167701Ssam int fmode; 5177701Ssam } *uap; 5187701Ssam register struct inode *ip; 5197701Ssam register struct file *fp; 5207701Ssam 5217701Ssam uap = (struct a *)u.u_ap; 52212756Ssam fp = getinode(uap->fd); 5237701Ssam if (fp == NULL) 5247701Ssam return; 52512756Ssam ip = (struct inode *)fp->f_data; 5269167Ssam if (u.u_uid != ip->i_uid && !suser()) 5279167Ssam return; 5287701Ssam ilock(ip); 5297701Ssam chmod1(ip, uap->fmode); 5309167Ssam iunlock(ip); 5317701Ssam } 5327701Ssam 5339167Ssam /* 5349167Ssam * Change the mode on a file. 5359167Ssam * Inode must be locked before calling. 5369167Ssam */ 5377701Ssam chmod1(ip, mode) 5387701Ssam register struct inode *ip; 5397701Ssam register int mode; 5407701Ssam { 5417868Sroot 5426254Sroot ip->i_mode &= ~07777; 5437439Sroot if (u.u_uid) { 5447701Ssam mode &= ~ISVTX; 54511811Ssam if (!groupmember(ip->i_gid)) 54611811Ssam mode &= ~ISGID; 5477439Sroot } 5487701Ssam ip->i_mode |= mode&07777; 5496254Sroot ip->i_flag |= ICHG; 5506254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5516254Sroot xrele(ip); 5525992Swnj } 5535992Swnj 5549167Ssam /* 5559167Ssam * Set ownership given a path name. 5569167Ssam */ 5576254Sroot chown() 55837Sbill { 5597701Ssam struct inode *ip; 5607701Ssam struct a { 5616254Sroot char *fname; 5626254Sroot int uid; 5636254Sroot int gid; 56437Sbill } *uap; 56537Sbill 56637Sbill uap = (struct a *)u.u_ap; 56711821Ssam if (!suser() || (ip = owner(0)) == NULL) 56837Sbill return; 56911811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5709167Ssam iput(ip); 5717701Ssam } 5727439Sroot 5739167Ssam /* 5749167Ssam * Set ownership given a file descriptor. 5759167Ssam */ 5767701Ssam fchown() 5777701Ssam { 5787701Ssam struct a { 5797701Ssam int fd; 5807701Ssam int uid; 5817701Ssam int gid; 5827701Ssam } *uap; 5837701Ssam register struct inode *ip; 5847701Ssam register struct file *fp; 5857701Ssam 5867701Ssam uap = (struct a *)u.u_ap; 58712756Ssam fp = getinode(uap->fd); 5887701Ssam if (fp == NULL) 5897701Ssam return; 59012756Ssam ip = (struct inode *)fp->f_data; 59111821Ssam if (!suser()) 5929167Ssam return; 5937701Ssam ilock(ip); 59411811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5959167Ssam iunlock(ip); 5967701Ssam } 5977701Ssam 5987701Ssam /* 5997701Ssam * Perform chown operation on inode ip; 6007701Ssam * inode must be locked prior to call. 6017701Ssam */ 6027701Ssam chown1(ip, uid, gid) 6037701Ssam register struct inode *ip; 6047701Ssam int uid, gid; 6057701Ssam { 6067701Ssam #ifdef QUOTA 6077701Ssam register long change; 60811811Ssam #endif 6097701Ssam 61011811Ssam if (uid == -1) 61111811Ssam uid = ip->i_uid; 61211811Ssam if (gid == -1) 61311811Ssam gid = ip->i_gid; 61411811Ssam #ifdef QUOTA 61514385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6167482Skre change = 0; 61712646Ssam else 61812646Ssam change = ip->i_blocks; 61912646Ssam (void) chkdq(ip, -change, 1); 62012646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6217482Skre dqrele(ip->i_dquot); 6227482Skre #endif 62311811Ssam ip->i_uid = uid; 62411811Ssam ip->i_gid = gid; 6256254Sroot ip->i_flag |= ICHG; 6266254Sroot if (u.u_ruid != 0) 6276254Sroot ip->i_mode &= ~(ISUID|ISGID); 6287701Ssam #ifdef QUOTA 6297482Skre ip->i_dquot = inoquota(ip); 63012646Ssam (void) chkdq(ip, change, 1); 63112646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 63212646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 63312646Ssam #else 63412646Ssam return (0); 6357482Skre #endif 63637Sbill } 63737Sbill 63811811Ssam utimes() 63911811Ssam { 64011811Ssam register struct a { 64111811Ssam char *fname; 64211811Ssam struct timeval *tptr; 64311811Ssam } *uap = (struct a *)u.u_ap; 64411811Ssam register struct inode *ip; 64511811Ssam struct timeval tv[2]; 64611811Ssam 64711811Ssam if ((ip = owner(1)) == NULL) 64811811Ssam return; 64911811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 65011811Ssam if (u.u_error == 0) { 65111811Ssam ip->i_flag |= IACC|IUPD|ICHG; 65211811Ssam iupdat(ip, &tv[0], &tv[1], 0); 65311811Ssam } 65411811Ssam iput(ip); 65511811Ssam } 65611811Ssam 6579167Ssam /* 6589167Ssam * Flush any pending I/O. 6599167Ssam */ 6606254Sroot sync() 66137Sbill { 66237Sbill 6638673Sroot update(); 66437Sbill } 6657535Sroot 6669167Ssam /* 6679167Ssam * Truncate a file given its path name. 6689167Ssam */ 6697701Ssam truncate() 6707701Ssam { 6717701Ssam struct a { 6727701Ssam char *fname; 6739167Ssam u_long length; 6747826Sroot } *uap = (struct a *)u.u_ap; 6757701Ssam struct inode *ip; 6767701Ssam 6779167Ssam ip = namei(uchar, LOOKUP, 1); 6787701Ssam if (ip == NULL) 6797701Ssam return; 6807701Ssam if (access(ip, IWRITE)) 6817701Ssam goto bad; 6827701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 6837701Ssam u.u_error = EISDIR; 6847701Ssam goto bad; 6857701Ssam } 6867701Ssam itrunc(ip, uap->length); 6877701Ssam bad: 6887701Ssam iput(ip); 6897701Ssam } 6907701Ssam 6919167Ssam /* 6929167Ssam * Truncate a file given a file descriptor. 6939167Ssam */ 6947701Ssam ftruncate() 6957701Ssam { 6967701Ssam struct a { 6977701Ssam int fd; 6989167Ssam u_long length; 6997826Sroot } *uap = (struct a *)u.u_ap; 7007701Ssam struct inode *ip; 7017701Ssam struct file *fp; 7027701Ssam 70312756Ssam fp = getinode(uap->fd); 7047701Ssam if (fp == NULL) 7057701Ssam return; 7067701Ssam if ((fp->f_flag&FWRITE) == 0) { 7077701Ssam u.u_error = EINVAL; 7087701Ssam return; 7097701Ssam } 71012756Ssam ip = (struct inode *)fp->f_data; 7117701Ssam ilock(ip); 7127701Ssam itrunc(ip, uap->length); 7139167Ssam iunlock(ip); 7147701Ssam } 7157701Ssam 7169167Ssam /* 7179167Ssam * Synch an open file. 7189167Ssam */ 7199167Ssam fsync() 7209167Ssam { 7219167Ssam struct a { 7229167Ssam int fd; 7239167Ssam } *uap = (struct a *)u.u_ap; 7249167Ssam struct inode *ip; 7259167Ssam struct file *fp; 7269167Ssam 72712756Ssam fp = getinode(uap->fd); 7289167Ssam if (fp == NULL) 7299167Ssam return; 73012756Ssam ip = (struct inode *)fp->f_data; 7319167Ssam ilock(ip); 7329167Ssam syncip(ip); 7339167Ssam iunlock(ip); 7349167Ssam } 7359167Ssam 7369167Ssam /* 7379167Ssam * Rename system call. 7389167Ssam * rename("foo", "bar"); 7399167Ssam * is essentially 7409167Ssam * unlink("bar"); 7419167Ssam * link("foo", "bar"); 7429167Ssam * unlink("foo"); 7439167Ssam * but ``atomically''. Can't do full commit without saving state in the 7449167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7459167Ssam * always guarantee the target exists. 7469167Ssam * 7479167Ssam * Basic algorithm is: 7489167Ssam * 7499167Ssam * 1) Bump link count on source while we're linking it to the 7509167Ssam * target. This also insure the inode won't be deleted out 7519167Ssam * from underneath us while we work. 7529167Ssam * 2) Link source to destination. If destination already exists, 7539167Ssam * delete it first. 7549167Ssam * 3) Unlink source reference to inode if still around. 7559167Ssam * 4) If a directory was moved and the parent of the destination 7569167Ssam * is different from the source, patch the ".." entry in the 7579167Ssam * directory. 7589167Ssam * 7599167Ssam * Source and destination must either both be directories, or both 7609167Ssam * not be directories. If target is a directory, it must be empty. 7619167Ssam */ 7627701Ssam rename() 7637701Ssam { 7647701Ssam struct a { 7657701Ssam char *from; 7667701Ssam char *to; 7677701Ssam } *uap; 7689167Ssam register struct inode *ip, *xp, *dp; 7699167Ssam int oldparent, parentdifferent, doingdirectory; 77010051Ssam int error = 0; 7717701Ssam 7729167Ssam uap = (struct a *)u.u_ap; 77311641Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 7749167Ssam if (ip == NULL) 7759167Ssam return; 7769167Ssam dp = u.u_pdir; 7779167Ssam oldparent = 0, doingdirectory = 0; 7789167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7799167Ssam register struct direct *d; 7809167Ssam 7819167Ssam d = &u.u_dent; 7829167Ssam /* 78311641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7849167Ssam */ 78511641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 78611641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 78711641Ssam (dp == ip)) { 78811641Ssam iput(dp); 78911641Ssam if (dp == ip) 79011641Ssam irele(ip); 79111641Ssam else 79210051Ssam iput(ip); 79311641Ssam u.u_error = EINVAL; 79411641Ssam return; 7959167Ssam } 7969167Ssam oldparent = dp->i_number; 7979167Ssam doingdirectory++; 7989167Ssam } 79911641Ssam iput(dp); 8009167Ssam 8019167Ssam /* 8029167Ssam * 1) Bump link count while we're moving stuff 8039167Ssam * around. If we crash somewhere before 8049167Ssam * completing our work, the link count 8059167Ssam * may be wrong, but correctable. 8069167Ssam */ 8079167Ssam ip->i_nlink++; 8089167Ssam ip->i_flag |= ICHG; 8099167Ssam iupdat(ip, &time, &time, 1); 8109167Ssam iunlock(ip); 8119167Ssam 8129167Ssam /* 8139167Ssam * When the target exists, both the directory 8149167Ssam * and target inodes are returned locked. 8159167Ssam */ 8169167Ssam u.u_dirp = (caddr_t)uap->to; 81715797Smckusick xp = namei(uchar, CREATE | LOCKPARENT | NOCACHE, 0); 81810051Ssam if (u.u_error) { 81910051Ssam error = u.u_error; 8209167Ssam goto out; 82110051Ssam } 8229167Ssam dp = u.u_pdir; 8239167Ssam /* 82411641Ssam * If ".." must be changed (ie the directory gets a new 82512816Smckusick * parent) then the source directory must not be in the 82612816Smckusick * directory heirarchy above the target, as this would 82712816Smckusick * orphan everything below the source directory. Also 82812816Smckusick * the user must have write permission in the source so 82912816Smckusick * as to be able to change "..". We must repeat the call 83012816Smckusick * to namei, as the parent directory is unlocked by the 83112816Smckusick * call to checkpath(). 83211641Ssam */ 83311641Ssam parentdifferent = oldparent != dp->i_number; 83412816Smckusick if (doingdirectory && parentdifferent) { 83512816Smckusick if (access(ip, IWRITE)) 83612816Smckusick goto bad; 83712816Smckusick do { 83812816Smckusick dp = u.u_pdir; 83912816Smckusick if (xp != NULL) 84012816Smckusick iput(xp); 84112816Smckusick u.u_error = checkpath(ip, dp); 84212816Smckusick if (u.u_error) 84312816Smckusick goto out; 84412816Smckusick u.u_dirp = (caddr_t)uap->to; 84515797Smckusick xp = namei(uchar, CREATE | LOCKPARENT | NOCACHE, 0); 84612816Smckusick if (u.u_error) { 84712816Smckusick error = u.u_error; 84812816Smckusick goto out; 84912816Smckusick } 85012816Smckusick } while (dp != u.u_pdir); 85112816Smckusick } 85211641Ssam /* 8539167Ssam * 2) If target doesn't exist, link the target 8549167Ssam * to the source and unlink the source. 8559167Ssam * Otherwise, rewrite the target directory 8569167Ssam * entry to reference the source inode and 8579167Ssam * expunge the original entry's existence. 8589167Ssam */ 8599167Ssam if (xp == NULL) { 8609167Ssam if (dp->i_dev != ip->i_dev) { 86110051Ssam error = EXDEV; 8629167Ssam goto bad; 8639167Ssam } 8649167Ssam /* 8659167Ssam * Account for ".." in directory. 8669167Ssam * When source and destination have the 8679167Ssam * same parent we don't fool with the 8689167Ssam * link count -- this isn't required 8699167Ssam * because we do a similar check below. 8709167Ssam */ 8719167Ssam if (doingdirectory && parentdifferent) { 8729167Ssam dp->i_nlink++; 8739167Ssam dp->i_flag |= ICHG; 8749167Ssam iupdat(dp, &time, &time, 1); 8759167Ssam } 87610850Ssam error = direnter(ip); 87710850Ssam if (error) 8789167Ssam goto out; 8799167Ssam } else { 8809167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 88110051Ssam error = EXDEV; 8829167Ssam goto bad; 8839167Ssam } 8849167Ssam /* 88510590Ssam * Short circuit rename(foo, foo). 88610590Ssam */ 88710590Ssam if (xp->i_number == ip->i_number) 88810590Ssam goto bad; 88910590Ssam /* 89010051Ssam * Target must be empty if a directory 89110051Ssam * and have no links to it. 8929167Ssam * Also, insure source and target are 8939167Ssam * compatible (both directories, or both 8949167Ssam * not directories). 8959167Ssam */ 8969167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 89710051Ssam if (!dirempty(xp) || xp->i_nlink > 2) { 89810051Ssam error = ENOTEMPTY; 8999167Ssam goto bad; 9009167Ssam } 9019167Ssam if (!doingdirectory) { 90210051Ssam error = ENOTDIR; 9039167Ssam goto bad; 9049167Ssam } 9059167Ssam } else if (doingdirectory) { 90610051Ssam error = EISDIR; 9079167Ssam goto bad; 9089167Ssam } 9099167Ssam dirrewrite(dp, ip); 91010051Ssam if (u.u_error) { 91110051Ssam error = u.u_error; 9129167Ssam goto bad1; 91310051Ssam } 9149167Ssam /* 91510051Ssam * Adjust the link count of the target to 91610051Ssam * reflect the dirrewrite above. If this is 91710051Ssam * a directory it is empty and there are 91810051Ssam * no links to it, so we can squash the inode and 91910051Ssam * any space associated with it. We disallowed 92010051Ssam * renaming over top of a directory with links to 92110051Ssam * it above, as we've no way to determine if 92210051Ssam * we've got a link or the directory itself, and 92310051Ssam * if we get a link, then ".." will be screwed up. 9249167Ssam */ 92510051Ssam xp->i_nlink--; 9269167Ssam if (doingdirectory) { 92710051Ssam if (--xp->i_nlink != 0) 92810051Ssam panic("rename: linked directory"); 9299167Ssam itrunc(xp, (u_long)0); 93010051Ssam } 9319167Ssam xp->i_flag |= ICHG; 9329167Ssam iput(xp); 93310246Ssam xp = NULL; 9349167Ssam } 9359167Ssam 9369167Ssam /* 9379167Ssam * 3) Unlink the source. 9389167Ssam */ 9399167Ssam u.u_dirp = uap->from; 9409167Ssam dp = namei(uchar, DELETE, 0); 9419167Ssam /* 9429167Ssam * Insure directory entry still exists and 9439167Ssam * has not changed since the start of all 9449167Ssam * this. If either has occured, forget about 945*16652Ssam * about deleting the original entry. 9469167Ssam */ 947*16652Ssam if (dp != NULL && u.u_dent.d_ino == ip->i_number) { 9489167Ssam /* 9499167Ssam * If source is a directory, must adjust 9509167Ssam * link count of parent directory also. 9519167Ssam * If target didn't exist and source and 9529167Ssam * target have the same parent, then we 9539167Ssam * needn't touch the link count, it all 9549167Ssam * balances out in the end. Otherwise, we 9559167Ssam * must do so to reflect deletion of ".." 9569167Ssam * done above. 9579167Ssam */ 9589167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9599167Ssam dp->i_nlink--; 9609167Ssam dp->i_flag |= ICHG; 9619167Ssam } 9629167Ssam if (dirremove()) { 9639167Ssam ip->i_nlink--; 9649167Ssam ip->i_flag |= ICHG; 9659167Ssam } 96610051Ssam if (error == 0) /* conservative */ 96710051Ssam error = u.u_error; 9689167Ssam } 9699167Ssam irele(ip); 9709167Ssam if (dp) 9719167Ssam iput(dp); 9729167Ssam 9739167Ssam /* 9749167Ssam * 4) Renaming a directory with the parent 9759167Ssam * different requires ".." to be rewritten. 9769167Ssam * The window is still there for ".." to 9779167Ssam * be inconsistent, but this is unavoidable, 9789167Ssam * and a lot shorter than when it was done 9799167Ssam * in a user process. 9809167Ssam */ 98110051Ssam if (doingdirectory && parentdifferent && error == 0) { 9829167Ssam struct dirtemplate dirbuf; 9839167Ssam 9849167Ssam u.u_dirp = uap->to; 9859167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 9869167Ssam if (ip == NULL) { 9879167Ssam printf("rename: .. went away\n"); 9889167Ssam return; 9899167Ssam } 9909167Ssam dp = u.u_pdir; 9919167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 9929167Ssam printf("rename: .. not a directory\n"); 9939167Ssam goto stuck; 9949167Ssam } 99510051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 9969167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 99710051Ssam if (error == 0) { 9989167Ssam dirbuf.dotdot_ino = dp->i_number; 99916644Ssam dp->i_id = ++nextinodeid; 10009167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10019167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10029167Ssam } 10039167Ssam stuck: 10049167Ssam irele(dp); 10059167Ssam iput(ip); 10069167Ssam } 100710051Ssam goto done; 100810051Ssam 10099167Ssam bad: 101010246Ssam iput(dp); 10119167Ssam bad1: 10129167Ssam if (xp) 101310246Ssam iput(xp); 10149167Ssam out: 10159167Ssam ip->i_nlink--; 10169167Ssam ip->i_flag |= ICHG; 10179167Ssam irele(ip); 101810051Ssam done: 101910051Ssam if (error) 102010051Ssam u.u_error = error; 10217701Ssam } 10227701Ssam 10237535Sroot /* 10247535Sroot * Make a new file. 10257535Sroot */ 10267535Sroot struct inode * 10277535Sroot maknode(mode) 10287535Sroot int mode; 10297535Sroot { 10307535Sroot register struct inode *ip; 10317535Sroot ino_t ipref; 10327535Sroot 10337535Sroot if ((mode & IFMT) == IFDIR) 10347535Sroot ipref = dirpref(u.u_pdir->i_fs); 10357535Sroot else 10367535Sroot ipref = u.u_pdir->i_number; 10377535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10387535Sroot if (ip == NULL) { 10397535Sroot iput(u.u_pdir); 10407701Ssam return (NULL); 10417535Sroot } 10427701Ssam #ifdef QUOTA 10437535Sroot if (ip->i_dquot != NODQUOT) 10447535Sroot panic("maknode: dquot"); 10457535Sroot #endif 10467535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10477535Sroot if ((mode & IFMT) == 0) 10487535Sroot mode |= IFREG; 10497535Sroot ip->i_mode = mode & ~u.u_cmask; 10507535Sroot ip->i_nlink = 1; 10517535Sroot ip->i_uid = u.u_uid; 10527535Sroot ip->i_gid = u.u_pdir->i_gid; 105311811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 105411811Ssam ip->i_mode &= ~ISGID; 10557701Ssam #ifdef QUOTA 10567535Sroot ip->i_dquot = inoquota(ip); 10577535Sroot #endif 10587535Sroot 10597535Sroot /* 10607535Sroot * Make sure inode goes to disk before directory entry. 10617535Sroot */ 10628673Sroot iupdat(ip, &time, &time, 1); 106310850Ssam u.u_error = direnter(ip); 10647535Sroot if (u.u_error) { 10657535Sroot /* 106610850Ssam * Write error occurred trying to update directory 106710850Ssam * so must deallocate the inode. 10687535Sroot */ 10697535Sroot ip->i_nlink = 0; 10707535Sroot ip->i_flag |= ICHG; 10717535Sroot iput(ip); 10727701Ssam return (NULL); 10737535Sroot } 10747701Ssam return (ip); 10757535Sroot } 107612756Ssam 107712756Ssam /* 107812756Ssam * A virgin directory (no blushing please). 107912756Ssam */ 108012756Ssam struct dirtemplate mastertemplate = { 108112756Ssam 0, 12, 1, ".", 108212756Ssam 0, DIRBLKSIZ - 12, 2, ".." 108312756Ssam }; 108412756Ssam 108512756Ssam /* 108612756Ssam * Mkdir system call 108712756Ssam */ 108812756Ssam mkdir() 108912756Ssam { 109012756Ssam struct a { 109112756Ssam char *name; 109212756Ssam int dmode; 109312756Ssam } *uap; 109412756Ssam register struct inode *ip, *dp; 109512756Ssam struct dirtemplate dirtemplate; 109612756Ssam 109712756Ssam uap = (struct a *)u.u_ap; 109812756Ssam ip = namei(uchar, CREATE, 0); 109912756Ssam if (u.u_error) 110012756Ssam return; 110112756Ssam if (ip != NULL) { 110212756Ssam iput(ip); 110312756Ssam u.u_error = EEXIST; 110412756Ssam return; 110512756Ssam } 110612756Ssam dp = u.u_pdir; 110712756Ssam uap->dmode &= 0777; 110812756Ssam uap->dmode |= IFDIR; 110912756Ssam /* 111012756Ssam * Must simulate part of maknode here 111112756Ssam * in order to acquire the inode, but 111212756Ssam * not have it entered in the parent 111312756Ssam * directory. The entry is made later 111412756Ssam * after writing "." and ".." entries out. 111512756Ssam */ 111612756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 111712756Ssam if (ip == NULL) { 111812756Ssam iput(dp); 111912756Ssam return; 112012756Ssam } 112112756Ssam #ifdef QUOTA 112212756Ssam if (ip->i_dquot != NODQUOT) 112312756Ssam panic("mkdir: dquot"); 112412756Ssam #endif 112512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 112612756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 112712756Ssam ip->i_nlink = 2; 112812756Ssam ip->i_uid = u.u_uid; 112912756Ssam ip->i_gid = dp->i_gid; 113012756Ssam #ifdef QUOTA 113112756Ssam ip->i_dquot = inoquota(ip); 113212756Ssam #endif 113312756Ssam iupdat(ip, &time, &time, 1); 113412756Ssam 113512756Ssam /* 113612756Ssam * Bump link count in parent directory 113712756Ssam * to reflect work done below. Should 113812756Ssam * be done before reference is created 113912756Ssam * so reparation is possible if we crash. 114012756Ssam */ 114112756Ssam dp->i_nlink++; 114212756Ssam dp->i_flag |= ICHG; 114312756Ssam iupdat(dp, &time, &time, 1); 114412756Ssam 114512756Ssam /* 114612756Ssam * Initialize directory with "." 114712756Ssam * and ".." from static template. 114812756Ssam */ 114912756Ssam dirtemplate = mastertemplate; 115012756Ssam dirtemplate.dot_ino = ip->i_number; 115112756Ssam dirtemplate.dotdot_ino = dp->i_number; 115212756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 115312756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 115412756Ssam if (u.u_error) { 115512756Ssam dp->i_nlink--; 115612756Ssam dp->i_flag |= ICHG; 115712756Ssam goto bad; 115812756Ssam } 115912756Ssam /* 116012756Ssam * Directory all set up, now 116112756Ssam * install the entry for it in 116212756Ssam * the parent directory. 116312756Ssam */ 116412756Ssam u.u_error = direnter(ip); 116512756Ssam dp = NULL; 116612756Ssam if (u.u_error) { 116712756Ssam u.u_dirp = uap->name; 116815797Smckusick dp = namei(uchar, LOOKUP | NOCACHE, 0); 116912756Ssam if (dp) { 117012756Ssam dp->i_nlink--; 117112756Ssam dp->i_flag |= ICHG; 117212756Ssam } 117312756Ssam } 117412756Ssam bad: 117512756Ssam /* 117612756Ssam * No need to do an explicit itrunc here, 117712756Ssam * irele will do this for us because we set 117812756Ssam * the link count to 0. 117912756Ssam */ 118012756Ssam if (u.u_error) { 118112756Ssam ip->i_nlink = 0; 118212756Ssam ip->i_flag |= ICHG; 118312756Ssam } 118412756Ssam if (dp) 118512756Ssam iput(dp); 118612756Ssam iput(ip); 118712756Ssam } 118812756Ssam 118912756Ssam /* 119012756Ssam * Rmdir system call. 119112756Ssam */ 119212756Ssam rmdir() 119312756Ssam { 119412756Ssam struct a { 119512756Ssam char *name; 119612756Ssam }; 119712756Ssam register struct inode *ip, *dp; 119812756Ssam 119912756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 120012756Ssam if (ip == NULL) 120112756Ssam return; 120212756Ssam dp = u.u_pdir; 120312756Ssam /* 120412756Ssam * No rmdir "." please. 120512756Ssam */ 120612756Ssam if (dp == ip) { 120712756Ssam irele(dp); 120812756Ssam iput(ip); 120912756Ssam u.u_error = EINVAL; 121012756Ssam return; 121112756Ssam } 121212756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 121312756Ssam u.u_error = ENOTDIR; 121412756Ssam goto out; 121512756Ssam } 121612756Ssam /* 121712756Ssam * Don't remove a mounted on directory. 121812756Ssam */ 121912756Ssam if (ip->i_dev != dp->i_dev) { 122012756Ssam u.u_error = EBUSY; 122112756Ssam goto out; 122212756Ssam } 122312756Ssam /* 122412756Ssam * Verify the directory is empty (and valid). 122512756Ssam * (Rmdir ".." won't be valid since 122612756Ssam * ".." will contain a reference to 122712756Ssam * the current directory and thus be 122812756Ssam * non-empty.) 122912756Ssam */ 123012756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 123112756Ssam u.u_error = ENOTEMPTY; 123212756Ssam goto out; 123312756Ssam } 123412756Ssam /* 123512756Ssam * Delete reference to directory before purging 123612756Ssam * inode. If we crash in between, the directory 123712756Ssam * will be reattached to lost+found, 123812756Ssam */ 123912756Ssam if (dirremove() == 0) 124012756Ssam goto out; 124112756Ssam dp->i_nlink--; 124212756Ssam dp->i_flag |= ICHG; 124312756Ssam iput(dp); 124412756Ssam dp = NULL; 124512756Ssam /* 124612756Ssam * Truncate inode. The only stuff left 124712756Ssam * in the directory is "." and "..". The 124812756Ssam * "." reference is inconsequential since 124912756Ssam * we're quashing it. The ".." reference 125012756Ssam * has already been adjusted above. We've 125112756Ssam * removed the "." reference and the reference 125212756Ssam * in the parent directory, but there may be 125312756Ssam * other hard links so decrement by 2 and 125412756Ssam * worry about them later. 125512756Ssam */ 125612756Ssam ip->i_nlink -= 2; 125712756Ssam itrunc(ip, (u_long)0); 125812756Ssam out: 125912756Ssam if (dp) 126012756Ssam iput(dp); 126112756Ssam iput(ip); 126212756Ssam } 126312756Ssam 126412756Ssam struct file * 126512756Ssam getinode(fdes) 126612756Ssam int fdes; 126712756Ssam { 126816540Ssam struct file *fp; 126912756Ssam 127016540Ssam if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { 127116540Ssam u.u_error = EBADF; 127216540Ssam return ((struct file *)0); 127316540Ssam } 127412756Ssam if (fp->f_type != DTYPE_INODE) { 127512756Ssam u.u_error = EINVAL; 127616540Ssam return ((struct file *)0); 127712756Ssam } 127812756Ssam return (fp); 127912756Ssam } 128012756Ssam 128112756Ssam /* 128212756Ssam * mode mask for creation of files 128312756Ssam */ 128412756Ssam umask() 128512756Ssam { 128612756Ssam register struct a { 128712756Ssam int mask; 128812756Ssam } *uap; 128912756Ssam 129012756Ssam uap = (struct a *)u.u_ap; 129112756Ssam u.u_r.r_val1 = u.u_cmask; 129212756Ssam u.u_cmask = uap->mask & 07777; 129312756Ssam } 1294