From: Simon 'corecode' Schubert Date: Wed, 15 Jul 2009 14:04:42 +0000 (+0200) Subject: MFC: fstest regression fixes - POSIX error codes. X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/fa8302b1b7803a0621c8975e38e763f1c3aeae8d MFC: fstest regression fixes - POSIX error codes. 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). --- diff --git a/sys/kern/vfs_helper.c b/sys/kern/vfs_helper.c index 0ea69e52ca..daa9c66e0b 100644 --- a/sys/kern/vfs_helper.c +++ b/sys/kern/vfs_helper.c @@ -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); diff --git a/sys/kern/vfs_nlookup.c b/sys/kern/vfs_nlookup.c index 3efa97f257..aef474f429 100644 --- a/sys/kern/vfs_nlookup.c +++ b/sys/kern/vfs_nlookup.c @@ -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; } } diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index d0ab7c8654..cf40df2b16 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -133,6 +133,12 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) struct vattr *vap = &vat; 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);