]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
libsmb: Add protocol-agnostic cli_read
authorVolker Lendecke <vl@samba.org>
Wed, 4 Apr 2018 14:18:28 +0000 (16:18 +0200)
committerJeremy Allison <jra@samba.org>
Mon, 27 Aug 2018 21:09:15 +0000 (23:09 +0200)
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 <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/libsmb/clireadwrite.c
source3/libsmb/proto.h

index 67870d8c40bc94881bd5a9f6456b3674d3f2e596..a93f35727a0dcd1f3e4e82a38c1b2d8aee866172 100644 (file)
@@ -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;
index 2bd61b1d2c24ccc55788b56627984f5deafdf101..06d0a0c9e062578785ecf878f8c6285f564246ee 100644 (file)
@@ -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);