1*12816Smckusick /* vfs_syscalls.c 4.58 83/05/28 */ 237Sbill 337Sbill #include "../h/param.h" 437Sbill #include "../h/systm.h" 537Sbill #include "../h/dir.h" 637Sbill #include "../h/user.h" 78040Sroot #include "../h/kernel.h" 86254Sroot #include "../h/file.h" 96574Smckusic #include "../h/stat.h" 1037Sbill #include "../h/inode.h" 116574Smckusic #include "../h/fs.h" 126254Sroot #include "../h/buf.h" 136254Sroot #include "../h/proc.h" 147482Skre #include "../h/quota.h" 157826Sroot #include "../h/uio.h" 167826Sroot #include "../h/socket.h" 178632Sroot #include "../h/socketvar.h" 189167Ssam #include "../h/nami.h" 1912756Ssam #include "../h/mount.h" 2037Sbill 2112756Ssam extern struct fileops inodeops; 2212756Ssam struct file *getinode(); 2312756Ssam 249167Ssam /* 259167Ssam * Change current working directory (``.''). 269167Ssam */ 276254Sroot chdir() 286254Sroot { 296254Sroot 306254Sroot chdirec(&u.u_cdir); 316254Sroot } 326254Sroot 339167Ssam /* 349167Ssam * Change notion of root (``/'') directory. 359167Ssam */ 366254Sroot chroot() 376254Sroot { 386254Sroot 396254Sroot if (suser()) 406254Sroot chdirec(&u.u_rdir); 416254Sroot } 426254Sroot 439167Ssam /* 449167Ssam * Common routine for chroot and chdir. 459167Ssam */ 466254Sroot chdirec(ipp) 477701Ssam register struct inode **ipp; 486254Sroot { 496254Sroot register struct inode *ip; 506254Sroot struct a { 516254Sroot char *fname; 526254Sroot }; 536254Sroot 549167Ssam ip = namei(uchar, LOOKUP, 1); 559167Ssam if (ip == NULL) 566254Sroot return; 579167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 586254Sroot u.u_error = ENOTDIR; 596254Sroot goto bad; 606254Sroot } 619167Ssam if (access(ip, IEXEC)) 626254Sroot goto bad; 637122Smckusick iunlock(ip); 647142Smckusick if (*ipp) 657142Smckusick irele(*ipp); 666254Sroot *ipp = ip; 676254Sroot return; 686254Sroot 696254Sroot bad: 706254Sroot iput(ip); 716254Sroot } 726254Sroot 7337Sbill /* 746254Sroot * Open system call. 756254Sroot */ 766254Sroot open() 776254Sroot { 7812756Ssam struct a { 796254Sroot char *fname; 807701Ssam int mode; 8112756Ssam int crtmode; 8212756Ssam } *uap = (struct a *) u.u_ap; 836254Sroot 8412756Ssam copen(uap->mode-FOPEN, uap->crtmode); 856254Sroot } 866254Sroot 876254Sroot /* 886254Sroot * Creat system call. 896254Sroot */ 9012756Ssam creat() 916254Sroot { 9212756Ssam struct a { 936254Sroot char *fname; 946254Sroot int fmode; 9512756Ssam } *uap = (struct a *)u.u_ap; 966254Sroot 9712756Ssam copen(FWRITE|FCREAT|FTRUNC, uap->fmode); 986254Sroot } 996254Sroot 1006254Sroot /* 1016254Sroot * Common code for open and creat. 10212756Ssam * Check permissions, allocate an open file structure, 10312756Ssam * and call the device open routine if any. 1046254Sroot */ 10512756Ssam copen(mode, arg) 10612756Ssam register int mode; 10712756Ssam int arg; 10812756Ssam { 1096254Sroot register struct inode *ip; 1106254Sroot register struct file *fp; 11112756Ssam int i; 1126254Sroot 11312756Ssam #ifdef notdef 11412756Ssam if ((mode&(FREAD|FWRITE)) == 0) { 11512756Ssam u.u_error = EINVAL; 11612756Ssam return; 11712756Ssam } 11812756Ssam #endif 11912756Ssam if (mode&FCREAT) { 12012756Ssam ip = namei(uchar, CREATE, 1); 12112756Ssam if (ip == NULL) { 12212756Ssam if (u.u_error) 12312756Ssam return; 12412756Ssam ip = maknode(arg&07777&(~ISVTX)); 12512756Ssam if (ip == NULL) 12612756Ssam return; 12712756Ssam mode &= ~FTRUNC; 12812756Ssam } else { 12912756Ssam if (mode&FEXCL) { 13012756Ssam u.u_error = EEXIST; 13112756Ssam iput(ip); 13212756Ssam return; 13312756Ssam } 13412756Ssam mode &= ~FCREAT; 13512756Ssam } 13612756Ssam } else { 13712756Ssam ip = namei(uchar, LOOKUP, 1); 13812756Ssam if (ip == NULL) 13912756Ssam return; 14012756Ssam } 14112756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 14212756Ssam u.u_error = EOPNOTSUPP; 14312756Ssam goto bad; 14412756Ssam } 14512756Ssam if ((mode&FCREAT) == 0) { 1466254Sroot if (mode&FREAD) 1477701Ssam if (access(ip, IREAD)) 1487701Ssam goto bad; 1496254Sroot if (mode&FWRITE) { 1507701Ssam if (access(ip, IWRITE)) 1517701Ssam goto bad; 1527701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1536254Sroot u.u_error = EISDIR; 1547701Ssam goto bad; 1557701Ssam } 1566254Sroot } 1576254Sroot } 15812756Ssam fp = falloc(); 15912756Ssam if (fp == NULL) 16012756Ssam goto bad; 16112756Ssam if (mode&FTRUNC) 1629167Ssam itrunc(ip, (u_long)0); 1637122Smckusick iunlock(ip); 16412756Ssam fp->f_flag = mode&FMASK; 16512756Ssam fp->f_type = DTYPE_INODE; 16612756Ssam fp->f_ops = &inodeops; 16712756Ssam fp->f_data = (caddr_t)ip; 1686254Sroot i = u.u_r.r_val1; 16912756Ssam #ifdef notdef 17012756Ssam if (setjmp(&u.u_qsave)) { 17112756Ssam if (u.u_error == 0) 17212756Ssam u.u_error = EINTR; 17312756Ssam u.u_ofile[i] = NULL; 17412756Ssam closef(fp); 17512756Ssam return; 17612756Ssam } 17712756Ssam #endif 1788559Sroot u.u_error = openi(ip, mode); 17912756Ssam if (u.u_error == 0) 1806254Sroot return; 1816254Sroot u.u_ofile[i] = NULL; 1826254Sroot fp->f_count--; 1837142Smckusick irele(ip); 1847701Ssam return; 1857701Ssam bad: 1867701Ssam iput(ip); 1876254Sroot } 1886254Sroot 1896254Sroot /* 1906254Sroot * Mknod system call 1916254Sroot */ 1926254Sroot mknod() 1936254Sroot { 1946254Sroot register struct inode *ip; 1956254Sroot register struct a { 1966254Sroot char *fname; 1976254Sroot int fmode; 1986254Sroot int dev; 1996254Sroot } *uap; 2006254Sroot 2016254Sroot uap = (struct a *)u.u_ap; 20212756Ssam if (!suser()) 20312756Ssam return; 20412756Ssam ip = namei(uchar, CREATE, 0); 20512756Ssam if (ip != NULL) { 20612756Ssam u.u_error = EEXIST; 20712756Ssam goto out; 2086254Sroot } 2096254Sroot if (u.u_error) 2106254Sroot return; 2116254Sroot ip = maknode(uap->fmode); 2126254Sroot if (ip == NULL) 2136254Sroot return; 21412756Ssam switch (ip->i_mode & IFMT) { 21512756Ssam 21612756Ssam case IFCHR: 21712756Ssam case IFBLK: 21812756Ssam if (uap->dev) { 21912756Ssam /* 22012756Ssam * Want to be able to use this to make badblock 22112756Ssam * inodes, so don't truncate the dev number. 22212756Ssam */ 22312756Ssam ip->i_rdev = uap->dev; 22412756Ssam ip->i_flag |= IACC|IUPD|ICHG; 22512756Ssam } 2266254Sroot } 2276254Sroot 2286254Sroot out: 2296254Sroot iput(ip); 2306254Sroot } 2316254Sroot 2326254Sroot /* 2336254Sroot * link system call 2346254Sroot */ 2356254Sroot link() 2366254Sroot { 2376254Sroot register struct inode *ip, *xp; 2386254Sroot register struct a { 2396254Sroot char *target; 2406254Sroot char *linkname; 2416254Sroot } *uap; 2426254Sroot 2436254Sroot uap = (struct a *)u.u_ap; 2449167Ssam ip = namei(uchar, LOOKUP, 1); /* well, this routine is doomed anyhow */ 2456254Sroot if (ip == NULL) 2466254Sroot return; 2479167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2487439Sroot iput(ip); 2497439Sroot return; 2507439Sroot } 2516254Sroot ip->i_nlink++; 2526254Sroot ip->i_flag |= ICHG; 2538673Sroot iupdat(ip, &time, &time, 1); 2547122Smckusick iunlock(ip); 2556254Sroot u.u_dirp = (caddr_t)uap->linkname; 2569167Ssam xp = namei(uchar, CREATE, 0); 2576254Sroot if (xp != NULL) { 2586254Sroot u.u_error = EEXIST; 2596254Sroot iput(xp); 2606254Sroot goto out; 2616254Sroot } 2626254Sroot if (u.u_error) 2636254Sroot goto out; 2646254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2656254Sroot iput(u.u_pdir); 2666254Sroot u.u_error = EXDEV; 2676254Sroot goto out; 2686254Sroot } 26910850Ssam u.u_error = direnter(ip); 2706254Sroot out: 2716254Sroot if (u.u_error) { 2726254Sroot ip->i_nlink--; 2736254Sroot ip->i_flag |= ICHG; 2746254Sroot } 2757142Smckusick irele(ip); 2766254Sroot } 2776254Sroot 2786254Sroot /* 2796254Sroot * symlink -- make a symbolic link 2806254Sroot */ 2816254Sroot symlink() 2826254Sroot { 2836254Sroot register struct a { 2846254Sroot char *target; 2856254Sroot char *linkname; 2866254Sroot } *uap; 2876254Sroot register struct inode *ip; 2886254Sroot register char *tp; 2896254Sroot register c, nc; 2906254Sroot 2916254Sroot uap = (struct a *)u.u_ap; 2926254Sroot tp = uap->target; 2936254Sroot nc = 0; 2946254Sroot while (c = fubyte(tp)) { 2956254Sroot if (c < 0) { 2966254Sroot u.u_error = EFAULT; 2976254Sroot return; 2986254Sroot } 2996254Sroot tp++; 3006254Sroot nc++; 3016254Sroot } 3026254Sroot u.u_dirp = uap->linkname; 3039167Ssam ip = namei(uchar, CREATE, 0); 3046254Sroot if (ip) { 3056254Sroot iput(ip); 3066254Sroot u.u_error = EEXIST; 3076254Sroot return; 3086254Sroot } 3096254Sroot if (u.u_error) 3106254Sroot return; 3116254Sroot ip = maknode(IFLNK | 0777); 3126254Sroot if (ip == NULL) 3136254Sroot return; 3147826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3159167Ssam /* handle u.u_error != 0 */ 3166254Sroot iput(ip); 3176254Sroot } 3186254Sroot 3196254Sroot /* 3206254Sroot * Unlink system call. 3216254Sroot * Hard to avoid races here, especially 3226254Sroot * in unlinking directories. 3236254Sroot */ 3246254Sroot unlink() 3256254Sroot { 3266254Sroot struct a { 3276254Sroot char *fname; 3286254Sroot }; 3299167Ssam register struct inode *ip, *dp; 3306254Sroot 3319167Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 3329167Ssam if (ip == NULL) 3336254Sroot return; 3349167Ssam dp = u.u_pdir; 3359167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3366254Sroot goto out; 3376254Sroot /* 3386254Sroot * Don't unlink a mounted file. 3396254Sroot */ 3409167Ssam if (ip->i_dev != dp->i_dev) { 3416254Sroot u.u_error = EBUSY; 3426254Sroot goto out; 3436254Sroot } 3446254Sroot if (ip->i_flag&ITEXT) 3456254Sroot xrele(ip); /* try once to free text */ 3467535Sroot if (dirremove()) { 3477535Sroot ip->i_nlink--; 3487535Sroot ip->i_flag |= ICHG; 3496254Sroot } 3506254Sroot out: 3519167Ssam if (dp == ip) 3527142Smckusick irele(ip); 3537142Smckusick else 3547142Smckusick iput(ip); 3559167Ssam iput(dp); 3566254Sroot } 3576254Sroot 3586254Sroot /* 3596254Sroot * Seek system call 3606254Sroot */ 3618040Sroot lseek() 3626254Sroot { 3636254Sroot register struct file *fp; 3646254Sroot register struct a { 3657701Ssam int fd; 3666254Sroot off_t off; 3676254Sroot int sbase; 3686254Sroot } *uap; 3696254Sroot 3706254Sroot uap = (struct a *)u.u_ap; 37112756Ssam fp = getinode(uap->fd); 3726254Sroot if (fp == NULL) 3736254Sroot return; 37412756Ssam if (uap->sbase == L_INCR) 3756254Sroot uap->off += fp->f_offset; 37612756Ssam else if (uap->sbase == L_XTND) 37712756Ssam uap->off += ((struct inode *)fp->f_data)->i_size; 3786254Sroot fp->f_offset = uap->off; 3796254Sroot u.u_r.r_off = uap->off; 3806254Sroot } 3816254Sroot 3826254Sroot /* 3836254Sroot * Access system call 3846254Sroot */ 3856254Sroot saccess() 3866254Sroot { 3876254Sroot register svuid, svgid; 3886254Sroot register struct inode *ip; 3896254Sroot register struct a { 3906254Sroot char *fname; 3916254Sroot int fmode; 3926254Sroot } *uap; 3936254Sroot 3946254Sroot uap = (struct a *)u.u_ap; 3956254Sroot svuid = u.u_uid; 3966254Sroot svgid = u.u_gid; 3976254Sroot u.u_uid = u.u_ruid; 3986254Sroot u.u_gid = u.u_rgid; 3999167Ssam ip = namei(uchar, LOOKUP, 1); 4006254Sroot if (ip != NULL) { 40112756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4027701Ssam goto done; 40312756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4047701Ssam goto done; 40512756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4067701Ssam goto done; 4077701Ssam done: 4086254Sroot iput(ip); 4096254Sroot } 4106254Sroot u.u_uid = svuid; 4116254Sroot u.u_gid = svgid; 4126254Sroot } 4136254Sroot 4146254Sroot /* 4156574Smckusic * Stat system call. This version follows links. 41637Sbill */ 41737Sbill stat() 41837Sbill { 41937Sbill 42012756Ssam stat1(1); 42137Sbill } 42237Sbill 42337Sbill /* 4246574Smckusic * Lstat system call. This version does not follow links. 4255992Swnj */ 4265992Swnj lstat() 4275992Swnj { 42812756Ssam 42912756Ssam stat1(0); 43012756Ssam } 43112756Ssam 43212756Ssam stat1(follow) 43312756Ssam int follow; 43412756Ssam { 4355992Swnj register struct inode *ip; 4365992Swnj register struct a { 4375992Swnj char *fname; 43812756Ssam struct stat *ub; 4395992Swnj } *uap; 44012756Ssam struct stat sb; 4415992Swnj 4425992Swnj uap = (struct a *)u.u_ap; 44312756Ssam ip = namei(uchar, LOOKUP, follow); 4445992Swnj if (ip == NULL) 4455992Swnj return; 44612756Ssam (void) statinode(ip, &sb); 4475992Swnj iput(ip); 44812756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4495992Swnj } 4505992Swnj 4515992Swnj /* 4525992Swnj * Return target name of a symbolic link 45337Sbill */ 4545992Swnj readlink() 4555992Swnj { 4565992Swnj register struct inode *ip; 4575992Swnj register struct a { 4585992Swnj char *name; 4595992Swnj char *buf; 4605992Swnj int count; 4617826Sroot } *uap = (struct a *)u.u_ap; 4627826Sroot int resid; 4635992Swnj 4649167Ssam ip = namei(uchar, LOOKUP, 0); 4655992Swnj if (ip == NULL) 4665992Swnj return; 4675992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 4685992Swnj u.u_error = ENXIO; 4695992Swnj goto out; 4705992Swnj } 4717826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 4725992Swnj out: 4735992Swnj iput(ip); 4747826Sroot u.u_r.r_val1 = uap->count - resid; 4755992Swnj } 4765992Swnj 4779167Ssam /* 4789167Ssam * Change mode of a file given path name. 4799167Ssam */ 4806254Sroot chmod() 4815992Swnj { 4827701Ssam struct inode *ip; 4837701Ssam struct a { 4846254Sroot char *fname; 4856254Sroot int fmode; 4865992Swnj } *uap; 4875992Swnj 4885992Swnj uap = (struct a *)u.u_ap; 4896254Sroot if ((ip = owner(1)) == NULL) 4905992Swnj return; 4917701Ssam chmod1(ip, uap->fmode); 4929167Ssam iput(ip); 4937701Ssam } 4947439Sroot 4959167Ssam /* 4969167Ssam * Change mode of a file given a file descriptor. 4979167Ssam */ 4987701Ssam fchmod() 4997701Ssam { 5007701Ssam struct a { 5017701Ssam int fd; 5027701Ssam int fmode; 5037701Ssam } *uap; 5047701Ssam register struct inode *ip; 5057701Ssam register struct file *fp; 5067701Ssam 5077701Ssam uap = (struct a *)u.u_ap; 50812756Ssam fp = getinode(uap->fd); 5097701Ssam if (fp == NULL) 5107701Ssam return; 51112756Ssam ip = (struct inode *)fp->f_data; 5129167Ssam if (u.u_uid != ip->i_uid && !suser()) 5139167Ssam return; 5147701Ssam ilock(ip); 5157701Ssam chmod1(ip, uap->fmode); 5169167Ssam iunlock(ip); 5177701Ssam } 5187701Ssam 5199167Ssam /* 5209167Ssam * Change the mode on a file. 5219167Ssam * Inode must be locked before calling. 5229167Ssam */ 5237701Ssam chmod1(ip, mode) 5247701Ssam register struct inode *ip; 5257701Ssam register int mode; 5267701Ssam { 5277868Sroot 5286254Sroot ip->i_mode &= ~07777; 5297439Sroot if (u.u_uid) { 5307701Ssam mode &= ~ISVTX; 53111811Ssam if (!groupmember(ip->i_gid)) 53211811Ssam mode &= ~ISGID; 5337439Sroot } 5347701Ssam ip->i_mode |= mode&07777; 5356254Sroot ip->i_flag |= ICHG; 5366254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5376254Sroot xrele(ip); 5385992Swnj } 5395992Swnj 5409167Ssam /* 5419167Ssam * Set ownership given a path name. 5429167Ssam */ 5436254Sroot chown() 54437Sbill { 5457701Ssam struct inode *ip; 5467701Ssam struct a { 5476254Sroot char *fname; 5486254Sroot int uid; 5496254Sroot int gid; 55037Sbill } *uap; 55137Sbill 55237Sbill uap = (struct a *)u.u_ap; 55311821Ssam if (!suser() || (ip = owner(0)) == NULL) 55437Sbill return; 55511811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5569167Ssam iput(ip); 5577701Ssam } 5587439Sroot 5599167Ssam /* 5609167Ssam * Set ownership given a file descriptor. 5619167Ssam */ 5627701Ssam fchown() 5637701Ssam { 5647701Ssam struct a { 5657701Ssam int fd; 5667701Ssam int uid; 5677701Ssam int gid; 5687701Ssam } *uap; 5697701Ssam register struct inode *ip; 5707701Ssam register struct file *fp; 5717701Ssam 5727701Ssam uap = (struct a *)u.u_ap; 57312756Ssam fp = getinode(uap->fd); 5747701Ssam if (fp == NULL) 5757701Ssam return; 57612756Ssam ip = (struct inode *)fp->f_data; 57711821Ssam if (!suser()) 5789167Ssam return; 5797701Ssam ilock(ip); 58011811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5819167Ssam iunlock(ip); 5827701Ssam } 5837701Ssam 5847701Ssam /* 5857701Ssam * Perform chown operation on inode ip; 5867701Ssam * inode must be locked prior to call. 5877701Ssam */ 5887701Ssam chown1(ip, uid, gid) 5897701Ssam register struct inode *ip; 5907701Ssam int uid, gid; 5917701Ssam { 5927701Ssam #ifdef QUOTA 5937701Ssam register long change; 59411811Ssam #endif 5957701Ssam 59611811Ssam if (uid == -1) 59711811Ssam uid = ip->i_uid; 59811811Ssam if (gid == -1) 59911811Ssam gid = ip->i_gid; 60011811Ssam #ifdef QUOTA 60112646Ssam if (ip->i_uid != uid) /* this just speeds things a little */ 6027482Skre change = 0; 60312646Ssam else 60412646Ssam change = ip->i_blocks; 60512646Ssam (void) chkdq(ip, -change, 1); 60612646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6077482Skre dqrele(ip->i_dquot); 6087482Skre #endif 60911811Ssam ip->i_uid = uid; 61011811Ssam ip->i_gid = gid; 6116254Sroot ip->i_flag |= ICHG; 6126254Sroot if (u.u_ruid != 0) 6136254Sroot ip->i_mode &= ~(ISUID|ISGID); 6147701Ssam #ifdef QUOTA 6157482Skre ip->i_dquot = inoquota(ip); 61612646Ssam (void) chkdq(ip, change, 1); 61712646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 61812646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 61912646Ssam #else 62012646Ssam return (0); 6217482Skre #endif 62237Sbill } 62337Sbill 62411811Ssam #ifndef NOCOMPAT 62537Sbill /* 6266254Sroot * Set IUPD and IACC times on file. 6276254Sroot * Can't set ICHG. 62837Sbill */ 6298107Sroot outime() 6304828Swnj { 63137Sbill register struct a { 6326254Sroot char *fname; 6336254Sroot time_t *tptr; 63411811Ssam } *uap = (struct a *)u.u_ap; 6356254Sroot register struct inode *ip; 6366254Sroot time_t tv[2]; 6378632Sroot struct timeval tv0, tv1; 63837Sbill 6396254Sroot if ((ip = owner(1)) == NULL) 64037Sbill return; 64111811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 64210001Ssam if (u.u_error == 0) { 6436254Sroot ip->i_flag |= IACC|IUPD|ICHG; 6448632Sroot tv0.tv_sec = tv[0]; tv0.tv_usec = 0; 6458632Sroot tv1.tv_sec = tv[1]; tv1.tv_usec = 0; 6468632Sroot iupdat(ip, &tv0, &tv1, 0); 64737Sbill } 64837Sbill iput(ip); 64937Sbill } 65011811Ssam #endif 65137Sbill 65211811Ssam utimes() 65311811Ssam { 65411811Ssam register struct a { 65511811Ssam char *fname; 65611811Ssam struct timeval *tptr; 65711811Ssam } *uap = (struct a *)u.u_ap; 65811811Ssam register struct inode *ip; 65911811Ssam struct timeval tv[2]; 66011811Ssam 66111811Ssam if ((ip = owner(1)) == NULL) 66211811Ssam return; 66311811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 66411811Ssam if (u.u_error == 0) { 66511811Ssam ip->i_flag |= IACC|IUPD|ICHG; 66611811Ssam iupdat(ip, &tv[0], &tv[1], 0); 66711811Ssam } 66811811Ssam iput(ip); 66911811Ssam } 67011811Ssam 6719167Ssam /* 6729167Ssam * Flush any pending I/O. 6739167Ssam */ 6746254Sroot sync() 67537Sbill { 67637Sbill 6778673Sroot update(); 67837Sbill } 6797535Sroot 6809167Ssam /* 6819167Ssam * Apply an advisory lock on a file descriptor. 6829167Ssam */ 6837701Ssam flock() 6847701Ssam { 68512756Ssam register struct a { 6867701Ssam int fd; 6877701Ssam int how; 68812756Ssam } *uap = (struct a *)u.u_ap; 6897701Ssam register struct file *fp; 6907701Ssam register int cmd, flags; 6917701Ssam 69212756Ssam fp = getinode(uap->fd); 6937701Ssam if (fp == NULL) 6947701Ssam return; 6957701Ssam cmd = uap->how; 6969593Ssam flags = u.u_pofile[uap->fd] & (UF_SHLOCK|UF_EXLOCK); 69712756Ssam if (cmd&LOCK_UN) { 6987701Ssam if (flags == 0) { 6997701Ssam u.u_error = EINVAL; 7007701Ssam return; 7017701Ssam } 70212756Ssam funlocki((struct inode *)fp->f_data, flags); 7039593Ssam u.u_pofile[uap->fd] &= ~(UF_SHLOCK|UF_EXLOCK); 7047701Ssam return; 7057701Ssam } 7067701Ssam /* 7077701Ssam * No reason to write lock a file we've already 7087701Ssam * write locked, similarly with a read lock. 7097701Ssam */ 71012756Ssam if ((flags&UF_EXLOCK) && (cmd&LOCK_EX) || 71112756Ssam (flags&UF_SHLOCK) && (cmd&LOCK_SH)) 7127701Ssam return; 71312756Ssam u.u_pofile[uap->fd] = 71412756Ssam flocki((struct inode *)fp->f_data, u.u_pofile[uap->fd], cmd); 7157701Ssam } 7167701Ssam 7179167Ssam /* 7189167Ssam * Truncate a file given its path name. 7199167Ssam */ 7207701Ssam truncate() 7217701Ssam { 7227701Ssam struct a { 7237701Ssam char *fname; 7249167Ssam u_long length; 7257826Sroot } *uap = (struct a *)u.u_ap; 7267701Ssam struct inode *ip; 7277701Ssam 7289167Ssam ip = namei(uchar, LOOKUP, 1); 7297701Ssam if (ip == NULL) 7307701Ssam return; 7317701Ssam if (access(ip, IWRITE)) 7327701Ssam goto bad; 7337701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7347701Ssam u.u_error = EISDIR; 7357701Ssam goto bad; 7367701Ssam } 7377701Ssam itrunc(ip, uap->length); 7387701Ssam bad: 7397701Ssam iput(ip); 7407701Ssam } 7417701Ssam 7429167Ssam /* 7439167Ssam * Truncate a file given a file descriptor. 7449167Ssam */ 7457701Ssam ftruncate() 7467701Ssam { 7477701Ssam struct a { 7487701Ssam int fd; 7499167Ssam u_long length; 7507826Sroot } *uap = (struct a *)u.u_ap; 7517701Ssam struct inode *ip; 7527701Ssam struct file *fp; 7537701Ssam 75412756Ssam fp = getinode(uap->fd); 7557701Ssam if (fp == NULL) 7567701Ssam return; 7577701Ssam if ((fp->f_flag&FWRITE) == 0) { 7587701Ssam u.u_error = EINVAL; 7597701Ssam return; 7607701Ssam } 76112756Ssam ip = (struct inode *)fp->f_data; 7627701Ssam ilock(ip); 7637701Ssam itrunc(ip, uap->length); 7649167Ssam iunlock(ip); 7657701Ssam } 7667701Ssam 7679167Ssam /* 7689167Ssam * Synch an open file. 7699167Ssam */ 7709167Ssam fsync() 7719167Ssam { 7729167Ssam struct a { 7739167Ssam int fd; 7749167Ssam } *uap = (struct a *)u.u_ap; 7759167Ssam struct inode *ip; 7769167Ssam struct file *fp; 7779167Ssam 77812756Ssam fp = getinode(uap->fd); 7799167Ssam if (fp == NULL) 7809167Ssam return; 78112756Ssam ip = (struct inode *)fp->f_data; 7829167Ssam ilock(ip); 7839167Ssam syncip(ip); 7849167Ssam iunlock(ip); 7859167Ssam } 7869167Ssam 7879167Ssam /* 7889167Ssam * Rename system call. 7899167Ssam * rename("foo", "bar"); 7909167Ssam * is essentially 7919167Ssam * unlink("bar"); 7929167Ssam * link("foo", "bar"); 7939167Ssam * unlink("foo"); 7949167Ssam * but ``atomically''. Can't do full commit without saving state in the 7959167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7969167Ssam * always guarantee the target exists. 7979167Ssam * 7989167Ssam * Basic algorithm is: 7999167Ssam * 8009167Ssam * 1) Bump link count on source while we're linking it to the 8019167Ssam * target. This also insure the inode won't be deleted out 8029167Ssam * from underneath us while we work. 8039167Ssam * 2) Link source to destination. If destination already exists, 8049167Ssam * delete it first. 8059167Ssam * 3) Unlink source reference to inode if still around. 8069167Ssam * 4) If a directory was moved and the parent of the destination 8079167Ssam * is different from the source, patch the ".." entry in the 8089167Ssam * directory. 8099167Ssam * 8109167Ssam * Source and destination must either both be directories, or both 8119167Ssam * not be directories. If target is a directory, it must be empty. 8129167Ssam */ 8137701Ssam rename() 8147701Ssam { 8157701Ssam struct a { 8167701Ssam char *from; 8177701Ssam char *to; 8187701Ssam } *uap; 8199167Ssam register struct inode *ip, *xp, *dp; 8209167Ssam int oldparent, parentdifferent, doingdirectory; 82110051Ssam int error = 0; 8227701Ssam 8239167Ssam uap = (struct a *)u.u_ap; 82411641Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 8259167Ssam if (ip == NULL) 8269167Ssam return; 8279167Ssam dp = u.u_pdir; 8289167Ssam oldparent = 0, doingdirectory = 0; 8299167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 8309167Ssam register struct direct *d; 8319167Ssam 8329167Ssam d = &u.u_dent; 8339167Ssam /* 83411641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 8359167Ssam */ 83611641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 83711641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 83811641Ssam (dp == ip)) { 83911641Ssam iput(dp); 84011641Ssam if (dp == ip) 84111641Ssam irele(ip); 84211641Ssam else 84310051Ssam iput(ip); 84411641Ssam u.u_error = EINVAL; 84511641Ssam return; 8469167Ssam } 8479167Ssam oldparent = dp->i_number; 8489167Ssam doingdirectory++; 8499167Ssam } 85011641Ssam iput(dp); 8519167Ssam 8529167Ssam /* 8539167Ssam * 1) Bump link count while we're moving stuff 8549167Ssam * around. If we crash somewhere before 8559167Ssam * completing our work, the link count 8569167Ssam * may be wrong, but correctable. 8579167Ssam */ 8589167Ssam ip->i_nlink++; 8599167Ssam ip->i_flag |= ICHG; 8609167Ssam iupdat(ip, &time, &time, 1); 8619167Ssam iunlock(ip); 8629167Ssam 8639167Ssam /* 8649167Ssam * When the target exists, both the directory 8659167Ssam * and target inodes are returned locked. 8669167Ssam */ 8679167Ssam u.u_dirp = (caddr_t)uap->to; 8689167Ssam xp = namei(uchar, CREATE | LOCKPARENT, 0); 86910051Ssam if (u.u_error) { 87010051Ssam error = u.u_error; 8719167Ssam goto out; 87210051Ssam } 8739167Ssam dp = u.u_pdir; 8749167Ssam /* 87511641Ssam * If ".." must be changed (ie the directory gets a new 876*12816Smckusick * parent) then the source directory must not be in the 877*12816Smckusick * directory heirarchy above the target, as this would 878*12816Smckusick * orphan everything below the source directory. Also 879*12816Smckusick * the user must have write permission in the source so 880*12816Smckusick * as to be able to change "..". We must repeat the call 881*12816Smckusick * to namei, as the parent directory is unlocked by the 882*12816Smckusick * call to checkpath(). 88311641Ssam */ 88411641Ssam parentdifferent = oldparent != dp->i_number; 885*12816Smckusick if (doingdirectory && parentdifferent) { 886*12816Smckusick if (access(ip, IWRITE)) 887*12816Smckusick goto bad; 888*12816Smckusick do { 889*12816Smckusick dp = u.u_pdir; 890*12816Smckusick if (xp != NULL) 891*12816Smckusick iput(xp); 892*12816Smckusick u.u_error = checkpath(ip, dp); 893*12816Smckusick if (u.u_error) 894*12816Smckusick goto out; 895*12816Smckusick u.u_dirp = (caddr_t)uap->to; 896*12816Smckusick xp = namei(uchar, CREATE | LOCKPARENT, 0); 897*12816Smckusick if (u.u_error) { 898*12816Smckusick error = u.u_error; 899*12816Smckusick goto out; 900*12816Smckusick } 901*12816Smckusick } while (dp != u.u_pdir); 902*12816Smckusick } 90311641Ssam /* 9049167Ssam * 2) If target doesn't exist, link the target 9059167Ssam * to the source and unlink the source. 9069167Ssam * Otherwise, rewrite the target directory 9079167Ssam * entry to reference the source inode and 9089167Ssam * expunge the original entry's existence. 9099167Ssam */ 9109167Ssam if (xp == NULL) { 9119167Ssam if (dp->i_dev != ip->i_dev) { 91210051Ssam error = EXDEV; 9139167Ssam goto bad; 9149167Ssam } 9159167Ssam /* 9169167Ssam * Account for ".." in directory. 9179167Ssam * When source and destination have the 9189167Ssam * same parent we don't fool with the 9199167Ssam * link count -- this isn't required 9209167Ssam * because we do a similar check below. 9219167Ssam */ 9229167Ssam if (doingdirectory && parentdifferent) { 9239167Ssam dp->i_nlink++; 9249167Ssam dp->i_flag |= ICHG; 9259167Ssam iupdat(dp, &time, &time, 1); 9269167Ssam } 92710850Ssam error = direnter(ip); 92810850Ssam if (error) 9299167Ssam goto out; 9309167Ssam } else { 9319167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 93210051Ssam error = EXDEV; 9339167Ssam goto bad; 9349167Ssam } 9359167Ssam /* 93610590Ssam * Short circuit rename(foo, foo). 93710590Ssam */ 93810590Ssam if (xp->i_number == ip->i_number) 93910590Ssam goto bad; 94010590Ssam /* 94110051Ssam * Target must be empty if a directory 94210051Ssam * and have no links to it. 9439167Ssam * Also, insure source and target are 9449167Ssam * compatible (both directories, or both 9459167Ssam * not directories). 9469167Ssam */ 9479167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 94810051Ssam if (!dirempty(xp) || xp->i_nlink > 2) { 94910051Ssam error = ENOTEMPTY; 9509167Ssam goto bad; 9519167Ssam } 9529167Ssam if (!doingdirectory) { 95310051Ssam error = ENOTDIR; 9549167Ssam goto bad; 9559167Ssam } 9569167Ssam } else if (doingdirectory) { 95710051Ssam error = EISDIR; 9589167Ssam goto bad; 9599167Ssam } 9609167Ssam dirrewrite(dp, ip); 96110051Ssam if (u.u_error) { 96210051Ssam error = u.u_error; 9639167Ssam goto bad1; 96410051Ssam } 9659167Ssam /* 96610051Ssam * Adjust the link count of the target to 96710051Ssam * reflect the dirrewrite above. If this is 96810051Ssam * a directory it is empty and there are 96910051Ssam * no links to it, so we can squash the inode and 97010051Ssam * any space associated with it. We disallowed 97110051Ssam * renaming over top of a directory with links to 97210051Ssam * it above, as we've no way to determine if 97310051Ssam * we've got a link or the directory itself, and 97410051Ssam * if we get a link, then ".." will be screwed up. 9759167Ssam */ 97610051Ssam xp->i_nlink--; 9779167Ssam if (doingdirectory) { 97810051Ssam if (--xp->i_nlink != 0) 97910051Ssam panic("rename: linked directory"); 9809167Ssam itrunc(xp, (u_long)0); 98110051Ssam } 9829167Ssam xp->i_flag |= ICHG; 9839167Ssam iput(xp); 98410246Ssam xp = NULL; 9859167Ssam } 9869167Ssam 9879167Ssam /* 9889167Ssam * 3) Unlink the source. 9899167Ssam */ 9909167Ssam u.u_dirp = uap->from; 9919167Ssam dp = namei(uchar, DELETE, 0); 9929167Ssam /* 9939167Ssam * Insure directory entry still exists and 9949167Ssam * has not changed since the start of all 9959167Ssam * this. If either has occured, forget about 9969167Ssam * about deleting the original entry and just 9979167Ssam * adjust the link count in the inode. 9989167Ssam */ 9999167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 10009167Ssam ip->i_nlink--; 10019167Ssam ip->i_flag |= ICHG; 10029167Ssam } else { 10039167Ssam /* 10049167Ssam * If source is a directory, must adjust 10059167Ssam * link count of parent directory also. 10069167Ssam * If target didn't exist and source and 10079167Ssam * target have the same parent, then we 10089167Ssam * needn't touch the link count, it all 10099167Ssam * balances out in the end. Otherwise, we 10109167Ssam * must do so to reflect deletion of ".." 10119167Ssam * done above. 10129167Ssam */ 10139167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 10149167Ssam dp->i_nlink--; 10159167Ssam dp->i_flag |= ICHG; 10169167Ssam } 10179167Ssam if (dirremove()) { 10189167Ssam ip->i_nlink--; 10199167Ssam ip->i_flag |= ICHG; 10209167Ssam } 102110051Ssam if (error == 0) /* conservative */ 102210051Ssam error = u.u_error; 10239167Ssam } 10249167Ssam irele(ip); 10259167Ssam if (dp) 10269167Ssam iput(dp); 10279167Ssam 10289167Ssam /* 10299167Ssam * 4) Renaming a directory with the parent 10309167Ssam * different requires ".." to be rewritten. 10319167Ssam * The window is still there for ".." to 10329167Ssam * be inconsistent, but this is unavoidable, 10339167Ssam * and a lot shorter than when it was done 10349167Ssam * in a user process. 10359167Ssam */ 103610051Ssam if (doingdirectory && parentdifferent && error == 0) { 10379167Ssam struct dirtemplate dirbuf; 10389167Ssam 10399167Ssam u.u_dirp = uap->to; 10409167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 10419167Ssam if (ip == NULL) { 10429167Ssam printf("rename: .. went away\n"); 10439167Ssam return; 10449167Ssam } 10459167Ssam dp = u.u_pdir; 10469167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 10479167Ssam printf("rename: .. not a directory\n"); 10489167Ssam goto stuck; 10499167Ssam } 105010051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 10519167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 105210051Ssam if (error == 0) { 10539167Ssam dirbuf.dotdot_ino = dp->i_number; 10549167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10559167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10569167Ssam } 10579167Ssam stuck: 10589167Ssam irele(dp); 10599167Ssam iput(ip); 10609167Ssam } 106110051Ssam goto done; 106210051Ssam 10639167Ssam bad: 106410246Ssam iput(dp); 10659167Ssam bad1: 10669167Ssam if (xp) 106710246Ssam iput(xp); 10689167Ssam out: 10699167Ssam ip->i_nlink--; 10709167Ssam ip->i_flag |= ICHG; 10719167Ssam irele(ip); 107210051Ssam done: 107310051Ssam if (error) 107410051Ssam u.u_error = error; 10757701Ssam } 10767701Ssam 10777535Sroot /* 10787535Sroot * Make a new file. 10797535Sroot */ 10807535Sroot struct inode * 10817535Sroot maknode(mode) 10827535Sroot int mode; 10837535Sroot { 10847535Sroot register struct inode *ip; 10857535Sroot ino_t ipref; 10867535Sroot 10877535Sroot if ((mode & IFMT) == IFDIR) 10887535Sroot ipref = dirpref(u.u_pdir->i_fs); 10897535Sroot else 10907535Sroot ipref = u.u_pdir->i_number; 10917535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10927535Sroot if (ip == NULL) { 10937535Sroot iput(u.u_pdir); 10947701Ssam return (NULL); 10957535Sroot } 10967701Ssam #ifdef QUOTA 10977535Sroot if (ip->i_dquot != NODQUOT) 10987535Sroot panic("maknode: dquot"); 10997535Sroot #endif 11007535Sroot ip->i_flag |= IACC|IUPD|ICHG; 11017535Sroot if ((mode & IFMT) == 0) 11027535Sroot mode |= IFREG; 11037535Sroot ip->i_mode = mode & ~u.u_cmask; 11047535Sroot ip->i_nlink = 1; 11057535Sroot ip->i_uid = u.u_uid; 11067535Sroot ip->i_gid = u.u_pdir->i_gid; 110711811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 110811811Ssam ip->i_mode &= ~ISGID; 11097701Ssam #ifdef QUOTA 11107535Sroot ip->i_dquot = inoquota(ip); 11117535Sroot #endif 11127535Sroot 11137535Sroot /* 11147535Sroot * Make sure inode goes to disk before directory entry. 11157535Sroot */ 11168673Sroot iupdat(ip, &time, &time, 1); 111710850Ssam u.u_error = direnter(ip); 11187535Sroot if (u.u_error) { 11197535Sroot /* 112010850Ssam * Write error occurred trying to update directory 112110850Ssam * so must deallocate the inode. 11227535Sroot */ 11237535Sroot ip->i_nlink = 0; 11247535Sroot ip->i_flag |= ICHG; 11257535Sroot iput(ip); 11267701Ssam return (NULL); 11277535Sroot } 11287701Ssam return (ip); 11297535Sroot } 113012756Ssam 113112756Ssam /* 113212756Ssam * A virgin directory (no blushing please). 113312756Ssam */ 113412756Ssam struct dirtemplate mastertemplate = { 113512756Ssam 0, 12, 1, ".", 113612756Ssam 0, DIRBLKSIZ - 12, 2, ".." 113712756Ssam }; 113812756Ssam 113912756Ssam /* 114012756Ssam * Mkdir system call 114112756Ssam */ 114212756Ssam mkdir() 114312756Ssam { 114412756Ssam struct a { 114512756Ssam char *name; 114612756Ssam int dmode; 114712756Ssam } *uap; 114812756Ssam register struct inode *ip, *dp; 114912756Ssam struct dirtemplate dirtemplate; 115012756Ssam 115112756Ssam uap = (struct a *)u.u_ap; 115212756Ssam ip = namei(uchar, CREATE, 0); 115312756Ssam if (u.u_error) 115412756Ssam return; 115512756Ssam if (ip != NULL) { 115612756Ssam iput(ip); 115712756Ssam u.u_error = EEXIST; 115812756Ssam return; 115912756Ssam } 116012756Ssam dp = u.u_pdir; 116112756Ssam uap->dmode &= 0777; 116212756Ssam uap->dmode |= IFDIR; 116312756Ssam /* 116412756Ssam * Must simulate part of maknode here 116512756Ssam * in order to acquire the inode, but 116612756Ssam * not have it entered in the parent 116712756Ssam * directory. The entry is made later 116812756Ssam * after writing "." and ".." entries out. 116912756Ssam */ 117012756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 117112756Ssam if (ip == NULL) { 117212756Ssam iput(dp); 117312756Ssam return; 117412756Ssam } 117512756Ssam #ifdef QUOTA 117612756Ssam if (ip->i_dquot != NODQUOT) 117712756Ssam panic("mkdir: dquot"); 117812756Ssam #endif 117912756Ssam ip->i_flag |= IACC|IUPD|ICHG; 118012756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 118112756Ssam ip->i_nlink = 2; 118212756Ssam ip->i_uid = u.u_uid; 118312756Ssam ip->i_gid = dp->i_gid; 118412756Ssam #ifdef QUOTA 118512756Ssam ip->i_dquot = inoquota(ip); 118612756Ssam #endif 118712756Ssam iupdat(ip, &time, &time, 1); 118812756Ssam 118912756Ssam /* 119012756Ssam * Bump link count in parent directory 119112756Ssam * to reflect work done below. Should 119212756Ssam * be done before reference is created 119312756Ssam * so reparation is possible if we crash. 119412756Ssam */ 119512756Ssam dp->i_nlink++; 119612756Ssam dp->i_flag |= ICHG; 119712756Ssam iupdat(dp, &time, &time, 1); 119812756Ssam 119912756Ssam /* 120012756Ssam * Initialize directory with "." 120112756Ssam * and ".." from static template. 120212756Ssam */ 120312756Ssam dirtemplate = mastertemplate; 120412756Ssam dirtemplate.dot_ino = ip->i_number; 120512756Ssam dirtemplate.dotdot_ino = dp->i_number; 120612756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 120712756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 120812756Ssam if (u.u_error) { 120912756Ssam dp->i_nlink--; 121012756Ssam dp->i_flag |= ICHG; 121112756Ssam goto bad; 121212756Ssam } 121312756Ssam /* 121412756Ssam * Directory all set up, now 121512756Ssam * install the entry for it in 121612756Ssam * the parent directory. 121712756Ssam */ 121812756Ssam u.u_error = direnter(ip); 121912756Ssam dp = NULL; 122012756Ssam if (u.u_error) { 122112756Ssam u.u_dirp = uap->name; 122212756Ssam dp = namei(uchar, LOOKUP, 0); 122312756Ssam if (dp) { 122412756Ssam dp->i_nlink--; 122512756Ssam dp->i_flag |= ICHG; 122612756Ssam } 122712756Ssam } 122812756Ssam bad: 122912756Ssam /* 123012756Ssam * No need to do an explicit itrunc here, 123112756Ssam * irele will do this for us because we set 123212756Ssam * the link count to 0. 123312756Ssam */ 123412756Ssam if (u.u_error) { 123512756Ssam ip->i_nlink = 0; 123612756Ssam ip->i_flag |= ICHG; 123712756Ssam } 123812756Ssam if (dp) 123912756Ssam iput(dp); 124012756Ssam iput(ip); 124112756Ssam } 124212756Ssam 124312756Ssam /* 124412756Ssam * Rmdir system call. 124512756Ssam */ 124612756Ssam rmdir() 124712756Ssam { 124812756Ssam struct a { 124912756Ssam char *name; 125012756Ssam }; 125112756Ssam register struct inode *ip, *dp; 125212756Ssam 125312756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 125412756Ssam if (ip == NULL) 125512756Ssam return; 125612756Ssam dp = u.u_pdir; 125712756Ssam /* 125812756Ssam * No rmdir "." please. 125912756Ssam */ 126012756Ssam if (dp == ip) { 126112756Ssam irele(dp); 126212756Ssam iput(ip); 126312756Ssam u.u_error = EINVAL; 126412756Ssam return; 126512756Ssam } 126612756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 126712756Ssam u.u_error = ENOTDIR; 126812756Ssam goto out; 126912756Ssam } 127012756Ssam /* 127112756Ssam * Don't remove a mounted on directory. 127212756Ssam */ 127312756Ssam if (ip->i_dev != dp->i_dev) { 127412756Ssam u.u_error = EBUSY; 127512756Ssam goto out; 127612756Ssam } 127712756Ssam /* 127812756Ssam * Verify the directory is empty (and valid). 127912756Ssam * (Rmdir ".." won't be valid since 128012756Ssam * ".." will contain a reference to 128112756Ssam * the current directory and thus be 128212756Ssam * non-empty.) 128312756Ssam */ 128412756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 128512756Ssam u.u_error = ENOTEMPTY; 128612756Ssam goto out; 128712756Ssam } 128812756Ssam /* 128912756Ssam * Delete reference to directory before purging 129012756Ssam * inode. If we crash in between, the directory 129112756Ssam * will be reattached to lost+found, 129212756Ssam */ 129312756Ssam if (dirremove() == 0) 129412756Ssam goto out; 129512756Ssam dp->i_nlink--; 129612756Ssam dp->i_flag |= ICHG; 129712756Ssam iput(dp); 129812756Ssam dp = NULL; 129912756Ssam /* 130012756Ssam * Truncate inode. The only stuff left 130112756Ssam * in the directory is "." and "..". The 130212756Ssam * "." reference is inconsequential since 130312756Ssam * we're quashing it. The ".." reference 130412756Ssam * has already been adjusted above. We've 130512756Ssam * removed the "." reference and the reference 130612756Ssam * in the parent directory, but there may be 130712756Ssam * other hard links so decrement by 2 and 130812756Ssam * worry about them later. 130912756Ssam */ 131012756Ssam ip->i_nlink -= 2; 131112756Ssam itrunc(ip, (u_long)0); 131212756Ssam out: 131312756Ssam if (dp) 131412756Ssam iput(dp); 131512756Ssam iput(ip); 131612756Ssam } 131712756Ssam 131812756Ssam struct file * 131912756Ssam getinode(fdes) 132012756Ssam int fdes; 132112756Ssam { 132212756Ssam register struct file *fp; 132312756Ssam 132412756Ssam fp = getf(fdes); 132512756Ssam if (fp == 0) 132612756Ssam return (0); 132712756Ssam if (fp->f_type != DTYPE_INODE) { 132812756Ssam u.u_error = EINVAL; 132912756Ssam return (0); 133012756Ssam } 133112756Ssam return (fp); 133212756Ssam } 133312756Ssam 133412756Ssam /* 133512756Ssam * mode mask for creation of files 133612756Ssam */ 133712756Ssam umask() 133812756Ssam { 133912756Ssam register struct a { 134012756Ssam int mask; 134112756Ssam } *uap; 134212756Ssam 134312756Ssam uap = (struct a *)u.u_ap; 134412756Ssam u.u_r.r_val1 = u.u_cmask; 134512756Ssam u.u_cmask = uap->mask & 07777; 134612756Ssam } 1347