#include <sys/types.h>
#include <sys/param.h>
#include <sys/t_lock.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <sys/user.h>
#include <sys/uio.h>
#include <sys/file.h>
#include <sys/pathname.h>
#include <sys/vfs.h>
#include <sys/vfs_opreg.h>
#include <sys/vnode.h>
#include <sys/rwstlock.h>
#include <sys/fem.h>
#include <sys/stat.h>
#include <sys/mode.h>
#include <sys/conf.h>
#include <sys/sysmacros.h>
#include <sys/cmn_err.h>
#include <sys/systm.h>
#include <sys/kmem.h>
#include <sys/debug.h>
#include <sys/acl.h>
#include <sys/nbmlock.h>
#include <sys/fcntl.h>
#include <fs/fs_subr.h>
#include <sys/taskq.h>
#include <fs/fs_reparse.h>
#include <sys/time.h>
#include <libfksmbfs.h>
int
vn_close_rele(vnode_t *vp, int flag)
{
int error;
error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
vn_rele(vp);
return (error);
}
int
vn_open(
char *pnamep,
enum uio_seg seg,
int filemode,
int createmode,
struct vnode **vpp,
enum create crwhy,
mode_t umask)
{
struct vnode *vp;
int mode;
int accessflags;
int error;
int open_done = 0;
struct vattr vattr;
int estale_retry = 0;
mode = 0;
accessflags = 0;
if (filemode & FREAD)
mode |= VREAD;
if (filemode & (FWRITE|FTRUNC))
mode |= VWRITE;
if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
mode |= VEXEC;
if (filemode & FAPPEND)
accessflags |= V_APPEND;
top:
if (filemode & FCREAT) {
enum vcexcl excl;
vattr.va_type = VREG;
vattr.va_mode = createmode;
vattr.va_mask = AT_TYPE|AT_MODE;
if (filemode & FTRUNC) {
vattr.va_size = 0;
vattr.va_mask |= AT_SIZE;
}
if (filemode & FEXCL)
excl = EXCL;
else
excl = NONEXCL;
if ((error =
vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
(filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
return (error);
} else {
if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
if ((error == ESTALE) &&
fs_need_estale_retry(estale_retry++))
goto top;
return (error);
}
if (filemode & FXATTRDIROPEN) {
vnode_t *xvp = NULL;
error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
LOOKUP_XATTR, rootdir, CRED(), NULL,
NULL, NULL);
VN_RELE(vp);
vp = xvp;
}
if (filemode & (FWRITE|FTRUNC)) {
if (vp->v_type == VDIR) {
error = EISDIR;
goto out;
}
}
if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
goto out;
if ((filemode & FSEARCH) && vp->v_type != VDIR) {
error = ENOTDIR;
goto out;
}
if ((filemode & FEXEC) && vp->v_type != VREG) {
error = ENOEXEC;
goto out;
}
}
if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
error = ELOOP;
goto out;
}
if (filemode & FNOLINKS) {
vattr.va_mask = AT_NLINK;
if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
goto out;
}
if (vattr.va_nlink != 1) {
error = EMLINK;
goto out;
}
}
if (vp->v_type == VSOCK) {
error = EOPNOTSUPP;
goto out;
}
error = VOP_OPEN(&vp, filemode, CRED(), NULL);
if (error)
goto out;
open_done = 1;
if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
vattr.va_size = 0;
vattr.va_mask = AT_SIZE;
if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
goto out;
}
out:
ASSERT(vp->v_count > 0);
if (error) {
if (open_done) {
(void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
NULL);
open_done = 0;
}
VN_RELE(vp);
} else
*vpp = vp;
return (error);
}
int
vn_create(
char *pnamep,
enum uio_seg seg,
struct vattr *vap,
enum vcexcl excl,
int mode,
struct vnode **vpp,
enum create why,
int flag,
mode_t umask)
{
struct vnode *dvp = NULL;
char *lastcomp = NULL;
int error;
ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
flag &= ~(FNOFOLLOW|FNOLINKS);
*vpp = NULL;
error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
if (error != 0) {
return (error);
}
if (umask) {
vap->va_mode &= ~umask;
}
if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
error = EROFS;
goto out;
}
if (why == CRMKDIR) {
error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
NULL, 0, NULL);
} else {
error = VOP_CREATE(dvp, lastcomp, vap,
excl, mode, vpp, CRED(), flag, NULL, NULL);
}
out:
if (dvp != NULL)
VN_RELE(dvp);
return (error);
}