1*14385Ssam /* vfs_syscalls.c 4.62 83/08/06 */ 237Sbill 337Sbill #include "../h/param.h" 437Sbill #include "../h/systm.h" 537Sbill #include "../h/dir.h" 637Sbill #include "../h/user.h" 78040Sroot #include "../h/kernel.h" 86254Sroot #include "../h/file.h" 96574Smckusic #include "../h/stat.h" 1037Sbill #include "../h/inode.h" 116574Smckusic #include "../h/fs.h" 126254Sroot #include "../h/buf.h" 136254Sroot #include "../h/proc.h" 147482Skre #include "../h/quota.h" 157826Sroot #include "../h/uio.h" 167826Sroot #include "../h/socket.h" 178632Sroot #include "../h/socketvar.h" 189167Ssam #include "../h/nami.h" 1912756Ssam #include "../h/mount.h" 2037Sbill 2112756Ssam extern struct fileops inodeops; 2212756Ssam struct file *getinode(); 2312756Ssam 249167Ssam /* 259167Ssam * Change current working directory (``.''). 269167Ssam */ 276254Sroot chdir() 286254Sroot { 296254Sroot 306254Sroot chdirec(&u.u_cdir); 316254Sroot } 326254Sroot 339167Ssam /* 349167Ssam * Change notion of root (``/'') directory. 359167Ssam */ 366254Sroot chroot() 376254Sroot { 386254Sroot 396254Sroot if (suser()) 406254Sroot chdirec(&u.u_rdir); 416254Sroot } 426254Sroot 439167Ssam /* 449167Ssam * Common routine for chroot and chdir. 459167Ssam */ 466254Sroot chdirec(ipp) 477701Ssam register struct inode **ipp; 486254Sroot { 496254Sroot register struct inode *ip; 506254Sroot struct a { 516254Sroot char *fname; 526254Sroot }; 536254Sroot 549167Ssam ip = namei(uchar, LOOKUP, 1); 559167Ssam if (ip == NULL) 566254Sroot return; 579167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 586254Sroot u.u_error = ENOTDIR; 596254Sroot goto bad; 606254Sroot } 619167Ssam if (access(ip, IEXEC)) 626254Sroot goto bad; 637122Smckusick iunlock(ip); 647142Smckusick if (*ipp) 657142Smckusick irele(*ipp); 666254Sroot *ipp = ip; 676254Sroot return; 686254Sroot 696254Sroot bad: 706254Sroot iput(ip); 716254Sroot } 726254Sroot 7337Sbill /* 746254Sroot * Open system call. 756254Sroot */ 766254Sroot open() 776254Sroot { 7812756Ssam struct a { 796254Sroot char *fname; 807701Ssam int mode; 8112756Ssam int crtmode; 8212756Ssam } *uap = (struct a *) u.u_ap; 836254Sroot 8412756Ssam copen(uap->mode-FOPEN, uap->crtmode); 856254Sroot } 866254Sroot 876254Sroot /* 886254Sroot * Creat system call. 896254Sroot */ 9012756Ssam creat() 916254Sroot { 9212756Ssam struct a { 936254Sroot char *fname; 946254Sroot int fmode; 9512756Ssam } *uap = (struct a *)u.u_ap; 966254Sroot 9712756Ssam copen(FWRITE|FCREAT|FTRUNC, uap->fmode); 986254Sroot } 996254Sroot 1006254Sroot /* 1016254Sroot * Common code for open and creat. 10212756Ssam * Check permissions, allocate an open file structure, 10312756Ssam * and call the device open routine if any. 1046254Sroot */ 10512756Ssam copen(mode, arg) 10612756Ssam register int mode; 10712756Ssam int arg; 10812756Ssam { 1096254Sroot register struct inode *ip; 1106254Sroot register struct file *fp; 11112756Ssam int i; 1126254Sroot 11312756Ssam #ifdef notdef 11412756Ssam if ((mode&(FREAD|FWRITE)) == 0) { 11512756Ssam u.u_error = EINVAL; 11612756Ssam return; 11712756Ssam } 11812756Ssam #endif 11912756Ssam if (mode&FCREAT) { 12012756Ssam ip = namei(uchar, CREATE, 1); 12112756Ssam if (ip == NULL) { 12212756Ssam if (u.u_error) 12312756Ssam return; 12412756Ssam ip = maknode(arg&07777&(~ISVTX)); 12512756Ssam if (ip == NULL) 12612756Ssam return; 12712756Ssam mode &= ~FTRUNC; 12812756Ssam } else { 12912756Ssam if (mode&FEXCL) { 13012756Ssam u.u_error = EEXIST; 13112756Ssam iput(ip); 13212756Ssam return; 13312756Ssam } 13412756Ssam mode &= ~FCREAT; 13512756Ssam } 13612756Ssam } else { 13712756Ssam ip = namei(uchar, LOOKUP, 1); 13812756Ssam if (ip == NULL) 13912756Ssam return; 14012756Ssam } 14112756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 14212756Ssam u.u_error = EOPNOTSUPP; 14312756Ssam goto bad; 14412756Ssam } 14512756Ssam if ((mode&FCREAT) == 0) { 1466254Sroot if (mode&FREAD) 1477701Ssam if (access(ip, IREAD)) 1487701Ssam goto bad; 1496254Sroot if (mode&FWRITE) { 1507701Ssam if (access(ip, IWRITE)) 1517701Ssam goto bad; 1527701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1536254Sroot u.u_error = EISDIR; 1547701Ssam goto bad; 1557701Ssam } 1566254Sroot } 1576254Sroot } 15812756Ssam fp = falloc(); 15912756Ssam if (fp == NULL) 16012756Ssam goto bad; 16112756Ssam if (mode&FTRUNC) 1629167Ssam itrunc(ip, (u_long)0); 1637122Smckusick iunlock(ip); 16412756Ssam fp->f_flag = mode&FMASK; 16512756Ssam fp->f_type = DTYPE_INODE; 16612756Ssam fp->f_ops = &inodeops; 16712756Ssam fp->f_data = (caddr_t)ip; 1686254Sroot i = u.u_r.r_val1; 16912756Ssam #ifdef notdef 17012756Ssam if (setjmp(&u.u_qsave)) { 17112756Ssam if (u.u_error == 0) 17212756Ssam u.u_error = EINTR; 17312756Ssam u.u_ofile[i] = NULL; 17412756Ssam closef(fp); 17512756Ssam return; 17612756Ssam } 17712756Ssam #endif 1788559Sroot u.u_error = openi(ip, mode); 17912756Ssam if (u.u_error == 0) 1806254Sroot return; 1816254Sroot u.u_ofile[i] = NULL; 1826254Sroot fp->f_count--; 1837142Smckusick irele(ip); 1847701Ssam return; 1857701Ssam bad: 1867701Ssam iput(ip); 1876254Sroot } 1886254Sroot 1896254Sroot /* 1906254Sroot * Mknod system call 1916254Sroot */ 1926254Sroot mknod() 1936254Sroot { 1946254Sroot register struct inode *ip; 1956254Sroot register struct a { 1966254Sroot char *fname; 1976254Sroot int fmode; 1986254Sroot int dev; 1996254Sroot } *uap; 2006254Sroot 2016254Sroot uap = (struct a *)u.u_ap; 20212756Ssam if (!suser()) 20312756Ssam return; 20412756Ssam ip = namei(uchar, CREATE, 0); 20512756Ssam if (ip != NULL) { 20612756Ssam u.u_error = EEXIST; 20712756Ssam goto out; 2086254Sroot } 2096254Sroot if (u.u_error) 2106254Sroot return; 2116254Sroot ip = maknode(uap->fmode); 2126254Sroot if (ip == NULL) 2136254Sroot return; 21412756Ssam switch (ip->i_mode & IFMT) { 21512756Ssam 21612756Ssam case IFCHR: 21712756Ssam case IFBLK: 21812756Ssam if (uap->dev) { 21912756Ssam /* 22012756Ssam * Want to be able to use this to make badblock 22112756Ssam * inodes, so don't truncate the dev number. 22212756Ssam */ 22312756Ssam ip->i_rdev = uap->dev; 22412756Ssam ip->i_flag |= IACC|IUPD|ICHG; 22512756Ssam } 2266254Sroot } 2276254Sroot 2286254Sroot out: 2296254Sroot iput(ip); 2306254Sroot } 2316254Sroot 2326254Sroot /* 2336254Sroot * link system call 2346254Sroot */ 2356254Sroot link() 2366254Sroot { 2376254Sroot register struct inode *ip, *xp; 2386254Sroot register struct a { 2396254Sroot char *target; 2406254Sroot char *linkname; 2416254Sroot } *uap; 2426254Sroot 2436254Sroot uap = (struct a *)u.u_ap; 2449167Ssam ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */ 2456254Sroot if (ip == NULL) 2466254Sroot return; 2479167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2487439Sroot iput(ip); 2497439Sroot return; 2507439Sroot } 2516254Sroot ip->i_nlink++; 2526254Sroot ip->i_flag |= ICHG; 2538673Sroot iupdat(ip, &time, &time, 1); 2547122Smckusick iunlock(ip); 2556254Sroot u.u_dirp = (caddr_t)uap->linkname; 2569167Ssam xp = namei(uchar, CREATE, 0); 2576254Sroot if (xp != NULL) { 2586254Sroot u.u_error = EEXIST; 2596254Sroot iput(xp); 2606254Sroot goto out; 2616254Sroot } 2626254Sroot if (u.u_error) 2636254Sroot goto out; 2646254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2656254Sroot iput(u.u_pdir); 2666254Sroot u.u_error = EXDEV; 2676254Sroot goto out; 2686254Sroot } 26910850Ssam u.u_error = direnter(ip); 2706254Sroot out: 2716254Sroot if (u.u_error) { 2726254Sroot ip->i_nlink--; 2736254Sroot ip->i_flag |= ICHG; 2746254Sroot } 2757142Smckusick irele(ip); 2766254Sroot } 2776254Sroot 2786254Sroot /* 2796254Sroot * symlink -- make a symbolic link 2806254Sroot */ 2816254Sroot symlink() 2826254Sroot { 2836254Sroot register struct a { 2846254Sroot char *target; 2856254Sroot char *linkname; 2866254Sroot } *uap; 2876254Sroot register struct inode *ip; 2886254Sroot register char *tp; 2896254Sroot register c, nc; 2906254Sroot 2916254Sroot uap = (struct a *)u.u_ap; 2926254Sroot tp = uap->target; 2936254Sroot nc = 0; 2946254Sroot while (c = fubyte(tp)) { 2956254Sroot if (c < 0) { 2966254Sroot u.u_error = EFAULT; 2976254Sroot return; 2986254Sroot } 2996254Sroot tp++; 3006254Sroot nc++; 3016254Sroot } 3026254Sroot u.u_dirp = uap->linkname; 3039167Ssam ip = namei(uchar, CREATE, 0); 3046254Sroot if (ip) { 3056254Sroot iput(ip); 3066254Sroot u.u_error = EEXIST; 3076254Sroot return; 3086254Sroot } 3096254Sroot if (u.u_error) 3106254Sroot return; 3116254Sroot ip = maknode(IFLNK | 0777); 3126254Sroot if (ip == NULL) 3136254Sroot return; 3147826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3159167Ssam /* handle u.u_error != 0 */ 3166254Sroot iput(ip); 3176254Sroot } 3186254Sroot 3196254Sroot /* 3206254Sroot * Unlink system call. 3216254Sroot * Hard to avoid races here, especially 3226254Sroot * in unlinking directories. 3236254Sroot */ 3246254Sroot unlink() 3256254Sroot { 3266254Sroot struct a { 3276254Sroot char *fname; 3286254Sroot }; 3299167Ssam register struct inode *ip, *dp; 3306254Sroot 3319167Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 3329167Ssam if (ip == NULL) 3336254Sroot return; 3349167Ssam dp = u.u_pdir; 3359167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3366254Sroot goto out; 3376254Sroot /* 3386254Sroot * Don't unlink a mounted file. 3396254Sroot */ 3409167Ssam if (ip->i_dev != dp->i_dev) { 3416254Sroot u.u_error = EBUSY; 3426254Sroot goto out; 3436254Sroot } 3446254Sroot if (ip->i_flag&ITEXT) 3456254Sroot xrele(ip); /* try once to free text */ 3467535Sroot if (dirremove()) { 3477535Sroot ip->i_nlink--; 3487535Sroot ip->i_flag |= ICHG; 3496254Sroot } 3506254Sroot out: 3519167Ssam if (dp == ip) 3527142Smckusick irele(ip); 3537142Smckusick else 3547142Smckusick iput(ip); 3559167Ssam iput(dp); 3566254Sroot } 3576254Sroot 3586254Sroot /* 3596254Sroot * Seek system call 3606254Sroot */ 3618040Sroot lseek() 3626254Sroot { 3636254Sroot register struct file *fp; 3646254Sroot register struct a { 3657701Ssam int fd; 3666254Sroot off_t off; 3676254Sroot int sbase; 3686254Sroot } *uap; 3696254Sroot 3706254Sroot uap = (struct a *)u.u_ap; 37112756Ssam fp = getinode(uap->fd); 3726254Sroot if (fp == NULL) 3736254Sroot return; 37413878Ssam switch (uap->sbase) { 37513878Ssam 37613878Ssam case L_INCR: 37713878Ssam fp->f_offset += uap->off; 37813878Ssam break; 37913878Ssam 38013878Ssam case L_XTND: 38113878Ssam fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; 38213878Ssam break; 38313878Ssam 38413878Ssam case L_SET: 38513878Ssam fp->f_offset = uap->off; 38613878Ssam break; 38713878Ssam 38813878Ssam default: 38913878Ssam u.u_error = EINVAL; 39013878Ssam return; 39113878Ssam } 39213878Ssam u.u_r.r_off = fp->f_offset; 3936254Sroot } 3946254Sroot 3956254Sroot /* 3966254Sroot * Access system call 3976254Sroot */ 3986254Sroot saccess() 3996254Sroot { 4006254Sroot register svuid, svgid; 4016254Sroot register struct inode *ip; 4026254Sroot register struct a { 4036254Sroot char *fname; 4046254Sroot int fmode; 4056254Sroot } *uap; 4066254Sroot 4076254Sroot uap = (struct a *)u.u_ap; 4086254Sroot svuid = u.u_uid; 4096254Sroot svgid = u.u_gid; 4106254Sroot u.u_uid = u.u_ruid; 4116254Sroot u.u_gid = u.u_rgid; 4129167Ssam ip = namei(uchar, LOOKUP, 1); 4136254Sroot if (ip != NULL) { 41412756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4157701Ssam goto done; 41612756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4177701Ssam goto done; 41812756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4197701Ssam goto done; 4207701Ssam done: 4216254Sroot iput(ip); 4226254Sroot } 4236254Sroot u.u_uid = svuid; 4246254Sroot u.u_gid = svgid; 4256254Sroot } 4266254Sroot 4276254Sroot /* 4286574Smckusic * Stat system call. This version follows links. 42937Sbill */ 43037Sbill stat() 43137Sbill { 43237Sbill 43312756Ssam stat1(1); 43437Sbill } 43537Sbill 43637Sbill /* 4376574Smckusic * Lstat system call. This version does not follow links. 4385992Swnj */ 4395992Swnj lstat() 4405992Swnj { 44112756Ssam 44212756Ssam stat1(0); 44312756Ssam } 44412756Ssam 44512756Ssam stat1(follow) 44612756Ssam int follow; 44712756Ssam { 4485992Swnj register struct inode *ip; 4495992Swnj register struct a { 4505992Swnj char *fname; 45112756Ssam struct stat *ub; 4525992Swnj } *uap; 45312756Ssam struct stat sb; 4545992Swnj 4555992Swnj uap = (struct a *)u.u_ap; 45612756Ssam ip = namei(uchar, LOOKUP, follow); 4575992Swnj if (ip == NULL) 4585992Swnj return; 45913043Ssam (void) ino_stat(ip, &sb); 4605992Swnj iput(ip); 46112756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4625992Swnj } 4635992Swnj 4645992Swnj /* 4655992Swnj * Return target name of a symbolic link 46637Sbill */ 4675992Swnj readlink() 4685992Swnj { 4695992Swnj register struct inode *ip; 4705992Swnj register struct a { 4715992Swnj char *name; 4725992Swnj char *buf; 4735992Swnj int count; 4747826Sroot } *uap = (struct a *)u.u_ap; 4757826Sroot int resid; 4765992Swnj 4779167Ssam ip = namei(uchar, LOOKUP, 0); 4785992Swnj if (ip == NULL) 4795992Swnj return; 4805992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 4815992Swnj u.u_error = ENXIO; 4825992Swnj goto out; 4835992Swnj } 4847826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 4855992Swnj out: 4865992Swnj iput(ip); 4877826Sroot u.u_r.r_val1 = uap->count - resid; 4885992Swnj } 4895992Swnj 4909167Ssam /* 4919167Ssam * Change mode of a file given path name. 4929167Ssam */ 4936254Sroot chmod() 4945992Swnj { 4957701Ssam struct inode *ip; 4967701Ssam struct a { 4976254Sroot char *fname; 4986254Sroot int fmode; 4995992Swnj } *uap; 5005992Swnj 5015992Swnj uap = (struct a *)u.u_ap; 5026254Sroot if ((ip = owner(1)) == NULL) 5035992Swnj return; 5047701Ssam chmod1(ip, uap->fmode); 5059167Ssam iput(ip); 5067701Ssam } 5077439Sroot 5089167Ssam /* 5099167Ssam * Change mode of a file given a file descriptor. 5109167Ssam */ 5117701Ssam fchmod() 5127701Ssam { 5137701Ssam struct a { 5147701Ssam int fd; 5157701Ssam int fmode; 5167701Ssam } *uap; 5177701Ssam register struct inode *ip; 5187701Ssam register struct file *fp; 5197701Ssam 5207701Ssam uap = (struct a *)u.u_ap; 52112756Ssam fp = getinode(uap->fd); 5227701Ssam if (fp == NULL) 5237701Ssam return; 52412756Ssam ip = (struct inode *)fp->f_data; 5259167Ssam if (u.u_uid != ip->i_uid && !suser()) 5269167Ssam return; 5277701Ssam ilock(ip); 5287701Ssam chmod1(ip, uap->fmode); 5299167Ssam iunlock(ip); 5307701Ssam } 5317701Ssam 5329167Ssam /* 5339167Ssam * Change the mode on a file. 5349167Ssam * Inode must be locked before calling. 5359167Ssam */ 5367701Ssam chmod1(ip, mode) 5377701Ssam register struct inode *ip; 5387701Ssam register int mode; 5397701Ssam { 5407868Sroot 5416254Sroot ip->i_mode &= ~07777; 5427439Sroot if (u.u_uid) { 5437701Ssam mode &= ~ISVTX; 54411811Ssam if (!groupmember(ip->i_gid)) 54511811Ssam mode &= ~ISGID; 5467439Sroot } 5477701Ssam ip->i_mode |= mode&07777; 5486254Sroot ip->i_flag |= ICHG; 5496254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5506254Sroot xrele(ip); 5515992Swnj } 5525992Swnj 5539167Ssam /* 5549167Ssam * Set ownership given a path name. 5559167Ssam */ 5566254Sroot chown() 55737Sbill { 5587701Ssam struct inode *ip; 5597701Ssam struct a { 5606254Sroot char *fname; 5616254Sroot int uid; 5626254Sroot int gid; 56337Sbill } *uap; 56437Sbill 56537Sbill uap = (struct a *)u.u_ap; 56611821Ssam if (!suser() || (ip = owner(0)) == NULL) 56737Sbill return; 56811811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5699167Ssam iput(ip); 5707701Ssam } 5717439Sroot 5729167Ssam /* 5739167Ssam * Set ownership given a file descriptor. 5749167Ssam */ 5757701Ssam fchown() 5767701Ssam { 5777701Ssam struct a { 5787701Ssam int fd; 5797701Ssam int uid; 5807701Ssam int gid; 5817701Ssam } *uap; 5827701Ssam register struct inode *ip; 5837701Ssam register struct file *fp; 5847701Ssam 5857701Ssam uap = (struct a *)u.u_ap; 58612756Ssam fp = getinode(uap->fd); 5877701Ssam if (fp == NULL) 5887701Ssam return; 58912756Ssam ip = (struct inode *)fp->f_data; 59011821Ssam if (!suser()) 5919167Ssam return; 5927701Ssam ilock(ip); 59311811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5949167Ssam iunlock(ip); 5957701Ssam } 5967701Ssam 5977701Ssam /* 5987701Ssam * Perform chown operation on inode ip; 5997701Ssam * inode must be locked prior to call. 6007701Ssam */ 6017701Ssam chown1(ip, uid, gid) 6027701Ssam register struct inode *ip; 6037701Ssam int uid, gid; 6047701Ssam { 6057701Ssam #ifdef QUOTA 6067701Ssam register long change; 60711811Ssam #endif 6087701Ssam 60911811Ssam if (uid == -1) 61011811Ssam uid = ip->i_uid; 61111811Ssam if (gid == -1) 61211811Ssam gid = ip->i_gid; 61311811Ssam #ifdef QUOTA 614*14385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6157482Skre change = 0; 61612646Ssam else 61712646Ssam change = ip->i_blocks; 61812646Ssam (void) chkdq(ip, -change, 1); 61912646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6207482Skre dqrele(ip->i_dquot); 6217482Skre #endif 62211811Ssam ip->i_uid = uid; 62311811Ssam ip->i_gid = gid; 6246254Sroot ip->i_flag |= ICHG; 6256254Sroot if (u.u_ruid != 0) 6266254Sroot ip->i_mode &= ~(ISUID|ISGID); 6277701Ssam #ifdef QUOTA 6287482Skre ip->i_dquot = inoquota(ip); 62912646Ssam (void) chkdq(ip, change, 1); 63012646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 63112646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 63212646Ssam #else 63312646Ssam return (0); 6347482Skre #endif 63537Sbill } 63637Sbill 63711811Ssam utimes() 63811811Ssam { 63911811Ssam register struct a { 64011811Ssam char *fname; 64111811Ssam struct timeval *tptr; 64211811Ssam } *uap = (struct a *)u.u_ap; 64311811Ssam register struct inode *ip; 64411811Ssam struct timeval tv[2]; 64511811Ssam 64611811Ssam if ((ip = owner(1)) == NULL) 64711811Ssam return; 64811811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 64911811Ssam if (u.u_error == 0) { 65011811Ssam ip->i_flag |= IACC|IUPD|ICHG; 65111811Ssam iupdat(ip, &tv[0], &tv[1], 0); 65211811Ssam } 65311811Ssam iput(ip); 65411811Ssam } 65511811Ssam 6569167Ssam /* 6579167Ssam * Flush any pending I/O. 6589167Ssam */ 6596254Sroot sync() 66037Sbill { 66137Sbill 6628673Sroot update(); 66337Sbill } 6647535Sroot 6659167Ssam /* 6669167Ssam * Truncate a file given its path name. 6679167Ssam */ 6687701Ssam truncate() 6697701Ssam { 6707701Ssam struct a { 6717701Ssam char *fname; 6729167Ssam u_long length; 6737826Sroot } *uap = (struct a *)u.u_ap; 6747701Ssam struct inode *ip; 6757701Ssam 6769167Ssam ip = namei(uchar, LOOKUP, 1); 6777701Ssam if (ip == NULL) 6787701Ssam return; 6797701Ssam if (access(ip, IWRITE)) 6807701Ssam goto bad; 6817701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 6827701Ssam u.u_error = EISDIR; 6837701Ssam goto bad; 6847701Ssam } 6857701Ssam itrunc(ip, uap->length); 6867701Ssam bad: 6877701Ssam iput(ip); 6887701Ssam } 6897701Ssam 6909167Ssam /* 6919167Ssam * Truncate a file given a file descriptor. 6929167Ssam */ 6937701Ssam ftruncate() 6947701Ssam { 6957701Ssam struct a { 6967701Ssam int fd; 6979167Ssam u_long length; 6987826Sroot } *uap = (struct a *)u.u_ap; 6997701Ssam struct inode *ip; 7007701Ssam struct file *fp; 7017701Ssam 70212756Ssam fp = getinode(uap->fd); 7037701Ssam if (fp == NULL) 7047701Ssam return; 7057701Ssam if ((fp->f_flag&FWRITE) == 0) { 7067701Ssam u.u_error = EINVAL; 7077701Ssam return; 7087701Ssam } 70912756Ssam ip = (struct inode *)fp->f_data; 7107701Ssam ilock(ip); 7117701Ssam itrunc(ip, uap->length); 7129167Ssam iunlock(ip); 7137701Ssam } 7147701Ssam 7159167Ssam /* 7169167Ssam * Synch an open file. 7179167Ssam */ 7189167Ssam fsync() 7199167Ssam { 7209167Ssam struct a { 7219167Ssam int fd; 7229167Ssam } *uap = (struct a *)u.u_ap; 7239167Ssam struct inode *ip; 7249167Ssam struct file *fp; 7259167Ssam 72612756Ssam fp = getinode(uap->fd); 7279167Ssam if (fp == NULL) 7289167Ssam return; 72912756Ssam ip = (struct inode *)fp->f_data; 7309167Ssam ilock(ip); 7319167Ssam syncip(ip); 7329167Ssam iunlock(ip); 7339167Ssam } 7349167Ssam 7359167Ssam /* 7369167Ssam * Rename system call. 7379167Ssam * rename("foo", "bar"); 7389167Ssam * is essentially 7399167Ssam * unlink("bar"); 7409167Ssam * link("foo", "bar"); 7419167Ssam * unlink("foo"); 7429167Ssam * but ``atomically''. Can't do full commit without saving state in the 7439167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7449167Ssam * always guarantee the target exists. 7459167Ssam * 7469167Ssam * Basic algorithm is: 7479167Ssam * 7489167Ssam * 1) Bump link count on source while we're linking it to the 7499167Ssam * target. This also insure the inode won't be deleted out 7509167Ssam * from underneath us while we work. 7519167Ssam * 2) Link source to destination. If destination already exists, 7529167Ssam * delete it first. 7539167Ssam * 3) Unlink source reference to inode if still around. 7549167Ssam * 4) If a directory was moved and the parent of the destination 7559167Ssam * is different from the source, patch the ".." entry in the 7569167Ssam * directory. 7579167Ssam * 7589167Ssam * Source and destination must either both be directories, or both 7599167Ssam * not be directories. If target is a directory, it must be empty. 7609167Ssam */ 7617701Ssam rename() 7627701Ssam { 7637701Ssam struct a { 7647701Ssam char *from; 7657701Ssam char *to; 7667701Ssam } *uap; 7679167Ssam register struct inode *ip, *xp, *dp; 7689167Ssam int oldparent, parentdifferent, doingdirectory; 76910051Ssam int error = 0; 7707701Ssam 7719167Ssam uap = (struct a *)u.u_ap; 77211641Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 7739167Ssam if (ip == NULL) 7749167Ssam return; 7759167Ssam dp = u.u_pdir; 7769167Ssam oldparent = 0, doingdirectory = 0; 7779167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7789167Ssam register struct direct *d; 7799167Ssam 7809167Ssam d = &u.u_dent; 7819167Ssam /* 78211641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 7839167Ssam */ 78411641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 78511641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 78611641Ssam (dp == ip)) { 78711641Ssam iput(dp); 78811641Ssam if (dp == ip) 78911641Ssam irele(ip); 79011641Ssam else 79110051Ssam iput(ip); 79211641Ssam u.u_error = EINVAL; 79311641Ssam return; 7949167Ssam } 7959167Ssam oldparent = dp->i_number; 7969167Ssam doingdirectory++; 7979167Ssam } 79811641Ssam iput(dp); 7999167Ssam 8009167Ssam /* 8019167Ssam * 1) Bump link count while we're moving stuff 8029167Ssam * around. If we crash somewhere before 8039167Ssam * completing our work, the link count 8049167Ssam * may be wrong, but correctable. 8059167Ssam */ 8069167Ssam ip->i_nlink++; 8079167Ssam ip->i_flag |= ICHG; 8089167Ssam iupdat(ip, &time, &time, 1); 8099167Ssam iunlock(ip); 8109167Ssam 8119167Ssam /* 8129167Ssam * When the target exists, both the directory 8139167Ssam * and target inodes are returned locked. 8149167Ssam */ 8159167Ssam u.u_dirp = (caddr_t)uap->to; 8169167Ssam xp = namei(uchar, CREATE | LOCKPARENT, 0); 81710051Ssam if (u.u_error) { 81810051Ssam error = u.u_error; 8199167Ssam goto out; 82010051Ssam } 8219167Ssam dp = u.u_pdir; 8229167Ssam /* 82311641Ssam * If ".." must be changed (ie the directory gets a new 82412816Smckusick * parent) then the source directory must not be in the 82512816Smckusick * directory heirarchy above the target, as this would 82612816Smckusick * orphan everything below the source directory. Also 82712816Smckusick * the user must have write permission in the source so 82812816Smckusick * as to be able to change "..". We must repeat the call 82912816Smckusick * to namei, as the parent directory is unlocked by the 83012816Smckusick * call to checkpath(). 83111641Ssam */ 83211641Ssam parentdifferent = oldparent != dp->i_number; 83312816Smckusick if (doingdirectory && parentdifferent) { 83412816Smckusick if (access(ip, IWRITE)) 83512816Smckusick goto bad; 83612816Smckusick do { 83712816Smckusick dp = u.u_pdir; 83812816Smckusick if (xp != NULL) 83912816Smckusick iput(xp); 84012816Smckusick u.u_error = checkpath(ip, dp); 84112816Smckusick if (u.u_error) 84212816Smckusick goto out; 84312816Smckusick u.u_dirp = (caddr_t)uap->to; 84412816Smckusick xp = namei(uchar, CREATE | LOCKPARENT, 0); 84512816Smckusick if (u.u_error) { 84612816Smckusick error = u.u_error; 84712816Smckusick goto out; 84812816Smckusick } 84912816Smckusick } while (dp != u.u_pdir); 85012816Smckusick } 85111641Ssam /* 8529167Ssam * 2) If target doesn't exist, link the target 8539167Ssam * to the source and unlink the source. 8549167Ssam * Otherwise, rewrite the target directory 8559167Ssam * entry to reference the source inode and 8569167Ssam * expunge the original entry's existence. 8579167Ssam */ 8589167Ssam if (xp == NULL) { 8599167Ssam if (dp->i_dev != ip->i_dev) { 86010051Ssam error = EXDEV; 8619167Ssam goto bad; 8629167Ssam } 8639167Ssam /* 8649167Ssam * Account for ".." in directory. 8659167Ssam * When source and destination have the 8669167Ssam * same parent we don't fool with the 8679167Ssam * link count -- this isn't required 8689167Ssam * because we do a similar check below. 8699167Ssam */ 8709167Ssam if (doingdirectory && parentdifferent) { 8719167Ssam dp->i_nlink++; 8729167Ssam dp->i_flag |= ICHG; 8739167Ssam iupdat(dp, &time, &time, 1); 8749167Ssam } 87510850Ssam error = direnter(ip); 87610850Ssam if (error) 8779167Ssam goto out; 8789167Ssam } else { 8799167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 88010051Ssam error = EXDEV; 8819167Ssam goto bad; 8829167Ssam } 8839167Ssam /* 88410590Ssam * Short circuit rename(foo, foo). 88510590Ssam */ 88610590Ssam if (xp->i_number == ip->i_number) 88710590Ssam goto bad; 88810590Ssam /* 88910051Ssam * Target must be empty if a directory 89010051Ssam * and have no links to it. 8919167Ssam * Also, insure source and target are 8929167Ssam * compatible (both directories, or both 8939167Ssam * not directories). 8949167Ssam */ 8959167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 89610051Ssam if (!dirempty(xp) || xp->i_nlink > 2) { 89710051Ssam error = ENOTEMPTY; 8989167Ssam goto bad; 8999167Ssam } 9009167Ssam if (!doingdirectory) { 90110051Ssam error = ENOTDIR; 9029167Ssam goto bad; 9039167Ssam } 9049167Ssam } else if (doingdirectory) { 90510051Ssam error = EISDIR; 9069167Ssam goto bad; 9079167Ssam } 9089167Ssam dirrewrite(dp, ip); 90910051Ssam if (u.u_error) { 91010051Ssam error = u.u_error; 9119167Ssam goto bad1; 91210051Ssam } 9139167Ssam /* 91410051Ssam * Adjust the link count of the target to 91510051Ssam * reflect the dirrewrite above. If this is 91610051Ssam * a directory it is empty and there are 91710051Ssam * no links to it, so we can squash the inode and 91810051Ssam * any space associated with it. We disallowed 91910051Ssam * renaming over top of a directory with links to 92010051Ssam * it above, as we've no way to determine if 92110051Ssam * we've got a link or the directory itself, and 92210051Ssam * if we get a link, then ".." will be screwed up. 9239167Ssam */ 92410051Ssam xp->i_nlink--; 9259167Ssam if (doingdirectory) { 92610051Ssam if (--xp->i_nlink != 0) 92710051Ssam panic("rename: linked directory"); 9289167Ssam itrunc(xp, (u_long)0); 92910051Ssam } 9309167Ssam xp->i_flag |= ICHG; 9319167Ssam iput(xp); 93210246Ssam xp = NULL; 9339167Ssam } 9349167Ssam 9359167Ssam /* 9369167Ssam * 3) Unlink the source. 9379167Ssam */ 9389167Ssam u.u_dirp = uap->from; 9399167Ssam dp = namei(uchar, DELETE, 0); 9409167Ssam /* 9419167Ssam * Insure directory entry still exists and 9429167Ssam * has not changed since the start of all 9439167Ssam * this. If either has occured, forget about 9449167Ssam * about deleting the original entry and just 9459167Ssam * adjust the link count in the inode. 9469167Ssam */ 9479167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 9489167Ssam ip->i_nlink--; 9499167Ssam ip->i_flag |= ICHG; 9509167Ssam } else { 9519167Ssam /* 9529167Ssam * If source is a directory, must adjust 9539167Ssam * link count of parent directory also. 9549167Ssam * If target didn't exist and source and 9559167Ssam * target have the same parent, then we 9569167Ssam * needn't touch the link count, it all 9579167Ssam * balances out in the end. Otherwise, we 9589167Ssam * must do so to reflect deletion of ".." 9599167Ssam * done above. 9609167Ssam */ 9619167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9629167Ssam dp->i_nlink--; 9639167Ssam dp->i_flag |= ICHG; 9649167Ssam } 9659167Ssam if (dirremove()) { 9669167Ssam ip->i_nlink--; 9679167Ssam ip->i_flag |= ICHG; 9689167Ssam } 96910051Ssam if (error == 0) /* conservative */ 97010051Ssam error = u.u_error; 9719167Ssam } 9729167Ssam irele(ip); 9739167Ssam if (dp) 9749167Ssam iput(dp); 9759167Ssam 9769167Ssam /* 9779167Ssam * 4) Renaming a directory with the parent 9789167Ssam * different requires ".." to be rewritten. 9799167Ssam * The window is still there for ".." to 9809167Ssam * be inconsistent, but this is unavoidable, 9819167Ssam * and a lot shorter than when it was done 9829167Ssam * in a user process. 9839167Ssam */ 98410051Ssam if (doingdirectory && parentdifferent && error == 0) { 9859167Ssam struct dirtemplate dirbuf; 9869167Ssam 9879167Ssam u.u_dirp = uap->to; 9889167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 9899167Ssam if (ip == NULL) { 9909167Ssam printf("rename: .. went away\n"); 9919167Ssam return; 9929167Ssam } 9939167Ssam dp = u.u_pdir; 9949167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 9959167Ssam printf("rename: .. not a directory\n"); 9969167Ssam goto stuck; 9979167Ssam } 99810051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 9999167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 100010051Ssam if (error == 0) { 10019167Ssam dirbuf.dotdot_ino = dp->i_number; 10029167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10039167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10049167Ssam } 10059167Ssam stuck: 10069167Ssam irele(dp); 10079167Ssam iput(ip); 10089167Ssam } 100910051Ssam goto done; 101010051Ssam 10119167Ssam bad: 101210246Ssam iput(dp); 10139167Ssam bad1: 10149167Ssam if (xp) 101510246Ssam iput(xp); 10169167Ssam out: 10179167Ssam ip->i_nlink--; 10189167Ssam ip->i_flag |= ICHG; 10199167Ssam irele(ip); 102010051Ssam done: 102110051Ssam if (error) 102210051Ssam u.u_error = error; 10237701Ssam } 10247701Ssam 10257535Sroot /* 10267535Sroot * Make a new file. 10277535Sroot */ 10287535Sroot struct inode * 10297535Sroot maknode(mode) 10307535Sroot int mode; 10317535Sroot { 10327535Sroot register struct inode *ip; 10337535Sroot ino_t ipref; 10347535Sroot 10357535Sroot if ((mode & IFMT) == IFDIR) 10367535Sroot ipref = dirpref(u.u_pdir->i_fs); 10377535Sroot else 10387535Sroot ipref = u.u_pdir->i_number; 10397535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10407535Sroot if (ip == NULL) { 10417535Sroot iput(u.u_pdir); 10427701Ssam return (NULL); 10437535Sroot } 10447701Ssam #ifdef QUOTA 10457535Sroot if (ip->i_dquot != NODQUOT) 10467535Sroot panic("maknode: dquot"); 10477535Sroot #endif 10487535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10497535Sroot if ((mode & IFMT) == 0) 10507535Sroot mode |= IFREG; 10517535Sroot ip->i_mode = mode & ~u.u_cmask; 10527535Sroot ip->i_nlink = 1; 10537535Sroot ip->i_uid = u.u_uid; 10547535Sroot ip->i_gid = u.u_pdir->i_gid; 105511811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 105611811Ssam ip->i_mode &= ~ISGID; 10577701Ssam #ifdef QUOTA 10587535Sroot ip->i_dquot = inoquota(ip); 10597535Sroot #endif 10607535Sroot 10617535Sroot /* 10627535Sroot * Make sure inode goes to disk before directory entry. 10637535Sroot */ 10648673Sroot iupdat(ip, &time, &time, 1); 106510850Ssam u.u_error = direnter(ip); 10667535Sroot if (u.u_error) { 10677535Sroot /* 106810850Ssam * Write error occurred trying to update directory 106910850Ssam * so must deallocate the inode. 10707535Sroot */ 10717535Sroot ip->i_nlink = 0; 10727535Sroot ip->i_flag |= ICHG; 10737535Sroot iput(ip); 10747701Ssam return (NULL); 10757535Sroot } 10767701Ssam return (ip); 10777535Sroot } 107812756Ssam 107912756Ssam /* 108012756Ssam * A virgin directory (no blushing please). 108112756Ssam */ 108212756Ssam struct dirtemplate mastertemplate = { 108312756Ssam 0, 12, 1, ".", 108412756Ssam 0, DIRBLKSIZ - 12, 2, ".." 108512756Ssam }; 108612756Ssam 108712756Ssam /* 108812756Ssam * Mkdir system call 108912756Ssam */ 109012756Ssam mkdir() 109112756Ssam { 109212756Ssam struct a { 109312756Ssam char *name; 109412756Ssam int dmode; 109512756Ssam } *uap; 109612756Ssam register struct inode *ip, *dp; 109712756Ssam struct dirtemplate dirtemplate; 109812756Ssam 109912756Ssam uap = (struct a *)u.u_ap; 110012756Ssam ip = namei(uchar, CREATE, 0); 110112756Ssam if (u.u_error) 110212756Ssam return; 110312756Ssam if (ip != NULL) { 110412756Ssam iput(ip); 110512756Ssam u.u_error = EEXIST; 110612756Ssam return; 110712756Ssam } 110812756Ssam dp = u.u_pdir; 110912756Ssam uap->dmode &= 0777; 111012756Ssam uap->dmode |= IFDIR; 111112756Ssam /* 111212756Ssam * Must simulate part of maknode here 111312756Ssam * in order to acquire the inode, but 111412756Ssam * not have it entered in the parent 111512756Ssam * directory. The entry is made later 111612756Ssam * after writing "." and ".." entries out. 111712756Ssam */ 111812756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 111912756Ssam if (ip == NULL) { 112012756Ssam iput(dp); 112112756Ssam return; 112212756Ssam } 112312756Ssam #ifdef QUOTA 112412756Ssam if (ip->i_dquot != NODQUOT) 112512756Ssam panic("mkdir: dquot"); 112612756Ssam #endif 112712756Ssam ip->i_flag |= IACC|IUPD|ICHG; 112812756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 112912756Ssam ip->i_nlink = 2; 113012756Ssam ip->i_uid = u.u_uid; 113112756Ssam ip->i_gid = dp->i_gid; 113212756Ssam #ifdef QUOTA 113312756Ssam ip->i_dquot = inoquota(ip); 113412756Ssam #endif 113512756Ssam iupdat(ip, &time, &time, 1); 113612756Ssam 113712756Ssam /* 113812756Ssam * Bump link count in parent directory 113912756Ssam * to reflect work done below. Should 114012756Ssam * be done before reference is created 114112756Ssam * so reparation is possible if we crash. 114212756Ssam */ 114312756Ssam dp->i_nlink++; 114412756Ssam dp->i_flag |= ICHG; 114512756Ssam iupdat(dp, &time, &time, 1); 114612756Ssam 114712756Ssam /* 114812756Ssam * Initialize directory with "." 114912756Ssam * and ".." from static template. 115012756Ssam */ 115112756Ssam dirtemplate = mastertemplate; 115212756Ssam dirtemplate.dot_ino = ip->i_number; 115312756Ssam dirtemplate.dotdot_ino = dp->i_number; 115412756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 115512756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 115612756Ssam if (u.u_error) { 115712756Ssam dp->i_nlink--; 115812756Ssam dp->i_flag |= ICHG; 115912756Ssam goto bad; 116012756Ssam } 116112756Ssam /* 116212756Ssam * Directory all set up, now 116312756Ssam * install the entry for it in 116412756Ssam * the parent directory. 116512756Ssam */ 116612756Ssam u.u_error = direnter(ip); 116712756Ssam dp = NULL; 116812756Ssam if (u.u_error) { 116912756Ssam u.u_dirp = uap->name; 117012756Ssam dp = namei(uchar, LOOKUP, 0); 117112756Ssam if (dp) { 117212756Ssam dp->i_nlink--; 117312756Ssam dp->i_flag |= ICHG; 117412756Ssam } 117512756Ssam } 117612756Ssam bad: 117712756Ssam /* 117812756Ssam * No need to do an explicit itrunc here, 117912756Ssam * irele will do this for us because we set 118012756Ssam * the link count to 0. 118112756Ssam */ 118212756Ssam if (u.u_error) { 118312756Ssam ip->i_nlink = 0; 118412756Ssam ip->i_flag |= ICHG; 118512756Ssam } 118612756Ssam if (dp) 118712756Ssam iput(dp); 118812756Ssam iput(ip); 118912756Ssam } 119012756Ssam 119112756Ssam /* 119212756Ssam * Rmdir system call. 119312756Ssam */ 119412756Ssam rmdir() 119512756Ssam { 119612756Ssam struct a { 119712756Ssam char *name; 119812756Ssam }; 119912756Ssam register struct inode *ip, *dp; 120012756Ssam 120112756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 120212756Ssam if (ip == NULL) 120312756Ssam return; 120412756Ssam dp = u.u_pdir; 120512756Ssam /* 120612756Ssam * No rmdir "." please. 120712756Ssam */ 120812756Ssam if (dp == ip) { 120912756Ssam irele(dp); 121012756Ssam iput(ip); 121112756Ssam u.u_error = EINVAL; 121212756Ssam return; 121312756Ssam } 121412756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 121512756Ssam u.u_error = ENOTDIR; 121612756Ssam goto out; 121712756Ssam } 121812756Ssam /* 121912756Ssam * Don't remove a mounted on directory. 122012756Ssam */ 122112756Ssam if (ip->i_dev != dp->i_dev) { 122212756Ssam u.u_error = EBUSY; 122312756Ssam goto out; 122412756Ssam } 122512756Ssam /* 122612756Ssam * Verify the directory is empty (and valid). 122712756Ssam * (Rmdir ".." won't be valid since 122812756Ssam * ".." will contain a reference to 122912756Ssam * the current directory and thus be 123012756Ssam * non-empty.) 123112756Ssam */ 123212756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 123312756Ssam u.u_error = ENOTEMPTY; 123412756Ssam goto out; 123512756Ssam } 123612756Ssam /* 123712756Ssam * Delete reference to directory before purging 123812756Ssam * inode. If we crash in between, the directory 123912756Ssam * will be reattached to lost+found, 124012756Ssam */ 124112756Ssam if (dirremove() == 0) 124212756Ssam goto out; 124312756Ssam dp->i_nlink--; 124412756Ssam dp->i_flag |= ICHG; 124512756Ssam iput(dp); 124612756Ssam dp = NULL; 124712756Ssam /* 124812756Ssam * Truncate inode. The only stuff left 124912756Ssam * in the directory is "." and "..". The 125012756Ssam * "." reference is inconsequential since 125112756Ssam * we're quashing it. The ".." reference 125212756Ssam * has already been adjusted above. We've 125312756Ssam * removed the "." reference and the reference 125412756Ssam * in the parent directory, but there may be 125512756Ssam * other hard links so decrement by 2 and 125612756Ssam * worry about them later. 125712756Ssam */ 125812756Ssam ip->i_nlink -= 2; 125912756Ssam itrunc(ip, (u_long)0); 126012756Ssam out: 126112756Ssam if (dp) 126212756Ssam iput(dp); 126312756Ssam iput(ip); 126412756Ssam } 126512756Ssam 126612756Ssam struct file * 126712756Ssam getinode(fdes) 126812756Ssam int fdes; 126912756Ssam { 127012756Ssam register struct file *fp; 127112756Ssam 127212756Ssam fp = getf(fdes); 127312756Ssam if (fp == 0) 127412756Ssam return (0); 127512756Ssam if (fp->f_type != DTYPE_INODE) { 127612756Ssam u.u_error = EINVAL; 127712756Ssam return (0); 127812756Ssam } 127912756Ssam return (fp); 128012756Ssam } 128112756Ssam 128212756Ssam /* 128312756Ssam * mode mask for creation of files 128412756Ssam */ 128512756Ssam umask() 128612756Ssam { 128712756Ssam register struct a { 128812756Ssam int mask; 128912756Ssam } *uap; 129012756Ssam 129112756Ssam uap = (struct a *)u.u_ap; 129212756Ssam u.u_r.r_val1 = u.u_cmask; 129312756Ssam u.u_cmask = uap->mask & 07777; 129412756Ssam } 1295