/* * smb_tree_close_odirs * * Close all open odirs in the tree's list which were opened by * the process identified by pid. * If pid is zero, close all open odirs in the tree's list. */ static void smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) { smb_odir_t *od, *next_od; ASSERT(tree); ASSERT(tree->t_magic == SMB_TREE_MAGIC); od = smb_tree_get_odir(tree, NULL); while (od) { ASSERT(od->d_magic == SMB_ODIR_MAGIC); ASSERT(od->d_tree == tree); next_od = smb_tree_get_odir(tree, od); if ((pid == 0) || (od->d_opened_by_pid == pid)) smb_odir_close(od); smb_odir_release(od); od = next_od; } }
smb_sdrc_t smb_com_find_close2(smb_request_t *sr) { uint16_t odid; smb_odir_t *od; if (smbsr_decode_vwv(sr, "w", &odid) != 0) return (SDRC_ERROR); od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } smb_odir_close(od); smb_odir_release(od); if (smbsr_encode_empty_result(sr)) return (SDRC_ERROR); return (SDRC_SUCCESS); }
/* * smb_com_trans2_find_next2 * * Client Request Value * ================================== ================================= * * WordCount 15 * SetupCount 1 * Setup[0] TRANS2_FIND_NEXT2 * * Parameter Block Encoding Description * ================================== ================================= * * USHORT Sid; Search handle * USHORT SearchCount; Maximum number of entries to * return * USHORT InformationLevel; Levels described in * TRANS2_FIND_FIRST2 request * ULONG ResumeKey; Value returned by previous find2 * call * USHORT Flags; Additional information: bit set- * 0 - close search after this * request * 1 - close search if end of search * reached * 2 - return resume keys for each * entry found * 3 - resume/continue from previous * ending place * 4 - find with backup intent * STRING FileName; Resume file name * * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2 * call. If Bit3 of Flags is set, then FileName may be the NULL string, * since the search is continued from the previous TRANS2_FIND request. * Otherwise, FileName must not be more than 256 characters long. * * Response Field Description * ================================== ================================= * * USHORT SearchCount; Number of entries returned * USHORT EndOfSearch; Was last entry returned? * USHORT EaErrorOffset; Offset into EA list if EA error * USHORT LastNameOffset; Offset into data to file name of * last entry, if server needs it to * resume search; else 0 * UCHAR Data[TotalDataCount] Level dependent info about the * matches found in the search * * * The last parameter in the request is a filename, which is a * null-terminated unicode string. * * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr, * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname) * * The filename parameter is not currently decoded because we * expect a 2-byte null but Mac OS 10 clients send a 1-byte null, * which leads to a decode error. * Thus, we do not support resume by filename. We treat a request * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST. */ smb_sdrc_t smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) { int count; uint16_t odid; smb_odir_t *od; smb_find_args_t args; smb_odir_resume_t odir_resume; bzero(&args, sizeof (args)); bzero(&odir_resume, sizeof (odir_resume)); if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERROR_ACCESS_DENIED); return (SDRC_ERROR); } if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlwu", sr, &odid, &args.fa_maxcount, &args.fa_infolev, &odir_resume.or_cookie, &args.fa_fflag, &odir_resume.or_fname) != 0) { return (SDRC_ERROR); } if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) sr->user_cr = smb_user_getprivcred(sr->uid_user); args.fa_maxdata = smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); if (args.fa_maxdata == 0) return (SDRC_ERROR); od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } /* * Set the correct position in the directory. * * "Continue from last" is easy, but due to a history of * buggy server implementations, most clients don't use * that method. The most widely used (and reliable) is * resume by file name. Unfortunately, that can't really * be fully supported unless your file system stores all * directory entries in some sorted order (like NTFS). * We can partially support resume by name, where the only * name we're ever asked to resume on is the same as the * most recent we returned. That's always what the client * gives us as the resume name, so we can simply remember * the last name/offset pair and use that to position on * the following FindNext call. In the unlikely event * that the client asks to resume somewhere else, we'll * use the numeric resume key, and hope the client gives * correctly uses one of the resume keys we provided. */ if (args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) { odir_resume.or_type = SMB_ODIR_RESUME_CONT; } else { odir_resume.or_type = SMB_ODIR_RESUME_FNAME; } smb_odir_resume_at(od, &odir_resume); count = smb_trans2_find_entries(sr, xa, od, &args); if (count == -1) { smb_odir_close(od); smb_odir_release(od); return (SDRC_ERROR); } if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { smb_odir_close(od); } /* else leave odir open for trans2_find_next2 */ smb_odir_release(od); (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", count, /* Search Count */ args.fa_eos, /* End Of Search */ 0, /* EA Error Offset */ args.fa_lno); /* Last Name Offset */ return (SDRC_SUCCESS); }
/* * smb_com_trans2_find_first2 * * Client Request Value * ============================ ================================== * * UCHAR WordCount 15 * UCHAR TotalDataCount Total size of extended attribute list * UCHAR SetupCount 1 * UCHAR Setup[0] TRANS2_FIND_FIRST2 * * Parameter Block Encoding Description * ============================ ================================== * USHORT SearchAttributes; * USHORT SearchCount; Maximum number of entries to return * USHORT Flags; Additional information: * Bit 0 - close search after this request * Bit 1 - close search if end of search * reached * Bit 2 - return resume keys for each * entry found * Bit 3 - continue search from previous * ending place * Bit 4 - find with backup intent * USHORT InformationLevel; See below * ULONG SearchStorageType; * STRING FileName; Pattern for the search * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is * QUERY_EAS_FROM_LIST * * Response Parameter Block Description * ============================ ================================== * * USHORT Sid; Search handle * USHORT SearchCount; Number of entries returned * USHORT EndOfSearch; Was last entry returned? * USHORT EaErrorOffset; Offset into EA list if EA error * USHORT LastNameOffset; Offset into data to file name of last * entry, if server needs it to resume * search; else 0 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches * found in the search */ smb_sdrc_t smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) { int count; uint16_t sattr, odid; smb_pathname_t *pn; smb_odir_t *od; smb_find_args_t args; uint32_t odir_flags = 0; bzero(&args, sizeof (smb_find_args_t)); if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERROR_ACCESS_DENIED); return (SDRC_ERROR); } pn = &sr->arg.dirop.fqi.fq_path; if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr, &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, &pn->pn_path) != 0) { return (SDRC_ERROR); } smb_pathname_init(sr, pn, pn->pn_path); if (!smb_pathname_validate(sr, pn)) return (-1); if (smb_is_stream_name(pn->pn_path)) { smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, ERRDOS, ERROR_INVALID_NAME); return (SDRC_ERROR); } if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) { sr->user_cr = smb_user_getprivcred(sr->uid_user); odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT; } args.fa_maxdata = smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); if (args.fa_maxdata == 0) return (SDRC_ERROR); odid = smb_odir_open(sr, pn->pn_path, sattr, odir_flags); if (odid == 0) { if (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND) { smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERROR_FILE_NOT_FOUND); } return (SDRC_ERROR); } od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od == NULL) return (SDRC_ERROR); count = smb_trans2_find_entries(sr, xa, od, &args); if (count == -1) { smb_odir_close(od); smb_odir_release(od); return (SDRC_ERROR); } if (count == 0) { smb_odir_close(od); smb_odir_release(od); smbsr_errno(sr, ENOENT); return (SDRC_ERROR); } if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { smb_odir_close(od); } /* else leave odir open for trans2_find_next2 */ smb_odir_release(od); (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", odid, /* Search ID */ count, /* Search Count */ args.fa_eos, /* End Of Search */ 0, /* EA Error Offset */ args.fa_lno); /* Last Name Offset */ return (SDRC_SUCCESS); }
/* * smb_ofile_close */ void smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec) { smb_attr_t *pa; timestruc_t now; uint32_t flags = 0; SMB_OFILE_VALID(of); mutex_enter(&of->f_mutex); ASSERT(of->f_refcnt); if (of->f_state != SMB_OFILE_STATE_OPEN) { mutex_exit(&of->f_mutex); return; } of->f_state = SMB_OFILE_STATE_CLOSING; mutex_exit(&of->f_mutex); switch (of->f_ftype) { case SMB_FTYPE_BYTE_PIPE: case SMB_FTYPE_MESG_PIPE: smb_opipe_close(of); smb_server_dec_pipes(of->f_server); break; case SMB_FTYPE_DISK: case SMB_FTYPE_PRINTER: /* * In here we make changes to of->f_pending_attr * while not holding of->f_mutex. This is OK * because we've changed f_state to CLOSING, * so no more threads will take this path. */ pa = &of->f_pending_attr; if (mtime_sec != 0) { pa->sa_vattr.va_mtime.tv_sec = mtime_sec; pa->sa_mask |= SMB_AT_MTIME; } /* * If we have ever modified data via this handle * (write or truncate) and if the mtime was not * set via this handle, update the mtime again * during the close. Windows expects this. * [ MS-FSA 2.1.5.4 "Update Timestamps" ] */ if (of->f_written && (pa->sa_mask & SMB_AT_MTIME) == 0) { pa->sa_mask |= SMB_AT_MTIME; gethrestime(&now); pa->sa_vattr.va_mtime = now; } if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) { if (smb_tree_has_feature(of->f_tree, SMB_TREE_CATIA)) { flags |= SMB_CATIA; } (void) smb_node_set_delete_on_close(of->f_node, of->f_cr, flags); } smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); smb_node_destroy_lock_by_ofile(of->f_node, of); if (smb_node_is_file(of->f_node)) { (void) smb_fsop_close(of->f_node, of->f_mode, of->f_cr); smb_oplock_release(of->f_node, of); } else { /* * If there was an odir, close it. */ if (of->f_odir != NULL) smb_odir_close(of->f_odir); } if (smb_node_dec_open_ofiles(of->f_node) == 0) { /* * Last close. The f_pending_attr has * only times (atime,ctime,mtime) so * we can borrow it to commit the * n_pending_dosattr from the node. */ pa->sa_dosattr = of->f_node->n_pending_dosattr; if (pa->sa_dosattr != 0) pa->sa_mask |= SMB_AT_DOSATTR; /* Let's leave this zero when not in use. */ of->f_node->n_allocsz = 0; } if (pa->sa_mask != 0) { /* * Commit any pending attributes from * the ofile we're closing. Note that * we pass NULL as the ofile to setattr * so it will write to the file system * and not keep anything on the ofile. * This clears n_pending_dosattr if * there are no opens, otherwise the * dosattr will be pending again. */ (void) smb_node_setattr(NULL, of->f_node, of->f_cr, NULL, pa); } /* * Cancel any notify change requests that * may be using this open instance. */ if (of->f_node->n_fcn.fcn_count) smb_notify_file_closed(of); smb_server_dec_files(of->f_server); break; } atomic_dec_32(&of->f_tree->t_open_files); mutex_enter(&of->f_mutex); ASSERT(of->f_refcnt); ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); of->f_state = SMB_OFILE_STATE_CLOSED; mutex_exit(&of->f_mutex); }
/* * 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_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_com_trans2_find_next2 * * Client Request Value * ================================== ================================= * * WordCount 15 * SetupCount 1 * Setup[0] TRANS2_FIND_NEXT2 * * Parameter Block Encoding Description * ================================== ================================= * * USHORT Sid; Search handle * USHORT SearchCount; Maximum number of entries to * return * USHORT InformationLevel; Levels described in * TRANS2_FIND_FIRST2 request * ULONG ResumeKey; Value returned by previous find2 * call * USHORT Flags; Additional information: bit set- * 0 - close search after this * request * 1 - close search if end of search * reached * 2 - return resume keys for each * entry found * 3 - resume/continue from previous * ending place * 4 - find with backup intent * STRING FileName; Resume file name * * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2 * call. If Bit3 of Flags is set, then FileName may be the NULL string, * since the search is continued from the previous TRANS2_FIND request. * Otherwise, FileName must not be more than 256 characters long. * * Response Field Description * ================================== ================================= * * USHORT SearchCount; Number of entries returned * USHORT EndOfSearch; Was last entry returned? * USHORT EaErrorOffset; Offset into EA list if EA error * USHORT LastNameOffset; Offset into data to file name of * last entry, if server needs it to * resume search; else 0 * UCHAR Data[TotalDataCount] Level dependent info about the * matches found in the search * * * The last parameter in the request is a filename, which is a * null-terminated unicode string. * * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr, * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname) * * The filename parameter is not currently decoded because we * expect a 2-byte null but Mac OS 10 clients send a 1-byte null, * which leads to a decode error. * Thus, we do not support resume by filename. We treat a request * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST. */ smb_sdrc_t smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) { int count; uint16_t odid; uint32_t cookie; smb_odir_t *od; smb_find_args_t args; boolean_t eos; smb_odir_resume_t odir_resume; bzero(&args, sizeof (smb_find_args_t)); if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid, &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag) != 0) { return (SDRC_ERROR); } /* continuation by filename not supported */ if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) { odir_resume.or_type = SMB_ODIR_RESUME_IDX; odir_resume.or_idx = 0; } else { odir_resume.or_type = SMB_ODIR_RESUME_COOKIE; odir_resume.or_cookie = cookie; } if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) sr->user_cr = smb_user_getprivcred(sr->uid_user); args.fa_maxdata = smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); if (args.fa_maxdata == 0) return (SDRC_ERROR); od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } smb_odir_resume_at(od, &odir_resume); count = smb_trans2_find_entries(sr, xa, od, &args, &eos); if (count == -1) { smb_odir_close(od); smb_odir_release(od); return (SDRC_ERROR); } if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { smb_odir_close(od); } /* else leave odir open for trans2_find_next2 */ smb_odir_release(od); (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", count, (eos) ? 1 : 0, 0, 0); return (SDRC_SUCCESS); }
/* * smb_com_trans2_find_first2 * * Client Request Value * ============================ ================================== * * UCHAR WordCount 15 * UCHAR TotalDataCount Total size of extended attribute list * UCHAR SetupCount 1 * UCHAR Setup[0] TRANS2_FIND_FIRST2 * * Parameter Block Encoding Description * ============================ ================================== * USHORT SearchAttributes; * USHORT SearchCount; Maximum number of entries to return * USHORT Flags; Additional information: * Bit 0 - close search after this request * Bit 1 - close search if end of search * reached * Bit 2 - return resume keys for each * entry found * Bit 3 - continue search from previous * ending place * Bit 4 - find with backup intent * USHORT InformationLevel; See below * ULONG SearchStorageType; * STRING FileName; Pattern for the search * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is * QUERY_EAS_FROM_LIST * * Response Parameter Block Description * ============================ ================================== * * USHORT Sid; Search handle * USHORT SearchCount; Number of entries returned * USHORT EndOfSearch; Was last entry returned? * USHORT EaErrorOffset; Offset into EA list if EA error * USHORT LastNameOffset; Offset into data to file name of last * entry, if server needs it to resume * search; else 0 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches * found in the search */ smb_sdrc_t smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) { int count; uint16_t sattr, odid; char *path; smb_odir_t *od; smb_find_args_t args; boolean_t eos; uint32_t odir_flags = 0; bzero(&args, sizeof (smb_find_args_t)); if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERROR_ACCESS_DENIED); return (SDRC_ERROR); } if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr, &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, &path) != 0) { return (SDRC_ERROR); } if (smb_is_stream_name(path)) { smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, ERRDOS, ERROR_INVALID_NAME); return (SDRC_ERROR); } if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) { sr->user_cr = smb_user_getprivcred(sr->uid_user); odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT; } args.fa_maxdata = smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); if (args.fa_maxdata == 0) return (SDRC_ERROR); if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) (void) smb_convert_wildcards(path); odid = smb_odir_open(sr, path, sattr, odir_flags); if (odid == 0) return (SDRC_ERROR); od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od == NULL) return (SDRC_ERROR); count = smb_trans2_find_entries(sr, xa, od, &args, &eos); if (count == -1) { smb_odir_close(od); smb_odir_release(od); return (SDRC_ERROR); } if (count == 0) { smb_odir_close(od); smb_odir_release(od); smbsr_errno(sr, ENOENT); return (SDRC_ERROR); } if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { smb_odir_close(od); } /* else leave odir open for trans2_find_next2 */ smb_odir_release(od); (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", odid, count, (eos) ? 1 : 0, 0, 0); return (SDRC_SUCCESS); }