smb_sdrc_t
smb_com_open(smb_request_t *sr)
{
	struct open_param *op = &sr->arg.open;
	smb_node_t *node;
	smb_attr_t attr;
	uint16_t file_attr;
	int rc;

	op->desired_access = smb_omode_to_amask(op->omode);
	op->share_access = smb_denymode_to_sharemode(op->omode,
	    op->fqi.fq_path.pn_path);
	op->crtime.tv_sec = op->crtime.tv_nsec = 0;
	op->create_disposition = FILE_OPEN;
	op->create_options = FILE_NON_DIRECTORY_FILE;
	if (op->omode & SMB_DA_WRITE_THROUGH)
		op->create_options |= FILE_WRITE_THROUGH;

	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
			op->op_oplock_level = SMB_OPLOCK_BATCH;
		else
			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
	} else {
		op->op_oplock_level = SMB_OPLOCK_NONE;
	}

	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
		return (SDRC_ERROR);

	if (op->op_oplock_level == SMB_OPLOCK_NONE) {
		sr->smb_flg &=
		    ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
	}

	if (smb_open_dsize_check && op->dsize > UINT_MAX) {
		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	file_attr = op->dattr  & FILE_ATTRIBUTE_MASK;
	node = sr->fid_ofile->f_node;
	if (smb_node_getattr(sr, node, &attr) != 0) {
		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
		    ERRDOS, ERROR_INTERNAL_ERROR);
		return (SDRC_ERROR);
	}

	rc = smbsr_encode_result(sr, 7, 0, "bwwllww",
	    7,
	    sr->smb_fid,
	    file_attr,
	    smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
	    (uint32_t)op->dsize,
	    op->omode,
	    (uint16_t)0);	/* bcc */

	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
/*
 * smb_trans2_mbc_encode
 *
 * This function encodes the mbc for one directory entry.
 *
 * The function returns -1 when the max data requested by client
 * is reached. If the entry is valid and successful encoded, 0
 * will be returned; otherwise, 1 will be returned.
 *
 * We always null terminate the filename. The space for the null
 * is included in the maxdata calculation and is therefore included
 * in the next_entry_offset. namelen is the unterminated length of
 * the filename. For levels except STANDARD and EA_SIZE, if the
 * filename is ascii the name length returned to the client should
 * include the null terminator. Otherwise the length returned to
 * the client should not include the terminator.
 *
 * Returns: 0 - data successfully encoded
 *          1 - client request's maxdata limit reached
 *	   -1 - error
 */
static int
smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
    smb_fileinfo_t *fileinfo, smb_find_args_t *args)
{
	int		namelen, shortlen;
	uint32_t	next_entry_offset;
	uint32_t	dsize32, asize32;
	uint32_t	mb_flags = 0;
	uint32_t	resume_key;
	char		buf83[26];
	smb_msgbuf_t	mb;

	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
	if (namelen == -1)
		return (-1);

	/*
	 * If ascii the filename length returned to the client should
	 * include the null terminator for levels except STANDARD and
	 * EASIZE.
	 */
	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
			namelen += 1;
	}

	next_entry_offset = args->fa_maxdata + namelen;

	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
		return (1);

	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_size;
	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;

	resume_key = fileinfo->fi_cookie;
	if (smbd_use_resume_keys == 0)
		resume_key = 0;

	/*
	 * This switch handles all the "information levels" (formats)
	 * that we support.  Note that all formats have the file name
	 * placed after some fixed-size data, and the code to write
	 * the file name is factored out at the end of this switch.
	 */
	switch (args->fa_infolev) {
	case SMB_INFO_STANDARD:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    resume_key);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    namelen);
		break;

	case SMB_INFO_QUERY_EA_SIZE:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    resume_key);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    0L,		/* EA Size */
		    namelen);
		break;

	case SMB_FIND_FILE_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen);
		break;

	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L);
		break;

	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    fileinfo->fi_nodeid);
		break;

	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c",
		    sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_ascii_or_unicode_strlen(sr,
		    fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb,
		    "%llTTTTqqlllb.24c2.q",
		    sr,
		    next_entry_offset,
		    resume_key,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83,
		    fileinfo->fi_nodeid);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_NAMES_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr,
		    next_entry_offset,
		    resume_key,
		    namelen);
		break;

	default:
		/* invalid info. level */
		return (-1);
	}

	/*
	 * At this point we have written all the fixed-size data
	 * for the specified info. level, and we're about to put
	 * the file name string in the message.  We may later
	 * need the offset in the trans2 data where this string
	 * is placed, so save the message position now.  Note:
	 * We also need to account for the alignment padding
	 * that may precede the unicode string.
	 */
	args->fa_lno = xa->rep_data_mb.chain_offset;
	if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 &&
	    (args->fa_lno & 1) != 0)
		args->fa_lno++;

	(void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr,
	    fileinfo->fi_name);

	return (0);
}
smb_sdrc_t
smb_com_open_andx(smb_request_t *sr)
{
	struct open_param	*op = &sr->arg.open;
	uint16_t		file_attr;
	smb_attr_t		attr;
	int rc;

	op->desired_access = smb_omode_to_amask(op->omode);
	op->share_access = smb_denymode_to_sharemode(op->omode,
	    op->fqi.fq_path.pn_path);

	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	op->create_options = FILE_NON_DIRECTORY_FILE;
	if (op->omode & SMB_DA_WRITE_THROUGH)
		op->create_options |= FILE_WRITE_THROUGH;

	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
		return (SDRC_ERROR);

	if (smb_open_dsize_check && op->dsize > UINT_MAX) {
		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	if (op->op_oplock_level != SMB_OPLOCK_NONE)
		op->action_taken |= SMB_OACT_LOCK;
	else
		op->action_taken &= ~SMB_OACT_LOCK;

	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {

		smb_node_t *node = sr->fid_ofile->f_node;
		if (smb_node_getattr(sr, node, &attr) != 0) {
			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
			    ERRDOS, ERROR_INTERNAL_ERROR);
			return (SDRC_ERROR);
		}

		rc = smbsr_encode_result(sr, 15, 0,
		    "bb.wwwllwwwwl2.w",
		    15,
		    sr->andx_com, VAR_BCC,
		    sr->smb_fid,
		    file_attr,
		    smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
		    (uint32_t)op->dsize,
		    op->omode, op->ftype,
		    op->devstate,
		    op->action_taken, op->fileid,
		    0);
	} else {
		rc = smbsr_encode_result(sr, 15, 0,
		    "bb.wwwllwwwwl2.w",
		    15,
		    sr->andx_com, VAR_BCC,
		    sr->smb_fid,
		    file_attr,
		    0L,
		    0L,
		    op->omode, op->ftype,
		    op->devstate,
		    op->action_taken, op->fileid,
		    0);
	}

	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
/*
 * smb_query_encode_response
 *
 * Encode the data from smb_queryinfo_t into client response
 */
int
smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
    uint16_t infolev, smb_queryinfo_t *qinfo)
{
	uint16_t dattr;
	u_offset_t datasz, allocsz;
	uint32_t isdir;

	dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
	datasz = qinfo->qi_attr.sa_vattr.va_size;
	allocsz = qinfo->qi_attr.sa_allocsz;
	isdir = ((dattr & FILE_ATTRIBUTE_DIRECTORY) != 0);

	switch (infolev) {
	case SMB_QUERY_INFORMATION:
		(void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
		    10,
		    dattr,
		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
		    smb_size32(datasz),
		    0);
		break;

	case SMB_QUERY_INFORMATION2:
		(void) smbsr_encode_result(sr, 11, 0, "byyyllww",
		    11,
		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
		    smb_size32(datasz), smb_size32(allocsz), dattr, 0);
	break;

	case SMB_FILE_ACCESS_INFORMATION:
		ASSERT(sr->fid_ofile);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
		    sr->fid_ofile->f_granted_access);
		break;

	case SMB_INFO_STANDARD:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb,
		    ((sr->session->native_os == NATIVE_OS_WIN95) ?
		    "YYYllw" : "yyyllw"),
		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
		    smb_size32(datasz), smb_size32(allocsz), dattr);
		break;

	case SMB_INFO_QUERY_EA_SIZE:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb,
		    ((sr->session->native_os == NATIVE_OS_WIN95) ?
		    "YYYllwl" : "yyyllwl"),
		    smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
		    smb_size32(datasz), smb_size32(allocsz), dattr, 0);
		break;

	case SMB_INFO_QUERY_ALL_EAS:
	case SMB_INFO_QUERY_EAS_FROM_LIST:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
		break;

	case SMB_INFO_IS_NAME_VALID:
		break;

	case SMB_QUERY_FILE_BASIC_INFO:
	case SMB_FILE_BASIC_INFORMATION:
		/*
		 * NT includes 6 bytes (spec says 4) at the end of this
		 * response, which are required by NetBench 5.01.
		 */
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
		    &qinfo->qi_crtime,
		    &qinfo->qi_atime,
		    &qinfo->qi_mtime,
		    &qinfo->qi_ctime,
		    dattr);
		break;

	case SMB_QUERY_FILE_STANDARD_INFO:
	case SMB_FILE_STANDARD_INFORMATION:
		/* 2-byte pad at end */
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
		    (uint64_t)allocsz,
		    (uint64_t)datasz,
		    qinfo->qi_attr.sa_vattr.va_nlink,
		    qinfo->qi_delete_on_close,
		    (uint8_t)isdir);
		break;

	case SMB_QUERY_FILE_EA_INFO:
	case SMB_FILE_EA_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
		break;

	case SMB_QUERY_FILE_NAME_INFO:
	case SMB_FILE_NAME_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
		    qinfo->qi_namelen, qinfo->qi_name);
		break;

	case SMB_QUERY_FILE_ALL_INFO:
	case SMB_FILE_ALL_INFORMATION:
		/*
		 * There is a 6-byte pad between Attributes and AllocationSize,
		 * and a 2-byte pad after the Directory field.
		 */
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
		    &qinfo->qi_crtime,
		    &qinfo->qi_atime,
		    &qinfo->qi_mtime,
		    &qinfo->qi_ctime,
		    dattr,
		    (uint64_t)allocsz,
		    (uint64_t)datasz,
		    qinfo->qi_attr.sa_vattr.va_nlink,
		    qinfo->qi_delete_on_close,
		    isdir,
		    0);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
		    sr, qinfo->qi_namelen, qinfo->qi_name);
		break;

	case SMB_QUERY_FILE_ALT_NAME_INFO:
	case SMB_FILE_ALT_NAME_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
		    smb_wcequiv_strlen(qinfo->qi_shortname),
		    qinfo->qi_shortname);
		break;

	case SMB_QUERY_FILE_STREAM_INFO:
	case SMB_FILE_STREAM_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		smb_encode_stream_info(sr, xa, qinfo);
		break;

	case SMB_QUERY_FILE_COMPRESSION_INFO:
	case SMB_FILE_COMPRESSION_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
		    datasz, 0, 0, 0, 0);
		break;

	case SMB_FILE_INTERNAL_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "q",
		    qinfo->qi_attr.sa_vattr.va_nodeid);
		break;

	case SMB_FILE_NETWORK_OPEN_INFORMATION:
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.",
		    &qinfo->qi_crtime,
		    &qinfo->qi_atime,
		    &qinfo->qi_mtime,
		    &qinfo->qi_ctime,
		    (uint64_t)allocsz,
		    (uint64_t)datasz,
		    (uint32_t)dattr);
		break;

	case SMB_FILE_ATTR_TAG_INFORMATION:
		/*
		 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
		 * second dword should be the reparse tag.  Otherwise
		 * the tag value should be set to zero.
		 * We don't support reparse points, so we set the tag
		 * to zero.
		 */
		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
		(void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
		    (uint32_t)dattr, 0);
		break;

	default:
		if ((infolev > 1000) && smb_query_passthru)
			smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
			    ERRDOS, ERROR_NOT_SUPPORTED);
		else
			smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
		return (-1);
	}

	return (0);
}
/*
 * smb_trans2_mbc_encode
 *
 * This function encodes the mbc for one directory entry.
 *
 * The function returns -1 when the max data requested by client
 * is reached. If the entry is valid and successful encoded, 0
 * will be returned; otherwise, 1 will be returned.
 *
 * We always null terminate the filename. The space for the null
 * is included in the maxdata calculation and is therefore included
 * in the next_entry_offset. namelen is the unterminated length of
 * the filename. For levels except STANDARD and EA_SIZE, if the
 * filename is ascii the name length returned to the client should
 * include the null terminator. Otherwise the length returned to
 * the client should not include the terminator.
 *
 * Returns: 0 - data successfully encoded
 *          1 - client request's maxdata limit reached
 *	   -1 - error
 */
static int
smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
    smb_fileinfo_t *fileinfo, smb_find_args_t *args)
{
	int		namelen, shortlen, buflen;
	uint32_t	next_entry_offset;
	uint32_t	dsize32, asize32;
	uint32_t	mb_flags = 0;
	char		buf83[26];
	char		*tmpbuf;
	smb_msgbuf_t	mb;

	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
	if (namelen == -1)
		return (-1);

	next_entry_offset = args->fa_maxdata + namelen;

	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
		return (1);

	/*
	 * If ascii the filename length returned to the client should
	 * include the null terminator for levels except STANDARD and
	 * EASIZE.
	 */
	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
			namelen += 1;
	}

	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_size;
	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;

	switch (args->fa_infolev) {
	case SMB_INFO_STANDARD:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    fileinfo->fi_cookie);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    namelen,
		    fileinfo->fi_name);
		break;

	case SMB_INFO_QUERY_EA_SIZE:
		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
			    fileinfo->fi_cookie);

		/*
		 * Unicode filename should NOT be aligned. Encode ('u')
		 * into a temporary buffer, then encode buffer as a
		 * byte stream ('#c').
		 * Regardless of whether unicode or ascii, a single
		 * termination byte is used.
		 */
		buflen = namelen + sizeof (smb_wchar_t);
		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) {
			smb_msgbuf_term(&mb);
			kmem_free(tmpbuf, buflen);
			return (-1);
		}
		tmpbuf[namelen] = '\0';

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
		    dsize32,
		    asize32,
		    fileinfo->fi_dosattr,
		    0L,		/* EA Size */
		    namelen,
		    namelen + 1,
		    tmpbuf);

		smb_msgbuf_term(&mb);
		kmem_free(tmpbuf, buflen);
		break;

	case SMB_FIND_FILE_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    fileinfo->fi_name);
		break;

	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    fileinfo->fi_name);
		break;

	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    fileinfo->fi_nodeid,
		    fileinfo->fi_name);
		break;

	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
		    sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83,
		    fileinfo->fi_name);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
		bzero(buf83, sizeof (buf83));
		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
		    mb_flags);
		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
			smb_msgbuf_term(&mb);
			return (-1);
		}
		shortlen = smb_ascii_or_unicode_strlen(sr,
		    fileinfo->fi_shortname);

		(void) smb_mbc_encodef(&xa->rep_data_mb,
		    "%llTTTTqqlllb.24c2.qu",
		    sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    &fileinfo->fi_crtime,
		    &fileinfo->fi_atime,
		    &fileinfo->fi_mtime,
		    &fileinfo->fi_ctime,
		    fileinfo->fi_size,
		    fileinfo->fi_alloc_size,
		    fileinfo->fi_dosattr,
		    namelen,
		    0L,
		    shortlen,
		    buf83,
		    fileinfo->fi_nodeid,
		    fileinfo->fi_name);

		smb_msgbuf_term(&mb);
		break;

	case SMB_FIND_FILE_NAMES_INFO:
		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
		    next_entry_offset,
		    fileinfo->fi_cookie,
		    namelen,
		    fileinfo->fi_name);
		break;
	}

	return (0);
}