Esempio n. 1
0
static int
smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
{
	struct smb_share *ssp = np->n_mount->sm_share;
	struct smb_rq *rqp;
	struct mbchain *mbp;
	int error;

	if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
	    SMBTOV(np)->v_type != VREG)
		return 0; /* not a regular open file */
	rqp = malloc(sizeof(struct smb_rq), M_SMBFSDATA, M_WAITOK);
	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
	if (error) {
		free(rqp, M_SMBFSDATA);
		return (error);
	}
	smb_rq_getrequest(rqp, &mbp);
	smb_rq_wstart(rqp);
	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);
	smb_rq_bend(rqp);
	error = smb_rq_simple(rqp);
	smb_rq_done(rqp);
	free(rqp, M_SMBFSDATA);
	if (!error)
		np->n_flag &= ~NFLUSHWIRE;
	return (error);
}
Esempio n. 2
0
/*
 * Return locked root vnode of a filesystem.
 */
int
smbfs_root(struct mount *mp, struct vnode **vpp)
{
	struct smbmount *smp = VFSTOSMBFS(mp);

	if (__predict_false(!smp->sm_root)) {
		int error = smbfs_setroot(mp);
		if (error)
			return (error);
		/* fallthrough */
	}

	KASSERT(smp->sm_root != NULL && SMBTOV(smp->sm_root) != NULL);
	*vpp = SMBTOV(smp->sm_root);
	return vget(*vpp, LK_EXCLUSIVE | LK_RETRY);
}
Esempio n. 3
0
/*
 * find root of smbfs
 */
static int
smbfs_root(vfs_t *vfsp, vnode_t **vpp)
{
	smbmntinfo_t	*smi;
	vnode_t		*vp;

	smi = VFTOSMI(vfsp);

	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
		return (EPERM);

	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
		return (EIO);

	/*
	 * The root vp is created in mount and held
	 * until unmount, so this is paranoia.
	 */
	if (smi->smi_root == NULL)
		return (EIO);

	/* Just take a reference and return it. */
	vp = SMBTOV(smi->smi_root);
	VN_HOLD(vp);
	*vpp = vp;

	return (0);
}
Esempio n. 4
0
static int
smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
	const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp)
{
	struct thread *td = curthread;	/* XXX */
	struct smbmount *smp = VFSTOSMBFS(mp);
	struct smbnode_hashhead *nhpp;
	struct smbnode *np, *np2, *dnp;
	struct vnode *vp;
	u_long hashval;
	int error;

	*vpp = NULL;
	if (smp->sm_root != NULL && dvp == NULL) {
		SMBERROR("do not allocate root vnode twice!\n");
		return EINVAL;
	}
	if (nmlen == 2 && bcmp(name, "..", 2) == 0) {
		if (dvp == NULL)
			return EINVAL;
		vp = VTOSMB(dvp)->n_parent->n_vnode;
		error = vget(vp, LK_EXCLUSIVE, td);
		if (error == 0)
			*vpp = vp;
		return error;
	} else if (nmlen == 1 && name[0] == '.') {
		SMBERROR("do not call me with dot!\n");
		return EINVAL;
	}
	dnp = dvp ? VTOSMB(dvp) : NULL;
	if (dnp == NULL && dvp != NULL) {
		vprint("smbfs_node_alloc: dead parent vnode", dvp);
		return EINVAL;
	}
	hashval = smbfs_hash(name, nmlen);
retry:
	smbfs_hash_lock(smp, td);
loop:
	nhpp = SMBFS_NOHASH(smp, hashval);
	LIST_FOREACH(np, nhpp, n_hash) {
		vp = SMBTOV(np);
		if (np->n_parent != dnp ||
		    np->n_nmlen != nmlen || bcmp(name, np->n_name, nmlen) != 0)
			continue;
		VI_LOCK(vp);
		smbfs_hash_unlock(smp, td);
		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0)
			goto retry;
		*vpp = vp;
		return 0;
	}
Esempio n. 5
0
int
smbfs_hashprint(struct mount *mp)
{
	struct smbmount *smp = VFSTOSMBFS(mp);
	struct smbnode_hashhead *nhpp;
	struct smbnode *np;
	int i;

	for(i = 0; i <= smp->sm_hashlen; i++) {
		nhpp = &smp->sm_hash[i];
		LIST_FOREACH(np, nhpp, n_hash)
			vprint(NULL, SMBTOV(np));
	}
	return 0;
}
Esempio n. 6
0
/* Unmount the filesystem described by mp. */
int
smbfs_unmount(struct mount *mp, int mntflags)
{
	struct lwp *l = curlwp;
	struct smbmount *smp = VFSTOSMBFS(mp);
	struct smb_cred scred;
	struct vnode *smbfs_rootvp = SMBTOV(smp->sm_root);
	int error, flags;

	SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
	flags = 0;
	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	if (smbfs_rootvp->v_usecount > 1 && (mntflags & MNT_FORCE) == 0)
		return EBUSY;

	/* Flush all vnodes.
	 * Keep trying to flush the vnode list for the mount while 
	 * some are still busy and we are making progress towards
	 * making them not busy. This is needed because smbfs vnodes
	 * reference their parent directory but may appear after their
	 * parent in the list; one pass over the vnode list is not
	 * sufficient in this case. */
	do {
		smp->sm_didrele = 0;
		error = vflush(mp, smbfs_rootvp, flags);
	} while (error == EBUSY && smp->sm_didrele != 0);
	if (error)
		return error;

	vgone(smbfs_rootvp);

	smb_makescred(&scred, l, l->l_cred);
	smb_share_lock(smp->sm_share);
	smb_share_put(smp->sm_share, &scred);
	mp->mnt_data = NULL;

	hashdone(smp->sm_hash, HASH_LIST, smp->sm_hashlen);
	mutex_destroy(&smp->sm_hashlock);
	free(smp, M_SMBFSDATA);
	return 0;
}
Esempio n. 7
0
/* 
 * Return locked root vnode of a filesystem
 */
static int
smbfs_root(struct mount *mp, struct vnode **vpp)
{
	struct thread *td = curthread;	/* XXX */
	struct smbmount *smp = VFSTOSMBFS(mp);
	struct vnode *vp;
	struct smbnode *np;
	struct smbfattr fattr;
	struct ucred *cred;
	struct smb_cred scred;
	int error;

	if (smp == NULL) {
		SMBERROR("smp == NULL (bug in umount)\n");
		return EINVAL;
	}
	if (smp->sm_root) {
		*vpp = SMBTOV(smp->sm_root);
		return vget(*vpp, LK_EXCLUSIVE | LK_RETRY);
	}
	if (td->td_proc)
		cred = td->td_proc->p_ucred;
	else
		cred = proc0.p_ucred;

	smb_makescred(&scred, td, cred);
	error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
	if (error)
		return error;
	error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
	if (error)
		return error;
	vsetflags(vp, VROOT);
	np = VTOSMB(vp);
	smp->sm_root = np;
	*vpp = vp;
	return 0;
}
Esempio n. 8
0
/* 
 * Return locked root vnode of a filesystem
 */
static int
smbfs_root(struct mount *mp, int flags, struct vnode **vpp)
{
	struct smbmount *smp = VFSTOSMBFS(mp);
	struct vnode *vp;
	struct smbnode *np;
	struct smbfattr fattr;
	struct thread *td;
	struct ucred *cred;
	struct smb_cred *scred;
	int error;

	td = curthread;
	cred = td->td_ucred;

	if (smp->sm_root) {
		*vpp = SMBTOV(smp->sm_root);
		return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
	}
	scred = smbfs_malloc_scred();
	smb_makescred(scred, td, cred);
	error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, scred);
	if (error)
		goto out;
	error = smbfs_nget(mp, NULL, NULL, 0, &fattr, &vp);
	if (error)
		goto out;
	ASSERT_VOP_LOCKED(vp, "smbfs_root");
	vp->v_vflag |= VV_ROOT;
	np = VTOSMB(vp);
	smp->sm_root = np;
	*vpp = vp;
out:
	smbfs_free_scred(scred);
	return error;
}
Esempio n. 9
0
static int
smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
	const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp)
{
	struct vattr vattr;
	struct thread *td = curthread;	/* XXX */
	struct smbmount *smp = VFSTOSMBFS(mp);
	struct smbnode_hashhead *nhpp;
	struct smbnode *np, *np2, *dnp;
	struct vnode *vp;
	u_long hashval;
	int error;

	*vpp = NULL;
	if (smp->sm_root != NULL && dvp == NULL) {
		SMBERROR("do not allocate root vnode twice!\n");
		return EINVAL;
	}
	if (nmlen == 2 && bcmp(name, "..", 2) == 0) {
		if (dvp == NULL)
			return EINVAL;
		vp = VTOSMB(VTOSMB(dvp)->n_parent)->n_vnode;
		error = vget(vp, LK_EXCLUSIVE, td);
		if (error == 0)
			*vpp = vp;
		return error;
	} else if (nmlen == 1 && name[0] == '.') {
		SMBERROR("do not call me with dot!\n");
		return EINVAL;
	}
	dnp = dvp ? VTOSMB(dvp) : NULL;
	if (dnp == NULL && dvp != NULL) {
		vprint("smbfs_node_alloc: dead parent vnode", dvp);
		return EINVAL;
	}
	hashval = smbfs_hash(name, nmlen);
retry:
	smbfs_hash_lock(smp);
loop:
	nhpp = SMBFS_NOHASH(smp, hashval);
	LIST_FOREACH(np, nhpp, n_hash) {
		vp = SMBTOV(np);
		if (np->n_parent != dvp ||
		    np->n_nmlen != nmlen || bcmp(name, np->n_name, nmlen) != 0)
			continue;
		VI_LOCK(vp);
		smbfs_hash_unlock(smp);
		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0)
			goto retry;
		/* Force cached attributes to be refreshed if stale. */
		(void)VOP_GETATTR(vp, &vattr, td->td_ucred);
		/*
		 * If the file type on the server is inconsistent with
		 * what it was when we created the vnode, kill the
		 * bogus vnode now and fall through to the code below
		 * to create a new one with the right type.
		 */
		if ((vp->v_type == VDIR && (np->n_dosattr & SMB_FA_DIR) == 0) ||
		    (vp->v_type == VREG && (np->n_dosattr & SMB_FA_DIR) != 0)) {
			vgone(vp);
			vput(vp);
			break;
		}
		*vpp = vp;
		return 0;
	}
Esempio n. 10
0
/*
 * This call is used to fetch FID for directories. For normal files,
 * SMB_COM_OPEN is used.
 */
int
smbfs_smb_ntcreatex(struct smbnode *np, int accmode,
    struct smb_cred *scred)
{
	struct smb_rq *rqp;
	struct smb_share *ssp = np->n_mount->sm_share;
	struct mbchain *mbp;
	struct mdchain *mdp;
	int error;
	u_int8_t wc;
	u_int8_t *nmlen;
	u_int16_t flen;

	KASSERT(SMBTOV(np)->v_type == VDIR);

	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scred, &rqp);
	if (error)
		return error;
	smb_rq_getrequest(rqp, &mbp);
	smb_rq_wstart(rqp);
	mb_put_uint8(mbp, 0xff);	/* Secondary command; 0xFF = None */
	mb_put_uint8(mbp, 0);		/* Reserved (must be 0) */
	mb_put_uint16le(mbp, 0);	/* Off to next cmd WordCount */
	mb_put_uint8(mbp, 0);		/* Reserved (must be 0) */
	nmlen = mb_reserve(mbp, sizeof(u_int16_t));
					/* Length of Name[] in bytes */
	mb_put_uint32le(mbp, SMB_FL_CANONICAL_PATHNAMES);
					/* Flags - Create bit set */
	mb_put_uint32le(mbp, 0);	/* If nonzero, open relative to this */
	mb_put_uint32le(mbp, NT_FILE_LIST_DIRECTORY);	/* Access mask */
	mb_put_uint32le(mbp, 0);	/* Low 32bit */
	mb_put_uint32le(mbp, 0);	/* Hi 32bit */
					/* Initial allocation size */
	mb_put_uint32le(mbp, 0);	/* File attributes */
	mb_put_uint32le(mbp, NT_FILE_SHARE_READ|NT_FILE_SHARE_WRITE);
					/* Type of share access */
	mb_put_uint32le(mbp, NT_OPEN_EXISTING);
					/* Create disposition - just open */
	mb_put_uint32le(mbp, NT_FILE_DIRECTORY_FILE);
					/* Options to use if creating a file */
	mb_put_uint32le(mbp, 0);	/* Security QOS information */
	mb_put_uint8(mbp, 0);		/* Security tracking mode flags */
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);

	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
	if (error)
		return error;

	/* Windows XP seems to include the final zero. Better do that too. */
	mb_put_uint8(mbp, 0);

	flen = mbp->mb_count;
	SMBRQ_PUTLE16(nmlen, flen);

	smb_rq_bend(rqp);
	error = smb_rq_simple(rqp);
	if (error)
		goto bad;

	smb_rq_getreply(rqp, &mdp);
	md_get_uint8(mdp, &wc);		/* WordCount - check? */
	md_get_uint8(mdp, NULL);	/* AndXCommand */
	md_get_uint8(mdp, NULL);	/* Reserved - must be zero */
	md_get_uint16(mdp, NULL);	/* Offset to next cmd WordCount */
	md_get_uint8(mdp, NULL);	/* Oplock level granted */
	md_get_uint16(mdp, &np->n_fid);	/* FID */
	/* ignore rest */

bad:
	smb_rq_done(rqp);
	return (error);
}