[SCM] Samba Shared Repository - branch v3-4-test updated

Karolin Seeger kseeger at samba.org
Thu Oct 15 01:04:58 MDT 2009


The branch, v3-4-test has been updated
       via  c685beb... s3: Fix bug 6606
      from  0fc6494... s3:winbind: Fix a double-free

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-4-test


- Log -----------------------------------------------------------------
commit c685beb091cb0fedfb3f64bcc2ec2beb00fc9328
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Oct 10 11:15:42 2009 +0200

    s3: Fix bug 6606
    
    This is a port of 1f34ffa0caae5 and 24309bdb2efc to 3.4.
    
    Fix file corruption using smbclient with NT4 server.

-----------------------------------------------------------------------

Summary of changes:
 source3/libsmb/clireadwrite.c |  189 +++++++++++++++++++++++++++++++++++------
 1 files changed, 164 insertions(+), 25 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index b1064ba..e6c7fb4 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -195,6 +195,135 @@ NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
 	return NT_STATUS_OK;
 }
 
+struct cli_readall_state {
+	struct tevent_context *ev;
+	struct cli_state *cli;
+	uint16_t fnum;
+	off_t start_offset;
+	size_t size;
+	size_t received;
+	uint8_t *buf;
+};
+
+static void cli_readall_done(struct async_req *subreq);
+
+static struct async_req *cli_readall_send(TALLOC_CTX *mem_ctx,
+					  struct event_context *ev,
+					  struct cli_state *cli,
+					  uint16_t fnum,
+					  off_t offset, size_t size)
+{
+	struct async_req *req, *subreq;
+	struct cli_readall_state *state;
+
+	if (!async_req_setup(mem_ctx, &req, &state,
+			     struct cli_readall_state)) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->cli = cli;
+	state->fnum = fnum;
+	state->start_offset = offset;
+	state->size = size;
+	state->received = 0;
+	state->buf = NULL;
+
+	subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size);
+	if (async_req_nomem(subreq, req)) {
+		TALLOC_FREE(req);
+		return NULL;
+	}
+	subreq->async.fn = cli_readall_done;
+	subreq->async.priv = req;
+	return req;
+}
+
+static void cli_readall_done(struct async_req *subreq)
+{
+	struct async_req *req = talloc_get_type_abort(
+		subreq->async.priv, struct async_req);
+	struct cli_readall_state *state = talloc_get_type_abort(
+		req->private_data, struct cli_readall_state);
+	ssize_t received;
+	uint8_t *buf;
+	NTSTATUS status;
+
+	status = cli_read_andx_recv(subreq, &received, &buf);
+	if (!NT_STATUS_IS_OK(status)) {
+		async_req_nterror(req, status);
+		return;
+	}
+
+	if (received == 0) {
+		/* EOF */
+		async_req_done(req);
+		return;
+	}
+
+	if ((state->received == 0) && (received == state->size)) {
+		/* Ideal case: Got it all in one run */
+		state->buf = buf;
+		state->received += received;
+		async_req_done(req);
+		return;
+	}
+
+	/*
+	 * We got a short read, issue a read for the
+	 * rest. Unfortunately we have to allocate the buffer
+	 * ourselves now, as our caller expects to receive a single
+	 * buffer. cli_read_andx does it from the buffer received from
+	 * the net, but with a short read we have to put it together
+	 * from several reads.
+	 */
+
+	if (state->buf == NULL) {
+		state->buf = talloc_array(state, uint8_t, state->size);
+		if (async_req_nomem(state->buf, req)) {
+			return;
+		}
+	}
+	memcpy(state->buf + state->received, buf, received);
+	state->received += received;
+
+	TALLOC_FREE(subreq);
+
+	if (state->received >= state->size) {
+		async_req_done(req);
+		return;
+	}
+
+	subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum,
+				    state->start_offset + state->received,
+				    state->size - state->received);
+	if (async_req_nomem(subreq, req)) {
+		return;
+	}
+	subreq->async.fn = cli_readall_done;
+	subreq->async.priv = req;
+}
+
+static NTSTATUS cli_readall_recv(struct async_req *req, ssize_t *received,
+				 uint8_t **rcvbuf)
+{
+	struct cli_readall_state *state = talloc_get_type_abort(
+		req->private_data, struct cli_readall_state);
+	NTSTATUS status;
+
+	if (async_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*received = state->received;
+	*rcvbuf = state->buf;
+	return NT_STATUS_OK;
+}
+
+struct cli_pull_subreq {
+	struct async_req *req;
+	ssize_t received;
+	uint8_t *buf;
+};
+
 /*
  * Parallel read support.
  *
@@ -221,7 +350,7 @@ struct cli_pull_state {
 	 * Outstanding requests
 	 */
 	int num_reqs;
-	struct async_req **reqs;
+	struct cli_pull_subreq *reqs;
 
 	/*
 	 * For how many bytes did we send requests already?
@@ -308,7 +437,7 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
 	state->num_reqs = MAX(window_size/state->chunk_size, 1);
 	state->num_reqs = MIN(state->num_reqs, cli->max_mux);
 
-	state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *,
+	state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_pull_subreq,
 					state->num_reqs);
 	if (state->reqs == NULL) {
 		goto failed;
@@ -317,6 +446,7 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
 	state->requested = 0;
 
 	for (i=0; i<state->num_reqs; i++) {
+		struct cli_pull_subreq *subreq = &state->reqs[i];
 		SMB_OFF_T size_left;
 		size_t request_thistime;
 
@@ -328,17 +458,17 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
 		size_left = size - state->requested;
 		request_thistime = MIN(size_left, state->chunk_size);
 
-		state->reqs[i] = cli_read_andx_send(
+		subreq->req = cli_readall_send(
 			state->reqs, ev, cli, fnum,
 			state->start_offset + state->requested,
 			request_thistime);
 
-		if (state->reqs[i] == NULL) {
+		if (subreq->req == NULL) {
 			goto failed;
 		}
 
-		state->reqs[i]->async.fn = cli_pull_read_done;
-		state->reqs[i]->async.priv = result;
+		subreq->req->async.fn = cli_pull_read_done;
+		subreq->req->async.priv = result;
 
 		state->requested += request_thistime;
 	}
@@ -360,12 +490,24 @@ static void cli_pull_read_done(struct async_req *read_req)
 		read_req->async.priv, struct async_req);
 	struct cli_pull_state *state = talloc_get_type_abort(
 		pull_req->private_data, struct cli_pull_state);
-	struct cli_request *read_state = talloc_get_type_abort(
-		read_req->private_data, struct cli_request);
+	struct cli_pull_subreq *pull_subreq = NULL;
 	NTSTATUS status;
+	int i;
+
+	for (i = 0; i < state->num_reqs; i++) {
+		pull_subreq = &state->reqs[i];
+		if (read_req == pull_subreq->req) {
+			break;
+		}
+	}
+	if (i == state->num_reqs) {
+		/* Huh -- received something we did not send?? */
+		async_req_nterror(pull_req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
 
-	status = cli_read_andx_recv(read_req, &read_state->data.read.received,
-				    &read_state->data.read.rcvbuf);
+	status = cli_readall_recv(read_req, &pull_subreq->received,
+				  &pull_subreq->buf);
 	if (!NT_STATUS_IS_OK(status)) {
 		async_req_nterror(state->req, status);
 		return;
@@ -380,36 +522,33 @@ static void cli_pull_read_done(struct async_req *read_req)
 	 * requests.
 	 */
 
-	while (state->reqs[state->top_req] != NULL) {
-		struct cli_request *top_read;
+	while (state->reqs[state->top_req].req != NULL) {
+		struct cli_pull_subreq *top_read;
 
 		DEBUG(11, ("cli_pull_read_done: top_req = %d\n",
 			   state->top_req));
 
-		if (state->reqs[state->top_req]->state < ASYNC_REQ_DONE) {
+		top_read = &state->reqs[state->top_req];
+
+		if (state->reqs[state->top_req].req->state < ASYNC_REQ_DONE) {
 			DEBUG(11, ("cli_pull_read_done: top request not yet "
 				   "done\n"));
 			return;
 		}
 
-		top_read = talloc_get_type_abort(
-			state->reqs[state->top_req]->private_data,
-			struct cli_request);
-
 		DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already "
-			   "pushed\n", (int)top_read->data.read.received,
+			   "pushed\n", (int)top_read->received,
 			   (int)state->pushed));
 
-		status = state->sink((char *)top_read->data.read.rcvbuf,
-				     top_read->data.read.received,
-				     state->priv);
+		status = state->sink((char *)top_read->buf,
+				     top_read->received, state->priv);
 		if (!NT_STATUS_IS_OK(status)) {
 			async_req_nterror(state->req, status);
 			return;
 		}
-		state->pushed += top_read->data.read.received;
+		state->pushed += top_read->received;
 
-		TALLOC_FREE(state->reqs[state->top_req]);
+		TALLOC_FREE(state->reqs[state->top_req].req);
 
 		if (state->requested < state->size) {
 			struct async_req *new_req;
@@ -426,7 +565,7 @@ static void cli_pull_read_done(struct async_req *read_req)
 					 + state->requested),
 				   state->top_req));
 
-			new_req = cli_read_andx_send(
+			new_req = cli_readall_send(
 				state->reqs, state->ev, state->cli,
 				state->fnum,
 				state->start_offset + state->requested,
@@ -439,7 +578,7 @@ static void cli_pull_read_done(struct async_req *read_req)
 			new_req->async.fn = cli_pull_read_done;
 			new_req->async.priv = pull_req;
 
-			state->reqs[state->top_req] = new_req;
+			state->reqs[state->top_req].req = new_req;
 			state->requested += request_thistime;
 		}
 


-- 
Samba Shared Repository


More information about the samba-cvs mailing list