1*16032Skarels /* vfs_syscalls.c 6.5 84/02/10 */ 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; 149*16032Skarels 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; 37012756Ssam fp = getinode(uap->fd); 3716254Sroot if (fp == NULL) 3726254Sroot return; 37313878Ssam switch (uap->sbase) { 37413878Ssam 37513878Ssam case L_INCR: 37613878Ssam fp->f_offset += uap->off; 37713878Ssam break; 37813878Ssam 37913878Ssam case L_XTND: 38013878Ssam fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; 38113878Ssam break; 38213878Ssam 38313878Ssam case L_SET: 38413878Ssam fp->f_offset = uap->off; 38513878Ssam break; 38613878Ssam 38713878Ssam default: 38813878Ssam u.u_error = EINVAL; 38913878Ssam return; 39013878Ssam } 39113878Ssam u.u_r.r_off = fp->f_offset; 3926254Sroot } 3936254Sroot 3946254Sroot /* 3956254Sroot * Access system call 3966254Sroot */ 3976254Sroot saccess() 3986254Sroot { 3996254Sroot register svuid, svgid; 4006254Sroot register struct inode *ip; 4016254Sroot register struct a { 4026254Sroot char *fname; 4036254Sroot int fmode; 4046254Sroot } *uap; 4056254Sroot 4066254Sroot uap = (struct a *)u.u_ap; 4076254Sroot svuid = u.u_uid; 4086254Sroot svgid = u.u_gid; 4096254Sroot u.u_uid = u.u_ruid; 4106254Sroot u.u_gid = u.u_rgid; 4119167Ssam ip = namei(uchar, LOOKUP, 1); 4126254Sroot if (ip != NULL) { 41312756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4147701Ssam goto done; 41512756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4167701Ssam goto done; 41712756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4187701Ssam goto done; 4197701Ssam done: 4206254Sroot iput(ip); 4216254Sroot } 4226254Sroot u.u_uid = svuid; 4236254Sroot u.u_gid = svgid; 4246254Sroot } 4256254Sroot 4266254Sroot /* 4276574Smckusic * Stat system call. This version follows links. 42837Sbill */ 42937Sbill stat() 43037Sbill { 43137Sbill 43212756Ssam stat1(1); 43337Sbill } 43437Sbill 43537Sbill /* 4366574Smckusic * Lstat system call. This version does not follow links. 4375992Swnj */ 4385992Swnj lstat() 4395992Swnj { 44012756Ssam 44112756Ssam stat1(0); 44212756Ssam } 44312756Ssam 44412756Ssam stat1(follow) 44512756Ssam int follow; 44612756Ssam { 4475992Swnj register struct inode *ip; 4485992Swnj register struct a { 4495992Swnj char *fname; 45012756Ssam struct stat *ub; 4515992Swnj } *uap; 45212756Ssam struct stat sb; 4535992Swnj 4545992Swnj uap = (struct a *)u.u_ap; 45512756Ssam ip = namei(uchar, LOOKUP, follow); 4565992Swnj if (ip == NULL) 4575992Swnj return; 45813043Ssam (void) ino_stat(ip, &sb); 4595992Swnj iput(ip); 46012756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4615992Swnj } 4625992Swnj 4635992Swnj /* 4645992Swnj * Return target name of a symbolic link 46537Sbill */ 4665992Swnj readlink() 4675992Swnj { 4685992Swnj register struct inode *ip; 4695992Swnj register struct a { 4705992Swnj char *name; 4715992Swnj char *buf; 4725992Swnj int count; 4737826Sroot } *uap = (struct a *)u.u_ap; 4747826Sroot int resid; 4755992Swnj 4769167Ssam ip = namei(uchar, LOOKUP, 0); 4775992Swnj if (ip == NULL) 4785992Swnj return; 4795992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 4805992Swnj u.u_error = ENXIO; 4815992Swnj goto out; 4825992Swnj } 4837826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 4845992Swnj out: 4855992Swnj iput(ip); 4867826Sroot u.u_r.r_val1 = uap->count - resid; 4875992Swnj } 4885992Swnj 4899167Ssam /* 4909167Ssam * Change mode of a file given path name. 4919167Ssam */ 4926254Sroot chmod() 4935992Swnj { 4947701Ssam struct inode *ip; 4957701Ssam struct a { 4966254Sroot char *fname; 4976254Sroot int fmode; 4985992Swnj } *uap; 4995992Swnj 5005992Swnj uap = (struct a *)u.u_ap; 5016254Sroot if ((ip = owner(1)) == NULL) 5025992Swnj return; 5037701Ssam chmod1(ip, uap->fmode); 5049167Ssam iput(ip); 5057701Ssam } 5067439Sroot 5079167Ssam /* 5089167Ssam * Change mode of a file given a file descriptor. 5099167Ssam */ 5107701Ssam fchmod() 5117701Ssam { 5127701Ssam struct a { 5137701Ssam int fd; 5147701Ssam int fmode; 5157701Ssam } *uap; 5167701Ssam register struct inode *ip; 5177701Ssam register struct file *fp; 5187701Ssam 5197701Ssam uap = (struct a *)u.u_ap; 52012756Ssam fp = getinode(uap->fd); 5217701Ssam if (fp == NULL) 5227701Ssam return; 52312756Ssam ip = (struct inode *)fp->f_data; 5249167Ssam if (u.u_uid != ip->i_uid && !suser()) 5259167Ssam return; 5267701Ssam ilock(ip); 5277701Ssam chmod1(ip, uap->fmode); 5289167Ssam iunlock(ip); 5297701Ssam } 5307701Ssam 5319167Ssam /* 5329167Ssam * Change the mode on a file. 5339167Ssam * Inode must be locked before calling. 5349167Ssam */ 5357701Ssam chmod1(ip, mode) 5367701Ssam register struct inode *ip; 5377701Ssam register int mode; 5387701Ssam { 5397868Sroot 5406254Sroot ip->i_mode &= ~07777; 5417439Sroot if (u.u_uid) { 5427701Ssam mode &= ~ISVTX; 54311811Ssam if (!groupmember(ip->i_gid)) 54411811Ssam mode &= ~ISGID; 5457439Sroot } 5467701Ssam ip->i_mode |= mode&07777; 5476254Sroot ip->i_flag |= ICHG; 5486254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5496254Sroot xrele(ip); 5505992Swnj } 5515992Swnj 5529167Ssam /* 5539167Ssam * Set ownership given a path name. 5549167Ssam */ 5556254Sroot chown() 55637Sbill { 5577701Ssam struct inode *ip; 5587701Ssam struct a { 5596254Sroot char *fname; 5606254Sroot int uid; 5616254Sroot int gid; 56237Sbill } *uap; 56337Sbill 56437Sbill uap = (struct a *)u.u_ap; 56511821Ssam if (!suser() || (ip = owner(0)) == NULL) 56637Sbill return; 56711811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5689167Ssam iput(ip); 5697701Ssam } 5707439Sroot 5719167Ssam /* 5729167Ssam * Set ownership given a file descriptor. 5739167Ssam */ 5747701Ssam fchown() 5757701Ssam { 5767701Ssam struct a { 5777701Ssam int fd; 5787701Ssam int uid; 5797701Ssam int gid; 5807701Ssam } *uap; 5817701Ssam register struct inode *ip; 5827701Ssam register struct file *fp; 5837701Ssam 5847701Ssam uap = (struct a *)u.u_ap; 58512756Ssam fp = getinode(uap->fd); 5867701Ssam if (fp == NULL) 5877701Ssam return; 58812756Ssam ip = (struct inode *)fp->f_data; 58911821Ssam if (!suser()) 5909167Ssam return; 5917701Ssam ilock(ip); 59211811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5939167Ssam iunlock(ip); 5947701Ssam } 5957701Ssam 5967701Ssam /* 5977701Ssam * Perform chown operation on inode ip; 5987701Ssam * inode must be locked prior to call. 5997701Ssam */ 6007701Ssam chown1(ip, uid, gid) 6017701Ssam register struct inode *ip; 6027701Ssam int uid, gid; 6037701Ssam { 6047701Ssam #ifdef QUOTA 6057701Ssam register long change; 60611811Ssam #endif 6077701Ssam 60811811Ssam if (uid == -1) 60911811Ssam uid = ip->i_uid; 61011811Ssam if (gid == -1) 61111811Ssam gid = ip->i_gid; 61211811Ssam #ifdef QUOTA 61314385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6147482Skre change = 0; 61512646Ssam else 61612646Ssam change = ip->i_blocks; 61712646Ssam (void) chkdq(ip, -change, 1); 61812646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6197482Skre dqrele(ip->i_dquot); 6207482Skre #endif 62111811Ssam ip->i_uid = uid; 62211811Ssam ip->i_gid = gid; 6236254Sroot ip->i_flag |= ICHG; 6246254Sroot if (u.u_ruid != 0) 6256254Sroot ip->i_mode &= ~(ISUID|ISGID); 6267701Ssam #ifdef QUOTA 6277482Skre ip->i_dquot = inoquota(ip); 62812646Ssam (void) chkdq(ip, change, 1); 62912646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 63012646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 63112646Ssam #else 63212646Ssam return (0); 6337482Skre #endif 63437Sbill } 63537Sbill 63611811Ssam utimes() 63711811Ssam { 63811811Ssam register struct a { 63911811Ssam char *fname; 64011811Ssam struct timeval *tptr; 64111811Ssam } *uap = (struct a *)u.u_ap; 64211811Ssam register struct inode *ip; 64311811Ssam struct timeval tv[2]; 64411811Ssam 64511811Ssam if ((ip = owner(1)) == NULL) 64611811Ssam return; 64711811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 64811811Ssam if (u.u_error == 0) { 64911811Ssam ip->i_flag |= IACC|IUPD|ICHG; 65011811Ssam iupdat(ip, &tv[0], &tv[1], 0); 65111811Ssam } 65211811Ssam iput(ip); 65311811Ssam } 65411811Ssam 6559167Ssam /* 6569167Ssam * Flush any pending I/O. 6579167Ssam */ 6586254Sroot sync() 65937Sbill { 66037Sbill 6618673Sroot update(); 66237Sbill } 6637535Sroot 6649167Ssam /* 6659167Ssam * Truncate a file given its path name. 6669167Ssam */ 6677701Ssam truncate() 6687701Ssam { 6697701Ssam struct a { 6707701Ssam char *fname; 6719167Ssam u_long length; 6727826Sroot } *uap = (struct a *)u.u_ap; 6737701Ssam struct inode *ip; 6747701Ssam 6759167Ssam ip = namei(uchar, LOOKUP, 1); 6767701Ssam if (ip == NULL) 6777701Ssam return; 6787701Ssam if (access(ip, IWRITE)) 6797701Ssam goto bad; 6807701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 6817701Ssam u.u_error = EISDIR; 6827701Ssam goto bad; 6837701Ssam } 6847701Ssam itrunc(ip, uap->length); 6857701Ssam bad: 6867701Ssam iput(ip); 6877701Ssam } 6887701Ssam 6899167Ssam /* 6909167Ssam * Truncate a file given a file descriptor. 6919167Ssam */ 6927701Ssam ftruncate() 6937701Ssam { 6947701Ssam struct a { 6957701Ssam int fd; 6969167Ssam u_long length; 6977826Sroot } *uap = (struct a *)u.u_ap; 6987701Ssam struct inode *ip; 6997701Ssam struct file *fp; 7007701Ssam 70112756Ssam fp = getinode(uap->fd); 7027701Ssam if (fp == NULL) 7037701Ssam return; 7047701Ssam if ((fp->f_flag&FWRITE) == 0) { 7057701Ssam u.u_error = EINVAL; 7067701Ssam return; 7077701Ssam } 70812756Ssam ip = (struct inode *)fp->f_data; 7097701Ssam ilock(ip); 7107701Ssam itrunc(ip, uap->length); 7119167Ssam iunlock(ip); 7127701Ssam } 7137701Ssam 7149167Ssam /* 7159167Ssam * Synch an open file. 7169167Ssam */ 7179167Ssam fsync() 7189167Ssam { 7199167Ssam struct a { 7209167Ssam int fd; 7219167Ssam } *uap = (struct a *)u.u_ap; 7229167Ssam struct inode *ip; 7239167Ssam struct file *fp; 7249167Ssam 72512756Ssam fp = getinode(uap->fd); 7269167Ssam if (fp == NULL) 7279167Ssam return; 72812756Ssam ip = (struct inode *)fp->f_data; 7299167Ssam ilock(ip); 7309167Ssam syncip(ip); 7319167Ssam iunlock(ip); 7329167Ssam } 7339167Ssam 7349167Ssam /* 7359167Ssam * Rename system call. 7369167Ssam * rename("foo", "bar"); 7379167Ssam * is essentially 7389167Ssam * unlink("bar"); 7399167Ssam * link("foo", "bar"); 7409167Ssam * unlink("foo"); 7419167Ssam * but ``atomically''. Can't do full commit without saving state in the 7429167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7439167Ssam * always guarantee the target exists. 7449167Ssam * 7459167Ssam * Basic algorithm is: 7469167Ssam * 7479167Ssam * 1) Bump link count on source while we're linking it to the 7489167Ssam * target. This also insure the inode won't be deleted out 7499167Ssam * from underneath us while we work. 7509167Ssam * 2) Link source to destination. If destination already exists, 7519167Ssam * delete it first. 7529167Ssam * 3) Unlink source reference to inode if still around. 7539167Ssam * 4) If a directory was moved and the parent of the destination 7549167Ssam * is different from the source, patch the ".." entry in the 7559167Ssam * directory. 7569167Ssam * 7579167Ssam * Source and destination must either both be directories, or both 7589167Ssam * not be directories. If target is a directory, it must be empty. 7599167Ssam */ 7607701Ssam rename() 7617701Ssam { 7627701Ssam struct a { 7637701Ssam char *from; 7647701Ssam char *to; 7657701Ssam } *uap; 7669167Ssam register struct inode *ip, *xp, *dp; 7679167Ssam int oldparent, parentdifferent, doingdirectory; 76810051Ssam int error = 0; 7697701Ssam 7709167Ssam uap = (struct a *)u.u_ap; 77111641Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 7729167Ssam if (ip == NULL) 7739167Ssam return; 7749167Ssam dp = u.u_pdir; 7759167Ssam oldparent = 0, doingdirectory = 0; 7769167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7779167Ssam register struct direct *d; 7789167Ssam 7799167Ssam d = &u.u_dent; 7809167Ssam /* 78111641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7829167Ssam */ 78311641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 78411641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 78511641Ssam (dp == ip)) { 78611641Ssam iput(dp); 78711641Ssam if (dp == ip) 78811641Ssam irele(ip); 78911641Ssam else 79010051Ssam iput(ip); 79111641Ssam u.u_error = EINVAL; 79211641Ssam return; 7939167Ssam } 7949167Ssam oldparent = dp->i_number; 7959167Ssam doingdirectory++; 7969167Ssam } 79711641Ssam iput(dp); 7989167Ssam 7999167Ssam /* 8009167Ssam * 1) Bump link count while we're moving stuff 8019167Ssam * around. If we crash somewhere before 8029167Ssam * completing our work, the link count 8039167Ssam * may be wrong, but correctable. 8049167Ssam */ 8059167Ssam ip->i_nlink++; 8069167Ssam ip->i_flag |= ICHG; 8079167Ssam iupdat(ip, &time, &time, 1); 8089167Ssam iunlock(ip); 8099167Ssam 8109167Ssam /* 8119167Ssam * When the target exists, both the directory 8129167Ssam * and target inodes are returned locked. 8139167Ssam */ 8149167Ssam u.u_dirp = (caddr_t)uap->to; 81515797Smckusick xp = namei(uchar, CREATE | LOCKPARENT | NOCACHE, 0); 81610051Ssam if (u.u_error) { 81710051Ssam error = u.u_error; 8189167Ssam goto out; 81910051Ssam } 8209167Ssam dp = u.u_pdir; 8219167Ssam /* 82211641Ssam * If ".." must be changed (ie the directory gets a new 82312816Smckusick * parent) then the source directory must not be in the 82412816Smckusick * directory heirarchy above the target, as this would 82512816Smckusick * orphan everything below the source directory. Also 82612816Smckusick * the user must have write permission in the source so 82712816Smckusick * as to be able to change "..". We must repeat the call 82812816Smckusick * to namei, as the parent directory is unlocked by the 82912816Smckusick * call to checkpath(). 83011641Ssam */ 83111641Ssam parentdifferent = oldparent != dp->i_number; 83212816Smckusick if (doingdirectory && parentdifferent) { 83312816Smckusick if (access(ip, IWRITE)) 83412816Smckusick goto bad; 83512816Smckusick do { 83612816Smckusick dp = u.u_pdir; 83712816Smckusick if (xp != NULL) 83812816Smckusick iput(xp); 83912816Smckusick u.u_error = checkpath(ip, dp); 84012816Smckusick if (u.u_error) 84112816Smckusick goto out; 84212816Smckusick u.u_dirp = (caddr_t)uap->to; 84315797Smckusick xp = namei(uchar, CREATE | LOCKPARENT | NOCACHE, 0); 84412816Smckusick if (u.u_error) { 84512816Smckusick error = u.u_error; 84612816Smckusick goto out; 84712816Smckusick } 84812816Smckusick } while (dp != u.u_pdir); 84912816Smckusick } 85011641Ssam /* 8519167Ssam * 2) If target doesn't exist, link the target 8529167Ssam * to the source and unlink the source. 8539167Ssam * Otherwise, rewrite the target directory 8549167Ssam * entry to reference the source inode and 8559167Ssam * expunge the original entry's existence. 8569167Ssam */ 8579167Ssam if (xp == NULL) { 8589167Ssam if (dp->i_dev != ip->i_dev) { 85910051Ssam error = EXDEV; 8609167Ssam goto bad; 8619167Ssam } 8629167Ssam /* 8639167Ssam * Account for ".." in directory. 8649167Ssam * When source and destination have the 8659167Ssam * same parent we don't fool with the 8669167Ssam * link count -- this isn't required 8679167Ssam * because we do a similar check below. 8689167Ssam */ 8699167Ssam if (doingdirectory && parentdifferent) { 8709167Ssam dp->i_nlink++; 8719167Ssam dp->i_flag |= ICHG; 8729167Ssam iupdat(dp, &time, &time, 1); 8739167Ssam } 87410850Ssam error = direnter(ip); 87510850Ssam if (error) 8769167Ssam goto out; 8779167Ssam } else { 8789167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 87910051Ssam error = EXDEV; 8809167Ssam goto bad; 8819167Ssam } 8829167Ssam /* 88310590Ssam * Short circuit rename(foo, foo). 88410590Ssam */ 88510590Ssam if (xp->i_number == ip->i_number) 88610590Ssam goto bad; 88710590Ssam /* 88810051Ssam * Target must be empty if a directory 88910051Ssam * and have no links to it. 8909167Ssam * Also, insure source and target are 8919167Ssam * compatible (both directories, or both 8929167Ssam * not directories). 8939167Ssam */ 8949167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 89510051Ssam if (!dirempty(xp) || xp->i_nlink > 2) { 89610051Ssam error = ENOTEMPTY; 8979167Ssam goto bad; 8989167Ssam } 8999167Ssam if (!doingdirectory) { 90010051Ssam error = ENOTDIR; 9019167Ssam goto bad; 9029167Ssam } 9039167Ssam } else if (doingdirectory) { 90410051Ssam error = EISDIR; 9059167Ssam goto bad; 9069167Ssam } 9079167Ssam dirrewrite(dp, ip); 90810051Ssam if (u.u_error) { 90910051Ssam error = u.u_error; 9109167Ssam goto bad1; 91110051Ssam } 9129167Ssam /* 91310051Ssam * Adjust the link count of the target to 91410051Ssam * reflect the dirrewrite above. If this is 91510051Ssam * a directory it is empty and there are 91610051Ssam * no links to it, so we can squash the inode and 91710051Ssam * any space associated with it. We disallowed 91810051Ssam * renaming over top of a directory with links to 91910051Ssam * it above, as we've no way to determine if 92010051Ssam * we've got a link or the directory itself, and 92110051Ssam * if we get a link, then ".." will be screwed up. 9229167Ssam */ 92310051Ssam xp->i_nlink--; 9249167Ssam if (doingdirectory) { 92510051Ssam if (--xp->i_nlink != 0) 92610051Ssam panic("rename: linked directory"); 9279167Ssam itrunc(xp, (u_long)0); 92810051Ssam } 9299167Ssam xp->i_flag |= ICHG; 9309167Ssam iput(xp); 93110246Ssam xp = NULL; 9329167Ssam } 9339167Ssam 9349167Ssam /* 9359167Ssam * 3) Unlink the source. 9369167Ssam */ 9379167Ssam u.u_dirp = uap->from; 9389167Ssam dp = namei(uchar, DELETE, 0); 9399167Ssam /* 9409167Ssam * Insure directory entry still exists and 9419167Ssam * has not changed since the start of all 9429167Ssam * this. If either has occured, forget about 9439167Ssam * about deleting the original entry and just 9449167Ssam * adjust the link count in the inode. 9459167Ssam */ 9469167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 9479167Ssam ip->i_nlink--; 9489167Ssam ip->i_flag |= ICHG; 9499167Ssam } else { 9509167Ssam /* 9519167Ssam * If source is a directory, must adjust 9529167Ssam * link count of parent directory also. 9539167Ssam * If target didn't exist and source and 9549167Ssam * target have the same parent, then we 9559167Ssam * needn't touch the link count, it all 9569167Ssam * balances out in the end. Otherwise, we 9579167Ssam * must do so to reflect deletion of ".." 9589167Ssam * done above. 9599167Ssam */ 9609167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9619167Ssam dp->i_nlink--; 9629167Ssam dp->i_flag |= ICHG; 9639167Ssam } 9649167Ssam if (dirremove()) { 9659167Ssam ip->i_nlink--; 9669167Ssam ip->i_flag |= ICHG; 9679167Ssam } 96810051Ssam if (error == 0) /* conservative */ 96910051Ssam error = u.u_error; 9709167Ssam } 9719167Ssam irele(ip); 9729167Ssam if (dp) 9739167Ssam iput(dp); 9749167Ssam 9759167Ssam /* 9769167Ssam * 4) Renaming a directory with the parent 9779167Ssam * different requires ".." to be rewritten. 9789167Ssam * The window is still there for ".." to 9799167Ssam * be inconsistent, but this is unavoidable, 9809167Ssam * and a lot shorter than when it was done 9819167Ssam * in a user process. 9829167Ssam */ 98310051Ssam if (doingdirectory && parentdifferent && error == 0) { 9849167Ssam struct dirtemplate dirbuf; 9859167Ssam 9869167Ssam u.u_dirp = uap->to; 9879167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 9889167Ssam if (ip == NULL) { 9899167Ssam printf("rename: .. went away\n"); 9909167Ssam return; 9919167Ssam } 9929167Ssam dp = u.u_pdir; 9939167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 9949167Ssam printf("rename: .. not a directory\n"); 9959167Ssam goto stuck; 9969167Ssam } 99710051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 9989167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 99910051Ssam if (error == 0) { 10009167Ssam dirbuf.dotdot_ino = dp->i_number; 10019167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10029167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10039167Ssam } 10049167Ssam stuck: 10059167Ssam irele(dp); 10069167Ssam iput(ip); 10079167Ssam } 100810051Ssam goto done; 100910051Ssam 10109167Ssam bad: 101110246Ssam iput(dp); 10129167Ssam bad1: 10139167Ssam if (xp) 101410246Ssam iput(xp); 10159167Ssam out: 10169167Ssam ip->i_nlink--; 10179167Ssam ip->i_flag |= ICHG; 10189167Ssam irele(ip); 101910051Ssam done: 102010051Ssam if (error) 102110051Ssam u.u_error = error; 10227701Ssam } 10237701Ssam 10247535Sroot /* 10257535Sroot * Make a new file. 10267535Sroot */ 10277535Sroot struct inode * 10287535Sroot maknode(mode) 10297535Sroot int mode; 10307535Sroot { 10317535Sroot register struct inode *ip; 10327535Sroot ino_t ipref; 10337535Sroot 10347535Sroot if ((mode & IFMT) == IFDIR) 10357535Sroot ipref = dirpref(u.u_pdir->i_fs); 10367535Sroot else 10377535Sroot ipref = u.u_pdir->i_number; 10387535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10397535Sroot if (ip == NULL) { 10407535Sroot iput(u.u_pdir); 10417701Ssam return (NULL); 10427535Sroot } 10437701Ssam #ifdef QUOTA 10447535Sroot if (ip->i_dquot != NODQUOT) 10457535Sroot panic("maknode: dquot"); 10467535Sroot #endif 10477535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10487535Sroot if ((mode & IFMT) == 0) 10497535Sroot mode |= IFREG; 10507535Sroot ip->i_mode = mode & ~u.u_cmask; 10517535Sroot ip->i_nlink = 1; 10527535Sroot ip->i_uid = u.u_uid; 10537535Sroot ip->i_gid = u.u_pdir->i_gid; 105411811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 105511811Ssam ip->i_mode &= ~ISGID; 10567701Ssam #ifdef QUOTA 10577535Sroot ip->i_dquot = inoquota(ip); 10587535Sroot #endif 10597535Sroot 10607535Sroot /* 10617535Sroot * Make sure inode goes to disk before directory entry. 10627535Sroot */ 10638673Sroot iupdat(ip, &time, &time, 1); 106410850Ssam u.u_error = direnter(ip); 10657535Sroot if (u.u_error) { 10667535Sroot /* 106710850Ssam * Write error occurred trying to update directory 106810850Ssam * so must deallocate the inode. 10697535Sroot */ 10707535Sroot ip->i_nlink = 0; 10717535Sroot ip->i_flag |= ICHG; 10727535Sroot iput(ip); 10737701Ssam return (NULL); 10747535Sroot } 10757701Ssam return (ip); 10767535Sroot } 107712756Ssam 107812756Ssam /* 107912756Ssam * A virgin directory (no blushing please). 108012756Ssam */ 108112756Ssam struct dirtemplate mastertemplate = { 108212756Ssam 0, 12, 1, ".", 108312756Ssam 0, DIRBLKSIZ - 12, 2, ".." 108412756Ssam }; 108512756Ssam 108612756Ssam /* 108712756Ssam * Mkdir system call 108812756Ssam */ 108912756Ssam mkdir() 109012756Ssam { 109112756Ssam struct a { 109212756Ssam char *name; 109312756Ssam int dmode; 109412756Ssam } *uap; 109512756Ssam register struct inode *ip, *dp; 109612756Ssam struct dirtemplate dirtemplate; 109712756Ssam 109812756Ssam uap = (struct a *)u.u_ap; 109912756Ssam ip = namei(uchar, CREATE, 0); 110012756Ssam if (u.u_error) 110112756Ssam return; 110212756Ssam if (ip != NULL) { 110312756Ssam iput(ip); 110412756Ssam u.u_error = EEXIST; 110512756Ssam return; 110612756Ssam } 110712756Ssam dp = u.u_pdir; 110812756Ssam uap->dmode &= 0777; 110912756Ssam uap->dmode |= IFDIR; 111012756Ssam /* 111112756Ssam * Must simulate part of maknode here 111212756Ssam * in order to acquire the inode, but 111312756Ssam * not have it entered in the parent 111412756Ssam * directory. The entry is made later 111512756Ssam * after writing "." and ".." entries out. 111612756Ssam */ 111712756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 111812756Ssam if (ip == NULL) { 111912756Ssam iput(dp); 112012756Ssam return; 112112756Ssam } 112212756Ssam #ifdef QUOTA 112312756Ssam if (ip->i_dquot != NODQUOT) 112412756Ssam panic("mkdir: dquot"); 112512756Ssam #endif 112612756Ssam ip->i_flag |= IACC|IUPD|ICHG; 112712756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 112812756Ssam ip->i_nlink = 2; 112912756Ssam ip->i_uid = u.u_uid; 113012756Ssam ip->i_gid = dp->i_gid; 113112756Ssam #ifdef QUOTA 113212756Ssam ip->i_dquot = inoquota(ip); 113312756Ssam #endif 113412756Ssam iupdat(ip, &time, &time, 1); 113512756Ssam 113612756Ssam /* 113712756Ssam * Bump link count in parent directory 113812756Ssam * to reflect work done below. Should 113912756Ssam * be done before reference is created 114012756Ssam * so reparation is possible if we crash. 114112756Ssam */ 114212756Ssam dp->i_nlink++; 114312756Ssam dp->i_flag |= ICHG; 114412756Ssam iupdat(dp, &time, &time, 1); 114512756Ssam 114612756Ssam /* 114712756Ssam * Initialize directory with "." 114812756Ssam * and ".." from static template. 114912756Ssam */ 115012756Ssam dirtemplate = mastertemplate; 115112756Ssam dirtemplate.dot_ino = ip->i_number; 115212756Ssam dirtemplate.dotdot_ino = dp->i_number; 115312756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 115412756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 115512756Ssam if (u.u_error) { 115612756Ssam dp->i_nlink--; 115712756Ssam dp->i_flag |= ICHG; 115812756Ssam goto bad; 115912756Ssam } 116012756Ssam /* 116112756Ssam * Directory all set up, now 116212756Ssam * install the entry for it in 116312756Ssam * the parent directory. 116412756Ssam */ 116512756Ssam u.u_error = direnter(ip); 116612756Ssam dp = NULL; 116712756Ssam if (u.u_error) { 116812756Ssam u.u_dirp = uap->name; 116915797Smckusick dp = namei(uchar, LOOKUP | NOCACHE, 0); 117012756Ssam if (dp) { 117112756Ssam dp->i_nlink--; 117212756Ssam dp->i_flag |= ICHG; 117312756Ssam } 117412756Ssam } 117512756Ssam bad: 117612756Ssam /* 117712756Ssam * No need to do an explicit itrunc here, 117812756Ssam * irele will do this for us because we set 117912756Ssam * the link count to 0. 118012756Ssam */ 118112756Ssam if (u.u_error) { 118212756Ssam ip->i_nlink = 0; 118312756Ssam ip->i_flag |= ICHG; 118412756Ssam } 118512756Ssam if (dp) 118612756Ssam iput(dp); 118712756Ssam iput(ip); 118812756Ssam } 118912756Ssam 119012756Ssam /* 119112756Ssam * Rmdir system call. 119212756Ssam */ 119312756Ssam rmdir() 119412756Ssam { 119512756Ssam struct a { 119612756Ssam char *name; 119712756Ssam }; 119812756Ssam register struct inode *ip, *dp; 119912756Ssam 120012756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 120112756Ssam if (ip == NULL) 120212756Ssam return; 120312756Ssam dp = u.u_pdir; 120412756Ssam /* 120512756Ssam * No rmdir "." please. 120612756Ssam */ 120712756Ssam if (dp == ip) { 120812756Ssam irele(dp); 120912756Ssam iput(ip); 121012756Ssam u.u_error = EINVAL; 121112756Ssam return; 121212756Ssam } 121312756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 121412756Ssam u.u_error = ENOTDIR; 121512756Ssam goto out; 121612756Ssam } 121712756Ssam /* 121812756Ssam * Don't remove a mounted on directory. 121912756Ssam */ 122012756Ssam if (ip->i_dev != dp->i_dev) { 122112756Ssam u.u_error = EBUSY; 122212756Ssam goto out; 122312756Ssam } 122412756Ssam /* 122512756Ssam * Verify the directory is empty (and valid). 122612756Ssam * (Rmdir ".." won't be valid since 122712756Ssam * ".." will contain a reference to 122812756Ssam * the current directory and thus be 122912756Ssam * non-empty.) 123012756Ssam */ 123112756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 123212756Ssam u.u_error = ENOTEMPTY; 123312756Ssam goto out; 123412756Ssam } 123512756Ssam /* 123612756Ssam * Delete reference to directory before purging 123712756Ssam * inode. If we crash in between, the directory 123812756Ssam * will be reattached to lost+found, 123912756Ssam */ 124012756Ssam if (dirremove() == 0) 124112756Ssam goto out; 124212756Ssam dp->i_nlink--; 124312756Ssam dp->i_flag |= ICHG; 124412756Ssam iput(dp); 124512756Ssam dp = NULL; 124612756Ssam /* 124712756Ssam * Truncate inode. The only stuff left 124812756Ssam * in the directory is "." and "..". The 124912756Ssam * "." reference is inconsequential since 125012756Ssam * we're quashing it. The ".." reference 125112756Ssam * has already been adjusted above. We've 125212756Ssam * removed the "." reference and the reference 125312756Ssam * in the parent directory, but there may be 125412756Ssam * other hard links so decrement by 2 and 125512756Ssam * worry about them later. 125612756Ssam */ 125712756Ssam ip->i_nlink -= 2; 125812756Ssam itrunc(ip, (u_long)0); 125912756Ssam out: 126012756Ssam if (dp) 126112756Ssam iput(dp); 126212756Ssam iput(ip); 126312756Ssam } 126412756Ssam 126512756Ssam struct file * 126612756Ssam getinode(fdes) 126712756Ssam int fdes; 126812756Ssam { 126912756Ssam register struct file *fp; 127012756Ssam 127112756Ssam fp = getf(fdes); 127212756Ssam if (fp == 0) 127312756Ssam return (0); 127412756Ssam if (fp->f_type != DTYPE_INODE) { 127512756Ssam u.u_error = EINVAL; 127612756Ssam return (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