X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Flibsmb%2Fclifile.c;h=fdfa257ec82d1dc49d52ee2bbeb21b9764d1271e;hb=7cc92a4828b5a49e311ef4ec652136ef1e3d83f1;hp=d3819af444825f301f046f079e35c1e392f89dfe;hpb=c82f268a1c1c5eff1cbdb410da3c717464bdbdd7;p=metze%2Fsamba%2Fwip.git diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d3819af44482..fdfa257ec82d 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. client file operations Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) Jeremy Allison 2001-2002 + Copyright (C) Jeremy Allison 2001-2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ static bool cli_link_internal(struct cli_state *cli, const char *oldname, const { unsigned int data_len = 0; unsigned int param_len = 0; - uint16 setup = TRANSACT2_SETPATHINFO; + uint16_t setup = TRANSACT2_SETPATHINFO; char *param; char *data; char *rparam=NULL, *rdata=NULL; @@ -66,7 +66,7 @@ static bool cli_link_internal(struct cli_state *cli, const char *oldname, const -1, 0, /* fid, flags */ &setup, 1, 0, /* setup, length, max */ param, param_len, 2, /* param, length, max */ - (char *)&data, data_len, cli->max_xmit /* data, length, max */ + data, data_len, cli->max_xmit /* data, length, max */ )) { SAFE_FREE(data); SAFE_FREE(param); @@ -94,7 +94,7 @@ static bool cli_link_internal(struct cli_state *cli, const char *oldname, const Map standard UNIX permissions onto wire representations. ****************************************************************************/ -uint32 unix_perms_to_wire(mode_t perms) +uint32_t unix_perms_to_wire(mode_t perms) { unsigned int ret = 0; @@ -123,7 +123,7 @@ uint32 unix_perms_to_wire(mode_t perms) Map wire permissions to standard UNIX. ****************************************************************************/ -mode_t wire_perms_to_unix(uint32 perms) +mode_t wire_perms_to_unix(uint32_t perms) { mode_t ret = (mode_t)0; @@ -152,7 +152,7 @@ mode_t wire_perms_to_unix(uint32 perms) Return the file type from the wire filetype for UNIX extensions. ****************************************************************************/ -static mode_t unix_filetype_from_wire(uint32 wire_type) +static mode_t unix_filetype_from_wire(uint32_t wire_type) { switch (wire_type) { case UNIX_TYPE_FILE: @@ -192,7 +192,7 @@ bool cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, { unsigned int param_len = 0; unsigned int data_len = 0; - uint16 setup = TRANSACT2_QPATHINFO; + uint16_t setup = TRANSACT2_QPATHINFO; char *param; size_t nlen = 2*(strlen(name)+1); char *rparam=NULL, *rdata=NULL; @@ -250,7 +250,7 @@ bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbu { unsigned int param_len = 0; unsigned int data_len = 0; - uint16 setup = TRANSACT2_QPATHINFO; + uint16_t setup = TRANSACT2_QPATHINFO; char *param; size_t nlen = 2*(strlen(name)+1); char *rparam=NULL, *rdata=NULL; @@ -311,8 +311,8 @@ bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbu sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56)); #if defined(HAVE_MAKEDEV) { - uint32 dev_major = IVAL(rdata,60); - uint32 dev_minor = IVAL(rdata,68); + uint32_t dev_major = IVAL(rdata,60); + uint32_t dev_minor = IVAL(rdata,68); sbuf->st_rdev = makedev(dev_major, dev_minor); } #endif @@ -348,11 +348,11 @@ bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *n Chmod or chown a file internal (UNIX extensions). ****************************************************************************/ -static bool cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32 mode, uint32 uid, uint32 gid) +static bool cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32_t mode, uint32_t uid, uint32_t gid) { unsigned int data_len = 0; unsigned int param_len = 0; - uint16 setup = TRANSACT2_SETPATHINFO; + uint16_t setup = TRANSACT2_SETPATHINFO; size_t nlen = 2*(strlen(fname)+1); char *param; char data[100]; @@ -429,254 +429,671 @@ bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t g Rename a file. ****************************************************************************/ -bool cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst) +static void cli_rename_done(struct tevent_req *subreq); + +struct cli_rename_state { + uint16_t vwv[1]; +}; + +struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname_src, + const char *fname_dst) { - char *p; + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_rename_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 cli_rename_state); + if (req == NULL) { + return NULL; + } - cli_set_message(cli->outbuf,1, 0, true); + SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR); - SCVAL(cli->outbuf,smb_com,SMBmv); - 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), fname_src, + strlen(fname_src)+1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR); + bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t, + talloc_get_size(bytes)+1); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, fname_src, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); - *p++ = 4; - p += clistr_push(cli, p, fname_dst, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); + bytes[talloc_get_size(bytes)-1] = 4; + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst, + strlen(fname_dst)+1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - cli_setup_bcc(cli, p); + subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags, + 1, 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_rename_done, req); + return req; +} - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return false; +static void cli_rename_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); +} - if (cli_is_error(cli)) { - return false; +NTSTATUS cli_rename_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst) +{ + 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; } - return true; + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_rename_send(frame, ev, cli, fname_src, fname_dst); + 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_rename_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** NT Rename a file. ****************************************************************************/ -bool cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst) +static void cli_ntrename_internal_done(struct tevent_req *subreq); + +struct cli_ntrename_internal_state { + uint16_t vwv[4]; +}; + +static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname_src, + const char *fname_dst, + uint16_t rename_flag) { - char *p; + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_ntrename_internal_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 cli_ntrename_internal_state); + if (req == NULL) { + return NULL; + } - cli_set_message(cli->outbuf, 4, 0, true); + SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR); + SSVAL(state->vwv+1, 0, rename_flag); - SCVAL(cli->outbuf,smb_com,SMBntrename); - 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), fname_src, + strlen(fname_src)+1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR); - SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_RENAME); + bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t, + talloc_get_size(bytes)+1); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, fname_src, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); - *p++ = 4; - p += clistr_push(cli, p, fname_dst, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); + bytes[talloc_get_size(bytes)-1] = 4; + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst, + strlen(fname_dst)+1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - cli_setup_bcc(cli, p); + subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags, + 4, 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_ntrename_internal_done, req); + return req; +} - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return false; +static void cli_ntrename_internal_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); +} - if (cli_is_error(cli)) { - return false; +static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname_src, + const char *fname_dst) +{ + return cli_ntrename_internal_send(mem_ctx, + ev, + cli, + fname_src, + fname_dst, + RENAME_FLAG_RENAME); +} + +NTSTATUS cli_ntrename_recv(struct tevent_req *req) +{ + return cli_ntrename_internal_recv(req); +} + +NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst) +{ + 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; } - return true; + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst); + 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_ntrename_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** NT hardlink a file. ****************************************************************************/ -bool cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst) +struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname_src, + const char *fname_dst) { - char *p; - - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); - - cli_set_message(cli->outbuf, 4, 0, true); + return cli_ntrename_internal_send(mem_ctx, + ev, + cli, + fname_src, + fname_dst, + RENAME_FLAG_HARD_LINK); +} - SCVAL(cli->outbuf,smb_com,SMBntrename); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); +NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req) +{ + return cli_ntrename_internal_recv(req); +} - SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR); - SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_HARD_LINK); +NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, fname_src, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); - *p++ = 4; - p += clistr_push(cli, p, fname_dst, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); + 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; + } - cli_setup_bcc(cli, p); + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return false; + req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - if (cli_is_error(cli)) { - return false; + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - return true; + status = cli_nt_hardlink_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Delete a file. ****************************************************************************/ -bool cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs) -{ - char *p; +static void cli_unlink_done(struct tevent_req *subreq); - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); +struct cli_unlink_state { + uint16_t vwv[1]; +}; - cli_set_message(cli->outbuf,1, 0, true); +struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname, + uint16_t mayhave_attrs) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_unlink_state *state = NULL; + uint8_t additional_flags = 0; + uint8_t *bytes = NULL; - SCVAL(cli->outbuf,smb_com,SMBunlink); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state); + if (req == NULL) { + return NULL; + } - SSVAL(cli->outbuf,smb_vwv0, attrs); + SSVAL(state->vwv+0, 0, mayhave_attrs); - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, fname, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); + 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), fname, + strlen(fname)+1, NULL); - cli_setup_bcc(cli, p); - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return false; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - if (cli_is_error(cli)) { - return false; + subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags, + 1, 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_unlink_done, req); + return req; +} - return true; +static void cli_unlink_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); } -/**************************************************************************** - Delete a file. -****************************************************************************/ +NTSTATUS cli_unlink_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} -bool cli_unlink(struct cli_state *cli, const char *fname) +NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs) { - return cli_unlink_full(cli, fname, aSYSTEM | aHIDDEN); + 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_unlink_send(frame, ev, cli, fname, mayhave_attrs); + 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_unlink_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Create a directory. ****************************************************************************/ -bool cli_mkdir(struct cli_state *cli, const char *dname) +static void cli_mkdir_done(struct tevent_req *subreq); + +struct cli_mkdir_state { + int dummy; +}; + +struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *dname) { - char *p; + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_mkdir_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 cli_mkdir_state); + if (req == NULL) { + return NULL; + } - cli_set_message(cli->outbuf,0, 0, true); + 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), dname, + strlen(dname)+1, NULL); - SCVAL(cli->outbuf,smb_com,SMBmkdir); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, dname, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); + subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags, + 0, NULL, talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_mkdir_done, req); + return req; +} - cli_setup_bcc(cli, p); +static void cli_mkdir_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return False; + 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); +} - if (cli_is_error(cli)) { - return False; +NTSTATUS cli_mkdir_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname) +{ + 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; } - return True; + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_mkdir_send(frame, ev, cli, dname); + 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_mkdir_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Remove a directory. ****************************************************************************/ -bool cli_rmdir(struct cli_state *cli, const char *dname) +static void cli_rmdir_done(struct tevent_req *subreq); + +struct cli_rmdir_state { + int dummy; +}; + +struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *dname) { - char *p; + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_rmdir_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 cli_rmdir_state); + if (req == NULL) { + return NULL; + } + + 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), dname, + strlen(dname)+1, NULL); - cli_set_message(cli->outbuf,0, 0, true); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } - SCVAL(cli->outbuf,smb_com,SMBrmdir); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags, + 0, NULL, talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_rmdir_done, req); + return req; +} - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, dname, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); +static void cli_rmdir_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; - cli_setup_bcc(cli, p); + 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); +} - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return false; +NTSTATUS cli_rmdir_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname) +{ + 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; } - if (cli_is_error(cli)) { - return false; + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - return true; + req = cli_rmdir_send(frame, ev, cli, dname); + 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_rmdir_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Set or clear the delete on close flag. ****************************************************************************/ -int cli_nt_delete_on_close(struct cli_state *cli, int fnum, bool flag) +int cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag) { unsigned int data_len = 1; unsigned int param_len = 6; - uint16 setup = TRANSACT2_SETFILEINFO; + uint16_t setup = TRANSACT2_SETFILEINFO; char param[6]; unsigned char data; char *rparam=NULL, *rdata=NULL; @@ -709,88 +1126,193 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, bool flag) return true; } -/**************************************************************************** - Open a file - exposing the full horror of the NT API :-). - Used in smbtorture. -****************************************************************************/ - -int cli_nt_create_full(struct cli_state *cli, const char *fname, - uint32 CreatFlags, uint32 DesiredAccess, - uint32 FileAttributes, uint32 ShareAccess, - uint32 CreateDisposition, uint32 CreateOptions, - uint8 SecurityFlags) +struct cli_ntcreate_state { + uint16_t vwv[24]; + uint16_t fnum; +}; + +static void cli_ntcreate_done(struct tevent_req *subreq); + +struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t CreatFlags, + uint32_t DesiredAccess, + uint32_t FileAttributes, + uint32_t ShareAccess, + uint32_t CreateDisposition, + uint32_t CreateOptions, + uint8_t SecurityFlags) { - char *p; - int len; + struct tevent_req *req, *subreq; + struct cli_ntcreate_state *state; + uint16_t *vwv; + uint8_t *bytes; + size_t converted_len; - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); + req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state); + if (req == NULL) { + return NULL; + } + vwv = state->vwv; - cli_set_message(cli->outbuf,24,0, true); + SCVAL(vwv+0, 0, 0xFF); + SCVAL(vwv+0, 1, 0); + SSVAL(vwv+1, 0, 0); + SCVAL(vwv+2, 0, 0); - SCVAL(cli->outbuf,smb_com,SMBntcreateX); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); - - SSVAL(cli->outbuf,smb_vwv0,0xFF); - if (cli->use_oplocks) + if (cli->use_oplocks) { CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK); + } + SIVAL(vwv+3, 1, CreatFlags); + SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */ + SIVAL(vwv+7, 1, DesiredAccess); + SIVAL(vwv+9, 1, 0x0); /* AllocationSize */ + SIVAL(vwv+11, 1, 0x0); /* AllocationSize */ + SIVAL(vwv+13, 1, FileAttributes); + SIVAL(vwv+15, 1, ShareAccess); + SIVAL(vwv+17, 1, CreateDisposition); + SIVAL(vwv+19, 1, CreateOptions); + SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */ + SCVAL(vwv+23, 1, SecurityFlags); + + bytes = talloc_array(state, uint8_t, 0); + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), + fname, strlen(fname)+1, + &converted_len); - SIVAL(cli->outbuf,smb_ntcreate_Flags, CreatFlags); - SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0); - SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess); - SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, FileAttributes); - SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, ShareAccess); - SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, CreateDisposition); - SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, CreateOptions); - SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02); - SCVAL(cli->outbuf,smb_ntcreate_SecurityFlags, SecurityFlags); - - p = smb_buf(cli->outbuf); - /* this alignment and termination is critical for netapp filers. Don't change */ - p += clistr_align_out(cli, p, 0); - len = clistr_push(cli, p, fname, - cli->bufsize - PTR_DIFF(p,cli->outbuf), 0); - p += len; - SSVAL(cli->outbuf,smb_ntcreate_NameLength, len); /* sigh. this copes with broken netapp filer behaviour */ - p += clistr_push(cli, p, "", - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); - - cli_setup_bcc(cli, p); + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL); - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return -1; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - if (cli_is_error(cli)) { - return -1; + SIVAL(vwv+2, 1, converted_len); + + subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv, + talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, cli_ntcreate_done, req); + return req; +} - return SVAL(cli->inbuf,smb_vwv2 + 1); +static void cli_ntcreate_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); + uint8_t wct; + uint16_t *vwv; + uint32_t num_bytes; + uint8_t *bytes; + NTSTATUS status; + + status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; + } + state->fnum = SVAL(vwv+2, 1); + tevent_req_done(req); } -/**************************************************************************** - Open a file. -****************************************************************************/ +NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum) +{ + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); + NTSTATUS status; -int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess) + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *pfnum = state->fnum; + return NT_STATUS_OK; +} + +NTSTATUS cli_ntcreate(struct cli_state *cli, + const char *fname, + uint32_t CreatFlags, + uint32_t DesiredAccess, + uint32_t FileAttributes, + uint32_t ShareAccess, + uint32_t CreateDisposition, + uint32_t CreateOptions, + uint8_t SecurityFlags, + uint16_t *pfid) { - return cli_nt_create_full(cli, fname, 0, DesiredAccess, 0, - FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0); + 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_ntcreate_send(frame, ev, cli, fname, CreatFlags, + DesiredAccess, FileAttributes, ShareAccess, + CreateDisposition, CreateOptions, + SecurityFlags); + 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_ntcreate_recv(req, pfid); + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } -uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, const char *str) +/*********************************************************** + Common function for pushing stings, used by smb_bytes_push_str() + and trans_bytes_push_str(). Only difference is the align_odd + parameter setting. +***********************************************************/ + +static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2, + const char *str, size_t str_len, + bool align_odd, + size_t *pconverted_size) { - size_t buflen = talloc_get_size(buf); + size_t buflen; char *converted; size_t converted_size; - /* - * We're pushing into an SMB buffer, align odd - */ - if (ucs2 && (buflen % 2 == 0)) { + if (buf == NULL) { + return NULL; + } + + buflen = talloc_get_size(buf); + + if (align_odd && ucs2 && (buflen % 2 == 0)) { + /* + * We're pushing into an SMB buffer, align odd + */ buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1); if (buf == NULL) { return NULL; @@ -799,41 +1321,91 @@ uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, const char *str) buflen += 1; } - if (!convert_string_allocate(talloc_tos(), CH_UNIX, - ucs2 ? CH_UTF16LE : CH_DOS, - str, strlen(str)+1, &converted, - &converted_size, true)) { + if (!convert_string_talloc(talloc_tos(), CH_UNIX, + ucs2 ? CH_UTF16LE : CH_DOS, + str, str_len, &converted, + &converted_size, true)) { return NULL; } buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + converted_size); if (buf == NULL) { + TALLOC_FREE(converted); return NULL; } memcpy(buf + buflen, converted, converted_size); TALLOC_FREE(converted); + + if (pconverted_size) { + *pconverted_size = converted_size; + } + return buf; } +/*********************************************************** + Push a string into an SMB buffer, with odd byte alignment + if it's a UCS2 string. +***********************************************************/ + +uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, + const char *str, size_t str_len, + size_t *pconverted_size) +{ + return internal_bytes_push_str(buf, ucs2, str, str_len, + true, pconverted_size); +} + +/*********************************************************** + Same as smb_bytes_push_str(), but without the odd byte + align for ucs2 (we're pushing into a param or data block). + static for now, although this will probably change when + other modules use async trans calls. +***********************************************************/ + +static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2, + const char *str, size_t str_len, + size_t *pconverted_size) +{ + return internal_bytes_push_str(buf, ucs2, str, str_len, + false, pconverted_size); +} + /**************************************************************************** Open a file WARNING: if you open with O_WRONLY then getattrE won't work! ****************************************************************************/ -struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, - const char *fname, int flags, int share_mode) +struct cli_open_state { + uint16_t vwv[15]; + uint16_t fnum; + struct iovec bytes; +}; + +static void cli_open_done(struct tevent_req *subreq); + +struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, const char *fname, + int flags, int share_mode, + struct tevent_req **psmbreq) { - unsigned openfn = 0; - unsigned accessmode = 0; - uint8_t additional_flags = 0; + struct tevent_req *req, *subreq; + struct cli_open_state *state; + unsigned openfn; + unsigned accessmode; + uint8_t additional_flags; uint8_t *bytes; - uint16_t vwv[15]; - struct async_req *result; + req = tevent_req_create(mem_ctx, &state, struct cli_open_state); + if (req == NULL) { + return NULL; + } + + openfn = 0; if (flags & O_CREAT) { openfn |= (1<<4); } @@ -862,182 +1434,263 @@ struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, accessmode = 0xFF; } - SCVAL(vwv + 0, 0, 0xFF); - SCVAL(vwv + 0, 1, 0); - SSVAL(vwv + 1, 0, 0); - SSVAL(vwv + 2, 0, 0); /* no additional info */ - SSVAL(vwv + 3, 0, accessmode); - SSVAL(vwv + 4, 0, aSYSTEM | aHIDDEN); - SSVAL(vwv + 5, 0, 0); - SIVAL(vwv + 6, 0, 0); - SSVAL(vwv + 8, 0, openfn); - SIVAL(vwv + 9, 0, 0); - SIVAL(vwv + 11, 0, 0); - SIVAL(vwv + 13, 0, 0); + SCVAL(state->vwv + 0, 0, 0xFF); + SCVAL(state->vwv + 0, 1, 0); + SSVAL(state->vwv + 1, 0, 0); + SSVAL(state->vwv + 2, 0, 0); /* no additional info */ + SSVAL(state->vwv + 3, 0, accessmode); + SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN); + SSVAL(state->vwv + 5, 0, 0); + SIVAL(state->vwv + 6, 0, 0); + SSVAL(state->vwv + 8, 0, openfn); + SIVAL(state->vwv + 9, 0, 0); + SIVAL(state->vwv + 11, 0, 0); + SIVAL(state->vwv + 13, 0, 0); + + additional_flags = 0; if (cli->use_oplocks) { /* if using oplocks then ask for a batch oplock via core and extended methods */ additional_flags = FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK; - SSVAL(vwv+2, 0, SVAL(vwv+2, 0) | 6); + SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6); } - bytes = talloc_array(talloc_tos(), uint8_t, 0); - if (bytes == NULL) { - return NULL; + bytes = talloc_array(state, uint8_t, 0); + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname, + strlen(fname)+1, NULL); + + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - bytes = smb_bytes_push_str( - bytes, (cli->capabilities & CAP_UNICODE) != 0, fname); - if (bytes == NULL) { + state->bytes.iov_base = bytes; + state->bytes.iov_len = talloc_get_size(bytes); + + subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags, + 15, state->vwv, 1, &state->bytes); + if (subreq == NULL) { + TALLOC_FREE(req); return NULL; } + tevent_req_set_callback(subreq, cli_open_done, req); + *psmbreq = subreq; + return req; +} - result = cli_request_send(mem_ctx, ev, cli, SMBopenX, additional_flags, - 15, vwv, talloc_get_size(bytes), bytes); - TALLOC_FREE(bytes); - return result; +struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, const char *fname, + int flags, int share_mode) +{ + struct tevent_req *req, *subreq; + + req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode, + &subreq); + if ((req == NULL) || !cli_smb_req_send(subreq)) { + TALLOC_FREE(req); + return NULL; + } + return req; } -NTSTATUS cli_open_recv(struct async_req *req, int *fnum) +static void cli_open_done(struct tevent_req *subreq) { + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_open_state *state = tevent_req_data( + req, struct cli_open_state); uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; NTSTATUS status; - SMB_ASSERT(req->state >= ASYNC_REQ_DONE); - if (req->state == ASYNC_REQ_ERROR) { - return req->status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL); if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (wct < 3) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; } + state->fnum = SVAL(vwv+2, 0); + tevent_req_done(req); +} - *fnum = SVAL(vwv+2, 0); +NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum) +{ + struct cli_open_state *state = tevent_req_data( + req, struct cli_open_state); + NTSTATUS status; + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *pfnum = state->fnum; return NT_STATUS_OK; } -int cli_open(struct cli_state *cli, const char *fname, int flags, - int share_mode) +NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags, + int share_mode, uint16_t *pfnum) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - int result = -1; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = cli_open_send(frame, ev, cli, fname, flags, share_mode); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - cli_open_recv(req, &result); + status = cli_open_recv(req, pfnum); fail: TALLOC_FREE(frame); - return result; + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Close a file. ****************************************************************************/ -struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, int fnum) +struct cli_close_state { + uint16_t vwv[3]; +}; + +static void cli_close_done(struct tevent_req *subreq); + +struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + struct tevent_req **psubreq) +{ + struct tevent_req *req, *subreq; + struct cli_close_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_close_state); + if (req == NULL) { + return NULL; + } + SSVAL(state->vwv+0, 0, fnum); + SIVALS(state->vwv+1, 0, -1); + + subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv, + 0, NULL); + if (subreq == NULL) { + TALLOC_FREE(req); + return NULL; + } + tevent_req_set_callback(subreq, cli_close_done, req); + *psubreq = subreq; + return req; +} + +struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum) { - uint16_t vwv[3]; + struct tevent_req *req, *subreq; - SSVAL(vwv+0, 0, fnum); - SIVALS(vwv+1, 0, -1); - - return cli_request_send(mem_ctx, ev, cli, SMBclose, 0, 3, vwv, - 0, NULL); + req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq); + if ((req == NULL) || !cli_smb_req_send(subreq)) { + TALLOC_FREE(req); + return NULL; + } + return req; } -NTSTATUS cli_close_recv(struct async_req *req) +static void cli_close_done(struct tevent_req *subreq) { - uint8_t wct; - uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; - SMB_ASSERT(req->state >= ASYNC_REQ_DONE); - if (req->state == ASYNC_REQ_ERROR) { - return req->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); +} - return cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); +NTSTATUS cli_close_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } -bool cli_close(struct cli_state *cli, int fnum) +NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - bool result = false; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = cli_close_send(frame, ev, cli, fnum); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - result = NT_STATUS_IS_OK(cli_close_recv(req)); + status = cli_close_recv(req); fail: TALLOC_FREE(frame); - return result; + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Truncate a file to a specified size ****************************************************************************/ -bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size) +bool cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size) { unsigned int param_len = 6; unsigned int data_len = 8; - uint16 setup = TRANSACT2_SETFILEINFO; + uint16_t setup = TRANSACT2_SETFILEINFO; char param[6]; unsigned char data[8]; char *rparam=NULL, *rdata=NULL; @@ -1083,8 +1736,8 @@ bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size) this is used for testing LOCKING_ANDX_CANCEL_LOCK ****************************************************************************/ -NTSTATUS cli_locktype(struct cli_state *cli, int fnum, - uint32 offset, uint32 len, +NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum, + uint32_t offset, uint32_t len, int timeout, unsigned char locktype) { char *p; @@ -1136,8 +1789,8 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum, note that timeout is in units of 2 milliseconds ****************************************************************************/ -bool cli_lock(struct cli_state *cli, int fnum, - uint32 offset, uint32 len, int timeout, enum brl_type lock_type) +bool cli_lock(struct cli_state *cli, uint16_t fnum, + uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type) { char *p; int saved_timeout = cli->timeout; @@ -1191,7 +1844,7 @@ bool cli_lock(struct cli_state *cli, int fnum, Unlock a file. ****************************************************************************/ -bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len) +bool cli_unlock(struct cli_state *cli, uint16_t fnum, uint32_t offset, uint32_t len) { char *p; @@ -1233,8 +1886,8 @@ bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len) Lock a file with 64 bit offsets. ****************************************************************************/ -bool cli_lock64(struct cli_state *cli, int fnum, - SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type) +bool cli_lock64(struct cli_state *cli, uint16_t fnum, + uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type) { char *p; int saved_timeout = cli->timeout; @@ -1294,7 +1947,7 @@ bool cli_lock64(struct cli_state *cli, int fnum, Unlock a file with 64 bit offsets. ****************************************************************************/ -bool cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len) +bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len) { char *p; @@ -1340,12 +1993,12 @@ bool cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_ Get/unlock a POSIX lock on a file - internal function. ****************************************************************************/ -static bool cli_posix_lock_internal(struct cli_state *cli, int fnum, - SMB_BIG_UINT offset, SMB_BIG_UINT len, bool wait_lock, enum brl_type lock_type) +static bool cli_posix_lock_internal(struct cli_state *cli, uint16_t fnum, + uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type) { unsigned int param_len = 4; unsigned int data_len = POSIX_LOCK_DATA_SIZE; - uint16 setup = TRANSACT2_SETFILEINFO; + uint16_t setup = TRANSACT2_SETFILEINFO; char param[4]; unsigned char data[POSIX_LOCK_DATA_SIZE]; char *rparam=NULL, *rdata=NULL; @@ -1411,8 +2064,8 @@ static bool cli_posix_lock_internal(struct cli_state *cli, int fnum, POSIX Lock a file. ****************************************************************************/ -bool cli_posix_lock(struct cli_state *cli, int fnum, - SMB_BIG_UINT offset, SMB_BIG_UINT len, +bool cli_posix_lock(struct cli_state *cli, uint16_t fnum, + uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type) { if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) { @@ -1425,7 +2078,7 @@ bool cli_posix_lock(struct cli_state *cli, int fnum, POSIX Unlock a file. ****************************************************************************/ -bool cli_posix_unlock(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len) +bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len) { return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK); } @@ -1434,7 +2087,7 @@ bool cli_posix_unlock(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_ POSIX Get any lock covering a file. ****************************************************************************/ -bool cli_posix_getlock(struct cli_state *cli, int fnum, SMB_BIG_UINT *poffset, SMB_BIG_UINT *plen) +bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen) { return True; } @@ -1443,258 +2096,780 @@ bool cli_posix_getlock(struct cli_state *cli, int fnum, SMB_BIG_UINT *poffset, S Do a SMBgetattrE call. ****************************************************************************/ -bool cli_getattrE(struct cli_state *cli, int fd, - uint16 *attr, SMB_OFF_T *size, - time_t *change_time, - time_t *access_time, - time_t *write_time) -{ - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); +static void cli_getattrE_done(struct tevent_req *subreq); - cli_set_message(cli->outbuf,1,0,True); +struct cli_getattrE_state { + uint16_t vwv[1]; + int zone_offset; + uint16_t attr; + SMB_OFF_T size; + time_t change_time; + time_t access_time; + time_t write_time; +}; - SCVAL(cli->outbuf,smb_com,SMBgetattrE); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); +struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_getattrE_state *state = NULL; + uint8_t additional_flags = 0; - SSVAL(cli->outbuf,smb_vwv0,fd); + req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state); + if (req == NULL) { + return NULL; + } - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return False; + state->zone_offset = cli->serverzone; + SSVAL(state->vwv+0,0,fnum); + + subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, + 1, state->vwv, 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, cli_getattrE_done, req); + return req; +} - if (cli_is_error(cli)) { - return False; +static void cli_getattrE_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_getattrE_state *state = tevent_req_data( + req, struct cli_getattrE_state); + uint8_t wct; + uint16_t *vwv = NULL; + NTSTATUS status; + + status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; } + state->size = (SMB_OFF_T)IVAL(vwv+6,0); + state->attr = SVAL(vwv+10,0); + state->change_time = make_unix_date2(vwv+0, state->zone_offset); + state->access_time = make_unix_date2(vwv+2, state->zone_offset); + state->write_time = make_unix_date2(vwv+4, state->zone_offset); + + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +NTSTATUS cli_getattrE_recv(struct tevent_req *req, + uint16_t *attr, + SMB_OFF_T *size, + time_t *change_time, + time_t *access_time, + time_t *write_time) +{ + struct cli_getattrE_state *state = tevent_req_data( + req, struct cli_getattrE_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (attr) { + *attr = state->attr; + } if (size) { - *size = IVAL(cli->inbuf, smb_vwv6); + *size = state->size; + } + if (change_time) { + *change_time = state->change_time; + } + if (access_time) { + *access_time = state->access_time; + } + if (write_time) { + *write_time = state->write_time; } + return NT_STATUS_OK; +} - if (attr) { - *attr = SVAL(cli->inbuf,smb_vwv10); +NTSTATUS cli_getattrE(struct cli_state *cli, + uint16_t fnum, + uint16_t *attr, + SMB_OFF_T *size, + time_t *change_time, + time_t *access_time, + time_t *write_time) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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; } - if (change_time) { - *change_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv0); + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - if (access_time) { - *access_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv2); + req = cli_getattrE_send(frame, ev, cli, fnum); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - if (write_time) { - *write_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv4); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - return True; + status = cli_getattrE_recv(req, + attr, + size, + change_time, + access_time, + write_time); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Do a SMBgetatr call ****************************************************************************/ -bool cli_getatr(struct cli_state *cli, const char *fname, - uint16 *attr, SMB_OFF_T *size, time_t *write_time) -{ - char *p; +static void cli_getatr_done(struct tevent_req *subreq); - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); +struct cli_getatr_state { + int zone_offset; + uint16_t attr; + SMB_OFF_T size; + time_t write_time; +}; - cli_set_message(cli->outbuf,0,0,True); +struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_getatr_state *state = NULL; + uint8_t additional_flags = 0; + uint8_t *bytes = NULL; - SCVAL(cli->outbuf,smb_com,SMBgetatr); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state); + if (req == NULL) { + return NULL; + } - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, fname, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); + state->zone_offset = cli->serverzone; - cli_setup_bcc(cli, p); + 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), fname, + strlen(fname)+1, NULL); - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return False; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - if (cli_is_error(cli)) { - return False; + subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags, + 0, NULL, talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, cli_getatr_done, req); + return req; +} - if (size) { - *size = IVAL(cli->inbuf, smb_vwv3); +static void cli_getatr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_getatr_state *state = tevent_req_data( + req, struct cli_getatr_state); + uint8_t wct; + uint16_t *vwv = NULL; + NTSTATUS status; + + status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; } + state->attr = SVAL(vwv+0,0); + state->size = (SMB_OFF_T)IVAL(vwv+3,0); + state->write_time = make_unix_date3(vwv+1, state->zone_offset); + + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +NTSTATUS cli_getatr_recv(struct tevent_req *req, + uint16_t *attr, + SMB_OFF_T *size, + time_t *write_time) +{ + struct cli_getatr_state *state = tevent_req_data( + req, struct cli_getatr_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (attr) { + *attr = state->attr; + } + if (size) { + *size = state->size; + } if (write_time) { - *write_time = cli_make_unix_date3(cli, cli->inbuf+smb_vwv1); + *write_time = state->write_time; } + return NT_STATUS_OK; +} - if (attr) { - *attr = SVAL(cli->inbuf,smb_vwv0); +NTSTATUS cli_getatr(struct cli_state *cli, + const char *fname, + uint16_t *attr, + SMB_OFF_T *size, + time_t *write_time) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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; } - return True; + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_getatr_send(frame, ev, cli, fname); + 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_getatr_recv(req, + attr, + size, + write_time); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Do a SMBsetattrE call. ****************************************************************************/ -bool cli_setattrE(struct cli_state *cli, int fd, - time_t change_time, - time_t access_time, - time_t write_time) +static void cli_setattrE_done(struct tevent_req *subreq); + +struct cli_setattrE_state { + int dummy; +}; +struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + time_t change_time, + time_t access_time, + time_t write_time) { - char *p; + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_setattrE_state *state = NULL; + uint8_t additional_flags = 0; + uint16_t vwv[7]; - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); + req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state); + if (req == NULL) { + return NULL; + } - cli_set_message(cli->outbuf,7,0,True); + memset(vwv, '\0', sizeof(vwv)); + SSVAL(vwv+0, 0, fnum); + cli_put_dos_date2(cli, (char *)&vwv[1], 0, change_time); + cli_put_dos_date2(cli, (char *)&vwv[3], 0, access_time); + cli_put_dos_date2(cli, (char *)&vwv[5], 0, write_time); - SCVAL(cli->outbuf,smb_com,SMBsetattrE); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, + 7, vwv, 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_setattrE_done, req); + return req; +} - SSVAL(cli->outbuf,smb_vwv0, fd); - cli_put_dos_date2(cli, cli->outbuf,smb_vwv1, change_time); - cli_put_dos_date2(cli, cli->outbuf,smb_vwv3, access_time); - cli_put_dos_date2(cli, cli->outbuf,smb_vwv5, write_time); +static void cli_setattrE_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; - p = smb_buf(cli->outbuf); - *p++ = 4; + 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); +} - cli_setup_bcc(cli, p); +NTSTATUS cli_setattrE_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return False; +NTSTATUS cli_setattrE(struct cli_state *cli, + uint16_t fnum, + time_t change_time, + time_t access_time, + time_t write_time) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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_setattrE_send(frame, ev, + cli, + fnum, + change_time, + access_time, + write_time); + + 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_setattrE_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; +} + +/**************************************************************************** + Do a SMBsetatr call. +****************************************************************************/ + +static void cli_setatr_done(struct tevent_req *subreq); + +struct cli_setatr_state { + uint16_t vwv[8]; +}; + +struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname, + uint16_t attr, + time_t mtime) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_setatr_state *state = NULL; + uint8_t additional_flags = 0; + uint8_t *bytes = NULL; + + req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state); + if (req == NULL) { + return NULL; + } + + memset(state->vwv, '\0', sizeof(state->vwv)); + SSVAL(state->vwv+0, 0, attr); + cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime); + + 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), fname, + strlen(fname)+1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t, + talloc_get_size(bytes)+1); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + + bytes[talloc_get_size(bytes)-1] = 4; + bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", + 1, NULL); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + + subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags, + 8, 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_setatr_done, req); + return req; +} + +static void cli_setatr_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_setatr_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_setatr(struct cli_state *cli, + const char *fname, + uint16_t attr, + time_t mtime) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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_setatr_send(frame, ev, cli, fname, attr, mtime); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - if (cli_is_error(cli)) { - return False; + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - return True; + status = cli_setatr_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** - Do a SMBsetatr call. + Check for existance of a dir. ****************************************************************************/ -bool cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t) -{ - char *p; - - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); - - cli_set_message(cli->outbuf,8,0,True); +static void cli_chkpath_done(struct tevent_req *subreq); - SCVAL(cli->outbuf,smb_com,SMBsetatr); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); +struct cli_chkpath_state { + int dummy; +}; - SSVAL(cli->outbuf,smb_vwv0, attr); - cli_put_dos_date3(cli, cli->outbuf,smb_vwv1, t); +struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_chkpath_state *state = NULL; + uint8_t additional_flags = 0; + uint8_t *bytes = NULL; - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, fname, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); - *p++ = 4; + req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state); + if (req == NULL) { + return NULL; + } - cli_setup_bcc(cli, p); + 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), fname, + strlen(fname)+1, NULL); - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return False; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - if (cli_is_error(cli)) { - return False; + subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags, + 0, NULL, talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, cli_chkpath_done, req); + return req; +} - return True; +static void cli_chkpath_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); } -/**************************************************************************** - Check for existance of a dir. -****************************************************************************/ +NTSTATUS cli_chkpath_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} -bool cli_chkpath(struct cli_state *cli, const char *path) +NTSTATUS cli_chkpath(struct cli_state *cli, const char *path) { - char *path2 = NULL; - char *p; TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + char *path2 = NULL; + 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; + } path2 = talloc_strdup(frame, path); if (!path2) { - TALLOC_FREE(frame); - return false; + status = NT_STATUS_NO_MEMORY; + goto fail; } trim_char(path2,'\0','\\'); if (!*path2) { path2 = talloc_strdup(frame, "\\"); if (!path2) { - TALLOC_FREE(frame); - return false; + status = NT_STATUS_NO_MEMORY; + goto fail; } } - memset(cli->outbuf,'\0',smb_size); - cli_set_message(cli->outbuf,0,0,True); - SCVAL(cli->outbuf,smb_com,SMBcheckpath); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); - p = smb_buf(cli->outbuf); - *p++ = 4; - p += clistr_push(cli, p, path2, - cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE); - - cli_setup_bcc(cli, p); + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - TALLOC_FREE(frame); - return False; + req = cli_chkpath_send(frame, ev, cli, path2); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - TALLOC_FREE(frame); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } - if (cli_is_error(cli)) return False; + status = cli_chkpath_recv(req); - return True; + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** Query disk space. ****************************************************************************/ -bool cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) +static void cli_dskattr_done(struct tevent_req *subreq); + +struct cli_dskattr_state { + int bsize; + int total; + int avail; +}; + +struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli) { - memset(cli->outbuf,'\0',smb_size); - cli_set_message(cli->outbuf,0,0,True); - SCVAL(cli->outbuf,smb_com,SMBdskattr); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_dskattr_state *state = NULL; + uint8_t additional_flags = 0; - cli_send_smb(cli); - if (!cli_receive_smb(cli)) { - return False; + req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state); + if (req == NULL) { + return NULL; } - *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2); - *total = SVAL(cli->inbuf,smb_vwv0); - *avail = SVAL(cli->inbuf,smb_vwv3); + subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, + 0, NULL, 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_dskattr_done, req); + return req; +} - return True; +static void cli_dskattr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_dskattr_state *state = tevent_req_data( + req, struct cli_dskattr_state); + uint8_t wct; + uint16_t *vwv = NULL; + NTSTATUS status; + + status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0); + state->total = SVAL(vwv+0, 0); + state->avail = SVAL(vwv+3, 0); + TALLOC_FREE(subreq); + tevent_req_done(req); +} + +NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail) +{ + struct cli_dskattr_state *state = tevent_req_data( + req, struct cli_dskattr_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *bsize = state->bsize; + *total = state->total; + *avail = state->avail; + return NT_STATUS_OK; +} + +NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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_dskattr_send(frame, ev, cli); + 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_dskattr_recv(req, bsize, total, avail); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** @@ -1746,7 +2921,7 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path) if (!path2) { return -1; } - clistr_pull(cli, path2, p, + clistr_pull(cli->inbuf, path2, p, len+1, len, STR_ASCII); *tmp_path = path2; } @@ -1757,7 +2932,7 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path) /* send a raw ioctl - used by the torture code */ -NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *blob) +NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob) { memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); @@ -1788,7 +2963,7 @@ NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB * Set an extended attribute utility fn. *********************************************************/ -static bool cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigned int param_len, +static bool cli_set_ea(struct cli_state *cli, uint16_t setup, char *param, unsigned int param_len, const char *ea_name, const char *ea_val, size_t ea_len) { unsigned int data_len = 0; @@ -1852,7 +3027,7 @@ static bool cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigne bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len) { - uint16 setup = TRANSACT2_SETPATHINFO; + uint16_t setup = TRANSACT2_SETPATHINFO; unsigned int param_len = 0; char *param; size_t srclen = 2*(strlen(path)+1); @@ -1879,10 +3054,10 @@ bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_nam Set an extended attribute on an fnum. *********************************************************/ -bool cli_set_ea_fnum(struct cli_state *cli, int fnum, 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) { char param[6]; - uint16 setup = TRANSACT2_SETFILEINFO; + uint16_t setup = TRANSACT2_SETFILEINFO; memset(param, 0, 6); SSVAL(param,0,fnum); @@ -1896,7 +3071,7 @@ bool cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const *********************************************************/ static bool cli_get_ea_list(struct cli_state *cli, - uint16 setup, char *param, unsigned int param_len, + uint16_t setup, char *param, unsigned int param_len, TALLOC_CTX *ctx, size_t *pnum_eas, struct ea_struct **pea_list) @@ -2025,7 +3200,7 @@ bool cli_get_ea_list_path(struct cli_state *cli, const char *path, size_t *pnum_eas, struct ea_struct **pea_list) { - uint16 setup = TRANSACT2_QPATHINFO; + uint16_t setup = TRANSACT2_QPATHINFO; unsigned int param_len = 0; char *param; char *p; @@ -2052,12 +3227,12 @@ bool cli_get_ea_list_path(struct cli_state *cli, const char *path, Get an extended attribute list from an fnum. *********************************************************/ -bool cli_get_ea_list_fnum(struct cli_state *cli, int fnum, +bool cli_get_ea_list_fnum(struct cli_state *cli, uint16_t fnum, TALLOC_CTX *ctx, size_t *pnum_eas, struct ea_struct **pea_list) { - uint16 setup = TRANSACT2_QFILEINFO; + uint16_t setup = TRANSACT2_QFILEINFO; char param[6]; memset(param, 0, 6); @@ -2068,13 +3243,13 @@ bool cli_get_ea_list_fnum(struct cli_state *cli, int fnum, } /**************************************************************************** - Convert open "flags" arg to uint32 on wire. + Convert open "flags" arg to uint32_t on wire. ****************************************************************************/ -static uint32 open_flags_to_wire(int flags) +static uint32_t open_flags_to_wire(int flags) { int open_mode = flags & O_ACCMODE; - uint32 ret = 0; + uint32_t ret = 0; switch (open_mode) { case O_WRONLY: @@ -2128,13 +3303,13 @@ static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int { unsigned int data_len = 0; unsigned int param_len = 0; - uint16 setup = TRANSACT2_SETPATHINFO; + uint16_t setup = TRANSACT2_SETPATHINFO; char *param; char data[18]; char *rparam=NULL, *rdata=NULL; char *p; - int fnum = -1; - uint32 wire_flags = open_flags_to_wire(flags); + uint16_t fnum = (uint16_t)-1; + uint32_t wire_flags = open_flags_to_wire(flags); size_t srclen = 2*(strlen(fname)+1); param = SMB_MALLOC_ARRAY(char, 6+srclen+2); @@ -2166,7 +3341,7 @@ static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int NULL, /* name */ -1, 0, /* fid, flags */ &setup, 1, 0, /* setup, length, max */ - param, param_len, 2, /* param, length, max */ + param, param_len, 0, /* param, length, max */ (char *)&data, data_len, cli->max_xmit /* data, length, max */ )) { SAFE_FREE(param); @@ -2211,71 +3386,219 @@ int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode) unlink or rmdir - POSIX semantics. ****************************************************************************/ -static bool cli_posix_unlink_internal(struct cli_state *cli, const char *fname, bool is_dir) +struct unlink_state { + uint16_t setup; + uint8_t data[2]; +}; + +static void cli_posix_unlink_internal_done(struct tevent_req *subreq) { - unsigned int data_len = 0; - unsigned int param_len = 0; - uint16 setup = TRANSACT2_SETPATHINFO; - char *param; - char data[2]; - char *rparam=NULL, *rdata=NULL; - char *p; - size_t srclen = 2*(strlen(fname)+1); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct unlink_state *state = tevent_req_data(req, struct unlink_state); + NTSTATUS status; - param = SMB_MALLOC_ARRAY(char, 6+srclen+2); - if (!param) { - return false; + status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; } - memset(param, '\0', 6); - SSVAL(param,0, SMB_POSIX_PATH_UNLINK); - p = ¶m[6]; + tevent_req_done(req); +} - p += clistr_push(cli, p, fname, srclen, STR_TERMINATE); - param_len = PTR_DIFF(p, param); +static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname, + bool is_dir) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct unlink_state *state = NULL; + uint8_t *param = NULL; - SSVAL(data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET : - SMB_POSIX_UNLINK_FILE_TARGET); - data_len = 2; + req = tevent_req_create(mem_ctx, &state, struct unlink_state); + if (req == NULL) { + return NULL; + } - if (!cli_send_trans(cli, SMBtrans2, - NULL, /* name */ - -1, 0, /* fid, flags */ - &setup, 1, 0, /* setup, length, max */ - param, param_len, 2, /* param, length, max */ - (char *)&data, data_len, cli->max_xmit /* data, length, max */ - )) { - SAFE_FREE(param); - return False; + /* Setup setup word. */ + SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO); + + /* Setup param array. */ + param = talloc_array(state, uint8_t, 6); + if (tevent_req_nomem(param, req)) { + return tevent_req_post(req, ev); } + memset(param, '\0', 6); + SSVAL(param, 0, SMB_POSIX_PATH_UNLINK); - SAFE_FREE(param); + param = trans2_bytes_push_str(param, cli_ucs2(cli), fname, + strlen(fname)+1, NULL); - if (!cli_receive_trans(cli, SMBtrans2, - &rparam, ¶m_len, - &rdata, &data_len)) { - return False; + if (tevent_req_nomem(param, req)) { + return tevent_req_post(req, ev); } - SAFE_FREE(rdata); - SAFE_FREE(rparam); + /* Setup data word. */ + SSVAL(state->data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET : + SMB_POSIX_UNLINK_FILE_TARGET); - return True; + subreq = cli_trans_send(state, /* mem ctx. */ + ev, /* event ctx. */ + cli, /* cli_state. */ + SMBtrans2, /* cmd. */ + NULL, /* pipe name. */ + -1, /* fid. */ + 0, /* function. */ + 0, /* flags. */ + &state->setup, /* setup. */ + 1, /* num setup uint16_t words. */ + 0, /* max returned setup. */ + param, /* param. */ + talloc_get_size(param), /* num param. */ + 2, /* max returned param. */ + state->data, /* data. */ + 2, /* num data. */ + 0); /* max returned data. */ + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req); + return req; +} + +struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname) +{ + return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, false); +} + +NTSTATUS cli_posix_unlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + return NT_STATUS_OK; } /**************************************************************************** unlink - POSIX semantics. ****************************************************************************/ -bool cli_posix_unlink(struct cli_state *cli, const char *fname) +NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname) { - return cli_posix_unlink_internal(cli, fname, False); + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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_posix_unlink_send(frame, + ev, + cli, + fname); + 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_posix_unlink_recv(req, frame); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** rmdir - POSIX semantics. ****************************************************************************/ -int cli_posix_rmdir(struct cli_state *cli, const char *fname) +struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname) +{ + return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, true); +} + +NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + return NT_STATUS_OK; +} + +NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname) { - return cli_posix_unlink_internal(cli, fname, True); + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + 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_posix_rmdir_send(frame, + ev, + cli, + fname); + 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_posix_rmdir_recv(req, frame); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; }