+ if (fmode & O_CREAT) {
+ ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
+ if ((fmode & O_EXCL) == 0)
+ ndp->ni_nameiop |= FOLLOW;
+ if (error = namei(ndp, p))
+ return (error);
+ if (ndp->ni_vp == NULL) {
+ VATTR_NULL(vap);
+ vap->va_type = VREG;
+ vap->va_mode = cmode;
+ if (error = VOP_CREATE(ndp, vap, p))
+ return (error);
+ fmode &= ~O_TRUNC;
+ vp = ndp->ni_vp;
+ } else {
+ VOP_ABORTOP(ndp);
+ 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 & O_EXCL) {
+ error = EEXIST;
+ goto bad;
+ }
+ fmode &= ~O_CREAT;
+ }
+ } else {
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ if (error = namei(ndp, p))
+ return (error);
+ vp = ndp->ni_vp;
+ }
+ if (vp->v_type == VSOCK) {
+ error = EOPNOTSUPP;
+ goto bad;
+ }
+ if ((fmode & O_CREAT) == 0) {
+ if (fmode & FREAD) {
+ if (error = VOP_ACCESS(vp, VREAD, cred, p))
+ goto bad;
+ }
+ if (fmode & (FWRITE | O_TRUNC)) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto bad;
+ }
+ if ((error = vn_writechk(vp)) ||
+ (error = VOP_ACCESS(vp, VWRITE, cred, p)))
+ goto bad;
+ }
+ }
+ if (fmode & O_TRUNC) {
+ VATTR_NULL(vap);
+ vap->va_size = 0;
+ if (error = VOP_SETATTR(vp, vap, cred, p))
+ goto bad;