LCOV - code coverage report
Current view: top level - ufs/ufs - ufs_vnops.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1000 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 39 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ufs_vnops.c,v 1.142 2018/06/21 14:17:23 visa Exp $    */
       2             : /*      $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $   */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1982, 1986, 1989, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  * (c) UNIX System Laboratories, Inc.
       8             :  * All or some portions of this file are derived from material licensed
       9             :  * to the University of California by American Telephone and Telegraph
      10             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      11             :  * the permission of UNIX System Laboratories, Inc.
      12             :  *
      13             :  * Redistribution and use in source and binary forms, with or without
      14             :  * modification, are permitted provided that the following conditions
      15             :  * are met:
      16             :  * 1. Redistributions of source code must retain the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer.
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  * 3. Neither the name of the University nor the names of its contributors
      22             :  *    may be used to endorse or promote products derived from this software
      23             :  *    without specific prior written permission.
      24             :  *
      25             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      26             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      27             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      28             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      29             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      30             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      31             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      32             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      33             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      34             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      35             :  * SUCH DAMAGE.
      36             :  *
      37             :  *      @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
      38             :  */
      39             : 
      40             : #include <sys/param.h>
      41             : #include <sys/systm.h>
      42             : #include <sys/namei.h>
      43             : #include <sys/resourcevar.h>
      44             : #include <sys/kernel.h>
      45             : #include <sys/fcntl.h>
      46             : #include <sys/file.h>
      47             : #include <sys/stat.h>
      48             : #include <sys/buf.h>
      49             : #include <sys/proc.h>
      50             : #include <sys/mount.h>
      51             : #include <sys/vnode.h>
      52             : #include <sys/malloc.h>
      53             : #include <sys/pool.h>
      54             : #include <sys/dirent.h>
      55             : #include <sys/lockf.h>
      56             : #include <sys/event.h>
      57             : #include <sys/poll.h>
      58             : #include <sys/specdev.h>
      59             : #include <sys/unistd.h>
      60             : 
      61             : #include <miscfs/fifofs/fifo.h>
      62             : 
      63             : #include <ufs/ufs/quota.h>
      64             : #include <ufs/ufs/inode.h>
      65             : #include <ufs/ufs/dir.h>
      66             : #include <ufs/ufs/ufsmount.h>
      67             : #include <ufs/ufs/ufs_extern.h>
      68             : #ifdef UFS_DIRHASH
      69             : #include <ufs/ufs/dirhash.h>
      70             : #endif
      71             : #include <ufs/ext2fs/ext2fs_extern.h>
      72             : 
      73             : #include <uvm/uvm_extern.h>
      74             : 
      75             : int ufs_chmod(struct vnode *, int, struct ucred *, struct proc *);
      76             : int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
      77             : int filt_ufsread(struct knote *, long);
      78             : int filt_ufswrite(struct knote *, long);
      79             : int filt_ufsvnode(struct knote *, long);
      80             : void filt_ufsdetach(struct knote *);
      81             : 
      82             : /*
      83             :  * A virgin directory (no blushing please).
      84             :  */
      85             : static struct dirtemplate mastertemplate = {
      86             :         0, 12, DT_DIR, 1, ".",
      87             :         0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
      88             : };
      89             : static struct odirtemplate omastertemplate = {
      90             :         0, 12, 1, ".",
      91             :         0, DIRBLKSIZ - 12, 2, ".."
      92             : };
      93             : 
      94             : /*
      95             :  * Update the times in the inode
      96             :  */
      97             : void
      98           0 : ufs_itimes(struct vnode *vp)
      99             : {
     100             :         struct inode *ip;
     101           0 :         struct timespec ts;
     102             : 
     103           0 :         ip = VTOI(vp);
     104           0 :         if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
     105           0 :                 return;
     106             : 
     107           0 :         if (vp->v_mount->mnt_flag & MNT_RDONLY)
     108             :                 goto out;
     109             : 
     110             : #ifdef EXT2FS
     111           0 :         if (IS_EXT2_VNODE(ip->i_vnode)) {
     112           0 :                 EXT2FS_ITIMES(ip);
     113             :                 goto out;
     114             :         }
     115             : #endif
     116             : 
     117           0 :         if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp))
     118           0 :                 ip->i_flag |= IN_LAZYMOD;
     119             :         else
     120           0 :                 ip->i_flag |= IN_MODIFIED;
     121             : 
     122           0 :         getnanotime(&ts);
     123           0 :         if (ip->i_flag & IN_ACCESS) {
     124           0 :                 DIP_ASSIGN(ip, atime, ts.tv_sec);
     125           0 :                 DIP_ASSIGN(ip, atimensec, ts.tv_nsec);
     126             :         }
     127           0 :         if (ip->i_flag & IN_UPDATE) {
     128           0 :                 DIP_ASSIGN(ip, mtime, ts.tv_sec);
     129           0 :                 DIP_ASSIGN(ip, mtimensec, ts.tv_nsec);
     130             :         }
     131           0 :         if (ip->i_flag & IN_CHANGE) {
     132           0 :                 DIP_ASSIGN(ip, ctime, ts.tv_sec);
     133           0 :                 DIP_ASSIGN(ip, ctimensec, ts.tv_nsec);
     134           0 :                 ip->i_modrev++;
     135           0 :         }
     136             : 
     137             :  out:
     138           0 :         ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
     139           0 : }
     140             : 
     141             : 
     142             : /*
     143             :  * Create a regular file
     144             :  */
     145             : int
     146           0 : ufs_create(void *v)
     147             : {
     148           0 :         struct vop_create_args *ap = v;
     149             :         int error;
     150             : 
     151             :         error =
     152           0 :             ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
     153           0 :                           ap->a_dvp, ap->a_vpp, ap->a_cnp);
     154           0 :         if (error == 0)
     155           0 :                 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
     156           0 :         return (error);
     157             : }
     158             : 
     159             : /*
     160             :  * Mknod vnode call
     161             :  */
     162             : int
     163           0 : ufs_mknod(void *v)
     164             : {
     165           0 :         struct vop_mknod_args *ap = v;
     166           0 :         struct vattr *vap = ap->a_vap;
     167           0 :         struct vnode **vpp = ap->a_vpp;
     168             :         struct inode *ip;
     169             :         int error;
     170             : 
     171           0 :         if ((error =
     172           0 :             ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
     173           0 :             ap->a_dvp, vpp, ap->a_cnp)) != 0)
     174           0 :                 return (error);
     175           0 :         VN_KNOTE(ap->a_dvp, NOTE_WRITE);
     176           0 :         ip = VTOI(*vpp);
     177           0 :         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
     178           0 :         if (vap->va_rdev != VNOVAL) {
     179             :                 /*
     180             :                  * Want to be able to use this to make badblock
     181             :                  * inodes, so don't truncate the dev number.
     182             :                  */
     183           0 :                 DIP_ASSIGN(ip, rdev, vap->va_rdev);
     184             :         }
     185             :         /*
     186             :          * Remove inode so that it will be reloaded by VFS_VGET and
     187             :          * checked to see if it is an alias of an existing entry in
     188             :          * the inode cache.
     189             :          */
     190           0 :         vput(*vpp);
     191           0 :         (*vpp)->v_type = VNON;
     192           0 :         vgone(*vpp);
     193           0 :         *vpp = NULL;
     194           0 :         return (0);
     195           0 : }
     196             : 
     197             : /*
     198             :  * Open called.
     199             :  *
     200             :  * Nothing to do.
     201             :  */
     202             : int
     203           0 : ufs_open(void *v)
     204             : {
     205           0 :         struct vop_open_args *ap = v;
     206           0 :         struct inode *ip = VTOI(ap->a_vp);
     207             : 
     208             :         /*
     209             :          * Files marked append-only must be opened for appending.
     210             :          */
     211           0 :         if ((DIP(ip, flags) & APPEND) &&
     212           0 :             (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
     213           0 :                 return (EPERM);
     214             : 
     215           0 :         if (ap->a_mode & O_TRUNC)
     216           0 :                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
     217             : 
     218           0 :         return (0);
     219           0 : }
     220             : 
     221             : /*
     222             :  * Close called.
     223             :  *
     224             :  * Update the times on the inode.
     225             :  */
     226             : int
     227           0 : ufs_close(void *v)
     228             : {
     229           0 :         struct vop_close_args *ap = v;
     230           0 :         struct vnode *vp = ap->a_vp;
     231             : 
     232           0 :         if (vp->v_usecount > 1)
     233           0 :                 ufs_itimes(vp);
     234           0 :         return (0);
     235             : }
     236             : 
     237             : int
     238           0 : ufs_access(void *v)
     239             : {
     240           0 :         struct vop_access_args *ap = v;
     241           0 :         struct vnode *vp = ap->a_vp;
     242           0 :         struct inode *ip = VTOI(vp);
     243           0 :         mode_t mode = ap->a_mode;
     244             : 
     245             :         /*
     246             :          * Disallow write attempts on read-only file systems;
     247             :          * unless the file is a socket, fifo, or a block or
     248             :          * character device resident on the file system.
     249             :          */
     250           0 :         if (mode & VWRITE) {
     251           0 :                 switch (vp->v_type) {
     252             :                         int error;
     253             :                 case VDIR:
     254             :                 case VLNK:
     255             :                 case VREG:
     256           0 :                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
     257           0 :                                 return (EROFS);
     258             : 
     259           0 :                         if ((error = getinoquota(ip)) != 0)
     260           0 :                                 return (error);
     261             :                         break;
     262             :                 case VBAD:
     263             :                 case VBLK:
     264             :                 case VCHR:
     265             :                 case VSOCK:
     266             :                 case VFIFO:
     267             :                 case VNON:
     268             :                         break;
     269             : 
     270             :                 }
     271             :         }
     272             : 
     273             :         /* If immutable bit set, nobody gets to write it. */
     274           0 :         if ((mode & VWRITE) && (DIP(ip, flags) & IMMUTABLE))
     275           0 :                 return (EPERM);
     276             : 
     277           0 :         if ((vp->v_mount->mnt_flag & MNT_NOPERM) &&
     278           0 :             (vp->v_flag & VROOT) == 0)
     279           0 :                 return (0);
     280             : 
     281           0 :         return (vaccess(vp->v_type, DIP(ip, mode), DIP(ip, uid), DIP(ip, gid),
     282           0 :             mode, ap->a_cred));
     283           0 : }
     284             : 
     285             : int
     286           0 : ufs_getattr(void *v)
     287             : {
     288           0 :         struct vop_getattr_args *ap = v;
     289           0 :         struct vnode *vp = ap->a_vp;
     290           0 :         struct inode *ip = VTOI(vp);
     291           0 :         struct vattr *vap = ap->a_vap;
     292             : 
     293           0 :         ufs_itimes(vp);
     294             : 
     295             :         /*
     296             :          * Copy from inode table
     297             :          */
     298           0 :         vap->va_fsid = ip->i_dev;
     299           0 :         vap->va_fileid = ip->i_number;
     300           0 :         vap->va_mode = DIP(ip, mode) & ~IFMT;
     301           0 :         vap->va_nlink = ip->i_effnlink;
     302           0 :         vap->va_uid = DIP(ip, uid);
     303           0 :         vap->va_gid = DIP(ip, gid);
     304           0 :         vap->va_rdev = (dev_t) DIP(ip, rdev);
     305           0 :         vap->va_size = DIP(ip, size);
     306           0 :         vap->va_atime.tv_sec = DIP(ip, atime);
     307           0 :         vap->va_atime.tv_nsec = DIP(ip, atimensec);
     308           0 :         vap->va_mtime.tv_sec = DIP(ip, mtime);
     309           0 :         vap->va_mtime.tv_nsec = DIP(ip, mtimensec);
     310           0 :         vap->va_ctime.tv_sec = DIP(ip, ctime);
     311           0 :         vap->va_ctime.tv_nsec = DIP(ip, ctimensec);
     312           0 :         vap->va_flags = DIP(ip, flags);
     313           0 :         vap->va_gen = DIP(ip, gen);
     314             :         /* this doesn't belong here */
     315           0 :         if (vp->v_type == VBLK)
     316           0 :                 vap->va_blocksize = BLKDEV_IOSIZE;
     317           0 :         else if (vp->v_type == VCHR)
     318           0 :                 vap->va_blocksize = MAXBSIZE;
     319             :         else
     320           0 :                 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
     321           0 :         vap->va_bytes = dbtob((u_quad_t) DIP(ip, blocks));
     322           0 :         vap->va_type = vp->v_type;
     323           0 :         vap->va_filerev = ip->i_modrev;
     324           0 :         return (0);
     325             : }
     326             : 
     327             : /*
     328             :  * Set attribute vnode op. called from several syscalls
     329             :  */
     330             : int
     331           0 : ufs_setattr(void *v)
     332             : {
     333           0 :         struct vop_setattr_args *ap = v;
     334           0 :         struct vattr *vap = ap->a_vap;
     335           0 :         struct vnode *vp = ap->a_vp;
     336           0 :         struct inode *ip = VTOI(vp);
     337           0 :         struct ucred *cred = ap->a_cred;
     338           0 :         struct proc *p = ap->a_p;
     339             :         int error;
     340             :         long hint = NOTE_ATTRIB;
     341             :         u_quad_t oldsize;
     342             : 
     343             :         /*
     344             :          * Check for unsettable attributes.
     345             :          */
     346           0 :         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
     347           0 :             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
     348           0 :             (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
     349           0 :             ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
     350           0 :                 return (EINVAL);
     351             :         }
     352           0 :         if (vap->va_flags != VNOVAL) {
     353           0 :                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
     354           0 :                         return (EROFS);
     355           0 :                 if (cred->cr_uid != DIP(ip, uid) &&
     356           0 :                     (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
     357           0 :                     (error = suser_ucred(cred)))
     358           0 :                         return (error);
     359           0 :                 if (cred->cr_uid == 0) {
     360           0 :                         if ((DIP(ip, flags) & (SF_IMMUTABLE | SF_APPEND)) &&
     361           0 :                             securelevel > 0)
     362           0 :                                 return (EPERM);
     363           0 :                         DIP_ASSIGN(ip, flags, vap->va_flags);
     364             :                 } else {
     365           0 :                         if (DIP(ip, flags) & (SF_IMMUTABLE | SF_APPEND) ||
     366           0 :                             (vap->va_flags & UF_SETTABLE) != vap->va_flags)
     367           0 :                                 return (EPERM);
     368           0 :                         DIP_AND(ip, flags, SF_SETTABLE);
     369           0 :                         DIP_OR(ip, flags, vap->va_flags & UF_SETTABLE);
     370             :                 }
     371           0 :                 ip->i_flag |= IN_CHANGE;
     372           0 :                 if (vap->va_flags & (IMMUTABLE | APPEND))
     373           0 :                         return (0);
     374             :         }
     375           0 :         if (DIP(ip, flags) & (IMMUTABLE | APPEND))
     376           0 :                 return (EPERM);
     377             :         /*
     378             :          * Go through the fields and update if not VNOVAL.
     379             :          */
     380           0 :         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
     381           0 :                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
     382           0 :                         return (EROFS);
     383           0 :                 error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
     384           0 :                 if (error)
     385           0 :                         return (error);
     386             :         }
     387           0 :         if (vap->va_size != VNOVAL) {
     388           0 :                 oldsize = DIP(ip, size);
     389             :                 /*
     390             :                  * Disallow write attempts on read-only file systems;
     391             :                  * unless the file is a socket, fifo, or a block or
     392             :                  * character device resident on the file system.
     393             :                  */
     394           0 :                 switch (vp->v_type) {
     395             :                 case VDIR:
     396           0 :                         return (EISDIR);
     397             :                 case VLNK:
     398             :                 case VREG:
     399           0 :                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
     400           0 :                                 return (EROFS);
     401             :                         break;
     402             :                 default:
     403             :                         break;
     404             :                 }
     405           0 :                 if ((error = UFS_TRUNCATE(ip, vap->va_size, 0, cred)) != 0)
     406           0 :                         return (error);
     407           0 :                 if (vap->va_size < oldsize)
     408           0 :                         hint |= NOTE_TRUNCATE;
     409             :         }
     410           0 :         if ((vap->va_vaflags & VA_UTIMES_CHANGE) ||
     411           0 :             vap->va_atime.tv_nsec != VNOVAL ||
     412           0 :             vap->va_mtime.tv_nsec != VNOVAL) {
     413           0 :                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
     414           0 :                         return (EROFS);
     415           0 :                 if (cred->cr_uid != DIP(ip, uid) &&
     416           0 :                     (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
     417           0 :                     (error = suser_ucred(cred)) &&
     418           0 :                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
     419           0 :                     (error = VOP_ACCESS(vp, VWRITE, cred, p))))
     420           0 :                         return (error);
     421           0 :                 if (vap->va_mtime.tv_nsec != VNOVAL)
     422           0 :                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
     423           0 :                 else if (vap->va_vaflags & VA_UTIMES_CHANGE)
     424           0 :                         ip->i_flag |= IN_CHANGE;
     425           0 :                 if (vap->va_atime.tv_nsec != VNOVAL) {
     426           0 :                         if (!(vp->v_mount->mnt_flag & MNT_NOATIME) ||
     427           0 :                             (ip->i_flag & (IN_CHANGE | IN_UPDATE)))
     428           0 :                                 ip->i_flag |= IN_ACCESS;
     429             :                 }
     430           0 :                 ufs_itimes(vp);
     431           0 :                 if (vap->va_mtime.tv_nsec != VNOVAL) {
     432           0 :                         DIP_ASSIGN(ip, mtime, vap->va_mtime.tv_sec);
     433           0 :                         DIP_ASSIGN(ip, mtimensec, vap->va_mtime.tv_nsec);
     434             :                 }
     435           0 :                 if (vap->va_atime.tv_nsec != VNOVAL) {
     436           0 :                         DIP_ASSIGN(ip, atime, vap->va_atime.tv_sec);
     437           0 :                         DIP_ASSIGN(ip, atimensec, vap->va_atime.tv_nsec);
     438             :                 }
     439           0 :                 error = UFS_UPDATE(ip, 0);
     440           0 :                 if (error)
     441           0 :                         return (error);
     442             :         }
     443             :         error = 0;
     444           0 :         if (vap->va_mode != (mode_t)VNOVAL) {
     445           0 :                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
     446           0 :                         return (EROFS);
     447           0 :                 error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
     448           0 :         }
     449           0 :         VN_KNOTE(vp, hint);
     450           0 :         return (error);
     451           0 : }
     452             : 
     453             : /*
     454             :  * Change the mode on a file.
     455             :  * Inode must be locked before calling.
     456             :  */
     457             : int
     458           0 : ufs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
     459             : {
     460           0 :         struct inode *ip = VTOI(vp);
     461             :         int error;
     462             : 
     463           0 :         if (cred->cr_uid != DIP(ip, uid) &&
     464           0 :             (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
     465           0 :             (error = suser_ucred(cred)))
     466           0 :                 return (error);
     467           0 :         if (cred->cr_uid &&
     468           0 :             (vp->v_mount->mnt_flag & MNT_NOPERM) == 0) {
     469           0 :                 if (vp->v_type != VDIR && (mode & S_ISTXT))
     470           0 :                         return (EFTYPE);
     471           0 :                 if (!groupmember(DIP(ip, gid), cred) && (mode & ISGID))
     472           0 :                         return (EPERM);
     473             :         }
     474           0 :         DIP_AND(ip, mode, ~ALLPERMS);
     475           0 :         DIP_OR(ip, mode, mode & ALLPERMS);
     476           0 :         ip->i_flag |= IN_CHANGE;
     477           0 :         if ((vp->v_flag & VTEXT) && (DIP(ip, mode) & S_ISTXT) == 0)
     478           0 :                 (void) uvm_vnp_uncache(vp);
     479           0 :         return (0);
     480           0 : }
     481             : 
     482             : /*
     483             :  * Perform chown operation on inode ip;
     484             :  * inode must be locked prior to call.
     485             :  */
     486             : int
     487           0 : ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
     488             :     struct proc *p)
     489             : {
     490           0 :         struct inode *ip = VTOI(vp);
     491             :         uid_t ouid;
     492             :         gid_t ogid;
     493             :         int error = 0;
     494             :         daddr_t change;
     495             :         enum ufs_quota_flags quota_flags = 0;
     496             : 
     497           0 :         if (uid == (uid_t)VNOVAL)
     498           0 :                 uid = DIP(ip, uid);
     499           0 :         if (gid == (gid_t)VNOVAL)
     500           0 :                 gid = DIP(ip, gid);
     501             :         /*
     502             :          * If we don't own the file, are trying to change the owner
     503             :          * of the file, or are not a member of the target group,
     504             :          * the caller must be superuser or the call fails.
     505             :          */
     506           0 :         if ((cred->cr_uid != DIP(ip, uid) || uid != DIP(ip, uid) ||
     507           0 :             (gid != DIP(ip, gid) && !groupmember(gid, cred))) &&
     508           0 :             (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
     509           0 :             (error = suser_ucred(cred)))
     510           0 :                 return (error);
     511           0 :         ogid = DIP(ip, gid);
     512           0 :         ouid = DIP(ip, uid);
     513           0 :         change = DIP(ip, blocks);
     514             : 
     515           0 :         if (ouid == uid)
     516           0 :                 quota_flags |= UFS_QUOTA_NOUID;
     517             :         
     518           0 :         if (ogid == gid)
     519           0 :                 quota_flags |= UFS_QUOTA_NOGID;
     520             : 
     521           0 :         if ((error = getinoquota(ip)) != 0)
     522           0 :                 return (error);
     523           0 :         (void) ufs_quota_free_blocks2(ip, change, cred, quota_flags);
     524           0 :         (void) ufs_quota_free_inode2(ip, cred, quota_flags);
     525           0 :         (void) ufs_quota_delete(ip);
     526             : 
     527           0 :         DIP_ASSIGN(ip, gid, gid);
     528           0 :         DIP_ASSIGN(ip, uid, uid);
     529             : 
     530           0 :         if ((error = getinoquota(ip)) != 0)
     531             :                 goto error;
     532             : 
     533           0 :         if ((error = ufs_quota_alloc_blocks2(ip, change, cred, 
     534           0 :                  quota_flags)) != 0) 
     535             :                 goto error;
     536             : 
     537           0 :         if ((error = ufs_quota_alloc_inode2(ip, cred ,
     538           0 :                  quota_flags)) != 0) {
     539           0 :                 (void)ufs_quota_free_blocks2(ip, change, cred, 
     540             :                     quota_flags);               
     541           0 :                 goto error;
     542             :         }
     543             : 
     544           0 :         if (getinoquota(ip))
     545           0 :                 panic("chown: lost quota");
     546             : 
     547           0 :         if (ouid != uid || ogid != gid)
     548           0 :                 ip->i_flag |= IN_CHANGE;
     549           0 :         if (ouid != uid && cred->cr_uid != 0 &&
     550           0 :             (vp->v_mount->mnt_flag & MNT_NOPERM) == 0)
     551           0 :                 DIP_AND(ip, mode, ~ISUID);
     552           0 :         if (ogid != gid && cred->cr_uid != 0 &&
     553           0 :             (vp->v_mount->mnt_flag & MNT_NOPERM) == 0)
     554           0 :                 DIP_AND(ip, mode, ~ISGID);
     555           0 :         return (0);
     556             : 
     557             : error:
     558           0 :         (void) ufs_quota_delete(ip);
     559             : 
     560           0 :         DIP_ASSIGN(ip, gid, ogid);
     561           0 :         DIP_ASSIGN(ip, uid, ouid);
     562             : 
     563           0 :         if (getinoquota(ip) == 0) {
     564           0 :                 (void) ufs_quota_alloc_blocks2(ip, change, cred, 
     565           0 :                     quota_flags | UFS_QUOTA_FORCE);
     566           0 :                 (void) ufs_quota_alloc_inode2(ip, cred,
     567             :                     quota_flags | UFS_QUOTA_FORCE);
     568           0 :                 (void) getinoquota(ip);
     569           0 :         }
     570           0 :         return (error);
     571             : 
     572           0 : }
     573             : 
     574             : /* ARGSUSED */
     575             : int
     576           0 : ufs_ioctl(void *v)
     577             : {
     578             : #if 0
     579             :         struct vop_ioctl_args *ap = v;
     580             : #endif
     581           0 :         return (ENOTTY);
     582             : }
     583             : 
     584             : int
     585           0 : ufs_poll(void *v)
     586             : {
     587           0 :         struct vop_poll_args *ap = v;
     588             : 
     589             :         /*
     590             :          * We should really check to see if I/O is possible.
     591             :          */
     592           0 :         return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
     593             : }
     594             : 
     595             : int
     596           0 : ufs_remove(void *v)
     597             : {
     598           0 :         struct vop_remove_args *ap = v;
     599             :         struct inode *ip;
     600           0 :         struct vnode *vp = ap->a_vp;
     601           0 :         struct vnode *dvp = ap->a_dvp;
     602             :         int error;
     603             : 
     604           0 :         ip = VTOI(vp);
     605           0 :         if (vp->v_type == VDIR || (DIP(ip, flags) & (IMMUTABLE | APPEND)) ||
     606           0 :             (DIP(VTOI(dvp), flags) & APPEND)) {
     607             :                 error = EPERM;
     608           0 :                 goto out;
     609             :         }
     610           0 :         error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
     611           0 :         VN_KNOTE(vp, NOTE_DELETE);
     612           0 :         VN_KNOTE(dvp, NOTE_WRITE);
     613             :  out:
     614           0 :         if (dvp == vp)
     615           0 :                 vrele(vp);
     616             :         else
     617           0 :                 vput(vp);
     618           0 :         vput(dvp);
     619           0 :         return (error);
     620             : }
     621             : 
     622             : /*
     623             :  * link vnode call
     624             :  */
     625             : int
     626           0 : ufs_link(void *v)
     627             : {
     628           0 :         struct vop_link_args *ap = v;
     629           0 :         struct vnode *dvp = ap->a_dvp;
     630           0 :         struct vnode *vp = ap->a_vp;
     631           0 :         struct componentname *cnp = ap->a_cnp;
     632             :         struct inode *ip;
     633           0 :         struct direct newdir;
     634             :         int error;
     635             : 
     636             : #ifdef DIAGNOSTIC
     637           0 :         if ((cnp->cn_flags & HASBUF) == 0)
     638           0 :                 panic("ufs_link: no name");
     639             : #endif
     640           0 :         if (vp->v_type == VDIR) {
     641           0 :                 VOP_ABORTOP(dvp, cnp);
     642             :                 error = EPERM;
     643           0 :                 goto out2;
     644             :         }
     645           0 :         if (dvp->v_mount != vp->v_mount) {
     646           0 :                 VOP_ABORTOP(dvp, cnp);
     647             :                 error = EXDEV;
     648           0 :                 goto out2;
     649             :         }
     650           0 :         if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
     651           0 :                 VOP_ABORTOP(dvp, cnp);
     652           0 :                 goto out2;
     653             :         }
     654           0 :         ip = VTOI(vp);
     655           0 :         if ((nlink_t) DIP(ip, nlink) >= LINK_MAX) {
     656           0 :                 VOP_ABORTOP(dvp, cnp);
     657             :                 error = EMLINK;
     658           0 :                 goto out1;
     659             :         }
     660           0 :         if (DIP(ip, flags) & (IMMUTABLE | APPEND)) {
     661           0 :                 VOP_ABORTOP(dvp, cnp);
     662             :                 error = EPERM;
     663           0 :                 goto out1;
     664             :         }
     665           0 :         ip->i_effnlink++;
     666           0 :         DIP_ADD(ip, nlink, 1);
     667           0 :         ip->i_flag |= IN_CHANGE;
     668           0 :         if (DOINGSOFTDEP(vp))
     669           0 :                 softdep_change_linkcnt(ip, 0);
     670           0 :         if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(vp))) == 0) {
     671           0 :                 ufs_makedirentry(ip, cnp, &newdir);
     672           0 :                 error = ufs_direnter(dvp, vp, &newdir, cnp, NULL);
     673           0 :         }
     674           0 :         if (error) {
     675           0 :                 ip->i_effnlink--;
     676           0 :                 DIP_ADD(ip, nlink, -1);
     677           0 :                 ip->i_flag |= IN_CHANGE;
     678           0 :                 if (DOINGSOFTDEP(vp))
     679           0 :                         softdep_change_linkcnt(ip, 0);
     680             :         }
     681           0 :         pool_put(&namei_pool, cnp->cn_pnbuf);
     682           0 :         VN_KNOTE(vp, NOTE_LINK);
     683           0 :         VN_KNOTE(dvp, NOTE_WRITE);
     684             : out1:
     685           0 :         if (dvp != vp)
     686           0 :                 VOP_UNLOCK(vp);
     687             : out2:
     688           0 :         vput(dvp);
     689           0 :         return (error);
     690           0 : }
     691             : 
     692             : /*
     693             :  * Rename system call.
     694             :  *      rename("foo", "bar");
     695             :  * is essentially
     696             :  *      unlink("bar");
     697             :  *      link("foo", "bar");
     698             :  *      unlink("foo");
     699             :  * but ``atomically''.  Can't do full commit without saving state in the
     700             :  * inode on disk which isn't feasible at this time.  Best we can do is
     701             :  * always guarantee the target exists.
     702             :  *
     703             :  * Basic algorithm is:
     704             :  *
     705             :  * 1) Bump link count on source while we're linking it to the
     706             :  *    target.  This also ensure the inode won't be deleted out
     707             :  *    from underneath us while we work (it may be truncated by
     708             :  *    a concurrent `trunc' or `open' for creation).
     709             :  * 2) Link source to destination.  If destination already exists,
     710             :  *    delete it first.
     711             :  * 3) Unlink source reference to inode if still around. If a
     712             :  *    directory was moved and the parent of the destination
     713             :  *    is different from the source, patch the ".." entry in the
     714             :  *    directory.
     715             :  */
     716             : int
     717           0 : ufs_rename(void *v)
     718             : {
     719           0 :         struct vop_rename_args *ap = v;
     720           0 :         struct vnode *tvp = ap->a_tvp;
     721           0 :         struct vnode *tdvp = ap->a_tdvp;
     722           0 :         struct vnode *fvp = ap->a_fvp;
     723           0 :         struct vnode *fdvp = ap->a_fdvp;
     724           0 :         struct componentname *tcnp = ap->a_tcnp;
     725           0 :         struct componentname *fcnp = ap->a_fcnp;
     726             :         struct inode *ip, *xp, *dp;
     727           0 :         struct direct newdir;
     728             :         int doingdirectory = 0, oldparent = 0, newparent = 0;
     729             :         int error = 0;
     730             : 
     731             : #ifdef DIAGNOSTIC
     732           0 :         if ((tcnp->cn_flags & HASBUF) == 0 ||
     733           0 :             (fcnp->cn_flags & HASBUF) == 0)
     734           0 :                 panic("ufs_rename: no name");
     735             : #endif
     736             :         /*
     737             :          * Check for cross-device rename.
     738             :          */
     739           0 :         if ((fvp->v_mount != tdvp->v_mount) ||
     740           0 :             (tvp && (fvp->v_mount != tvp->v_mount))) {
     741           0 :                 error = EXDEV;
     742             : abortit:
     743           0 :                 VOP_ABORTOP(tdvp, tcnp);
     744           0 :                 if (tdvp == tvp)
     745           0 :                         vrele(tdvp);
     746             :                 else
     747           0 :                         vput(tdvp);
     748           0 :                 if (tvp)
     749           0 :                         vput(tvp);
     750           0 :                 VOP_ABORTOP(fdvp, fcnp);
     751           0 :                 vrele(fdvp);
     752           0 :                 vrele(fvp);
     753           0 :                 return (error);
     754             :         }
     755             : 
     756           0 :         if (tvp && ((DIP(VTOI(tvp), flags) & (IMMUTABLE | APPEND)) ||
     757           0 :             (DIP(VTOI(tdvp), flags) & APPEND))) {
     758             :                 error = EPERM;
     759           0 :                 goto abortit;
     760             :         }
     761             : 
     762             :         /*
     763             :          * Check if just deleting a link name or if we've lost a race.
     764             :          * If another process completes the same rename after we've looked
     765             :          * up the source and have blocked looking up the target, then the
     766             :          * source and target inodes may be identical now although the
     767             :          * names were never linked.
     768             :          */
     769           0 :         if (fvp == tvp) {
     770           0 :                 if (fvp->v_type == VDIR) {
     771             :                         /*
     772             :                          * Linked directories are impossible, so we must
     773             :                          * have lost the race.  Pretend that the rename
     774             :                          * completed before the lookup.
     775             :                          */
     776             :                         error = ENOENT;
     777           0 :                         goto abortit;
     778             :                 }
     779             : 
     780             :                 /* Release destination completely. */
     781           0 :                 VOP_ABORTOP(tdvp, tcnp);
     782           0 :                 vput(tdvp);
     783           0 :                 vput(tvp);
     784             : 
     785             :                 /*
     786             :                  * Delete source.  There is another race now that everything
     787             :                  * is unlocked, but this doesn't cause any new complications.
     788             :                  * relookup() may find a file that is unrelated to the
     789             :                  * original one, or it may fail.  Too bad.
     790             :                  */
     791           0 :                 vrele(fvp);
     792           0 :                 fcnp->cn_flags &= ~MODMASK;
     793           0 :                 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
     794           0 :                 if ((fcnp->cn_flags & SAVESTART) == 0)
     795           0 :                         panic("ufs_rename: lost from startdir");
     796           0 :                 fcnp->cn_nameiop = DELETE;
     797           0 :                 if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0)
     798           0 :                         return (error);         /* relookup did vrele() */
     799           0 :                 vrele(fdvp);
     800           0 :                 return (VOP_REMOVE(fdvp, fvp, fcnp));
     801             :         }
     802             : 
     803           0 :         if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
     804             :                 goto abortit;
     805             : 
     806             :         /* fvp, tdvp, tvp now locked */
     807           0 :         dp = VTOI(fdvp);
     808           0 :         ip = VTOI(fvp);
     809           0 :         if ((nlink_t) DIP(ip, nlink) >= LINK_MAX) {
     810           0 :                 VOP_UNLOCK(fvp);
     811             :                 error = EMLINK;
     812           0 :                 goto abortit;
     813             :         }
     814           0 :         if ((DIP(ip, flags) & (IMMUTABLE | APPEND)) ||
     815           0 :             (DIP(dp, flags) & APPEND)) {
     816           0 :                 VOP_UNLOCK(fvp);
     817             :                 error = EPERM;
     818           0 :                 goto abortit;
     819             :         }
     820           0 :         if ((DIP(ip, mode) & IFMT) == IFDIR) {
     821           0 :                 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
     822           0 :                 if (!error && tvp)
     823           0 :                         error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
     824           0 :                 if (error) {
     825           0 :                         VOP_UNLOCK(fvp);
     826             :                         error = EACCES;
     827           0 :                         goto abortit;
     828             :                 }
     829             :                 /*
     830             :                  * Avoid ".", "..", and aliases of "." for obvious reasons.
     831             :                  */
     832           0 :                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
     833           0 :                     dp == ip ||
     834           0 :                     (fcnp->cn_flags & ISDOTDOT) ||
     835           0 :                     (tcnp->cn_flags & ISDOTDOT) ||
     836           0 :                     (ip->i_flag & IN_RENAME)) {
     837           0 :                         VOP_UNLOCK(fvp);
     838             :                         error = EINVAL;
     839           0 :                         goto abortit;
     840             :                 }
     841           0 :                 ip->i_flag |= IN_RENAME;
     842           0 :                 oldparent = dp->i_number;
     843             :                 doingdirectory = 1;
     844           0 :         }
     845           0 :         VN_KNOTE(fdvp, NOTE_WRITE);             /* XXX right place? */
     846             : 
     847             :         /*
     848             :          * When the target exists, both the directory
     849             :          * and target vnodes are returned locked.
     850             :          */
     851           0 :         dp = VTOI(tdvp);
     852             :         xp = NULL;
     853           0 :         if (tvp)
     854           0 :                 xp = VTOI(tvp);
     855             : 
     856             :         /*
     857             :          * 1) Bump link count while we're moving stuff
     858             :          *    around.  If we crash somewhere before
     859             :          *    completing our work, the link count
     860             :          *    may be wrong, but correctable.
     861             :          */
     862           0 :         ip->i_effnlink++;
     863           0 :         DIP_ADD(ip, nlink, 1);
     864           0 :         ip->i_flag |= IN_CHANGE;
     865           0 :         if (DOINGSOFTDEP(fvp))
     866           0 :                 softdep_change_linkcnt(ip, 0);
     867           0 :         if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(fvp))) != 0) {
     868           0 :                 VOP_UNLOCK(fvp);
     869           0 :                 goto bad;
     870             :         }
     871             : 
     872             :         /*
     873             :          * If ".." must be changed (ie the directory gets a new
     874             :          * parent) then the source directory must not be in the
     875             :          * directory hierarchy above the target, as this would
     876             :          * orphan everything below the source directory. Also
     877             :          * the user must have write permission in the source so
     878             :          * as to be able to change "..". We must repeat the call 
     879             :          * to namei, as the parent directory is unlocked by the
     880             :          * call to checkpath().
     881             :          */
     882           0 :         error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
     883           0 :         VOP_UNLOCK(fvp);
     884             : 
     885             :         /* tdvp and tvp locked */
     886           0 :         if (oldparent != dp->i_number)
     887           0 :                 newparent = dp->i_number;
     888           0 :         if (doingdirectory && newparent) {
     889           0 :                 if (error)      /* write access check above */
     890             :                         goto bad;
     891           0 :                 if (xp != NULL)
     892           0 :                         vput(tvp);
     893             :                 /*
     894             :                  * Compensate for the reference ufs_checkpath() loses.
     895             :                  */
     896           0 :                 vref(tdvp);
     897             :                 /* Only tdvp is locked */
     898           0 :                 if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0) {
     899           0 :                         vrele(tdvp);
     900           0 :                         goto out;
     901             :                 }
     902           0 :                 if ((tcnp->cn_flags & SAVESTART) == 0)
     903           0 :                         panic("ufs_rename: lost to startdir");
     904           0 :                 if ((error = vfs_relookup(tdvp, &tvp, tcnp)) != 0)
     905             :                         goto out;
     906           0 :                 vrele(tdvp); /* relookup() acquired a reference */
     907           0 :                 dp = VTOI(tdvp);
     908             :                 xp = NULL;
     909           0 :                 if (tvp)
     910           0 :                         xp = VTOI(tvp);
     911             :         }
     912             :         /*
     913             :          * 2) If target doesn't exist, link the target
     914             :          *    to the source and unlink the source. 
     915             :          *    Otherwise, rewrite the target directory
     916             :          *    entry to reference the source inode and
     917             :          *    expunge the original entry's existence.
     918             :          */
     919           0 :         if (xp == NULL) {
     920           0 :                 if (dp->i_dev != ip->i_dev)
     921           0 :                         panic("rename: EXDEV");
     922             :                 /*
     923             :                  * Account for ".." in new directory.
     924             :                  * When source and destination have the same
     925             :                  * parent we don't fool with the link count.
     926             :                  */
     927           0 :                 if (doingdirectory && newparent) {
     928           0 :                         if ((nlink_t) DIP(dp, nlink) >= LINK_MAX) {
     929             :                                 error = EMLINK;
     930           0 :                                 goto bad;
     931             :                         }
     932           0 :                         dp->i_effnlink++;
     933           0 :                         DIP_ADD(dp, nlink, 1);
     934           0 :                         dp->i_flag |= IN_CHANGE;
     935           0 :                         if (DOINGSOFTDEP(tdvp))
     936           0 :                                 softdep_change_linkcnt(dp, 0);
     937           0 :                         if ((error = UFS_UPDATE(dp, !DOINGSOFTDEP(tdvp))) 
     938           0 :                             != 0) {
     939           0 :                                 dp->i_effnlink--;
     940           0 :                                 DIP_ADD(dp, nlink, -1);
     941           0 :                                 dp->i_flag |= IN_CHANGE;
     942           0 :                                 if (DOINGSOFTDEP(tdvp))
     943           0 :                                         softdep_change_linkcnt(dp, 0);
     944             :                                 goto bad;
     945             :                         }
     946             :                 }
     947           0 :                 ufs_makedirentry(ip, tcnp, &newdir);
     948           0 :                 if ((error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL)) != 0) {
     949           0 :                         if (doingdirectory && newparent) {
     950           0 :                                 dp->i_effnlink--;
     951           0 :                                 DIP_ADD(dp, nlink, -1);
     952           0 :                                 dp->i_flag |= IN_CHANGE;
     953           0 :                                 if (DOINGSOFTDEP(tdvp))
     954           0 :                                         softdep_change_linkcnt(dp, 0);
     955           0 :                                 (void)UFS_UPDATE(dp, 1);
     956           0 :                         }
     957             :                         goto bad;
     958             :                 }
     959           0 :                 VN_KNOTE(tdvp, NOTE_WRITE);
     960           0 :                 vput(tdvp);
     961           0 :         } else {
     962           0 :                 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
     963           0 :                         panic("rename: EXDEV");
     964             :                 /*
     965             :                  * Short circuit rename(foo, foo).
     966             :                  */
     967           0 :                 if (xp->i_number == ip->i_number)
     968           0 :                         panic("ufs_rename: same file");
     969             :                 /*
     970             :                  * If the parent directory is "sticky", then the user must
     971             :                  * own the parent directory, or the destination of the rename,
     972             :                  * otherwise the destination may not be changed (except by
     973             :                  * root). This implements append-only directories.
     974             :                  */
     975           0 :                 if ((DIP(dp, mode) & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
     976           0 :                     tcnp->cn_cred->cr_uid != DIP(dp, uid) &&
     977           0 :                     DIP(xp, uid )!= tcnp->cn_cred->cr_uid &&
     978           0 :                     (tdvp->v_mount->mnt_flag & MNT_NOPERM) == 0) {
     979             :                         error = EPERM;
     980           0 :                         goto bad;
     981             :                 }
     982             :                 /*
     983             :                  * Target must be empty if a directory and have no links
     984             :                  * to it. Also, ensure source and target are compatible
     985             :                  * (both directories, or both not directories).
     986             :                  */
     987           0 :                 if ((DIP(xp, mode) & IFMT) == IFDIR) {
     988           0 :                         if (xp->i_effnlink > 2 ||
     989           0 :                             !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
     990             :                                 error = ENOTEMPTY;
     991           0 :                                 goto bad;
     992             :                         }
     993           0 :                         if (!doingdirectory) {
     994             :                                 error = ENOTDIR;
     995           0 :                                 goto bad;
     996             :                         }
     997           0 :                         cache_purge(tdvp);
     998           0 :                 } else if (doingdirectory) {
     999             :                         error = EISDIR;
    1000           0 :                         goto bad;
    1001             :                 }
    1002             :                 
    1003           0 :                 if ((error = ufs_dirrewrite(dp, xp, ip->i_number,
    1004           0 :                     IFTODT(DIP(ip, mode)), (doingdirectory && newparent) ?
    1005           0 :                     newparent : doingdirectory)) != 0)
    1006             :                         goto bad;
    1007           0 :                 if (doingdirectory) {
    1008           0 :                         if (!newparent) {
    1009           0 :                                 dp->i_effnlink--;
    1010           0 :                                 if (DOINGSOFTDEP(tdvp))
    1011           0 :                                         softdep_change_linkcnt(dp, 0);
    1012             :                         }
    1013           0 :                         xp->i_effnlink--;
    1014           0 :                         if (DOINGSOFTDEP(tvp))
    1015           0 :                                 softdep_change_linkcnt(xp, 0);
    1016             :                 }
    1017           0 :                 if (doingdirectory && !DOINGSOFTDEP(tvp)) {
    1018             :                         /*
    1019             :                         * Truncate inode. The only stuff left in the directory
    1020             :                         * is "." and "..". The "." reference is inconsequential
    1021             :                         * since we are quashing it. We have removed the "."
    1022             :                         * reference and the reference in the parent directory,
    1023             :                         * but there may be other hard links. The soft
    1024             :                         * dependency code will arrange to do these operations
    1025             :                         * after the parent directory entry has been deleted on
    1026             :                         * disk, so when running with that code we avoid doing
    1027             :                         * them now.
    1028             :                         */
    1029           0 :                         if (!newparent) {
    1030           0 :                                 DIP_ADD(dp, nlink, -1);
    1031           0 :                                 dp->i_flag |= IN_CHANGE;
    1032           0 :                         }
    1033             : 
    1034           0 :                         DIP_ADD(xp, nlink, -1);
    1035           0 :                         xp->i_flag |= IN_CHANGE;
    1036           0 :                         if ((error = UFS_TRUNCATE(VTOI(tvp), (off_t)0, IO_SYNC,
    1037           0 :                             tcnp->cn_cred)) != 0)
    1038             :                                 goto bad;
    1039             :                 }
    1040           0 :                 VN_KNOTE(tdvp, NOTE_WRITE);
    1041           0 :                 vput(tdvp);
    1042           0 :                 VN_KNOTE(tvp, NOTE_DELETE);
    1043           0 :                 vput(tvp);
    1044             :                 xp = NULL;
    1045             :         }
    1046             : 
    1047             :         /*
    1048             :          * 3) Unlink the source.
    1049             :          */
    1050           0 :         fcnp->cn_flags &= ~MODMASK;
    1051           0 :         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
    1052           0 :         if ((fcnp->cn_flags & SAVESTART) == 0)
    1053           0 :                 panic("ufs_rename: lost from startdir");
    1054           0 :         if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0) {
    1055           0 :                 vrele(ap->a_fvp);
    1056           0 :                 return (error);
    1057             :         }
    1058           0 :         vrele(fdvp);
    1059           0 :         if (fvp == NULL) {
    1060             :                 /*
    1061             :                  * From name has disappeared.
    1062             :                  */
    1063           0 :                 if (doingdirectory)
    1064           0 :                         panic("ufs_rename: lost dir entry");
    1065           0 :                 vrele(ap->a_fvp);
    1066           0 :                 return (0);
    1067             :         }
    1068             : 
    1069           0 :         xp = VTOI(fvp);
    1070           0 :         dp = VTOI(fdvp);
    1071             : 
    1072             :         /*
    1073             :          * Ensure that the directory entry still exists and has not
    1074             :          * changed while the new name has been entered. If the source is
    1075             :          * a file then the entry may have been unlinked or renamed. In
    1076             :          * either case there is no further work to be done. If the source
    1077             :          * is a directory then it cannot have been rmdir'ed; the IN_RENAME 
    1078             :          * flag ensures that it cannot be moved by another rename or removed
    1079             :          * by a rmdir.
    1080             :          */
    1081           0 :         if (xp != ip) {
    1082           0 :                 if (doingdirectory)
    1083           0 :                         panic("ufs_rename: lost dir entry");
    1084             :         } else {
    1085             :                 /*
    1086             :                  * If the source is a directory with a
    1087             :                  * new parent, the link count of the old
    1088             :                  * parent directory must be decremented
    1089             :                  * and ".." set to point to the new parent.
    1090             :                  */
    1091           0 :                 if (doingdirectory && newparent) {
    1092           0 :                         xp->i_offset = mastertemplate.dot_reclen;
    1093           0 :                         ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0);
    1094           0 :                         cache_purge(fdvp);
    1095           0 :                 }
    1096           0 :                 error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
    1097           0 :                 xp->i_flag &= ~IN_RENAME;
    1098             :         }
    1099           0 :         VN_KNOTE(fvp, NOTE_RENAME);
    1100           0 :         if (dp)
    1101           0 :                 vput(fdvp);
    1102           0 :         if (xp)
    1103           0 :                 vput(fvp);
    1104           0 :         vrele(ap->a_fvp);
    1105           0 :         return (error);
    1106             : 
    1107             : bad:
    1108           0 :         if (xp)
    1109           0 :                 vput(ITOV(xp));
    1110           0 :         vput(ITOV(dp));
    1111             : out:
    1112           0 :         vrele(fdvp);
    1113           0 :         if (doingdirectory)
    1114           0 :                 ip->i_flag &= ~IN_RENAME;
    1115           0 :         if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
    1116           0 :                 ip->i_effnlink--;
    1117           0 :                 DIP_ADD(ip, nlink, -1);
    1118           0 :                 ip->i_flag |= IN_CHANGE;
    1119           0 :                 ip->i_flag &= ~IN_RENAME;
    1120           0 :                 if (DOINGSOFTDEP(fvp))
    1121           0 :                         softdep_change_linkcnt(ip, 0);
    1122           0 :                 vput(fvp);
    1123           0 :         } else
    1124           0 :                 vrele(fvp);
    1125           0 :         return (error);
    1126           0 : }
    1127             : 
    1128             : /*
    1129             :  * Mkdir system call
    1130             :  */
    1131             : int
    1132           0 : ufs_mkdir(void *v)
    1133             : {
    1134           0 :         struct vop_mkdir_args *ap = v;
    1135           0 :         struct vnode *dvp = ap->a_dvp;
    1136           0 :         struct vattr *vap = ap->a_vap;
    1137           0 :         struct componentname *cnp = ap->a_cnp;
    1138             :         struct inode *ip, *dp;
    1139           0 :         struct vnode *tvp;
    1140           0 :         struct buf *bp;
    1141           0 :         struct direct newdir;
    1142           0 :         struct dirtemplate dirtemplate, *dtp;
    1143             :         int error, dmode, blkoff;
    1144             : 
    1145             : #ifdef DIAGNOSTIC
    1146           0 :         if ((cnp->cn_flags & HASBUF) == 0)
    1147           0 :                 panic("ufs_mkdir: no name");
    1148             : #endif
    1149           0 :         dp = VTOI(dvp);
    1150           0 :         if ((nlink_t) DIP(dp, nlink) >= LINK_MAX) {
    1151             :                 error = EMLINK;
    1152           0 :                 goto out;
    1153             :         }
    1154           0 :         dmode = vap->va_mode & 0777;
    1155           0 :         dmode |= IFDIR;
    1156             :         /*
    1157             :          * Must simulate part of ufs_makeinode here to acquire the inode,
    1158             :          * but not have it entered in the parent directory. The entry is
    1159             :          * made later after writing "." and ".." entries.
    1160             :          */
    1161           0 :         if ((error = UFS_INODE_ALLOC(dp, dmode, cnp->cn_cred, &tvp)) != 0)
    1162             :                 goto out;
    1163             : 
    1164           0 :         ip = VTOI(tvp);
    1165             : 
    1166           0 :         DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);
    1167           0 :         DIP_ASSIGN(ip, gid, DIP(dp, gid));
    1168             : 
    1169           0 :         if ((error = getinoquota(ip)) ||
    1170           0 :             (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
    1171           0 :                 pool_put(&namei_pool, cnp->cn_pnbuf);
    1172           0 :                 UFS_INODE_FREE(ip, ip->i_number, dmode);
    1173           0 :                 vput(tvp);
    1174           0 :                 vput(dvp);
    1175           0 :                 return (error);
    1176             :         }
    1177             : 
    1178           0 :         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
    1179           0 :         DIP_ASSIGN(ip, mode, dmode);
    1180           0 :         tvp->v_type = VDIR;  /* Rest init'd in getnewvnode(). */
    1181           0 :         ip->i_effnlink = 2;
    1182           0 :         DIP_ASSIGN(ip, nlink, 2);
    1183           0 :         if (DOINGSOFTDEP(tvp))
    1184           0 :                 softdep_change_linkcnt(ip, 0);
    1185             : 
    1186             :         /*
    1187             :          * Bump link count in parent directory to reflect work done below.
    1188             :          * Should be done before reference is create so cleanup is 
    1189             :          * possible if we crash.
    1190             :          */
    1191           0 :         dp->i_effnlink++;
    1192           0 :         DIP_ADD(dp, nlink, 1);
    1193           0 :         dp->i_flag |= IN_CHANGE;
    1194           0 :         if (DOINGSOFTDEP(dvp))
    1195           0 :                 softdep_change_linkcnt(dp, 0);
    1196           0 :         if ((error = UFS_UPDATE(dp, !DOINGSOFTDEP(dvp))) != 0)
    1197             :                 goto bad;
    1198             : 
    1199             :         /* 
    1200             :          * Initialize directory with "." and ".." from static template.
    1201             :          */
    1202           0 :         if (dp->i_ump->um_maxsymlinklen > 0)
    1203           0 :                 dtp = &mastertemplate;
    1204             :         else
    1205             :                 dtp = (struct dirtemplate *)&omastertemplate;
    1206           0 :         dirtemplate = *dtp;
    1207           0 :         dirtemplate.dot_ino = ip->i_number;
    1208           0 :         dirtemplate.dotdot_ino = dp->i_number;
    1209             : 
    1210           0 :         if ((error = UFS_BUF_ALLOC(ip, (off_t)0, DIRBLKSIZ, cnp->cn_cred,
    1211           0 :             B_CLRBUF, &bp)) != 0)
    1212             :                 goto bad;
    1213           0 :         DIP_ASSIGN(ip, size, DIRBLKSIZ);
    1214           0 :         ip->i_flag |= IN_CHANGE | IN_UPDATE;
    1215           0 :         uvm_vnp_setsize(tvp, DIP(ip, size));
    1216           0 :         memcpy(bp->b_data, &dirtemplate, sizeof(dirtemplate));
    1217           0 :         if (DOINGSOFTDEP(tvp)) {
    1218             :                 /*
    1219             :                  * Ensure that the entire newly allocated block is a
    1220             :                  * valid directory so that future growth within the
    1221             :                  * block does not have to ensure that the block is
    1222             :                  * written before the inode
    1223             :                  */
    1224             :                 blkoff = DIRBLKSIZ;
    1225           0 :                 while (blkoff < bp->b_bcount) {
    1226             :                         ((struct direct *)
    1227           0 :                          (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
    1228           0 :                         blkoff += DIRBLKSIZ;
    1229             :                 }
    1230             :         }
    1231           0 :         if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))) != 0) {
    1232           0 :                 (void)VOP_BWRITE(bp);
    1233           0 :                 goto bad;
    1234             :         }
    1235             : 
    1236             :         /*
    1237             :          * Directory set up, now install its entry in the parent directory.
    1238             :          *
    1239             :          * If we are not doing soft dependencies, then we must write out the
    1240             :          * buffer containing the new directory body before entering the new
    1241             :          * name in the parent. If we are doing soft dependencies, then the
    1242             :          * buffer containing the new directory body will be passed to and
    1243             :          * released in the soft dependency code after the code has attached
    1244             :          * an appropriate ordering dependency to the buffer which ensures that
    1245             :          * the buffer is written before the new name is written in the parent.
    1246             :          */
    1247           0 :         if (!DOINGSOFTDEP(dvp) && ((error = VOP_BWRITE(bp)) != 0))
    1248             :                 goto bad;
    1249           0 :         ufs_makedirentry(ip, cnp, &newdir);
    1250           0 :         error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
    1251             :   
    1252             : bad:
    1253           0 :         if (error == 0) {
    1254           0 :                 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
    1255           0 :                 *ap->a_vpp = tvp;
    1256           0 :         } else {
    1257           0 :                 dp->i_effnlink--;
    1258           0 :                 DIP_ADD(dp, nlink, -1);
    1259           0 :                 dp->i_flag |= IN_CHANGE;
    1260           0 :                 if (DOINGSOFTDEP(dvp))
    1261           0 :                         softdep_change_linkcnt(dp, 0);
    1262             :                 /*
    1263             :                  * No need to do an explicit VOP_TRUNCATE here, vrele will
    1264             :                  * do this for us because we set the link count to 0.
    1265             :                  */
    1266           0 :                 ip->i_effnlink = 0;
    1267           0 :                 DIP_ASSIGN(ip, nlink, 0);
    1268           0 :                 ip->i_flag |= IN_CHANGE;
    1269           0 :                 if (DOINGSOFTDEP(tvp))
    1270           0 :                         softdep_change_linkcnt(ip, 0);
    1271           0 :                 vput(tvp);
    1272             :         }
    1273             : out:
    1274           0 :         pool_put(&namei_pool, cnp->cn_pnbuf);
    1275           0 :         vput(dvp);
    1276             : 
    1277           0 :         return (error);
    1278           0 : }
    1279             : 
    1280             : /*
    1281             :  * Rmdir system call.
    1282             :  */
    1283             : int
    1284           0 : ufs_rmdir(void *v)
    1285             : {
    1286           0 :         struct vop_rmdir_args *ap = v;
    1287           0 :         struct vnode *vp = ap->a_vp;
    1288           0 :         struct vnode *dvp = ap->a_dvp;
    1289           0 :         struct componentname *cnp = ap->a_cnp;
    1290             :         struct inode *ip, *dp;
    1291             :         int error;
    1292             : 
    1293           0 :         ip = VTOI(vp);
    1294           0 :         dp = VTOI(dvp);
    1295             :         /*
    1296             :          * Do not remove a directory that is in the process of being renamed.
    1297             :          * Verify the directory is empty (and valid). Rmdir ".." will not be
    1298             :          * valid since ".." will contain a reference to the current directory
    1299             :          * and thus be non-empty.
    1300             :          */
    1301             :         error = 0;
    1302           0 :         if (ip->i_flag & IN_RENAME) {
    1303             :                 error = EINVAL;
    1304           0 :                 goto out;
    1305             :         }
    1306           0 :         if (ip->i_effnlink != 2 ||
    1307           0 :             !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
    1308             :                 error = ENOTEMPTY;
    1309           0 :                 goto out;
    1310             :         }
    1311           0 :         if ((DIP(dp, flags) & APPEND) ||
    1312           0 :                 (DIP(ip, flags) & (IMMUTABLE | APPEND))) {
    1313             :                 error = EPERM;
    1314           0 :                 goto out;
    1315             :         }
    1316             :         /*
    1317             :          * Delete reference to directory before purging
    1318             :          * inode.  If we crash in between, the directory
    1319             :          * will be reattached to lost+found,
    1320             :          */
    1321           0 :         dp->i_effnlink--;
    1322           0 :         ip->i_effnlink--;
    1323           0 :         if (DOINGSOFTDEP(vp)) {
    1324           0 :                 softdep_change_linkcnt(dp, 0);
    1325           0 :                 softdep_change_linkcnt(ip, 0);
    1326           0 :         }
    1327           0 :         if ((error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1)) != 0) {
    1328           0 :                 dp->i_effnlink++;
    1329           0 :                 ip->i_effnlink++;
    1330           0 :                 if (DOINGSOFTDEP(vp)) {
    1331           0 :                         softdep_change_linkcnt(dp, 0);
    1332           0 :                         softdep_change_linkcnt(ip, 0);
    1333           0 :                 }
    1334             :                 goto out;
    1335             :         }
    1336             : 
    1337           0 :         VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
    1338           0 :         cache_purge(dvp);
    1339             :         /*
    1340             :          * Truncate inode. The only stuff left in the directory is "." and
    1341             :          * "..". The "." reference is inconsequential since we are quashing
    1342             :          * it. The soft dependency code will arrange to do these operations
    1343             :          * after the parent directory entry has been deleted on disk, so
    1344             :          * when running with that code we avoid doing them now.
    1345             :          */
    1346           0 :         if (!DOINGSOFTDEP(vp)) {
    1347             :                 int ioflag;
    1348             : 
    1349           0 :                 DIP_ADD(dp, nlink, -1);
    1350           0 :                 dp->i_flag |= IN_CHANGE;
    1351           0 :                 DIP_ADD(ip, nlink, -1);
    1352           0 :                 ip->i_flag |= IN_CHANGE;
    1353           0 :                 ioflag = DOINGASYNC(vp) ? 0 : IO_SYNC;
    1354           0 :                 error = UFS_TRUNCATE(ip, (off_t)0, ioflag, cnp->cn_cred);
    1355           0 :         }
    1356           0 :         cache_purge(vp);
    1357             : #ifdef UFS_DIRHASH
    1358             :         /* Kill any active hash; i_effnlink == 0, so it will not come back. */
    1359           0 :         if (ip->i_dirhash != NULL)
    1360           0 :                 ufsdirhash_free(ip);
    1361             : #endif
    1362             : 
    1363             : out:
    1364           0 :         VN_KNOTE(vp, NOTE_DELETE);
    1365           0 :         vput(dvp);
    1366           0 :         vput(vp);
    1367           0 :         return (error);
    1368             : }
    1369             : 
    1370             : /*
    1371             :  * symlink -- make a symbolic link
    1372             :  */
    1373             : int
    1374           0 : ufs_symlink(void *v)
    1375             : {
    1376           0 :         struct vop_symlink_args *ap = v;
    1377           0 :         struct vnode *vp, **vpp = ap->a_vpp;
    1378             :         struct inode *ip;
    1379             :         int len, error;
    1380             : 
    1381           0 :         error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
    1382           0 :             vpp, ap->a_cnp);
    1383           0 :         if (error) {
    1384           0 :                 vput(ap->a_dvp);
    1385           0 :                 return (error);
    1386             :         }
    1387           0 :         VN_KNOTE(ap->a_dvp, NOTE_WRITE);
    1388           0 :         vput(ap->a_dvp);
    1389           0 :         vp = *vpp;
    1390           0 :         ip = VTOI(vp);
    1391           0 :         len = strlen(ap->a_target);
    1392           0 :         if (len < ip->i_ump->um_maxsymlinklen) {
    1393           0 :                 memcpy(SHORTLINK(ip), ap->a_target, len);
    1394           0 :                 DIP_ASSIGN(ip, size, len);
    1395           0 :                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
    1396           0 :         } else
    1397           0 :                 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
    1398           0 :                     UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
    1399           0 :                     curproc);
    1400           0 :         vput(vp);
    1401           0 :         return (error);
    1402           0 : }
    1403             : 
    1404             : /*
    1405             :  * Vnode op for reading directories.
    1406             :  * 
    1407             :  * This routine converts the on-disk struct direct entries to the
    1408             :  * struct dirent entries expected by userland and the rest of the kernel.
    1409             :  */
    1410             : int
    1411           0 : ufs_readdir(void *v)
    1412             : {
    1413           0 :         struct vop_readdir_args *ap = v;
    1414           0 :         struct uio auio, *uio = ap->a_uio;
    1415           0 :         struct iovec aiov;
    1416           0 :         union {
    1417             :                 struct  dirent dn;
    1418             :                 char __pad[roundup(sizeof(struct dirent), 8)];
    1419             :         } u;
    1420           0 :         off_t off = uio->uio_offset;
    1421             :         struct direct *dp;
    1422             :         char *edp;
    1423             :         caddr_t diskbuf;
    1424             :         size_t count, entries;
    1425             :         int bufsize, readcnt, error;
    1426             : #if (BYTE_ORDER == LITTLE_ENDIAN)
    1427           0 :         int ofmt = VTOI(ap->a_vp)->i_ump->um_maxsymlinklen == 0;
    1428             : #endif
    1429             : 
    1430           0 :         if (uio->uio_rw != UIO_READ)
    1431           0 :                 return (EINVAL);
    1432             : 
    1433           0 :         count = uio->uio_resid;
    1434           0 :         entries = (uio->uio_offset + count) & (DIRBLKSIZ - 1);
    1435             : 
    1436             :         /* Make sure we don't return partial entries. */
    1437           0 :         if (count <= entries)
    1438           0 :                 return (EINVAL);
    1439             : 
    1440             :         /*
    1441             :          * Convert and copy back the on-disk struct direct format to
    1442             :          * the user-space struct dirent format, one entry at a time
    1443             :          */
    1444             : 
    1445             :         /* read from disk, stopping on a block boundary, max 64kB */
    1446           0 :         readcnt = min(count, 64*1024) - entries;
    1447             : 
    1448           0 :         auio = *uio;
    1449           0 :         auio.uio_iov = &aiov;
    1450           0 :         auio.uio_iovcnt = 1;
    1451           0 :         auio.uio_resid = readcnt;
    1452           0 :         auio.uio_segflg = UIO_SYSSPACE;
    1453           0 :         aiov.iov_len = readcnt;
    1454             :         bufsize = readcnt;
    1455           0 :         diskbuf = malloc(bufsize, M_TEMP, M_WAITOK);
    1456           0 :         aiov.iov_base = diskbuf;
    1457           0 :         error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
    1458           0 :         readcnt -= auio.uio_resid;
    1459           0 :         dp = (struct direct *)diskbuf;
    1460           0 :         edp = &diskbuf[readcnt];
    1461             : 
    1462           0 :         memset(&u, 0, sizeof(u));
    1463             : 
    1464             :         /*
    1465             :          * While
    1466             :          *  - we haven't failed to VOP_READ or uiomove()
    1467             :          *  - there's space in the read buf for the head of an entry
    1468             :          *  - that entry has a valid d_reclen, and
    1469             :          *  - there's space for the *entire* entry
    1470             :          * then we're good to process this one.
    1471             :          */
    1472           0 :         while (error == 0 &&
    1473           0 :             (char *)dp + offsetof(struct direct, d_name) < edp &&
    1474           0 :             dp->d_reclen > offsetof(struct direct, d_name) &&
    1475           0 :             (char *)dp + dp->d_reclen <= edp) {
    1476           0 :                 u.dn.d_reclen = roundup(dp->d_namlen+1 +
    1477             :                     offsetof(struct dirent, d_name), 8);
    1478           0 :                 if (u.dn.d_reclen > uio->uio_resid)
    1479             :                         break;
    1480           0 :                 off += dp->d_reclen;
    1481           0 :                 u.dn.d_off = off;
    1482           0 :                 u.dn.d_fileno = dp->d_ino;
    1483             : #if (BYTE_ORDER == LITTLE_ENDIAN)
    1484           0 :                 if (ofmt) {
    1485           0 :                         u.dn.d_type = dp->d_namlen;
    1486           0 :                         u.dn.d_namlen = dp->d_type;
    1487           0 :                 } else
    1488             : #endif
    1489             :                 {
    1490           0 :                         u.dn.d_type = dp->d_type;
    1491           0 :                         u.dn.d_namlen = dp->d_namlen;
    1492             :                 }
    1493           0 :                 memcpy(u.dn.d_name, dp->d_name, u.dn.d_namlen);
    1494           0 :                 memset(u.dn.d_name + u.dn.d_namlen, 0, u.dn.d_reclen
    1495             :                     - u.dn.d_namlen - offsetof(struct dirent, d_name));
    1496             : 
    1497           0 :                 error = uiomove(&u.dn, u.dn.d_reclen, uio);
    1498           0 :                 dp = (struct direct *)((char *)dp + dp->d_reclen);
    1499             :         }
    1500             : 
    1501             :         /*
    1502             :          * If there was room for an entry in what we read but its
    1503             :          * d_reclen is bogus, fail
    1504             :          */
    1505           0 :         if ((char *)dp + offsetof(struct direct, d_name) < edp &&
    1506           0 :             dp->d_reclen <= offsetof(struct direct, d_name))
    1507           0 :                 error = EIO;
    1508           0 :         free(diskbuf, M_TEMP, bufsize);
    1509             : 
    1510           0 :         uio->uio_offset = off;
    1511           0 :         *ap->a_eofflag = DIP(VTOI(ap->a_vp), size) <= off;
    1512             : 
    1513           0 :         return (error);
    1514           0 : }
    1515             : 
    1516             : /*
    1517             :  * Return target name of a symbolic link
    1518             :  */
    1519             : int
    1520           0 : ufs_readlink(void *v)
    1521             : {
    1522           0 :         struct vop_readlink_args *ap = v;
    1523           0 :         struct vnode *vp = ap->a_vp;
    1524           0 :         struct inode *ip = VTOI(vp);
    1525             :         u_int64_t isize;
    1526             : 
    1527           0 :         isize = DIP(ip, size);
    1528           0 :         if (isize < ip->i_ump->um_maxsymlinklen ||
    1529           0 :             (ip->i_ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
    1530           0 :                 return (uiomove((char *)SHORTLINK(ip), isize, ap->a_uio));
    1531             :         }
    1532           0 :         return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
    1533           0 : }
    1534             : 
    1535             : /*
    1536             :  * Lock an inode. If its already locked, set the WANT bit and sleep.
    1537             :  */
    1538             : int
    1539           0 : ufs_lock(void *v)
    1540             : {
    1541           0 :         struct vop_lock_args *ap = v;
    1542           0 :         struct vnode *vp = ap->a_vp;
    1543             : 
    1544           0 :         return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS);
    1545             : }
    1546             : 
    1547             : /*
    1548             :  * Unlock an inode.  If WANT bit is on, wakeup.
    1549             :  */
    1550             : int
    1551           0 : ufs_unlock(void *v)
    1552             : {
    1553           0 :         struct vop_unlock_args *ap = v;
    1554           0 :         struct vnode *vp = ap->a_vp;
    1555             : 
    1556           0 :         rrw_exit(&VTOI(vp)->i_lock);
    1557           0 :         return 0;
    1558             : }
    1559             : 
    1560             : /*
    1561             :  * Check for a locked inode.
    1562             :  */
    1563             : int
    1564           0 : ufs_islocked(void *v)
    1565             : {
    1566           0 :         struct vop_islocked_args *ap = v;
    1567             : 
    1568           0 :         return rrw_status(&VTOI(ap->a_vp)->i_lock);
    1569             : }
    1570             : 
    1571             : /*
    1572             :  * Calculate the logical to physical mapping if not done already,
    1573             :  * then call the device strategy routine.
    1574             :  */
    1575             : int
    1576           0 : ufs_strategy(void *v)
    1577             : {
    1578           0 :         struct vop_strategy_args *ap = v;
    1579           0 :         struct buf *bp = ap->a_bp;
    1580           0 :         struct vnode *vp = bp->b_vp;
    1581             :         struct inode *ip;
    1582             :         int error;
    1583             :         int s;
    1584             : 
    1585           0 :         ip = VTOI(vp);
    1586           0 :         if (vp->v_type == VBLK || vp->v_type == VCHR)
    1587           0 :                 panic("ufs_strategy: spec");
    1588           0 :         if (bp->b_blkno == bp->b_lblkno) {
    1589           0 :                 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
    1590             :                                  NULL);
    1591           0 :                 if (error) {
    1592           0 :                         bp->b_error = error;
    1593           0 :                         bp->b_flags |= B_ERROR;
    1594           0 :                         s = splbio();
    1595           0 :                         biodone(bp);
    1596           0 :                         splx(s);
    1597           0 :                         return (error);
    1598             :                 }
    1599           0 :                 if (bp->b_blkno == -1)
    1600           0 :                         clrbuf(bp);
    1601             :         }
    1602           0 :         if (bp->b_blkno == -1) {
    1603           0 :                 s = splbio();
    1604           0 :                 biodone(bp);
    1605           0 :                 splx(s);
    1606           0 :                 return (0);
    1607             :         }
    1608           0 :         vp = ip->i_devvp;
    1609           0 :         bp->b_dev = vp->v_rdev;
    1610           0 :         (vp->v_op->vop_strategy)(ap);
    1611           0 :         return (0);
    1612           0 : }
    1613             : 
    1614             : /*
    1615             :  * Print out the contents of an inode.
    1616             :  */
    1617             : int
    1618           0 : ufs_print(void *v)
    1619             : {
    1620             : #ifdef DIAGNOSTIC
    1621           0 :         struct vop_print_args *ap = v;
    1622             : 
    1623           0 :         struct vnode *vp = ap->a_vp;
    1624           0 :         struct inode *ip = VTOI(vp);
    1625             : 
    1626           0 :         printf("tag VT_UFS, ino %u, on dev %d, %d", ip->i_number,
    1627           0 :                 major(ip->i_dev), minor(ip->i_dev));
    1628           0 :         printf(" flags 0x%x, effnlink %d, nlink %d\n",
    1629           0 :            ip->i_flag, ip->i_effnlink, DIP(ip, nlink));
    1630           0 :         printf("\tmode 0%o, owner %d, group %d, size %lld",
    1631           0 :             DIP(ip, mode), DIP(ip, uid), DIP(ip, gid), DIP(ip, size));
    1632             : 
    1633             : #ifdef FIFO
    1634           0 :         if (vp->v_type == VFIFO)
    1635           0 :                 fifo_printinfo(vp);
    1636             : #endif /* FIFO */
    1637           0 :         printf("\n");
    1638             : 
    1639             : #endif /* DIAGNOSTIC */
    1640             : 
    1641           0 :         return (0);
    1642             : }
    1643             : 
    1644             : /*
    1645             :  * Read wrapper for special devices.
    1646             :  */
    1647             : int
    1648           0 : ufsspec_read(void *v)
    1649             : {
    1650           0 :         struct vop_read_args *ap = v;
    1651             : 
    1652             :         /*
    1653             :          * Set access flag.
    1654             :          */
    1655           0 :         VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
    1656           0 :         return (spec_read(ap));
    1657             : }
    1658             : 
    1659             : /*
    1660             :  * Write wrapper for special devices.
    1661             :  */
    1662             : int
    1663           0 : ufsspec_write(void *v)
    1664             : {
    1665           0 :         struct vop_write_args *ap = v;
    1666             : 
    1667             :         /*
    1668             :          * Set update and change flags.
    1669             :          */
    1670           0 :         VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
    1671           0 :         return (spec_write(ap));
    1672             : }
    1673             : 
    1674             : /*
    1675             :  * Close wrapper for special devices.
    1676             :  *
    1677             :  * Update the times on the inode then do device close.
    1678             :  */
    1679             : int
    1680           0 : ufsspec_close(void *v)
    1681             : {
    1682           0 :         struct vop_close_args *ap = v;
    1683           0 :         struct vnode *vp = ap->a_vp;
    1684             : 
    1685           0 :         if (vp->v_usecount > 1)
    1686           0 :                 ufs_itimes(vp);
    1687           0 :         return (spec_close(ap));
    1688             : }
    1689             : 
    1690             : #ifdef FIFO
    1691             : /*
    1692             :  * Read wrapper for fifo's
    1693             :  */
    1694             : int
    1695           0 : ufsfifo_read(void *v)
    1696             : {
    1697           0 :         struct vop_read_args *ap = v;
    1698             : 
    1699             :         /*
    1700             :          * Set access flag.
    1701             :          */
    1702           0 :         VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
    1703           0 :         return (fifo_read(ap));
    1704             : }
    1705             : 
    1706             : /*
    1707             :  * Write wrapper for fifo's.
    1708             :  */
    1709             : int
    1710           0 : ufsfifo_write(void *v)
    1711             : {
    1712           0 :         struct vop_write_args *ap = v;
    1713             : 
    1714             :         /*
    1715             :          * Set update and change flags.
    1716             :          */
    1717           0 :         VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
    1718           0 :         return (fifo_write(ap));
    1719             : }
    1720             : 
    1721             : /*
    1722             :  * Close wrapper for fifo's.
    1723             :  *
    1724             :  * Update the times on the inode then do device close.
    1725             :  */
    1726             : int
    1727           0 : ufsfifo_close(void *v)
    1728             : {
    1729           0 :         struct vop_close_args *ap = v;
    1730           0 :         struct vnode *vp = ap->a_vp;
    1731             : 
    1732           0 :         if (vp->v_usecount > 1)
    1733           0 :                 ufs_itimes(vp);
    1734           0 :         return (fifo_close(ap));
    1735             : }
    1736             : #endif /* FIFO */
    1737             : 
    1738             : /*
    1739             :  * Return POSIX pathconf information applicable to ufs filesystems.
    1740             :  */
    1741             : int
    1742           0 : ufs_pathconf(void *v)
    1743             : {
    1744           0 :         struct vop_pathconf_args *ap = v;
    1745             :         int error = 0;
    1746             : 
    1747           0 :         switch (ap->a_name) {
    1748             :         case _PC_LINK_MAX:
    1749           0 :                 *ap->a_retval = LINK_MAX;
    1750           0 :                 break;
    1751             :         case _PC_NAME_MAX:
    1752           0 :                 *ap->a_retval = NAME_MAX;
    1753           0 :                 break;
    1754             :         case _PC_CHOWN_RESTRICTED:
    1755           0 :                 *ap->a_retval = 1;
    1756           0 :                 break;
    1757             :         case _PC_NO_TRUNC:
    1758           0 :                 *ap->a_retval = 1;
    1759           0 :                 break;
    1760             :         case _PC_ALLOC_SIZE_MIN:
    1761           0 :                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
    1762           0 :                 break;
    1763             :         case _PC_FILESIZEBITS:
    1764           0 :                 *ap->a_retval = 64;
    1765           0 :                 break;
    1766             :         case _PC_REC_INCR_XFER_SIZE:
    1767           0 :                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
    1768           0 :                 break;
    1769             :         case _PC_REC_MAX_XFER_SIZE:
    1770           0 :                 *ap->a_retval = -1; /* means ``unlimited'' */
    1771           0 :                 break;
    1772             :         case _PC_REC_MIN_XFER_SIZE:
    1773           0 :                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
    1774           0 :                 break;
    1775             :         case _PC_REC_XFER_ALIGN:
    1776           0 :                 *ap->a_retval = PAGE_SIZE;
    1777           0 :                 break;
    1778             :         case _PC_SYMLINK_MAX:
    1779           0 :                 *ap->a_retval = MAXPATHLEN;
    1780           0 :                 break;
    1781             :         case _PC_2_SYMLINKS:
    1782           0 :                 *ap->a_retval = 1;
    1783           0 :                 break;
    1784             :         case _PC_TIMESTAMP_RESOLUTION:
    1785           0 :                 *ap->a_retval = 1;
    1786           0 :                 break;
    1787             :         default:
    1788             :                 error = EINVAL;
    1789           0 :                 break;
    1790             :         }
    1791             : 
    1792           0 :         return (error);
    1793             : }
    1794             : 
    1795             : /*
    1796             :  * Advisory record locking support
    1797             :  */
    1798             : int
    1799           0 : ufs_advlock(void *v)
    1800             : {
    1801           0 :         struct vop_advlock_args *ap = v;
    1802           0 :         struct inode *ip = VTOI(ap->a_vp);
    1803             : 
    1804           0 :         return (lf_advlock(&ip->i_lockf, DIP(ip, size), ap->a_id, ap->a_op,
    1805           0 :             ap->a_fl, ap->a_flags));
    1806             : }
    1807             : 
    1808             : /*
    1809             :  * Allocate a new inode.
    1810             :  */
    1811             : int
    1812           0 : ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
    1813             :     struct componentname *cnp)
    1814             : {
    1815             :         struct inode *ip, *pdir;
    1816           0 :         struct direct newdir;
    1817           0 :         struct vnode *tvp;
    1818             :         int error;
    1819             : 
    1820           0 :         pdir = VTOI(dvp);
    1821             : #ifdef DIAGNOSTIC
    1822           0 :         if ((cnp->cn_flags & HASBUF) == 0)
    1823           0 :                 panic("ufs_makeinode: no name");
    1824             : #endif
    1825           0 :         *vpp = NULL;
    1826           0 :         if ((mode & IFMT) == 0)
    1827           0 :                 mode |= IFREG;
    1828             : 
    1829           0 :         if ((error = UFS_INODE_ALLOC(pdir, mode, cnp->cn_cred, &tvp)) != 0) {
    1830           0 :                 pool_put(&namei_pool, cnp->cn_pnbuf);
    1831           0 :                 return (error);
    1832             :         }
    1833             : 
    1834           0 :         ip = VTOI(tvp);
    1835             : 
    1836           0 :         DIP_ASSIGN(ip, gid, DIP(pdir, gid));
    1837           0 :         DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);
    1838             : 
    1839           0 :         if ((error = getinoquota(ip)) ||
    1840           0 :             (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
    1841           0 :                 pool_put(&namei_pool, cnp->cn_pnbuf);
    1842           0 :                 UFS_INODE_FREE(ip, ip->i_number, mode);
    1843           0 :                 vput(tvp);
    1844           0 :                 return (error);
    1845             :         }
    1846             : 
    1847           0 :         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
    1848           0 :         DIP_ASSIGN(ip, mode, mode);
    1849           0 :         tvp->v_type = IFTOVT(mode);  /* Rest init'd in getnewvnode(). */
    1850           0 :         ip->i_effnlink = 1;
    1851           0 :         DIP_ASSIGN(ip, nlink, 1);
    1852           0 :         if (DOINGSOFTDEP(tvp))
    1853           0 :                 softdep_change_linkcnt(ip, 0);
    1854           0 :         if ((DIP(ip, mode) & ISGID) &&
    1855           0 :                 !groupmember(DIP(ip, gid), cnp->cn_cred) &&
    1856           0 :             (dvp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
    1857           0 :             suser_ucred(cnp->cn_cred))
    1858           0 :                 DIP_AND(ip, mode, ~ISGID);
    1859             : 
    1860             :         /*
    1861             :          * Make sure inode goes to disk before directory entry.
    1862             :          */
    1863           0 :         if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))) != 0)
    1864             :                 goto bad;
    1865             : 
    1866           0 :         ufs_makedirentry(ip, cnp, &newdir);
    1867           0 :         if ((error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL)) != 0)
    1868             :                 goto bad;
    1869             : 
    1870           0 :         if ((cnp->cn_flags & SAVESTART) == 0)
    1871           0 :                 pool_put(&namei_pool, cnp->cn_pnbuf);
    1872           0 :         *vpp = tvp;
    1873           0 :         return (0);
    1874             : 
    1875             : bad:
    1876             :         /*
    1877             :          * Write error occurred trying to update the inode
    1878             :          * or the directory so must deallocate the inode.
    1879             :          */
    1880           0 :         pool_put(&namei_pool, cnp->cn_pnbuf);
    1881           0 :         ip->i_effnlink = 0;
    1882           0 :         DIP_ASSIGN(ip, nlink, 0);
    1883           0 :         ip->i_flag |= IN_CHANGE;
    1884           0 :         if (DOINGSOFTDEP(tvp))
    1885           0 :                 softdep_change_linkcnt(ip, 0);
    1886           0 :         tvp->v_type = VNON;
    1887           0 :         vput(tvp);
    1888             : 
    1889           0 :         return (error);
    1890           0 : }
    1891             : 
    1892             : struct filterops ufsread_filtops = 
    1893             :         { 1, NULL, filt_ufsdetach, filt_ufsread };
    1894             : struct filterops ufswrite_filtops = 
    1895             :         { 1, NULL, filt_ufsdetach, filt_ufswrite };
    1896             : struct filterops ufsvnode_filtops = 
    1897             :         { 1, NULL, filt_ufsdetach, filt_ufsvnode };
    1898             : 
    1899             : int
    1900           0 : ufs_kqfilter(void *v)
    1901             : {
    1902           0 :         struct vop_kqfilter_args *ap = v;
    1903           0 :         struct vnode *vp = ap->a_vp;
    1904           0 :         struct knote *kn = ap->a_kn;
    1905             : 
    1906           0 :         switch (kn->kn_filter) {
    1907             :         case EVFILT_READ:
    1908           0 :                 kn->kn_fop = &ufsread_filtops;
    1909           0 :                 break;
    1910             :         case EVFILT_WRITE:
    1911           0 :                 kn->kn_fop = &ufswrite_filtops;
    1912           0 :                 break;
    1913             :         case EVFILT_VNODE:
    1914           0 :                 kn->kn_fop = &ufsvnode_filtops;
    1915           0 :                 break;
    1916             :         default:
    1917           0 :                 return (EINVAL);
    1918             :         }
    1919             : 
    1920           0 :         kn->kn_hook = (caddr_t)vp;
    1921             : 
    1922           0 :         SLIST_INSERT_HEAD(&vp->v_selectinfo.si_note, kn, kn_selnext);
    1923             : 
    1924           0 :         return (0);
    1925           0 : }
    1926             : 
    1927             : void
    1928           0 : filt_ufsdetach(struct knote *kn)
    1929             : {
    1930           0 :         struct vnode *vp = (struct vnode *)kn->kn_hook;
    1931             : 
    1932           0 :         SLIST_REMOVE(&vp->v_selectinfo.si_note, kn, knote, kn_selnext);
    1933           0 : }
    1934             : 
    1935             : int
    1936           0 : filt_ufsread(struct knote *kn, long hint)
    1937             : {
    1938           0 :         struct vnode *vp = (struct vnode *)kn->kn_hook;
    1939           0 :         struct inode *ip = VTOI(vp);
    1940             : 
    1941             :         /*
    1942             :          * filesystem is gone, so set the EOF flag and schedule 
    1943             :          * the knote for deletion.
    1944             :          */
    1945           0 :         if (hint == NOTE_REVOKE) {
    1946           0 :                 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
    1947           0 :                 return (1);
    1948             :         }
    1949             : 
    1950             : #ifdef EXT2FS
    1951           0 :         if (IS_EXT2_VNODE(ip->i_vnode))
    1952           0 :                 kn->kn_data = ext2fs_size(ip) - kn->kn_fp->f_offset;
    1953             :         else
    1954             : #endif
    1955           0 :                 kn->kn_data = DIP(ip, size) - kn->kn_fp->f_offset;
    1956           0 :         if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
    1957           0 :                 kn->kn_fflags |= NOTE_EOF;
    1958           0 :                 return (1);
    1959             :         }
    1960             : 
    1961           0 :         return (kn->kn_data != 0);
    1962           0 : }
    1963             : 
    1964             : int
    1965           0 : filt_ufswrite(struct knote *kn, long hint)
    1966             : {
    1967             :         /*
    1968             :          * filesystem is gone, so set the EOF flag and schedule 
    1969             :          * the knote for deletion.
    1970             :          */
    1971           0 :         if (hint == NOTE_REVOKE) {
    1972           0 :                 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
    1973           0 :                 return (1);
    1974             :         }
    1975             : 
    1976           0 :         kn->kn_data = 0;
    1977           0 :         return (1);
    1978           0 : }
    1979             : 
    1980             : int
    1981           0 : filt_ufsvnode(struct knote *kn, long hint)
    1982             : {
    1983           0 :         if (kn->kn_sfflags & hint)
    1984           0 :                 kn->kn_fflags |= hint;
    1985           0 :         if (hint == NOTE_REVOKE) {
    1986           0 :                 kn->kn_flags |= EV_EOF;
    1987           0 :                 return (1);
    1988             :         }
    1989           0 :         return (kn->kn_fflags != 0);
    1990           0 : }

Generated by: LCOV version 1.13