123405Smckusick /* 229121Smckusick * Copyright (c) 1982, 1986 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*36614Sbostic * @(#)vfs_syscalls.c 7.4 (Berkeley) 01/24/89 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; 12224543Smckusick int indx; 1236254Sroot 12424543Smckusick fp = falloc(); 12524543Smckusick if (fp == NULL) 12612756Ssam return; 12724543Smckusick 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) 13824543Smckusick goto bad1; 13916694Smckusick ip = maknode(arg&07777&(~ISVTX), ndp); 14012756Ssam if (ip == NULL) 14124543Smckusick goto bad1; 14212756Ssam mode &= ~FTRUNC; 14312756Ssam } else { 14412756Ssam if (mode&FEXCL) { 14512756Ssam u.u_error = EEXIST; 14624543Smckusick goto bad; 14712756Ssam } 14812756Ssam mode &= ~FCREAT; 14912756Ssam } 15012756Ssam } else { 15116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 15216694Smckusick ip = namei(ndp); 15312756Ssam if (ip == NULL) 15424543Smckusick 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; 18324543Smckusick 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; 19024543Smckusick ILOCK(ip); 1917701Ssam bad: 1927701Ssam iput(ip); 19324543Smckusick bad1: 19424543Smckusick u.u_ofile[indx] = NULL; 19524543Smckusick 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; 33426361Skarels u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0, 33526361Skarels (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) { 51721015Smckusick u.u_error = EINVAL; 5185992Swnj goto out; 5195992Swnj } 52026361Skarels u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0, 52126361Skarels &resid); 5225992Swnj out: 5235992Swnj iput(ip); 5247826Sroot u.u_r.r_val1 = uap->count - resid; 5255992Swnj } 5265992Swnj 5279167Ssam /* 5289167Ssam * Change mode of a file given path name. 5299167Ssam */ 5306254Sroot chmod() 5315992Swnj { 5327701Ssam struct inode *ip; 5337701Ssam struct a { 5346254Sroot char *fname; 5356254Sroot int fmode; 53616694Smckusick } *uap = (struct a *)u.u_ap; 5375992Swnj 53816694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 5395992Swnj return; 54021015Smckusick u.u_error = chmod1(ip, uap->fmode); 5419167Ssam iput(ip); 5427701Ssam } 5437439Sroot 5449167Ssam /* 5459167Ssam * Change mode of a file given a file descriptor. 5469167Ssam */ 5477701Ssam fchmod() 5487701Ssam { 5497701Ssam struct a { 5507701Ssam int fd; 5517701Ssam int fmode; 55216694Smckusick } *uap = (struct a *)u.u_ap; 5537701Ssam register struct inode *ip; 5547701Ssam register struct file *fp; 5557701Ssam 55612756Ssam fp = getinode(uap->fd); 5577701Ssam if (fp == NULL) 5587701Ssam return; 55912756Ssam ip = (struct inode *)fp->f_data; 5609167Ssam if (u.u_uid != ip->i_uid && !suser()) 5619167Ssam return; 56216664Smckusick ILOCK(ip); 56321015Smckusick u.u_error = chmod1(ip, uap->fmode); 56416664Smckusick IUNLOCK(ip); 5657701Ssam } 5667701Ssam 5679167Ssam /* 5689167Ssam * Change the mode on a file. 5699167Ssam * Inode must be locked before calling. 5709167Ssam */ 5717701Ssam chmod1(ip, mode) 5727701Ssam register struct inode *ip; 5737701Ssam register int mode; 5747701Ssam { 5757868Sroot 57621015Smckusick if (ip->i_fs->fs_ronly) 57721015Smckusick return (EROFS); 5786254Sroot ip->i_mode &= ~07777; 5797439Sroot if (u.u_uid) { 58021015Smckusick if ((ip->i_mode & IFMT) != IFDIR) 58121015Smckusick mode &= ~ISVTX; 58211811Ssam if (!groupmember(ip->i_gid)) 58311811Ssam mode &= ~ISGID; 5847439Sroot } 5857701Ssam ip->i_mode |= mode&07777; 5866254Sroot ip->i_flag |= ICHG; 5876254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5886254Sroot xrele(ip); 58921015Smckusick return (0); 5905992Swnj } 5915992Swnj 5929167Ssam /* 5939167Ssam * Set ownership given a path name. 5949167Ssam */ 5956254Sroot chown() 59637Sbill { 5977701Ssam struct inode *ip; 5987701Ssam struct a { 5996254Sroot char *fname; 6006254Sroot int uid; 6016254Sroot int gid; 60216694Smckusick } *uap = (struct a *)u.u_ap; 603*36614Sbostic register struct nameidata *ndp = &u.u_nd; 60437Sbill 605*36614Sbostic ndp->ni_nameiop = LOOKUP | NOFOLLOW; 606*36614Sbostic ndp->ni_segflg = UIO_USERSPACE; 607*36614Sbostic ndp->ni_dirp = uap->fname; 608*36614Sbostic ip = namei(ndp); 609*36614Sbostic if (ip == NULL) 61037Sbill return; 61111811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 6129167Ssam iput(ip); 6137701Ssam } 6147439Sroot 6159167Ssam /* 6169167Ssam * Set ownership given a file descriptor. 6179167Ssam */ 6187701Ssam fchown() 6197701Ssam { 6207701Ssam struct a { 6217701Ssam int fd; 6227701Ssam int uid; 6237701Ssam int gid; 62416694Smckusick } *uap = (struct a *)u.u_ap; 6257701Ssam register struct inode *ip; 6267701Ssam register struct file *fp; 6277701Ssam 62812756Ssam fp = getinode(uap->fd); 6297701Ssam if (fp == NULL) 6307701Ssam return; 63112756Ssam ip = (struct inode *)fp->f_data; 63216664Smckusick ILOCK(ip); 63311811Ssam u.u_error = chown1(ip, uap->uid, uap->gid); 63416664Smckusick IUNLOCK(ip); 6357701Ssam } 6367701Ssam 6377701Ssam /* 6387701Ssam * Perform chown operation on inode ip; 6397701Ssam * inode must be locked prior to call. 6407701Ssam */ 6417701Ssam chown1(ip, uid, gid) 6427701Ssam register struct inode *ip; 6437701Ssam int uid, gid; 6447701Ssam { 6457701Ssam #ifdef QUOTA 6467701Ssam register long change; 64711811Ssam #endif 6487701Ssam 64921015Smckusick if (ip->i_fs->fs_ronly) 65021015Smckusick return (EROFS); 65111811Ssam if (uid == -1) 65211811Ssam uid = ip->i_uid; 65311811Ssam if (gid == -1) 65411811Ssam gid = ip->i_gid; 655*36614Sbostic /* 656*36614Sbostic * If we don't own the file, are trying to change the owner 657*36614Sbostic * of the file, or are not a member of the target group, 658*36614Sbostic * the caller must be superuser or the call fails. 659*36614Sbostic */ 660*36614Sbostic if ((u.u_uid != ip->i_uid || uid != ip->i_uid || 661*36614Sbostic !groupmember((gid_t)gid)) && !suser()) 66226473Skarels return (u.u_error); 66311811Ssam #ifdef QUOTA 66414385Ssam if (ip->i_uid == uid) /* this just speeds things a little */ 6657482Skre change = 0; 66612646Ssam else 66712646Ssam change = ip->i_blocks; 66812646Ssam (void) chkdq(ip, -change, 1); 66912646Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 1); 6707482Skre dqrele(ip->i_dquot); 6717482Skre #endif 67211811Ssam ip->i_uid = uid; 67311811Ssam ip->i_gid = gid; 6746254Sroot ip->i_flag |= ICHG; 6756254Sroot if (u.u_ruid != 0) 6766254Sroot ip->i_mode &= ~(ISUID|ISGID); 6777701Ssam #ifdef QUOTA 6787482Skre ip->i_dquot = inoquota(ip); 67912646Ssam (void) chkdq(ip, change, 1); 68026361Skarels (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1); 68112646Ssam return (u.u_error); /* should == 0 ALWAYS !! */ 68212646Ssam #else 68312646Ssam return (0); 6847482Skre #endif 68537Sbill } 68637Sbill 68711811Ssam utimes() 68811811Ssam { 68911811Ssam register struct a { 69011811Ssam char *fname; 69111811Ssam struct timeval *tptr; 69211811Ssam } *uap = (struct a *)u.u_ap; 69311811Ssam register struct inode *ip; 69411811Ssam struct timeval tv[2]; 69511811Ssam 69616694Smckusick if ((ip = owner(uap->fname, FOLLOW)) == NULL) 69711811Ssam return; 69821015Smckusick if (ip->i_fs->fs_ronly) { 69921015Smckusick u.u_error = EROFS; 70021015Smckusick iput(ip); 70121015Smckusick return; 70221015Smckusick } 70311811Ssam u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 70411811Ssam if (u.u_error == 0) { 70511811Ssam ip->i_flag |= IACC|IUPD|ICHG; 70611811Ssam iupdat(ip, &tv[0], &tv[1], 0); 70711811Ssam } 70811811Ssam iput(ip); 70911811Ssam } 71011811Ssam 7119167Ssam /* 7129167Ssam * Flush any pending I/O. 7139167Ssam */ 7146254Sroot sync() 71537Sbill { 71637Sbill 7178673Sroot update(); 71837Sbill } 7197535Sroot 7209167Ssam /* 7219167Ssam * Truncate a file given its path name. 7229167Ssam */ 7237701Ssam truncate() 7247701Ssam { 7257701Ssam struct a { 7267701Ssam char *fname; 72726473Skarels off_t length; 7287826Sroot } *uap = (struct a *)u.u_ap; 7297701Ssam struct inode *ip; 73016694Smckusick register struct nameidata *ndp = &u.u_nd; 7317701Ssam 73216694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 73316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73416694Smckusick ndp->ni_dirp = uap->fname; 73516694Smckusick ip = namei(ndp); 7367701Ssam if (ip == NULL) 7377701Ssam return; 7387701Ssam if (access(ip, IWRITE)) 7397701Ssam goto bad; 7407701Ssam if ((ip->i_mode&IFMT) == IFDIR) { 7417701Ssam u.u_error = EISDIR; 7427701Ssam goto bad; 7437701Ssam } 74426473Skarels itrunc(ip, (u_long)uap->length); 7457701Ssam bad: 7467701Ssam iput(ip); 7477701Ssam } 7487701Ssam 7499167Ssam /* 7509167Ssam * Truncate a file given a file descriptor. 7519167Ssam */ 7527701Ssam ftruncate() 7537701Ssam { 7547701Ssam struct a { 7557701Ssam int fd; 75626473Skarels off_t length; 7577826Sroot } *uap = (struct a *)u.u_ap; 7587701Ssam struct inode *ip; 7597701Ssam struct file *fp; 7607701Ssam 76112756Ssam fp = getinode(uap->fd); 7627701Ssam if (fp == NULL) 7637701Ssam return; 7647701Ssam if ((fp->f_flag&FWRITE) == 0) { 7657701Ssam u.u_error = EINVAL; 7667701Ssam return; 7677701Ssam } 76812756Ssam ip = (struct inode *)fp->f_data; 76916664Smckusick ILOCK(ip); 77026473Skarels itrunc(ip, (u_long)uap->length); 77116664Smckusick IUNLOCK(ip); 7727701Ssam } 7737701Ssam 7749167Ssam /* 7759167Ssam * Synch an open file. 7769167Ssam */ 7779167Ssam fsync() 7789167Ssam { 7799167Ssam struct a { 7809167Ssam int fd; 7819167Ssam } *uap = (struct a *)u.u_ap; 7829167Ssam struct inode *ip; 7839167Ssam struct file *fp; 7849167Ssam 78512756Ssam fp = getinode(uap->fd); 7869167Ssam if (fp == NULL) 7879167Ssam return; 78812756Ssam ip = (struct inode *)fp->f_data; 78916664Smckusick ILOCK(ip); 79030598Smckusick if (fp->f_flag&FWRITE) 79130598Smckusick ip->i_flag |= ICHG; 7929167Ssam syncip(ip); 79316664Smckusick IUNLOCK(ip); 7949167Ssam } 7959167Ssam 7969167Ssam /* 7979167Ssam * Rename system call. 7989167Ssam * rename("foo", "bar"); 7999167Ssam * is essentially 8009167Ssam * unlink("bar"); 8019167Ssam * link("foo", "bar"); 8029167Ssam * unlink("foo"); 8039167Ssam * but ``atomically''. Can't do full commit without saving state in the 8049167Ssam * inode on disk which isn't feasible at this time. Best we can do is 8059167Ssam * always guarantee the target exists. 8069167Ssam * 8079167Ssam * Basic algorithm is: 8089167Ssam * 8099167Ssam * 1) Bump link count on source while we're linking it to the 8109167Ssam * target. This also insure the inode won't be deleted out 81116776Smckusick * from underneath us while we work (it may be truncated by 81216776Smckusick * a concurrent `trunc' or `open' for creation). 8139167Ssam * 2) Link source to destination. If destination already exists, 8149167Ssam * delete it first. 81516776Smckusick * 3) Unlink source reference to inode if still around. If a 81616776Smckusick * directory was moved and the parent of the destination 8179167Ssam * is different from the source, patch the ".." entry in the 8189167Ssam * directory. 8199167Ssam * 8209167Ssam * Source and destination must either both be directories, or both 8219167Ssam * not be directories. If target is a directory, it must be empty. 8229167Ssam */ 8237701Ssam rename() 8247701Ssam { 8257701Ssam struct a { 8267701Ssam char *from; 8277701Ssam char *to; 82816694Smckusick } *uap = (struct a *)u.u_ap; 8299167Ssam register struct inode *ip, *xp, *dp; 83016776Smckusick struct dirtemplate dirbuf; 83116776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0; 83216694Smckusick register struct nameidata *ndp = &u.u_nd; 83310051Ssam int error = 0; 8347701Ssam 83516694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 83616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83716694Smckusick ndp->ni_dirp = uap->from; 83816694Smckusick ip = namei(ndp); 8399167Ssam if (ip == NULL) 8409167Ssam return; 84116694Smckusick dp = ndp->ni_pdir; 8429167Ssam if ((ip->i_mode&IFMT) == IFDIR) { 8439167Ssam register struct direct *d; 8449167Ssam 84516694Smckusick d = &ndp->ni_dent; 8469167Ssam /* 84711641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons. 8489167Ssam */ 84911641Ssam if ((d->d_namlen == 1 && d->d_name[0] == '.') || 85011641Ssam (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) || 85116776Smckusick (dp == ip) || (ip->i_flag & IRENAME)) { 85211641Ssam iput(dp); 85311641Ssam if (dp == ip) 85411641Ssam irele(ip); 85511641Ssam else 85610051Ssam iput(ip); 85711641Ssam u.u_error = EINVAL; 85811641Ssam return; 8599167Ssam } 86016776Smckusick ip->i_flag |= IRENAME; 8619167Ssam oldparent = dp->i_number; 8629167Ssam doingdirectory++; 8639167Ssam } 86411641Ssam iput(dp); 8659167Ssam 8669167Ssam /* 8679167Ssam * 1) Bump link count while we're moving stuff 8689167Ssam * around. If we crash somewhere before 8699167Ssam * completing our work, the link count 8709167Ssam * may be wrong, but correctable. 8719167Ssam */ 8729167Ssam ip->i_nlink++; 8739167Ssam ip->i_flag |= ICHG; 8749167Ssam iupdat(ip, &time, &time, 1); 87516664Smckusick IUNLOCK(ip); 8769167Ssam 8779167Ssam /* 8789167Ssam * When the target exists, both the directory 8799167Ssam * and target inodes are returned locked. 8809167Ssam */ 88116694Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE; 88216694Smckusick ndp->ni_dirp = (caddr_t)uap->to; 88316694Smckusick xp = namei(ndp); 88410051Ssam if (u.u_error) { 88510051Ssam error = u.u_error; 8869167Ssam goto out; 88710051Ssam } 88816694Smckusick dp = ndp->ni_pdir; 8899167Ssam /* 89011641Ssam * If ".." must be changed (ie the directory gets a new 89112816Smckusick * parent) then the source directory must not be in the 89212816Smckusick * directory heirarchy above the target, as this would 89312816Smckusick * orphan everything below the source directory. Also 89412816Smckusick * the user must have write permission in the source so 89512816Smckusick * as to be able to change "..". We must repeat the call 89612816Smckusick * to namei, as the parent directory is unlocked by the 89712816Smckusick * call to checkpath(). 89811641Ssam */ 89916776Smckusick if (oldparent != dp->i_number) 90016776Smckusick newparent = dp->i_number; 90116776Smckusick if (doingdirectory && newparent) { 90212816Smckusick if (access(ip, IWRITE)) 90312816Smckusick goto bad; 90412816Smckusick do { 90516694Smckusick dp = ndp->ni_pdir; 90612816Smckusick if (xp != NULL) 90712816Smckusick iput(xp); 90812816Smckusick u.u_error = checkpath(ip, dp); 90912816Smckusick if (u.u_error) 91012816Smckusick goto out; 91116694Smckusick xp = namei(ndp); 91212816Smckusick if (u.u_error) { 91312816Smckusick error = u.u_error; 91412816Smckusick goto out; 91512816Smckusick } 91616694Smckusick } while (dp != ndp->ni_pdir); 91712816Smckusick } 91811641Ssam /* 9199167Ssam * 2) If target doesn't exist, link the target 9209167Ssam * to the source and unlink the source. 9219167Ssam * Otherwise, rewrite the target directory 9229167Ssam * entry to reference the source inode and 9239167Ssam * expunge the original entry's existence. 9249167Ssam */ 9259167Ssam if (xp == NULL) { 9269167Ssam if (dp->i_dev != ip->i_dev) { 92710051Ssam error = EXDEV; 9289167Ssam goto bad; 9299167Ssam } 9309167Ssam /* 93116776Smckusick * Account for ".." in new directory. 93216776Smckusick * When source and destination have the same 93316776Smckusick * parent we don't fool with the link count. 9349167Ssam */ 93516776Smckusick if (doingdirectory && newparent) { 9369167Ssam dp->i_nlink++; 9379167Ssam dp->i_flag |= ICHG; 9389167Ssam iupdat(dp, &time, &time, 1); 9399167Ssam } 94016694Smckusick error = direnter(ip, ndp); 94110850Ssam if (error) 9429167Ssam goto out; 9439167Ssam } else { 9449167Ssam if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) { 94510051Ssam error = EXDEV; 9469167Ssam goto bad; 9479167Ssam } 9489167Ssam /* 94910590Ssam * Short circuit rename(foo, foo). 95010590Ssam */ 95110590Ssam if (xp->i_number == ip->i_number) 95210590Ssam goto bad; 95310590Ssam /* 95424433Sbloom * If the parent directory is "sticky", then the user must 95524433Sbloom * own the parent directory, or the destination of the rename, 95624433Sbloom * otherwise the destination may not be changed (except by 95724433Sbloom * root). This implements append-only directories. 95824433Sbloom */ 95924433Sbloom if ((dp->i_mode & ISVTX) && u.u_uid != 0 && 96024433Sbloom u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) { 96124433Sbloom error = EPERM; 96224433Sbloom goto bad; 96324433Sbloom } 96424433Sbloom /* 96510051Ssam * Target must be empty if a directory 96610051Ssam * and have no links to it. 9679167Ssam * Also, insure source and target are 9689167Ssam * compatible (both directories, or both 9699167Ssam * not directories). 9709167Ssam */ 9719167Ssam if ((xp->i_mode&IFMT) == IFDIR) { 97216776Smckusick if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) { 97310051Ssam error = ENOTEMPTY; 9749167Ssam goto bad; 9759167Ssam } 9769167Ssam if (!doingdirectory) { 97710051Ssam error = ENOTDIR; 9789167Ssam goto bad; 9799167Ssam } 98016776Smckusick cacheinval(dp); 9819167Ssam } else if (doingdirectory) { 98210051Ssam error = EISDIR; 9839167Ssam goto bad; 9849167Ssam } 98516694Smckusick dirrewrite(dp, ip, ndp); 98610051Ssam if (u.u_error) { 98710051Ssam error = u.u_error; 9889167Ssam goto bad1; 98910051Ssam } 9909167Ssam /* 99110051Ssam * Adjust the link count of the target to 99210051Ssam * reflect the dirrewrite above. If this is 99310051Ssam * a directory it is empty and there are 99410051Ssam * no links to it, so we can squash the inode and 99510051Ssam * any space associated with it. We disallowed 99610051Ssam * renaming over top of a directory with links to 99716776Smckusick * it above, as the remaining link would point to 99816776Smckusick * a directory without "." or ".." entries. 9999167Ssam */ 100010051Ssam xp->i_nlink--; 10019167Ssam if (doingdirectory) { 100210051Ssam if (--xp->i_nlink != 0) 100310051Ssam panic("rename: linked directory"); 10049167Ssam itrunc(xp, (u_long)0); 100510051Ssam } 10069167Ssam xp->i_flag |= ICHG; 10079167Ssam iput(xp); 100810246Ssam xp = NULL; 10099167Ssam } 10109167Ssam 10119167Ssam /* 10129167Ssam * 3) Unlink the source. 10139167Ssam */ 101416694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 101516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 101616694Smckusick ndp->ni_dirp = uap->from; 101716776Smckusick xp = namei(ndp); 101817758Smckusick if (xp != NULL) 101917758Smckusick dp = ndp->ni_pdir; 102017758Smckusick else 102117758Smckusick dp = NULL; 10229167Ssam /* 102316776Smckusick * Insure that the directory entry still exists and has not 102416776Smckusick * changed while the new name has been entered. If the source is 102516776Smckusick * a file then the entry may have been unlinked or renamed. In 102616776Smckusick * either case there is no further work to be done. If the source 102716776Smckusick * is a directory then it cannot have been rmdir'ed; its link 102816776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY. 102916776Smckusick * The IRENAME flag insures that it cannot be moved by another 103016776Smckusick * rename. 10319167Ssam */ 103217758Smckusick if (xp != ip) { 103316776Smckusick if (doingdirectory) 103417758Smckusick panic("rename: lost dir entry"); 103516776Smckusick } else { 10369167Ssam /* 103716776Smckusick * If the source is a directory with a 103816776Smckusick * new parent, the link count of the old 103916776Smckusick * parent directory must be decremented 104016776Smckusick * and ".." set to point to the new parent. 10419167Ssam */ 104216776Smckusick if (doingdirectory && newparent) { 10439167Ssam dp->i_nlink--; 10449167Ssam dp->i_flag |= ICHG; 104516776Smckusick error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf, 104616776Smckusick sizeof (struct dirtemplate), (off_t)0, 1, 104716776Smckusick (int *)0); 104816776Smckusick if (error == 0) { 104916776Smckusick if (dirbuf.dotdot_namlen != 2 || 105016776Smckusick dirbuf.dotdot_name[0] != '.' || 105116776Smckusick dirbuf.dotdot_name[1] != '.') { 105216776Smckusick printf("rename: mangled dir\n"); 105316776Smckusick } else { 105416776Smckusick dirbuf.dotdot_ino = newparent; 105516776Smckusick (void) rdwri(UIO_WRITE, xp, 105616776Smckusick (caddr_t)&dirbuf, 105716776Smckusick sizeof (struct dirtemplate), 105816776Smckusick (off_t)0, 1, (int *)0); 105916776Smckusick cacheinval(dp); 106016776Smckusick } 106116776Smckusick } 10629167Ssam } 106316694Smckusick if (dirremove(ndp)) { 106416776Smckusick xp->i_nlink--; 106516776Smckusick xp->i_flag |= ICHG; 10669167Ssam } 106716776Smckusick xp->i_flag &= ~IRENAME; 106816776Smckusick if (error == 0) /* XXX conservative */ 106910051Ssam error = u.u_error; 10709167Ssam } 10719167Ssam if (dp) 10729167Ssam iput(dp); 107316776Smckusick if (xp) 107416776Smckusick iput(xp); 107516776Smckusick irele(ip); 107616776Smckusick if (error) 107716776Smckusick u.u_error = error; 107816776Smckusick return; 10799167Ssam 10809167Ssam bad: 108110246Ssam iput(dp); 10829167Ssam bad1: 10839167Ssam if (xp) 108410246Ssam iput(xp); 10859167Ssam out: 10869167Ssam ip->i_nlink--; 10879167Ssam ip->i_flag |= ICHG; 10889167Ssam irele(ip); 108910051Ssam if (error) 109010051Ssam u.u_error = error; 10917701Ssam } 10927701Ssam 10937535Sroot /* 10947535Sroot * Make a new file. 10957535Sroot */ 10967535Sroot struct inode * 109716694Smckusick maknode(mode, ndp) 10987535Sroot int mode; 109916694Smckusick register struct nameidata *ndp; 11007535Sroot { 11017535Sroot register struct inode *ip; 110216694Smckusick register struct inode *pdir = ndp->ni_pdir; 11037535Sroot ino_t ipref; 11047535Sroot 11057535Sroot if ((mode & IFMT) == IFDIR) 110616694Smckusick ipref = dirpref(pdir->i_fs); 11077535Sroot else 110816694Smckusick ipref = pdir->i_number; 110916694Smckusick ip = ialloc(pdir, ipref, mode); 11107535Sroot if (ip == NULL) { 111116694Smckusick iput(pdir); 11127701Ssam return (NULL); 11137535Sroot } 11147701Ssam #ifdef QUOTA 11157535Sroot if (ip->i_dquot != NODQUOT) 11167535Sroot panic("maknode: dquot"); 11177535Sroot #endif 11187535Sroot ip->i_flag |= IACC|IUPD|ICHG; 11197535Sroot if ((mode & IFMT) == 0) 11207535Sroot mode |= IFREG; 11217535Sroot ip->i_mode = mode & ~u.u_cmask; 11227535Sroot ip->i_nlink = 1; 11237535Sroot ip->i_uid = u.u_uid; 112416694Smckusick ip->i_gid = pdir->i_gid; 112530926Skarels if (ip->i_mode & ISGID && !groupmember(ip->i_gid) && !suser()) 112611811Ssam ip->i_mode &= ~ISGID; 11277701Ssam #ifdef QUOTA 11287535Sroot ip->i_dquot = inoquota(ip); 11297535Sroot #endif 11307535Sroot 11317535Sroot /* 11327535Sroot * Make sure inode goes to disk before directory entry. 11337535Sroot */ 11348673Sroot iupdat(ip, &time, &time, 1); 113516694Smckusick u.u_error = direnter(ip, ndp); 11367535Sroot if (u.u_error) { 11377535Sroot /* 113810850Ssam * Write error occurred trying to update directory 113910850Ssam * so must deallocate the inode. 11407535Sroot */ 11417535Sroot ip->i_nlink = 0; 11427535Sroot ip->i_flag |= ICHG; 11437535Sroot iput(ip); 11447701Ssam return (NULL); 11457535Sroot } 11467701Ssam return (ip); 11477535Sroot } 114812756Ssam 114912756Ssam /* 115012756Ssam * A virgin directory (no blushing please). 115112756Ssam */ 115212756Ssam struct dirtemplate mastertemplate = { 115312756Ssam 0, 12, 1, ".", 115412756Ssam 0, DIRBLKSIZ - 12, 2, ".." 115512756Ssam }; 115612756Ssam 115712756Ssam /* 115812756Ssam * Mkdir system call 115912756Ssam */ 116012756Ssam mkdir() 116112756Ssam { 116212756Ssam struct a { 116312756Ssam char *name; 116412756Ssam int dmode; 116516694Smckusick } *uap = (struct a *)u.u_ap; 116612756Ssam register struct inode *ip, *dp; 116712756Ssam struct dirtemplate dirtemplate; 116816694Smckusick register struct nameidata *ndp = &u.u_nd; 116912756Ssam 117016694Smckusick ndp->ni_nameiop = CREATE; 117116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 117216694Smckusick ndp->ni_dirp = uap->name; 117316694Smckusick ip = namei(ndp); 117412756Ssam if (u.u_error) 117512756Ssam return; 117612756Ssam if (ip != NULL) { 117712756Ssam iput(ip); 117812756Ssam u.u_error = EEXIST; 117912756Ssam return; 118012756Ssam } 118116694Smckusick dp = ndp->ni_pdir; 118212756Ssam uap->dmode &= 0777; 118312756Ssam uap->dmode |= IFDIR; 118412756Ssam /* 118512756Ssam * Must simulate part of maknode here 118612756Ssam * in order to acquire the inode, but 118712756Ssam * not have it entered in the parent 118812756Ssam * directory. The entry is made later 118912756Ssam * after writing "." and ".." entries out. 119012756Ssam */ 119112756Ssam ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode); 119212756Ssam if (ip == NULL) { 119312756Ssam iput(dp); 119412756Ssam return; 119512756Ssam } 119612756Ssam #ifdef QUOTA 119712756Ssam if (ip->i_dquot != NODQUOT) 119812756Ssam panic("mkdir: dquot"); 119912756Ssam #endif 120012756Ssam ip->i_flag |= IACC|IUPD|ICHG; 120112756Ssam ip->i_mode = uap->dmode & ~u.u_cmask; 120212756Ssam ip->i_nlink = 2; 120312756Ssam ip->i_uid = u.u_uid; 120412756Ssam ip->i_gid = dp->i_gid; 120512756Ssam #ifdef QUOTA 120612756Ssam ip->i_dquot = inoquota(ip); 120712756Ssam #endif 120812756Ssam iupdat(ip, &time, &time, 1); 120912756Ssam 121012756Ssam /* 121112756Ssam * Bump link count in parent directory 121212756Ssam * to reflect work done below. Should 121312756Ssam * be done before reference is created 121412756Ssam * so reparation is possible if we crash. 121512756Ssam */ 121612756Ssam dp->i_nlink++; 121712756Ssam dp->i_flag |= ICHG; 121812756Ssam iupdat(dp, &time, &time, 1); 121912756Ssam 122012756Ssam /* 122112756Ssam * Initialize directory with "." 122212756Ssam * and ".." from static template. 122312756Ssam */ 122412756Ssam dirtemplate = mastertemplate; 122512756Ssam dirtemplate.dot_ino = ip->i_number; 122612756Ssam dirtemplate.dotdot_ino = dp->i_number; 122712756Ssam u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate, 122812756Ssam sizeof (dirtemplate), (off_t)0, 1, (int *)0); 122912756Ssam if (u.u_error) { 123012756Ssam dp->i_nlink--; 123112756Ssam dp->i_flag |= ICHG; 123212756Ssam goto bad; 123312756Ssam } 123418103Smckusick if (DIRBLKSIZ > ip->i_fs->fs_fsize) 123518103Smckusick panic("mkdir: blksize"); /* XXX - should grow with bmap() */ 123618103Smckusick else 123718103Smckusick ip->i_size = DIRBLKSIZ; 123812756Ssam /* 123912756Ssam * Directory all set up, now 124012756Ssam * install the entry for it in 124112756Ssam * the parent directory. 124212756Ssam */ 124316694Smckusick u.u_error = direnter(ip, ndp); 124412756Ssam dp = NULL; 124512756Ssam if (u.u_error) { 124616694Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE; 124716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 124816694Smckusick ndp->ni_dirp = uap->name; 124916694Smckusick dp = namei(ndp); 125012756Ssam if (dp) { 125112756Ssam dp->i_nlink--; 125212756Ssam dp->i_flag |= ICHG; 125312756Ssam } 125412756Ssam } 125512756Ssam bad: 125612756Ssam /* 125712756Ssam * No need to do an explicit itrunc here, 125812756Ssam * irele will do this for us because we set 125912756Ssam * the link count to 0. 126012756Ssam */ 126112756Ssam if (u.u_error) { 126212756Ssam ip->i_nlink = 0; 126312756Ssam ip->i_flag |= ICHG; 126412756Ssam } 126512756Ssam if (dp) 126612756Ssam iput(dp); 126712756Ssam iput(ip); 126812756Ssam } 126912756Ssam 127012756Ssam /* 127112756Ssam * Rmdir system call. 127212756Ssam */ 127312756Ssam rmdir() 127412756Ssam { 127512756Ssam struct a { 127612756Ssam char *name; 127716694Smckusick } *uap = (struct a *)u.u_ap; 127812756Ssam register struct inode *ip, *dp; 127916694Smckusick register struct nameidata *ndp = &u.u_nd; 128012756Ssam 128116694Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT; 128216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 128316694Smckusick ndp->ni_dirp = uap->name; 128416694Smckusick ip = namei(ndp); 128512756Ssam if (ip == NULL) 128612756Ssam return; 128716694Smckusick dp = ndp->ni_pdir; 128812756Ssam /* 128912756Ssam * No rmdir "." please. 129012756Ssam */ 129112756Ssam if (dp == ip) { 129212756Ssam irele(dp); 129312756Ssam iput(ip); 129412756Ssam u.u_error = EINVAL; 129512756Ssam return; 129612756Ssam } 129712756Ssam if ((ip->i_mode&IFMT) != IFDIR) { 129812756Ssam u.u_error = ENOTDIR; 129912756Ssam goto out; 130012756Ssam } 130112756Ssam /* 130212756Ssam * Don't remove a mounted on directory. 130312756Ssam */ 130412756Ssam if (ip->i_dev != dp->i_dev) { 130512756Ssam u.u_error = EBUSY; 130612756Ssam goto out; 130712756Ssam } 130812756Ssam /* 130912756Ssam * Verify the directory is empty (and valid). 131012756Ssam * (Rmdir ".." won't be valid since 131112756Ssam * ".." will contain a reference to 131212756Ssam * the current directory and thus be 131312756Ssam * non-empty.) 131412756Ssam */ 131516776Smckusick if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) { 131612756Ssam u.u_error = ENOTEMPTY; 131712756Ssam goto out; 131812756Ssam } 131912756Ssam /* 132012756Ssam * Delete reference to directory before purging 132112756Ssam * inode. If we crash in between, the directory 132212756Ssam * will be reattached to lost+found, 132312756Ssam */ 132416694Smckusick if (dirremove(ndp) == 0) 132512756Ssam goto out; 132612756Ssam dp->i_nlink--; 132712756Ssam dp->i_flag |= ICHG; 132816776Smckusick cacheinval(dp); 132912756Ssam iput(dp); 133012756Ssam dp = NULL; 133112756Ssam /* 133212756Ssam * Truncate inode. The only stuff left 133312756Ssam * in the directory is "." and "..". The 133412756Ssam * "." reference is inconsequential since 133512756Ssam * we're quashing it. The ".." reference 133612756Ssam * has already been adjusted above. We've 133712756Ssam * removed the "." reference and the reference 133812756Ssam * in the parent directory, but there may be 133912756Ssam * other hard links so decrement by 2 and 134012756Ssam * worry about them later. 134112756Ssam */ 134212756Ssam ip->i_nlink -= 2; 134312756Ssam itrunc(ip, (u_long)0); 134416739Smckusick cacheinval(ip); 134512756Ssam out: 134612756Ssam if (dp) 134712756Ssam iput(dp); 134812756Ssam iput(ip); 134912756Ssam } 135012756Ssam 135112756Ssam struct file * 135212756Ssam getinode(fdes) 135312756Ssam int fdes; 135412756Ssam { 135516540Ssam struct file *fp; 135612756Ssam 135716540Ssam if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { 135816540Ssam u.u_error = EBADF; 135916540Ssam return ((struct file *)0); 136016540Ssam } 136112756Ssam if (fp->f_type != DTYPE_INODE) { 136212756Ssam u.u_error = EINVAL; 136316540Ssam return ((struct file *)0); 136412756Ssam } 136512756Ssam return (fp); 136612756Ssam } 136712756Ssam 136812756Ssam /* 136912756Ssam * mode mask for creation of files 137012756Ssam */ 137112756Ssam umask() 137212756Ssam { 137312756Ssam register struct a { 137412756Ssam int mask; 137516694Smckusick } *uap = (struct a *)u.u_ap; 137612756Ssam 137712756Ssam u.u_r.r_val1 = u.u_cmask; 137812756Ssam u.u_cmask = uap->mask & 07777; 137912756Ssam } 1380