diff options
Diffstat (limited to 'usr/src/uts/common/fs/vnode.c')
-rw-r--r-- | usr/src/uts/common/fs/vnode.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c index e16dbbbc8d..9e0b071999 100644 --- a/usr/src/uts/common/fs/vnode.c +++ b/usr/src/uts/common/fs/vnode.c @@ -972,6 +972,7 @@ vn_openat( int estale_retry = 0; struct shrlock shr; struct shr_locowner shr_own; + boolean_t create; mode = 0; accessflags = 0; @@ -991,8 +992,31 @@ vn_openat( if (filemode & FAPPEND) accessflags |= V_APPEND; + /* + * We need to handle the case of FCREAT | FDIRECTORY and the case of + * FEXCL. If all three are specified, then we always fail because we + * cannot create a directory through this interface and FEXCL says we + * need to fail the request if we can't create it. If, however, only + * FCREAT | FDIRECTORY are specified, then we can treat this as the case + * of opening a file that already exists. If it exists, we can do + * something and if not, we fail. Effectively FCREAT | FDIRECTORY is + * treated as FDIRECTORY. + */ + if ((filemode & (FCREAT | FDIRECTORY | FEXCL)) == + (FCREAT | FDIRECTORY | FEXCL)) { + return (EINVAL); + } + + if ((filemode & (FCREAT | FDIRECTORY)) == (FCREAT | FDIRECTORY)) { + create = B_FALSE; + } else if ((filemode & FCREAT) != 0) { + create = B_TRUE; + } else { + create = B_FALSE; + } + top: - if (filemode & FCREAT) { + if (create) { enum vcexcl excl; /* @@ -1089,11 +1113,13 @@ top: */ if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL)) goto out; + /* - * Require FSEARCH to return a directory. - * Require FEXEC to return a regular file. + * Require FSEARCH and FDIRECTORY to return a directory. Require + * FEXEC to return a regular file. */ - if ((filemode & FSEARCH) && vp->v_type != VDIR) { + if ((filemode & (FSEARCH|FDIRECTORY)) != 0 && + vp->v_type != VDIR) { error = ENOTDIR; goto out; } |