MFC: fstest regression fixes - POSIX error codes.
authorSimon 'corecode' Schubert <corecode@fs.ei.tum.de>
Wed, 15 Jul 2009 14:04:42 +0000 (16:04 +0200)
committerSimon 'corecode' Schubert <corecode@fs.ei.tum.de>
Wed, 15 Jul 2009 14:11:42 +0000 (16:11 +0200)
Partial MFC of d7c75c7a20590cab729c3d653aaa91a4960d6165:

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 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 MFC'd:
    * Return EISDIR if an attempt is made to open a directory for writing,
      instead of EINVAL.

This is required so that /usr/bin/tar can extract to an existing
directory:

tar cf - . | (cd otherdir && tar xof -)

failed before (breaking nrelease).

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

index 0ea69e5..daa9c66 100644 (file)
@@ -249,6 +249,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 3efa97f..aef474f 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
@@ -420,7 +425,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) {
@@ -473,7 +478,15 @@ nlookup(struct nlookupdata *nd)
            }
            if (error == 0 && wasdotordotdot &&
                (nd->nl_flags & (NLC_CREATE | NLC_RENAME | NLC_DELETE))) {
-               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;
            }
        }
 
index d0ab7c8..cf40df2 100644 (file)
@@ -134,6 +134,12 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
        int mode, 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.
         *
@@ -142,6 +148,10 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
         * XXX with only a little work we should be able to avoid locking
         * the vnode if FWRITE, O_CREAT, and O_TRUNC are *not* set.
         */
+
+       if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
+               nd->nl_flags |= NLC_FOLLOW;
+
        if (fmode & O_CREAT) {
                /*
                 * CONDITIONAL CREATE FILE CASE
@@ -153,8 +163,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);