From: Volker Lendecke Date: Wed, 4 Apr 2018 14:18:28 +0000 (+0200) Subject: libsmb: Add protocol-agnostic cli_read X-Git-Tag: tdb-1.3.17~2004 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5c4d91ebf6527001a2cc8a316db931768ec8249;p=thirdparty%2Fsamba.git libsmb: Add protocol-agnostic cli_read So far only cli_pull could be called directly without looking at the protocol. We did not have a simple read that did the right thing depending on the protocol Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 67870d8c40b..a93f35727a0 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -700,6 +700,128 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, return status; } +struct cli_read_state { + struct cli_state *cli; + char *buf; + size_t buflen; + size_t received; +}; + +static void cli_read_done(struct tevent_req *subreq); + +struct tevent_req *cli_read_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + char *buf, + off_t offset, + size_t size) +{ + struct tevent_req *req, *subreq; + struct cli_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_read_state); + if (req == NULL) { + return NULL; + } + state->cli = cli; + state->buf = buf; + state->buflen = size; + + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + uint32_t max_size; + bool ok; + + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (!ok) { + tevent_req_nterror( + req, + NT_STATUS_INSUFFICIENT_RESOURCES); + return tevent_req_post(req, ev); + } + + /* + * downgrade depending on the available credits + */ + size = MIN(max_size, size); + + subreq = cli_smb2_read_send( + state, ev, cli, fnum, offset, size); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + } else { + bool ok; + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + tevent_req_nterror( + req, + NT_STATUS_INSUFFICIENT_RESOURCES); + return tevent_req_post(req, ev); + } + + subreq = cli_read_andx_send( + state, ev, cli, fnum, offset, size); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + } + + tevent_req_set_callback(subreq, cli_read_done, req); + + return req; +} + +static void cli_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_read_state *state = tevent_req_data( + req, struct cli_read_state); + NTSTATUS status; + ssize_t received; + uint8_t *buf; + + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_read_recv(subreq, &received, &buf); + } else { + status = cli_read_andx_recv(subreq, &received, &buf); + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { + received = 0; + status = NT_STATUS_OK; + } + if (tevent_req_nterror(req, status)) { + return; + } + if ((received < 0) || (received > state->buflen)) { + state->received = 0; + tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR); + return; + } + + memcpy(state->buf, buf, received); + state->received = received; + tevent_req_done(req); +} + +NTSTATUS cli_read_recv(struct tevent_req *req, size_t *received) +{ + struct cli_read_state *state = tevent_req_data( + req, struct cli_read_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (received != NULL) { + *received = state->received; + } + return NT_STATUS_OK; +} + static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv) { char **pbuf = (char **)priv; diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 2bd61b1d2c2..06d0a0c9e06 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -839,6 +839,15 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, off_t start_offset, off_t size, size_t window_size, NTSTATUS (*sink)(char *buf, size_t n, void *priv), void *priv, off_t *received); +struct tevent_req *cli_read_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + char *buf, + off_t offset, + size_t size); +NTSTATUS cli_read_recv(struct tevent_req *req, size_t *received); NTSTATUS cli_read(struct cli_state *cli, uint16_t fnum, char *buf, off_t offset, size_t size, size_t *nread);