Пример #1
0
int
smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
	struct smb_cred *scred)
{
	int error = 0;
	size_t len, tsize, resid;
	int wx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX);

	resid = 0;	/* XXX gcc */

	tsize = uio->uio_resid;
	while (tsize > 0) {
		len = tsize;
		if (wx)
		    error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred);
		else
		    error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
		if (error)
			break;
		if (resid < len) {
			error = EIO;
			break;
		}
		tsize -= resid;
	}
	return error;
}
Пример #2
0
int
smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
	struct smb_cred *scred)
{
	size_t tsize, len, resid;
	int error = 0;
	int rx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX);

	resid = 0;	/* XXX gcc */

	tsize = uio->uio_resid;
	while (tsize > 0) {
		len = tsize;
		if (rx)
		    error = smb_smb_readx(ssp, fid, &len, &resid, uio, scred);
		else
		    error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
		if (error)
			break;
		tsize -= resid;
		if (resid < len)
			break;
	}
	return error;
}
Пример #3
0
int
smbfs_smb_setfsize(struct smbnode *np, u_quad_t newsize,
		   struct smb_cred *scred)
{
	struct smb_share *ssp = np->n_mount->sm_share;
	struct smb_rq *rqp;
	struct mbchain *mbp;
	int error;

	if (newsize >= (1LL << 32)) {
		if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES))
			return EFBIG;
		return smbfs_smb_seteof(np, (int64_t)newsize, scred);
	}

	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
	if (error)
		return error;
	smb_rq_getrequest(rqp, &mbp);
	smb_rq_wstart(rqp);
	mb_put_mem(mbp, (void *)&np->n_fid, 2, MB_MSYSTEM);
	mb_put_uint16le(mbp, 0);
	mb_put_uint32le(mbp, newsize);
	mb_put_uint16le(mbp, 0);
	smb_rq_wend(rqp);
	smb_rq_bstart(rqp);
	mb_put_uint8(mbp, SMB_DT_DATA);
	mb_put_uint16le(mbp, 0);
	smb_rq_bend(rqp);
	error = smb_rq_simple(rqp);
	smb_rq_done(rqp);
	return error;
}
Пример #4
0
/*
 * NT level. Specially for win9x
 */
int
smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
	struct timespec *atime, struct smb_cred *scred)
{
	struct smb_t2rq *t2p;
	struct smb_share *ssp = np->n_mount->sm_share;
	struct smb_vc *vcp = SSTOVC(ssp);
	struct mbchain *mbp;
	int64_t tm;
	int error, tzoff;

	/*
	 * SMB_SET_FILE_BASIC_INFO isn't supported for
	 * SMB_TRANS2_SET_PATH_INFORMATION,
	 * so use SMB_SET_FILE_BASIC_INFORMATION instead,
	 * but it requires SMB_CAP_INFOLEVEL_PASSTHRU capability.
	 */
	if ((SMB_CAPS(vcp) & SMB_CAP_INFOLEVEL_PASSTHRU) == 0)
		return smbfs_smb_setptime2(np, mtime, atime, attr, scred);

	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
	    scred, &t2p);
	if (error)
		return error;
	mbp = &t2p->t2_tparam;
	mb_init(mbp);
	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFORMATION);
	mb_put_uint32le(mbp, 0);		/* MBZ */
	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
	if (error) {
		smb_t2_done(t2p);
		return error;
	}
	tzoff = vcp->vc_sopt.sv_tz;
	mbp = &t2p->t2_tdata;
	mb_init(mbp);
	mb_put_int64le(mbp, 0);		/* creation time */
	if (atime) {
		smb_time_local2NT(atime, tzoff, &tm);
	} else
		tm = 0;
	mb_put_int64le(mbp, tm);
	if (mtime) {
		smb_time_local2NT(mtime, tzoff, &tm);
	} else
		tm = 0;
	mb_put_int64le(mbp, tm);
	mb_put_int64le(mbp, tm);		/* change time */
	mb_put_uint32le(mbp, attr);		/* attr */
	mb_put_uint32le(mbp, 0);		/* padding */
	t2p->t2_maxpcount = 2;
	t2p->t2_maxdcount = 0;
	error = smb_t2_request(t2p);
	smb_t2_done(t2p);
	return error;
}
Пример #5
0
static u_int32_t
smb_vc_maxwrite(struct smb_vc *vcp)
{
	/*
	 * Specs say up to 64k data bytes, but Windows traffic
	 * uses 60k... probably for some good reason.
	 */
	if (SMB_CAPS(vcp) & SMB_CAP_LARGE_WRITEX)
		return (60*1024);
	else
		return (vcp->vc_sopt.sv_maxtx);
}
Пример #6
0
static u_int32_t
smb_vc_maxread(struct smb_vc *vcp)
{
	/*
	 * Specs say up to 64k data bytes, but Windows traffic
	 * uses 60k... no doubt for some good reason.
	 */
	if (SMB_CAPS(vcp) & SMB_CAP_LARGE_READX)
		return (60*1024);
	else
		return (vcp->vc_sopt.sv_maxtx);
}
Пример #7
0
/*
 * Close called.
 */
int
smbfs_close(void *v)
{
	struct vop_close_args /* {
		struct vnodeop_desc *a_desc;
		struct vnode *a_vp;
		int  a_fflag;
		kauth_cred_t a_cred;
	} */ *ap = v;
	int error;
	struct lwp *l = curlwp;
	struct vnode *vp = ap->a_vp;
	struct smbnode *np = VTOSMB(vp);

	/* Flush all file data */
	error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, l, 1);
	if (error)
		return (error);

	/*
	 * We must close the directory lookup context now, so that
	 * later directory changes would be properly detected.
	 * Ideally, the lookup routines should handle such case, and
	 * the context would be removed only in smbfs_inactive().
	 */
	if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0) {
		struct smb_share *ssp = np->n_mount->sm_share;
		struct smb_cred scred;

		smb_makescred(&scred, l, ap->a_cred);

		if (np->n_dirseq != NULL) {
			smbfs_findclose(np->n_dirseq, &scred);
			np->n_dirseq = NULL;
		}

		if (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_NT_SMBS)
			smbfs_smb_close(ssp, np->n_fid, &np->n_mtime, &scred);

		np->n_flag &= ~NOPEN;
		smbfs_attr_cacheremove(vp);
	}

	return (0);
}
Пример #8
0
int
smbfs_setattr(void *v)
{
	struct vop_setattr_args /* {
		struct vnode *a_vp;
		struct vattr *a_vap;
		kauth_cred_t a_cred;
	} */ *ap = v;
	struct lwp *l = curlwp;
	struct vnode *vp = ap->a_vp;
	struct smbnode *np = VTOSMB(vp);
	struct vattr *vap = ap->a_vap;
	struct timespec *mtime, *atime;
	struct smb_cred scred;
	struct smb_share *ssp = np->n_mount->sm_share;
	struct smb_vc *vcp = SSTOVC(ssp);
	u_quad_t tsize = 0;
	int isreadonly, doclose, error = 0;

	SMBVDEBUG0("\n");
	if (vap->va_flags != VNOVAL)
		return EOPNOTSUPP;
	isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY);
	/*
	 * Disallow write attempts if the filesystem is mounted read-only.
	 */
  	if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL ||
	     vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
	     vap->va_mode != (mode_t)VNOVAL) && isreadonly)
		return EROFS;
	smb_makescred(&scred, l, ap->a_cred);
	if (vap->va_size != VNOVAL) {
 		switch (vp->v_type) {
 		case VDIR:
 			return EISDIR;
 		case VREG:
			break;
 		default:
			return EINVAL;
  		};
		if (isreadonly)
			return EROFS;
		doclose = 0;
 		tsize = np->n_size;
 		np->n_size = vap->va_size;
		uvm_vnp_setsize(vp, vap->va_size);
		if ((np->n_flag & NOPEN) == 0) {
			error = smbfs_smb_open(np,
			    SMB_SM_DENYNONE|SMB_AM_OPENRW, &scred);
			if (error == 0)
				doclose = 1;
		}
		if (error == 0)
			error = smbfs_smb_setfsize(np, vap->va_size, &scred);
		if (doclose)
			smbfs_smb_close(ssp, np->n_fid, NULL, &scred);
		if (error) {
			np->n_size = tsize;
			uvm_vnp_setsize(vp, tsize);
			return (error);
		}
  	}
	mtime = atime = NULL;
	if (vap->va_mtime.tv_sec != VNOVAL)
		mtime = &vap->va_mtime;
	if (vap->va_atime.tv_sec != VNOVAL)
		atime = &vap->va_atime;
	if (mtime != atime) {
		error = kauth_authorize_vnode(ap->a_cred,
		    KAUTH_VNODE_WRITE_TIMES, ap->a_vp, NULL,
		    genfs_can_chtimes(ap->a_vp, vap->va_vaflags,
		    VTOSMBFS(vp)->sm_args.uid, ap->a_cred));
		if (error)
			return (error);

#if 0
		if (mtime == NULL)
			mtime = &np->n_mtime;
		if (atime == NULL)
			atime = &np->n_atime;
#endif
		/*
		 * If file is opened, then we can use handle based calls.
		 * If not, use path based ones.
		 */
		if ((np->n_flag & NOPEN) == 0) {
			if (vcp->vc_flags & SMBV_WIN95) {
				error = VOP_OPEN(vp, FWRITE, ap->a_cred);
				if (!error) {
/*				error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
				VOP_GETATTR(vp, &vattr, ap->a_cred);*/
				if (mtime)
					np->n_mtime = *mtime;
				VOP_CLOSE(vp, FWRITE, ap->a_cred);
				}
			} else if (SMB_CAPS(vcp) & SMB_CAP_NT_SMBS) {
				error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);
			} else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) {
				error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred);
			} else {
				error = smbfs_smb_setpattr(np, 0, mtime, &scred);
			}
		} else {
			if (SMB_CAPS(vcp) & SMB_CAP_NT_SMBS) {
				error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
			} else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
				error = smbfs_smb_setftime(np, mtime, atime, &scred);
			} else {
				/*
				 * XXX I have no idea how to handle this for core
				 * level servers. The possible solution is to
				 * update mtime after file is closed.
				 */
			}
		}
	}
	/*
	 * Invalidate attribute cache in case if server doesn't set
	 * required attributes.
	 */
	smbfs_attr_cacheremove(vp);	/* invalidate cache */
	VOP_GETATTR(vp, vap, ap->a_cred);
	np->n_mtime.tv_sec = vap->va_mtime.tv_sec;
	VN_KNOTE(vp, NOTE_ATTRIB);
	return error;
}
Пример #9
0
/* ARGSUSED */
int
smbfs_open(void *v)
{
	struct vop_open_args /* {
		struct vnode *a_vp;
		int  a_mode;
		kauth_cred_t a_cred;
	} */ *ap = v;
	struct lwp *l = curlwp;
	struct vnode *vp = ap->a_vp;
	struct smbnode *np = VTOSMB(vp);
	struct smb_cred scred;
	struct vattr vattr;
	u_int32_t sv_caps = SMB_CAPS(SSTOVC(np->n_mount->sm_share));
	int error, accmode;

	SMBVDEBUG("%.*s,%d\n", (int) np->n_nmlen, np->n_name,
	    (np->n_flag & NOPEN) != 0);
	if (vp->v_type != VREG && vp->v_type != VDIR) {
		SMBFSERR("open eacces vtype=%d\n", vp->v_type);
		return EACCES;
	}
	if (vp->v_type == VDIR) {
		if ((sv_caps & SMB_CAP_NT_SMBS) == 0) {
			np->n_flag |= NOPEN;
			return 0;
		}
		goto do_open;	/* skip 'modified' check */
	}

	if (np->n_flag & NMODIFIED) {
		if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, l, 1)) == EINTR)
			return error;
		smbfs_attr_cacheremove(vp);
		error = VOP_GETATTR(vp, &vattr, ap->a_cred);
		if (error)
			return error;
		np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
	} else {
		error = VOP_GETATTR(vp, &vattr, ap->a_cred);
		if (error)
			return error;
		if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
			error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, l, 1);
			if (error == EINTR)
				return error;
			np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
		}
	}

do_open:
	if ((np->n_flag & NOPEN) != 0)
		return 0;

	smb_makescred(&scred, l, ap->a_cred);
	if (vp->v_type == VDIR)
		error = smbfs_smb_ntcreatex(np,
		    SMB_SM_DENYNONE|SMB_AM_OPENREAD, &scred);
	else {
		/*
		 * Use DENYNONE to give unixy semantics of permitting
		 * everything not forbidden by permissions.  Ie denial
		 * is up to server with clients/openers needing to use
		 * advisory locks for further control.
		 */
		accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD;
		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
			accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW;
		error = smbfs_smb_open(np, accmode, &scred);
		if (error) {
			if (ap->a_mode & FWRITE)
				return EACCES;

			error = smbfs_smb_open(np,
			    SMB_SM_DENYNONE|SMB_AM_OPENREAD, &scred);
		}
	}
	if (!error)
		np->n_flag |= NOPEN;
	smbfs_attr_cacheremove(vp);
	return error;
}