1*12756Ssam /* lfs_vnops.c 4.57 83/05/27 */ 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" 19*12756Ssam #include "../h/mount.h" 2037Sbill 21*12756Ssam extern struct fileops inodeops; 22*12756Ssam struct file *getinode(); 23*12756Ssam 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 { 78*12756Ssam struct a { 796254Sroot char *fname; 807701Ssam int mode; 81*12756Ssam int crtmode; 82*12756Ssam } *uap = (struct a *) u.u_ap; 836254Sroot 84*12756Ssam copen(uap->mode-FOPEN, uap->crtmode); 856254Sroot } 866254Sroot 876254Sroot /* 886254Sroot * Creat system call. 896254Sroot */ 90*12756Ssam creat() 916254Sroot { 92*12756Ssam struct a { 936254Sroot char *fname; 946254Sroot int fmode; 95*12756Ssam } *uap = (struct a *)u.u_ap; 966254Sroot 97*12756Ssam copen(FWRITE|FCREAT|FTRUNC, uap->fmode); 986254Sroot } 996254Sroot 1006254Sroot /* 1016254Sroot * Common code for open and creat. 102*12756Ssam * Check permissions, allocate an open file structure, 103*12756Ssam * and call the device open routine if any. 1046254Sroot */ 105*12756Ssam copen(mode, arg) 106*12756Ssam register int mode; 107*12756Ssam int arg; 108*12756Ssam { 1096254Sroot register struct inode *ip; 1106254Sroot register struct file *fp; 111*12756Ssam int i; 1126254Sroot 113*12756Ssam #ifdef notdef 114*12756Ssam if ((mode&(FREAD|FWRITE)) == 0) { 115*12756Ssam u.u_error = EINVAL; 116*12756Ssam return; 117*12756Ssam } 118*12756Ssam #endif 119*12756Ssam if (mode&FCREAT) { 120*12756Ssam ip = namei(uchar, CREATE, 1); 121*12756Ssam if (ip == NULL) { 122*12756Ssam if (u.u_error) 123*12756Ssam return; 124*12756Ssam ip = maknode(arg&07777&(~ISVTX)); 125*12756Ssam if (ip == NULL) 126*12756Ssam return; 127*12756Ssam mode &= ~FTRUNC; 128*12756Ssam } else { 129*12756Ssam if (mode&FEXCL) { 130*12756Ssam u.u_error = EEXIST; 131*12756Ssam iput(ip); 132*12756Ssam return; 133*12756Ssam } 134*12756Ssam mode &= ~FCREAT; 135*12756Ssam } 136*12756Ssam } else { 137*12756Ssam ip = namei(uchar, LOOKUP, 1); 138*12756Ssam if (ip == NULL) 139*12756Ssam return; 140*12756Ssam } 141*12756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 142*12756Ssam u.u_error = EOPNOTSUPP; 143*12756Ssam goto bad; 144*12756Ssam } 145*12756Ssam 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 } 158*12756Ssam fp = falloc(); 159*12756Ssam if (fp == NULL) 160*12756Ssam goto bad; 161*12756Ssam if (mode&FTRUNC) 1629167Ssam itrunc(ip, (u_long)0); 1637122Smckusick iunlock(ip); 164*12756Ssam fp->f_flag = mode&FMASK; 165*12756Ssam fp->f_type = DTYPE_INODE; 166*12756Ssam fp->f_ops = &inodeops; 167*12756Ssam fp->f_data = (caddr_t)ip; 1686254Sroot i = u.u_r.r_val1; 169*12756Ssam #ifdef notdef 170*12756Ssam if (setjmp(&u.u_qsave)) { 171*12756Ssam if (u.u_error == 0) 172*12756Ssam u.u_error = EINTR; 173*12756Ssam u.u_ofile[i] = NULL; 174*12756Ssam closef(fp); 175*12756Ssam return; 176*12756Ssam } 177*12756Ssam #endif 1788559Sroot u.u_error = openi(ip, mode); 179*12756Ssam 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; 202*12756Ssam if (!suser()) 203*12756Ssam return; 204*12756Ssam ip = namei(uchar, CREATE, 0); 205*12756Ssam if (ip != NULL) { 206*12756Ssam u.u_error = EEXIST; 207*12756Ssam goto out; 2086254Sroot } 2096254Sroot if (u.u_error) 2106254Sroot return; 2116254Sroot ip = maknode(uap->fmode); 2126254Sroot if (ip == NULL) 2136254Sroot return; 214*12756Ssam switch (ip->i_mode & IFMT) { 215*12756Ssam 216*12756Ssam case IFCHR: 217*12756Ssam case IFBLK: 218*12756Ssam if (uap->dev) { 219*12756Ssam /* 220*12756Ssam * Want to be able to use this to make badblock 221*12756Ssam * inodes, so don't truncate the dev number. 222*12756Ssam */ 223*12756Ssam ip->i_rdev = uap->dev; 224*12756Ssam ip->i_flag |= IACC|IUPD|ICHG; 225*12756Ssam } 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; 371*12756Ssam fp = getinode(uap->fd); 3726254Sroot if (fp == NULL) 3736254Sroot return; 374*12756Ssam if (uap->sbase == L_INCR) 3756254Sroot uap->off += fp->f_offset; 376*12756Ssam else if (uap->sbase == L_XTND) 377*12756Ssam 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) { 401*12756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4027701Ssam goto done; 403*12756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4047701Ssam goto done; 405*12756Ssam 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 420*12756Ssam stat1(1); 42137Sbill } 42237Sbill 42337Sbill /* 4246574Smckusic * Lstat system call. This version does not follow links. 4255992Swnj */ 4265992Swnj lstat() 4275992Swnj { 428*12756Ssam 429*12756Ssam stat1(0); 430*12756Ssam } 431*12756Ssam 432*12756Ssam stat1(follow) 433*12756Ssam int follow; 434*12756Ssam { 4355992Swnj register struct inode *ip; 4365992Swnj register struct a { 4375992Swnj char *fname; 438*12756Ssam struct stat *ub; 4395992Swnj } *uap; 440*12756Ssam struct stat sb; 4415992Swnj 4425992Swnj uap = (struct a *)u.u_ap; 443*12756Ssam ip = namei(uchar, LOOKUP, follow); 4445992Swnj if (ip == NULL) 4455992Swnj return; 446*12756Ssam (void) statinode(ip, &sb); 4475992Swnj iput(ip); 448*12756Ssam 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; 508*12756Ssam fp = getinode(uap->fd); 5097701Ssam if (fp == NULL) 5107701Ssam return; 511*12756Ssam 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; 573*12756Ssam fp = getinode(uap->fd); 5747701Ssam if (fp == NULL) 5757701Ssam return; 576*12756Ssam 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 { 685*12756Ssam register struct a { 6867701Ssam int fd; 6877701Ssam int how; 688*12756Ssam } *uap = (struct a *)u.u_ap; 6897701Ssam register struct file *fp; 6907701Ssam register int cmd, flags; 6917701Ssam 692*12756Ssam 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); 697*12756Ssam if (cmd&LOCK_UN) { 6987701Ssam if (flags == 0) { 6997701Ssam u.u_error = EINVAL; 7007701Ssam return; 7017701Ssam } 702*12756Ssam 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 */ 710*12756Ssam if ((flags&UF_EXLOCK) && (cmd&LOCK_EX) || 711*12756Ssam (flags&UF_SHLOCK) && (cmd&LOCK_SH)) 7127701Ssam return; 713*12756Ssam u.u_pofile[uap->fd] = 714*12756Ssam 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 754*12756Ssam 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 } 761*12756Ssam 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 778*12756Ssam fp = getinode(uap->fd); 7799167Ssam if (fp == NULL) 7809167Ssam return; 781*12756Ssam 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 87611641Ssam * parent) then the user must have write permission. 87711641Ssam */ 87811641Ssam parentdifferent = oldparent != dp->i_number; 87911643Ssam if (doingdirectory && parentdifferent && access(ip, IWRITE)) 88011641Ssam goto bad; 88111641Ssam /* 8829167Ssam * 2) If target doesn't exist, link the target 8839167Ssam * to the source and unlink the source. 8849167Ssam * Otherwise, rewrite the target directory 8859167Ssam * entry to reference the source inode and 8869167Ssam * expunge the original entry's existence. 8879167Ssam */ 8889167Ssam if (xp == NULL) { 8899167Ssam if (dp->i_dev != ip->i_dev) { 89010051Ssam error = EXDEV; 8919167Ssam goto bad; 8929167Ssam } 8939167Ssam /* 89410590Ssam * Disallow rename(foo, foo/bar). 89510590Ssam */ 89610590Ssam if (dp->i_number == ip->i_number) { 89710590Ssam error = EEXIST; 89810590Ssam goto bad; 89910590Ssam } 90010590Ssam /* 9019167Ssam * Account for ".." in directory. 9029167Ssam * When source and destination have the 9039167Ssam * same parent we don't fool with the 9049167Ssam * link count -- this isn't required 9059167Ssam * because we do a similar check below. 9069167Ssam */ 9079167Ssam if (doingdirectory && parentdifferent) { 9089167Ssam dp->i_nlink++; 9099167Ssam dp->i_flag |= ICHG; 9109167Ssam iupdat(dp, &time, &time, 1); 9119167Ssam } 91210850Ssam error = direnter(ip); 91310850Ssam if (error) 9149167Ssam goto out; 9159167Ssam } else { 9169167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 91710051Ssam error = EXDEV; 9189167Ssam goto bad; 9199167Ssam } 9209167Ssam /* 92110590Ssam * Short circuit rename(foo, foo). 92210590Ssam */ 92310590Ssam if (xp->i_number == ip->i_number) 92410590Ssam goto bad; 92510590Ssam /* 92610051Ssam * Target must be empty if a directory 92710051Ssam * and have no links to it. 9289167Ssam * Also, insure source and target are 9299167Ssam * compatible (both directories, or both 9309167Ssam * not directories). 9319167Ssam */ 9329167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 93310051Ssam if (!dirempty(xp) || xp->i_nlink > 2) { 93410051Ssam error = ENOTEMPTY; 9359167Ssam goto bad; 9369167Ssam } 9379167Ssam if (!doingdirectory) { 93810051Ssam error = ENOTDIR; 9399167Ssam goto bad; 9409167Ssam } 9419167Ssam } else if (doingdirectory) { 94210051Ssam error = EISDIR; 9439167Ssam goto bad; 9449167Ssam } 9459167Ssam dirrewrite(dp, ip); 94610051Ssam if (u.u_error) { 94710051Ssam error = u.u_error; 9489167Ssam goto bad1; 94910051Ssam } 9509167Ssam /* 95110051Ssam * Adjust the link count of the target to 95210051Ssam * reflect the dirrewrite above. If this is 95310051Ssam * a directory it is empty and there are 95410051Ssam * no links to it, so we can squash the inode and 95510051Ssam * any space associated with it. We disallowed 95610051Ssam * renaming over top of a directory with links to 95710051Ssam * it above, as we've no way to determine if 95810051Ssam * we've got a link or the directory itself, and 95910051Ssam * if we get a link, then ".." will be screwed up. 9609167Ssam */ 96110051Ssam xp->i_nlink--; 9629167Ssam if (doingdirectory) { 96310051Ssam if (--xp->i_nlink != 0) 96410051Ssam panic("rename: linked directory"); 9659167Ssam itrunc(xp, (u_long)0); 96610051Ssam } 9679167Ssam xp->i_flag |= ICHG; 9689167Ssam iput(xp); 96910246Ssam xp = NULL; 9709167Ssam } 9719167Ssam 9729167Ssam /* 9739167Ssam * 3) Unlink the source. 9749167Ssam */ 9759167Ssam u.u_dirp = uap->from; 9769167Ssam dp = namei(uchar, DELETE, 0); 9779167Ssam /* 9789167Ssam * Insure directory entry still exists and 9799167Ssam * has not changed since the start of all 9809167Ssam * this. If either has occured, forget about 9819167Ssam * about deleting the original entry and just 9829167Ssam * adjust the link count in the inode. 9839167Ssam */ 9849167Ssam if (dp == NULL || u.u_dent.d_ino != ip->i_number) { 9859167Ssam ip->i_nlink--; 9869167Ssam ip->i_flag |= ICHG; 9879167Ssam } else { 9889167Ssam /* 9899167Ssam * If source is a directory, must adjust 9909167Ssam * link count of parent directory also. 9919167Ssam * If target didn't exist and source and 9929167Ssam * target have the same parent, then we 9939167Ssam * needn't touch the link count, it all 9949167Ssam * balances out in the end. Otherwise, we 9959167Ssam * must do so to reflect deletion of ".." 9969167Ssam * done above. 9979167Ssam */ 9989167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9999167Ssam dp->i_nlink--; 10009167Ssam dp->i_flag |= ICHG; 10019167Ssam } 10029167Ssam if (dirremove()) { 10039167Ssam ip->i_nlink--; 10049167Ssam ip->i_flag |= ICHG; 10059167Ssam } 100610051Ssam if (error == 0) /* conservative */ 100710051Ssam error = u.u_error; 10089167Ssam } 10099167Ssam irele(ip); 10109167Ssam if (dp) 10119167Ssam iput(dp); 10129167Ssam 10139167Ssam /* 10149167Ssam * 4) Renaming a directory with the parent 10159167Ssam * different requires ".." to be rewritten. 10169167Ssam * The window is still there for ".." to 10179167Ssam * be inconsistent, but this is unavoidable, 10189167Ssam * and a lot shorter than when it was done 10199167Ssam * in a user process. 10209167Ssam */ 102110051Ssam if (doingdirectory && parentdifferent && error == 0) { 10229167Ssam struct dirtemplate dirbuf; 10239167Ssam 10249167Ssam u.u_dirp = uap->to; 10259167Ssam ip = namei(uchar, LOOKUP | LOCKPARENT, 0); 10269167Ssam if (ip == NULL) { 10279167Ssam printf("rename: .. went away\n"); 10289167Ssam return; 10299167Ssam } 10309167Ssam dp = u.u_pdir; 10319167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 10329167Ssam printf("rename: .. not a directory\n"); 10339167Ssam goto stuck; 10349167Ssam } 103510051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 10369167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 103710051Ssam if (error == 0) { 10389167Ssam dirbuf.dotdot_ino = dp->i_number; 10399167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10409167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10419167Ssam } 10429167Ssam stuck: 10439167Ssam irele(dp); 10449167Ssam iput(ip); 10459167Ssam } 104610051Ssam goto done; 104710051Ssam 10489167Ssam bad: 104910246Ssam iput(dp); 10509167Ssam bad1: 10519167Ssam if (xp) 105210246Ssam iput(xp); 10539167Ssam out: 10549167Ssam ip->i_nlink--; 10559167Ssam ip->i_flag |= ICHG; 10569167Ssam irele(ip); 105710051Ssam done: 105810051Ssam if (error) 105910051Ssam u.u_error = error; 10607701Ssam } 10617701Ssam 10627535Sroot /* 10637535Sroot * Make a new file. 10647535Sroot */ 10657535Sroot struct inode * 10667535Sroot maknode(mode) 10677535Sroot int mode; 10687535Sroot { 10697535Sroot register struct inode *ip; 10707535Sroot ino_t ipref; 10717535Sroot 10727535Sroot if ((mode & IFMT) == IFDIR) 10737535Sroot ipref = dirpref(u.u_pdir->i_fs); 10747535Sroot else 10757535Sroot ipref = u.u_pdir->i_number; 10767535Sroot ip = ialloc(u.u_pdir, ipref, mode); 10777535Sroot if (ip == NULL) { 10787535Sroot iput(u.u_pdir); 10797701Ssam return (NULL); 10807535Sroot } 10817701Ssam #ifdef QUOTA 10827535Sroot if (ip->i_dquot != NODQUOT) 10837535Sroot panic("maknode: dquot"); 10847535Sroot #endif 10857535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10867535Sroot if ((mode & IFMT) == 0) 10877535Sroot mode |= IFREG; 10887535Sroot ip->i_mode = mode & ~u.u_cmask; 10897535Sroot ip->i_nlink = 1; 10907535Sroot ip->i_uid = u.u_uid; 10917535Sroot ip->i_gid = u.u_pdir->i_gid; 109211811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 109311811Ssam ip->i_mode &= ~ISGID; 10947701Ssam #ifdef QUOTA 10957535Sroot ip->i_dquot = inoquota(ip); 10967535Sroot #endif 10977535Sroot 10987535Sroot /* 10997535Sroot * Make sure inode goes to disk before directory entry. 11007535Sroot */ 11018673Sroot iupdat(ip, &time, &time, 1); 110210850Ssam u.u_error = direnter(ip); 11037535Sroot if (u.u_error) { 11047535Sroot /* 110510850Ssam * Write error occurred trying to update directory 110610850Ssam * so must deallocate the inode. 11077535Sroot */ 11087535Sroot ip->i_nlink = 0; 11097535Sroot ip->i_flag |= ICHG; 11107535Sroot iput(ip); 11117701Ssam return (NULL); 11127535Sroot } 11137701Ssam return (ip); 11147535Sroot } 1115*12756Ssam 1116*12756Ssam /* 1117*12756Ssam * A virgin directory (no blushing please). 1118*12756Ssam */ 1119*12756Ssam struct dirtemplate mastertemplate = { 1120*12756Ssam 0, 12, 1, ".", 1121*12756Ssam 0, DIRBLKSIZ - 12, 2, ".." 1122*12756Ssam }; 1123*12756Ssam 1124*12756Ssam /* 1125*12756Ssam * Mkdir system call 1126*12756Ssam */ 1127*12756Ssam mkdir() 1128*12756Ssam { 1129*12756Ssam struct a { 1130*12756Ssam char *name; 1131*12756Ssam int dmode; 1132*12756Ssam } *uap; 1133*12756Ssam register struct inode *ip, *dp; 1134*12756Ssam struct dirtemplate dirtemplate; 1135*12756Ssam 1136*12756Ssam uap = (struct a *)u.u_ap; 1137*12756Ssam ip = namei(uchar, CREATE, 0); 1138*12756Ssam if (u.u_error) 1139*12756Ssam return; 1140*12756Ssam if (ip != NULL) { 1141*12756Ssam iput(ip); 1142*12756Ssam u.u_error = EEXIST; 1143*12756Ssam return; 1144*12756Ssam } 1145*12756Ssam dp = u.u_pdir; 1146*12756Ssam uap->dmode &= 0777; 1147*12756Ssam uap->dmode |= IFDIR; 1148*12756Ssam /* 1149*12756Ssam * Must simulate part of maknode here 1150*12756Ssam * in order to acquire the inode, but 1151*12756Ssam * not have it entered in the parent 1152*12756Ssam * directory. The entry is made later 1153*12756Ssam * after writing "." and ".." entries out. 1154*12756Ssam */ 1155*12756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 1156*12756Ssam if (ip == NULL) { 1157*12756Ssam iput(dp); 1158*12756Ssam return; 1159*12756Ssam } 1160*12756Ssam #ifdef QUOTA 1161*12756Ssam if (ip->i_dquot != NODQUOT) 1162*12756Ssam panic("mkdir: dquot"); 1163*12756Ssam #endif 1164*12756Ssam ip->i_flag |= IACC|IUPD|ICHG; 1165*12756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 1166*12756Ssam ip->i_nlink = 2; 1167*12756Ssam ip->i_uid = u.u_uid; 1168*12756Ssam ip->i_gid = dp->i_gid; 1169*12756Ssam #ifdef QUOTA 1170*12756Ssam ip->i_dquot = inoquota(ip); 1171*12756Ssam #endif 1172*12756Ssam iupdat(ip, &time, &time, 1); 1173*12756Ssam 1174*12756Ssam /* 1175*12756Ssam * Bump link count in parent directory 1176*12756Ssam * to reflect work done below. Should 1177*12756Ssam * be done before reference is created 1178*12756Ssam * so reparation is possible if we crash. 1179*12756Ssam */ 1180*12756Ssam dp->i_nlink++; 1181*12756Ssam dp->i_flag |= ICHG; 1182*12756Ssam iupdat(dp, &time, &time, 1); 1183*12756Ssam 1184*12756Ssam /* 1185*12756Ssam * Initialize directory with "." 1186*12756Ssam * and ".." from static template. 1187*12756Ssam */ 1188*12756Ssam dirtemplate = mastertemplate; 1189*12756Ssam dirtemplate.dot_ino = ip->i_number; 1190*12756Ssam dirtemplate.dotdot_ino = dp->i_number; 1191*12756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 1192*12756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 1193*12756Ssam if (u.u_error) { 1194*12756Ssam dp->i_nlink--; 1195*12756Ssam dp->i_flag |= ICHG; 1196*12756Ssam goto bad; 1197*12756Ssam } 1198*12756Ssam /* 1199*12756Ssam * Directory all set up, now 1200*12756Ssam * install the entry for it in 1201*12756Ssam * the parent directory. 1202*12756Ssam */ 1203*12756Ssam u.u_error = direnter(ip); 1204*12756Ssam dp = NULL; 1205*12756Ssam if (u.u_error) { 1206*12756Ssam u.u_dirp = uap->name; 1207*12756Ssam dp = namei(uchar, LOOKUP, 0); 1208*12756Ssam if (dp) { 1209*12756Ssam dp->i_nlink--; 1210*12756Ssam dp->i_flag |= ICHG; 1211*12756Ssam } 1212*12756Ssam } 1213*12756Ssam bad: 1214*12756Ssam /* 1215*12756Ssam * No need to do an explicit itrunc here, 1216*12756Ssam * irele will do this for us because we set 1217*12756Ssam * the link count to 0. 1218*12756Ssam */ 1219*12756Ssam if (u.u_error) { 1220*12756Ssam ip->i_nlink = 0; 1221*12756Ssam ip->i_flag |= ICHG; 1222*12756Ssam } 1223*12756Ssam if (dp) 1224*12756Ssam iput(dp); 1225*12756Ssam iput(ip); 1226*12756Ssam } 1227*12756Ssam 1228*12756Ssam /* 1229*12756Ssam * Rmdir system call. 1230*12756Ssam */ 1231*12756Ssam rmdir() 1232*12756Ssam { 1233*12756Ssam struct a { 1234*12756Ssam char *name; 1235*12756Ssam }; 1236*12756Ssam register struct inode *ip, *dp; 1237*12756Ssam 1238*12756Ssam ip = namei(uchar, DELETE | LOCKPARENT, 0); 1239*12756Ssam if (ip == NULL) 1240*12756Ssam return; 1241*12756Ssam dp = u.u_pdir; 1242*12756Ssam /* 1243*12756Ssam * No rmdir "." please. 1244*12756Ssam */ 1245*12756Ssam if (dp == ip) { 1246*12756Ssam irele(dp); 1247*12756Ssam iput(ip); 1248*12756Ssam u.u_error = EINVAL; 1249*12756Ssam return; 1250*12756Ssam } 1251*12756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 1252*12756Ssam u.u_error = ENOTDIR; 1253*12756Ssam goto out; 1254*12756Ssam } 1255*12756Ssam /* 1256*12756Ssam * Don't remove a mounted on directory. 1257*12756Ssam */ 1258*12756Ssam if (ip->i_dev != dp->i_dev) { 1259*12756Ssam u.u_error = EBUSY; 1260*12756Ssam goto out; 1261*12756Ssam } 1262*12756Ssam /* 1263*12756Ssam * Verify the directory is empty (and valid). 1264*12756Ssam * (Rmdir ".." won't be valid since 1265*12756Ssam * ".." will contain a reference to 1266*12756Ssam * the current directory and thus be 1267*12756Ssam * non-empty.) 1268*12756Ssam */ 1269*12756Ssam if (ip->i_nlink != 2 || !dirempty(ip)) { 1270*12756Ssam u.u_error = ENOTEMPTY; 1271*12756Ssam goto out; 1272*12756Ssam } 1273*12756Ssam /* 1274*12756Ssam * Delete reference to directory before purging 1275*12756Ssam * inode. If we crash in between, the directory 1276*12756Ssam * will be reattached to lost+found, 1277*12756Ssam */ 1278*12756Ssam if (dirremove() == 0) 1279*12756Ssam goto out; 1280*12756Ssam dp->i_nlink--; 1281*12756Ssam dp->i_flag |= ICHG; 1282*12756Ssam iput(dp); 1283*12756Ssam dp = NULL; 1284*12756Ssam /* 1285*12756Ssam * Truncate inode. The only stuff left 1286*12756Ssam * in the directory is "." and "..". The 1287*12756Ssam * "." reference is inconsequential since 1288*12756Ssam * we're quashing it. The ".." reference 1289*12756Ssam * has already been adjusted above. We've 1290*12756Ssam * removed the "." reference and the reference 1291*12756Ssam * in the parent directory, but there may be 1292*12756Ssam * other hard links so decrement by 2 and 1293*12756Ssam * worry about them later. 1294*12756Ssam */ 1295*12756Ssam ip->i_nlink -= 2; 1296*12756Ssam itrunc(ip, (u_long)0); 1297*12756Ssam out: 1298*12756Ssam if (dp) 1299*12756Ssam iput(dp); 1300*12756Ssam iput(ip); 1301*12756Ssam } 1302*12756Ssam 1303*12756Ssam struct file * 1304*12756Ssam getinode(fdes) 1305*12756Ssam int fdes; 1306*12756Ssam { 1307*12756Ssam register struct file *fp; 1308*12756Ssam 1309*12756Ssam fp = getf(fdes); 1310*12756Ssam if (fp == 0) 1311*12756Ssam return (0); 1312*12756Ssam if (fp->f_type != DTYPE_INODE) { 1313*12756Ssam u.u_error = EINVAL; 1314*12756Ssam return (0); 1315*12756Ssam } 1316*12756Ssam return (fp); 1317*12756Ssam } 1318*12756Ssam 1319*12756Ssam /* 1320*12756Ssam * mode mask for creation of files 1321*12756Ssam */ 1322*12756Ssam umask() 1323*12756Ssam { 1324*12756Ssam register struct a { 1325*12756Ssam int mask; 1326*12756Ssam } *uap; 1327*12756Ssam 1328*12756Ssam uap = (struct a *)u.u_ap; 1329*12756Ssam u.u_r.r_val1 = u.u_cmask; 1330*12756Ssam u.u_cmask = uap->mask & 07777; 1331*12756Ssam } 1332