+ if (fmode & FCREAT) {
+ ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
+ if ((fmode & FEXCL) == 0)
+ ndp->ni_nameiop |= FOLLOW;
+ if (error = namei(ndp))
+ return (error);
+ if (ndp->ni_vp == NULL) {
+ VATTR_NULL(vap);
+ vap->va_type = VREG;
+ vap->va_mode = cmode;
+ if (error = VOP_CREATE(ndp, vap))
+ return (error);
+ fmode &= ~FTRUNC;
+ vp = ndp->ni_vp;
+ } else {
+ if (ndp->ni_dvp == ndp->ni_vp)
+ vrele(ndp->ni_dvp);
+ else
+ vput(ndp->ni_dvp);
+ ndp->ni_dvp = NULL;
+ vp = ndp->ni_vp;
+ if (fmode & FEXCL) {
+ error = EEXIST;
+ goto bad;
+ }
+ fmode &= ~FCREAT;
+ }
+ } else {
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ if (error = namei(ndp))
+ return (error);
+ vp = ndp->ni_vp;
+ }
+ if (vp->v_type == VSOCK) {
+ error = EOPNOTSUPP;
+ goto bad;
+ }
+ if ((fmode & FCREAT) == 0) {
+ if (fmode & FREAD) {
+ if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred))
+ goto bad;
+ }
+ if (fmode & (FWRITE|FTRUNC)) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto bad;
+ }
+ if ((error = vn_writechk(vp)) ||
+ (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
+ goto bad;
+ }