return status;
}
-NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
- uint32_t buffer_size, uint32_t completion_filter,
- bool recursive, TALLOC_CTX *mem_ctx,
- struct notify_change **pchanges,
- uint32_t *pnum_changes)
+struct cli_smb2_notify_state {
+ struct tevent_req *subreq;
+ struct notify_change *changes;
+ size_t num_changes;
+};
+
+static void cli_smb2_notify_done(struct tevent_req *subreq);
+static bool cli_smb2_notify_cancel(struct tevent_req *req);
+
+struct tevent_req *cli_smb2_notify_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint32_t buffer_size,
+ uint32_t completion_filter,
+ bool recursive)
{
- NTSTATUS status;
+ struct tevent_req *req = NULL;
+ struct cli_smb2_notify_state *state = NULL;
struct smb2_hnd *ph = NULL;
- TALLOC_CTX *frame = talloc_stackframe();
- uint8_t *base;
- uint32_t len, ofs;
- struct notify_change *changes = NULL;
- size_t num_changes = 0;
+ NTSTATUS status;
- if (smbXcli_conn_has_async_calls(cli->conn)) {
- /*
- * Can't use sync call while an async call is in flight
- */
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_smb2_notify_state);
+ if (req == NULL) {
+ return NULL;
}
if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
}
status = map_fnum_to_smb2_handle(cli, fnum, &ph);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- status = smb2cli_notify(cli->conn, cli->timeout,
- cli->smb2.session, cli->smb2.tcon,
- buffer_size,
- ph->fid_persistent, ph->fid_volatile,
- completion_filter, recursive,
- frame, &base, &len);
+ state->subreq = smb2cli_notify_send(
+ state,
+ ev,
+ cli->conn,
+ cli->timeout,
+ cli->smb2.session,
+ cli->smb2.tcon,
+ buffer_size,
+ ph->fid_persistent,
+ ph->fid_volatile,
+ completion_filter,
+ recursive);
+ if (tevent_req_nomem(state->subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
+ tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
+ return req;
+}
+
+static bool cli_smb2_notify_cancel(struct tevent_req *req)
+{
+ struct cli_smb2_notify_state *state = tevent_req_data(
+ req, struct cli_smb2_notify_state);
+ bool ok;
+
+ ok = tevent_req_cancel(state->subreq);
+ return ok;
+}
+
+static void cli_smb2_notify_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_smb2_notify_state *state = tevent_req_data(
+ req, struct cli_smb2_notify_state);
+ uint8_t *base;
+ uint32_t len;
+ uint32_t ofs;
+ NTSTATUS status;
+
+ status = smb2cli_notify_recv(subreq, state, &base, &len);
+ TALLOC_FREE(subreq);
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
- len = 0;
- status = NT_STATUS_OK;
+ tevent_req_done(req);
+ return;
}
-
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+ if (tevent_req_nterror(req, status)) {
+ return;
}
ofs = 0;
size_t namelen;
bool ok;
- tmp = talloc_realloc(frame, changes, struct notify_change,
- num_changes + 1);
- if (tmp == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
+ tmp = talloc_realloc(
+ state,
+ state->changes,
+ struct notify_change,
+ state->num_changes + 1);
+ if (tevent_req_nomem(tmp, req)) {
+ return;
}
- changes = tmp;
- c = &changes[num_changes];
- num_changes += 1;
+ state->changes = tmp;
+ c = &state->changes[state->num_changes];
+ state->num_changes += 1;
if (smb_buffer_oob(len, ofs, next_ofs) ||
smb_buffer_oob(len, ofs+12, file_name_length)) {
- status = NT_STATUS_INVALID_NETWORK_RESPONSE;
- goto fail;
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
c->action = IVAL(base, ofs+4);
- ok = convert_string_talloc(changes, CH_UTF16LE, CH_UNIX,
- base + ofs + 12, file_name_length,
- &c->name, &namelen);
+ ok = convert_string_talloc(
+ state->changes,
+ CH_UTF16LE,
+ CH_UNIX,
+ base + ofs + 12,
+ file_name_length,
+ &c->name,
+ &namelen);
if (!ok) {
- status = NT_STATUS_INVALID_NETWORK_RESPONSE;
- goto fail;
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
if (next_ofs == 0) {
ofs += next_ofs;
}
- *pchanges = talloc_move(mem_ctx, &changes);
- *pnum_changes = num_changes;
- status = NT_STATUS_OK;
+ tevent_req_done(req);
+}
-fail:
- cli->raw_status = status;
+NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct notify_change **pchanges,
+ uint32_t *pnum_changes)
+{
+ struct cli_smb2_notify_state *state = tevent_req_data(
+ req, struct cli_smb2_notify_state);
+ NTSTATUS status;
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *pchanges = talloc_move(mem_ctx, &state->changes);
+ *pnum_changes = state->num_changes;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
+ uint32_t buffer_size, uint32_t completion_filter,
+ bool recursive, TALLOC_CTX *mem_ctx,
+ struct notify_change **pchanges,
+ uint32_t *pnum_changes)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_smb2_notify_send(
+ frame,
+ ev,
+ cli,
+ fnum,
+ buffer_size,
+ completion_filter,
+ recursive);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
+fail:
TALLOC_FREE(frame);
return status;
}