From: Ralph Boehme Date: Tue, 3 Jul 2018 09:25:57 +0000 (+0200) Subject: smbd: factor out smb2_query_directory_next_entry() from smbd_smb2_query_directory_send() X-Git-Tag: ldb-1.5.0~142 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=abef6ca70610fbc2f0a527ff2084fe8eda43031b;p=thirdparty%2Fsamba.git smbd: factor out smb2_query_directory_next_entry() from smbd_smb2_query_directory_send() This paves the way for adding async functions into the enumeration loop. Best viewed with: git show -w Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher --- diff --git a/source3/smbd/smb2_query_directory.c b/source3/smbd/smb2_query_directory.c index 7584598c2c3..6577ab81eaa 100644 --- a/source3/smbd/smb2_query_directory.c +++ b/source3/smbd/smb2_query_directory.c @@ -205,15 +205,32 @@ static struct tevent_req *fetch_write_time_send(TALLOC_CTX *mem_ctx, bool *stop); static NTSTATUS fetch_write_time_recv(struct tevent_req *req); - struct smbd_smb2_query_directory_state { struct tevent_context *ev; struct smbd_smb2_request *smb2req; - uint64_t async_count; + uint64_t async_sharemode_count; uint32_t find_async_delay_usec; DATA_BLOB out_output_buffer; + struct smb_request *smbreq; + int in_output_buffer_length; + struct files_struct *fsp; + const char *in_file_name; + NTSTATUS empty_status; + uint32_t info_level; + uint32_t max_count; + char *pdata; + char *base_data; + char *end_data; + uint32_t num; + uint32_t dirtype; + bool dont_descend; + bool ask_sharemode; + bool async_ask_sharemode; + int last_entry_off; + bool done; }; +static bool smb2_query_directory_next_entry(struct tevent_req *req); static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq); static void smb2_query_directory_waited(struct tevent_req *subreq); @@ -230,25 +247,12 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, struct smbXsrv_connection *xconn = smb2req->xconn; struct tevent_req *req; struct smbd_smb2_query_directory_state *state; - struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat; NTSTATUS status; - NTSTATUS empty_status; - uint32_t info_level; - uint32_t max_count; - char *pdata; - char *base_data; - char *end_data; - int last_entry_off = 0; - int off = 0; - uint32_t num = 0; - uint32_t dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY; - bool dont_descend = false; - bool ask_sharemode = false; - bool async_ask_sharemode = false; bool wcard_has_wild = false; struct tm tm; char *p; + bool stop = false; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_query_directory_state); @@ -256,14 +260,18 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, return NULL; } state->ev = ev; + state->fsp = fsp; state->smb2req = smb2req; + state->in_output_buffer_length = in_output_buffer_length; + state->in_file_name = in_file_name; state->out_output_buffer = data_blob_null; + state->dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY; DEBUG(10,("smbd_smb2_query_directory_send: %s - %s\n", fsp_str_dbg(fsp), fsp_fnum_dbg(fsp))); - smbreq = smbd_smb2_fake_smb_request(smb2req); - if (tevent_req_nomem(smbreq, req)) { + state->smbreq = smbd_smb2_fake_smb_request(smb2req); + if (tevent_req_nomem(state->smbreq, req)) { return tevent_req_post(req, ev); } @@ -272,20 +280,20 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (strcmp(in_file_name, "") == 0) { + if (strcmp(state->in_file_name, "") == 0) { tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID); return tevent_req_post(req, ev); } - if (strchr_m(in_file_name, '\\') != NULL) { + if (strchr_m(state->in_file_name, '\\') != NULL) { tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID); return tevent_req_post(req, ev); } - if (strchr_m(in_file_name, '/') != NULL) { + if (strchr_m(state->in_file_name, '/') != NULL) { tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID); return tevent_req_post(req, ev); } - p = strptime(in_file_name, GMT_FORMAT, &tm); + p = strptime(state->in_file_name, GMT_FORMAT, &tm); if ((p != NULL) && (*p =='\0')) { /* * Bogus find that asks for a shadow copy timestamp as a @@ -315,27 +323,27 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, switch (in_file_info_class) { case SMB2_FIND_DIRECTORY_INFO: - info_level = SMB_FIND_FILE_DIRECTORY_INFO; + state->info_level = SMB_FIND_FILE_DIRECTORY_INFO; break; case SMB2_FIND_FULL_DIRECTORY_INFO: - info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; + state->info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; break; case SMB2_FIND_BOTH_DIRECTORY_INFO: - info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO; + state->info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO; break; case SMB2_FIND_NAME_INFO: - info_level = SMB_FIND_FILE_NAMES_INFO; + state->info_level = SMB_FIND_FILE_NAMES_INFO; break; case SMB2_FIND_ID_BOTH_DIRECTORY_INFO: - info_level = SMB_FIND_ID_BOTH_DIRECTORY_INFO; + state->info_level = SMB_FIND_ID_BOTH_DIRECTORY_INFO; break; case SMB2_FIND_ID_FULL_DIRECTORY_INFO: - info_level = SMB_FIND_ID_FULL_DIRECTORY_INFO; + state->info_level = SMB_FIND_ID_FULL_DIRECTORY_INFO; break; default: @@ -366,8 +374,8 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, } } - if (!smbreq->posix_pathnames) { - wcard_has_wild = ms_has_wild(in_file_name); + if (!state->smbreq->posix_pathnames) { + wcard_has_wild = ms_has_wild(state->in_file_name); } /* Ensure we've canonicalized any search path if not a wildcard. */ @@ -378,17 +386,17 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, char *to_free = NULL; uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP | - (smbreq->posix_pathnames ? + (state->smbreq->posix_pathnames ? UCF_POSIX_PATHNAMES : 0); if (ISDOT(fsp->fsp_name->base_name)) { - fullpath = in_file_name; + fullpath = state->in_file_name; } else { size_t len; char *tmp; len = full_path_tos( - fsp->fsp_name->base_name, in_file_name, + fsp->fsp_name->base_name, state->in_file_name, tmpbuf, sizeof(tmpbuf), &tmp, &to_free); if (len == -1) { tevent_req_oom(req); @@ -409,7 +417,7 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - in_file_name = smb_fname->original_lcomp; + state->in_file_name = smb_fname->original_lcomp; } if (fsp->dptr == NULL) { @@ -420,18 +428,18 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, false, /* old_handle */ false, /* expect_close */ 0, /* spid */ - in_file_name, /* wcard */ + state->in_file_name, /* wcard */ wcard_has_wild, - dirtype, + state->dirtype, &fsp->dptr); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return tevent_req_post(req, ev); } - empty_status = NT_STATUS_NO_SUCH_FILE; + state->empty_status = NT_STATUS_NO_SUCH_FILE; } else { - empty_status = STATUS_NO_MORE_FILES; + state->empty_status = STATUS_NO_MORE_FILES; } if (in_flags & SMB2_CONTINUE_FLAG_RESTART) { @@ -439,9 +447,9 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, } if (in_flags & SMB2_CONTINUE_FLAG_SINGLE) { - max_count = 1; + state->max_count = 1; } else { - max_count = UINT16_MAX; + state->max_count = UINT16_MAX; } #define DIR_ENTRY_SAFETY_MARGIN 4096 @@ -453,16 +461,13 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, } state->out_output_buffer.length = 0; - pdata = (char *)state->out_output_buffer.data; - base_data = pdata; + state->pdata = (char *)state->out_output_buffer.data; + state->base_data = state->pdata; /* * end_data must include the safety margin as it's what is * used to determine if pushed strings have been truncated. */ - end_data = pdata + in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN - 1; - last_entry_off = 0; - off = 0; - num = 0; + state->end_data = state->pdata + in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN - 1; DEBUG(8,("smbd_smb2_query_directory_send: dirpath=<%s> dontdescend=<%s>, " "in_output_buffer_length = %u\n", @@ -470,7 +475,7 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, (unsigned int)in_output_buffer_length )); if (in_list(fsp->fsp_name->base_name,lp_dont_descend(talloc_tos(), SNUM(conn)), conn->case_sensitive)) { - dont_descend = true; + state->dont_descend = true; } /* @@ -479,15 +484,14 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, * This may change when we try to improve the delete on close * handling in future. */ - if (info_level != SMB_FIND_FILE_NAMES_INFO) { - ask_sharemode = lp_parm_bool(SNUM(conn), - "smbd", "search ask sharemode", - true); + if (state->info_level != SMB_FIND_FILE_NAMES_INFO) { + state->ask_sharemode = lp_parm_bool( + SNUM(conn), "smbd", "search ask sharemode", true); } - if (ask_sharemode && lp_clustering()) { - ask_sharemode = false; - async_ask_sharemode = true; + if (state->ask_sharemode && lp_clustering()) { + state->ask_sharemode = false; + state->async_ask_sharemode = true; /* * Should we only set async_internal @@ -504,127 +508,139 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, "find async delay usec", 0); - while (true) { - bool got_exact_match = false; - int space_remaining = in_output_buffer_length - off; - struct file_id file_id; - bool stop = false; - - SMB_ASSERT(space_remaining >= 0); - - status = smbd_dirptr_lanman2_entry(state, - conn, - fsp->dptr, - smbreq->flags2, - in_file_name, - dirtype, - info_level, - false, /* requires_resume_key */ - dont_descend, - ask_sharemode, - true, - 8, /* align to 8 bytes */ - false, /* no padding */ - &pdata, - base_data, - end_data, - space_remaining, - &got_exact_match, - &last_entry_off, - NULL, - &file_id); - - off = (int)PTR_DIFF(pdata, base_data); + while (!stop) { + stop = smb2_query_directory_next_entry(req); + } - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) { - /* - * Bad character conversion on name. Ignore this - * entry. - */ - continue; - } else if (num > 0) { - goto last_entry_done; - } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { - tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH); - return tevent_req_post(req, ev); - } else { - tevent_req_nterror(req, empty_status); - return tevent_req_post(req, ev); - } - } + if (!tevent_req_is_in_progress(req)) { + return tevent_req_post(req, ev); + } - if (async_ask_sharemode) { - struct tevent_req *subreq = NULL; - - subreq = fetch_write_time_send(req, - ev, - conn, - file_id, - info_level, - base_data + last_entry_off, - &stop); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback( - subreq, - smb2_query_directory_fetch_write_time_done, - req); + return req; +} + +static bool smb2_query_directory_next_entry(struct tevent_req *req) +{ + struct smbd_smb2_query_directory_state *state = tevent_req_data( + req, struct smbd_smb2_query_directory_state); + bool got_exact_match = false; + int off = state->out_output_buffer.length; + int space_remaining = state->in_output_buffer_length - off; + struct file_id file_id; + NTSTATUS status; + bool stop = false; + + SMB_ASSERT(space_remaining >= 0); + + status = smbd_dirptr_lanman2_entry(state, + state->fsp->conn, + state->fsp->dptr, + state->smbreq->flags2, + state->in_file_name, + state->dirtype, + state->info_level, + false, /* requires_resume_key */ + state->dont_descend, + state->ask_sharemode, + true, + 8, /* align to 8 bytes */ + false, /* no padding */ + &state->pdata, + state->base_data, + state->end_data, + space_remaining, + &got_exact_match, + &state->last_entry_off, + NULL, + &file_id); + + off = (int)PTR_DIFF(state->pdata, state->base_data); - state->async_count++; + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) { + /* + * Bad character conversion on name. Ignore this + * entry. + */ + return false; + } else if (state->num > 0) { + goto last_entry_done; + } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { + tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH); + return true; + } else { + tevent_req_nterror(req, state->empty_status); + return true; } + } - num++; - state->out_output_buffer.length = off; + if (state->async_ask_sharemode) { + struct tevent_req *subreq = NULL; - if (num >= max_count) { - stop = true; + subreq = fetch_write_time_send(state, + state->ev, + state->fsp->conn, + file_id, + state->info_level, + state->base_data + state->last_entry_off, + &stop); + if (tevent_req_nomem(subreq, req)) { + return true; } + tevent_req_set_callback( + subreq, + smb2_query_directory_fetch_write_time_done, + req); + state->async_sharemode_count++; + } - if (!stop) { - continue; - } + state->num++; + state->out_output_buffer.length = off; + + if (!state->done && state->num < state->max_count) { + return stop; + } last_entry_done: - SIVAL(state->out_output_buffer.data, last_entry_off, 0); - if (state->async_count > 0) { - DBG_DEBUG("Stopping after %"PRIu64" async mtime " - "updates\n", state->async_count); - return req; - } + SIVAL(state->out_output_buffer.data, state->last_entry_off, 0); - if (state->find_async_delay_usec > 0) { - struct timeval tv; - struct tevent_req *subreq = NULL; + state->done = true; - /* - * Should we only set async_internal - * if we're not the last request in - * a compound chain? - */ - smb2_request_set_async_internal(smb2req, true); + if (state->async_sharemode_count > 0) { + DBG_DEBUG("Stopping after %"PRIu64" async mtime " + "updates\n", state->async_sharemode_count); + return true; + } - tv = timeval_current_ofs(0, state->find_async_delay_usec); + if (state->find_async_delay_usec > 0) { + struct timeval tv; + struct tevent_req *subreq = NULL; - subreq = tevent_wakeup_send(state, ev, tv); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, - smb2_query_directory_waited, - req); - return req; - } + /* + * Should we only set async_internal + * if we're not the last request in + * a compound chain? + */ + smb2_request_set_async_internal(state->smb2req, true); - tevent_req_done(req); - return tevent_req_post(req, ev); + tv = timeval_current_ofs(0, state->find_async_delay_usec); + + subreq = tevent_wakeup_send(state, state->ev, tv); + if (tevent_req_nomem(subreq, req)) { + return true; + } + tevent_req_set_callback(subreq, + smb2_query_directory_waited, + req); + return req; } - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); - return tevent_req_post(req, ev); + tevent_req_done(req); + return true; } +static void smb2_query_directory_check_next_entry(struct tevent_req *req); + static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( @@ -633,7 +649,7 @@ static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq req, struct smbd_smb2_query_directory_state); NTSTATUS status; - state->async_count--; + state->async_sharemode_count--; status = fetch_write_time_recv(subreq); TALLOC_FREE(subreq); @@ -641,12 +657,30 @@ static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq return; } - if (state->async_count > 0) { + smb2_query_directory_check_next_entry(req); + return; +} + +static void smb2_query_directory_check_next_entry(struct tevent_req *req) +{ + struct smbd_smb2_query_directory_state *state = tevent_req_data( + req, struct smbd_smb2_query_directory_state); + bool stop = false; + + if (!state->done) { + while (!stop) { + stop = smb2_query_directory_next_entry(req); + } + return; + } + + if (state->async_sharemode_count > 0) { return; } if (state->find_async_delay_usec > 0) { struct timeval tv; + struct tevent_req *subreq = NULL; tv = timeval_current_ofs(0, state->find_async_delay_usec);