static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint16_t in_flags, uint32_t in_output_buffer_length, uint64_t in_completion_filter) { struct tevent_req *req; struct smbd_smb2_notify_state *state; struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat_conn; bool recursive = (in_flags & 0x0001) ? true : false; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_notify_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->status = NT_STATUS_INTERNAL_ERROR; state->out_output_buffer = data_blob_null; state->im = NULL; DEBUG(10,("smbd_smb2_notify_send: %s - fnum[%d]\n", fsp_str_dbg(fsp), fsp->fnum)); smbreq = smbd_smb2_fake_smb_request(smb2req); if (tevent_req_nomem(smbreq, req)) { return tevent_req_post(req, ev); } state->smbreq = smbreq; smbreq->async_priv = (void *)req; { char *filter_string; filter_string = notify_filter_string(NULL, in_completion_filter); if (tevent_req_nomem(filter_string, req)) { return tevent_req_post(req, ev); } DEBUG(3,("smbd_smb2_notify_send: notify change " "called on %s, filter = %s, recursive = %d\n", fsp_str_dbg(fsp), filter_string, recursive)); TALLOC_FREE(filter_string); } if ((!fsp->is_directory) || (conn != fsp->conn)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } if (fsp->notify == NULL) { status = change_notify_create(fsp, in_completion_filter, recursive); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("change_notify_create returned %s\n", nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } if (fsp->notify->num_changes != 0) { /* * We've got changes pending, respond immediately */ /* * TODO: write a torture test to check the filtering behaviour * here. */ change_notify_reply(smbreq, NT_STATUS_OK, in_output_buffer_length, fsp->notify, smbd_smb2_notify_reply); /* * change_notify_reply() above has independently * called tevent_req_done(). */ return tevent_req_post(req, ev); } state->im = tevent_create_immediate(state); if (tevent_req_nomem(state->im, req)) { return tevent_req_post(req, ev); } /* * No changes pending, queue the request */ status = change_notify_add_request(smbreq, in_output_buffer_length, in_completion_filter, recursive, fsp, smbd_smb2_notify_reply); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return tevent_req_post(req, ev); } /* allow this request to be canceled */ tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel); return req; }
static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, struct files_struct *fsp, uint16_t in_flags, uint32_t in_output_buffer_length, uint64_t in_completion_filter) { struct tevent_req *req; struct smbd_smb2_notify_state *state; struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat; bool recursive = (in_flags & SMB2_WATCH_TREE) ? true : false; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_notify_state); if (req == NULL) { return NULL; } state->smb2req = smb2req; state->status = NT_STATUS_INTERNAL_ERROR; state->out_output_buffer = data_blob_null; talloc_set_destructor(state, smbd_smb2_notify_state_destructor); DEBUG(10,("smbd_smb2_notify_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)) { return tevent_req_post(req, ev); } state->smbreq = smbreq; smbreq->async_priv = (void *)req; if (DEBUGLEVEL >= 3) { char *filter_string; filter_string = notify_filter_string(NULL, in_completion_filter); if (tevent_req_nomem(filter_string, req)) { return tevent_req_post(req, ev); } DEBUG(3,("smbd_smb2_notify_send: notify change " "called on %s, filter = %s, recursive = %d\n", fsp_str_dbg(fsp), filter_string, recursive)); TALLOC_FREE(filter_string); } if ((!fsp->is_directory) || (conn != fsp->conn)) { tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } if (fsp->notify == NULL) { status = change_notify_create(fsp, in_completion_filter, recursive); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("change_notify_create returned %s\n", nt_errstr(status))); tevent_req_nterror(req, status); return tevent_req_post(req, ev); } } if (change_notify_fsp_has_changes(fsp)) { /* * We've got changes pending, respond immediately */ /* * TODO: write a torture test to check the filtering behaviour * here. */ change_notify_reply(smbreq, NT_STATUS_OK, in_output_buffer_length, fsp->notify, smbd_smb2_notify_reply); /* * change_notify_reply() above has independently * called tevent_req_done(). */ return tevent_req_post(req, ev); } /* * No changes pending, queue the request */ status = change_notify_add_request(smbreq, in_output_buffer_length, in_completion_filter, recursive, fsp, smbd_smb2_notify_reply); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return tevent_req_post(req, ev); } /* * This is a HACK! * * change_notify_add_request() talloc_moves() * smbreq away from us, so we need a destructor * which moves it back at the end. */ state->has_request = true; talloc_set_destructor(smbreq, smbd_smb2_notify_smbreq_destructor); /* allow this request to be canceled */ tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel); SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(state->smb2req->profile); return req; }