Example #1
0
static int
smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
{
	struct mdchain *mbp;
	struct smb_t2rq *t2p;
	char *cp;
	u_int8_t tb;
	u_int16_t date, time, wattr;
	u_int32_t size, next, dattr;
	int64_t lint;
	int error, svtz, cnt, fxsz, nmlen, recsz;

	if (ctx->f_ecnt == 0) {
		if (ctx->f_flags & SMBFS_RDD_EOF)
			return ENOENT;
		ctx->f_left = ctx->f_limit = limit;
		error = smbfs_smb_trans2find2(ctx);
		if (error)
			return error;
	}
	t2p = ctx->f_t2;
	mbp = &t2p->t2_rdata;
	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
	switch (ctx->f_infolevel) {
	    case SMB_INFO_STANDARD:
		next = 0;
		fxsz = 0;
		md_get_uint16le(mbp, &date);
		md_get_uint16le(mbp, &time);	/* creation time */
		md_get_uint16le(mbp, &date);
		md_get_uint16le(mbp, &time);	/* access time */
		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
		md_get_uint16le(mbp, &date);
		md_get_uint16le(mbp, &time);	/* access time */
		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
		md_get_uint32le(mbp, &size);
		ctx->f_attr.fa_size = size;
		md_get_uint32(mbp, NULL);	/* allocation size */
		md_get_uint16le(mbp, &wattr);
		ctx->f_attr.fa_attr = wattr;
		md_get_uint8(mbp, &tb);
		size = nmlen = tb;
		fxsz = 23;
		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
		break;
	    case SMB_FIND_FILE_DIRECTORY_INFO:
		md_get_uint32le(mbp, &next);
		md_get_uint32(mbp, NULL);	/* file index */
		md_get_int64(mbp, NULL);	/* creation time */
		md_get_int64le(mbp, &lint);
		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
		md_get_int64le(mbp, &lint);
		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
		md_get_int64le(mbp, &lint);
		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
		md_get_int64le(mbp, &lint);	/* file size */
		ctx->f_attr.fa_size = lint;
		md_get_int64(mbp, NULL);	/* real size (should use) */
		md_get_uint32le(mbp, &dattr);	/* EA */
		ctx->f_attr.fa_attr = dattr;
		md_get_uint32le(mbp, &size);	/* name len */
		fxsz = 64;
		recsz = next ? next : fxsz + size;
		break;
	    default:
		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
		return EINVAL;
	}
	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
		nmlen = min(size, SMB_MAXFNAMELEN * 2);
	} else
		nmlen = min(size, SMB_MAXFNAMELEN);
	cp = ctx->f_name;
	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
	if (error)
		return error;
	if (next) {
		cnt = next - nmlen - fxsz;
		if (cnt > 0)
			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
		else if (cnt < 0) {
			SMBERROR("out of sync\n");
			return EBADRPC;
		}
	}
	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
			nmlen -= 2;
	} else
		if (nmlen && cp[nmlen - 1] == 0)
			nmlen--;
	if (nmlen == 0)
		return EBADRPC;

	next = ctx->f_eofs + recsz;
	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
		/*
		 * Server needs a resume filename.
		 */
		if (ctx->f_rnamelen <= nmlen) {
			if (ctx->f_rname)
				free(ctx->f_rname, M_SMBFSDATA);
			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
			ctx->f_rnamelen = nmlen;
		}
		bcopy(ctx->f_name, ctx->f_rname, nmlen);
		ctx->f_rname[nmlen] = 0;
		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
	}
	ctx->f_nmlen = nmlen;
	ctx->f_eofs = next;
	ctx->f_ecnt--;
	ctx->f_left--;
	return 0;
}
static int
smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
		    struct smb_cred *scred, short infolevel)
{
	struct smb_share *ssp = np->n_mount->sm_share;
	struct smb_vc *vcp = SSTOVC(ssp);
	struct smb_t2rq *t2p;
	int error, svtz, timesok = 1;
	struct mbchain *mbp;
	struct mdchain *mdp;
	u_int16_t date, time, wattr;
	int64_t lint;
	u_int32_t size, dattr;

	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
			     scred, &t2p);
	if (error)
		return error;
	mbp = &t2p->t2_tparam;
	mb_init(mbp);
	if (!infolevel) {
		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
			infolevel = SMB_QUERY_FILE_STANDARD;
		else
			infolevel = SMB_QUERY_FILE_BASIC_INFO;
	}
	mb_put_uint16le(mbp, infolevel);
	mb_put_uint32le(mbp, 0);
	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
	if (error) {
		smb_t2_done(t2p);
		return error;
	}
	t2p->t2_maxpcount = 2;
	t2p->t2_maxdcount = vcp->vc_txmax;
	error = smb_t2_request(t2p);
	if (error) {
		smb_t2_done(t2p);
		if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL)
			return error;
		return smbfs_smb_qpathinfo(np, fap, scred,
					   SMB_QUERY_FILE_STANDARD);
	}
	mdp = &t2p->t2_rdata;
	svtz = vcp->vc_sopt.sv_tz;
	switch (infolevel) {
	    case SMB_QUERY_FILE_STANDARD:
		timesok = 0;
		md_get_uint16le(mdp, NULL);
		md_get_uint16le(mdp, NULL);	/* creation time */
		md_get_uint16le(mdp, &date);
		md_get_uint16le(mdp, &time);	/* access time */
		if (date || time) {
			timesok++;
			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
		}
		md_get_uint16le(mdp, &date);
		md_get_uint16le(mdp, &time);	/* modify time */
		if (date || time) {
			timesok++;
			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
		}
		md_get_uint32le(mdp, &size);
		fap->fa_size = size;
		md_get_uint32(mdp, NULL);	/* allocation size */
		md_get_uint16le(mdp, &wattr);
		fap->fa_attr = wattr;
		break;
	    case SMB_QUERY_FILE_BASIC_INFO:
		timesok = 0;
		md_get_int64(mdp, NULL);	/* creation time */
		md_get_int64le(mdp, &lint);
		if (lint) {
			timesok++;
			smb_time_NT2local(lint, svtz, &fap->fa_atime);
		}
		md_get_int64le(mdp, &lint);
		if (lint) {
			timesok++;
			smb_time_NT2local(lint, svtz, &fap->fa_mtime);
		}
		md_get_int64le(mdp, &lint);
		if (lint) {
			timesok++;
			smb_time_NT2local(lint, svtz, &fap->fa_ctime);
		}
		md_get_uint32le(mdp, &dattr);
		fap->fa_attr = dattr;
		md_get_uint32(mdp, NULL);
		/* XXX could use ALL_INFO to get size */
		break;
	    default:
		SMBERROR("unexpected info level %d\n", infolevel);
		error = EINVAL;
	}
	smb_t2_done(t2p);
	/*
	 * if all times are zero (observed with FAT on NT4SP6)
	 * then fall back to older info level
	 */
	if (!timesok) {
		if (infolevel != SMB_QUERY_FILE_STANDARD)
			return smbfs_smb_qpathinfo(np, fap, scred,
						   SMB_QUERY_FILE_STANDARD);
		error = EINVAL;
	}
	return error;
}