1*21015Smckusick /* vfs_syscalls.c 6.18 85/05/22 */ 237Sbill 317101Sbloom #include "param.h" 417101Sbloom #include "systm.h" 517101Sbloom #include "dir.h" 617101Sbloom #include "user.h" 717101Sbloom #include "kernel.h" 817101Sbloom #include "file.h" 917101Sbloom #include "stat.h" 1017101Sbloom #include "inode.h" 1117101Sbloom #include "fs.h" 1217101Sbloom #include "buf.h" 1317101Sbloom #include "proc.h" 1417101Sbloom #include "quota.h" 1517101Sbloom #include "uio.h" 1617101Sbloom #include "socket.h" 1717101Sbloom #include "socketvar.h" 1817101Sbloom #include "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; 5116694Smckusick } *uap = (struct a *)u.u_ap; 5216694Smckusick register struct nameidata *ndp = &u.u_nd; 536254Sroot 5416694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 5516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 5616694Smckusick ndp->ni_dirp = uap->fname; 5716694Smckusick 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 8716694Smckusick 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 10016694Smckusick 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 */ 10816694Smckusick copen(mode, arg, fname) 10912756Ssam register int mode; 11012756Ssam int arg; 11116694Smckusick caddr_t fname; 11212756Ssam { 1136254Sroot register struct inode *ip; 1146254Sroot register struct file *fp; 11516694Smckusick 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 12416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 12516694Smckusick ndp->ni_dirp = fname; 12612756Ssam if (mode&FCREAT) { 12718416Smckusick if (mode & FEXCL) 12818416Smckusick ndp->ni_nameiop = CREATE; 12918416Smckusick else 13018416Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 13116694Smckusick ip = namei(ndp); 13212756Ssam if (ip == NULL) { 13312756Ssam if (u.u_error) 13412756Ssam return; 13516694Smckusick ip = maknode(arg&07777&(~ISVTX), ndp); 13612756Ssam if (ip == NULL) 13712756Ssam return; 13812756Ssam mode &= ~FTRUNC; 13912756Ssam } else { 14012756Ssam if (mode&FEXCL) { 14112756Ssam u.u_error = EEXIST; 14212756Ssam iput(ip); 14312756Ssam return; 14412756Ssam } 14512756Ssam mode &= ~FCREAT; 14612756Ssam } 14712756Ssam } else { 14816694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 14916694Smckusick ip = namei(ndp); 15012756Ssam if (ip == NULL) 15112756Ssam return; 15212756Ssam } 15312756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 15412756Ssam u.u_error = EOPNOTSUPP; 15512756Ssam goto bad; 15612756Ssam } 15712756Ssam if ((mode&FCREAT) == 0) { 1586254Sroot if (mode&FREAD) 1597701Ssam if (access(ip, IREAD)) 1607701Ssam goto bad; 16116032Skarels if (mode&(FWRITE|FTRUNC)) { 1627701Ssam if (access(ip, IWRITE)) 1637701Ssam goto bad; 1647701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1656254Sroot u.u_error = EISDIR; 1667701Ssam goto bad; 1677701Ssam } 1686254Sroot } 1696254Sroot } 17012756Ssam fp = falloc(); 17112756Ssam if (fp == NULL) 17212756Ssam goto bad; 17312756Ssam if (mode&FTRUNC) 1749167Ssam itrunc(ip, (u_long)0); 17516664Smckusick IUNLOCK(ip); 17612756Ssam fp->f_flag = mode&FMASK; 17712756Ssam fp->f_type = DTYPE_INODE; 17812756Ssam fp->f_ops = &inodeops; 17912756Ssam fp->f_data = (caddr_t)ip; 1806254Sroot i = u.u_r.r_val1; 18112756Ssam if (setjmp(&u.u_qsave)) { 18212756Ssam if (u.u_error == 0) 18312756Ssam u.u_error = EINTR; 18412756Ssam u.u_ofile[i] = NULL; 18512756Ssam closef(fp); 18612756Ssam return; 18712756Ssam } 1888559Sroot u.u_error = openi(ip, mode); 18912756Ssam if (u.u_error == 0) 1906254Sroot return; 1916254Sroot u.u_ofile[i] = NULL; 1926254Sroot fp->f_count--; 1937142Smckusick irele(ip); 1947701Ssam return; 1957701Ssam bad: 1967701Ssam iput(ip); 1976254Sroot } 1986254Sroot 1996254Sroot /* 2006254Sroot * Mknod system call 2016254Sroot */ 2026254Sroot mknod() 2036254Sroot { 2046254Sroot register struct inode *ip; 2056254Sroot register struct a { 2066254Sroot char *fname; 2076254Sroot int fmode; 2086254Sroot int dev; 20916694Smckusick } *uap = (struct a *)u.u_ap; 21016694Smckusick register struct nameidata *ndp = &u.u_nd; 2116254Sroot 21212756Ssam if (!suser()) 21312756Ssam return; 21416694Smckusick ndp->ni_nameiop = CREATE; 21516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 21616694Smckusick ndp->ni_dirp = uap->fname; 21716694Smckusick ip = namei(ndp); 21812756Ssam if (ip != NULL) { 21912756Ssam u.u_error = EEXIST; 22012756Ssam goto out; 2216254Sroot } 2226254Sroot if (u.u_error) 2236254Sroot return; 22416694Smckusick ip = maknode(uap->fmode, ndp); 2256254Sroot if (ip == NULL) 2266254Sroot return; 22712756Ssam switch (ip->i_mode & IFMT) { 22812756Ssam 22915093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 23012756Ssam case IFCHR: 23112756Ssam case IFBLK: 23212756Ssam if (uap->dev) { 23312756Ssam /* 23412756Ssam * Want to be able to use this to make badblock 23512756Ssam * inodes, so don't truncate the dev number. 23612756Ssam */ 23712756Ssam ip->i_rdev = uap->dev; 23812756Ssam ip->i_flag |= IACC|IUPD|ICHG; 23912756Ssam } 2406254Sroot } 2416254Sroot 2426254Sroot out: 2436254Sroot iput(ip); 2446254Sroot } 2456254Sroot 2466254Sroot /* 2476254Sroot * link system call 2486254Sroot */ 2496254Sroot link() 2506254Sroot { 2516254Sroot register struct inode *ip, *xp; 2526254Sroot register struct a { 2536254Sroot char *target; 2546254Sroot char *linkname; 25516694Smckusick } *uap = (struct a *)u.u_ap; 25616694Smckusick register struct nameidata *ndp = &u.u_nd; 2576254Sroot 25816694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 25916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 26016694Smckusick ndp->ni_dirp = uap->target; 26116694Smckusick ip = namei(ndp); /* well, this routine is doomed anyhow */ 2626254Sroot if (ip == NULL) 2636254Sroot return; 2649167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2657439Sroot iput(ip); 2667439Sroot return; 2677439Sroot } 2686254Sroot ip->i_nlink++; 2696254Sroot ip->i_flag |= ICHG; 2708673Sroot iupdat(ip, &time, &time, 1); 27116664Smckusick IUNLOCK(ip); 27216694Smckusick ndp->ni_nameiop = CREATE; 27316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 27416694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 27516694Smckusick xp = namei(ndp); 2766254Sroot if (xp != NULL) { 2776254Sroot u.u_error = EEXIST; 2786254Sroot iput(xp); 2796254Sroot goto out; 2806254Sroot } 2816254Sroot if (u.u_error) 2826254Sroot goto out; 28316694Smckusick if (ndp->ni_pdir->i_dev != ip->i_dev) { 28416694Smckusick iput(ndp->ni_pdir); 2856254Sroot u.u_error = EXDEV; 2866254Sroot goto out; 2876254Sroot } 28816694Smckusick u.u_error = direnter(ip, ndp); 2896254Sroot out: 2906254Sroot if (u.u_error) { 2916254Sroot ip->i_nlink--; 2926254Sroot ip->i_flag |= ICHG; 2936254Sroot } 2947142Smckusick irele(ip); 2956254Sroot } 2966254Sroot 2976254Sroot /* 2986254Sroot * symlink -- make a symbolic link 2996254Sroot */ 3006254Sroot symlink() 3016254Sroot { 3026254Sroot register struct a { 3036254Sroot char *target; 3046254Sroot char *linkname; 30516694Smckusick } *uap = (struct a *)u.u_ap; 3066254Sroot register struct inode *ip; 3076254Sroot register char *tp; 3086254Sroot register c, nc; 30916694Smckusick register struct nameidata *ndp = &u.u_nd; 3106254Sroot 3116254Sroot tp = uap->target; 3126254Sroot nc = 0; 3136254Sroot while (c = fubyte(tp)) { 3146254Sroot if (c < 0) { 3156254Sroot u.u_error = EFAULT; 3166254Sroot return; 3176254Sroot } 3186254Sroot tp++; 3196254Sroot nc++; 3206254Sroot } 32116694Smckusick ndp->ni_nameiop = CREATE; 32216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 32316694Smckusick ndp->ni_dirp = uap->linkname; 32416694Smckusick ip = namei(ndp); 3256254Sroot if (ip) { 3266254Sroot iput(ip); 3276254Sroot u.u_error = EEXIST; 3286254Sroot return; 3296254Sroot } 3306254Sroot if (u.u_error) 3316254Sroot return; 33216694Smckusick ip = maknode(IFLNK | 0777, ndp); 3336254Sroot if (ip == NULL) 3346254Sroot return; 3357826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3369167Ssam /* handle u.u_error != 0 */ 3376254Sroot iput(ip); 3386254Sroot } 3396254Sroot 3406254Sroot /* 3416254Sroot * Unlink system call. 3426254Sroot * Hard to avoid races here, especially 3436254Sroot * in unlinking directories. 3446254Sroot */ 3456254Sroot unlink() 3466254Sroot { 3476254Sroot struct a { 3486254Sroot char *fname; 34916694Smckusick } *uap = (struct a *)u.u_ap; 3509167Ssam register struct inode *ip, *dp; 35116694Smckusick register struct nameidata *ndp = &u.u_nd; 3526254Sroot 35316694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 35416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 35516694Smckusick ndp->ni_dirp = uap->fname; 35616694Smckusick ip = namei(ndp); 3579167Ssam if (ip == NULL) 3586254Sroot return; 35916694Smckusick dp = ndp->ni_pdir; 3609167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3616254Sroot goto out; 3626254Sroot /* 3636254Sroot * Don't unlink a mounted file. 3646254Sroot */ 3659167Ssam if (ip->i_dev != dp->i_dev) { 3666254Sroot u.u_error = EBUSY; 3676254Sroot goto out; 3686254Sroot } 3696254Sroot if (ip->i_flag&ITEXT) 3706254Sroot xrele(ip); /* try once to free text */ 37116694Smckusick if (dirremove(ndp)) { 3727535Sroot ip->i_nlink--; 3737535Sroot ip->i_flag |= ICHG; 3746254Sroot } 3756254Sroot out: 3769167Ssam if (dp == ip) 3777142Smckusick irele(ip); 3787142Smckusick else 3797142Smckusick iput(ip); 3809167Ssam iput(dp); 3816254Sroot } 3826254Sroot 3836254Sroot /* 3846254Sroot * Seek system call 3856254Sroot */ 3868040Sroot lseek() 3876254Sroot { 3886254Sroot register struct file *fp; 3896254Sroot register struct a { 3907701Ssam int fd; 3916254Sroot off_t off; 3926254Sroot int sbase; 39316694Smckusick } *uap = (struct a *)u.u_ap; 3946254Sroot 39516540Ssam GETF(fp, uap->fd); 39616540Ssam if (fp->f_type != DTYPE_INODE) { 39716540Ssam u.u_error = ESPIPE; 3986254Sroot return; 39916540Ssam } 40013878Ssam switch (uap->sbase) { 40113878Ssam 40213878Ssam case L_INCR: 40313878Ssam fp->f_offset += uap->off; 40413878Ssam break; 40513878Ssam 40613878Ssam case L_XTND: 40713878Ssam fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; 40813878Ssam break; 40913878Ssam 41013878Ssam case L_SET: 41113878Ssam fp->f_offset = uap->off; 41213878Ssam break; 41313878Ssam 41413878Ssam default: 41513878Ssam u.u_error = EINVAL; 41613878Ssam return; 41713878Ssam } 41813878Ssam u.u_r.r_off = fp->f_offset; 4196254Sroot } 4206254Sroot 4216254Sroot /* 4226254Sroot * Access system call 4236254Sroot */ 4246254Sroot saccess() 4256254Sroot { 4266254Sroot register svuid, svgid; 4276254Sroot register struct inode *ip; 4286254Sroot register struct a { 4296254Sroot char *fname; 4306254Sroot int fmode; 43116694Smckusick } *uap = (struct a *)u.u_ap; 43216694Smckusick register struct nameidata *ndp = &u.u_nd; 4336254Sroot 4346254Sroot svuid = u.u_uid; 4356254Sroot svgid = u.u_gid; 4366254Sroot u.u_uid = u.u_ruid; 4376254Sroot u.u_gid = u.u_rgid; 43816694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 43916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 44016694Smckusick ndp->ni_dirp = uap->fname; 44116694Smckusick ip = namei(ndp); 4426254Sroot if (ip != NULL) { 44312756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4447701Ssam goto done; 44512756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4467701Ssam goto done; 44712756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4487701Ssam goto done; 4497701Ssam done: 4506254Sroot iput(ip); 4516254Sroot } 4526254Sroot u.u_uid = svuid; 4536254Sroot u.u_gid = svgid; 4546254Sroot } 4556254Sroot 4566254Sroot /* 4576574Smckusic * Stat system call. This version follows links. 45837Sbill */ 45937Sbill stat() 46037Sbill { 46137Sbill 46216694Smckusick stat1(FOLLOW); 46337Sbill } 46437Sbill 46537Sbill /* 4666574Smckusic * Lstat system call. This version does not follow links. 4675992Swnj */ 4685992Swnj lstat() 4695992Swnj { 47012756Ssam 47116694Smckusick stat1(NOFOLLOW); 47212756Ssam } 47312756Ssam 47412756Ssam stat1(follow) 47512756Ssam int follow; 47612756Ssam { 4775992Swnj register struct inode *ip; 4785992Swnj register struct a { 4795992Swnj char *fname; 48012756Ssam struct stat *ub; 48116694Smckusick } *uap = (struct a *)u.u_ap; 48212756Ssam struct stat sb; 48316694Smckusick register struct nameidata *ndp = &u.u_nd; 4845992Swnj 48516694Smckusick ndp->ni_nameiop = LOOKUP | follow; 48616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 48716694Smckusick ndp->ni_dirp = uap->fname; 48816694Smckusick ip = namei(ndp); 4895992Swnj if (ip == NULL) 4905992Swnj return; 49113043Ssam (void) ino_stat(ip, &sb); 4925992Swnj iput(ip); 49312756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4945992Swnj } 4955992Swnj 4965992Swnj /* 4975992Swnj * Return target name of a symbolic link 49837Sbill */ 4995992Swnj readlink() 5005992Swnj { 5015992Swnj register struct inode *ip; 5025992Swnj register struct a { 5035992Swnj char *name; 5045992Swnj char *buf; 5055992Swnj int count; 5067826Sroot } *uap = (struct a *)u.u_ap; 50716694Smckusick register struct nameidata *ndp = &u.u_nd; 5087826Sroot int resid; 5095992Swnj 51016694Smckusick ndp->ni_nameiop = LOOKUP; 51116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 51216694Smckusick ndp->ni_dirp = uap->name; 51316694Smckusick ip = namei(ndp); 5145992Swnj if (ip == NULL) 5155992Swnj return; 5165992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 517*21015Smckusick u.u_error = EINVAL; 5185992Swnj goto out; 5195992Swnj } 5207826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 5215992Swnj out: 5225992Swnj iput(ip); 5237826Sroot u.u_r.r_val1 = uap->count - resid; 5245992Swnj } 5255992Swnj 5269167Ssam /* 5279167Ssam * Change mode of a file given path name. 5289167Ssam */ 5296254Sroot chmod() 5305992Swnj { 5317701Ssam struct inode *ip; 5327701Ssam struct a { 5336254Sroot char *fname; 5346254Sroot int fmode; 53516694Smckusick } *uap = (struct a *)u.u_ap; 5365992Swnj 53716694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 5385992Swnj return; 539*21015Smckusick u.u_error = chmod1(ip, uap->fmode); 5409167Ssam iput(ip); 5417701Ssam } 5427439Sroot 5439167Ssam /* 5449167Ssam * Change mode of a file given a file descriptor. 5459167Ssam */ 5467701Ssam fchmod() 5477701Ssam { 5487701Ssam struct a { 5497701Ssam int fd; 5507701Ssam int fmode; 55116694Smckusick } *uap = (struct a *)u.u_ap; 5527701Ssam register struct inode *ip; 5537701Ssam register struct file *fp; 5547701Ssam 55512756Ssam fp = getinode(uap->fd); 5567701Ssam if (fp == NULL) 5577701Ssam return; 55812756Ssam ip = (struct inode *)fp->f_data; 5599167Ssam if (u.u_uid != ip->i_uid && !suser()) 5609167Ssam return; 56116664Smckusick ILOCK(ip); 562*21015Smckusick u.u_error = chmod1(ip, uap->fmode); 56316664Smckusick IUNLOCK(ip); 5647701Ssam } 5657701Ssam 5669167Ssam /* 5679167Ssam * Change the mode on a file. 5689167Ssam * Inode must be locked before calling. 5699167Ssam */ 5707701Ssam chmod1(ip, mode) 5717701Ssam register struct inode *ip; 5727701Ssam register int mode; 5737701Ssam { 5747868Sroot 575*21015Smckusick if (ip->i_fs->fs_ronly) 576*21015Smckusick return (EROFS); 5776254Sroot ip->i_mode &= ~07777; 5787439Sroot if (u.u_uid) { 579*21015Smckusick if ((ip->i_mode & IFMT) != IFDIR) 580*21015Smckusick mode &= ~ISVTX; 58111811Ssam if (!groupmember(ip->i_gid)) 58211811Ssam mode &= ~ISGID; 5837439Sroot } 5847701Ssam ip->i_mode |= mode&07777; 5856254Sroot ip->i_flag |= ICHG; 5866254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5876254Sroot xrele(ip); 588*21015Smckusick return (0); 5895992Swnj } 5905992Swnj 5919167Ssam /* 5929167Ssam * Set ownership given a path name. 5939167Ssam */ 5946254Sroot chown() 59537Sbill { 5967701Ssam struct inode *ip; 5977701Ssam struct a { 5986254Sroot char *fname; 5996254Sroot int uid; 6006254Sroot int gid; 60116694Smckusick } *uap = (struct a *)u.u_ap; 60237Sbill 60316694Smckusick if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL) 60437Sbill return; 60511811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 6069167Ssam iput(ip); 6077701Ssam } 6087439Sroot 6099167Ssam /* 6109167Ssam * Set ownership given a file descriptor. 6119167Ssam */ 6127701Ssam fchown() 6137701Ssam { 6147701Ssam struct a { 6157701Ssam int fd; 6167701Ssam int uid; 6177701Ssam int gid; 61816694Smckusick } *uap = (struct a *)u.u_ap; 6197701Ssam register struct inode *ip; 6207701Ssam register struct file *fp; 6217701Ssam 62212756Ssam fp = getinode(uap->fd); 6237701Ssam if (fp == NULL) 6247701Ssam return; 62512756Ssam ip = (struct inode *)fp->f_data; 62611821Ssam if (!suser()) 6279167Ssam return; 62816664Smckusick ILOCK(ip); 62911811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 63016664Smckusick IUNLOCK(ip); 6317701Ssam } 6327701Ssam 6337701Ssam /* 6347701Ssam * Perform chown operation on inode ip; 6357701Ssam * inode must be locked prior to call. 6367701Ssam */ 6377701Ssam chown1(ip, uid, gid) 6387701Ssam register struct inode *ip; 6397701Ssam int uid, gid; 6407701Ssam { 6417701Ssam #ifdef QUOTA 6427701Ssam register long change; 64311811Ssam #endif 6447701Ssam 645*21015Smckusick if (ip->i_fs->fs_ronly) 646*21015Smckusick return (EROFS); 64711811Ssam if (uid == -1) 64811811Ssam uid = ip->i_uid; 64911811Ssam if (gid == -1) 65011811Ssam gid = ip->i_gid; 65111811Ssam #ifdef QUOTA 65214385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6537482Skre change = 0; 65412646Ssam else 65512646Ssam change = ip->i_blocks; 65612646Ssam (void) chkdq(ip, -change, 1); 65712646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6587482Skre dqrele(ip->i_dquot); 6597482Skre #endif 66011811Ssam ip->i_uid = uid; 66111811Ssam ip->i_gid = gid; 6626254Sroot ip->i_flag |= ICHG; 6636254Sroot if (u.u_ruid != 0) 6646254Sroot ip->i_mode &= ~(ISUID|ISGID); 6657701Ssam #ifdef QUOTA 6667482Skre ip->i_dquot = inoquota(ip); 66712646Ssam (void) chkdq(ip, change, 1); 66812646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 66912646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 67012646Ssam #else 67112646Ssam return (0); 6727482Skre #endif 67337Sbill } 67437Sbill 67511811Ssam utimes() 67611811Ssam { 67711811Ssam register struct a { 67811811Ssam char *fname; 67911811Ssam struct timeval *tptr; 68011811Ssam } *uap = (struct a *)u.u_ap; 68111811Ssam register struct inode *ip; 68211811Ssam struct timeval tv[2]; 68311811Ssam 68416694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 68511811Ssam return; 686*21015Smckusick if (ip->i_fs->fs_ronly) { 687*21015Smckusick u.u_error = EROFS; 688*21015Smckusick iput(ip); 689*21015Smckusick return; 690*21015Smckusick } 69111811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 69211811Ssam if (u.u_error == 0) { 69311811Ssam ip->i_flag |= IACC|IUPD|ICHG; 69411811Ssam iupdat(ip, &tv[0], &tv[1], 0); 69511811Ssam } 69611811Ssam iput(ip); 69711811Ssam } 69811811Ssam 6999167Ssam /* 7009167Ssam * Flush any pending I/O. 7019167Ssam */ 7026254Sroot sync() 70337Sbill { 70437Sbill 7058673Sroot update(); 70637Sbill } 7077535Sroot 7089167Ssam /* 7099167Ssam * Truncate a file given its path name. 7109167Ssam */ 7117701Ssam truncate() 7127701Ssam { 7137701Ssam struct a { 7147701Ssam char *fname; 7159167Ssam u_long length; 7167826Sroot } *uap = (struct a *)u.u_ap; 7177701Ssam struct inode *ip; 71816694Smckusick register struct nameidata *ndp = &u.u_nd; 7197701Ssam 72016694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72216694Smckusick ndp->ni_dirp = uap->fname; 72316694Smckusick ip = namei(ndp); 7247701Ssam if (ip == NULL) 7257701Ssam return; 7267701Ssam if (access(ip, IWRITE)) 7277701Ssam goto bad; 7287701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7297701Ssam u.u_error = EISDIR; 7307701Ssam goto bad; 7317701Ssam } 7327701Ssam itrunc(ip, uap->length); 7337701Ssam bad: 7347701Ssam iput(ip); 7357701Ssam } 7367701Ssam 7379167Ssam /* 7389167Ssam * Truncate a file given a file descriptor. 7399167Ssam */ 7407701Ssam ftruncate() 7417701Ssam { 7427701Ssam struct a { 7437701Ssam int fd; 7449167Ssam u_long length; 7457826Sroot } *uap = (struct a *)u.u_ap; 7467701Ssam struct inode *ip; 7477701Ssam struct file *fp; 7487701Ssam 74912756Ssam fp = getinode(uap->fd); 7507701Ssam if (fp == NULL) 7517701Ssam return; 7527701Ssam if ((fp->f_flag&FWRITE) == 0) { 7537701Ssam u.u_error = EINVAL; 7547701Ssam return; 7557701Ssam } 75612756Ssam ip = (struct inode *)fp->f_data; 75716664Smckusick ILOCK(ip); 7587701Ssam itrunc(ip, uap->length); 75916664Smckusick IUNLOCK(ip); 7607701Ssam } 7617701Ssam 7629167Ssam /* 7639167Ssam * Synch an open file. 7649167Ssam */ 7659167Ssam fsync() 7669167Ssam { 7679167Ssam struct a { 7689167Ssam int fd; 7699167Ssam } *uap = (struct a *)u.u_ap; 7709167Ssam struct inode *ip; 7719167Ssam struct file *fp; 7729167Ssam 77312756Ssam fp = getinode(uap->fd); 7749167Ssam if (fp == NULL) 7759167Ssam return; 77612756Ssam ip = (struct inode *)fp->f_data; 77716664Smckusick ILOCK(ip); 7789167Ssam syncip(ip); 77916664Smckusick IUNLOCK(ip); 7809167Ssam } 7819167Ssam 7829167Ssam /* 7839167Ssam * Rename system call. 7849167Ssam * rename("foo", "bar"); 7859167Ssam * is essentially 7869167Ssam * unlink("bar"); 7879167Ssam * link("foo", "bar"); 7889167Ssam * unlink("foo"); 7899167Ssam * but ``atomically''. Can't do full commit without saving state in the 7909167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7919167Ssam * always guarantee the target exists. 7929167Ssam * 7939167Ssam * Basic algorithm is: 7949167Ssam * 7959167Ssam * 1) Bump link count on source while we're linking it to the 7969167Ssam * target. This also insure the inode won't be deleted out 79716776Smckusick * from underneath us while we work (it may be truncated by 79816776Smckusick * a concurrent `trunc' or `open' for creation). 7999167Ssam * 2) Link source to destination. If destination already exists, 8009167Ssam * delete it first. 80116776Smckusick * 3) Unlink source reference to inode if still around. If a 80216776Smckusick * directory was moved and the parent of the destination 8039167Ssam * is different from the source, patch the ".." entry in the 8049167Ssam * directory. 8059167Ssam * 8069167Ssam * Source and destination must either both be directories, or both 8079167Ssam * not be directories. If target is a directory, it must be empty. 8089167Ssam */ 8097701Ssam rename() 8107701Ssam { 8117701Ssam struct a { 8127701Ssam char *from; 8137701Ssam char *to; 81416694Smckusick } *uap = (struct a *)u.u_ap; 8159167Ssam register struct inode *ip, *xp, *dp; 81616776Smckusick struct dirtemplate dirbuf; 81716776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 81816694Smckusick register struct nameidata *ndp = &u.u_nd; 81910051Ssam int error = 0; 8207701Ssam 82116694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 82216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82316694Smckusick ndp->ni_dirp = uap->from; 82416694Smckusick ip = namei(ndp); 8259167Ssam if (ip == NULL) 8269167Ssam return; 82716694Smckusick dp = ndp->ni_pdir; 8289167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 8299167Ssam register struct direct *d; 8309167Ssam 83116694Smckusick d = &ndp->ni_dent; 8329167Ssam /* 83311641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 8349167Ssam */ 83511641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 83611641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 83716776Smckusick (dp == ip) || (ip->i_flag & IRENAME)) { 83811641Ssam iput(dp); 83911641Ssam if (dp == ip) 84011641Ssam irele(ip); 84111641Ssam else 84210051Ssam iput(ip); 84311641Ssam u.u_error = EINVAL; 84411641Ssam return; 8459167Ssam } 84616776Smckusick ip->i_flag |= IRENAME; 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); 86116664Smckusick IUNLOCK(ip); 8629167Ssam 8639167Ssam /* 8649167Ssam * When the target exists, both the directory 8659167Ssam * and target inodes are returned locked. 8669167Ssam */ 86716694Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE; 86816694Smckusick ndp->ni_dirp = (caddr_t)uap->to; 86916694Smckusick xp = namei(ndp); 87010051Ssam if (u.u_error) { 87110051Ssam error = u.u_error; 8729167Ssam goto out; 87310051Ssam } 87416694Smckusick dp = ndp->ni_pdir; 8759167Ssam /* 87611641Ssam * If ".." must be changed (ie the directory gets a new 87712816Smckusick * parent) then the source directory must not be in the 87812816Smckusick * directory heirarchy above the target, as this would 87912816Smckusick * orphan everything below the source directory. Also 88012816Smckusick * the user must have write permission in the source so 88112816Smckusick * as to be able to change "..". We must repeat the call 88212816Smckusick * to namei, as the parent directory is unlocked by the 88312816Smckusick * call to checkpath(). 88411641Ssam */ 88516776Smckusick if (oldparent != dp->i_number) 88616776Smckusick newparent = dp->i_number; 88716776Smckusick if (doingdirectory && newparent) { 88812816Smckusick if (access(ip, IWRITE)) 88912816Smckusick goto bad; 89012816Smckusick do { 89116694Smckusick dp = ndp->ni_pdir; 89212816Smckusick if (xp != NULL) 89312816Smckusick iput(xp); 89412816Smckusick u.u_error = checkpath(ip, dp); 89512816Smckusick if (u.u_error) 89612816Smckusick goto out; 89716694Smckusick xp = namei(ndp); 89812816Smckusick if (u.u_error) { 89912816Smckusick error = u.u_error; 90012816Smckusick goto out; 90112816Smckusick } 90216694Smckusick } while (dp != ndp->ni_pdir); 90312816Smckusick } 90411641Ssam /* 9059167Ssam * 2) If target doesn't exist, link the target 9069167Ssam * to the source and unlink the source. 9079167Ssam * Otherwise, rewrite the target directory 9089167Ssam * entry to reference the source inode and 9099167Ssam * expunge the original entry's existence. 9109167Ssam */ 9119167Ssam if (xp == NULL) { 9129167Ssam if (dp->i_dev != ip->i_dev) { 91310051Ssam error = EXDEV; 9149167Ssam goto bad; 9159167Ssam } 9169167Ssam /* 91716776Smckusick * Account for ".." in new directory. 91816776Smckusick * When source and destination have the same 91916776Smckusick * parent we don't fool with the link count. 9209167Ssam */ 92116776Smckusick if (doingdirectory && newparent) { 9229167Ssam dp->i_nlink++; 9239167Ssam dp->i_flag |= ICHG; 9249167Ssam iupdat(dp, &time, &time, 1); 9259167Ssam } 92616694Smckusick error = direnter(ip, ndp); 92710850Ssam if (error) 9289167Ssam goto out; 9299167Ssam } else { 9309167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 93110051Ssam error = EXDEV; 9329167Ssam goto bad; 9339167Ssam } 9349167Ssam /* 93510590Ssam * Short circuit rename(foo, foo). 93610590Ssam */ 93710590Ssam if (xp->i_number == ip->i_number) 93810590Ssam goto bad; 93910590Ssam /* 94010051Ssam * Target must be empty if a directory 94110051Ssam * and have no links to it. 9429167Ssam * Also, insure source and target are 9439167Ssam * compatible (both directories, or both 9449167Ssam * not directories). 9459167Ssam */ 9469167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 94716776Smckusick if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) { 94810051Ssam error = ENOTEMPTY; 9499167Ssam goto bad; 9509167Ssam } 9519167Ssam if (!doingdirectory) { 95210051Ssam error = ENOTDIR; 9539167Ssam goto bad; 9549167Ssam } 95516776Smckusick cacheinval(dp); 9569167Ssam } else if (doingdirectory) { 95710051Ssam error = EISDIR; 9589167Ssam goto bad; 9599167Ssam } 96016694Smckusick dirrewrite(dp, ip, ndp); 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 97216776Smckusick * it above, as the remaining link would point to 97316776Smckusick * a directory without "." or ".." entries. 9749167Ssam */ 97510051Ssam xp->i_nlink--; 9769167Ssam if (doingdirectory) { 97710051Ssam if (--xp->i_nlink != 0) 97810051Ssam panic("rename: linked directory"); 9799167Ssam itrunc(xp, (u_long)0); 98010051Ssam } 9819167Ssam xp->i_flag |= ICHG; 9829167Ssam iput(xp); 98310246Ssam xp = NULL; 9849167Ssam } 9859167Ssam 9869167Ssam /* 9879167Ssam * 3) Unlink the source. 9889167Ssam */ 98916694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 99016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 99116694Smckusick ndp->ni_dirp = uap->from; 99216776Smckusick xp = namei(ndp); 99317758Smckusick if (xp != NULL) 99417758Smckusick dp = ndp->ni_pdir; 99517758Smckusick else 99617758Smckusick dp = NULL; 9979167Ssam /* 99816776Smckusick * Insure that the directory entry still exists and has not 99916776Smckusick * changed while the new name has been entered. If the source is 100016776Smckusick * a file then the entry may have been unlinked or renamed. In 100116776Smckusick * either case there is no further work to be done. If the source 100216776Smckusick * is a directory then it cannot have been rmdir'ed; its link 100316776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 100416776Smckusick * The IRENAME flag insures that it cannot be moved by another 100516776Smckusick * rename. 10069167Ssam */ 100717758Smckusick if (xp != ip) { 100816776Smckusick if (doingdirectory) 100917758Smckusick panic("rename: lost dir entry"); 101016776Smckusick } else { 10119167Ssam /* 101216776Smckusick * If the source is a directory with a 101316776Smckusick * new parent, the link count of the old 101416776Smckusick * parent directory must be decremented 101516776Smckusick * and ".." set to point to the new parent. 10169167Ssam */ 101716776Smckusick if (doingdirectory && newparent) { 10189167Ssam dp->i_nlink--; 10199167Ssam dp->i_flag |= ICHG; 102016776Smckusick error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf, 102116776Smckusick sizeof (struct dirtemplate), (off_t)0, 1, 102216776Smckusick (int *)0); 102316776Smckusick if (error == 0) { 102416776Smckusick if (dirbuf.dotdot_namlen != 2 || 102516776Smckusick dirbuf.dotdot_name[0] != '.' || 102616776Smckusick dirbuf.dotdot_name[1] != '.') { 102716776Smckusick printf("rename: mangled dir\n"); 102816776Smckusick } else { 102916776Smckusick dirbuf.dotdot_ino = newparent; 103016776Smckusick (void) rdwri(UIO_WRITE, xp, 103116776Smckusick (caddr_t)&dirbuf, 103216776Smckusick sizeof (struct dirtemplate), 103316776Smckusick (off_t)0, 1, (int *)0); 103416776Smckusick cacheinval(dp); 103516776Smckusick } 103616776Smckusick } 10379167Ssam } 103816694Smckusick if (dirremove(ndp)) { 103916776Smckusick xp->i_nlink--; 104016776Smckusick xp->i_flag |= ICHG; 10419167Ssam } 104216776Smckusick xp->i_flag &= ~IRENAME; 104316776Smckusick if (error == 0) /* XXX conservative */ 104410051Ssam error = u.u_error; 10459167Ssam } 10469167Ssam if (dp) 10479167Ssam iput(dp); 104816776Smckusick if (xp) 104916776Smckusick iput(xp); 105016776Smckusick irele(ip); 105116776Smckusick if (error) 105216776Smckusick u.u_error = error; 105316776Smckusick return; 10549167Ssam 10559167Ssam bad: 105610246Ssam iput(dp); 10579167Ssam bad1: 10589167Ssam if (xp) 105910246Ssam iput(xp); 10609167Ssam out: 10619167Ssam ip->i_nlink--; 10629167Ssam ip->i_flag |= ICHG; 10639167Ssam irele(ip); 106410051Ssam if (error) 106510051Ssam u.u_error = error; 10667701Ssam } 10677701Ssam 10687535Sroot /* 10697535Sroot * Make a new file. 10707535Sroot */ 10717535Sroot struct inode * 107216694Smckusick maknode(mode, ndp) 10737535Sroot int mode; 107416694Smckusick register struct nameidata *ndp; 10757535Sroot { 10767535Sroot register struct inode *ip; 107716694Smckusick register struct inode *pdir = ndp->ni_pdir; 10787535Sroot ino_t ipref; 10797535Sroot 10807535Sroot if ((mode & IFMT) == IFDIR) 108116694Smckusick ipref = dirpref(pdir->i_fs); 10827535Sroot else 108316694Smckusick ipref = pdir->i_number; 108416694Smckusick ip = ialloc(pdir, ipref, mode); 10857535Sroot if (ip == NULL) { 108616694Smckusick iput(pdir); 10877701Ssam return (NULL); 10887535Sroot } 10897701Ssam #ifdef QUOTA 10907535Sroot if (ip->i_dquot != NODQUOT) 10917535Sroot panic("maknode: dquot"); 10927535Sroot #endif 10937535Sroot ip->i_flag |= IACC|IUPD|ICHG; 10947535Sroot if ((mode & IFMT) == 0) 10957535Sroot mode |= IFREG; 10967535Sroot ip->i_mode = mode & ~u.u_cmask; 10977535Sroot ip->i_nlink = 1; 10987535Sroot ip->i_uid = u.u_uid; 109916694Smckusick ip->i_gid = pdir->i_gid; 110011811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 110111811Ssam ip->i_mode &= ~ISGID; 11027701Ssam #ifdef QUOTA 11037535Sroot ip->i_dquot = inoquota(ip); 11047535Sroot #endif 11057535Sroot 11067535Sroot /* 11077535Sroot * Make sure inode goes to disk before directory entry. 11087535Sroot */ 11098673Sroot iupdat(ip, &time, &time, 1); 111016694Smckusick u.u_error = direnter(ip, ndp); 11117535Sroot if (u.u_error) { 11127535Sroot /* 111310850Ssam * Write error occurred trying to update directory 111410850Ssam * so must deallocate the inode. 11157535Sroot */ 11167535Sroot ip->i_nlink = 0; 11177535Sroot ip->i_flag |= ICHG; 11187535Sroot iput(ip); 11197701Ssam return (NULL); 11207535Sroot } 11217701Ssam return (ip); 11227535Sroot } 112312756Ssam 112412756Ssam /* 112512756Ssam * A virgin directory (no blushing please). 112612756Ssam */ 112712756Ssam struct dirtemplate mastertemplate = { 112812756Ssam 0, 12, 1, ".", 112912756Ssam 0, DIRBLKSIZ - 12, 2, ".." 113012756Ssam }; 113112756Ssam 113212756Ssam /* 113312756Ssam * Mkdir system call 113412756Ssam */ 113512756Ssam mkdir() 113612756Ssam { 113712756Ssam struct a { 113812756Ssam char *name; 113912756Ssam int dmode; 114016694Smckusick } *uap = (struct a *)u.u_ap; 114112756Ssam register struct inode *ip, *dp; 114212756Ssam struct dirtemplate dirtemplate; 114316694Smckusick register struct nameidata *ndp = &u.u_nd; 114412756Ssam 114516694Smckusick ndp->ni_nameiop = CREATE; 114616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 114716694Smckusick ndp->ni_dirp = uap->name; 114816694Smckusick ip = namei(ndp); 114912756Ssam if (u.u_error) 115012756Ssam return; 115112756Ssam if (ip != NULL) { 115212756Ssam iput(ip); 115312756Ssam u.u_error = EEXIST; 115412756Ssam return; 115512756Ssam } 115616694Smckusick dp = ndp->ni_pdir; 115712756Ssam uap->dmode &= 0777; 115812756Ssam uap->dmode |= IFDIR; 115912756Ssam /* 116012756Ssam * Must simulate part of maknode here 116112756Ssam * in order to acquire the inode, but 116212756Ssam * not have it entered in the parent 116312756Ssam * directory. The entry is made later 116412756Ssam * after writing "." and ".." entries out. 116512756Ssam */ 116612756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 116712756Ssam if (ip == NULL) { 116812756Ssam iput(dp); 116912756Ssam return; 117012756Ssam } 117112756Ssam #ifdef QUOTA 117212756Ssam if (ip->i_dquot != NODQUOT) 117312756Ssam panic("mkdir: dquot"); 117412756Ssam #endif 117512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 117612756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 117712756Ssam ip->i_nlink = 2; 117812756Ssam ip->i_uid = u.u_uid; 117912756Ssam ip->i_gid = dp->i_gid; 118012756Ssam #ifdef QUOTA 118112756Ssam ip->i_dquot = inoquota(ip); 118212756Ssam #endif 118312756Ssam iupdat(ip, &time, &time, 1); 118412756Ssam 118512756Ssam /* 118612756Ssam * Bump link count in parent directory 118712756Ssam * to reflect work done below. Should 118812756Ssam * be done before reference is created 118912756Ssam * so reparation is possible if we crash. 119012756Ssam */ 119112756Ssam dp->i_nlink++; 119212756Ssam dp->i_flag |= ICHG; 119312756Ssam iupdat(dp, &time, &time, 1); 119412756Ssam 119512756Ssam /* 119612756Ssam * Initialize directory with "." 119712756Ssam * and ".." from static template. 119812756Ssam */ 119912756Ssam dirtemplate = mastertemplate; 120012756Ssam dirtemplate.dot_ino = ip->i_number; 120112756Ssam dirtemplate.dotdot_ino = dp->i_number; 120212756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 120312756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 120412756Ssam if (u.u_error) { 120512756Ssam dp->i_nlink--; 120612756Ssam dp->i_flag |= ICHG; 120712756Ssam goto bad; 120812756Ssam } 120918103Smckusick if (DIRBLKSIZ > ip->i_fs->fs_fsize) 121018103Smckusick panic("mkdir: blksize"); /* XXX - should grow with bmap() */ 121118103Smckusick else 121218103Smckusick ip->i_size = DIRBLKSIZ; 121312756Ssam /* 121412756Ssam * Directory all set up, now 121512756Ssam * install the entry for it in 121612756Ssam * the parent directory. 121712756Ssam */ 121816694Smckusick u.u_error = direnter(ip, ndp); 121912756Ssam dp = NULL; 122012756Ssam if (u.u_error) { 122116694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 122216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122316694Smckusick ndp->ni_dirp = uap->name; 122416694Smckusick dp = namei(ndp); 122512756Ssam if (dp) { 122612756Ssam dp->i_nlink--; 122712756Ssam dp->i_flag |= ICHG; 122812756Ssam } 122912756Ssam } 123012756Ssam bad: 123112756Ssam /* 123212756Ssam * No need to do an explicit itrunc here, 123312756Ssam * irele will do this for us because we set 123412756Ssam * the link count to 0. 123512756Ssam */ 123612756Ssam if (u.u_error) { 123712756Ssam ip->i_nlink = 0; 123812756Ssam ip->i_flag |= ICHG; 123912756Ssam } 124012756Ssam if (dp) 124112756Ssam iput(dp); 124212756Ssam iput(ip); 124312756Ssam } 124412756Ssam 124512756Ssam /* 124612756Ssam * Rmdir system call. 124712756Ssam */ 124812756Ssam rmdir() 124912756Ssam { 125012756Ssam struct a { 125112756Ssam char *name; 125216694Smckusick } *uap = (struct a *)u.u_ap; 125312756Ssam register struct inode *ip, *dp; 125416694Smckusick register struct nameidata *ndp = &u.u_nd; 125512756Ssam 125616694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 125716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 125816694Smckusick ndp->ni_dirp = uap->name; 125916694Smckusick ip = namei(ndp); 126012756Ssam if (ip == NULL) 126112756Ssam return; 126216694Smckusick dp = ndp->ni_pdir; 126312756Ssam /* 126412756Ssam * No rmdir "." please. 126512756Ssam */ 126612756Ssam if (dp == ip) { 126712756Ssam irele(dp); 126812756Ssam iput(ip); 126912756Ssam u.u_error = EINVAL; 127012756Ssam return; 127112756Ssam } 127212756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 127312756Ssam u.u_error = ENOTDIR; 127412756Ssam goto out; 127512756Ssam } 127612756Ssam /* 127712756Ssam * Don't remove a mounted on directory. 127812756Ssam */ 127912756Ssam if (ip->i_dev != dp->i_dev) { 128012756Ssam u.u_error = EBUSY; 128112756Ssam goto out; 128212756Ssam } 128312756Ssam /* 128412756Ssam * Verify the directory is empty (and valid). 128512756Ssam * (Rmdir ".." won't be valid since 128612756Ssam * ".." will contain a reference to 128712756Ssam * the current directory and thus be 128812756Ssam * non-empty.) 128912756Ssam */ 129016776Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) { 129112756Ssam u.u_error = ENOTEMPTY; 129212756Ssam goto out; 129312756Ssam } 129412756Ssam /* 129512756Ssam * Delete reference to directory before purging 129612756Ssam * inode. If we crash in between, the directory 129712756Ssam * will be reattached to lost+found, 129812756Ssam */ 129916694Smckusick if (dirremove(ndp) == 0) 130012756Ssam goto out; 130112756Ssam dp->i_nlink--; 130212756Ssam dp->i_flag |= ICHG; 130316776Smckusick cacheinval(dp); 130412756Ssam iput(dp); 130512756Ssam dp = NULL; 130612756Ssam /* 130712756Ssam * Truncate inode. The only stuff left 130812756Ssam * in the directory is "." and "..". The 130912756Ssam * "." reference is inconsequential since 131012756Ssam * we're quashing it. The ".." reference 131112756Ssam * has already been adjusted above. We've 131212756Ssam * removed the "." reference and the reference 131312756Ssam * in the parent directory, but there may be 131412756Ssam * other hard links so decrement by 2 and 131512756Ssam * worry about them later. 131612756Ssam */ 131712756Ssam ip->i_nlink -= 2; 131812756Ssam itrunc(ip, (u_long)0); 131916739Smckusick cacheinval(ip); 132012756Ssam out: 132112756Ssam if (dp) 132212756Ssam iput(dp); 132312756Ssam iput(ip); 132412756Ssam } 132512756Ssam 132612756Ssam struct file * 132712756Ssam getinode(fdes) 132812756Ssam int fdes; 132912756Ssam { 133016540Ssam struct file *fp; 133112756Ssam 133216540Ssam if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { 133316540Ssam u.u_error = EBADF; 133416540Ssam return ((struct file *)0); 133516540Ssam } 133612756Ssam if (fp->f_type != DTYPE_INODE) { 133712756Ssam u.u_error = EINVAL; 133816540Ssam return ((struct file *)0); 133912756Ssam } 134012756Ssam return (fp); 134112756Ssam } 134212756Ssam 134312756Ssam /* 134412756Ssam * mode mask for creation of files 134512756Ssam */ 134612756Ssam umask() 134712756Ssam { 134812756Ssam register struct a { 134912756Ssam int mask; 135016694Smckusick } *uap = (struct a *)u.u_ap; 135112756Ssam 135212756Ssam u.u_r.r_val1 = u.u_cmask; 135312756Ssam u.u_cmask = uap->mask & 07777; 135412756Ssam } 1355