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
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+/***********************************************************
+ 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;
+ char *converted;
+ size_t converted_size;
+
+ 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;
+ }
+ buf[buflen] = '\0';
+ buflen += 1;
+ }
+
+ 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);
+}
+
/****************************************************************************
Hard/Symlink a file (UNIX extensions).
Creates new name (sym)linked to oldname.
****************************************************************************/
-static BOOL cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, BOOL hard_link)
+struct link_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint8_t *data;
+};
+
+static void cli_posix_link_internal_done(struct tevent_req *subreq)
{
- unsigned int data_len = 0;
- unsigned int param_len = 0;
- uint16 setup = TRANSACT2_SETPATHINFO;
- char param[sizeof(pstring)+6];
- pstring data;
- char *rparam=NULL, *rdata=NULL;
- char *p;
- size_t oldlen = 2*(strlen(oldname)+1);
- size_t newlen = 2*(strlen(newname)+1);
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct link_state *state = tevent_req_data(req, struct link_state);
+ NTSTATUS status;
+
+ 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;
+ }
+ tevent_req_done(req);
+}
- memset(param, 0, sizeof(param));
- SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
- p = ¶m[6];
+static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname,
+ bool hardlink)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct link_state *state = NULL;
- p += clistr_push(cli, p, newname, MIN(newlen, sizeof(param)-6), STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+ req = tevent_req_create(mem_ctx, &state, struct link_state);
+ if (req == NULL) {
+ return NULL;
+ }
- p = data;
- p += clistr_push(cli, p, oldname, MIN(oldlen,sizeof(data)), STR_TERMINATE);
- data_len = PTR_DIFF(p, data);
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
- 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 */
- )) {
- return False;
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
+ memset(state->param, '\0', 6);
+ SSVAL(state->param,0,hardlink ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), newname,
+ strlen(newname)+1, NULL);
+
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
+ /* Setup data array. */
+ state->data = talloc_array(state, uint8_t, 0);
+ if (tevent_req_nomem(state->data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->data = trans2_bytes_push_str(state->data, cli_ucs2(cli), oldname,
+ strlen(oldname)+1, NULL);
+
+ 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. */
+ state->param, /* param. */
+ talloc_get_size(state->param), /* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ talloc_get_size(state->data), /* 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_link_internal_done, req);
+ return req;
+}
- return True;
+/****************************************************************************
+ Symlink a file (UNIX extensions).
+****************************************************************************/
+
+struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ return cli_posix_link_internal_send(mem_ctx, ev, cli,
+ oldname, newname, false);
+}
+
+NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_symlink(struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ 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_symlink_send(frame,
+ ev,
+ cli,
+ oldname,
+ newname);
+ 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_symlink_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+/****************************************************************************
+ Read a POSIX symlink.
+****************************************************************************/
+
+struct readlink_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint8_t *data;
+ uint32_t num_data;
+};
+
+static void cli_posix_readlink_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct readlink_state *state = tevent_req_data(req, struct readlink_state);
+ NTSTATUS status;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
+ &state->data, &state->num_data);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ if (state->num_data == 0) {
+ tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
+ return;
+ }
+ if (state->data[state->num_data-1] != '\0') {
+ tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ size_t len)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct readlink_state *state = NULL;
+ uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
+
+ if (maxbytelen < len) {
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state, struct readlink_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
+
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memset(state->param, '\0', 6);
+ SSVAL(state->param,0,SMB_QUERY_FILE_UNIX_LINK);
+
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
+ strlen(fname)+1, NULL);
+
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ 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. */
+ state->param, /* param. */
+ talloc_get_size(state->param), /* num param. */
+ 2, /* max returned param. */
+ NULL, /* data. */
+ 0, /* num data. */
+ maxbytelen); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
+ return req;
+}
+
+NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
+ char *retpath, size_t len)
+{
+ NTSTATUS status;
+ char *converted = NULL;
+ size_t converted_size = 0;
+ struct readlink_state *state = tevent_req_data(req, struct readlink_state);
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ /* The returned data is a pushed string, not raw data. */
+ if (!convert_string_talloc(state,
+ cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
+ CH_UNIX,
+ state->data,
+ state->num_data,
+ &converted,
+ &converted_size,
+ true)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ len = MIN(len,converted_size);
+ if (len == 0) {
+ return NT_STATUS_DATA_ERROR;
+ }
+ memcpy(retpath, converted, len);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
+ char *linkpath, size_t len)
+{
+ 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;
+ }
+
+ /* Len is in bytes, we need it in UCS2 units. */
+ if (2*len < len) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ req = cli_posix_readlink_send(frame,
+ ev,
+ cli,
+ fname,
+ len);
+ 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_readlink_recv(req, cli, linkpath, len);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+/****************************************************************************
+ Hard link a file (UNIX extensions).
+****************************************************************************/
+
+struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ return cli_posix_link_internal_send(mem_ctx, ev, cli,
+ oldname, newname, true);
+}
+
+NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_hardlink(struct cli_state *cli,
+ const char *oldname,
+ const char *newname)
+{
+ 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_hardlink_send(frame,
+ ev,
+ cli,
+ oldname,
+ newname);
+ 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_hardlink_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
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;
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;
/****************************************************************************
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:
Do a POSIX getfacl (UNIX extensions).
****************************************************************************/
-BOOL cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf)
+struct getfacl_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint32_t num_data;
+ uint8_t *data;
+};
+
+static void cli_posix_getfacl_done(struct tevent_req *subreq)
{
- unsigned int param_len = 0;
- unsigned int data_len = 0;
- uint16 setup = TRANSACT2_QPATHINFO;
- char param[sizeof(pstring)+6];
- char *rparam=NULL, *rdata=NULL;
- char *p;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
+ NTSTATUS status;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
+ &state->data, &state->num_data);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
- p = param;
- memset(p, 0, 6);
- SSVAL(p, 0, SMB_QUERY_POSIX_ACL);
- p += 6;
- p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct link_state *state = 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 */
- NULL, 0, cli->max_xmit /* data, length, max */
- )) {
- return False;
+ req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
+ if (req == NULL) {
+ return NULL;
}
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
+
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
+ memset(state->param, '\0', 6);
+ SSVAL(state->param, 0, SMB_QUERY_POSIX_ACL);
- if (data_len < 6) {
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
- return False;
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
+ strlen(fname)+1, NULL);
+
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
- SAFE_FREE(rparam);
- *retbuf = rdata;
- *prb_size = (size_t)data_len;
+ 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. */
+ state->param, /* param. */
+ talloc_get_size(state->param), /* num param. */
+ 2, /* max returned param. */
+ NULL, /* data. */
+ 0, /* num data. */
+ cli->max_xmit); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
+ return req;
+}
- return True;
+NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *prb_size,
+ char **retbuf)
+{
+ struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *prb_size = (size_t)state->num_data;
+ *retbuf = (char *)talloc_move(mem_ctx, &state->data);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_getfacl(struct cli_state *cli,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ size_t *prb_size,
+ char **retbuf)
+{
+ 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_getfacl_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_getfacl_recv(req, mem_ctx, prb_size, retbuf);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
Stat a file (UNIX extensions).
****************************************************************************/
-BOOL cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
+struct stat_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint32_t num_data;
+ uint8_t *data;
+};
+
+static void cli_posix_stat_done(struct tevent_req *subreq)
{
- unsigned int param_len = 0;
- unsigned int data_len = 0;
- uint16 setup = TRANSACT2_QPATHINFO;
- char param[sizeof(pstring)+6];
- char *rparam=NULL, *rdata=NULL;
- char *p;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct stat_state *state = tevent_req_data(req, struct stat_state);
+ NTSTATUS status;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
+ &state->data, &state->num_data);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ tevent_req_done(req);
+}
- ZERO_STRUCTP(sbuf);
+struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct stat_state *state = NULL;
- p = param;
- memset(p, 0, 6);
- SSVAL(p, 0, SMB_QUERY_FILE_UNIX_BASIC);
- p += 6;
- p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+ req = tevent_req_create(mem_ctx, &state, struct stat_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 */
- NULL, 0, cli->max_xmit /* data, length, max */
- )) {
- return False;
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
+
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
+ memset(state->param, '\0', 6);
+ SSVAL(state->param, 0, SMB_QUERY_FILE_UNIX_BASIC);
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
+ strlen(fname)+1, NULL);
+
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
- if (data_len < 96) {
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
- return False;
+ 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. */
+ state->param, /* param. */
+ talloc_get_size(state->param), /* num param. */
+ 2, /* max returned param. */
+ NULL, /* data. */
+ 0, /* num data. */
+ 96); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_posix_stat_done, req);
+ return req;
+}
+
+NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
+ SMB_STRUCT_STAT *sbuf)
+{
+ struct stat_state *state = tevent_req_data(req, struct stat_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+
+ if (state->num_data != 96) {
+ return NT_STATUS_DATA_ERROR;
}
- sbuf->st_size = IVAL2_TO_SMB_BIG_UINT(rdata,0); /* total size, in bytes */
- sbuf->st_blocks = IVAL2_TO_SMB_BIG_UINT(rdata,8); /* number of blocks allocated */
+ sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
+ sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
- sbuf->st_blocks /= STAT_ST_BLOCKSIZE;
+ sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
#else
/* assume 512 byte blocks */
- sbuf->st_blocks /= 512;
+ sbuf->st_ex_blocks /= 512;
#endif
- set_ctimespec(sbuf, interpret_long_date(rdata + 16)); /* time of last change */
- set_atimespec(sbuf, interpret_long_date(rdata + 24)); /* time of last access */
- set_mtimespec(sbuf, interpret_long_date(rdata + 32)); /* time of last modification */
+ sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
+ sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
+ sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
- sbuf->st_uid = (uid_t) IVAL(rdata,40); /* user ID of owner */
- sbuf->st_gid = (gid_t) IVAL(rdata,48); /* group ID of owner */
- sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56));
+ sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
+ sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
+ sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
#if defined(HAVE_MAKEDEV)
{
- uint32 dev_major = IVAL(rdata,60);
- uint32 dev_minor = IVAL(rdata,68);
- sbuf->st_rdev = makedev(dev_major, dev_minor);
+ uint32_t dev_major = IVAL(state->data,60);
+ uint32_t dev_minor = IVAL(state->data,68);
+ sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
}
#endif
- sbuf->st_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(rdata,76); /* inode */
- sbuf->st_mode |= wire_perms_to_unix(IVAL(rdata,84)); /* protection */
- sbuf->st_nlink = IVAL(rdata,92); /* number of hard links */
-
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
+ sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
+ sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
+ sbuf->st_ex_nlink = IVAL(state->data,92); /* number of hard links */
- return True;
+ return NT_STATUS_OK;
}
-/****************************************************************************
- Symlink a file (UNIX extensions).
-****************************************************************************/
-
-BOOL cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
+NTSTATUS cli_posix_stat(struct cli_state *cli,
+ const char *fname,
+ SMB_STRUCT_STAT *sbuf)
{
- return cli_link_internal(cli, oldname, newname, 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;
+ }
-/****************************************************************************
- Hard a file (UNIX extensions).
-****************************************************************************/
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
-BOOL cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
-{
- return cli_link_internal(cli, oldname, newname, True);
+ req = cli_posix_stat_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_stat_recv(req, sbuf);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
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)
+struct ch_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint8_t *data;
+};
+
+static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
{
- unsigned int data_len = 0;
- unsigned int param_len = 0;
- uint16 setup = TRANSACT2_SETPATHINFO;
- char param[sizeof(pstring)+6];
- char data[100];
- char *rparam=NULL, *rdata=NULL;
- char *p;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ch_state *state = tevent_req_data(req, struct ch_state);
+ NTSTATUS status;
+
+ 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;
+ }
+ tevent_req_done(req);
+}
- memset(param, 0, sizeof(param));
- memset(data, 0, sizeof(data));
- SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
- p = ¶m[6];
+static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ uint32_t mode,
+ uint32_t uid,
+ uint32_t gid)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct ch_state *state = NULL;
- p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+ req = tevent_req_create(mem_ctx, &state, struct ch_state);
+ if (req == NULL) {
+ return NULL;
+ }
- memset(data, 0xff, 40); /* Set all sizes/times to no change. */
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
- SIVAL(data,40,uid);
- SIVAL(data,48,gid);
- SIVAL(data,84,mode);
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memset(state->param, '\0', 6);
+ SSVAL(state->param,0,SMB_SET_FILE_UNIX_BASIC);
- data_len = 100;
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
+ strlen(fname)+1, 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 */
- )) {
- return False;
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ /* Setup data array. */
+ state->data = talloc_array(state, uint8_t, 100);
+ if (tevent_req_nomem(state->data, req)) {
+ return tevent_req_post(req, ev);
}
-
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
-
- return True;
-}
+ memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
+ memset(&state->data[40], '\0', 60);
+ SIVAL(state->data,40,uid);
+ SIVAL(state->data,48,gid);
+ SIVAL(state->data,84,mode);
+
+ 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. */
+ state->param, /* param. */
+ talloc_get_size(state->param), /* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ talloc_get_size(state->data), /* 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_chown_chmod_internal_done, req);
+ return req;
+}
/****************************************************************************
chmod a file (UNIX extensions).
****************************************************************************/
-BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
+struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ mode_t mode)
{
- return cli_unix_chmod_chown_internal(cli, fname,
- unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
+ return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
+ fname,
+ unix_perms_to_wire(mode),
+ SMB_UID_NO_CHANGE,
+ SMB_GID_NO_CHANGE);
}
-/****************************************************************************
- chown a file (UNIX extensions).
-****************************************************************************/
+NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
-BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
{
- return cli_unix_chmod_chown_internal(cli, fname, SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
+ 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_chmod_send(frame,
+ ev,
+ cli,
+ fname,
+ mode);
+ 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_chmod_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- Rename a file.
+ chown a file (UNIX extensions).
****************************************************************************/
-BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ uid_t uid,
+ gid_t gid)
{
- char *p;
-
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
+ fname,
+ SMB_MODE_NO_CHANGE,
+ (uint32_t)uid,
+ (uint32_t)gid);
+}
- set_message(NULL,cli->outbuf,1, 0, True);
+NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
- SCVAL(cli->outbuf,smb_com,SMBmv);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
- SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
+NTSTATUS cli_posix_chown(struct cli_state *cli,
+ const char *fname,
+ uid_t uid,
+ gid_t gid)
+{
+ 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;
+ }
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
- *p++ = 4;
- p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- cli_setup_bcc(cli, p);
+ req = cli_posix_chown_send(frame,
+ ev,
+ cli,
+ fname,
+ uid,
+ gid);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
- if (cli_is_error(cli))
- return False;
+ status = cli_posix_chown_recv(req);
- return True;
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- NT Rename a file.
+ Rename a file.
****************************************************************************/
-BOOL cli_ntrename(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;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
+ if (req == NULL) {
+ return NULL;
+ }
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR);
- set_message(NULL,cli->outbuf, 4, 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), fname_src,
+ strlen(fname_src)+1, NULL);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- SCVAL(cli->outbuf,smb_com,SMBntrename);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ 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);
+ }
- SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
- SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_RENAME);
+ 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);
+ }
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
- *p++ = 4;
- p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+ 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_setup_bcc(cli, p);
+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);
+}
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+NTSTATUS cli_rename_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
- if (cli_is_error(cli))
- return False;
+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 hardlink a file.
+ NT Rename a file.
****************************************************************************/
-BOOL cli_nt_hardlink(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);
-
- set_message(NULL,cli->outbuf, 4, 0, True);
+static void cli_ntrename_internal_done(struct tevent_req *subreq);
- SCVAL(cli->outbuf,smb_com,SMBntrename);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+struct cli_ntrename_internal_state {
+ uint16_t vwv[4];
+};
- SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
- SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_HARD_LINK);
+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)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_ntrename_internal_state *state = NULL;
+ uint8_t additional_flags = 0;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_ntrename_internal_state);
+ if (req == NULL) {
+ return NULL;
+ }
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
- *p++ = 4;
- p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+ SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR);
+ SSVAL(state->vwv+1, 0, rename_flag);
- 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_src,
+ strlen(fname_src)+1, NULL);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ 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);
+ }
- if (cli_is_error(cli))
- return False;
+ 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);
+ }
- return True;
+ 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;
}
-/****************************************************************************
- Delete a file.
-****************************************************************************/
+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);
+}
-BOOL cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs)
+static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
{
- char *p;
+ return tevent_req_simple_recv_ntstatus(req);
+}
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+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);
+}
- set_message(NULL,cli->outbuf,1, 0,True);
+NTSTATUS cli_ntrename_recv(struct tevent_req *req)
+{
+ return cli_ntrename_internal_recv(req);
+}
- SCVAL(cli->outbuf,smb_com,SMBunlink);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+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;
+ }
- SSVAL(cli->outbuf,smb_vwv0, attrs);
-
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- cli_setup_bcc(cli, p);
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
+ req = cli_ntrename_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_ntrename_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- Delete a file.
+ NT hardlink a file.
****************************************************************************/
-BOOL cli_unlink(struct cli_state *cli, const char *fname)
+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)
{
- return cli_unlink_full(cli, fname, aSYSTEM | aHIDDEN);
+ return cli_ntrename_internal_send(mem_ctx,
+ ev,
+ cli,
+ fname_src,
+ fname_dst,
+ RENAME_FLAG_HARD_LINK);
}
-/****************************************************************************
- Create a directory.
-****************************************************************************/
-
-BOOL cli_mkdir(struct cli_state *cli, const char *dname)
+NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
{
- char *p;
-
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
-
- set_message(NULL,cli->outbuf,0, 0,True);
-
- SCVAL(cli->outbuf,smb_com,SMBmkdir);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ return cli_ntrename_internal_recv(req);
+}
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+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;
+
+ 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;
}
/****************************************************************************
- Remove a directory.
+ Delete a file.
****************************************************************************/
-BOOL cli_rmdir(struct cli_state *cli, const char *dname)
-{
- char *p;
-
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
-
- set_message(NULL,cli->outbuf,0, 0, True);
+static void cli_unlink_done(struct tevent_req *subreq);
- SCVAL(cli->outbuf,smb_com,SMBrmdir);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+struct cli_unlink_state {
+ uint16_t vwv[1];
+};
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+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;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
+ if (req == NULL) {
+ return NULL;
+ }
- cli_setup_bcc(cli, p);
+ SSVAL(state->vwv+0, 0, mayhave_attrs);
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
+ 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 (cli_is_error(cli)) {
- return False;
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
}
- return True;
+ 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;
}
-/****************************************************************************
- Set or clear the delete on close flag.
-****************************************************************************/
+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);
+}
-int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
+NTSTATUS cli_unlink_recv(struct tevent_req *req)
{
- unsigned int data_len = 1;
- unsigned int param_len = 6;
- uint16 setup = TRANSACT2_SETFILEINFO;
- pstring param;
- unsigned char data;
- char *rparam=NULL, *rdata=NULL;
+ return tevent_req_simple_recv_ntstatus(req);
+}
- memset(param, 0, param_len);
- SSVAL(param,0,fnum);
- SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
+NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
+{
+ 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;
+ }
- data = flag ? 1 : 0;
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- 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 */
- )) {
- return False;
+ req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
}
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
+ status = cli_unlink_recv(req);
- return True;
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- Open a file - exposing the full horror of the NT API :-).
- Used in smbtorture.
+ Create a directory.
****************************************************************************/
-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 SecuityFlags)
+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;
- int len;
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_mkdir_state *state = NULL;
+ uint8_t additional_flags = 0;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
+ if (req == NULL) {
+ return NULL;
+ }
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ 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);
- set_message(NULL,cli->outbuf,24,0,True);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- SCVAL(cli->outbuf,smb_com,SMBntcreateX);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ 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;
+}
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- if (cli->use_oplocks)
- CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
-
- 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, SecuityFlags);
+static void cli_mkdir_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);
+}
- 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, -1, 0);
- p += len;
- SSVAL(cli->outbuf,smb_ntcreate_NameLength, len);
- /* sigh. this copes with broken netapp filer behaviour */
- p += clistr_push(cli, p, "", -1, STR_TERMINATE);
+NTSTATUS cli_mkdir_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
- cli_setup_bcc(cli, p);
+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;
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return -1;
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- if (cli_is_error(cli)) {
- return -1;
+ req = cli_mkdir_send(frame, ev, cli, dname);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- return SVAL(cli->inbuf,smb_vwv2 + 1);
-}
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
-/****************************************************************************
- Open a file.
-****************************************************************************/
+ status = cli_mkdir_recv(req);
-int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess)
-{
- return cli_nt_create_full(cli, fname, 0, DesiredAccess, 0,
- FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- Open a file
- WARNING: if you open with O_WRONLY then getattrE won't work!
+ Remove a directory.
****************************************************************************/
-int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
+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;
- unsigned openfn=0;
- unsigned accessmode=0;
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_rmdir_state *state = NULL;
+ uint8_t additional_flags = 0;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
+ if (req == NULL) {
+ return NULL;
+ }
- if (flags & O_CREAT)
- openfn |= (1<<4);
- if (!(flags & O_EXCL)) {
- if (flags & O_TRUNC)
- openfn |= (1<<1);
- else
- openfn |= (1<<0);
+ 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);
- accessmode = (share_mode<<4);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- if ((flags & O_ACCMODE) == O_RDWR) {
- accessmode |= 2;
- } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ 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;
+}
+
+static void cli_rmdir_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_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;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ 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.
+****************************************************************************/
+
+struct doc_state {
+ uint16_t setup;
+ uint8_t param[6];
+ uint8_t data[1];
+};
+
+static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct doc_state *state = tevent_req_data(req, struct doc_state);
+ NTSTATUS status;
+
+ 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;
+ }
+ tevent_req_done(req);
+}
+
+struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ bool flag)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct doc_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct doc_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
+
+ /* Setup param array. */
+ SSVAL(state->param,0,fnum);
+ SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
+
+ /* Setup data array. */
+ SCVAL(&state->data[0], 0, flag ? 1 : 0);
+
+ 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. */
+ state->param, /* param. */
+ 6, /* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ 1, /* num data. */
+ 0); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
+ return req;
+}
+
+NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
+{
+ 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_nt_delete_on_close_send(frame,
+ ev,
+ cli,
+ fnum,
+ flag);
+ 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_nt_delete_on_close_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+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)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_ntcreate_state *state;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ size_t converted_len;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ vwv = state->vwv;
+
+ SCVAL(vwv+0, 0, 0xFF);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SCVAL(vwv+2, 0, 0);
+
+ 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);
+
+ /* sigh. this copes with broken netapp filer behaviour */
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
+
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SSVAL(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;
+}
+
+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);
+}
+
+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;
+
+ 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)
+{
+ 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;
+}
+
+/****************************************************************************
+ Open a file
+ WARNING: if you open with O_WRONLY then getattrE won't work!
+****************************************************************************/
+
+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)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_open_state *state;
+ unsigned openfn;
+ unsigned accessmode;
+ uint8_t additional_flags;
+ uint8_t *bytes;
+
+ 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);
+ }
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC)
+ openfn |= (1<<1);
+ else
+ openfn |= (1<<0);
+ }
+
+ accessmode = (share_mode<<4);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
accessmode |= 1;
- }
+ }
#if defined(O_SYNC)
if ((flags & O_SYNC) == O_SYNC) {
accessmode = 0xFF;
}
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
-
- set_message(NULL,cli->outbuf,15,0,True);
-
- SCVAL(cli->outbuf,smb_com,SMBopenX);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
-
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
- SSVAL(cli->outbuf,smb_vwv3,accessmode);
- SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
- SSVAL(cli->outbuf,smb_vwv5,0);
- SSVAL(cli->outbuf,smb_vwv8,openfn);
+ 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 */
- SCVAL(cli->outbuf,smb_flg, CVAL(cli->outbuf,smb_flg)|
- FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK);
- SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
+ additional_flags =
+ FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
+ SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
}
-
- p = smb_buf(cli->outbuf);
- p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
+ bytes = talloc_array(state, uint8_t, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+ strlen(fname)+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;
+ state->bytes.iov_base = (void *)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;
+}
+
+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;
+ NTSTATUS status;
+
+ req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
+ &subreq);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = cli_smb_req_send(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+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;
+ NTSTATUS status;
+
+ status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ state->fnum = SVAL(vwv+2, 0);
+ tevent_req_done(req);
+}
+
+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;
+}
+
+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 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_open_send(frame, ev, cli, fname, flags, share_mode);
+ 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;
}
- return SVAL(cli->inbuf,smb_vwv2);
+ status = cli_open_recv(req, pfnum);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
Close a file.
****************************************************************************/
-BOOL cli_close(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)
{
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ struct tevent_req *req, *subreq;
+ struct cli_close_state *state;
- set_message(NULL,cli->outbuf,3,0,True);
+ req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
+ if (req == NULL) {
+ return NULL;
+ }
- SCVAL(cli->outbuf,smb_com,SMBclose);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ SSVAL(state->vwv+0, 0, fnum);
+ SIVALS(state->vwv+1, 0, -1);
- SSVAL(cli->outbuf,smb_vwv0,fnum);
- SIVALS(cli->outbuf,smb_vwv1,-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;
+}
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
+struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum)
+{
+ struct tevent_req *req, *subreq;
+ NTSTATUS status;
+
+ req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = cli_smb_req_send(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void cli_close_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_close_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
+{
+ 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_close_send(frame, ev, cli, fnum);
+ 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_close_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+/****************************************************************************
+ Truncate a file to a specified size
+****************************************************************************/
+
+struct ftrunc_state {
+ uint16_t setup;
+ uint8_t param[6];
+ uint8_t data[8];
+};
+
+static void cli_ftruncate_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct ftrunc_state *state = tevent_req_data(req, struct ftrunc_state);
+ NTSTATUS status;
+
+ 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;
+ }
+ tevent_req_done(req);
+}
+
+struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t size)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct ftrunc_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
+ if (req == NULL) {
+ return NULL;
}
- return !cli_is_error(cli);
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
+
+ /* Setup param array. */
+ SSVAL(state->param,0,fnum);
+ SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
+ SSVAL(state->param,4,0);
+
+ /* Setup data array. */
+ SBVAL(state->data, 0, size);
+
+ 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. */
+ state->param, /* param. */
+ 6, /* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ 8, /* num data. */
+ 0); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_ftruncate_done, req);
+ return req;
+}
+
+NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
}
+NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
+{
+ 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_ftruncate_send(frame,
+ ev,
+ cli,
+ fnum,
+ size);
+ 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_ftruncate_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
/****************************************************************************
- send a lock with a specified locktype
+ send a lock with a specified locktype
this is used for testing LOCKING_ANDX_CANCEL_LOCK
****************************************************************************/
-NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
- uint32 offset, uint32 len, int timeout, unsigned char locktype)
+NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
+ uint32_t offset, uint32_t len,
+ int timeout, unsigned char locktype)
{
char *p;
int saved_timeout = cli->timeout;
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0', smb_size);
- set_message(NULL,cli->outbuf,8,0,True);
+ cli_set_message(cli->outbuf,8,0,True);
SCVAL(cli->outbuf,smb_com,SMBlockingX);
SSVAL(cli->outbuf,smb_tid,cli->cnum);
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;
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0', smb_size);
- set_message(NULL,cli->outbuf,8,0,True);
+ cli_set_message(cli->outbuf,8,0,True);
SCVAL(cli->outbuf,smb_com,SMBlockingX);
SSVAL(cli->outbuf,smb_tid,cli->cnum);
Unlock a file.
****************************************************************************/
-BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
-{
- char *p;
-
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+struct cli_unlock_state {
+ uint16_t vwv[8];
+ uint8_t data[10];
+};
- set_message(NULL,cli->outbuf,8,0,True);
+static void cli_unlock_done(struct tevent_req *subreq);
- SCVAL(cli->outbuf,smb_com,SMBlockingX);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t offset,
+ uint64_t len)
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,fnum);
- SCVAL(cli->outbuf,smb_vwv3,0);
- SIVALS(cli->outbuf, smb_vwv4, 0);
- SSVAL(cli->outbuf,smb_vwv6,1);
- SSVAL(cli->outbuf,smb_vwv7,0);
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_unlock_state *state = NULL;
+ uint8_t additional_flags = 0;
- p = smb_buf(cli->outbuf);
- SSVAL(p, 0, cli->pid);
- SIVAL(p, 2, offset);
- SIVAL(p, 6, len);
- p += 10;
- cli_setup_bcc(cli, p);
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
+ req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
+ if (req == NULL) {
+ return NULL;
}
- if (cli_is_error(cli)) {
- return False;
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SSVAL(state->vwv+2, 0, fnum);
+ SCVAL(state->vwv+3, 0, 0);
+ SIVALS(state->vwv+4, 0, 0);
+ SSVAL(state->vwv+6, 0, 1);
+ SSVAL(state->vwv+7, 0, 0);
+
+ SSVAL(state->data, 0, cli->pid);
+ SIVAL(state->data, 2, offset);
+ SIVAL(state->data, 6, len);
+
+ subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
+ 8, state->vwv, 10, state->data);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
-
- return True;
+ tevent_req_set_callback(subreq, cli_unlock_done, req);
+ return req;
}
-/****************************************************************************
+static void cli_unlock_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_unlock_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_unlock(struct cli_state *cli,
+ uint16_t fnum,
+ uint32_t offset,
+ uint32_t len)
+{
+ 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_unlock_send(frame, ev, cli,
+ fnum, offset, len);
+ 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_unlock_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+/****************************************************************************
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;
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0', smb_size);
- set_message(NULL,cli->outbuf,8,0,True);
+ cli_set_message(cli->outbuf,8,0,True);
SCVAL(cli->outbuf,smb_com,SMBlockingX);
SSVAL(cli->outbuf,smb_tid,cli->cnum);
Unlock a file with 64 bit offsets.
****************************************************************************/
-BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+struct cli_unlock64_state {
+ uint16_t vwv[8];
+ uint8_t data[20];
+};
+
+static void cli_unlock64_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t offset,
+ uint64_t len)
+
{
- char *p;
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_unlock64_state *state = NULL;
+ uint8_t additional_flags = 0;
- if (! (cli->capabilities & CAP_LARGE_FILES)) {
- return cli_unlock(cli, fnum, offset, len);
+ req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
+ if (req == NULL) {
+ return NULL;
}
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ SCVAL(state->vwv+0, 0, 0xff);
+ SSVAL(state->vwv+2, 0, fnum);
+ SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
+ SIVALS(state->vwv+4, 0, 0);
+ SSVAL(state->vwv+6, 0, 1);
+ SSVAL(state->vwv+7, 0, 0);
+
+ SIVAL(state->data, 0, cli->pid);
+ SOFF_T_R(state->data, 4, offset);
+ SOFF_T_R(state->data, 12, len);
+
+ subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
+ 8, state->vwv, 20, state->data);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_unlock64_done, req);
+ return req;
+}
- set_message(NULL,cli->outbuf,8,0,True);
+static void cli_unlock64_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);
+}
- SCVAL(cli->outbuf,smb_com,SMBlockingX);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+NTSTATUS cli_unlock64_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,fnum);
- SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
- SIVALS(cli->outbuf, smb_vwv4, 0);
- SSVAL(cli->outbuf,smb_vwv6,1);
- SSVAL(cli->outbuf,smb_vwv7,0);
+NTSTATUS cli_unlock64(struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t offset,
+ uint64_t len)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
- p = smb_buf(cli->outbuf);
- SIVAL(p, 0, cli->pid);
- SOFF_T_R(p, 4, offset);
- SOFF_T_R(p, 12, len);
- p += 20;
- cli_setup_bcc(cli, p);
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_unlock(cli, fnum, offset, len);
}
- if (cli_is_error(cli)) {
- return False;
+ 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_unlock64_send(frame, ev, cli,
+ fnum, offset, len);
+ 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_unlock64_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
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)
+struct posix_lock_state {
+ uint16_t setup;
+ uint8_t param[4];
+ uint8_t data[POSIX_LOCK_DATA_SIZE];
+};
+
+static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
{
- unsigned int param_len = 4;
- unsigned int data_len = POSIX_LOCK_DATA_SIZE;
- uint16 setup = TRANSACT2_SETFILEINFO;
- char param[4];
- unsigned char data[POSIX_LOCK_DATA_SIZE];
- char *rparam=NULL, *rdata=NULL;
- int saved_timeout = cli->timeout;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct posix_lock_state *state = tevent_req_data(req, struct posix_lock_state);
+ NTSTATUS status;
+
+ 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;
+ }
+ tevent_req_done(req);
+}
- SSVAL(param,0,fnum);
- SSVAL(param,2,SMB_SET_POSIX_LOCK);
+static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t offset,
+ uint64_t len,
+ bool wait_lock,
+ enum brl_type lock_type)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct posix_lock_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
+
+ /* Setup param array. */
+ SSVAL(&state->param, 0, fnum);
+ SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
+
+ /* Setup data array. */
switch (lock_type) {
case READ_LOCK:
- SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
+ SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
+ POSIX_LOCK_TYPE_READ);
break;
case WRITE_LOCK:
- SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
+ SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
+ POSIX_LOCK_TYPE_WRITE);
break;
case UNLOCK_LOCK:
- SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+ SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
+ POSIX_LOCK_TYPE_UNLOCK);
break;
default:
- return False;
+ return NULL;
}
if (wait_lock) {
- SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
- cli->timeout = 0x7FFFFFFF;
+ SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
+ POSIX_LOCK_FLAG_WAIT);
} else {
- SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
+ SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
+ POSIX_LOCK_FLAG_NOWAIT);
}
- SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
- SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
- SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
+ SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
+ SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
+ SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
+
+ 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. */
+ state->param, /* param. */
+ 4, /* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ POSIX_LOCK_DATA_SIZE, /* 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_unlock_internal_done, req);
+ return req;
+}
- 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 */
- )) {
- cli->timeout = saved_timeout;
- return False;
+/****************************************************************************
+ POSIX Lock a file.
+****************************************************************************/
+
+struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t offset,
+ uint64_t len,
+ bool wait_lock,
+ enum brl_type lock_type)
+{
+ return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
+ wait_lock, lock_type);
+}
+
+NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
}
+ return NT_STATUS_OK;
+}
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- cli->timeout = saved_timeout;
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
- return False;
+NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
+ uint64_t offset, uint64_t len,
+ bool wait_lock, enum brl_type lock_type)
+{
+ 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;
}
- cli->timeout = saved_timeout;
+ if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- return True;
+ req = cli_posix_lock_send(frame,
+ ev,
+ cli,
+ fnum,
+ offset,
+ len,
+ wait_lock,
+ lock_type);
+ 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_lock_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- POSIX Lock a file.
+ POSIX Unlock a file.
****************************************************************************/
-BOOL cli_posix_lock(struct cli_state *cli, int fnum,
- SMB_BIG_UINT offset, SMB_BIG_UINT len,
- BOOL wait_lock, enum brl_type lock_type)
+struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ uint64_t offset,
+ uint64_t len)
{
- if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
- return False;
+ return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
+ false, UNLOCK_LOCK);
+}
+
+NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
+{
+ 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_unlock_send(frame,
+ ev,
+ cli,
+ fnum,
+ offset,
+ len);
+ 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;
}
- return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
+
+ status = cli_posix_unlock_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- POSIX Unlock a file.
+ Do a SMBgetattrE call.
****************************************************************************/
-BOOL cli_posix_unlock(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+static void cli_getattrE_done(struct tevent_req *subreq);
+
+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;
+};
+
+struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum)
{
- return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_getattrE_state *state = NULL;
+ uint8_t additional_flags = 0;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ 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;
}
-/****************************************************************************
- POSIX Get any lock covering a file.
-****************************************************************************/
+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);
+}
-BOOL cli_posix_getlock(struct cli_state *cli, int fnum, SMB_BIG_UINT *poffset, SMB_BIG_UINT *plen)
+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)
{
- return True;
+ 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 = 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;
+}
+
+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;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = cli_getattrE_send(frame, ev, cli, fnum);
+ 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_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 SMBgetattrE call.
+ Do a SMBgetatr 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)
+static void cli_getatr_done(struct tevent_req *subreq);
+
+struct cli_getatr_state {
+ int zone_offset;
+ uint16_t attr;
+ SMB_OFF_T size;
+ time_t write_time;
+};
+
+struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname)
{
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_getatr_state *state = NULL;
+ uint8_t additional_flags = 0;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
+ if (req == NULL) {
+ return NULL;
+ }
- set_message(NULL,cli->outbuf,1,0,True);
+ state->zone_offset = cli->serverzone;
- SCVAL(cli->outbuf,smb_com,SMBgetattrE);
- 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,
+ strlen(fname)+1, NULL);
- SSVAL(cli->outbuf,smb_vwv0,fd);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(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);
}
-
- if (cli_is_error(cli)) {
- return False;
+ tevent_req_set_callback(subreq, cli_getatr_done, req);
+ return req;
+}
+
+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 = IVAL(cli->inbuf, smb_vwv6);
+ *size = state->size;
+ }
+ if (write_time) {
+ *write_time = state->write_time;
}
+ return NT_STATUS_OK;
+}
- if (attr) {
- *attr = SVAL(cli->inbuf,smb_vwv10);
+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;
}
- 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_getatr_send(frame, ev, cli, fname);
+ 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_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 SMBgetatr call
+ Do a SMBsetattrE call.
****************************************************************************/
-BOOL cli_getatr(struct cli_state *cli, const char *fname,
- uint16 *attr, SMB_OFF_T *size, time_t *write_time)
+static void cli_setattrE_done(struct tevent_req *subreq);
+
+struct cli_setattrE_state {
+ uint16_t vwv[7];
+};
+
+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;
- 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;
+ }
- set_message(NULL,cli->outbuf,0,0,True);
+ SSVAL(state->vwv+0, 0, fnum);
+ cli_put_dos_date2(cli, (char *)&state->vwv[1], 0, change_time);
+ cli_put_dos_date2(cli, (char *)&state->vwv[3], 0, access_time);
+ cli_put_dos_date2(cli, (char *)&state->vwv[5], 0, write_time);
- SCVAL(cli->outbuf,smb_com,SMBgetatr);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
+ 7, state->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;
+}
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+static void cli_setattrE_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);
+}
- 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;
}
-
- if (cli_is_error(cli)) {
- return False;
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- if (size) {
- *size = IVAL(cli->inbuf, smb_vwv3);
+ 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 (write_time) {
- *write_time = cli_make_unix_date3(cli, cli->inbuf+smb_vwv1);
+ 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;
+ }
+
+ 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 (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
+
+ status = cli_setatr_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+/****************************************************************************
+ Check for existance of a dir.
+****************************************************************************/
+
+static void cli_chkpath_done(struct tevent_req *subreq);
+
+struct cli_chkpath_state {
+ int dummy;
+};
+
+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;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
+ if (req == NULL) {
+ return NULL;
}
- if (attr) {
- *attr = SVAL(cli->inbuf,smb_vwv0);
+ 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);
+ }
- return True;
+ 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;
}
-/****************************************************************************
- 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_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);
+}
+NTSTATUS cli_chkpath_recv(struct tevent_req *req)
{
- char *p;
+ return tevent_req_simple_recv_ntstatus(req);
+}
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
+{
+ 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;
+ }
- set_message(NULL,cli->outbuf,7,0,True);
+ path2 = talloc_strdup(frame, path);
+ if (!path2) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ trim_char(path2,'\0','\\');
+ if (!*path2) {
+ path2 = talloc_strdup(frame, "\\");
+ if (!path2) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ }
- SCVAL(cli->outbuf,smb_com,SMBsetattrE);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- 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);
+ req = cli_chkpath_send(frame, ev, cli, path2);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- p = smb_buf(cli->outbuf);
- *p++ = 4;
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
+ }
- cli_setup_bcc(cli, p);
+ status = cli_chkpath_recv(req);
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
- }
-
- if (cli_is_error(cli)) {
- return False;
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
}
-
- return True;
+ return status;
}
/****************************************************************************
- Do a SMBsetatr call.
+ Query disk space.
****************************************************************************/
-BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
-{
- char *p;
+static void cli_dskattr_done(struct tevent_req *subreq);
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+struct cli_dskattr_state {
+ int bsize;
+ int total;
+ int avail;
+};
- set_message(NULL,cli->outbuf,8,0,True);
+struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct cli_dskattr_state *state = NULL;
+ uint8_t additional_flags = 0;
- SCVAL(cli->outbuf,smb_com,SMBsetatr);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
+ if (req == NULL) {
+ return NULL;
+ }
- SSVAL(cli->outbuf,smb_vwv0, attr);
- cli_put_dos_date3(cli, cli->outbuf,smb_vwv1, t);
+ 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;
+}
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
- *p++ = 4;
+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);
+}
- cli_setup_bcc(cli, p);
+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;
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
- }
-
- if (cli_is_error(cli)) {
- return False;
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
}
-
- return True;
+ *bsize = state->bsize;
+ *total = state->total;
+ *avail = state->avail;
+ return NT_STATUS_OK;
}
-/****************************************************************************
- Check for existance of a dir.
-****************************************************************************/
-BOOL cli_chkpath(struct cli_state *cli, const char *path)
+NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
{
- pstring path2;
- char *p;
-
- pstrcpy(path2,path);
- trim_char(path2,'\0','\\');
- if (!*path2)
- *path2 = '\\';
-
- memset(cli->outbuf,'\0',smb_size);
- set_message(NULL,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, -1, STR_TERMINATE);
+ 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;
+ }
- 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_dskattr_send(frame, ev, cli);
+ 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_dskattr_recv(req, bsize, total, avail);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
- Query disk space.
+ Create and open a temporary file.
****************************************************************************/
-BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+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)
{
- memset(cli->outbuf,'\0',smb_size);
- set_message(NULL,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 ctemp_state *state = NULL;
+ uint8_t additional_flags = 0;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
+ if (req == NULL) {
+ return NULL;
+ }
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return False;
+ SSVAL(state->vwv,0,0);
+ SIVALS(state->vwv+1,0,-1);
+
+ 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);
}
- *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
- *total = SVAL(cli->inbuf,smb_vwv0);
- *avail = SVAL(cli->inbuf,smb_vwv3);
-
- return True;
+ 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;
}
-/****************************************************************************
- 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)
{
- int len;
- char *p;
+ 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;
+
+ status = cli_smb_recv(subreq, 1, &wcnt, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
+ state->fnum = SVAL(vwv+0, 0);
- set_message(NULL,cli->outbuf,3,0,True);
+ TALLOC_FREE(subreq);
- SCVAL(cli->outbuf,smb_com,SMBctemp);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+ /* From W2K3, the result is just the ASCII name */
+ if (num_bytes < 2) {
+ tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
+ return;
+ }
- SSVAL(cli->outbuf,smb_vwv0,0);
- SIVALS(cli->outbuf,smb_vwv1,-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);
+}
- p = smb_buf(cli->outbuf);
- *p++ = 4;
- p += clistr_push(cli, p, path, -1, STR_TERMINATE);
+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;
- cli_setup_bcc(cli, p);
+ 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;
+}
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return -1;
+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;
}
- if (cli_is_error(cli)) {
- return -1;
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- /* 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) return -1;
+ req = cli_ctemp_send(frame, ev, cli, path);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
- if (tmp_path) {
- pstring path2;
- clistr_pull(cli, path2, p,
- sizeof(path2), len, STR_ASCII);
- *tmp_path = SMB_STRDUP(path2);
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix(errno);
+ goto fail;
}
- return SVAL(cli->inbuf,smb_vwv0);
-}
+ 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;
+}
-/*
+/*
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);
- set_message(NULL,cli->outbuf, 3, 0, True);
+ cli_set_message(cli->outbuf, 3, 0, True);
SCVAL(cli->outbuf,smb_com,SMBioctl);
cli_setup_packet(cli);
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;
char *data = NULL;
char *rparam=NULL, *rdata=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 */
- data, data_len, cli->max_xmit /* data, length, max */
- )) {
- return False;
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(data);
+ return False;
}
if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ &rparam, ¶m_len,
+ &rdata, &data_len)) {
+ SAFE_FREE(data);
+ return false;
}
SAFE_FREE(data);
Set an extended attribute on a pathname.
*********************************************************/
-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_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[sizeof(pstring)+6];
+ char *param;
size_t srclen = 2*(strlen(path)+1);
char *p;
+ bool ret;
- memset(param, 0, sizeof(param));
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
SSVAL(param,0,SMB_INFO_SET_EA);
p = ¶m[6];
- p += clistr_push(cli, p, path, MIN(srclen, sizeof(param)-6), STR_TERMINATE);
+ p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
param_len = PTR_DIFF(p, param);
- return cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
+ ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
+ SAFE_FREE(param);
+ return ret;
}
/*********************************************************
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);
}
/*********************************************************
- Get an extended attribute list tility fn.
+ Get an extended attribute list utility fn.
*********************************************************/
-static BOOL cli_get_ea_list(struct cli_state *cli,
- uint16 setup, char *param, unsigned int param_len,
+static bool cli_get_ea_list(struct cli_state *cli,
+ uint16_t setup, char *param, unsigned int param_len,
TALLOC_CTX *ctx,
size_t *pnum_eas,
struct ea_struct **pea_list)
char *p;
size_t ea_size;
size_t num_eas;
- BOOL ret = False;
+ bool ret = False;
struct ea_struct *ea_list;
*pnum_eas = 0;
Get an extended attribute list from a pathname.
*********************************************************/
-BOOL cli_get_ea_list_path(struct cli_state *cli, const char *path,
+bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
TALLOC_CTX *ctx,
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[sizeof(pstring)+6];
+ char *param;
char *p;
+ size_t srclen = 2*(strlen(path)+1);
+ bool ret;
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
p = param;
memset(p, 0, 6);
SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
p += 6;
- p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
+ p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
param_len = PTR_DIFF(p, param);
- return cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
+ ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
+ SAFE_FREE(param);
+ return ret;
}
/*********************************************************
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);
}
/****************************************************************************
- 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:
Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
****************************************************************************/
-static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int flags, mode_t mode, BOOL is_dir)
+struct posix_open_state {
+ uint16_t setup;
+ uint8_t *param;
+ uint8_t data[18];
+ uint16_t fnum; /* Out */
+};
+
+static void cli_posix_open_internal_done(struct tevent_req *subreq)
{
- unsigned int data_len = 0;
- unsigned int param_len = 0;
- uint16 setup = TRANSACT2_SETPATHINFO;
- char param[sizeof(pstring)+6];
- char data[18];
- char *rparam=NULL, *rdata=NULL;
- char *p;
- int fnum = -1;
- uint32 wire_flags = open_flags_to_wire(flags);
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
+ NTSTATUS status;
+ uint8_t *data;
+ uint32_t num_data;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, &data, &num_data);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ if (num_data < 12) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ state->fnum = SVAL(data,2);
+ tevent_req_done(req);
+}
- memset(param, 0, sizeof(param));
- SSVAL(param,0, SMB_POSIX_PATH_OPEN);
- p = ¶m[6];
+static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ int flags,
+ mode_t mode,
+ bool is_dir)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct posix_open_state *state = NULL;
+ uint32_t wire_flags = open_flags_to_wire(flags);
- p += clistr_push(cli, p, fname, sizeof(param)-6, STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+ req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
+ if (req == NULL) {
+ return NULL;
+ }
- if (is_dir) {
- wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
- wire_flags |= SMB_O_DIRECTORY;
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
+
+ /* Setup param array. */
+ state->param = talloc_array(state, uint8_t, 6);
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
}
+ memset(state->param, '\0', 6);
+ SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
- p = data;
- SIVAL(p,0,0); /* No oplock. */
- SIVAL(p,4,wire_flags);
- SIVAL(p,8,unix_perms_to_wire(mode));
- SIVAL(p,12,0); /* Top bits of perms currently undefined. */
- SSVAL(p,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
+ state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
+ strlen(fname)+1, NULL);
- data_len = 18;
+ if (tevent_req_nomem(state->param, req)) {
+ return tevent_req_post(req, ev);
+ }
- 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 */
- )) {
- return -1;
+ /* Setup data words. */
+ if (is_dir) {
+ wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+ wire_flags |= SMB_O_DIRECTORY;
}
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return -1;
+ SIVAL(state->data,0,0); /* No oplock. */
+ SIVAL(state->data,4,wire_flags);
+ SIVAL(state->data,8,unix_perms_to_wire(mode));
+ SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
+ SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
+
+ 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. */
+ state->param, /* param. */
+ talloc_get_size(state->param),/* num param. */
+ 2, /* max returned param. */
+ state->data, /* data. */
+ 18, /* num data. */
+ 12); /* max returned data. */
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
+ return req;
+}
- fnum = SVAL(rdata,2);
+struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ int flags,
+ mode_t mode)
+{
+ return cli_posix_open_internal_send(mem_ctx, ev,
+ cli, fname, flags, mode, false);
+}
- SAFE_FREE(rdata);
- SAFE_FREE(rparam);
+NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
+{
+ struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
+ NTSTATUS status;
- return fnum;
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *pfnum = state->fnum;
+ return NT_STATUS_OK;
}
/****************************************************************************
- open - POSIX semantics.
+ Open - POSIX semantics. Doesn't request oplock.
****************************************************************************/
-int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode)
+NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
+ int flags, mode_t mode, uint16_t *pfnum)
+{
+
+ 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_open_send(frame,
+ ev,
+ cli,
+ fname,
+ flags,
+ mode);
+ 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_open_recv(req, pfnum);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
+}
+
+struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct cli_state *cli,
+ const char *fname,
+ mode_t mode)
{
- return cli_posix_open_internal(cli, fname, flags, mode, False);
+ return cli_posix_open_internal_send(mem_ctx, ev,
+ cli, fname, O_CREAT, mode, true);
}
-/****************************************************************************
- mkdir - POSIX semantics.
-****************************************************************************/
+NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
-int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
+NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
{
- return (cli_posix_open_internal(cli, fname, O_CREAT, mode, True) == -1) ? -1 : 0;
+ 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_mkdir_send(frame,
+ ev,
+ cli,
+ fname,
+ mode);
+ 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_mkdir_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_set_error(cli, status);
+ }
+ return status;
}
/****************************************************************************
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[sizeof(pstring)+6];
- char data[2];
- char *rparam=NULL, *rdata=NULL;
- char *p;
+ 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;
+
+ 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;
+ }
+ tevent_req_done(req);
+}
- memset(param, 0, sizeof(param));
- SSVAL(param,0, SMB_POSIX_PATH_UNLINK);
- p = ¶m[6];
+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;
- p += clistr_push(cli, p, fname, sizeof(param)-6, STR_TERMINATE);
- param_len = PTR_DIFF(p, param);
+ req = tevent_req_create(mem_ctx, &state, struct unlink_state);
+ if (req == NULL) {
+ return NULL;
+ }
- SSVAL(data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
- SMB_POSIX_UNLINK_FILE_TARGET);
- data_len = 2;
+ /* Setup setup word. */
+ SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
- 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 */
- )) {
- return False;
+ /* 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);
- if (!cli_receive_trans(cli, SMBtrans2,
- &rparam, ¶m_len,
- &rdata, &data_len)) {
- return False;
+ param = trans2_bytes_push_str(param, cli_ucs2(cli), fname,
+ strlen(fname)+1, NULL);
+
+ 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)
+{
+ 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);
+
+ 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)
{
- return cli_posix_unlink_internal(cli, fname, True);
+ 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)
+{
+ 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;
}