/* * smb_query_pathname * * Determine the absolute pathname of 'node' within the share. * For some levels (e.g. ALL_INFO) the pathname should include the * sharename for others (e.g. NAME_INFO) the pathname should be * relative to the share. * For example if the node represents file "test1.txt" in directory * "dir1" on share "share1" * - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt * - if include_share is FALSE the pathname would be: \dir1\test1.txt * * For some reason NT will not show the security tab in the root * directory of a mapped drive unless the filename length is greater * than one. So if the length is 1 we set it to 2 to persuade NT to * show the tab. It should be safe because of the null terminator. */ static int smb_query_pathname(smb_request_t *sr, smb_node_t *node, boolean_t include_share, smb_queryinfo_t *qinfo) { smb_tree_t *tree = sr->tid_tree; char *buf = qinfo->qi_name; size_t buflen = MAXPATHLEN; size_t len; int rc; if (include_share) { len = snprintf(buf, buflen, "\\%s", tree->t_sharename); if (len == (buflen - 1)) return (ENAMETOOLONG); buf += len; buflen -= len; } if (node == tree->t_snode) { if (!include_share) (void) strlcpy(buf, "\\", buflen); return (0); } rc = smb_node_getshrpath(node, tree, buf, buflen); if (rc == 0) { qinfo->qi_namelen = smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); if (qinfo->qi_namelen == 1) qinfo->qi_namelen = 2; } return (rc); }
/* * smb_query_pipeinfo * * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE * (This should become an smb_opipe function.) */ static int smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev, smb_queryinfo_t *qinfo) { char *namep = opipe->p_name; (void) bzero(qinfo, sizeof (smb_queryinfo_t)); qinfo->qi_node = NULL; qinfo->qi_attr.sa_vattr.va_nlink = 1; qinfo->qi_delete_on_close = 1; if ((infolev == SMB_INFO_STANDARD) || (infolev == SMB_INFO_QUERY_EA_SIZE) || (infolev == SMB_QUERY_INFORMATION2)) { qinfo->qi_attr.sa_dosattr = 0; } else { qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL; } /* If the leading \ is missing from the pipe name, add it. */ if (*namep != '\\') (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep); else (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN); qinfo->qi_namelen= smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); return (0); }
/* * smb_stream_fits * * Check if the named stream entry can fit in the response buffer. * * Required space = * offset (size of current entry) * + SMB_STREAM_ENCODE_FIXED_SIZE * + length of encoded stream name * + length of null terminator * + alignment padding */ static boolean_t smb_stream_fits(smb_request_t *sr, smb_xa_t *xa, char *name, uint32_t offset) { uint32_t len, pad; len = SMB_STREAM_ENCODE_FIXED_SZ + smb_ascii_or_unicode_strlen(sr, name) + smb_ascii_or_unicode_null_len(sr); pad = smb_pad_align(len, 8); len += pad; return (MBC_ROOM_FOR(&xa->rep_data_mb, offset + len) != 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; 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_encode_stream_info * * This function encodes the streams information. * The following rules about how have been derived from observed NT * behaviour. * * If the target is a file: * 1. If there are no named streams, the response should still contain * an entry for the unnamed stream. * 2. If there are named streams, the response should contain an entry * for the unnamed stream followed by the entries for the named * streams. * * If the target is a directory: * 1. If there are no streams, the response is complete. Directories * do not report the unnamed stream. * 2. If there are streams, the response should contain entries for * those streams but there should not be an entry for the unnamed * stream. * * Note that the stream name lengths exclude the null terminator but * the field lengths (i.e. next offset calculations) need to include * the null terminator and be padded to a multiple of 8 bytes. The * last entry does not seem to need any padding. * * If an error is encountered when trying to read the stream entries * (smb_odir_read_streaminfo) it is treated as if there are no [more] * entries. The entries that have been read so far are returned and * no error is reported. * * If the response buffer is not large enough to return all of the * named stream entries, the entries that do fit are returned and * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset * value in the last returned entry must be 0. */ static void smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo) { char *stream_name; uint32_t next_offset; uint32_t stream_nlen; uint32_t pad; u_offset_t datasz, allocsz; boolean_t is_dir; smb_streaminfo_t *sinfo, *sinfo_next; int rc = 0; boolean_t done = B_FALSE; boolean_t eos = B_FALSE; uint16_t odid; smb_odir_t *od = NULL; smb_node_t *fnode = qinfo->qi_node; smb_attr_t *attr = &qinfo->qi_attr; ASSERT(fnode); if (SMB_IS_STREAM(fnode)) { fnode = fnode->n_unode; ASSERT(fnode); } ASSERT(fnode->n_magic == SMB_NODE_MAGIC); ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); is_dir = ((attr->sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) != 0); datasz = attr->sa_vattr.va_size; allocsz = attr->sa_allocsz; odid = smb_odir_openat(sr, fnode); if (odid != 0) od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od != NULL) rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos); if ((od == NULL) || (rc != 0) || (eos)) done = B_TRUE; /* If not a directory, encode an entry for the unnamed stream. */ if (!is_dir) { stream_name = "::$DATA"; stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen + smb_ascii_or_unicode_null_len(sr); /* Can unnamed stream fit in response buffer? */ if (MBC_ROOM_FOR(&xa->rep_data_mb, next_offset) == 0) { done = B_TRUE; smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, ERRDOS, ERROR_MORE_DATA); } else { /* Can first named stream fit in rsp buffer? */ if (!done && !smb_stream_fits(sr, xa, sinfo->si_name, next_offset)) { done = B_TRUE; smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, ERRDOS, ERROR_MORE_DATA); } if (done) next_offset = 0; (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, next_offset, stream_nlen, datasz, allocsz, stream_name); } } /* * If there is no next entry, or there is not enough space in * the response buffer for the next entry, the next_offset and * padding are 0. */ while (!done) { stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); sinfo_next->si_name[0] = 0; rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); if ((rc != 0) || (eos)) { done = B_TRUE; } else { next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen + smb_ascii_or_unicode_null_len(sr); pad = smb_pad_align(next_offset, 8); next_offset += pad; /* Can next named stream fit in response buffer? */ if (!smb_stream_fits(sr, xa, sinfo_next->si_name, next_offset)) { done = B_TRUE; smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, ERRDOS, ERROR_MORE_DATA); } } if (done) { next_offset = 0; pad = 0; } rc = smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", sr, next_offset, stream_nlen, sinfo->si_size, sinfo->si_alloc_size, sinfo->si_name, pad); (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t)); } kmem_free(sinfo, sizeof (smb_streaminfo_t)); kmem_free(sinfo_next, sizeof (smb_streaminfo_t)); if (od) { smb_odir_close(od); smb_odir_release(od); } }
/* * smb_query_fileinfo * * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK * (This should become an smb_ofile / smb_node function.) */ int smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev, smb_queryinfo_t *qinfo) { int rc; boolean_t include_sharename = B_FALSE; (void) bzero(qinfo, sizeof (smb_queryinfo_t)); if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) { smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, ERRDOS, ERROR_INTERNAL_ERROR); return (-1); } qinfo->qi_node = node; qinfo->qi_delete_on_close = (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0; /* * The number of links reported should be the number of * non-deleted links. Thus if delete_on_close is set, * decrement the link count. */ if (qinfo->qi_delete_on_close && qinfo->qi_attr.sa_vattr.va_nlink > 0) { --(qinfo->qi_attr.sa_vattr.va_nlink); } /* populate name, namelen and shortname */ /* ALL_INFO levels include the sharename in the name field */ if ((infolev == SMB_QUERY_FILE_ALL_INFO) || (infolev == SMB_FILE_ALL_INFORMATION)) { include_sharename = B_TRUE; } rc = smb_query_pathname(sr->tid_tree, node, include_sharename, qinfo->qi_name, MAXPATHLEN); if (rc != 0) { smbsr_errno(sr, rc); return (-1); } qinfo->qi_namelen = smb_ascii_or_unicode_strlen(sr, qinfo->qi_name); /* * For some reason NT will not show the security tab in the root * directory of a mapped drive unless the filename length is * greater than one. So we hack the length here to persuade NT * to show the tab. It should be safe because of the null * terminator character. */ if (qinfo->qi_namelen == 1) qinfo->qi_namelen = 2; /* * If the shortname is generated by smb_mangle_name() * it will be returned as the alternative name. * Otherwise, convert the original name to upper-case * and return it as the alternative name. */ (void) smb_mangle_name(qinfo->qi_attr.sa_vattr.va_nodeid, node->od_name, qinfo->qi_shortname, qinfo->qi_name83, 0); if (*qinfo->qi_shortname == 0) { (void) strlcpy(qinfo->qi_shortname, node->od_name, SMB_SHORTNAMELEN); (void) smb_strupr(qinfo->qi_shortname); } return (0); }
/* * smb_encode_stream_info * * This function encodes the streams information. * The following rules about how have been derived from observed NT * behaviour. * * If the target is a file: * 1. If there are no named streams, the response should still contain * an entry for the unnamed stream. * 2. If there are named streams, the response should contain an entry * for the unnamed stream followed by the entries for the named * streams. * * If the target is a directory: * 1. If there are no streams, the response is complete. Directories * do not report the unnamed stream. * 2. If there are streams, the response should contain entries for * those streams but there should not be an entry for the unnamed * stream. * * Note that the stream name lengths exclude the null terminator but * the field lengths (i.e. next offset calculations) need to include * the null terminator and be padded to a multiple of 8 bytes. The * last entry does not seem to need any padding. * * If an error is encountered when trying to read the stream entries * (smb_odir_read_streaminfo) it is treated as if there are no [more] * entries. The entries that have been read so far are returned and * no error is reported. * * Offset calculation: * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 */ static void smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo) { char *stream_name; uint32_t next_offset; uint32_t stream_nlen; uint32_t pad; u_offset_t datasz, allocsz; boolean_t is_dir; smb_streaminfo_t *sinfo, *sinfo_next; int rc = 0; boolean_t done = B_FALSE; boolean_t eos = B_FALSE; uint16_t odid; smb_odir_t *od = NULL; smb_node_t *fnode = qinfo->qi_node; smb_attr_t *attr = &qinfo->qi_attr; ASSERT(fnode); if (SMB_IS_STREAM(fnode)) { fnode = fnode->n_unode; ASSERT(fnode); } ASSERT(fnode->n_magic == SMB_NODE_MAGIC); ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); is_dir = (attr->sa_vattr.va_type == VDIR); datasz = attr->sa_vattr.va_size; allocsz = attr->sa_allocsz; odid = smb_odir_openat(sr, fnode); if (odid != 0) od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od != NULL) rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos); if ((od == NULL) || (rc != 0) || (eos)) done = B_TRUE; /* If not a directory, encode an entry for the unnamed stream. */ if (!is_dir) { stream_name = "::$DATA"; stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); if (done) next_offset = 0; else next_offset = 24 + stream_nlen + smb_ascii_or_unicode_null_len(sr); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, next_offset, stream_nlen, datasz, allocsz, stream_name); } /* * Since last packet does not have a pad we need to check * for the next stream before we encode the current one */ while (!done) { stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); sinfo_next->si_name[0] = 0; rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); if ((rc != 0) || (eos)) { done = B_TRUE; next_offset = 0; pad = 0; } else { next_offset = 24 + stream_nlen + smb_ascii_or_unicode_null_len(sr); pad = smb_pad_align(next_offset, 8); next_offset += pad; } (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", sr, next_offset, stream_nlen, sinfo->si_size, sinfo->si_alloc_size, sinfo->si_name, pad); (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t)); } kmem_free(sinfo, sizeof (smb_streaminfo_t)); kmem_free(sinfo_next, sizeof (smb_streaminfo_t)); if (od) { smb_odir_close(od); smb_odir_release(od); } }
/* * 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); }