Esempio n. 1
0
static int
smb_t2_reply(struct smb_t2rq *t2p)
{
	struct mdchain *mdp;
	struct smb_rq *rqp = t2p->t2_rq;
	int error, totpgot, totdgot;
	u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
	u_int16_t tmp, bc, dcount;
	u_int8_t wc;

	error = smb_rq_reply(rqp);
	if (error)
		return error;
	if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
		/* 
		 * this is an interim response, ignore it.
		 */
		SMBRQ_SLOCK(rqp);
		md_next_record(&rqp->sr_rp);
		SMBRQ_SUNLOCK(rqp);
		return 0;
	}
	/*
	 * Now we have to get all subsequent responses. The CIFS specification
	 * says that they can be disordered which is weird.
	 * TODO: timo
	 */
	totpgot = totdgot = 0;
	totpcount = totdcount = 0xffff;
	mdp = &rqp->sr_rp;
	for (;;) {
		m_dumpm(mdp->md_top);
		if ((error = md_get_uint8(mdp, &wc)) != 0)
			break;
		if (wc < 10) {
			error = ENOENT;
			break;
		}
		if ((error = md_get_uint16le(mdp, &tmp)) != 0)
			break;
		if (totpcount > tmp)
			totpcount = tmp;
		md_get_uint16le(mdp, &tmp);
		if (totdcount > tmp)
			totdcount = tmp;
		if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
		    (error = md_get_uint16le(mdp, &pcount)) != 0 ||
		    (error = md_get_uint16le(mdp, &poff)) != 0 ||
		    (error = md_get_uint16le(mdp, &pdisp)) != 0)
			break;
		if (pcount != 0 && pdisp != totpgot) {
			SMBERROR("Can't handle disordered parameters %d:%d\n",
			    pdisp, totpgot);
			error = EINVAL;
			break;
		}
		if ((error = md_get_uint16le(mdp, &dcount)) != 0 ||
		    (error = md_get_uint16le(mdp, &doff)) != 0 ||
		    (error = md_get_uint16le(mdp, &ddisp)) != 0)
			break;
		if (dcount != 0 && ddisp != totdgot) {
			SMBERROR("Can't handle disordered data\n");
			error = EINVAL;
			break;
		}
		md_get_uint8(mdp, &wc);
		md_get_uint8(mdp, NULL);
		tmp = wc;
		while (tmp--)
			md_get_uint16(mdp, NULL);
		if ((error = md_get_uint16le(mdp, &bc)) != 0)
			break;
/*		tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
		if (dcount) {
			error = smb_t2_placedata(mdp->md_top, doff, dcount,
			    &t2p->t2_rdata);
			if (error)
				break;
		}
		if (pcount) {
			error = smb_t2_placedata(mdp->md_top, poff, pcount,
			    &t2p->t2_rparam);
			if (error)
				break;
		}
		totpgot += pcount;
		totdgot += dcount;
		if (totpgot >= totpcount && totdgot >= totdcount) {
			error = 0;
			t2p->t2_flags |= SMBT2_ALLRECV;
			break;
		}
		/*
		 * We're done with this reply, look for the next one.
		 */
		SMBRQ_SLOCK(rqp);
		md_next_record(&rqp->sr_rp);
		SMBRQ_SUNLOCK(rqp);
		error = smb_rq_reply(rqp);
		if (error)
			break;
	}
	return error;
}
Esempio n. 2
0
int
smbfs_smb_nt_dirnotify_fetch(struct smb_rq *rqp, int *hint)
{
	int error;
	struct mdchain *mdp;
	u_int8_t sc;
	u_int32_t nextentry;

	error = smb_rq_reply(rqp);
	if (error) {
		/*
		 * If we get EMSGSIZE, there is already too many notifications
		 * available for the directory, and the internal buffer
		 * overflew. Just flag any possible relevant change.
		 */
		if (error == EMSGSIZE) {
			*hint = NOTE_ATTRIB | NOTE_WRITE;
			error = 0;
		}

		goto bad;
	}

	smb_rq_getreply(rqp, &mdp);

	/* Parse reply */
	error = md_get_mem(mdp, NULL, 4 + (8*4), MB_MZERO);	/* skip */
	if (error)
		goto bad;

	md_get_uint8(mdp, &sc);			/* SetupCount */
	if (sc > 0)
		md_get_mem(mdp, NULL, sc * sizeof(u_int16_t), MB_MZERO);
	md_get_uint16(mdp, NULL);		/* ByteCount */
	md_get_mem(mdp, NULL, 1 + (sc % 2) * 2, MB_MZERO);	/* Pad */

	/*
	 * The notify data are blocks of
	 *   ULONG nextentry - offset of next entry from start of this one
	 *   ULONG action - type of notification
	 *   ULONG filenamelen - length of filename in bytes
	 *   WCHAR filename[filenamelen/2] - Unicode filename
	 * nexentry == 0 means last notification, filename is in 16bit LE
	 * unicode
	 */
	*hint = 0;
	do {
		u_int32_t action;
#if 0
		u_int32_t fnlen;
		u_int16_t fnc;
#endif

		md_get_uint32le(mdp, &nextentry);
		md_get_uint32le(mdp, &action);
		if (nextentry)
			md_get_mem(mdp, NULL, nextentry - 2 * 4, MB_MZERO);
#if 0
		md_get_uint32le(mdp, &fnlen);

		printf("notify: next %u act %u fnlen %u fname '",
			nextentry, action, fnlen);
		for(; fnlen > 0; fnlen -= 2) {
			md_get_uint16le(mdp, &fnc);
			printf("%c", fnc&0xff);
		}
		printf("'\n");
#endif

		switch(action) {
		case FILE_ACTION_ADDED:
		case FILE_ACTION_REMOVED:
		case FILE_ACTION_RENAMED_OLD_NAME:
		case FILE_ACTION_RENAMED_NEW_NAME:
			*hint |= NOTE_ATTRIB | NOTE_WRITE;
			break;

		case FILE_ACTION_MODIFIED:
			*hint |= NOTE_ATTRIB;
			break;
		}
	} while(nextentry > 0);

bad:
	smb_rq_done(rqp);
	return error;
}