From dc5c7b7f98345621f4cf1b9992ebbe9144e14ebb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 10 Jun 2009 11:58:00 -0700 Subject: Make ctemp async. Fix the test to pass against W2K3. Jeremy. --- source3/include/proto.h | 14 +++- source3/lib/charcnv.c | 4 +- source3/libsmb/clifile.c | 171 ++++++++++++++++++++++++++++++++++++---------- source3/torture/torture.c | 3 +- 4 files changed, 150 insertions(+), 42 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 40855a0650..9b297155e9 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2582,7 +2582,19 @@ struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx, NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail); NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail); -int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path); +struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *path); +NTSTATUS cli_ctemp_recv(struct tevent_req *req, + TALLOC_CTX *ctx, + uint16_t *pfnum, + char **outfile); +NTSTATUS cli_ctemp(struct cli_state *cli, + TALLOC_CTX *ctx, + const char *path, + uint16_t *pfnum, + char **out_path); NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob); bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len); bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len); diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c index 791c866b57..a1663c1f38 100644 --- a/source3/lib/charcnv.c +++ b/source3/lib/charcnv.c @@ -1046,9 +1046,7 @@ size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, /** * Copy a string from a dos codepage source to a unix char* destination. - Talloc version. - Uses malloc if TALLOC_CTX is NULL (this is a bad interface and - needs fixing. JRA). + * Talloc version. * * The resulting string in "dest" is always null terminated. * diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index a2f089c5e9..af67fcb746 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3740,57 +3740,156 @@ NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) Create and open a temporary file. ****************************************************************************/ -int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path) +static void cli_ctemp_done(struct tevent_req *subreq); + +struct ctemp_state { + uint16_t vwv[3]; + char *ret_path; + uint16_t fnum; +}; + +struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *path) { - int len; - char *p; + struct tevent_req *req = NULL, *subreq = NULL; + struct ctemp_state *state = NULL; + uint8_t additional_flags = 0; + uint8_t *bytes = NULL; - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); + req = tevent_req_create(mem_ctx, &state, struct ctemp_state); + if (req == NULL) { + return NULL; + } - cli_set_message(cli->outbuf,3,0,True); + SSVAL(state->vwv,0,0); + SIVALS(state->vwv+1,0,-1); - SCVAL(cli->outbuf,smb_com,SMBctemp); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + bytes = talloc_array(state, uint8_t, 1); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + bytes[0] = 4; + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path, + strlen(path)+1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - SSVAL(cli->outbuf,smb_vwv0,0); - SIVALS(cli->outbuf,smb_vwv1,-1); + subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags, + 3, state->vwv, talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_ctemp_done, req); + return req; +} - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, path, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); +static void cli_ctemp_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctemp_state *state = tevent_req_data( + req, struct ctemp_state); + NTSTATUS status; + uint8_t wcnt; + uint16_t *vwv; + uint32_t num_bytes = 0; + uint8_t *bytes = NULL; - cli_setup_bcc(cli, p); + status = cli_smb_recv(subreq, 1, &wcnt, &vwv, &num_bytes, &bytes); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return -1; + state->fnum = SVAL(vwv+0, 0); + + /* From W2K3, the result is just the ASCII name */ + if (num_bytes < 2) { + tevent_req_nterror(req, NT_STATUS_DATA_ERROR); + return; } - if (cli_is_error(cli)) { - return -1; + if (pull_string_talloc(state, + NULL, + 0, + &state->ret_path, + bytes, + num_bytes, + STR_ASCII) == 0) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; } + tevent_req_done(req); +} - /* despite the spec, the result has a -1, followed by - length, followed by name */ - p = smb_buf(cli->inbuf); - p += 4; - len = smb_buflen(cli->inbuf) - 4; - if (len <= 0 || len > PATH_MAX) return -1; +NTSTATUS cli_ctemp_recv(struct tevent_req *req, + TALLOC_CTX *ctx, + uint16_t *pfnum, + char **outfile) +{ + struct ctemp_state *state = tevent_req_data(req, + struct ctemp_state); + NTSTATUS status; - if (tmp_path) { - char *path2 = SMB_MALLOC_ARRAY(char, len+1); - if (!path2) { - return -1; - } - clistr_pull(cli->inbuf, path2, p, - len+1, len, STR_ASCII); - *tmp_path = path2; + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *pfnum = state->fnum; + *outfile = talloc_strdup(ctx, state->ret_path); + if (!*outfile) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; +} + +NTSTATUS cli_ctemp(struct cli_state *cli, + TALLOC_CTX *ctx, + const char *path, + uint16_t *pfnum, + char **out_path) +{ + 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_ctemp_send(frame, ev, cli, path); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - return SVAL(cli->inbuf,smb_vwv0); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = cli_ctemp_recv(req, ctx, pfnum, out_path); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /* diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 056b74adea..baa8a15da4 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -3908,8 +3908,7 @@ static bool run_opentest(int dummy) printf("testing ctemp\n"); - fnum1 = cli_ctemp(cli1, "\\", &tmp_path); - if (fnum1 == (uint16_t)-1) { + if (!NT_STATUS_IS_OK(cli_ctemp(cli1, talloc_tos(), "\\", &fnum1, &tmp_path))) { printf("ctemp failed (%s)\n", cli_errstr(cli1)); return False; } -- cgit