lint
[unix-history] / usr / src / sys / ufs / ffs / ufs_vnops.c
index 40a7993..3a68963 100644 (file)
@@ -1,10 +1,10 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ufs_vnops.c 7.112 (Berkeley) %G%
+ *     @(#)ufs_vnops.c 8.8 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -98,7 +98,7 @@ ufs_mknod(ap)
            ap->a_dvp, vpp, ap->a_cnp))
                return (error);
        ip = VTOI(*vpp);
            ap->a_dvp, vpp, ap->a_cnp))
                return (error);
        ip = VTOI(*vpp);
-       ip->i_flag |= IACC|IUPD|ICHG;
+       ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
        if (vap->va_rdev != VNOVAL) {
                /*
                 * Want to be able to use this to make badblock
        if (vap->va_rdev != VNOVAL) {
                /*
                 * Want to be able to use this to make badblock
@@ -134,11 +134,17 @@ ufs_open(ap)
        } */ *ap;
 {
 
        } */ *ap;
 {
 
+       /*
+        * Files marked append-only must be opened for appending.
+        */
+       if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
+           (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
+               return (EPERM);
        return (0);
 }
 
 /*
        return (0);
 }
 
 /*
- * Close called
+ * Close called.
  *
  * Update the times on the inode.
  */
  *
  * Update the times on the inode.
  */
@@ -155,16 +161,11 @@ ufs_close(ap)
        register struct vnode *vp = ap->a_vp;
        register struct inode *ip = VTOI(vp);
 
        register struct vnode *vp = ap->a_vp;
        register struct inode *ip = VTOI(vp);
 
-       if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+       if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
                ITIMES(ip, &time, &time);
        return (0);
 }
 
                ITIMES(ip, &time, &time);
        return (0);
 }
 
-/*
- * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
- * The mode is shifted to select the owner/group/other fields. The
- * super user is granted all permissions.
- */
 int
 ufs_access(ap)
        struct vop_access_args /* {
 int
 ufs_access(ap)
        struct vop_access_args /* {
@@ -177,7 +178,7 @@ ufs_access(ap)
        register struct vnode *vp = ap->a_vp;
        register struct inode *ip = VTOI(vp);
        register struct ucred *cred = ap->a_cred;
        register struct vnode *vp = ap->a_vp;
        register struct inode *ip = VTOI(vp);
        register struct ucred *cred = ap->a_cred;
-       mode_t mode = ap->a_mode;
+       mode_t mask, mode = ap->a_mode;
        register gid_t *gp;
        int i, error;
 
        register gid_t *gp;
        int i, error;
 
@@ -188,35 +189,58 @@ ufs_access(ap)
        }
 #endif
 #ifdef QUOTA
        }
 #endif
 #ifdef QUOTA
-       if (mode & VWRITE) {
+       if (mode & VWRITE)
                switch (vp->v_type) {
                switch (vp->v_type) {
-               case VREG: case VDIR: case VLNK:
+               case VDIR:
+               case VLNK:
+               case VREG:
                        if (error = getinoquota(ip))
                                return (error);
                        if (error = getinoquota(ip))
                                return (error);
+                       break;
                }
                }
-       }
-#endif /* QUOTA */
-       /*
-        * If you're the super-user, you always get access.
-        */
+#endif
+
+       /* If immutable bit set, nobody gets to write it. */
+       if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
+               return (EPERM);
+
+       /* Otherwise, user id 0 always gets access. */
        if (cred->cr_uid == 0)
                return (0);
        if (cred->cr_uid == 0)
                return (0);
-       /*
-        * Access check is based on only one of owner, group, public.
-        * If not owner, then check group. If not a member of the
-        * group, then check public access.
-        */
-       if (cred->cr_uid != ip->i_uid) {
-               mode >>= 3;
-               gp = cred->cr_groups;
-               for (i = 0; i < cred->cr_ngroups; i++, gp++)
-                       if (ip->i_gid == *gp)
-                               goto found;
-               mode >>= 3;
-found:
-               ;
+
+       mask = 0;
+
+       /* Otherwise, check the owner. */
+       if (cred->cr_uid == ip->i_uid) {
+               if (mode & VEXEC)
+                       mask |= S_IXUSR;
+               if (mode & VREAD)
+                       mask |= S_IRUSR;
+               if (mode & VWRITE)
+                       mask |= S_IWUSR;
+               return ((ip->i_mode & mask) == mask ? 0 : EACCES);
        }
        }
-       return ((ip->i_mode & mode) == mode ? 0 : EACCES);
+
+       /* Otherwise, check the groups. */
+       for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
+               if (ip->i_gid == *gp) {
+                       if (mode & VEXEC)
+                               mask |= S_IXGRP;
+                       if (mode & VREAD)
+                               mask |= S_IRGRP;
+                       if (mode & VWRITE)
+                               mask |= S_IWGRP;
+                       return ((ip->i_mode & mask) == mask ? 0 : EACCES);
+               }
+
+       /* Otherwise, check everyone else. */
+       if (mode & VEXEC)
+               mask |= S_IXOTH;
+       if (mode & VREAD)
+               mask |= S_IROTH;
+       if (mode & VWRITE)
+               mask |= S_IWOTH;
+       return ((ip->i_mode & mask) == mask ? 0 : EACCES);
 }
 
 /* ARGSUSED */
 }
 
 /* ARGSUSED */
@@ -292,6 +316,27 @@ ufs_setattr(ap)
            ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
                return (EINVAL);
        }
            ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
                return (EINVAL);
        }
+       if (vap->va_flags != VNOVAL) {
+               if (cred->cr_uid != ip->i_uid &&
+                   (error = suser(cred, &p->p_acflag)))
+                       return (error);
+               if (cred->cr_uid == 0) {
+                       if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
+                           securelevel > 0)
+                               return (EPERM);
+                       ip->i_flags = vap->va_flags;
+               } else {
+                       if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND))
+                               return (EPERM);
+                       ip->i_flags &= SF_SETTABLE;
+                       ip->i_flags |= (vap->va_flags & UF_SETTABLE);
+               }
+               ip->i_flag |= IN_CHANGE;
+               if (vap->va_flags & (IMMUTABLE | APPEND))
+                       return (0);
+       }
+       if (ip->i_flags & (IMMUTABLE | APPEND))
+               return (EPERM);
        /*
         * Go through the fields and update iff not VNOVAL.
         */
        /*
         * Go through the fields and update iff not VNOVAL.
         */
@@ -307,12 +352,14 @@ ufs_setattr(ap)
        ip = VTOI(vp);
        if (vap->va_atime.ts_sec != VNOVAL || vap->va_mtime.ts_sec != VNOVAL) {
                if (cred->cr_uid != ip->i_uid &&
        ip = VTOI(vp);
        if (vap->va_atime.ts_sec != VNOVAL || vap->va_mtime.ts_sec != VNOVAL) {
                if (cred->cr_uid != ip->i_uid &&
-                   (error = suser(cred, &p->p_acflag)))
+                   (error = suser(cred, &p->p_acflag)) &&
+                   ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
+                   (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                        return (error);
                if (vap->va_atime.ts_sec != VNOVAL)
                        return (error);
                if (vap->va_atime.ts_sec != VNOVAL)
-                       ip->i_flag |= IACC;
+                       ip->i_flag |= IN_ACCESS;
                if (vap->va_mtime.ts_sec != VNOVAL)
                if (vap->va_mtime.ts_sec != VNOVAL)
-                       ip->i_flag |= IUPD | ICHG;
+                       ip->i_flag |= IN_CHANGE | IN_UPDATE;
                atimeval.tv_sec = vap->va_atime.ts_sec;
                atimeval.tv_usec = vap->va_atime.ts_nsec / 1000;
                mtimeval.tv_sec = vap->va_mtime.ts_sec;
                atimeval.tv_sec = vap->va_atime.ts_sec;
                atimeval.tv_usec = vap->va_atime.ts_nsec / 1000;
                mtimeval.tv_sec = vap->va_mtime.ts_sec;
@@ -323,18 +370,6 @@ ufs_setattr(ap)
        error = 0;
        if (vap->va_mode != (mode_t)VNOVAL)
                error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
        error = 0;
        if (vap->va_mode != (mode_t)VNOVAL)
                error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
-       if (vap->va_flags != VNOVAL) {
-               if (cred->cr_uid != ip->i_uid &&
-                   (error = suser(cred, &p->p_acflag)))
-                       return (error);
-               if (cred->cr_uid == 0) {
-                       ip->i_flags = vap->va_flags;
-               } else {
-                       ip->i_flags &= 0xffff0000;
-                       ip->i_flags |= (vap->va_flags & 0xffff);
-               }
-               ip->i_flag |= ICHG;
-       }
        return (error);
 }
 
        return (error);
 }
 
@@ -356,15 +391,15 @@ ufs_chmod(vp, mode, cred, p)
            (error = suser(cred, &p->p_acflag)))
                return (error);
        if (cred->cr_uid) {
            (error = suser(cred, &p->p_acflag)))
                return (error);
        if (cred->cr_uid) {
-               if (vp->v_type != VDIR && (mode & ISVTX))
+               if (vp->v_type != VDIR && (mode & S_ISTXT))
                        return (EFTYPE);
                if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
                        return (EPERM);
        }
                        return (EFTYPE);
                if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
                        return (EPERM);
        }
-       ip->i_mode &= ~07777;
-       ip->i_mode |= mode & 07777;
-       ip->i_flag |= ICHG;
-       if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
+       ip->i_mode &= ~ALLPERMS;
+       ip->i_mode |= (mode & ALLPERMS);
+       ip->i_flag |= IN_CHANGE;
+       if ((vp->v_flag & VTEXT) && (ip->i_mode & S_ISTXT) == 0)
                (void) vnode_pager_uncache(vp);
        return (0);
 }
                (void) vnode_pager_uncache(vp);
        return (0);
 }
@@ -403,8 +438,8 @@ ufs_chown(vp, uid, gid, cred, p)
            !groupmember((gid_t)gid, cred)) &&
            (error = suser(cred, &p->p_acflag)))
                return (error);
            !groupmember((gid_t)gid, cred)) &&
            (error = suser(cred, &p->p_acflag)))
                return (error);
-       ouid = ip->i_uid;
        ogid = ip->i_gid;
        ogid = ip->i_gid;
+       ouid = ip->i_uid;
 #ifdef QUOTA
        if (error = getinoquota(ip))
                return (error);
 #ifdef QUOTA
        if (error = getinoquota(ip))
                return (error);
@@ -424,8 +459,8 @@ ufs_chown(vp, uid, gid, cred, p)
                ip->i_dquot[i] = NODQUOT;
        }
 #endif
                ip->i_dquot[i] = NODQUOT;
        }
 #endif
-       ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_gid = gid;
+       ip->i_uid = uid;
 #ifdef QUOTA
        if ((error = getinoquota(ip)) == 0) {
                if (ouid == uid) {
 #ifdef QUOTA
        if ((error = getinoquota(ip)) == 0) {
                if (ouid == uid) {
@@ -447,8 +482,8 @@ ufs_chown(vp, uid, gid, cred, p)
                        ip->i_dquot[i] = NODQUOT;
                }
        }
                        ip->i_dquot[i] = NODQUOT;
                }
        }
-       ip->i_uid = ouid;
        ip->i_gid = ogid;
        ip->i_gid = ogid;
+       ip->i_uid = ouid;
        if (getinoquota(ip) == 0) {
                if (ouid == uid) {
                        dqrele(vp, ip->i_dquot[USRQUOTA]);
        if (getinoquota(ip) == 0) {
                if (ouid == uid) {
                        dqrele(vp, ip->i_dquot[USRQUOTA]);
@@ -468,7 +503,7 @@ good:
                panic("chown: lost quota");
 #endif /* QUOTA */
        if (ouid != uid || ogid != gid)
                panic("chown: lost quota");
 #endif /* QUOTA */
        if (ouid != uid || ogid != gid)
-               ip->i_flag |= ICHG;
+               ip->i_flag |= IN_CHANGE;
        if (ouid != uid && cred->cr_uid != 0)
                ip->i_mode &= ~ISUID;
        if (ogid != gid && cred->cr_uid != 0)
        if (ouid != uid && cred->cr_uid != 0)
                ip->i_mode &= ~ISUID;
        if (ogid != gid && cred->cr_uid != 0)
@@ -548,11 +583,6 @@ ufs_seek(ap)
        return (0);
 }
 
        return (0);
 }
 
-/*
- * ufs remove
- * Hard to avoid races here, especially
- * in unlinking directories.
- */
 int
 ufs_remove(ap)
        struct vop_remove_args /* {
 int
 ufs_remove(ap)
        struct vop_remove_args /* {
@@ -567,12 +597,16 @@ ufs_remove(ap)
        int error;
 
        ip = VTOI(vp);
        int error;
 
        ip = VTOI(vp);
-       error = ufs_dirremove(dvp, ap->a_cnp);
-       if (!error) {
-               ip = VTOI(vp);
+       if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
+           (VTOI(dvp)->i_flags & APPEND)) {
+               error = EPERM;
+               goto out;
+       }
+       if ((error = ufs_dirremove(dvp, ap->a_cnp)) == 0) {
                ip->i_nlink--;
                ip->i_nlink--;
-               ip->i_flag |= ICHG;
+               ip->i_flag |= IN_CHANGE;
        }
        }
+out:
        if (dvp == vp)
                vrele(vp);
        else
        if (dvp == vp)
                vrele(vp);
        else
@@ -618,15 +652,20 @@ ufs_link(ap)
                error = EMLINK;
                goto out1;
        }
                error = EMLINK;
                goto out1;
        }
+       if (ip->i_flags & (IMMUTABLE | APPEND)) {
+               VOP_ABORTOP(vp, cnp);
+               error = EPERM;
+               goto out1;
+       }
        ip->i_nlink++;
        ip->i_nlink++;
-       ip->i_flag |= ICHG;
+       ip->i_flag |= IN_CHANGE;
        tv = time;
        error = VOP_UPDATE(tdvp, &tv, &tv, 1);
        if (!error)
                error = ufs_direnter(ip, vp, cnp);
        if (error) {
                ip->i_nlink--;
        tv = time;
        error = VOP_UPDATE(tdvp, &tv, &tv, 1);
        if (!error)
                error = ufs_direnter(ip, vp, cnp);
        if (error) {
                ip->i_nlink--;
-               ip->i_flag |= ICHG;
+               ip->i_flag |= IN_CHANGE;
        }
        FREE(cnp->cn_pnbuf, M_NAMEI);
 out1:
        }
        FREE(cnp->cn_pnbuf, M_NAMEI);
 out1:
@@ -649,14 +688,14 @@ relookup(dvp, vpp, cnp)
        struct componentname *cnp;
 {
        register struct vnode *dp = 0;  /* the directory we are searching */
        struct componentname *cnp;
 {
        register struct vnode *dp = 0;  /* the directory we are searching */
-       struct vnode *tdp;              /* saved dp */
-       struct mount *mp;               /* mount table entry */
        int docache;                    /* == 0 do not cache last component */
        int wantparent;                 /* 1 => wantparent or lockparent flag */
        int rdonly;                     /* lookup read-only flag bit */
        int docache;                    /* == 0 do not cache last component */
        int wantparent;                 /* 1 => wantparent or lockparent flag */
        int rdonly;                     /* lookup read-only flag bit */
-       char *cp;                       /* DEBUG: check name ptr/len */
-       int newhash;                    /* DEBUG: check name hash */
        int error = 0;
        int error = 0;
+#ifdef NAMEI_DIAGNOSTIC
+       int newhash;                    /* DEBUG: check name hash */
+       char *cp;                       /* DEBUG: check name ptr/len */
+#endif
 
        /*
         * Setup: break out flag bits into variables.
 
        /*
         * Setup: break out flag bits into variables.
@@ -756,7 +795,6 @@ relookup(dvp, vpp, cnp)
                panic ("relookup: symlink found.\n");
 #endif
 
                panic ("relookup: symlink found.\n");
 #endif
 
-nextname:
        /*
         * Check for read-only file systems.
         */
        /*
         * Check for read-only file systems.
         */
@@ -839,7 +877,6 @@ ufs_rename(ap)
        struct timeval tv;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        int error = 0;
        struct timeval tv;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        int error = 0;
-       int fdvpneedsrele = 1, tdvpneedsrele = 1;
        u_char namlen;
 
 #ifdef DIAGNOSTIC
        u_char namlen;
 
 #ifdef DIAGNOSTIC
@@ -870,6 +907,11 @@ abortit:
        /*
         * Check if just deleting a link name.
         */
        /*
         * Check if just deleting a link name.
         */
+       if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
+           (VTOI(tdvp)->i_flags & APPEND))) {
+               error = EPERM;
+               goto abortit;
+       }
        if (fvp == tvp) {
                if (fvp->v_type == VDIR) {
                        error = EINVAL;
        if (fvp == tvp) {
                if (fvp->v_type == VDIR) {
                        error = EINVAL;
@@ -892,18 +934,23 @@ abortit:
                goto abortit;
        dp = VTOI(fdvp);
        ip = VTOI(fvp);
                goto abortit;
        dp = VTOI(fdvp);
        ip = VTOI(fvp);
+       if ((ip->i_flags & (IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) {
+               VOP_UNLOCK(fvp);
+               error = EPERM;
+               goto abortit;
+       }
        if ((ip->i_mode & IFMT) == IFDIR) {
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
                    dp == ip || (fcnp->cn_flags&ISDOTDOT) ||
        if ((ip->i_mode & IFMT) == IFDIR) {
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
                    dp == ip || (fcnp->cn_flags&ISDOTDOT) ||
-                   (ip->i_flag & IRENAME)) {
+                   (ip->i_flag & IN_RENAME)) {
                        VOP_UNLOCK(fvp);
                        error = EINVAL;
                        goto abortit;
                }
                        VOP_UNLOCK(fvp);
                        error = EINVAL;
                        goto abortit;
                }
-               ip->i_flag |= IRENAME;
+               ip->i_flag |= IN_RENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
                oldparent = dp->i_number;
                doingdirectory++;
        }
@@ -925,7 +972,7 @@ abortit:
         *    may be wrong, but correctable.
         */
        ip->i_nlink++;
         *    may be wrong, but correctable.
         */
        ip->i_nlink++;
-       ip->i_flag |= ICHG;
+       ip->i_flag |= IN_CHANGE;
        tv = time;
        if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) {
                VOP_UNLOCK(fvp);
        tv = time;
        if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) {
                VOP_UNLOCK(fvp);
@@ -984,14 +1031,14 @@ abortit:
                                goto bad;
                        }
                        dp->i_nlink++;
                                goto bad;
                        }
                        dp->i_nlink++;
-                       dp->i_flag |= ICHG;
+                       dp->i_flag |= IN_CHANGE;
                        if (error = VOP_UPDATE(tdvp, &tv, &tv, 1))
                                goto bad;
                }
                if (error = ufs_direnter(ip, tdvp, tcnp)) {
                        if (doingdirectory && newparent) {
                                dp->i_nlink--;
                        if (error = VOP_UPDATE(tdvp, &tv, &tv, 1))
                                goto bad;
                }
                if (error = ufs_direnter(ip, tdvp, tcnp)) {
                        if (doingdirectory && newparent) {
                                dp->i_nlink--;
-                               dp->i_flag |= ICHG;
+                               dp->i_flag |= IN_CHANGE;
                                (void)VOP_UPDATE(tdvp, &tv, &tv, 1);
                        }
                        goto bad;
                                (void)VOP_UPDATE(tdvp, &tv, &tv, 1);
                        }
                        goto bad;
@@ -1011,7 +1058,7 @@ abortit:
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
-               if ((dp->i_mode & ISVTX) && tcnp->cn_cred->cr_uid != 0 &&
+               if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
                    tcnp->cn_cred->cr_uid != dp->i_uid &&
                    xp->i_uid != tcnp->cn_cred->cr_uid) {
                        error = EPERM;
                    tcnp->cn_cred->cr_uid != dp->i_uid &&
                    xp->i_uid != tcnp->cn_cred->cr_uid) {
                        error = EPERM;
@@ -1047,7 +1094,7 @@ abortit:
                 */
                 if (doingdirectory && !newparent) {
                        dp->i_nlink--;
                 */
                 if (doingdirectory && !newparent) {
                        dp->i_nlink--;
-                       dp->i_flag |= ICHG;
+                       dp->i_flag |= IN_CHANGE;
                }
                vput(tdvp);
                /*
                }
                vput(tdvp);
                /*
@@ -1067,7 +1114,7 @@ abortit:
                        error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC,
                            tcnp->cn_cred, tcnp->cn_proc);
                }
                        error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC,
                            tcnp->cn_cred, tcnp->cn_proc);
                }
-               xp->i_flag |= ICHG;
+               xp->i_flag |= IN_CHANGE;
                vput(tvp);
                xp = NULL;
        }
                vput(tvp);
                xp = NULL;
        }
@@ -1115,7 +1162,7 @@ abortit:
                 */
                if (doingdirectory && newparent) {
                        dp->i_nlink--;
                 */
                if (doingdirectory && newparent) {
                        dp->i_nlink--;
-                       dp->i_flag |= ICHG;
+                       dp->i_flag |= IN_CHANGE;
                        error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
                                sizeof (struct dirtemplate), (off_t)0,
                                UIO_SYSSPACE, IO_NODELOCKED, 
                        error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
                                sizeof (struct dirtemplate), (off_t)0,
                                UIO_SYSSPACE, IO_NODELOCKED, 
@@ -1150,9 +1197,9 @@ abortit:
                error = ufs_dirremove(fdvp, fcnp);
                if (!error) {
                        xp->i_nlink--;
                error = ufs_dirremove(fdvp, fcnp);
                if (!error) {
                        xp->i_nlink--;
-                       xp->i_flag |= ICHG;
+                       xp->i_flag |= IN_CHANGE;
                }
                }
-               xp->i_flag &= ~IRENAME;
+               xp->i_flag &= ~IN_RENAME;
        }
        if (dp)
                vput(fdvp);
        }
        if (dp)
                vput(fdvp);
@@ -1168,7 +1215,7 @@ bad:
 out:
        if (VOP_LOCK(fvp) == 0) {
                ip->i_nlink--;
 out:
        if (VOP_LOCK(fvp) == 0) {
                ip->i_nlink--;
-               ip->i_flag |= ICHG;
+               ip->i_flag |= IN_CHANGE;
                vput(fvp);
        } else
                vrele(fvp);
                vput(fvp);
        } else
                vrele(fvp);
@@ -1214,22 +1261,18 @@ ufs_mkdir(ap)
 #endif
        dp = VTOI(dvp);
        if ((nlink_t)dp->i_nlink >= LINK_MAX) {
 #endif
        dp = VTOI(dvp);
        if ((nlink_t)dp->i_nlink >= LINK_MAX) {
-               free(cnp->cn_pnbuf, M_NAMEI);
-               vput(dvp);
-               return (EMLINK);
+               error = EMLINK;
+               goto out;
        }
        }
-       dmode = vap->va_mode&0777;
+       dmode = vap->va_mode & 0777;
        dmode |= IFDIR;
        /*
        dmode |= IFDIR;
        /*
-        * Must simulate part of maknode here to acquire the inode, but
-        * not have it entered in the parent directory. The entry is made
-        * later after writing "." and ".." entries.
+        * Must simulate part of ufs_makeinode here to acquire the inode,
+        * but not have it entered in the parent directory. The entry is
+        * made later after writing "." and ".." entries.
         */
         */
-       if (error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) {
-               free(cnp->cn_pnbuf, M_NAMEI);
-               vput(dvp);
-               return (error);
-       }
+       if (error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp))
+               goto out;
        ip = VTOI(tvp);
        ip->i_uid = cnp->cn_cred->cr_uid;
        ip->i_gid = dp->i_gid;
        ip = VTOI(tvp);
        ip->i_uid = cnp->cn_cred->cr_uid;
        ip->i_gid = dp->i_gid;
@@ -1243,7 +1286,7 @@ ufs_mkdir(ap)
                return (error);
        }
 #endif
                return (error);
        }
 #endif
-       ip->i_flag |= IACC|IUPD|ICHG;
+       ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
        ip->i_mode = dmode;
        tvp->v_type = VDIR;     /* Rest init'd in iget() */
        ip->i_nlink = 2;
        ip->i_mode = dmode;
        tvp->v_type = VDIR;     /* Rest init'd in iget() */
        ip->i_nlink = 2;
@@ -1257,7 +1300,7 @@ ufs_mkdir(ap)
         * so reparation is possible if we crash.
         */
        dp->i_nlink++;
         * so reparation is possible if we crash.
         */
        dp->i_nlink++;
-       dp->i_flag |= ICHG;
+       dp->i_flag |= IN_CHANGE;
        if (error = VOP_UPDATE(dvp, &tv, &tv, 1))
                goto bad;
 
        if (error = VOP_UPDATE(dvp, &tv, &tv, 1))
                goto bad;
 
@@ -1274,20 +1317,20 @@ ufs_mkdir(ap)
            IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
        if (error) {
                dp->i_nlink--;
            IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
        if (error) {
                dp->i_nlink--;
-               dp->i_flag |= ICHG;
+               dp->i_flag |= IN_CHANGE;
                goto bad;
        }
        if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
                panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
        else {
                ip->i_size = DIRBLKSIZ;
                goto bad;
        }
        if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
                panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
        else {
                ip->i_size = DIRBLKSIZ;
-               ip->i_flag |= ICHG;
+               ip->i_flag |= IN_CHANGE;
        }
 
        /* Directory set up, now install it's entry in the parent directory. */
        if (error = ufs_direnter(ip, dvp, cnp)) {
                dp->i_nlink--;
        }
 
        /* Directory set up, now install it's entry in the parent directory. */
        if (error = ufs_direnter(ip, dvp, cnp)) {
                dp->i_nlink--;
-               dp->i_flag |= ICHG;
+               dp->i_flag |= IN_CHANGE;
        }
 bad:
        /*
        }
 bad:
        /*
@@ -1296,10 +1339,11 @@ bad:
         */
        if (error) {
                ip->i_nlink = 0;
         */
        if (error) {
                ip->i_nlink = 0;
-               ip->i_flag |= ICHG;
+               ip->i_flag |= IN_CHANGE;
                vput(tvp);
        } else
                *ap->a_vpp = tvp;
                vput(tvp);
        } else
                *ap->a_vpp = tvp;
+out:
        FREE(cnp->cn_pnbuf, M_NAMEI);
        vput(dvp);
        return (error);
        FREE(cnp->cn_pnbuf, M_NAMEI);
        vput(dvp);
        return (error);
@@ -1345,6 +1389,10 @@ ufs_rmdir(ap)
                error = ENOTEMPTY;
                goto out;
        }
                error = ENOTEMPTY;
                goto out;
        }
+       if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE | APPEND))) {
+               error = EPERM;
+               goto out;
+       }
        /*
         * Delete reference to directory before purging
         * inode.  If we crash in between, the directory
        /*
         * Delete reference to directory before purging
         * inode.  If we crash in between, the directory
@@ -1353,7 +1401,7 @@ ufs_rmdir(ap)
        if (error = ufs_dirremove(dvp, cnp))
                goto out;
        dp->i_nlink--;
        if (error = ufs_dirremove(dvp, cnp))
                goto out;
        dp->i_nlink--;
-       dp->i_flag |= ICHG;
+       dp->i_flag |= IN_CHANGE;
        cache_purge(dvp);
        vput(dvp);
        dvp = NULL;
        cache_purge(dvp);
        vput(dvp);
        dvp = NULL;
@@ -1405,7 +1453,7 @@ ufs_symlink(ap)
                ip = VTOI(vp);
                bcopy(ap->a_target, (char *)ip->i_shortlink, len);
                ip->i_size = len;
                ip = VTOI(vp);
                bcopy(ap->a_target, (char *)ip->i_shortlink, len);
                ip->i_size = len;
-               ip->i_flag |= IUPD|ICHG;
+               ip->i_flag |= IN_CHANGE | IN_UPDATE;
        } else
                error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
                    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
        } else
                error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
                    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
@@ -1548,8 +1596,8 @@ start:
        if (vp->v_tag == VT_NON)
                return (ENOENT);
        ip = VTOI(vp);
        if (vp->v_tag == VT_NON)
                return (ENOENT);
        ip = VTOI(vp);
-       if (ip->i_flag & ILOCKED) {
-               ip->i_flag |= IWANT;
+       if (ip->i_flag & IN_LOCKED) {
+               ip->i_flag |= IN_WANTED;
 #ifdef DIAGNOSTIC
                if (p) {
                        if (p->p_pid == ip->i_lockholder)
 #ifdef DIAGNOSTIC
                if (p) {
                        if (p->p_pid == ip->i_lockholder)
@@ -1572,7 +1620,7 @@ start:
        else
                ip->i_lockholder = -1;
 #endif
        else
                ip->i_lockholder = -1;
 #endif
-       ip->i_flag |= ILOCKED;
+       ip->i_flag |= IN_LOCKED;
        return (0);
 }
 
        return (0);
 }
 
@@ -1590,7 +1638,7 @@ ufs_unlock(ap)
        struct proc *p = curproc;       /* XXX */
 
 #ifdef DIAGNOSTIC
        struct proc *p = curproc;       /* XXX */
 
 #ifdef DIAGNOSTIC
-       if ((ip->i_flag & ILOCKED) == 0) {
+       if ((ip->i_flag & IN_LOCKED) == 0) {
                vprint("ufs_unlock: unlocked inode", ap->a_vp);
                panic("ufs_unlock NOT LOCKED");
        }
                vprint("ufs_unlock: unlocked inode", ap->a_vp);
                panic("ufs_unlock NOT LOCKED");
        }
@@ -1600,9 +1648,9 @@ ufs_unlock(ap)
                    p->p_pid, ip->i_lockholder);
        ip->i_lockholder = 0;
 #endif
                    p->p_pid, ip->i_lockholder);
        ip->i_lockholder = 0;
 #endif
-       ip->i_flag &= ~ILOCKED;
-       if (ip->i_flag & IWANT) {
-               ip->i_flag &= ~IWANT;
+       ip->i_flag &= ~IN_LOCKED;
+       if (ip->i_flag & IN_WANTED) {
+               ip->i_flag &= ~IN_WANTED;
                wakeup((caddr_t)ip);
        }
        return (0);
                wakeup((caddr_t)ip);
        }
        return (0);
@@ -1618,7 +1666,7 @@ ufs_islocked(ap)
        } */ *ap;
 {
 
        } */ *ap;
 {
 
-       if (VTOI(ap->a_vp)->i_flag & ILOCKED)
+       if (VTOI(ap->a_vp)->i_flag & IN_LOCKED)
                return (1);
        return (0);
 }
                return (1);
        return (0);
 }
@@ -1627,6 +1675,9 @@ ufs_islocked(ap)
  * Calculate the logical to physical mapping if not done already,
  * then call the device strategy routine.
  */
  * Calculate the logical to physical mapping if not done already,
  * then call the device strategy routine.
  */
+#include <sys/sysctl.h>
+int checkblk = 1;
+struct ctldebug debug10 = { "checkblk", &checkblk };
 int
 ufs_strategy(ap)
        struct vop_strategy_args /* {
 int
 ufs_strategy(ap)
        struct vop_strategy_args /* {
@@ -1636,22 +1687,50 @@ ufs_strategy(ap)
        register struct buf *bp = ap->a_bp;
        register struct vnode *vp = bp->b_vp;
        register struct inode *ip;
        register struct buf *bp = ap->a_bp;
        register struct vnode *vp = bp->b_vp;
        register struct inode *ip;
+       daddr_t blkno;
        int error;
 
        ip = VTOI(vp);
        if (vp->v_type == VBLK || vp->v_type == VCHR)
                panic("ufs_strategy: spec");
        int error;
 
        ip = VTOI(vp);
        if (vp->v_type == VBLK || vp->v_type == VCHR)
                panic("ufs_strategy: spec");
-       if (bp->b_blkno == bp->b_lblkno) {
-               if (error =
-                   VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) {
+       if ((checkblk && (long)bp->b_lblkno >= 0 &&
+           (bp->b_flags & B_XXX) == 0) ||
+           bp->b_blkno == bp->b_lblkno) {
+               if (error = VOP_BMAP(vp, bp->b_lblkno, NULL, &blkno, NULL)) {
                        bp->b_error = error;
                        bp->b_flags |= B_ERROR;
                        biodone(bp);
                        return (error);
                }
                        bp->b_error = error;
                        bp->b_flags |= B_ERROR;
                        biodone(bp);
                        return (error);
                }
+               if (bp->b_blkno != bp->b_lblkno && bp->b_blkno != blkno &&
+                   !((bp->b_flags & B_READ) && (long)blkno == -1))
+                       panic("ufs_strategy: bad blkno %d != %d", bp->b_blkno,
+                           blkno);
+               /* If this is a clustered block, check sub-blocks as well */
+               if (bp->b_saveaddr) {
+                       struct buf *tbp;
+                       struct cluster_save *b_save;
+                       int i;
+                       daddr_t bn;
+
+                       b_save = (struct cluster_save *)bp->b_saveaddr;
+                       for (i = 0; i < b_save->bs_nchildren; i++) {
+                               tbp = b_save->bs_children[i];
+                               if ((tbp->b_flags & B_XXX) == 0 &&
+                                   !VOP_BMAP(vp, tbp->b_lblkno, NULL,
+                                   &bn, NULL) && tbp->b_blkno != bn)
+                                       panic("ufs_strategy: bad bno %d != %d",
+                                           bp->b_blkno, blkno);
+                       }
+               }
+               bp->b_blkno = blkno;
                if ((long)bp->b_blkno == -1)
                if ((long)bp->b_blkno == -1)
-                       clrbuf(bp);
+                       if ((bp->b_flags & B_READ) == 0)
+                               panic("ufs_startegy: write unallocated block");
+                       else
+                               clrbuf(bp);
        }
        }
+       bp->b_flags &=~ B_XXX;
        if ((long)bp->b_blkno == -1) {
                biodone(bp);
                return (0);
        if ((long)bp->b_blkno == -1) {
                biodone(bp);
                return (0);
@@ -1680,7 +1759,7 @@ ufs_print(ap)
        if (vp->v_type == VFIFO)
                fifo_printinfo(vp);
 #endif /* FIFO */
        if (vp->v_type == VFIFO)
                fifo_printinfo(vp);
 #endif /* FIFO */
-       printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
+       printf("%s\n", (ip->i_flag & IN_LOCKED) ? " (LOCKED)" : "");
        if (ip->i_lockholder == 0)
                return (0);
        printf("\towner pid %d", ip->i_lockholder);
        if (ip->i_lockholder == 0)
                return (0);
        printf("\towner pid %d", ip->i_lockholder);
@@ -1706,7 +1785,7 @@ ufsspec_read(ap)
        /*
         * Set access flag.
         */
        /*
         * Set access flag.
         */
-       VTOI(ap->a_vp)->i_flag |= IACC;
+       VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
 }
 
        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
 }
 
@@ -1726,7 +1805,7 @@ ufsspec_write(ap)
        /*
         * Set update and change flags.
         */
        /*
         * Set update and change flags.
         */
-       VTOI(ap->a_vp)->i_flag |= IUPD|ICHG;
+       VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
 }
 
        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
 }
 
@@ -1746,7 +1825,7 @@ ufsspec_close(ap)
 {
        register struct inode *ip = VTOI(ap->a_vp);
 
 {
        register struct inode *ip = VTOI(ap->a_vp);
 
-       if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+       if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
                ITIMES(ip, &time, &time);
        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
 }
                ITIMES(ip, &time, &time);
        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
 }
@@ -1769,7 +1848,7 @@ ufsfifo_read(ap)
        /*
         * Set access flag.
         */
        /*
         * Set access flag.
         */
-       VTOI(ap->a_vp)->i_flag |= IACC;
+       VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
 }
 
        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
 }
 
@@ -1790,7 +1869,7 @@ ufsfifo_write(ap)
        /*
         * Set update and change flags.
         */
        /*
         * Set update and change flags.
         */
-       VTOI(ap->a_vp)->i_flag |= IUPD|ICHG;
+       VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
 }
 
        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
 }
 
@@ -1810,12 +1889,48 @@ ufsfifo_close(ap)
        extern int (**fifo_vnodeop_p)();
        register struct inode *ip = VTOI(ap->a_vp);
 
        extern int (**fifo_vnodeop_p)();
        register struct inode *ip = VTOI(ap->a_vp);
 
-       if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+       if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
                ITIMES(ip, &time, &time);
        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
 }
 #endif /* FIFO */
 
                ITIMES(ip, &time, &time);
        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
 }
 #endif /* FIFO */
 
+/*
+ * Return POSIX pathconf information applicable to ufs filesystems.
+ */
+ufs_pathconf(ap)
+       struct vop_pathconf_args /* {
+               struct vnode *a_vp;
+               int a_name;
+               int *a_retval;
+       } */ *ap;
+{
+
+       switch (ap->a_name) {
+       case _PC_LINK_MAX:
+               *ap->a_retval = LINK_MAX;
+               return (0);
+       case _PC_NAME_MAX:
+               *ap->a_retval = NAME_MAX;
+               return (0);
+       case _PC_PATH_MAX:
+               *ap->a_retval = PATH_MAX;
+               return (0);
+       case _PC_PIPE_BUF:
+               *ap->a_retval = PIPE_BUF;
+               return (0);
+       case _PC_CHOWN_RESTRICTED:
+               *ap->a_retval = 1;
+               return (0);
+       case _PC_NO_TRUNC:
+               *ap->a_retval = 1;
+               return (0);
+       default:
+               return (EINVAL);
+       }
+       /* NOTREACHED */
+}
+
 /*
  * Advisory record locking support
  */
 /*
  * Advisory record locking support
  */
@@ -1995,8 +2110,11 @@ ufs_makeinode(mode, dvp, vpp, cnp)
                return (error);
        }
        ip = VTOI(tvp);
                return (error);
        }
        ip = VTOI(tvp);
-       ip->i_uid = cnp->cn_cred->cr_uid;
        ip->i_gid = pdir->i_gid;
        ip->i_gid = pdir->i_gid;
+       if ((mode & IFMT) == IFLNK)
+               ip->i_uid = pdir->i_uid;
+       else
+               ip->i_uid = cnp->cn_cred->cr_uid;
 #ifdef QUOTA
        if ((error = getinoquota(ip)) ||
            (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 #ifdef QUOTA
        if ((error = getinoquota(ip)) ||
            (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
@@ -2007,7 +2125,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
                return (error);
        }
 #endif
                return (error);
        }
 #endif
-       ip->i_flag |= IACC|IUPD|ICHG;
+       ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
        ip->i_mode = mode;
        tvp->v_type = IFTOVT(mode);     /* Rest init'd in iget() */
        ip->i_nlink = 1;
        ip->i_mode = mode;
        tvp->v_type = IFTOVT(mode);     /* Rest init'd in iget() */
        ip->i_nlink = 1;
@@ -2037,7 +2155,7 @@ bad:
        free(cnp->cn_pnbuf, M_NAMEI);
        vput(dvp);
        ip->i_nlink = 0;
        free(cnp->cn_pnbuf, M_NAMEI);
        vput(dvp);
        ip->i_nlink = 0;
-       ip->i_flag |= ICHG;
+       ip->i_flag |= IN_CHANGE;
        vput(tvp);
        return (error);
 }
        vput(tvp);
        return (error);
 }