123405Smckusick /* 223405Smckusick * Copyright (c) 1982 Regents of the University of California. 323405Smckusick * All rights reserved. The Berkeley software License Agreement 423405Smckusick * specifies the terms and conditions for redistribution. 523405Smckusick * 6*24543Smckusick * @(#)vfs_syscalls.c 6.21 (Berkeley) 09/05/85 723405Smckusick */ 837Sbill 917101Sbloom #include "param.h" 1017101Sbloom #include "systm.h" 1117101Sbloom #include "dir.h" 1217101Sbloom #include "user.h" 1317101Sbloom #include "kernel.h" 1417101Sbloom #include "file.h" 1517101Sbloom #include "stat.h" 1617101Sbloom #include "inode.h" 1717101Sbloom #include "fs.h" 1817101Sbloom #include "buf.h" 1917101Sbloom #include "proc.h" 2017101Sbloom #include "quota.h" 2117101Sbloom #include "uio.h" 2217101Sbloom #include "socket.h" 2317101Sbloom #include "socketvar.h" 2417101Sbloom #include "mount.h" 2537Sbill 2612756Ssam extern struct fileops inodeops; 2712756Ssam struct file *getinode(); 2812756Ssam 299167Ssam /* 309167Ssam * Change current working directory (``.''). 319167Ssam */ 326254Sroot chdir() 336254Sroot { 346254Sroot 356254Sroot chdirec(&u.u_cdir); 366254Sroot } 376254Sroot 389167Ssam /* 399167Ssam * Change notion of root (``/'') directory. 409167Ssam */ 416254Sroot chroot() 426254Sroot { 436254Sroot 446254Sroot if (suser()) 456254Sroot chdirec(&u.u_rdir); 466254Sroot } 476254Sroot 489167Ssam /* 499167Ssam * Common routine for chroot and chdir. 509167Ssam */ 516254Sroot chdirec(ipp) 527701Ssam register struct inode **ipp; 536254Sroot { 546254Sroot register struct inode *ip; 556254Sroot struct a { 566254Sroot char *fname; 5716694Smckusick } *uap = (struct a *)u.u_ap; 5816694Smckusick register struct nameidata *ndp = &u.u_nd; 596254Sroot 6016694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 6116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 6216694Smckusick ndp->ni_dirp = uap->fname; 6316694Smckusick ip = namei(ndp); 649167Ssam if (ip == NULL) 656254Sroot return; 669167Ssam if ((ip->i_mode&IFMT) != IFDIR) { 676254Sroot u.u_error = ENOTDIR; 686254Sroot goto bad; 696254Sroot } 709167Ssam if (access(ip, IEXEC)) 716254Sroot goto bad; 7216664Smckusick IUNLOCK(ip); 737142Smckusick if (*ipp) 747142Smckusick irele(*ipp); 756254Sroot *ipp = ip; 766254Sroot return; 776254Sroot 786254Sroot bad: 796254Sroot iput(ip); 806254Sroot } 816254Sroot 8237Sbill /* 836254Sroot * Open system call. 846254Sroot */ 856254Sroot open() 866254Sroot { 8712756Ssam struct a { 886254Sroot char *fname; 897701Ssam int mode; 9012756Ssam int crtmode; 9112756Ssam } *uap = (struct a *) u.u_ap; 926254Sroot 9316694Smckusick copen(uap->mode-FOPEN, uap->crtmode, uap->fname); 946254Sroot } 956254Sroot 966254Sroot /* 976254Sroot * Creat system call. 986254Sroot */ 9912756Ssam creat() 1006254Sroot { 10112756Ssam struct a { 1026254Sroot char *fname; 1036254Sroot int fmode; 10412756Ssam } *uap = (struct a *)u.u_ap; 1056254Sroot 10616694Smckusick copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname); 1076254Sroot } 1086254Sroot 1096254Sroot /* 1106254Sroot * Common code for open and creat. 11112756Ssam * Check permissions, allocate an open file structure, 11212756Ssam * and call the device open routine if any. 1136254Sroot */ 11416694Smckusick copen(mode, arg, fname) 11512756Ssam register int mode; 11612756Ssam int arg; 11716694Smckusick caddr_t fname; 11812756Ssam { 1196254Sroot register struct inode *ip; 1206254Sroot register struct file *fp; 12116694Smckusick register struct nameidata *ndp = &u.u_nd; 122*24543Smckusick int indx; 1236254Sroot 124*24543Smckusick fp = falloc(); 125*24543Smckusick if (fp == NULL) 12612756Ssam return; 127*24543Smckusick indx = u.u_r.r_val1; 12816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 12916694Smckusick ndp->ni_dirp = fname; 13012756Ssam if (mode&FCREAT) { 13118416Smckusick if (mode & FEXCL) 13218416Smckusick ndp->ni_nameiop = CREATE; 13318416Smckusick else 13418416Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 13516694Smckusick ip = namei(ndp); 13612756Ssam if (ip == NULL) { 13712756Ssam if (u.u_error) 138*24543Smckusick goto bad1; 13916694Smckusick ip = maknode(arg&07777&(~ISVTX), ndp); 14012756Ssam if (ip == NULL) 141*24543Smckusick goto bad1; 14212756Ssam mode &= ~FTRUNC; 14312756Ssam } else { 14412756Ssam if (mode&FEXCL) { 14512756Ssam u.u_error = EEXIST; 146*24543Smckusick goto bad; 14712756Ssam } 14812756Ssam mode &= ~FCREAT; 14912756Ssam } 15012756Ssam } else { 15116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 15216694Smckusick ip = namei(ndp); 15312756Ssam if (ip == NULL) 154*24543Smckusick goto bad1; 15512756Ssam } 15612756Ssam if ((ip->i_mode & IFMT) == IFSOCK) { 15712756Ssam u.u_error = EOPNOTSUPP; 15812756Ssam goto bad; 15912756Ssam } 16012756Ssam if ((mode&FCREAT) == 0) { 1616254Sroot if (mode&FREAD) 1627701Ssam if (access(ip, IREAD)) 1637701Ssam goto bad; 16416032Skarels if (mode&(FWRITE|FTRUNC)) { 1657701Ssam if (access(ip, IWRITE)) 1667701Ssam goto bad; 1677701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 1686254Sroot u.u_error = EISDIR; 1697701Ssam goto bad; 1707701Ssam } 1716254Sroot } 1726254Sroot } 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; 18012756Ssam if (setjmp(&u.u_qsave)) { 18112756Ssam if (u.u_error == 0) 18212756Ssam u.u_error = EINTR; 183*24543Smckusick u.u_ofile[indx] = NULL; 18412756Ssam closef(fp); 18512756Ssam return; 18612756Ssam } 1878559Sroot u.u_error = openi(ip, mode); 18812756Ssam if (u.u_error == 0) 1896254Sroot return; 190*24543Smckusick ILOCK(ip); 1917701Ssam bad: 1927701Ssam iput(ip); 193*24543Smckusick bad1: 194*24543Smckusick u.u_ofile[indx] = NULL; 195*24543Smckusick fp->f_count--; 1966254Sroot } 1976254Sroot 1986254Sroot /* 1996254Sroot * Mknod system call 2006254Sroot */ 2016254Sroot mknod() 2026254Sroot { 2036254Sroot register struct inode *ip; 2046254Sroot register struct a { 2056254Sroot char *fname; 2066254Sroot int fmode; 2076254Sroot int dev; 20816694Smckusick } *uap = (struct a *)u.u_ap; 20916694Smckusick register struct nameidata *ndp = &u.u_nd; 2106254Sroot 21112756Ssam if (!suser()) 21212756Ssam return; 21316694Smckusick ndp->ni_nameiop = CREATE; 21416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 21516694Smckusick ndp->ni_dirp = uap->fname; 21616694Smckusick ip = namei(ndp); 21712756Ssam if (ip != NULL) { 21812756Ssam u.u_error = EEXIST; 21912756Ssam goto out; 2206254Sroot } 2216254Sroot if (u.u_error) 2226254Sroot return; 22316694Smckusick ip = maknode(uap->fmode, ndp); 2246254Sroot if (ip == NULL) 2256254Sroot return; 22612756Ssam switch (ip->i_mode & IFMT) { 22712756Ssam 22815093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 22912756Ssam case IFCHR: 23012756Ssam case IFBLK: 23112756Ssam if (uap->dev) { 23212756Ssam /* 23312756Ssam * Want to be able to use this to make badblock 23412756Ssam * inodes, so don't truncate the dev number. 23512756Ssam */ 23612756Ssam ip->i_rdev = uap->dev; 23712756Ssam ip->i_flag |= IACC|IUPD|ICHG; 23812756Ssam } 2396254Sroot } 2406254Sroot 2416254Sroot out: 2426254Sroot iput(ip); 2436254Sroot } 2446254Sroot 2456254Sroot /* 2466254Sroot * link system call 2476254Sroot */ 2486254Sroot link() 2496254Sroot { 2506254Sroot register struct inode *ip, *xp; 2516254Sroot register struct a { 2526254Sroot char *target; 2536254Sroot char *linkname; 25416694Smckusick } *uap = (struct a *)u.u_ap; 25516694Smckusick register struct nameidata *ndp = &u.u_nd; 2566254Sroot 25716694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 25816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 25916694Smckusick ndp->ni_dirp = uap->target; 26016694Smckusick ip = namei(ndp); /* well, this routine is doomed anyhow */ 2616254Sroot if (ip == NULL) 2626254Sroot return; 2639167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) { 2647439Sroot iput(ip); 2657439Sroot return; 2667439Sroot } 2676254Sroot ip->i_nlink++; 2686254Sroot ip->i_flag |= ICHG; 2698673Sroot iupdat(ip, &time, &time, 1); 27016664Smckusick IUNLOCK(ip); 27116694Smckusick ndp->ni_nameiop = CREATE; 27216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 27316694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 27416694Smckusick xp = namei(ndp); 2756254Sroot if (xp != NULL) { 2766254Sroot u.u_error = EEXIST; 2776254Sroot iput(xp); 2786254Sroot goto out; 2796254Sroot } 2806254Sroot if (u.u_error) 2816254Sroot goto out; 28216694Smckusick if (ndp->ni_pdir->i_dev != ip->i_dev) { 28316694Smckusick iput(ndp->ni_pdir); 2846254Sroot u.u_error = EXDEV; 2856254Sroot goto out; 2866254Sroot } 28716694Smckusick u.u_error = direnter(ip, ndp); 2886254Sroot out: 2896254Sroot if (u.u_error) { 2906254Sroot ip->i_nlink--; 2916254Sroot ip->i_flag |= ICHG; 2926254Sroot } 2937142Smckusick irele(ip); 2946254Sroot } 2956254Sroot 2966254Sroot /* 2976254Sroot * symlink -- make a symbolic link 2986254Sroot */ 2996254Sroot symlink() 3006254Sroot { 3016254Sroot register struct a { 3026254Sroot char *target; 3036254Sroot char *linkname; 30416694Smckusick } *uap = (struct a *)u.u_ap; 3056254Sroot register struct inode *ip; 3066254Sroot register char *tp; 3076254Sroot register c, nc; 30816694Smckusick register struct nameidata *ndp = &u.u_nd; 3096254Sroot 3106254Sroot tp = uap->target; 3116254Sroot nc = 0; 3126254Sroot while (c = fubyte(tp)) { 3136254Sroot if (c < 0) { 3146254Sroot u.u_error = EFAULT; 3156254Sroot return; 3166254Sroot } 3176254Sroot tp++; 3186254Sroot nc++; 3196254Sroot } 32016694Smckusick ndp->ni_nameiop = CREATE; 32116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 32216694Smckusick ndp->ni_dirp = uap->linkname; 32316694Smckusick ip = namei(ndp); 3246254Sroot if (ip) { 3256254Sroot iput(ip); 3266254Sroot u.u_error = EEXIST; 3276254Sroot return; 3286254Sroot } 3296254Sroot if (u.u_error) 3306254Sroot return; 33116694Smckusick ip = maknode(IFLNK | 0777, ndp); 3326254Sroot if (ip == NULL) 3336254Sroot return; 3347826Sroot u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0); 3359167Ssam /* handle u.u_error != 0 */ 3366254Sroot iput(ip); 3376254Sroot } 3386254Sroot 3396254Sroot /* 3406254Sroot * Unlink system call. 3416254Sroot * Hard to avoid races here, especially 3426254Sroot * in unlinking directories. 3436254Sroot */ 3446254Sroot unlink() 3456254Sroot { 3466254Sroot struct a { 3476254Sroot char *fname; 34816694Smckusick } *uap = (struct a *)u.u_ap; 3499167Ssam register struct inode *ip, *dp; 35016694Smckusick register struct nameidata *ndp = &u.u_nd; 3516254Sroot 35216694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 35316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 35416694Smckusick ndp->ni_dirp = uap->fname; 35516694Smckusick ip = namei(ndp); 3569167Ssam if (ip == NULL) 3576254Sroot return; 35816694Smckusick dp = ndp->ni_pdir; 3599167Ssam if ((ip->i_mode&IFMT) == IFDIR && !suser()) 3606254Sroot goto out; 3616254Sroot /* 3626254Sroot * Don't unlink a mounted file. 3636254Sroot */ 3649167Ssam if (ip->i_dev != dp->i_dev) { 3656254Sroot u.u_error = EBUSY; 3666254Sroot goto out; 3676254Sroot } 3686254Sroot if (ip->i_flag&ITEXT) 3696254Sroot xrele(ip); /* try once to free text */ 37016694Smckusick if (dirremove(ndp)) { 3717535Sroot ip->i_nlink--; 3727535Sroot ip->i_flag |= ICHG; 3736254Sroot } 3746254Sroot out: 3759167Ssam if (dp == ip) 3767142Smckusick irele(ip); 3777142Smckusick else 3787142Smckusick iput(ip); 3799167Ssam iput(dp); 3806254Sroot } 3816254Sroot 3826254Sroot /* 3836254Sroot * Seek system call 3846254Sroot */ 3858040Sroot lseek() 3866254Sroot { 3876254Sroot register struct file *fp; 3886254Sroot register struct a { 3897701Ssam int fd; 3906254Sroot off_t off; 3916254Sroot int sbase; 39216694Smckusick } *uap = (struct a *)u.u_ap; 3936254Sroot 39416540Ssam GETF(fp, uap->fd); 39516540Ssam if (fp->f_type != DTYPE_INODE) { 39616540Ssam u.u_error = ESPIPE; 3976254Sroot return; 39816540Ssam } 39913878Ssam switch (uap->sbase) { 40013878Ssam 40113878Ssam case L_INCR: 40213878Ssam fp->f_offset += uap->off; 40313878Ssam break; 40413878Ssam 40513878Ssam case L_XTND: 40613878Ssam fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size; 40713878Ssam break; 40813878Ssam 40913878Ssam case L_SET: 41013878Ssam fp->f_offset = uap->off; 41113878Ssam break; 41213878Ssam 41313878Ssam default: 41413878Ssam u.u_error = EINVAL; 41513878Ssam return; 41613878Ssam } 41713878Ssam u.u_r.r_off = fp->f_offset; 4186254Sroot } 4196254Sroot 4206254Sroot /* 4216254Sroot * Access system call 4226254Sroot */ 4236254Sroot saccess() 4246254Sroot { 4256254Sroot register svuid, svgid; 4266254Sroot register struct inode *ip; 4276254Sroot register struct a { 4286254Sroot char *fname; 4296254Sroot int fmode; 43016694Smckusick } *uap = (struct a *)u.u_ap; 43116694Smckusick register struct nameidata *ndp = &u.u_nd; 4326254Sroot 4336254Sroot svuid = u.u_uid; 4346254Sroot svgid = u.u_gid; 4356254Sroot u.u_uid = u.u_ruid; 4366254Sroot u.u_gid = u.u_rgid; 43716694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 43816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 43916694Smckusick ndp->ni_dirp = uap->fname; 44016694Smckusick ip = namei(ndp); 4416254Sroot if (ip != NULL) { 44212756Ssam if ((uap->fmode&R_OK) && access(ip, IREAD)) 4437701Ssam goto done; 44412756Ssam if ((uap->fmode&W_OK) && access(ip, IWRITE)) 4457701Ssam goto done; 44612756Ssam if ((uap->fmode&X_OK) && access(ip, IEXEC)) 4477701Ssam goto done; 4487701Ssam done: 4496254Sroot iput(ip); 4506254Sroot } 4516254Sroot u.u_uid = svuid; 4526254Sroot u.u_gid = svgid; 4536254Sroot } 4546254Sroot 4556254Sroot /* 4566574Smckusic * Stat system call. This version follows links. 45737Sbill */ 45837Sbill stat() 45937Sbill { 46037Sbill 46116694Smckusick stat1(FOLLOW); 46237Sbill } 46337Sbill 46437Sbill /* 4656574Smckusic * Lstat system call. This version does not follow links. 4665992Swnj */ 4675992Swnj lstat() 4685992Swnj { 46912756Ssam 47016694Smckusick stat1(NOFOLLOW); 47112756Ssam } 47212756Ssam 47312756Ssam stat1(follow) 47412756Ssam int follow; 47512756Ssam { 4765992Swnj register struct inode *ip; 4775992Swnj register struct a { 4785992Swnj char *fname; 47912756Ssam struct stat *ub; 48016694Smckusick } *uap = (struct a *)u.u_ap; 48112756Ssam struct stat sb; 48216694Smckusick register struct nameidata *ndp = &u.u_nd; 4835992Swnj 48416694Smckusick ndp->ni_nameiop = LOOKUP | follow; 48516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 48616694Smckusick ndp->ni_dirp = uap->fname; 48716694Smckusick ip = namei(ndp); 4885992Swnj if (ip == NULL) 4895992Swnj return; 49013043Ssam (void) ino_stat(ip, &sb); 4915992Swnj iput(ip); 49212756Ssam u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 4935992Swnj } 4945992Swnj 4955992Swnj /* 4965992Swnj * Return target name of a symbolic link 49737Sbill */ 4985992Swnj readlink() 4995992Swnj { 5005992Swnj register struct inode *ip; 5015992Swnj register struct a { 5025992Swnj char *name; 5035992Swnj char *buf; 5045992Swnj int count; 5057826Sroot } *uap = (struct a *)u.u_ap; 50616694Smckusick register struct nameidata *ndp = &u.u_nd; 5077826Sroot int resid; 5085992Swnj 50916694Smckusick ndp->ni_nameiop = LOOKUP; 51016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 51116694Smckusick ndp->ni_dirp = uap->name; 51216694Smckusick ip = namei(ndp); 5135992Swnj if (ip == NULL) 5145992Swnj return; 5155992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 51621015Smckusick u.u_error = EINVAL; 5175992Swnj goto out; 5185992Swnj } 5197826Sroot u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid); 5205992Swnj out: 5215992Swnj iput(ip); 5227826Sroot u.u_r.r_val1 = uap->count - resid; 5235992Swnj } 5245992Swnj 5259167Ssam /* 5269167Ssam * Change mode of a file given path name. 5279167Ssam */ 5286254Sroot chmod() 5295992Swnj { 5307701Ssam struct inode *ip; 5317701Ssam struct a { 5326254Sroot char *fname; 5336254Sroot int fmode; 53416694Smckusick } *uap = (struct a *)u.u_ap; 5355992Swnj 53616694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 5375992Swnj return; 53821015Smckusick u.u_error = chmod1(ip, uap->fmode); 5399167Ssam iput(ip); 5407701Ssam } 5417439Sroot 5429167Ssam /* 5439167Ssam * Change mode of a file given a file descriptor. 5449167Ssam */ 5457701Ssam fchmod() 5467701Ssam { 5477701Ssam struct a { 5487701Ssam int fd; 5497701Ssam int fmode; 55016694Smckusick } *uap = (struct a *)u.u_ap; 5517701Ssam register struct inode *ip; 5527701Ssam register struct file *fp; 5537701Ssam 55412756Ssam fp = getinode(uap->fd); 5557701Ssam if (fp == NULL) 5567701Ssam return; 55712756Ssam ip = (struct inode *)fp->f_data; 5589167Ssam if (u.u_uid != ip->i_uid && !suser()) 5599167Ssam return; 56016664Smckusick ILOCK(ip); 56121015Smckusick u.u_error = chmod1(ip, uap->fmode); 56216664Smckusick IUNLOCK(ip); 5637701Ssam } 5647701Ssam 5659167Ssam /* 5669167Ssam * Change the mode on a file. 5679167Ssam * Inode must be locked before calling. 5689167Ssam */ 5697701Ssam chmod1(ip, mode) 5707701Ssam register struct inode *ip; 5717701Ssam register int mode; 5727701Ssam { 5737868Sroot 57421015Smckusick if (ip->i_fs->fs_ronly) 57521015Smckusick return (EROFS); 5766254Sroot ip->i_mode &= ~07777; 5777439Sroot if (u.u_uid) { 57821015Smckusick if ((ip->i_mode & IFMT) != IFDIR) 57921015Smckusick mode &= ~ISVTX; 58011811Ssam if (!groupmember(ip->i_gid)) 58111811Ssam mode &= ~ISGID; 5827439Sroot } 5837701Ssam ip->i_mode |= mode&07777; 5846254Sroot ip->i_flag |= ICHG; 5856254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5866254Sroot xrele(ip); 58721015Smckusick return (0); 5885992Swnj } 5895992Swnj 5909167Ssam /* 5919167Ssam * Set ownership given a path name. 5929167Ssam */ 5936254Sroot chown() 59437Sbill { 5957701Ssam struct inode *ip; 5967701Ssam struct a { 5976254Sroot char *fname; 5986254Sroot int uid; 5996254Sroot int gid; 60016694Smckusick } *uap = (struct a *)u.u_ap; 60137Sbill 60216694Smckusick if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL) 60337Sbill return; 60411811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 6059167Ssam iput(ip); 6067701Ssam } 6077439Sroot 6089167Ssam /* 6099167Ssam * Set ownership given a file descriptor. 6109167Ssam */ 6117701Ssam fchown() 6127701Ssam { 6137701Ssam struct a { 6147701Ssam int fd; 6157701Ssam int uid; 6167701Ssam int gid; 61716694Smckusick } *uap = (struct a *)u.u_ap; 6187701Ssam register struct inode *ip; 6197701Ssam register struct file *fp; 6207701Ssam 62112756Ssam fp = getinode(uap->fd); 6227701Ssam if (fp == NULL) 6237701Ssam return; 62412756Ssam ip = (struct inode *)fp->f_data; 62511821Ssam if (!suser()) 6269167Ssam return; 62716664Smckusick ILOCK(ip); 62811811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 62916664Smckusick IUNLOCK(ip); 6307701Ssam } 6317701Ssam 6327701Ssam /* 6337701Ssam * Perform chown operation on inode ip; 6347701Ssam * inode must be locked prior to call. 6357701Ssam */ 6367701Ssam chown1(ip, uid, gid) 6377701Ssam register struct inode *ip; 6387701Ssam int uid, gid; 6397701Ssam { 6407701Ssam #ifdef QUOTA 6417701Ssam register long change; 64211811Ssam #endif 6437701Ssam 64421015Smckusick if (ip->i_fs->fs_ronly) 64521015Smckusick return (EROFS); 64611811Ssam if (uid == -1) 64711811Ssam uid = ip->i_uid; 64811811Ssam if (gid == -1) 64911811Ssam gid = ip->i_gid; 65011811Ssam #ifdef QUOTA 65114385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6527482Skre change = 0; 65312646Ssam else 65412646Ssam change = ip->i_blocks; 65512646Ssam (void) chkdq(ip, -change, 1); 65612646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6577482Skre dqrele(ip->i_dquot); 6587482Skre #endif 65911811Ssam ip->i_uid = uid; 66011811Ssam ip->i_gid = gid; 6616254Sroot ip->i_flag |= ICHG; 6626254Sroot if (u.u_ruid != 0) 6636254Sroot ip->i_mode &= ~(ISUID|ISGID); 6647701Ssam #ifdef QUOTA 6657482Skre ip->i_dquot = inoquota(ip); 66612646Ssam (void) chkdq(ip, change, 1); 66712646Ssam (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1); 66812646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 66912646Ssam #else 67012646Ssam return (0); 6717482Skre #endif 67237Sbill } 67337Sbill 67411811Ssam utimes() 67511811Ssam { 67611811Ssam register struct a { 67711811Ssam char *fname; 67811811Ssam struct timeval *tptr; 67911811Ssam } *uap = (struct a *)u.u_ap; 68011811Ssam register struct inode *ip; 68111811Ssam struct timeval tv[2]; 68211811Ssam 68316694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 68411811Ssam return; 68521015Smckusick if (ip->i_fs->fs_ronly) { 68621015Smckusick u.u_error = EROFS; 68721015Smckusick iput(ip); 68821015Smckusick return; 68921015Smckusick } 69011811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 69111811Ssam if (u.u_error == 0) { 69211811Ssam ip->i_flag |= IACC|IUPD|ICHG; 69311811Ssam iupdat(ip, &tv[0], &tv[1], 0); 69411811Ssam } 69511811Ssam iput(ip); 69611811Ssam } 69711811Ssam 6989167Ssam /* 6999167Ssam * Flush any pending I/O. 7009167Ssam */ 7016254Sroot sync() 70237Sbill { 70337Sbill 7048673Sroot update(); 70537Sbill } 7067535Sroot 7079167Ssam /* 7089167Ssam * Truncate a file given its path name. 7099167Ssam */ 7107701Ssam truncate() 7117701Ssam { 7127701Ssam struct a { 7137701Ssam char *fname; 7149167Ssam u_long length; 7157826Sroot } *uap = (struct a *)u.u_ap; 7167701Ssam struct inode *ip; 71716694Smckusick register struct nameidata *ndp = &u.u_nd; 7187701Ssam 71916694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72116694Smckusick ndp->ni_dirp = uap->fname; 72216694Smckusick ip = namei(ndp); 7237701Ssam if (ip == NULL) 7247701Ssam return; 7257701Ssam if (access(ip, IWRITE)) 7267701Ssam goto bad; 7277701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7287701Ssam u.u_error = EISDIR; 7297701Ssam goto bad; 7307701Ssam } 7317701Ssam itrunc(ip, uap->length); 7327701Ssam bad: 7337701Ssam iput(ip); 7347701Ssam } 7357701Ssam 7369167Ssam /* 7379167Ssam * Truncate a file given a file descriptor. 7389167Ssam */ 7397701Ssam ftruncate() 7407701Ssam { 7417701Ssam struct a { 7427701Ssam int fd; 7439167Ssam u_long length; 7447826Sroot } *uap = (struct a *)u.u_ap; 7457701Ssam struct inode *ip; 7467701Ssam struct file *fp; 7477701Ssam 74812756Ssam fp = getinode(uap->fd); 7497701Ssam if (fp == NULL) 7507701Ssam return; 7517701Ssam if ((fp->f_flag&FWRITE) == 0) { 7527701Ssam u.u_error = EINVAL; 7537701Ssam return; 7547701Ssam } 75512756Ssam ip = (struct inode *)fp->f_data; 75616664Smckusick ILOCK(ip); 7577701Ssam itrunc(ip, uap->length); 75816664Smckusick IUNLOCK(ip); 7597701Ssam } 7607701Ssam 7619167Ssam /* 7629167Ssam * Synch an open file. 7639167Ssam */ 7649167Ssam fsync() 7659167Ssam { 7669167Ssam struct a { 7679167Ssam int fd; 7689167Ssam } *uap = (struct a *)u.u_ap; 7699167Ssam struct inode *ip; 7709167Ssam struct file *fp; 7719167Ssam 77212756Ssam fp = getinode(uap->fd); 7739167Ssam if (fp == NULL) 7749167Ssam return; 77512756Ssam ip = (struct inode *)fp->f_data; 77616664Smckusick ILOCK(ip); 7779167Ssam syncip(ip); 77816664Smckusick IUNLOCK(ip); 7799167Ssam } 7809167Ssam 7819167Ssam /* 7829167Ssam * Rename system call. 7839167Ssam * rename("foo", "bar"); 7849167Ssam * is essentially 7859167Ssam * unlink("bar"); 7869167Ssam * link("foo", "bar"); 7879167Ssam * unlink("foo"); 7889167Ssam * but ``atomically''. Can't do full commit without saving state in the 7899167Ssam * inode on disk which isn't feasible at this time. Best we can do is 7909167Ssam * always guarantee the target exists. 7919167Ssam * 7929167Ssam * Basic algorithm is: 7939167Ssam * 7949167Ssam * 1) Bump link count on source while we're linking it to the 7959167Ssam * target. This also insure the inode won't be deleted out 79616776Smckusick * from underneath us while we work (it may be truncated by 79716776Smckusick * a concurrent `trunc' or `open' for creation). 7989167Ssam * 2) Link source to destination. If destination already exists, 7999167Ssam * delete it first. 80016776Smckusick * 3) Unlink source reference to inode if still around. If a 80116776Smckusick * directory was moved and the parent of the destination 8029167Ssam * is different from the source, patch the ".." entry in the 8039167Ssam * directory. 8049167Ssam * 8059167Ssam * Source and destination must either both be directories, or both 8069167Ssam * not be directories. If target is a directory, it must be empty. 8079167Ssam */ 8087701Ssam rename() 8097701Ssam { 8107701Ssam struct a { 8117701Ssam char *from; 8127701Ssam char *to; 81316694Smckusick } *uap = (struct a *)u.u_ap; 8149167Ssam register struct inode *ip, *xp, *dp; 81516776Smckusick struct dirtemplate dirbuf; 81616776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 81716694Smckusick register struct nameidata *ndp = &u.u_nd; 81810051Ssam int error = 0; 8197701Ssam 82016694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 82116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82216694Smckusick ndp->ni_dirp = uap->from; 82316694Smckusick ip = namei(ndp); 8249167Ssam if (ip == NULL) 8259167Ssam return; 82616694Smckusick dp = ndp->ni_pdir; 8279167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 8289167Ssam register struct direct *d; 8299167Ssam 83016694Smckusick d = &ndp->ni_dent; 8319167Ssam /* 83211641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 8339167Ssam */ 83411641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 83511641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 83616776Smckusick (dp == ip) || (ip->i_flag & IRENAME)) { 83711641Ssam iput(dp); 83811641Ssam if (dp == ip) 83911641Ssam irele(ip); 84011641Ssam else 84110051Ssam iput(ip); 84211641Ssam u.u_error = EINVAL; 84311641Ssam return; 8449167Ssam } 84516776Smckusick ip->i_flag |= IRENAME; 8469167Ssam oldparent = dp->i_number; 8479167Ssam doingdirectory++; 8489167Ssam } 84911641Ssam iput(dp); 8509167Ssam 8519167Ssam /* 8529167Ssam * 1) Bump link count while we're moving stuff 8539167Ssam * around. If we crash somewhere before 8549167Ssam * completing our work, the link count 8559167Ssam * may be wrong, but correctable. 8569167Ssam */ 8579167Ssam ip->i_nlink++; 8589167Ssam ip->i_flag |= ICHG; 8599167Ssam iupdat(ip, &time, &time, 1); 86016664Smckusick IUNLOCK(ip); 8619167Ssam 8629167Ssam /* 8639167Ssam * When the target exists, both the directory 8649167Ssam * and target inodes are returned locked. 8659167Ssam */ 86616694Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE; 86716694Smckusick ndp->ni_dirp = (caddr_t)uap->to; 86816694Smckusick xp = namei(ndp); 86910051Ssam if (u.u_error) { 87010051Ssam error = u.u_error; 8719167Ssam goto out; 87210051Ssam } 87316694Smckusick dp = ndp->ni_pdir; 8749167Ssam /* 87511641Ssam * If ".." must be changed (ie the directory gets a new 87612816Smckusick * parent) then the source directory must not be in the 87712816Smckusick * directory heirarchy above the target, as this would 87812816Smckusick * orphan everything below the source directory. Also 87912816Smckusick * the user must have write permission in the source so 88012816Smckusick * as to be able to change "..". We must repeat the call 88112816Smckusick * to namei, as the parent directory is unlocked by the 88212816Smckusick * call to checkpath(). 88311641Ssam */ 88416776Smckusick if (oldparent != dp->i_number) 88516776Smckusick newparent = dp->i_number; 88616776Smckusick if (doingdirectory && newparent) { 88712816Smckusick if (access(ip, IWRITE)) 88812816Smckusick goto bad; 88912816Smckusick do { 89016694Smckusick dp = ndp->ni_pdir; 89112816Smckusick if (xp != NULL) 89212816Smckusick iput(xp); 89312816Smckusick u.u_error = checkpath(ip, dp); 89412816Smckusick if (u.u_error) 89512816Smckusick goto out; 89616694Smckusick xp = namei(ndp); 89712816Smckusick if (u.u_error) { 89812816Smckusick error = u.u_error; 89912816Smckusick goto out; 90012816Smckusick } 90116694Smckusick } while (dp != ndp->ni_pdir); 90212816Smckusick } 90311641Ssam /* 9049167Ssam * 2) If target doesn't exist, link the target 9059167Ssam * to the source and unlink the source. 9069167Ssam * Otherwise, rewrite the target directory 9079167Ssam * entry to reference the source inode and 9089167Ssam * expunge the original entry's existence. 9099167Ssam */ 9109167Ssam if (xp == NULL) { 9119167Ssam if (dp->i_dev != ip->i_dev) { 91210051Ssam error = EXDEV; 9139167Ssam goto bad; 9149167Ssam } 9159167Ssam /* 91616776Smckusick * Account for ".." in new directory. 91716776Smckusick * When source and destination have the same 91816776Smckusick * parent we don't fool with the link count. 9199167Ssam */ 92016776Smckusick if (doingdirectory && newparent) { 9219167Ssam dp->i_nlink++; 9229167Ssam dp->i_flag |= ICHG; 9239167Ssam iupdat(dp, &time, &time, 1); 9249167Ssam } 92516694Smckusick error = direnter(ip, ndp); 92610850Ssam if (error) 9279167Ssam goto out; 9289167Ssam } else { 9299167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 93010051Ssam error = EXDEV; 9319167Ssam goto bad; 9329167Ssam } 9339167Ssam /* 93410590Ssam * Short circuit rename(foo, foo). 93510590Ssam */ 93610590Ssam if (xp->i_number == ip->i_number) 93710590Ssam goto bad; 93810590Ssam /* 93924433Sbloom * If the parent directory is "sticky", then the user must 94024433Sbloom * own the parent directory, or the destination of the rename, 94124433Sbloom * otherwise the destination may not be changed (except by 94224433Sbloom * root). This implements append-only directories. 94324433Sbloom */ 94424433Sbloom if ((dp->i_mode & ISVTX) && u.u_uid != 0 && 94524433Sbloom u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) { 94624433Sbloom error = EPERM; 94724433Sbloom goto bad; 94824433Sbloom } 94924433Sbloom /* 95010051Ssam * Target must be empty if a directory 95110051Ssam * and have no links to it. 9529167Ssam * Also, insure source and target are 9539167Ssam * compatible (both directories, or both 9549167Ssam * not directories). 9559167Ssam */ 9569167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 95716776Smckusick if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) { 95810051Ssam error = ENOTEMPTY; 9599167Ssam goto bad; 9609167Ssam } 9619167Ssam if (!doingdirectory) { 96210051Ssam error = ENOTDIR; 9639167Ssam goto bad; 9649167Ssam } 96516776Smckusick cacheinval(dp); 9669167Ssam } else if (doingdirectory) { 96710051Ssam error = EISDIR; 9689167Ssam goto bad; 9699167Ssam } 97016694Smckusick dirrewrite(dp, ip, ndp); 97110051Ssam if (u.u_error) { 97210051Ssam error = u.u_error; 9739167Ssam goto bad1; 97410051Ssam } 9759167Ssam /* 97610051Ssam * Adjust the link count of the target to 97710051Ssam * reflect the dirrewrite above. If this is 97810051Ssam * a directory it is empty and there are 97910051Ssam * no links to it, so we can squash the inode and 98010051Ssam * any space associated with it. We disallowed 98110051Ssam * renaming over top of a directory with links to 98216776Smckusick * it above, as the remaining link would point to 98316776Smckusick * a directory without "." or ".." entries. 9849167Ssam */ 98510051Ssam xp->i_nlink--; 9869167Ssam if (doingdirectory) { 98710051Ssam if (--xp->i_nlink != 0) 98810051Ssam panic("rename: linked directory"); 9899167Ssam itrunc(xp, (u_long)0); 99010051Ssam } 9919167Ssam xp->i_flag |= ICHG; 9929167Ssam iput(xp); 99310246Ssam xp = NULL; 9949167Ssam } 9959167Ssam 9969167Ssam /* 9979167Ssam * 3) Unlink the source. 9989167Ssam */ 99916694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 100016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 100116694Smckusick ndp->ni_dirp = uap->from; 100216776Smckusick xp = namei(ndp); 100317758Smckusick if (xp != NULL) 100417758Smckusick dp = ndp->ni_pdir; 100517758Smckusick else 100617758Smckusick dp = NULL; 10079167Ssam /* 100816776Smckusick * Insure that the directory entry still exists and has not 100916776Smckusick * changed while the new name has been entered. If the source is 101016776Smckusick * a file then the entry may have been unlinked or renamed. In 101116776Smckusick * either case there is no further work to be done. If the source 101216776Smckusick * is a directory then it cannot have been rmdir'ed; its link 101316776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 101416776Smckusick * The IRENAME flag insures that it cannot be moved by another 101516776Smckusick * rename. 10169167Ssam */ 101717758Smckusick if (xp != ip) { 101816776Smckusick if (doingdirectory) 101917758Smckusick panic("rename: lost dir entry"); 102016776Smckusick } else { 10219167Ssam /* 102216776Smckusick * If the source is a directory with a 102316776Smckusick * new parent, the link count of the old 102416776Smckusick * parent directory must be decremented 102516776Smckusick * and ".." set to point to the new parent. 10269167Ssam */ 102716776Smckusick if (doingdirectory && newparent) { 10289167Ssam dp->i_nlink--; 10299167Ssam dp->i_flag |= ICHG; 103016776Smckusick error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf, 103116776Smckusick sizeof (struct dirtemplate), (off_t)0, 1, 103216776Smckusick (int *)0); 103316776Smckusick if (error == 0) { 103416776Smckusick if (dirbuf.dotdot_namlen != 2 || 103516776Smckusick dirbuf.dotdot_name[0] != '.' || 103616776Smckusick dirbuf.dotdot_name[1] != '.') { 103716776Smckusick printf("rename: mangled dir\n"); 103816776Smckusick } else { 103916776Smckusick dirbuf.dotdot_ino = newparent; 104016776Smckusick (void) rdwri(UIO_WRITE, xp, 104116776Smckusick (caddr_t)&dirbuf, 104216776Smckusick sizeof (struct dirtemplate), 104316776Smckusick (off_t)0, 1, (int *)0); 104416776Smckusick cacheinval(dp); 104516776Smckusick } 104616776Smckusick } 10479167Ssam } 104816694Smckusick if (dirremove(ndp)) { 104916776Smckusick xp->i_nlink--; 105016776Smckusick xp->i_flag |= ICHG; 10519167Ssam } 105216776Smckusick xp->i_flag &= ~IRENAME; 105316776Smckusick if (error == 0) /* XXX conservative */ 105410051Ssam error = u.u_error; 10559167Ssam } 10569167Ssam if (dp) 10579167Ssam iput(dp); 105816776Smckusick if (xp) 105916776Smckusick iput(xp); 106016776Smckusick irele(ip); 106116776Smckusick if (error) 106216776Smckusick u.u_error = error; 106316776Smckusick return; 10649167Ssam 10659167Ssam bad: 106610246Ssam iput(dp); 10679167Ssam bad1: 10689167Ssam if (xp) 106910246Ssam iput(xp); 10709167Ssam out: 10719167Ssam ip->i_nlink--; 10729167Ssam ip->i_flag |= ICHG; 10739167Ssam irele(ip); 107410051Ssam if (error) 107510051Ssam u.u_error = error; 10767701Ssam } 10777701Ssam 10787535Sroot /* 10797535Sroot * Make a new file. 10807535Sroot */ 10817535Sroot struct inode * 108216694Smckusick maknode(mode, ndp) 10837535Sroot int mode; 108416694Smckusick register struct nameidata *ndp; 10857535Sroot { 10867535Sroot register struct inode *ip; 108716694Smckusick register struct inode *pdir = ndp->ni_pdir; 10887535Sroot ino_t ipref; 10897535Sroot 10907535Sroot if ((mode & IFMT) == IFDIR) 109116694Smckusick ipref = dirpref(pdir->i_fs); 10927535Sroot else 109316694Smckusick ipref = pdir->i_number; 109416694Smckusick ip = ialloc(pdir, ipref, mode); 10957535Sroot if (ip == NULL) { 109616694Smckusick iput(pdir); 10977701Ssam return (NULL); 10987535Sroot } 10997701Ssam #ifdef QUOTA 11007535Sroot if (ip->i_dquot != NODQUOT) 11017535Sroot panic("maknode: dquot"); 11027535Sroot #endif 11037535Sroot ip->i_flag |= IACC|IUPD|ICHG; 11047535Sroot if ((mode & IFMT) == 0) 11057535Sroot mode |= IFREG; 11067535Sroot ip->i_mode = mode & ~u.u_cmask; 11077535Sroot ip->i_nlink = 1; 11087535Sroot ip->i_uid = u.u_uid; 110916694Smckusick ip->i_gid = pdir->i_gid; 111011811Ssam if (ip->i_mode & ISGID && !groupmember(ip->i_gid)) 111111811Ssam ip->i_mode &= ~ISGID; 11127701Ssam #ifdef QUOTA 11137535Sroot ip->i_dquot = inoquota(ip); 11147535Sroot #endif 11157535Sroot 11167535Sroot /* 11177535Sroot * Make sure inode goes to disk before directory entry. 11187535Sroot */ 11198673Sroot iupdat(ip, &time, &time, 1); 112016694Smckusick u.u_error = direnter(ip, ndp); 11217535Sroot if (u.u_error) { 11227535Sroot /* 112310850Ssam * Write error occurred trying to update directory 112410850Ssam * so must deallocate the inode. 11257535Sroot */ 11267535Sroot ip->i_nlink = 0; 11277535Sroot ip->i_flag |= ICHG; 11287535Sroot iput(ip); 11297701Ssam return (NULL); 11307535Sroot } 11317701Ssam return (ip); 11327535Sroot } 113312756Ssam 113412756Ssam /* 113512756Ssam * A virgin directory (no blushing please). 113612756Ssam */ 113712756Ssam struct dirtemplate mastertemplate = { 113812756Ssam 0, 12, 1, ".", 113912756Ssam 0, DIRBLKSIZ - 12, 2, ".." 114012756Ssam }; 114112756Ssam 114212756Ssam /* 114312756Ssam * Mkdir system call 114412756Ssam */ 114512756Ssam mkdir() 114612756Ssam { 114712756Ssam struct a { 114812756Ssam char *name; 114912756Ssam int dmode; 115016694Smckusick } *uap = (struct a *)u.u_ap; 115112756Ssam register struct inode *ip, *dp; 115212756Ssam struct dirtemplate dirtemplate; 115316694Smckusick register struct nameidata *ndp = &u.u_nd; 115412756Ssam 115516694Smckusick ndp->ni_nameiop = CREATE; 115616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 115716694Smckusick ndp->ni_dirp = uap->name; 115816694Smckusick ip = namei(ndp); 115912756Ssam if (u.u_error) 116012756Ssam return; 116112756Ssam if (ip != NULL) { 116212756Ssam iput(ip); 116312756Ssam u.u_error = EEXIST; 116412756Ssam return; 116512756Ssam } 116616694Smckusick dp = ndp->ni_pdir; 116712756Ssam uap->dmode &= 0777; 116812756Ssam uap->dmode |= IFDIR; 116912756Ssam /* 117012756Ssam * Must simulate part of maknode here 117112756Ssam * in order to acquire the inode, but 117212756Ssam * not have it entered in the parent 117312756Ssam * directory. The entry is made later 117412756Ssam * after writing "." and ".." entries out. 117512756Ssam */ 117612756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 117712756Ssam if (ip == NULL) { 117812756Ssam iput(dp); 117912756Ssam return; 118012756Ssam } 118112756Ssam #ifdef QUOTA 118212756Ssam if (ip->i_dquot != NODQUOT) 118312756Ssam panic("mkdir: dquot"); 118412756Ssam #endif 118512756Ssam ip->i_flag |= IACC|IUPD|ICHG; 118612756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 118712756Ssam ip->i_nlink = 2; 118812756Ssam ip->i_uid = u.u_uid; 118912756Ssam ip->i_gid = dp->i_gid; 119012756Ssam #ifdef QUOTA 119112756Ssam ip->i_dquot = inoquota(ip); 119212756Ssam #endif 119312756Ssam iupdat(ip, &time, &time, 1); 119412756Ssam 119512756Ssam /* 119612756Ssam * Bump link count in parent directory 119712756Ssam * to reflect work done below. Should 119812756Ssam * be done before reference is created 119912756Ssam * so reparation is possible if we crash. 120012756Ssam */ 120112756Ssam dp->i_nlink++; 120212756Ssam dp->i_flag |= ICHG; 120312756Ssam iupdat(dp, &time, &time, 1); 120412756Ssam 120512756Ssam /* 120612756Ssam * Initialize directory with "." 120712756Ssam * and ".." from static template. 120812756Ssam */ 120912756Ssam dirtemplate = mastertemplate; 121012756Ssam dirtemplate.dot_ino = ip->i_number; 121112756Ssam dirtemplate.dotdot_ino = dp->i_number; 121212756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 121312756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 121412756Ssam if (u.u_error) { 121512756Ssam dp->i_nlink--; 121612756Ssam dp->i_flag |= ICHG; 121712756Ssam goto bad; 121812756Ssam } 121918103Smckusick if (DIRBLKSIZ > ip->i_fs->fs_fsize) 122018103Smckusick panic("mkdir: blksize"); /* XXX - should grow with bmap() */ 122118103Smckusick else 122218103Smckusick ip->i_size = DIRBLKSIZ; 122312756Ssam /* 122412756Ssam * Directory all set up, now 122512756Ssam * install the entry for it in 122612756Ssam * the parent directory. 122712756Ssam */ 122816694Smckusick u.u_error = direnter(ip, ndp); 122912756Ssam dp = NULL; 123012756Ssam if (u.u_error) { 123116694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 123216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 123316694Smckusick ndp->ni_dirp = uap->name; 123416694Smckusick dp = namei(ndp); 123512756Ssam if (dp) { 123612756Ssam dp->i_nlink--; 123712756Ssam dp->i_flag |= ICHG; 123812756Ssam } 123912756Ssam } 124012756Ssam bad: 124112756Ssam /* 124212756Ssam * No need to do an explicit itrunc here, 124312756Ssam * irele will do this for us because we set 124412756Ssam * the link count to 0. 124512756Ssam */ 124612756Ssam if (u.u_error) { 124712756Ssam ip->i_nlink = 0; 124812756Ssam ip->i_flag |= ICHG; 124912756Ssam } 125012756Ssam if (dp) 125112756Ssam iput(dp); 125212756Ssam iput(ip); 125312756Ssam } 125412756Ssam 125512756Ssam /* 125612756Ssam * Rmdir system call. 125712756Ssam */ 125812756Ssam rmdir() 125912756Ssam { 126012756Ssam struct a { 126112756Ssam char *name; 126216694Smckusick } *uap = (struct a *)u.u_ap; 126312756Ssam register struct inode *ip, *dp; 126416694Smckusick register struct nameidata *ndp = &u.u_nd; 126512756Ssam 126616694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 126716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 126816694Smckusick ndp->ni_dirp = uap->name; 126916694Smckusick ip = namei(ndp); 127012756Ssam if (ip == NULL) 127112756Ssam return; 127216694Smckusick dp = ndp->ni_pdir; 127312756Ssam /* 127412756Ssam * No rmdir "." please. 127512756Ssam */ 127612756Ssam if (dp == ip) { 127712756Ssam irele(dp); 127812756Ssam iput(ip); 127912756Ssam u.u_error = EINVAL; 128012756Ssam return; 128112756Ssam } 128212756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 128312756Ssam u.u_error = ENOTDIR; 128412756Ssam goto out; 128512756Ssam } 128612756Ssam /* 128712756Ssam * Don't remove a mounted on directory. 128812756Ssam */ 128912756Ssam if (ip->i_dev != dp->i_dev) { 129012756Ssam u.u_error = EBUSY; 129112756Ssam goto out; 129212756Ssam } 129312756Ssam /* 129412756Ssam * Verify the directory is empty (and valid). 129512756Ssam * (Rmdir ".." won't be valid since 129612756Ssam * ".." will contain a reference to 129712756Ssam * the current directory and thus be 129812756Ssam * non-empty.) 129912756Ssam */ 130016776Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) { 130112756Ssam u.u_error = ENOTEMPTY; 130212756Ssam goto out; 130312756Ssam } 130412756Ssam /* 130512756Ssam * Delete reference to directory before purging 130612756Ssam * inode. If we crash in between, the directory 130712756Ssam * will be reattached to lost+found, 130812756Ssam */ 130916694Smckusick if (dirremove(ndp) == 0) 131012756Ssam goto out; 131112756Ssam dp->i_nlink--; 131212756Ssam dp->i_flag |= ICHG; 131316776Smckusick cacheinval(dp); 131412756Ssam iput(dp); 131512756Ssam dp = NULL; 131612756Ssam /* 131712756Ssam * Truncate inode. The only stuff left 131812756Ssam * in the directory is "." and "..". The 131912756Ssam * "." reference is inconsequential since 132012756Ssam * we're quashing it. The ".." reference 132112756Ssam * has already been adjusted above. We've 132212756Ssam * removed the "." reference and the reference 132312756Ssam * in the parent directory, but there may be 132412756Ssam * other hard links so decrement by 2 and 132512756Ssam * worry about them later. 132612756Ssam */ 132712756Ssam ip->i_nlink -= 2; 132812756Ssam itrunc(ip, (u_long)0); 132916739Smckusick cacheinval(ip); 133012756Ssam out: 133112756Ssam if (dp) 133212756Ssam iput(dp); 133312756Ssam iput(ip); 133412756Ssam } 133512756Ssam 133612756Ssam struct file * 133712756Ssam getinode(fdes) 133812756Ssam int fdes; 133912756Ssam { 134016540Ssam struct file *fp; 134112756Ssam 134216540Ssam if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { 134316540Ssam u.u_error = EBADF; 134416540Ssam return ((struct file *)0); 134516540Ssam } 134612756Ssam if (fp->f_type != DTYPE_INODE) { 134712756Ssam u.u_error = EINVAL; 134816540Ssam return ((struct file *)0); 134912756Ssam } 135012756Ssam return (fp); 135112756Ssam } 135212756Ssam 135312756Ssam /* 135412756Ssam * mode mask for creation of files 135512756Ssam */ 135612756Ssam umask() 135712756Ssam { 135812756Ssam register struct a { 135912756Ssam int mask; 136016694Smckusick } *uap = (struct a *)u.u_ap; 136112756Ssam 136212756Ssam u.u_r.r_val1 = u.u_cmask; 136312756Ssam u.u_cmask = uap->mask & 07777; 136412756Ssam } 1365