1*16694Smckusick /* vfs_syscalls.c 6.11 84/07/08 */ 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" 1812756Ssam #include "../h/mount.h" 1937Sbill 2012756Ssam extern struct fileops inodeops; 2112756Ssam struct file *getinode(); 2212756Ssam 239167Ssam /* 249167Ssam * Change current working directory (``.''). 259167Ssam */ 266254Sroot chdir() 276254Sroot { 286254Sroot 296254Sroot chdirec(&u.u_cdir); 306254Sroot } 316254Sroot 329167Ssam /* 339167Ssam * Change notion of root (``/'') directory. 349167Ssam */ 356254Sroot chroot() 366254Sroot { 376254Sroot 386254Sroot if (suser()) 396254Sroot chdirec(&u.u_rdir); 406254Sroot } 416254Sroot 429167Ssam /* 439167Ssam * Common routine for chroot and chdir. 449167Ssam */ 456254Sroot chdirec(ipp) 467701Ssam register struct inode **ipp; 476254Sroot { 486254Sroot register struct inode *ip; 496254Sroot struct a { 506254Sroot char *fname; 51*16694Smckusick } *uap = (struct a *)u.u_ap; 52*16694Smckusick register struct nameidata *ndp = &u.u_nd; 536254Sroot 54*16694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 55*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 56*16694Smckusick ndp->ni_dirp = uap->fname; 57*16694Smckusick ip = namei(ndp); 589167Ssam if (ip == NULL) 596254Sroot return; 609167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 616254Sroot u.u_error = ENOTDIR; 626254Sroot goto bad; 636254Sroot } 649167Ssam if (access(ip, IEXEC)) 656254Sroot goto bad; 6616664Smckusick IUNLOCK(ip); 677142Smckusick if (*ipp) 687142Smckusick irele(*ipp); 696254Sroot *ipp = ip; 706254Sroot return; 716254Sroot 726254Sroot bad: 736254Sroot iput(ip); 746254Sroot } 756254Sroot 7637Sbill /* 776254Sroot * Open system call. 786254Sroot */ 796254Sroot open() 806254Sroot { 8112756Ssam struct a { 826254Sroot char *fname; 837701Ssam int mode; 8412756Ssam int crtmode; 8512756Ssam } *uap = (struct a *) u.u_ap; 866254Sroot 87*16694Smckusick copen(uap->mode-FOPEN, uap->crtmode, uap->fname); 886254Sroot } 896254Sroot 906254Sroot /* 916254Sroot * Creat system call. 926254Sroot */ 9312756Ssam creat() 946254Sroot { 9512756Ssam struct a { 966254Sroot char *fname; 976254Sroot int fmode; 9812756Ssam } *uap = (struct a *)u.u_ap; 996254Sroot 100*16694Smckusick copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname); 1016254Sroot } 1026254Sroot 1036254Sroot /* 1046254Sroot * Common code for open and creat. 10512756Ssam * Check permissions, allocate an open file structure, 10612756Ssam * and call the device open routine if any. 1076254Sroot */ 108*16694Smckusick copen(mode, arg, fname) 10912756Ssam register int mode; 11012756Ssam int arg; 111*16694Smckusick caddr_t fname; 11212756Ssam { 1136254Sroot register struct inode *ip; 1146254Sroot register struct file *fp; 115*16694Smckusick register struct nameidata *ndp = &u.u_nd; 11612756Ssam int i; 1176254Sroot 11812756Ssam #ifdef notdef 11912756Ssam if ((mode&(FREAD|FWRITE)) == 0) { 12012756Ssam u.u_error = EINVAL; 12112756Ssam return; 12212756Ssam } 12312756Ssam #endif 124*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 125*16694Smckusick ndp->ni_dirp = fname; 12612756Ssam if (mode&FCREAT) { 127*16694Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 128*16694Smckusick ip = namei(ndp); 12912756Ssam if (ip == NULL) { 13012756Ssam if (u.u_error) 13112756Ssam return; 132*16694Smckusick ip = maknode(arg&07777&(~ISVTX), ndp); 13312756Ssam if (ip == NULL) 13412756Ssam return; 13512756Ssam mode &= ~FTRUNC; 13612756Ssam } else { 13712756Ssam if (mode&FEXCL) { 13812756Ssam u.u_error = EEXIST; 13912756Ssam iput(ip); 14012756Ssam return; 14112756Ssam } 14212756Ssam mode &= ~FCREAT; 14312756Ssam } 14412756Ssam } else { 145*16694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 146*16694Smckusick ip = namei(ndp); 14712756Ssam if (ip == NULL) 14812756Ssam return; 14912756Ssam } 15012756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 15112756Ssam u.u_error = EOPNOTSUPP; 15212756Ssam goto bad; 15312756Ssam } 15412756Ssam if ((mode&FCREAT) == 0) { 1556254Sroot if (mode&FREAD) 1567701Ssam if (access(ip, IREAD)) 1577701Ssam goto bad; 15816032Skarels if (mode&(FWRITE|FTRUNC)) { 1597701Ssam if (access(ip, IWRITE)) 1607701Ssam goto bad; 1617701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1626254Sroot u.u_error = EISDIR; 1637701Ssam goto bad; 1647701Ssam } 1656254Sroot } 1666254Sroot } 16712756Ssam fp = falloc(); 16812756Ssam if (fp == NULL) 16912756Ssam goto bad; 17012756Ssam if (mode&FTRUNC) 1719167Ssam itrunc(ip, (u_long)0); 17216664Smckusick IUNLOCK(ip); 17312756Ssam fp->f_flag = mode&FMASK; 17412756Ssam fp->f_type = DTYPE_INODE; 17512756Ssam fp->f_ops = &inodeops; 17612756Ssam fp->f_data = (caddr_t)ip; 1776254Sroot i = u.u_r.r_val1; 17812756Ssam if (setjmp(&u.u_qsave)) { 17912756Ssam if (u.u_error == 0) 18012756Ssam u.u_error = EINTR; 18112756Ssam u.u_ofile[i] = NULL; 18212756Ssam closef(fp); 18312756Ssam return; 18412756Ssam } 1858559Sroot u.u_error = openi(ip, mode); 18612756Ssam if (u.u_error == 0) 1876254Sroot return; 1886254Sroot u.u_ofile[i] = NULL; 1896254Sroot fp->f_count--; 1907142Smckusick irele(ip); 1917701Ssam return; 1927701Ssam bad: 1937701Ssam iput(ip); 1946254Sroot } 1956254Sroot 1966254Sroot /* 1976254Sroot * Mknod system call 1986254Sroot */ 1996254Sroot mknod() 2006254Sroot { 2016254Sroot register struct inode *ip; 2026254Sroot register struct a { 2036254Sroot char *fname; 2046254Sroot int fmode; 2056254Sroot int dev; 206*16694Smckusick } *uap = (struct a *)u.u_ap; 207*16694Smckusick register struct nameidata *ndp = &u.u_nd; 2086254Sroot 20912756Ssam if (!suser()) 21012756Ssam return; 211*16694Smckusick ndp->ni_nameiop = CREATE; 212*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 213*16694Smckusick ndp->ni_dirp = uap->fname; 214*16694Smckusick ip = namei(ndp); 21512756Ssam if (ip != NULL) { 21612756Ssam u.u_error = EEXIST; 21712756Ssam goto out; 2186254Sroot } 2196254Sroot if (u.u_error) 2206254Sroot return; 221*16694Smckusick ip = maknode(uap->fmode, ndp); 2226254Sroot if (ip == NULL) 2236254Sroot return; 22412756Ssam switch (ip->i_mode & IFMT) { 22512756Ssam 22615093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 22712756Ssam case IFCHR: 22812756Ssam case IFBLK: 22912756Ssam if (uap->dev) { 23012756Ssam /* 23112756Ssam * Want to be able to use this to make badblock 23212756Ssam * inodes, so don't truncate the dev number. 23312756Ssam */ 23412756Ssam ip->i_rdev = uap->dev; 23512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 23612756Ssam } 2376254Sroot } 2386254Sroot 2396254Sroot out: 2406254Sroot iput(ip); 2416254Sroot } 2426254Sroot 2436254Sroot /* 2446254Sroot * link system call 2456254Sroot */ 2466254Sroot link() 2476254Sroot { 2486254Sroot register struct inode *ip, *xp; 2496254Sroot register struct a { 2506254Sroot char *target; 2516254Sroot char *linkname; 252*16694Smckusick } *uap = (struct a *)u.u_ap; 253*16694Smckusick register struct nameidata *ndp = &u.u_nd; 2546254Sroot 255*16694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 256*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 257*16694Smckusick ndp->ni_dirp = uap->target; 258*16694Smckusick ip = namei(ndp); /* well, this routine is doomed anyhow */ 2596254Sroot if (ip == NULL) 2606254Sroot return; 2619167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2627439Sroot iput(ip); 2637439Sroot return; 2647439Sroot } 2656254Sroot ip->i_nlink++; 2666254Sroot ip->i_flag |= ICHG; 2678673Sroot iupdat(ip, &time, &time, 1); 26816664Smckusick IUNLOCK(ip); 269*16694Smckusick ndp->ni_nameiop = CREATE; 270*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 271*16694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 272*16694Smckusick xp = namei(ndp); 2736254Sroot if (xp != NULL) { 2746254Sroot u.u_error = EEXIST; 2756254Sroot iput(xp); 2766254Sroot goto out; 2776254Sroot } 2786254Sroot if (u.u_error) 2796254Sroot goto out; 280*16694Smckusick if (ndp->ni_pdir->i_dev != ip->i_dev) { 281*16694Smckusick iput(ndp->ni_pdir); 2826254Sroot u.u_error = EXDEV; 2836254Sroot goto out; 2846254Sroot } 285*16694Smckusick u.u_error = direnter(ip, ndp); 2866254Sroot out: 2876254Sroot if (u.u_error) { 2886254Sroot ip->i_nlink--; 2896254Sroot ip->i_flag |= ICHG; 2906254Sroot } 2917142Smckusick irele(ip); 2926254Sroot } 2936254Sroot 2946254Sroot /* 2956254Sroot * symlink -- make a symbolic link 2966254Sroot */ 2976254Sroot symlink() 2986254Sroot { 2996254Sroot register struct a { 3006254Sroot char *target; 3016254Sroot char *linkname; 302*16694Smckusick } *uap = (struct a *)u.u_ap; 3036254Sroot register struct inode *ip; 3046254Sroot register char *tp; 3056254Sroot register c, nc; 306*16694Smckusick register struct nameidata *ndp = &u.u_nd; 3076254Sroot 3086254Sroot tp = uap->target; 3096254Sroot nc = 0; 3106254Sroot while (c = fubyte(tp)) { 3116254Sroot if (c < 0) { 3126254Sroot u.u_error = EFAULT; 3136254Sroot return; 3146254Sroot } 3156254Sroot tp++; 3166254Sroot nc++; 3176254Sroot } 318*16694Smckusick ndp->ni_nameiop = CREATE; 319*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 320*16694Smckusick ndp->ni_dirp = uap->linkname; 321*16694Smckusick ip = namei(ndp); 3226254Sroot if (ip) { 3236254Sroot iput(ip); 3246254Sroot u.u_error = EEXIST; 3256254Sroot return; 3266254Sroot } 3276254Sroot if (u.u_error) 3286254Sroot return; 329*16694Smckusick ip = maknode(IFLNK | 0777, ndp); 3306254Sroot if (ip == NULL) 3316254Sroot return; 3327826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3339167Ssam /* handle u.u_error != 0 */ 3346254Sroot iput(ip); 3356254Sroot } 3366254Sroot 3376254Sroot /* 3386254Sroot * Unlink system call. 3396254Sroot * Hard to avoid races here, especially 3406254Sroot * in unlinking directories. 3416254Sroot */ 3426254Sroot unlink() 3436254Sroot { 3446254Sroot struct a { 3456254Sroot char *fname; 346*16694Smckusick } *uap = (struct a *)u.u_ap; 3479167Ssam register struct inode *ip, *dp; 348*16694Smckusick register struct nameidata *ndp = &u.u_nd; 3496254Sroot 350*16694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 351*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 352*16694Smckusick ndp->ni_dirp = uap->fname; 353*16694Smckusick ip = namei(ndp); 3549167Ssam if (ip == NULL) 3556254Sroot return; 356*16694Smckusick dp = ndp->ni_pdir; 3579167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3586254Sroot goto out; 3596254Sroot /* 3606254Sroot * Don't unlink a mounted file. 3616254Sroot */ 3629167Ssam if (ip->i_dev != dp->i_dev) { 3636254Sroot u.u_error = EBUSY; 3646254Sroot goto out; 3656254Sroot } 3666254Sroot if (ip->i_flag&ITEXT) 3676254Sroot xrele(ip); /* try once to free text */ 368*16694Smckusick if (dirremove(ndp)) { 3697535Sroot ip->i_nlink--; 3707535Sroot ip->i_flag |= ICHG; 3716254Sroot } 3726254Sroot out: 3739167Ssam if (dp == ip) 3747142Smckusick irele(ip); 3757142Smckusick else 3767142Smckusick iput(ip); 3779167Ssam iput(dp); 3786254Sroot } 3796254Sroot 3806254Sroot /* 3816254Sroot * Seek system call 3826254Sroot */ 3838040Sroot lseek() 3846254Sroot { 3856254Sroot register struct file *fp; 3866254Sroot register struct a { 3877701Ssam int fd; 3886254Sroot off_t off; 3896254Sroot int sbase; 390*16694Smckusick } *uap = (struct a *)u.u_ap; 3916254Sroot 39216540Ssam GETF(fp, uap->fd); 39316540Ssam if (fp->f_type != DTYPE_INODE) { 39416540Ssam u.u_error = ESPIPE; 3956254Sroot return; 39616540Ssam } 39713878Ssam switch (uap->sbase) { 39813878Ssam 39913878Ssam case L_INCR: 40013878Ssam fp->f_offset += uap->off; 40113878Ssam break; 40213878Ssam 40313878Ssam case L_XTND: 40413878Ssam fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; 40513878Ssam break; 40613878Ssam 40713878Ssam case L_SET: 40813878Ssam fp->f_offset = uap->off; 40913878Ssam break; 41013878Ssam 41113878Ssam default: 41213878Ssam u.u_error = EINVAL; 41313878Ssam return; 41413878Ssam } 41513878Ssam u.u_r.r_off = fp->f_offset; 4166254Sroot } 4176254Sroot 4186254Sroot /* 4196254Sroot * Access system call 4206254Sroot */ 4216254Sroot saccess() 4226254Sroot { 4236254Sroot register svuid, svgid; 4246254Sroot register struct inode *ip; 4256254Sroot register struct a { 4266254Sroot char *fname; 4276254Sroot int fmode; 428*16694Smckusick } *uap = (struct a *)u.u_ap; 429*16694Smckusick register struct nameidata *ndp = &u.u_nd; 4306254Sroot 4316254Sroot svuid = u.u_uid; 4326254Sroot svgid = u.u_gid; 4336254Sroot u.u_uid = u.u_ruid; 4346254Sroot u.u_gid = u.u_rgid; 435*16694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 436*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 437*16694Smckusick ndp->ni_dirp = uap->fname; 438*16694Smckusick ip = namei(ndp); 4396254Sroot if (ip != NULL) { 44012756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4417701Ssam goto done; 44212756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4437701Ssam goto done; 44412756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4457701Ssam goto done; 4467701Ssam done: 4476254Sroot iput(ip); 4486254Sroot } 4496254Sroot u.u_uid = svuid; 4506254Sroot u.u_gid = svgid; 4516254Sroot } 4526254Sroot 4536254Sroot /* 4546574Smckusic * Stat system call. This version follows links. 45537Sbill */ 45637Sbill stat() 45737Sbill { 45837Sbill 459*16694Smckusick stat1(FOLLOW); 46037Sbill } 46137Sbill 46237Sbill /* 4636574Smckusic * Lstat system call. This version does not follow links. 4645992Swnj */ 4655992Swnj lstat() 4665992Swnj { 46712756Ssam 468*16694Smckusick stat1(NOFOLLOW); 46912756Ssam } 47012756Ssam 47112756Ssam stat1(follow) 47212756Ssam int follow; 47312756Ssam { 4745992Swnj register struct inode *ip; 4755992Swnj register struct a { 4765992Swnj char *fname; 47712756Ssam struct stat *ub; 478*16694Smckusick } *uap = (struct a *)u.u_ap; 47912756Ssam struct stat sb; 480*16694Smckusick register struct nameidata *ndp = &u.u_nd; 4815992Swnj 482*16694Smckusick ndp->ni_nameiop = LOOKUP | follow; 483*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 484*16694Smckusick ndp->ni_dirp = uap->fname; 485*16694Smckusick ip = namei(ndp); 4865992Swnj if (ip == NULL) 4875992Swnj return; 48813043Ssam (void) ino_stat(ip, &sb); 4895992Swnj iput(ip); 49012756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4915992Swnj } 4925992Swnj 4935992Swnj /* 4945992Swnj * Return target name of a symbolic link 49537Sbill */ 4965992Swnj readlink() 4975992Swnj { 4985992Swnj register struct inode *ip; 4995992Swnj register struct a { 5005992Swnj char *name; 5015992Swnj char *buf; 5025992Swnj int count; 5037826Sroot } *uap = (struct a *)u.u_ap; 504*16694Smckusick register struct nameidata *ndp = &u.u_nd; 5057826Sroot int resid; 5065992Swnj 507*16694Smckusick ndp->ni_nameiop = LOOKUP; 508*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 509*16694Smckusick ndp->ni_dirp = uap->name; 510*16694Smckusick ip = namei(ndp); 5115992Swnj if (ip == NULL) 5125992Swnj return; 5135992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 5145992Swnj u.u_error = ENXIO; 5155992Swnj goto out; 5165992Swnj } 5177826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 5185992Swnj out: 5195992Swnj iput(ip); 5207826Sroot u.u_r.r_val1 = uap->count - resid; 5215992Swnj } 5225992Swnj 5239167Ssam /* 5249167Ssam * Change mode of a file given path name. 5259167Ssam */ 5266254Sroot chmod() 5275992Swnj { 5287701Ssam struct inode *ip; 5297701Ssam struct a { 5306254Sroot char *fname; 5316254Sroot int fmode; 532*16694Smckusick } *uap = (struct a *)u.u_ap; 5335992Swnj 534*16694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 5355992Swnj return; 5367701Ssam chmod1(ip, uap->fmode); 5379167Ssam iput(ip); 5387701Ssam } 5397439Sroot 5409167Ssam /* 5419167Ssam * Change mode of a file given a file descriptor. 5429167Ssam */ 5437701Ssam fchmod() 5447701Ssam { 5457701Ssam struct a { 5467701Ssam int fd; 5477701Ssam int fmode; 548*16694Smckusick } *uap = (struct a *)u.u_ap; 5497701Ssam register struct inode *ip; 5507701Ssam register struct file *fp; 5517701Ssam 55212756Ssam fp = getinode(uap->fd); 5537701Ssam if (fp == NULL) 5547701Ssam return; 55512756Ssam ip = (struct inode *)fp->f_data; 5569167Ssam if (u.u_uid != ip->i_uid && !suser()) 5579167Ssam return; 55816664Smckusick ILOCK(ip); 5597701Ssam chmod1(ip, uap->fmode); 56016664Smckusick IUNLOCK(ip); 5617701Ssam } 5627701Ssam 5639167Ssam /* 5649167Ssam * Change the mode on a file. 5659167Ssam * Inode must be locked before calling. 5669167Ssam */ 5677701Ssam chmod1(ip, mode) 5687701Ssam register struct inode *ip; 5697701Ssam register int mode; 5707701Ssam { 5717868Sroot 5726254Sroot ip->i_mode &= ~07777; 5737439Sroot if (u.u_uid) { 5747701Ssam mode &= ~ISVTX; 57511811Ssam if (!groupmember(ip->i_gid)) 57611811Ssam mode &= ~ISGID; 5777439Sroot } 5787701Ssam ip->i_mode |= mode&07777; 5796254Sroot ip->i_flag |= ICHG; 5806254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5816254Sroot xrele(ip); 5825992Swnj } 5835992Swnj 5849167Ssam /* 5859167Ssam * Set ownership given a path name. 5869167Ssam */ 5876254Sroot chown() 58837Sbill { 5897701Ssam struct inode *ip; 5907701Ssam struct a { 5916254Sroot char *fname; 5926254Sroot int uid; 5936254Sroot int gid; 594*16694Smckusick } *uap = (struct a *)u.u_ap; 59537Sbill 596*16694Smckusick if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL) 59737Sbill return; 59811811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 5999167Ssam iput(ip); 6007701Ssam } 6017439Sroot 6029167Ssam /* 6039167Ssam * Set ownership given a file descriptor. 6049167Ssam */ 6057701Ssam fchown() 6067701Ssam { 6077701Ssam struct a { 6087701Ssam int fd; 6097701Ssam int uid; 6107701Ssam int gid; 611*16694Smckusick } *uap = (struct a *)u.u_ap; 6127701Ssam register struct inode *ip; 6137701Ssam register struct file *fp; 6147701Ssam 61512756Ssam fp = getinode(uap->fd); 6167701Ssam if (fp == NULL) 6177701Ssam return; 61812756Ssam ip = (struct inode *)fp->f_data; 61911821Ssam if (!suser()) 6209167Ssam return; 62116664Smckusick ILOCK(ip); 62211811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 62316664Smckusick IUNLOCK(ip); 6247701Ssam } 6257701Ssam 6267701Ssam /* 6277701Ssam * Perform chown operation on inode ip; 6287701Ssam * inode must be locked prior to call. 6297701Ssam */ 6307701Ssam chown1(ip, uid, gid) 6317701Ssam register struct inode *ip; 6327701Ssam int uid, gid; 6337701Ssam { 6347701Ssam #ifdef QUOTA 6357701Ssam register long change; 63611811Ssam #endif 6377701Ssam 63811811Ssam if (uid == -1) 63911811Ssam uid = ip->i_uid; 64011811Ssam if (gid == -1) 64111811Ssam gid = ip->i_gid; 64211811Ssam #ifdef QUOTA 64314385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6447482Skre change = 0; 64512646Ssam else 64612646Ssam change = ip->i_blocks; 64712646Ssam (void) chkdq(ip, -change, 1); 64812646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6497482Skre dqrele(ip->i_dquot); 6507482Skre #endif 65111811Ssam ip->i_uid = uid; 65211811Ssam ip->i_gid = gid; 6536254Sroot ip->i_flag |= ICHG; 6546254Sroot if (u.u_ruid != 0) 6556254Sroot ip->i_mode &= ~(ISUID|ISGID); 6567701Ssam #ifdef QUOTA 6577482Skre ip->i_dquot = inoquota(ip); 65812646Ssam (void) chkdq(ip, change, 1); 65912646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 66012646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 66112646Ssam #else 66212646Ssam return (0); 6637482Skre #endif 66437Sbill } 66537Sbill 66611811Ssam utimes() 66711811Ssam { 66811811Ssam register struct a { 66911811Ssam char *fname; 67011811Ssam struct timeval *tptr; 67111811Ssam } *uap = (struct a *)u.u_ap; 67211811Ssam register struct inode *ip; 67311811Ssam struct timeval tv[2]; 67411811Ssam 675*16694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 67611811Ssam return; 67711811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 67811811Ssam if (u.u_error == 0) { 67911811Ssam ip->i_flag |= IACC|IUPD|ICHG; 68011811Ssam iupdat(ip, &tv[0], &tv[1], 0); 68111811Ssam } 68211811Ssam iput(ip); 68311811Ssam } 68411811Ssam 6859167Ssam /* 6869167Ssam * Flush any pending I/O. 6879167Ssam */ 6886254Sroot sync() 68937Sbill { 69037Sbill 6918673Sroot update(); 69237Sbill } 6937535Sroot 6949167Ssam /* 6959167Ssam * Truncate a file given its path name. 6969167Ssam */ 6977701Ssam truncate() 6987701Ssam { 6997701Ssam struct a { 7007701Ssam char *fname; 7019167Ssam u_long length; 7027826Sroot } *uap = (struct a *)u.u_ap; 7037701Ssam struct inode *ip; 704*16694Smckusick register struct nameidata *ndp = &u.u_nd; 7057701Ssam 706*16694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 707*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 708*16694Smckusick ndp->ni_dirp = uap->fname; 709*16694Smckusick ip = namei(ndp); 7107701Ssam if (ip == NULL) 7117701Ssam return; 7127701Ssam if (access(ip, IWRITE)) 7137701Ssam goto bad; 7147701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7157701Ssam u.u_error = EISDIR; 7167701Ssam goto bad; 7177701Ssam } 7187701Ssam itrunc(ip, uap->length); 7197701Ssam bad: 7207701Ssam iput(ip); 7217701Ssam } 7227701Ssam 7239167Ssam /* 7249167Ssam * Truncate a file given a file descriptor. 7259167Ssam */ 7267701Ssam ftruncate() 7277701Ssam { 7287701Ssam struct a { 7297701Ssam int fd; 7309167Ssam u_long length; 7317826Sroot } *uap = (struct a *)u.u_ap; 7327701Ssam struct inode *ip; 7337701Ssam struct file *fp; 7347701Ssam 73512756Ssam fp = getinode(uap->fd); 7367701Ssam if (fp == NULL) 7377701Ssam return; 7387701Ssam if ((fp->f_flag&FWRITE) == 0) { 7397701Ssam u.u_error = EINVAL; 7407701Ssam return; 7417701Ssam } 74212756Ssam ip = (struct inode *)fp->f_data; 74316664Smckusick ILOCK(ip); 7447701Ssam itrunc(ip, uap->length); 74516664Smckusick IUNLOCK(ip); 7467701Ssam } 7477701Ssam 7489167Ssam /* 7499167Ssam * Synch an open file. 7509167Ssam */ 7519167Ssam fsync() 7529167Ssam { 7539167Ssam struct a { 7549167Ssam int fd; 7559167Ssam } *uap = (struct a *)u.u_ap; 7569167Ssam struct inode *ip; 7579167Ssam struct file *fp; 7589167Ssam 75912756Ssam fp = getinode(uap->fd); 7609167Ssam if (fp == NULL) 7619167Ssam return; 76212756Ssam ip = (struct inode *)fp->f_data; 76316664Smckusick ILOCK(ip); 7649167Ssam syncip(ip); 76516664Smckusick IUNLOCK(ip); 7669167Ssam } 7679167Ssam 7689167Ssam /* 7699167Ssam * Rename system call. 7709167Ssam * rename("foo", "bar"); 7719167Ssam * is essentially 7729167Ssam * unlink("bar"); 7739167Ssam * link("foo", "bar"); 7749167Ssam * unlink("foo"); 7759167Ssam * but ``atomically''. Can't do full commit without saving state in the 7769167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7779167Ssam * always guarantee the target exists. 7789167Ssam * 7799167Ssam * Basic algorithm is: 7809167Ssam * 7819167Ssam * 1) Bump link count on source while we're linking it to the 7829167Ssam * target. This also insure the inode won't be deleted out 7839167Ssam * from underneath us while we work. 7849167Ssam * 2) Link source to destination. If destination already exists, 7859167Ssam * delete it first. 7869167Ssam * 3) Unlink source reference to inode if still around. 7879167Ssam * 4) If a directory was moved and the parent of the destination 7889167Ssam * is different from the source, patch the ".." entry in the 7899167Ssam * directory. 7909167Ssam * 7919167Ssam * Source and destination must either both be directories, or both 7929167Ssam * not be directories. If target is a directory, it must be empty. 7939167Ssam */ 7947701Ssam rename() 7957701Ssam { 7967701Ssam struct a { 7977701Ssam char *from; 7987701Ssam char *to; 799*16694Smckusick } *uap = (struct a *)u.u_ap; 8009167Ssam register struct inode *ip, *xp, *dp; 80116655Smckusick struct inode *zp; 8029167Ssam int oldparent, parentdifferent, doingdirectory; 803*16694Smckusick register struct nameidata *ndp = &u.u_nd; 80410051Ssam int error = 0; 8057701Ssam 806*16694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 807*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 808*16694Smckusick ndp->ni_dirp = uap->from; 809*16694Smckusick ip = namei(ndp); 8109167Ssam if (ip == NULL) 8119167Ssam return; 812*16694Smckusick dp = ndp->ni_pdir; 8139167Ssam oldparent = 0, doingdirectory = 0; 8149167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 8159167Ssam register struct direct *d; 8169167Ssam 817*16694Smckusick d = &ndp->ni_dent; 8189167Ssam /* 81911641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 8209167Ssam */ 82111641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 82211641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 82311641Ssam (dp == ip)) { 82411641Ssam iput(dp); 82511641Ssam if (dp == ip) 82611641Ssam irele(ip); 82711641Ssam else 82810051Ssam iput(ip); 82911641Ssam u.u_error = EINVAL; 83011641Ssam return; 8319167Ssam } 8329167Ssam oldparent = dp->i_number; 8339167Ssam doingdirectory++; 8349167Ssam } 83511641Ssam iput(dp); 8369167Ssam 8379167Ssam /* 8389167Ssam * 1) Bump link count while we're moving stuff 8399167Ssam * around. If we crash somewhere before 8409167Ssam * completing our work, the link count 8419167Ssam * may be wrong, but correctable. 8429167Ssam */ 8439167Ssam ip->i_nlink++; 8449167Ssam ip->i_flag |= ICHG; 8459167Ssam iupdat(ip, &time, &time, 1); 84616664Smckusick IUNLOCK(ip); 8479167Ssam 8489167Ssam /* 8499167Ssam * When the target exists, both the directory 8509167Ssam * and target inodes are returned locked. 8519167Ssam */ 852*16694Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE; 853*16694Smckusick ndp->ni_dirp = (caddr_t)uap->to; 854*16694Smckusick xp = namei(ndp); 85510051Ssam if (u.u_error) { 85610051Ssam error = u.u_error; 8579167Ssam goto out; 85810051Ssam } 859*16694Smckusick dp = ndp->ni_pdir; 8609167Ssam /* 86111641Ssam * If ".." must be changed (ie the directory gets a new 86212816Smckusick * parent) then the source directory must not be in the 86312816Smckusick * directory heirarchy above the target, as this would 86412816Smckusick * orphan everything below the source directory. Also 86512816Smckusick * the user must have write permission in the source so 86612816Smckusick * as to be able to change "..". We must repeat the call 86712816Smckusick * to namei, as the parent directory is unlocked by the 86812816Smckusick * call to checkpath(). 86911641Ssam */ 87011641Ssam parentdifferent = oldparent != dp->i_number; 87112816Smckusick if (doingdirectory && parentdifferent) { 87212816Smckusick if (access(ip, IWRITE)) 87312816Smckusick goto bad; 87412816Smckusick do { 875*16694Smckusick dp = ndp->ni_pdir; 87612816Smckusick if (xp != NULL) 87712816Smckusick iput(xp); 87812816Smckusick u.u_error = checkpath(ip, dp); 87912816Smckusick if (u.u_error) 88012816Smckusick goto out; 881*16694Smckusick xp = namei(ndp); 88212816Smckusick if (u.u_error) { 88312816Smckusick error = u.u_error; 88412816Smckusick goto out; 88512816Smckusick } 886*16694Smckusick } while (dp != ndp->ni_pdir); 88712816Smckusick } 88811641Ssam /* 8899167Ssam * 2) If target doesn't exist, link the target 8909167Ssam * to the source and unlink the source. 8919167Ssam * Otherwise, rewrite the target directory 8929167Ssam * entry to reference the source inode and 8939167Ssam * expunge the original entry's existence. 8949167Ssam */ 8959167Ssam if (xp == NULL) { 8969167Ssam if (dp->i_dev != ip->i_dev) { 89710051Ssam error = EXDEV; 8989167Ssam goto bad; 8999167Ssam } 9009167Ssam /* 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 } 912*16694Smckusick error = direnter(ip, ndp); 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 } 945*16694Smckusick dirrewrite(dp, ip, ndp); 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 */ 975*16694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 976*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 977*16694Smckusick ndp->ni_dirp = uap->from; 978*16694Smckusick zp = namei(ndp); 979*16694Smckusick dp = ndp->ni_pdir; 9809167Ssam /* 9819167Ssam * Insure directory entry still exists and 9829167Ssam * has not changed since the start of all 9839167Ssam * this. If either has occured, forget about 98416652Ssam * about deleting the original entry. 9859167Ssam */ 98616655Smckusick if (dp != NULL && zp == ip) { 9879167Ssam /* 9889167Ssam * If source is a directory, must adjust 9899167Ssam * link count of parent directory also. 9909167Ssam * If target didn't exist and source and 9919167Ssam * target have the same parent, then we 9929167Ssam * needn't touch the link count, it all 9939167Ssam * balances out in the end. Otherwise, we 9949167Ssam * must do so to reflect deletion of ".." 9959167Ssam * done above. 9969167Ssam */ 9979167Ssam if (doingdirectory && (xp != NULL || parentdifferent)) { 9989167Ssam dp->i_nlink--; 9999167Ssam dp->i_flag |= ICHG; 10009167Ssam } 1001*16694Smckusick if (dirremove(ndp)) { 100216655Smckusick zp->i_nlink--; 100316655Smckusick zp->i_flag |= ICHG; 10049167Ssam } 100510051Ssam if (error == 0) /* conservative */ 100610051Ssam error = u.u_error; 10079167Ssam } 100816655Smckusick if (zp != NULL) 100916655Smckusick iput(zp); 10109167Ssam irele(ip); 10119167Ssam if (dp) 10129167Ssam iput(dp); 10139167Ssam 10149167Ssam /* 10159167Ssam * 4) Renaming a directory with the parent 10169167Ssam * different requires ".." to be rewritten. 10179167Ssam * The window is still there for ".." to 10189167Ssam * be inconsistent, but this is unavoidable, 10199167Ssam * and a lot shorter than when it was done 10209167Ssam * in a user process. 10219167Ssam */ 102210051Ssam if (doingdirectory && parentdifferent && error == 0) { 10239167Ssam struct dirtemplate dirbuf; 10249167Ssam 1025*16694Smckusick ndp->ni_nameiop = LOOKUP | LOCKPARENT; 1026*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 1027*16694Smckusick ndp->ni_dirp = uap->to; 1028*16694Smckusick ip = namei(ndp); 10299167Ssam if (ip == NULL) { 10309167Ssam printf("rename: .. went away\n"); 10319167Ssam return; 10329167Ssam } 1033*16694Smckusick dp = ndp->ni_pdir; 10349167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 10359167Ssam printf("rename: .. not a directory\n"); 10369167Ssam goto stuck; 10379167Ssam } 103810051Ssam error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf, 10399167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 104010051Ssam if (error == 0) { 10419167Ssam dirbuf.dotdot_ino = dp->i_number; 104216644Ssam dp->i_id = ++nextinodeid; 10439167Ssam (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf, 10449167Ssam sizeof (struct dirtemplate), (off_t)0, 1, (int *)0); 10459167Ssam } 10469167Ssam stuck: 10479167Ssam irele(dp); 10489167Ssam iput(ip); 10499167Ssam } 105010051Ssam goto done; 105110051Ssam 10529167Ssam bad: 105310246Ssam iput(dp); 10549167Ssam bad1: 10559167Ssam if (xp) 105610246Ssam iput(xp); 10579167Ssam out: 10589167Ssam ip->i_nlink--; 10599167Ssam ip->i_flag |= ICHG; 10609167Ssam irele(ip); 106110051Ssam done: 106210051Ssam if (error) 106310051Ssam u.u_error = error; 10647701Ssam } 10657701Ssam 10667535Sroot /* 10677535Sroot * Make a new file. 10687535Sroot */ 10697535Sroot struct inode * 1070*16694Smckusick maknode(mode, ndp) 10717535Sroot int mode; 1072*16694Smckusick register struct nameidata *ndp; 10737535Sroot { 10747535Sroot register struct inode *ip; 1075*16694Smckusick register struct inode *pdir = ndp->ni_pdir; 10767535Sroot ino_t ipref; 10777535Sroot 10787535Sroot if ((mode & IFMT) == IFDIR) 1079*16694Smckusick ipref = dirpref(pdir->i_fs); 10807535Sroot else 1081*16694Smckusick ipref = pdir->i_number; 1082*16694Smckusick ip = ialloc(pdir, ipref, mode); 10837535Sroot if (ip == NULL) { 1084*16694Smckusick iput(pdir); 10857701Ssam return (NULL); 10867535Sroot } 10877701Ssam #ifdef QUOTA 10887535Sroot if (ip->i_dquot != NODQUOT) 10897535Sroot panic("maknode: dquot"); 10907535Sroot #endif 10917535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10927535Sroot if ((mode & IFMT) == 0) 10937535Sroot mode |= IFREG; 10947535Sroot ip->i_mode = mode & ~u.u_cmask; 10957535Sroot ip->i_nlink = 1; 10967535Sroot ip->i_uid = u.u_uid; 1097*16694Smckusick ip->i_gid = pdir->i_gid; 109811811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 109911811Ssam ip->i_mode &= ~ISGID; 11007701Ssam #ifdef QUOTA 11017535Sroot ip->i_dquot = inoquota(ip); 11027535Sroot #endif 11037535Sroot 11047535Sroot /* 11057535Sroot * Make sure inode goes to disk before directory entry. 11067535Sroot */ 11078673Sroot iupdat(ip, &time, &time, 1); 1108*16694Smckusick u.u_error = direnter(ip, ndp); 11097535Sroot if (u.u_error) { 11107535Sroot /* 111110850Ssam * Write error occurred trying to update directory 111210850Ssam * so must deallocate the inode. 11137535Sroot */ 11147535Sroot ip->i_nlink = 0; 11157535Sroot ip->i_flag |= ICHG; 11167535Sroot iput(ip); 11177701Ssam return (NULL); 11187535Sroot } 11197701Ssam return (ip); 11207535Sroot } 112112756Ssam 112212756Ssam /* 112312756Ssam * A virgin directory (no blushing please). 112412756Ssam */ 112512756Ssam struct dirtemplate mastertemplate = { 112612756Ssam 0, 12, 1, ".", 112712756Ssam 0, DIRBLKSIZ - 12, 2, ".." 112812756Ssam }; 112912756Ssam 113012756Ssam /* 113112756Ssam * Mkdir system call 113212756Ssam */ 113312756Ssam mkdir() 113412756Ssam { 113512756Ssam struct a { 113612756Ssam char *name; 113712756Ssam int dmode; 1138*16694Smckusick } *uap = (struct a *)u.u_ap; 113912756Ssam register struct inode *ip, *dp; 114012756Ssam struct dirtemplate dirtemplate; 1141*16694Smckusick register struct nameidata *ndp = &u.u_nd; 114212756Ssam 1143*16694Smckusick ndp->ni_nameiop = CREATE; 1144*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 1145*16694Smckusick ndp->ni_dirp = uap->name; 1146*16694Smckusick ip = namei(ndp); 114712756Ssam if (u.u_error) 114812756Ssam return; 114912756Ssam if (ip != NULL) { 115012756Ssam iput(ip); 115112756Ssam u.u_error = EEXIST; 115212756Ssam return; 115312756Ssam } 1154*16694Smckusick dp = ndp->ni_pdir; 115512756Ssam uap->dmode &= 0777; 115612756Ssam uap->dmode |= IFDIR; 115712756Ssam /* 115812756Ssam * Must simulate part of maknode here 115912756Ssam * in order to acquire the inode, but 116012756Ssam * not have it entered in the parent 116112756Ssam * directory. The entry is made later 116212756Ssam * after writing "." and ".." entries out. 116312756Ssam */ 116412756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 116512756Ssam if (ip == NULL) { 116612756Ssam iput(dp); 116712756Ssam return; 116812756Ssam } 116912756Ssam #ifdef QUOTA 117012756Ssam if (ip->i_dquot != NODQUOT) 117112756Ssam panic("mkdir: dquot"); 117212756Ssam #endif 117312756Ssam ip->i_flag |= IACC|IUPD|ICHG; 117412756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 117512756Ssam ip->i_nlink = 2; 117612756Ssam ip->i_uid = u.u_uid; 117712756Ssam ip->i_gid = dp->i_gid; 117812756Ssam #ifdef QUOTA 117912756Ssam ip->i_dquot = inoquota(ip); 118012756Ssam #endif 118112756Ssam iupdat(ip, &time, &time, 1); 118212756Ssam 118312756Ssam /* 118412756Ssam * Bump link count in parent directory 118512756Ssam * to reflect work done below. Should 118612756Ssam * be done before reference is created 118712756Ssam * so reparation is possible if we crash. 118812756Ssam */ 118912756Ssam dp->i_nlink++; 119012756Ssam dp->i_flag |= ICHG; 119112756Ssam iupdat(dp, &time, &time, 1); 119212756Ssam 119312756Ssam /* 119412756Ssam * Initialize directory with "." 119512756Ssam * and ".." from static template. 119612756Ssam */ 119712756Ssam dirtemplate = mastertemplate; 119812756Ssam dirtemplate.dot_ino = ip->i_number; 119912756Ssam dirtemplate.dotdot_ino = dp->i_number; 120012756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 120112756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 120212756Ssam if (u.u_error) { 120312756Ssam dp->i_nlink--; 120412756Ssam dp->i_flag |= ICHG; 120512756Ssam goto bad; 120612756Ssam } 120712756Ssam /* 120812756Ssam * Directory all set up, now 120912756Ssam * install the entry for it in 121012756Ssam * the parent directory. 121112756Ssam */ 1212*16694Smckusick u.u_error = direnter(ip, ndp); 121312756Ssam dp = NULL; 121412756Ssam if (u.u_error) { 1215*16694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 1216*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 1217*16694Smckusick ndp->ni_dirp = uap->name; 1218*16694Smckusick dp = namei(ndp); 121912756Ssam if (dp) { 122012756Ssam dp->i_nlink--; 122112756Ssam dp->i_flag |= ICHG; 122212756Ssam } 122312756Ssam } 122412756Ssam bad: 122512756Ssam /* 122612756Ssam * No need to do an explicit itrunc here, 122712756Ssam * irele will do this for us because we set 122812756Ssam * the link count to 0. 122912756Ssam */ 123012756Ssam if (u.u_error) { 123112756Ssam ip->i_nlink = 0; 123212756Ssam ip->i_flag |= ICHG; 123312756Ssam } 123412756Ssam if (dp) 123512756Ssam iput(dp); 123612756Ssam iput(ip); 123712756Ssam } 123812756Ssam 123912756Ssam /* 124012756Ssam * Rmdir system call. 124112756Ssam */ 124212756Ssam rmdir() 124312756Ssam { 124412756Ssam struct a { 124512756Ssam char *name; 1246*16694Smckusick } *uap = (struct a *)u.u_ap; 124712756Ssam register struct inode *ip, *dp; 1248*16694Smckusick register struct nameidata *ndp = &u.u_nd; 124912756Ssam 1250*16694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 1251*16694Smckusick ndp->ni_segflg = UIO_USERSPACE; 1252*16694Smckusick ndp->ni_dirp = uap->name; 1253*16694Smckusick ip = namei(ndp); 125412756Ssam if (ip == NULL) 125512756Ssam return; 1256*16694Smckusick dp = ndp->ni_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 */ 1293*16694Smckusick if (dirremove(ndp) == 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 { 132216540Ssam struct file *fp; 132312756Ssam 132416540Ssam if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { 132516540Ssam u.u_error = EBADF; 132616540Ssam return ((struct file *)0); 132716540Ssam } 132812756Ssam if (fp->f_type != DTYPE_INODE) { 132912756Ssam u.u_error = EINVAL; 133016540Ssam return ((struct file *)0); 133112756Ssam } 133212756Ssam return (fp); 133312756Ssam } 133412756Ssam 133512756Ssam /* 133612756Ssam * mode mask for creation of files 133712756Ssam */ 133812756Ssam umask() 133912756Ssam { 134012756Ssam register struct a { 134112756Ssam int mask; 1342*16694Smckusick } *uap = (struct a *)u.u_ap; 134312756Ssam 134412756Ssam u.u_r.r_val1 = u.u_cmask; 134512756Ssam u.u_cmask = uap->mask & 07777; 134612756Ssam } 1347