s3: Explicitly handle inbuf in cli_message_start_done
[samba.git] / source3 / libsmb / clifile.c
index af67fcb7467496954a46744ab03fffdfbc8acdc8..6e7a74f8d5d6e42d938008e14c0fe685b15b3439 100644 (file)
@@ -119,18 +119,9 @@ struct link_state {
 
 static void cli_posix_link_internal_done(struct tevent_req *subreq)
 {
-       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);
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
@@ -289,8 +280,8 @@ static void cli_posix_readlink_done(struct tevent_req *subreq)
        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);
+       status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
+                               &state->data, 0, &state->num_data);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -637,8 +628,8 @@ static void cli_posix_getfacl_done(struct tevent_req *subreq)
        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);
+       status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
+                               &state->data, 0, &state->num_data);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -786,8 +777,8 @@ static void cli_posix_stat_done(struct tevent_req *subreq)
        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);
+       status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
+                               &state->data, 96, &state->num_data);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -954,18 +945,9 @@ struct ch_state {
 
 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
 {
-       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);
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
@@ -1256,7 +1238,7 @@ static void cli_rename_done(struct tevent_req *subreq)
                                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -1382,7 +1364,7 @@ static void cli_ntrename_internal_done(struct tevent_req *subreq)
                                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -1577,7 +1559,7 @@ static void cli_unlink_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -1685,7 +1667,7 @@ static void cli_mkdir_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -1793,7 +1775,7 @@ static void cli_rmdir_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -1861,18 +1843,9 @@ struct doc_state {
 
 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);
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
@@ -1893,7 +1866,6 @@ struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
        SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
 
        /* Setup param array. */
-       memset(state->param, '\0', 6);
        SSVAL(state->param,0,fnum);
        SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
 
@@ -2010,6 +1982,7 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
        if (req == NULL) {
                return NULL;
        }
+
        vwv = state->vwv;
 
        SCVAL(vwv+0, 0, 0xFF);
@@ -2044,7 +2017,7 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       SIVAL(vwv+2, 1, converted_len);
+       SSVAL(vwv+2, 1, converted_len);
 
        subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
                              talloc_get_size(bytes), bytes);
@@ -2065,11 +2038,13 @@ static void cli_ntcreate_done(struct tevent_req *subreq)
        uint16_t *vwv;
        uint32_t num_bytes;
        uint8_t *bytes;
+       uint8_t *inbuf;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes);
+       status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
+                             &num_bytes, &bytes);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(subreq);
                tevent_req_nterror(req, status);
                return;
        }
@@ -2277,11 +2252,13 @@ static void cli_open_done(struct tevent_req *subreq)
                req, struct cli_open_state);
        uint8_t wct;
        uint16_t *vwv;
+       uint8_t *inbuf;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
+       status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
+                             NULL);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(subreq);
                tevent_req_nterror(req, status);
                return;
        }
@@ -2367,6 +2344,7 @@ struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
        if (req == NULL) {
                return NULL;
        }
+
        SSVAL(state->vwv+0, 0, fnum);
        SIVALS(state->vwv+1, 0, -1);
 
@@ -2408,7 +2386,7 @@ static void cli_close_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -2475,18 +2453,9 @@ struct ftrunc_state {
 
 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);
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
@@ -2708,42 +2677,114 @@ bool cli_lock(struct cli_state *cli, uint16_t fnum,
  Unlock a file.
 ****************************************************************************/
 
-bool cli_unlock(struct cli_state *cli, uint16_t fnum, uint32_t offset, uint32_t len)
+struct cli_unlock_state {
+       uint16_t vwv[8];
+       uint8_t data[10];
+};
+
+static void cli_unlock_done(struct tevent_req *subreq);
+
+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)
+
 {
-       char *p;
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_unlock_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_unlock_state);
+       if (req == NULL) {
+               return NULL;
+       }
 
-       cli_set_message(cli->outbuf,8,0,True);
+       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);
 
-       SCVAL(cli->outbuf,smb_com,SMBlockingX);
-       SSVAL(cli->outbuf,smb_tid,cli->cnum);
-       cli_setup_packet(cli);
+       SSVAL(state->data, 0, cli->pid);
+       SIVAL(state->data, 2, offset);
+       SIVAL(state->data, 6, 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);
+       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);
+       }
+       tevent_req_set_callback(subreq, cli_unlock_done, req);
+       return req;
+}
 
-       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;
+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, NULL, NULL, 0, NULL, NULL, NULL, NULL);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
        }
+       tevent_req_done(req);
+}
 
-       if (cli_is_error(cli)) {
-               return False;
+NTSTATUS cli_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;
        }
 
-       return True;
+       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;
 }
 
 /****************************************************************************
@@ -2811,149 +2852,369 @@ bool cli_lock64(struct cli_state *cli, uint16_t fnum,
  Unlock a file with 64 bit offsets.
 ****************************************************************************/
 
-bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t 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);
 
-       cli_set_message(cli->outbuf,8,0,True);
+       SIVAL(state->data, 0, cli->pid);
+       SOFF_T_R(state->data, 4, offset);
+       SOFF_T_R(state->data, 12, len);
 
-       SCVAL(cli->outbuf,smb_com,SMBlockingX);
-       SSVAL(cli->outbuf,smb_tid,cli->cnum);
-       cli_setup_packet(cli);
+       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;
+}
 
-       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);
+static void cli_unlock64_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+                               subreq, struct tevent_req);
+       NTSTATUS status;
 
-       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;
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
        }
+       tevent_req_done(req);
+}
 
-       if (cli_is_error(cli)) {
-               return False;
+NTSTATUS cli_unlock64_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+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;
+
+       if (! (cli->capabilities & CAP_LARGE_FILES)) {
+               return cli_unlock(cli, fnum, offset, len);
        }
 
-       return True;
+       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_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, uint16_t fnum,
-               uint64_t offset, uint64_t 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_t setup = TRANSACT2_SETFILEINFO;
-       char param[4];
-       unsigned char data[POSIX_LOCK_DATA_SIZE];
-       char *rparam=NULL, *rdata=NULL;
-       int saved_timeout = cli->timeout;
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
+}
 
-       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(&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. */
 
-       SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
-       SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
-       SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
-
-       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;
-       }
-
-       if (!cli_receive_trans(cli, SMBtrans2,
-                               &rparam, &param_len,
-                               &rdata, &data_len)) {
-               cli->timeout = saved_timeout;
-               SAFE_FREE(rdata);
-               SAFE_FREE(rparam);
-               return False;
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
        }
-
-       cli->timeout = saved_timeout;
-
-       SAFE_FREE(rdata);
-       SAFE_FREE(rparam);
-
-       return True;
+       tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
+       return req;
 }
 
 /****************************************************************************
  POSIX Lock a file.
 ****************************************************************************/
 
-bool cli_posix_lock(struct cli_state *cli, uint16_t fnum,
+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;
+}
+
+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;
+       }
+
        if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
-               return False;
+               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_lock_send(frame,
+                               ev,
+                               cli,
+                               fnum,
+                               offset,
+                               len,
+                               wait_lock,
+                               lock_type);
+       if (req == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
        }
-       return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
+
+       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 Unlock a file.
 ****************************************************************************/
 
-bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
+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)
 {
-       return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
+       return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
+                                       false, UNLOCK_LOCK);
 }
 
-/****************************************************************************
- POSIX Get any lock covering a file.
-****************************************************************************/
+NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
+{
+       NTSTATUS status;
 
-bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen)
+       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)
 {
-       return True;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev = NULL;
+       struct tevent_req *req = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+
+       if (cli_has_async_calls(cli)) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       req = cli_posix_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_posix_unlock_recv(req);
+
+ fail:
+       TALLOC_FREE(frame);
+       if (!NT_STATUS_IS_OK(status)) {
+               cli_set_error(cli, status);
+       }
+       return status;
 }
 
 /****************************************************************************
@@ -3006,9 +3267,12 @@ static void cli_getattrE_done(struct tevent_req *subreq)
                req, struct cli_getattrE_state);
        uint8_t wct;
        uint16_t *vwv = NULL;
+       uint8_t *inbuf;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL);
+       status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
+                             NULL, NULL);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return;
@@ -3020,7 +3284,6 @@ static void cli_getattrE_done(struct tevent_req *subreq)
        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);
 }
 
@@ -3168,9 +3431,12 @@ static void cli_getatr_done(struct tevent_req *subreq)
                req, struct cli_getatr_state);
        uint8_t wct;
        uint16_t *vwv = NULL;
+       uint8_t *inbuf;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
+       status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
+                             NULL);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return;
@@ -3180,7 +3446,6 @@ static void cli_getatr_done(struct tevent_req *subreq)
        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);
 }
 
@@ -3264,7 +3529,7 @@ NTSTATUS cli_getatr(struct cli_state *cli,
 static void cli_setattrE_done(struct tevent_req *subreq);
 
 struct cli_setattrE_state {
-       int dummy;
+       uint16_t vwv[7];
 };
 
 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
@@ -3278,21 +3543,19 @@ struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_setattrE_state *state = NULL;
        uint8_t additional_flags = 0;
-       uint16_t vwv[7];
 
        req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
        if (req == NULL) {
                return NULL;
        }
 
-       memset(vwv, '\0', sizeof(vwv));
-       SSVAL(vwv+0, 0, fnum);
-       cli_put_dos_date2(cli, (char *)&vwv[1], 0, change_time);
-       cli_put_dos_date2(cli, (char *)&vwv[3], 0, access_time);
-       cli_put_dos_date2(cli, (char *)&vwv[5], 0, write_time);
+       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);
 
        subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
-                             7, vwv, 0, NULL);
+                             7, state->vwv, 0, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -3306,7 +3569,7 @@ static void cli_setattrE_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -3399,7 +3662,6 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       memset(state->vwv, '\0', sizeof(state->vwv));
        SSVAL(state->vwv+0, 0, attr);
        cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime);
 
@@ -3441,7 +3703,7 @@ static void cli_setatr_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -3552,7 +3814,7 @@ static void cli_chkpath_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
+       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -3665,9 +3927,12 @@ static void cli_dskattr_done(struct tevent_req *subreq)
                req, struct cli_dskattr_state);
        uint8_t wct;
        uint16_t *vwv = NULL;
+       uint8_t *inbuf;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
+       status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
+                             NULL);
+       TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
                return;
@@ -3675,7 +3940,6 @@ static void cli_dskattr_done(struct tevent_req *subreq)
        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);
 }
 
@@ -3797,8 +4061,10 @@ static void cli_ctemp_done(struct tevent_req *subreq)
        uint16_t *vwv;
        uint32_t num_bytes = 0;
        uint8_t *bytes = NULL;
+       uint8_t *inbuf;
 
-       status = cli_smb_recv(subreq, 1, &wcnt, &vwv, &num_bytes, &bytes);
+       status = cli_smb_recv(subreq, state, &inbuf, 1, &wcnt, &vwv,
+                             &num_bytes, &bytes);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
                tevent_req_nterror(req, status);
@@ -3897,28 +4163,20 @@ NTSTATUS cli_ctemp(struct cli_state *cli,
 */
 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);
-
-       cli_set_message(cli->outbuf, 3, 0, True);
-       SCVAL(cli->outbuf,smb_com,SMBioctl);
-       cli_setup_packet(cli);
-
-       SSVAL(cli->outbuf, smb_vwv0, fnum);
-       SSVAL(cli->outbuf, smb_vwv1, code>>16);
-       SSVAL(cli->outbuf, smb_vwv2, (code&0xFFFF));
+       uint16_t vwv[3];
+       NTSTATUS status;
+       struct tevent_req *result_parent;
 
-       cli_send_smb(cli);
-       if (!cli_receive_smb(cli)) {
-               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
-       }
+       SSVAL(vwv+0, 0, fnum);
+       SSVAL(vwv+1, 0, code>>16);
+       SSVAL(vwv+2, 0, (code&0xFFFF));
 
-       if (cli_is_error(cli)) {
-               return cli_nt_error(cli);
+       status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
+                        &result_parent, 0, NULL, NULL, NULL, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
-
        *blob = data_blob_null;
-
        return NT_STATUS_OK;
 }
 
@@ -4278,16 +4536,13 @@ static void cli_posix_open_internal_done(struct tevent_req *subreq)
        uint8_t *data;
        uint32_t num_data;
 
-       status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, &data, &num_data);
+       status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
+                               &data, 12, &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);
 }
@@ -4517,18 +4772,9 @@ struct unlink_state {
 
 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
 {
-       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);
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
@@ -4726,3 +4972,147 @@ NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
        }
        return status;
 }
+
+/****************************************************************************
+ filechangenotify
+****************************************************************************/
+
+struct cli_notify_state {
+       uint8_t setup[8];
+       uint32_t num_changes;
+       struct notify_change *changes;
+};
+
+static void cli_notify_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev,
+                                  struct cli_state *cli, uint16_t fnum,
+                                  uint32_t buffer_size,
+                                  uint32_t completion_filter, bool recursive)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_notify_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       SIVAL(state->setup, 0, completion_filter);
+       SSVAL(state->setup, 4, fnum);
+       SSVAL(state->setup, 6, recursive);
+
+       subreq = cli_trans_send(
+               state,                  /* mem ctx. */
+               ev,                     /* event ctx. */
+               cli,                    /* cli_state. */
+               SMBnttrans,             /* cmd. */
+               NULL,                   /* pipe name. */
+               -1,                     /* fid. */
+               NT_TRANSACT_NOTIFY_CHANGE, /* function. */
+               0,                      /* flags. */
+               (uint16_t *)state->setup, /* setup. */
+               4,                      /* num setup uint16_t words. */
+               0,                      /* max returned setup. */
+               NULL,                   /* param. */
+               0,                      /* num param. */
+               buffer_size,            /* max returned param. */
+               NULL,                   /* data. */
+               0,                      /* num data. */
+               0);                     /* max returned data. */
+
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_notify_done, req);
+       return req;
+}
+
+static void cli_notify_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_notify_state *state = tevent_req_data(
+               req, struct cli_notify_state);
+       NTSTATUS status;
+       uint8_t *params;
+       uint32_t i, ofs, num_params;
+
+       status = cli_trans_recv(subreq, talloc_tos(), NULL, 0, NULL,
+                               &params, 0, &num_params, NULL, 0, NULL);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       state->num_changes = 0;
+       ofs = 0;
+
+       while (num_params - ofs > 12) {
+               uint32_t len = IVAL(params, ofs);
+               state->num_changes += 1;
+
+               if ((len == 0) || (ofs+len >= num_params)) {
+                       break;
+               }
+               ofs += len;
+       }
+
+       state->changes = talloc_array(state, struct notify_change,
+                                     state->num_changes);
+       if (tevent_req_nomem(state->changes, req)) {
+               TALLOC_FREE(params);
+               return;
+       }
+
+       ofs = 0;
+
+       for (i=0; i<state->num_changes; i++) {
+               uint32_t next = IVAL(params, ofs);
+               uint32_t len = IVAL(params, ofs+8);
+               ssize_t ret;
+               char *name;
+
+               if ((next != 0) && (len+12 != next)) {
+                       TALLOC_FREE(params);
+                       tevent_req_nterror(
+                               req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+                       return;
+               }
+
+               state->changes[i].action = IVAL(params, ofs+4);
+               ret = clistr_pull_talloc(params, (char *)params, &name,
+                                        params+ofs+12, len,
+                                        STR_TERMINATE|STR_UNICODE);
+               if (ret == -1) {
+                       TALLOC_FREE(params);
+                       tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+                       return;
+               }
+               state->changes[i].name = name;
+               ofs += next;
+       }
+
+       TALLOC_FREE(params);
+       tevent_req_done(req);
+}
+
+NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                        uint32_t *pnum_changes,
+                        struct notify_change **pchanges)
+{
+       struct cli_notify_state *state = tevent_req_data(
+               req, struct cli_notify_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+
+       *pnum_changes = state->num_changes;
+       *pchanges = talloc_move(mem_ctx, &state->changes);
+       return NT_STATUS_OK;
+}