fstest regression fixes - POSIX error codes.
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 May 2009 23:57:44 +0000 (16:57 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 May 2009 23:57:44 +0000 (16:57 -0700)
Deal with most of the issues found by FreeBSD's fstest regression test:
    * Limit path components to 255 characters.  Return ENAMETOOLONG if
      the limit is exceeded.

    * Return EEXIST, EINVAL, and ENOTEMPTY as appropriate when the user
      attempts to create, delete, or rename "." or "..", instead of EINVAL.

    * Return EISDIR if an attempt is made to open a directory for writing,
      instead of EINVAL.

    * Return EACCES if an attempt is made to open a file O_TRUNC without
      O_RDWR or O_WRONLY, instead of silently dropping the O_TRUNC.

    * Implement O_NOFOLLOW semantics generally instead of just with O_EXCL.

Not dealt with:
    * DragonFly clears SGID AND SUID on uid or gid change, if not root.
      If root is doing the operation SGID/SUID is not cleared.

    * HAMMER cannot modify the ctime without rolling a new inode, which
      is very expensive, and does not do so when entries are added or
      removed from a directory.  mtime is modified.

sys/kern/vfs_helper.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_vnops.c

index 531fd3e..1b2f6a5 100644 (file)
@@ -247,6 +247,12 @@ vop_helper_chown(struct vnode *vp, uid_t new_uid, gid_t new_gid,
        *cur_uidp = new_uid;
        *cur_gidp = new_gid;
        /* XXX QUOTA CODE */
+
+       /*
+        * DragonFly clears both SUID and SGID if either the owner or
+        * group is changed and root isn't doing it.  If root is doing
+        * it we do not clear SUID/SGID.
+        */
        if (cred->cr_uid != 0 && (ouid != new_uid || ogid != new_gid))
                *cur_modep &= ~(S_ISUID | S_ISGID);
        return(0);
index ab783b8..09758a6 100644 (file)
@@ -375,12 +375,17 @@ nlookup(struct nlookupdata *nd)
            break;
 
        /*
-        * Extract the path component
+        * Extract the path component.  Path components are limited to
+        * 255 characters.
         */
        nlc.nlc_nameptr = ptr;
        while (*ptr && *ptr != '/')
            ++ptr;
        nlc.nlc_namelen = ptr - nlc.nlc_nameptr;
+       if (nlc.nlc_namelen >= 256) {
+           error = ENAMETOOLONG;
+           break;
+       }
 
        /*
         * Lookup the path component in the cache, creating an unresolved
@@ -424,7 +429,7 @@ nlookup(struct nlookupdata *nd)
                KKASSERT(nch.ncp != NULL);
                cache_get(&nch, &nch);
            }
-           wasdotordotdot = 1;
+           wasdotordotdot = 2;
        } else {
            nch = cache_nlookup(&nd->nl_nch, &nlc);
            while ((error = cache_resolve(&nch, nd->nl_cred)) == EAGAIN) {
@@ -496,7 +501,15 @@ nlookup(struct nlookupdata *nd)
            if (error == 0 && wasdotordotdot &&
                (nd->nl_flags & (NLC_CREATE | NLC_DELETE |
                                 NLC_RENAME_SRC | NLC_RENAME_DST))) {
-               error = EINVAL;
+               /*
+                * POSIX junk
+                */
+               if (nd->nl_flags & NLC_CREATE)
+                       error = EEXIST;
+               else if (nd->nl_flags & NLC_DELETE)
+                       error = (wasdotordotdot == 1) ? EINVAL : ENOTEMPTY;
+               else
+                       error = EINVAL;
            }
        }
 
@@ -854,6 +867,9 @@ naccess(struct nchandle *nch, int nflags, struct ucred *cred, int *nflagsp)
                case VCHR:
                case VBLK:
                    break;
+               case VDIR:
+                   error = EISDIR;
+                   break;
                default:
                    error = EINVAL;
                    break;
@@ -943,6 +959,7 @@ naccess_va(struct vattr *va, int nflags, struct ucred *cred)
        if (nflags & (NLC_WRITE | NLC_TRUNCATE)) {
            switch(va->va_type) {
            case VDIR:
+               return (EISDIR);
            case VLNK:
            case VREG:
            case VDATABASE:
index 4bdf933..89c30f8 100644 (file)
@@ -134,6 +134,12 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
        int error;
 
        /*
+        * Certain combinations are illegal
+        */
+       if ((fmode & (FWRITE | O_TRUNC)) == O_TRUNC)
+               return(EACCES);
+
+       /*
         * Lookup the path and create or obtain the vnode.  After a
         * successful lookup a locked nd->nl_nch will be returned.
         *
@@ -151,6 +157,8 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
                nd->nl_flags |= NLC_READ;
        if (fmode & FWRITE)
                nd->nl_flags |= NLC_WRITE;
+       if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
+               nd->nl_flags |= NLC_FOLLOW;
 
        if (fmode & O_CREAT) {
                /*
@@ -163,8 +171,6 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
                 * write permission on the governing directory or EPERM
                 * is returned.
                 */
-               if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
-                       nd->nl_flags |= NLC_FOLLOW;
                nd->nl_flags |= NLC_CREATE;
                nd->nl_flags |= NLC_REFDVP;
                bwillinode(1);