1*15093Smckusick /* vfs_syscalls.c 6.2 83/09/25 */ 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 216*15093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 21712756Ssam case IFCHR: 21812756Ssam case IFBLK: 21912756Ssam if (uap->dev) { 22012756Ssam /* 22112756Ssam * Want to be able to use this to make badblock 22212756Ssam * inodes, so don't truncate the dev number. 22312756Ssam */ 22412756Ssam ip->i_rdev = uap->dev; 22512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 22612756Ssam } 2276254Sroot } 2286254Sroot 2296254Sroot out: 2306254Sroot iput(ip); 2316254Sroot } 2326254Sroot 2336254Sroot /* 2346254Sroot * link system call 2356254Sroot */ 2366254Sroot link() 2376254Sroot { 2386254Sroot register struct inode *ip, *xp; 2396254Sroot register struct a { 2406254Sroot char *target; 2416254Sroot char *linkname; 2426254Sroot } *uap; 2436254Sroot 2446254Sroot uap = (struct a *)u.u_ap; 2459167Ssam ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */ 2466254Sroot if (ip == NULL) 2476254Sroot return; 2489167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2497439Sroot iput(ip); 2507439Sroot return; 2517439Sroot } 2526254Sroot ip->i_nlink++; 2536254Sroot ip->i_flag |= ICHG; 2548673Sroot iupdat(ip, &time, &time, 1); 2557122Smckusick iunlock(ip); 2566254Sroot u.u_dirp = (caddr_t)uap->linkname; 2579167Ssam xp = namei(uchar, CREATE, 0); 2586254Sroot if (xp != NULL) { 2596254Sroot u.u_error = EEXIST; 2606254Sroot iput(xp); 2616254Sroot goto out; 2626254Sroot } 2636254Sroot if (u.u_error) 2646254Sroot goto out; 2656254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2666254Sroot iput(u.u_pdir); 2676254Sroot u.u_error = EXDEV; 2686254Sroot goto out; 2696254Sroot } 27010850Ssam u.u_error = direnter(ip); 2716254Sroot out: 2726254Sroot if (u.u_error) { 2736254Sroot ip->i_nlink--; 2746254Sroot ip->i_flag |= ICHG; 2756254Sroot } 2767142Smckusick irele(ip); 2776254Sroot } 2786254Sroot 2796254Sroot /* 2806254Sroot * symlink -- make a symbolic link 2816254Sroot */ 2826254Sroot symlink() 2836254Sroot { 2846254Sroot register struct a { 2856254Sroot char *target; 2866254Sroot char *linkname; 2876254Sroot } *uap; 2886254Sroot register struct inode *ip; 2896254Sroot register char *tp; 2906254Sroot register c, nc; 2916254Sroot 2926254Sroot uap = (struct a *)u.u_ap; 2936254Sroot tp = uap->target; 2946254Sroot nc = 0; 2956254Sroot while (c = fubyte(tp)) { 2966254Sroot if (c < 0) { 2976254Sroot u.u_error = EFAULT; 2986254Sroot return; 2996254Sroot } 3006254Sroot tp++; 3016254Sroot nc++; 3026254Sroot } 3036254Sroot u.u_dirp = uap->linkname; 3049167Ssam ip = namei(uchar, CREATE, 0); 3056254Sroot if (ip) { 3066254Sroot iput(ip); 3076254Sroot u.u_error = EEXIST; 3086254Sroot return; 3096254Sroot } 3106254Sroot if (u.u_error) 3116254Sroot return; 3126254Sroot ip = maknode(IFLNK | 0777); 3136254Sroot if (ip == NULL) 3146254Sroot return; 3157826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3169167Ssam /* handle u.u_error != 0 */ 3176254Sroot iput(ip); 3186254Sroot } 3196254Sroot 3206254Sroot /* 3216254Sroot * Unlink system call. 3226254Sroot * Hard to avoid races here, especially 3236254Sroot * in unlinking directories. 3246254Sroot */ 3256254Sroot unlink() 3266254Sroot { 3276254Sroot struct a { 3286254Sroot char *fname; 3296254Sroot }; 3309167Ssam register struct inode *ip, *dp; 3316254Sroot 3329167Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 3339167Ssam if (ip == NULL) 3346254Sroot return; 3359167Ssam dp = u.u_pdir; 3369167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3376254Sroot goto out; 3386254Sroot /* 3396254Sroot * Don't unlink a mounted file. 3406254Sroot */ 3419167Ssam if (ip->i_dev != dp->i_dev) { 3426254Sroot u.u_error = EBUSY; 3436254Sroot goto out; 3446254Sroot } 3456254Sroot if (ip->i_flag&ITEXT) 3466254Sroot xrele(ip); /* try once to free text */ 3477535Sroot if (dirremove()) { 3487535Sroot ip->i_nlink--; 3497535Sroot ip->i_flag |= ICHG; 3506254Sroot } 3516254Sroot out: 3529167Ssam if (dp == ip) 3537142Smckusick irele(ip); 3547142Smckusick else 3557142Smckusick iput(ip); 3569167Ssam iput(dp); 3576254Sroot } 3586254Sroot 3596254Sroot /* 3606254Sroot * Seek system call 3616254Sroot */ 3628040Sroot lseek() 3636254Sroot { 3646254Sroot register struct file *fp; 3656254Sroot register struct a { 3667701Ssam int fd; 3676254Sroot off_t off; 3686254Sroot int sbase; 3696254Sroot } *uap; 3706254Sroot 3716254Sroot uap = (struct a *)u.u_ap; 37212756Ssam fp = getinode(uap->fd); 3736254Sroot if (fp == NULL) 3746254Sroot return; 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; 8179167Ssam xp = namei(uchar, CREATE | LOCKPARENT, 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; 84512816Smckusick xp = namei(uchar, CREATE | LOCKPARENT, 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 9459167Ssam * about deleting the original entry and just 9469167Ssam * adjust the link count in the inode. 9479167Ssam */ 9489167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 9499167Ssam ip->i_nlink--; 9509167Ssam ip->i_flag |= ICHG; 9519167Ssam } else { 9529167Ssam /* 9539167Ssam * If source is a directory, must adjust 9549167Ssam * link count of parent directory also. 9559167Ssam * If target didn't exist and source and 9569167Ssam * target have the same parent, then we 9579167Ssam * needn't touch the link count, it all 9589167Ssam * balances out in the end. Otherwise, we 9599167Ssam * must do so to reflect deletion of ".." 9609167Ssam * done above. 9619167Ssam */ 9629167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9639167Ssam dp->i_nlink--; 9649167Ssam dp->i_flag |= ICHG; 9659167Ssam } 9669167Ssam if (dirremove()) { 9679167Ssam ip->i_nlink--; 9689167Ssam ip->i_flag |= ICHG; 9699167Ssam } 97010051Ssam if (error == 0) /* conservative */ 97110051Ssam error = u.u_error; 9729167Ssam } 9739167Ssam irele(ip); 9749167Ssam if (dp) 9759167Ssam iput(dp); 9769167Ssam 9779167Ssam /* 9789167Ssam * 4) Renaming a directory with the parent 9799167Ssam * different requires ".." to be rewritten. 9809167Ssam * The window is still there for ".." to 9819167Ssam * be inconsistent, but this is unavoidable, 9829167Ssam * and a lot shorter than when it was done 9839167Ssam * in a user process. 9849167Ssam */ 98510051Ssam if (doingdirectory && parentdifferent && error == 0) { 9869167Ssam struct dirtemplate dirbuf; 9879167Ssam 9889167Ssam u.u_dirp = uap->to; 9899167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 9909167Ssam if (ip == NULL) { 9919167Ssam printf("rename: .. went away\n"); 9929167Ssam return; 9939167Ssam } 9949167Ssam dp = u.u_pdir; 9959167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 9969167Ssam printf("rename: .. not a directory\n"); 9979167Ssam goto stuck; 9989167Ssam } 99910051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 10009167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 100110051Ssam if (error == 0) { 10029167Ssam dirbuf.dotdot_ino = dp->i_number; 10039167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10049167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10059167Ssam } 10069167Ssam stuck: 10079167Ssam irele(dp); 10089167Ssam iput(ip); 10099167Ssam } 101010051Ssam goto done; 101110051Ssam 10129167Ssam bad: 101310246Ssam iput(dp); 10149167Ssam bad1: 10159167Ssam if (xp) 101610246Ssam iput(xp); 10179167Ssam out: 10189167Ssam ip->i_nlink--; 10199167Ssam ip->i_flag |= ICHG; 10209167Ssam irele(ip); 102110051Ssam done: 102210051Ssam if (error) 102310051Ssam u.u_error = error; 10247701Ssam } 10257701Ssam 10267535Sroot /* 10277535Sroot * Make a new file. 10287535Sroot */ 10297535Sroot struct inode * 10307535Sroot maknode(mode) 10317535Sroot int mode; 10327535Sroot { 10337535Sroot register struct inode *ip; 10347535Sroot ino_t ipref; 10357535Sroot 10367535Sroot if ((mode & IFMT) == IFDIR) 10377535Sroot ipref = dirpref(u.u_pdir->i_fs); 10387535Sroot else 10397535Sroot ipref = u.u_pdir->i_number; 10407535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10417535Sroot if (ip == NULL) { 10427535Sroot iput(u.u_pdir); 10437701Ssam return (NULL); 10447535Sroot } 10457701Ssam #ifdef QUOTA 10467535Sroot if (ip->i_dquot != NODQUOT) 10477535Sroot panic("maknode: dquot"); 10487535Sroot #endif 10497535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10507535Sroot if ((mode & IFMT) == 0) 10517535Sroot mode |= IFREG; 10527535Sroot ip->i_mode = mode & ~u.u_cmask; 10537535Sroot ip->i_nlink = 1; 10547535Sroot ip->i_uid = u.u_uid; 10557535Sroot ip->i_gid = u.u_pdir->i_gid; 105611811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 105711811Ssam ip->i_mode &= ~ISGID; 10587701Ssam #ifdef QUOTA 10597535Sroot ip->i_dquot = inoquota(ip); 10607535Sroot #endif 10617535Sroot 10627535Sroot /* 10637535Sroot * Make sure inode goes to disk before directory entry. 10647535Sroot */ 10658673Sroot iupdat(ip, &time, &time, 1); 106610850Ssam u.u_error = direnter(ip); 10677535Sroot if (u.u_error) { 10687535Sroot /* 106910850Ssam * Write error occurred trying to update directory 107010850Ssam * so must deallocate the inode. 10717535Sroot */ 10727535Sroot ip->i_nlink = 0; 10737535Sroot ip->i_flag |= ICHG; 10747535Sroot iput(ip); 10757701Ssam return (NULL); 10767535Sroot } 10777701Ssam return (ip); 10787535Sroot } 107912756Ssam 108012756Ssam /* 108112756Ssam * A virgin directory (no blushing please). 108212756Ssam */ 108312756Ssam struct dirtemplate mastertemplate = { 108412756Ssam 0, 12, 1, ".", 108512756Ssam 0, DIRBLKSIZ - 12, 2, ".." 108612756Ssam }; 108712756Ssam 108812756Ssam /* 108912756Ssam * Mkdir system call 109012756Ssam */ 109112756Ssam mkdir() 109212756Ssam { 109312756Ssam struct a { 109412756Ssam char *name; 109512756Ssam int dmode; 109612756Ssam } *uap; 109712756Ssam register struct inode *ip, *dp; 109812756Ssam struct dirtemplate dirtemplate; 109912756Ssam 110012756Ssam uap = (struct a *)u.u_ap; 110112756Ssam ip = namei(uchar, CREATE, 0); 110212756Ssam if (u.u_error) 110312756Ssam return; 110412756Ssam if (ip != NULL) { 110512756Ssam iput(ip); 110612756Ssam u.u_error = EEXIST; 110712756Ssam return; 110812756Ssam } 110912756Ssam dp = u.u_pdir; 111012756Ssam uap->dmode &= 0777; 111112756Ssam uap->dmode |= IFDIR; 111212756Ssam /* 111312756Ssam * Must simulate part of maknode here 111412756Ssam * in order to acquire the inode, but 111512756Ssam * not have it entered in the parent 111612756Ssam * directory. The entry is made later 111712756Ssam * after writing "." and ".." entries out. 111812756Ssam */ 111912756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 112012756Ssam if (ip == NULL) { 112112756Ssam iput(dp); 112212756Ssam return; 112312756Ssam } 112412756Ssam #ifdef QUOTA 112512756Ssam if (ip->i_dquot != NODQUOT) 112612756Ssam panic("mkdir: dquot"); 112712756Ssam #endif 112812756Ssam ip->i_flag |= IACC|IUPD|ICHG; 112912756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 113012756Ssam ip->i_nlink = 2; 113112756Ssam ip->i_uid = u.u_uid; 113212756Ssam ip->i_gid = dp->i_gid; 113312756Ssam #ifdef QUOTA 113412756Ssam ip->i_dquot = inoquota(ip); 113512756Ssam #endif 113612756Ssam iupdat(ip, &time, &time, 1); 113712756Ssam 113812756Ssam /* 113912756Ssam * Bump link count in parent directory 114012756Ssam * to reflect work done below. Should 114112756Ssam * be done before reference is created 114212756Ssam * so reparation is possible if we crash. 114312756Ssam */ 114412756Ssam dp->i_nlink++; 114512756Ssam dp->i_flag |= ICHG; 114612756Ssam iupdat(dp, &time, &time, 1); 114712756Ssam 114812756Ssam /* 114912756Ssam * Initialize directory with "." 115012756Ssam * and ".." from static template. 115112756Ssam */ 115212756Ssam dirtemplate = mastertemplate; 115312756Ssam dirtemplate.dot_ino = ip->i_number; 115412756Ssam dirtemplate.dotdot_ino = dp->i_number; 115512756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 115612756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 115712756Ssam if (u.u_error) { 115812756Ssam dp->i_nlink--; 115912756Ssam dp->i_flag |= ICHG; 116012756Ssam goto bad; 116112756Ssam } 116212756Ssam /* 116312756Ssam * Directory all set up, now 116412756Ssam * install the entry for it in 116512756Ssam * the parent directory. 116612756Ssam */ 116712756Ssam u.u_error = direnter(ip); 116812756Ssam dp = NULL; 116912756Ssam if (u.u_error) { 117012756Ssam u.u_dirp = uap->name; 117112756Ssam dp = namei(uchar, LOOKUP, 0); 117212756Ssam if (dp) { 117312756Ssam dp->i_nlink--; 117412756Ssam dp->i_flag |= ICHG; 117512756Ssam } 117612756Ssam } 117712756Ssam bad: 117812756Ssam /* 117912756Ssam * No need to do an explicit itrunc here, 118012756Ssam * irele will do this for us because we set 118112756Ssam * the link count to 0. 118212756Ssam */ 118312756Ssam if (u.u_error) { 118412756Ssam ip->i_nlink = 0; 118512756Ssam ip->i_flag |= ICHG; 118612756Ssam } 118712756Ssam if (dp) 118812756Ssam iput(dp); 118912756Ssam iput(ip); 119012756Ssam } 119112756Ssam 119212756Ssam /* 119312756Ssam * Rmdir system call. 119412756Ssam */ 119512756Ssam rmdir() 119612756Ssam { 119712756Ssam struct a { 119812756Ssam char *name; 119912756Ssam }; 120012756Ssam register struct inode *ip, *dp; 120112756Ssam 120212756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 120312756Ssam if (ip == NULL) 120412756Ssam return; 120512756Ssam dp = u.u_pdir; 120612756Ssam /* 120712756Ssam * No rmdir "." please. 120812756Ssam */ 120912756Ssam if (dp == ip) { 121012756Ssam irele(dp); 121112756Ssam iput(ip); 121212756Ssam u.u_error = EINVAL; 121312756Ssam return; 121412756Ssam } 121512756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 121612756Ssam u.u_error = ENOTDIR; 121712756Ssam goto out; 121812756Ssam } 121912756Ssam /* 122012756Ssam * Don't remove a mounted on directory. 122112756Ssam */ 122212756Ssam if (ip->i_dev != dp->i_dev) { 122312756Ssam u.u_error = EBUSY; 122412756Ssam goto out; 122512756Ssam } 122612756Ssam /* 122712756Ssam * Verify the directory is empty (and valid). 122812756Ssam * (Rmdir ".." won't be valid since 122912756Ssam * ".." will contain a reference to 123012756Ssam * the current directory and thus be 123112756Ssam * non-empty.) 123212756Ssam */ 123312756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 123412756Ssam u.u_error = ENOTEMPTY; 123512756Ssam goto out; 123612756Ssam } 123712756Ssam /* 123812756Ssam * Delete reference to directory before purging 123912756Ssam * inode. If we crash in between, the directory 124012756Ssam * will be reattached to lost+found, 124112756Ssam */ 124212756Ssam if (dirremove() == 0) 124312756Ssam goto out; 124412756Ssam dp->i_nlink--; 124512756Ssam dp->i_flag |= ICHG; 124612756Ssam iput(dp); 124712756Ssam dp = NULL; 124812756Ssam /* 124912756Ssam * Truncate inode. The only stuff left 125012756Ssam * in the directory is "." and "..". The 125112756Ssam * "." reference is inconsequential since 125212756Ssam * we're quashing it. The ".." reference 125312756Ssam * has already been adjusted above. We've 125412756Ssam * removed the "." reference and the reference 125512756Ssam * in the parent directory, but there may be 125612756Ssam * other hard links so decrement by 2 and 125712756Ssam * worry about them later. 125812756Ssam */ 125912756Ssam ip->i_nlink -= 2; 126012756Ssam itrunc(ip, (u_long)0); 126112756Ssam out: 126212756Ssam if (dp) 126312756Ssam iput(dp); 126412756Ssam iput(ip); 126512756Ssam } 126612756Ssam 126712756Ssam struct file * 126812756Ssam getinode(fdes) 126912756Ssam int fdes; 127012756Ssam { 127112756Ssam register struct file *fp; 127212756Ssam 127312756Ssam fp = getf(fdes); 127412756Ssam if (fp == 0) 127512756Ssam return (0); 127612756Ssam if (fp->f_type != DTYPE_INODE) { 127712756Ssam u.u_error = EINVAL; 127812756Ssam return (0); 127912756Ssam } 128012756Ssam return (fp); 128112756Ssam } 128212756Ssam 128312756Ssam /* 128412756Ssam * mode mask for creation of files 128512756Ssam */ 128612756Ssam umask() 128712756Ssam { 128812756Ssam register struct a { 128912756Ssam int mask; 129012756Ssam } *uap; 129112756Ssam 129212756Ssam uap = (struct a *)u.u_ap; 129312756Ssam u.u_r.r_val1 = u.u_cmask; 129412756Ssam u.u_cmask = uap->mask & 07777; 129512756Ssam } 1296