/* * 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_mbc_vdecodef * * This function reads the contents of the mbc chain passed in under the list * of arguments passed in. * * The format string provides a description of the parameters passed in as well * as an action to be taken by smb_mbc_vdecodef(). * * % Pointer to an SMB request structure (smb_request_t *). There * should be only one of these in the string. * * C Pointer to an mbuf chain. Copy to that mbuf chain the number of * bytes specified (number preceding C). * * m Pointer to an mbuf. Copy to that mbuf the number of bytes * specified (number preceding m). * * M Read the 32 bit value at the current location of the mbuf chain * and check if it matches the signature of an SMB request (SMBX). * * b Pointer to a buffer. Copy to that buffer the number of bytes * specified (number preceding b). * * c Same as 'b'. * * w Pointer to a word (16bit value). Copy the next 16bit value into * that location. * * l Pointer to a long (32bit value). Copy the next 32bit value into * that location. * * q Pointer to a quad (64bit value). Copy the next 64bit value into * that location. * * Q Same as above with a call to qswap(). * * B Pointer to a vardata_block structure. That structure is used to * retrieve data from the mbuf chain (an iovec type structure is * embedded in a vardata_block). * * D Pointer to a vardata_block structure. That structure is used to * retrieve data from the mbuf chain, however, two fields of the * vardata_block structure (tag and len) are first initialized * using the mbuf chain itself. * * V Same as 'D'. * * L * * A * * P Same as 'A' * * S Same as 'A' * * u Pointer to a string pointer. Allocate memory and retrieve the * string at the current location in the mbuf chain. Store the * address to the buffer allocated at the address specified by * the pointer. In addition if an sr was passed and it indicates * that the string is an unicode string, convert it. * * s Same as 'u' without convertion. * * U Same as 'u'. The string to retrieve is unicode. * * y Pointer to a 32bit value. Read the dos time at the current mbuf * chain location, convert it to unix time and store it at the * location indicated by the pointer. * * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted. * * . Skip the number of bytes indicated by the number preceding '.'. * * , Same as '.' but take in account it is an unicode string. */ int smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap) { uint8_t c; uint8_t cval; uint8_t *cvalp; uint8_t **cvalpp; uint16_t wval; uint16_t *wvalp; uint32_t *lvalp; uint64_t *llvalp; smb_vdb_t *vdp; smb_request_t *sr = NULL; uint32_t lval; int unicode = 0; int repc; while ((c = *fmt++) != 0) { repc = 1; if ('0' <= c && c <= '9') { repc = 0; do { repc = repc * 10 + c - '0'; c = *fmt++; } while ('0' <= c && c <= '9'); } else if (c == '#') { repc = va_arg(ap, int); c = *fmt++; } switch (c) { case '%': sr = va_arg(ap, struct smb_request *); unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; break; case 'C': /* Mbuf_chain */ if (mbc_marshal_get_mbuf_chain(mbc, repc, va_arg(ap, mbuf_chain_t *)) != 0) return (-1); break; case 'm': /* struct_mbuf */ if (mbc_marshal_get_mbufs(mbc, repc, va_arg(ap, mbuf_t **)) != 0) return (-1); break; case 'M': if (mbc_marshal_get_long(mbc, &lval) != 0) /* Data will never be available */ return (-1); if (lval != 0x424D53FF) /* 0xFF S M B */ return (-1); break; case 'b': case 'c': cvalp = va_arg(ap, uint8_t *); if (MBC_ROOM_FOR(mbc, repc) == 0) /* Data will never be available */ return (-1); while (repc-- > 0) *cvalp++ = mbc_marshal_fetch_byte(mbc); break; case 'w': wvalp = va_arg(ap, uint16_t *); while (repc-- > 0) if (mbc_marshal_get_short(mbc, wvalp++) != 0) return (-1); break; case 'l': lvalp = va_arg(ap, uint32_t *); while (repc-- > 0) if (mbc_marshal_get_long(mbc, lvalp++) != 0) return (-1); break; case 'q': llvalp = va_arg(ap, uint64_t *); while (repc-- > 0) if (mbc_marshal_get_long_long( mbc, llvalp++) != 0) return (-1); break; case 'Q': llvalp = va_arg(ap, uint64_t *); while (repc-- > 0) if (mbc_marshal_get_odd_long_long( mbc, llvalp++) != 0) return (-1); break; case 'B': vdp = va_arg(ap, struct vardata_block *); vdp->vdb_tag = 0; vdp->vdb_len = repc; vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; vdp->vdb_uio.uio_resid = repc; if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0) return (-1); break; case 'D': case 'V': vdp = va_arg(ap, struct vardata_block *); if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0) return (-1); if (mbc_marshal_get_short(mbc, &wval) != 0) return (-1); vdp->vdb_len = (uint32_t)wval; vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; vdp->vdb_uio.uio_resid = vdp->vdb_len; if (vdp->vdb_len != 0) { if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0) return (-1); } break; case 'L': if (mbc_marshal_get_char(mbc, &cval) != 0) return (-1); if (cval != 2) return (-1); goto ascii_conversion; case 'A': case 'S': if (mbc_marshal_get_char(mbc, &cval) != 0) return (-1); if (((c == 'A' || c == 'S') && cval != 4) || (c == 'L' && cval != 2)) return (-1); /* FALLTHROUGH */ case 'u': /* Convert from unicode if flags are set */ if (unicode) goto unicode_translation; /* FALLTHROUGH */ case 's': ascii_conversion: ASSERT(sr != NULL); cvalpp = va_arg(ap, uint8_t **); if (repc <= 1) repc = 0; if (mbc_marshal_get_ascii_string(sr, mbc, cvalpp, repc) != 0) return (-1); break; case 'U': /* Convert from unicode */ unicode_translation: ASSERT(sr != 0); cvalpp = va_arg(ap, uint8_t **); if (repc <= 1) repc = 0; if (mbc->chain_offset & 1) mbc->chain_offset++; if (mbc_marshal_get_unicode_string(sr, mbc, cvalpp, repc) != 0) return (-1); break; case 'Y': /* dos time to unix time tt/dd */ lvalp = va_arg(ap, uint32_t *); while (repc-- > 0) { short d, t; if (mbc_marshal_get_short(mbc, (uint16_t *)&t) != 0) return (-1); if (mbc_marshal_get_short(mbc, (uint16_t *)&d) != 0) return (-1); *lvalp++ = smb_time_dos_to_unix(d, t); } break; case 'y': /* dos time to unix time dd/tt */ lvalp = va_arg(ap, uint32_t *); while (repc-- > 0) { short d, t; if (mbc_marshal_get_short(mbc, (uint16_t *)&d) != 0) return (-1); if (mbc_marshal_get_short(mbc, (uint16_t *)&t) != 0) return (-1); *lvalp++ = smb_time_dos_to_unix(d, t); } break; case ',': if (unicode) repc *= 2; /* FALLTHROUGH */ case '.': if (mbc_marshal_get_skip(mbc, repc) != 0) return (-1); break; default: ASSERT(0); return (-1); } }
/* * 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_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); }