diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/proto.h | 5 | ||||
-rw-r--r-- | source3/libsmb/clioplock.c | 123 |
2 files changed, 99 insertions, 29 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 514ee68e7a..d76ee08fd2 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2644,6 +2644,11 @@ bool cli_message_end(struct cli_state *cli, int grp); /* The following definitions come from libsmb/clioplock.c */ +struct tevent_req *cli_oplock_ack_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, uint8_t level); +NTSTATUS cli_oplock_ack_recv(struct tevent_req *req); bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level); void cli_oplock_handler(struct cli_state *cli, bool (*handler)(struct cli_state *, int, unsigned char)); diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c index ef8b396461..e3fb66aba0 100644 --- a/source3/libsmb/clioplock.c +++ b/source3/libsmb/clioplock.c @@ -23,38 +23,103 @@ send an ack for an oplock break request ****************************************************************************/ -bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level) +struct cli_oplock_ack_state { + uint16_t vwv[8]; +}; + +static void cli_oplock_ack_done(struct tevent_req *subreq); + +struct tevent_req *cli_oplock_ack_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, uint8_t level) +{ + struct tevent_req *req, *subreq; + struct cli_oplock_ack_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_oplock_ack_state);; + if (req == NULL) { + return NULL; + } + SCVAL(state->vwv+0, 0, 0xff); + SCVAL(state->vwv+0, 1, 0); + SSVAL(state->vwv+1, 0, 0); + SSVAL(state->vwv+2, 0, fnum); + SCVAL(state->vwv+3, 0, LOCKING_ANDX_OPLOCK_RELEASE); + SCVAL(state->vwv+3, 1, level); + SIVAL(state->vwv+4, 0, 0); /* timeout */ + SSVAL(state->vwv+6, 0, 0); /* unlockcount */ + SSVAL(state->vwv+7, 0, 0); /* lockcount */ + + subreq = cli_smb_send(state, ev, cli, SMBlockingX, 0, 8, state->vwv, + 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_oplock_ack_done, req); + return req; +} + +static void cli_oplock_ack_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS cli_oplock_ack_recv(struct tevent_req *req) { - char *oldbuf = cli->outbuf; - char buf[smb_size+16]; - bool ret; - - cli->outbuf = buf; - - memset(buf,'\0',smb_size); - cli_set_message(buf,8,0,True); - - SCVAL(buf,smb_com,SMBlockingX); - SSVAL(buf,smb_tid, cli->cnum); - cli_setup_packet(cli); - SSVAL(buf,smb_vwv0,0xFF); - SSVAL(buf,smb_vwv1,0); - SSVAL(buf,smb_vwv2,fnum); - if (level == 1) - SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */ - else - SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */ - SIVAL(buf,smb_vwv4,0); /* timoeut */ - SSVAL(buf,smb_vwv6,0); /* unlockcount */ - SSVAL(buf,smb_vwv7,0); /* lockcount */ - - ret = cli_send_smb(cli); - - cli->outbuf = oldbuf; - - return ret; + return tevent_req_simple_recv_ntstatus(req); } +bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; + + if (cli_has_async_calls(cli)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_oplock_ack_send(frame, ev, cli, fnum, level); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = cli_oplock_ack_recv(req); + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return NT_STATUS_IS_OK(status); +} /**************************************************************************** set the oplock handler for a connection |