libsmb: Use tevent_req_simple_finish_ntstatus
[samba.git] / source3 / libsmb / clifile.c
index 2ee6eda956f8d41cf070227b8244bb0011aa16c4..421e26f60863e37e1c412e866504f20f09f397cc 100644 (file)
 #include "libcli/security/secdesc.h"
 #include "../libcli/smb/smbXcli_base.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 (ucs2 &&
-           ((align_odd && (buflen % 2 == 0)) ||
-            (!align_odd && (buflen % 2 == 1)))) {
-               /*
-                * We're pushing into an SMB buffer, align odd
-                */
-               buf = talloc_realloc(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)) {
-               return NULL;
-       }
-
-       buf = talloc_realloc(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);
-}
-
-uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
-                             const uint8_t *bytes, size_t num_bytes)
-{
-       size_t buflen;
-
-       if (buf == NULL) {
-               return NULL;
-       }
-       buflen = talloc_get_size(buf);
-
-       buf = talloc_realloc(NULL, buf, uint8_t,
-                                  buflen + 1 + num_bytes);
-       if (buf == NULL) {
-               return NULL;
-       }
-       buf[buflen] = prefix;
-       memcpy(&buf[buflen+1], bytes, num_bytes);
-       return buf;
-}
-
-/***********************************************************
- 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.
-***********************************************************/
-
-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);
-}
-
-uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
-                                const uint8_t *bytes, size_t num_bytes)
-{
-       size_t buflen;
-
-       if (buf == NULL) {
-               return NULL;
-       }
-       buflen = talloc_get_size(buf);
-
-       buf = talloc_realloc(NULL, buf, uint8_t,
-                            buflen + num_bytes);
-       if (buf == NULL) {
-               return NULL;
-       }
-       memcpy(&buf[buflen], bytes, num_bytes);
-       return buf;
-}
-
 struct cli_setpathinfo_state {
        uint16_t setup;
        uint8_t *param;
@@ -173,6 +46,7 @@ struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req, *subreq;
        struct cli_setpathinfo_state *state;
+       uint16_t additional_flags2 = 0;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct cli_setpathinfo_state);
@@ -196,10 +70,16 @@ struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
+                       !INFO_LEVEL_IS_UNIX(level)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_trans_send(
                state,                  /* mem ctx. */
                ev,                     /* event ctx. */
                cli,                    /* cli_state. */
+               additional_flags2,      /* additional_flags2 */
                SMBtrans2,              /* cmd. */
                NULL,                   /* pipe name. */
                -1,                     /* fid. */
@@ -271,7 +151,7 @@ NTSTATUS cli_setpathinfo(struct cli_state *cli,
 
 /****************************************************************************
  Hard/Symlink a file (UNIX extensions).
- Creates new name (sym)linked to oldname.
+ Creates new name (sym)linked to link_target.
 ****************************************************************************/
 
 struct cli_posix_link_internal_state {
@@ -284,7 +164,7 @@ static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
                                        uint16_t level,
-                                       const char *oldname,
+                                       const char *link_target,
                                        const char *newname)
 {
        struct tevent_req *req = NULL, *subreq = NULL;
@@ -302,7 +182,8 @@ static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        state->data = trans2_bytes_push_str(
-               state->data, smbXcli_conn_use_unicode(cli->conn), oldname, strlen(oldname)+1, NULL);
+               state->data, smbXcli_conn_use_unicode(cli->conn),
+               link_target, strlen(link_target)+1, NULL);
 
        subreq = cli_setpathinfo_send(
                state, ev, cli, level, newname,
@@ -327,11 +208,11 @@ static void cli_posix_link_internal_done(struct tevent_req *subreq)
 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
-                                       const char *oldname,
+                                       const char *link_target,
                                        const char *newname)
 {
        return cli_posix_link_internal_send(
-               mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, oldname, newname);
+               mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
 }
 
 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
@@ -340,7 +221,7 @@ NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
 }
 
 NTSTATUS cli_posix_symlink(struct cli_state *cli,
-                       const char *oldname,
+                       const char *link_target,
                        const char *newname)
 {
        TALLOC_CTX *frame = talloc_stackframe();
@@ -365,15 +246,14 @@ NTSTATUS cli_posix_symlink(struct cli_state *cli,
        req = cli_posix_symlink_send(frame,
                                ev,
                                cli,
-                               oldname,
+                               link_target,
                                newname);
        if (req == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -513,8 +393,7 @@ NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -577,8 +456,7 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -590,25 +468,25 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli,
 }
 
 /****************************************************************************
- Do a POSIX getfacl (UNIX extensions).
+ Do a POSIX getacl - pathname based ACL get (UNIX extensions).
 ****************************************************************************/
 
-struct getfacl_state {
+struct getacl_state {
        uint32_t num_data;
        uint8_t *data;
 };
 
-static void cli_posix_getfacl_done(struct tevent_req *subreq);
+static void cli_posix_getacl_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
+struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
                                        const char *fname)
 {
        struct tevent_req *req = NULL, *subreq = NULL;
-       struct getfacl_state *state = NULL;
+       struct getacl_state *state = NULL;
 
-       req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
+       req = tevent_req_create(mem_ctx, &state, struct getacl_state);
        if (req == NULL) {
                return NULL;
        }
@@ -617,16 +495,16 @@ struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
+       tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
        return req;
 }
 
-static void cli_posix_getfacl_done(struct tevent_req *subreq)
+static void cli_posix_getacl_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct getfacl_state *state = tevent_req_data(
-               req, struct getfacl_state);
+       struct getacl_state *state = tevent_req_data(
+               req, struct getacl_state);
        NTSTATUS status;
 
        status = cli_qpathinfo_recv(subreq, state, &state->data,
@@ -638,12 +516,12 @@ static void cli_posix_getfacl_done(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
-NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
+NTSTATUS cli_posix_getacl_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);
+       struct getacl_state *state = tevent_req_data(req, struct getacl_state);
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
@@ -654,7 +532,7 @@ NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
        return NT_STATUS_OK;
 }
 
-NTSTATUS cli_posix_getfacl(struct cli_state *cli,
+NTSTATUS cli_posix_getacl(struct cli_state *cli,
                        const char *fname,
                        TALLOC_CTX *mem_ctx,
                        size_t *prb_size,
@@ -679,7 +557,7 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli,
                goto fail;
        }
 
-       req = cli_posix_getfacl_send(frame,
+       req = cli_posix_getacl_send(frame,
                                ev,
                                cli,
                                fname);
@@ -688,12 +566,111 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
-       status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
+       status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
+
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+/****************************************************************************
+ Do a POSIX setacl - pathname based ACL set (UNIX extensions).
+****************************************************************************/
+
+struct setacl_state {
+       uint8_t *data;
+};
+
+static void cli_posix_setacl_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct cli_state *cli,
+                                       const char *fname,
+                                       const void *data,
+                                       size_t num_data)
+{
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct setacl_state *state = NULL;
+
+       req = tevent_req_create(mem_ctx, &state, struct setacl_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->data = talloc_memdup(state, data, num_data);
+       if (tevent_req_nomem(state->data, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = cli_setpathinfo_send(state,
+                               ev,
+                               cli,
+                               SMB_SET_POSIX_ACL,
+                               fname,
+                               state->data,
+                               num_data);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
+       return req;
+}
+
+static void cli_posix_setacl_done(struct tevent_req *subreq)
+{
+       NTSTATUS status = cli_setpathinfo_recv(subreq);
+       tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_posix_setacl(struct cli_state *cli,
+                       const char *fname,
+                       const void *acl_buf,
+                       size_t acl_buf_size)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev = NULL;
+       struct tevent_req *req = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       req = cli_posix_setacl_send(frame,
+                               ev,
+                               cli,
+                               fname,
+                               acl_buf,
+                               acl_buf_size);
+       if (req == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+
+       status = cli_posix_setacl_recv(req);
 
  fail:
        TALLOC_FREE(frame);
@@ -819,8 +796,7 @@ NTSTATUS cli_posix_stat(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -933,8 +909,7 @@ NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1003,8 +978,7 @@ NTSTATUS cli_posix_chown(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1019,28 +993,146 @@ NTSTATUS cli_posix_chown(struct cli_state *cli,
  Rename a file.
 ****************************************************************************/
 
-static void cli_rename_done(struct tevent_req *subreq);
+static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
+                                              struct tevent_context *ev,
+                                              struct cli_state *cli,
+                                              const char *fname_src,
+                                              const char *fname_dst,
+                                              bool replace);
+
+static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
+                                              struct tevent_context *ev,
+                                              struct cli_state *cli,
+                                              const char *fname_src,
+                                              const char *fname_dst,
+                                              bool replace);
+
+struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev,
+                                  struct cli_state *cli,
+                                  const char *fname_src,
+                                  const char *fname_dst,
+                                  bool replace)
+{
+       if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
+               return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
+                                           fname_dst, replace);
+       } else {
+               return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
+                                           fname_dst, replace);
+       }
+}
+
+struct cli_smb1_rename_state {
+       uint8_t *data;
+};
+
+static void cli_smb1_rename_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
+                                              struct tevent_context *ev,
+                                              struct cli_state *cli,
+                                              const char *fname_src,
+                                              const char *fname_dst,
+                                              bool replace)
+{
+       NTSTATUS status;
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_smb1_rename_state *state = NULL;
+       smb_ucs2_t *converted_str = NULL;
+       size_t converted_size_bytes = 0;
+
+       req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
+                             &converted_size_bytes)) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       /* W2K8 insists the dest name is not null
+          terminated. Remove the last 2 zero bytes
+          and reduce the name length. */
+
+       if (converted_size_bytes < 2) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+       converted_size_bytes -= 2;
+
+       state->data =
+           talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
+       if (state->data == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       if (replace) {
+               SCVAL(state->data, 0, 1);
+       }
+
+       SIVAL(state->data, 8, converted_size_bytes);
+       memcpy(state->data + 12, converted_str, converted_size_bytes);
+
+       TALLOC_FREE(converted_str);
+
+       subreq = cli_setpathinfo_send(
+           state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
+           talloc_get_size(state->data));
+       if (tevent_req_nomem(subreq, req)) {
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+       tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
+       return req;
+
+fail:
+       TALLOC_FREE(converted_str);
+       tevent_req_nterror(req, status);
+       return tevent_req_post(req, ev);
+}
 
-struct cli_rename_state {
+static void cli_smb1_rename_done(struct tevent_req *subreq)
+{
+       NTSTATUS status = cli_setpathinfo_recv(subreq);
+       tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+static void cli_cifs_rename_done(struct tevent_req *subreq);
+
+struct cli_cifs_rename_state {
        uint16_t vwv[1];
 };
 
-struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
-                               struct tevent_context *ev,
-                               struct cli_state *cli,
-                               const char *fname_src,
-                               const char *fname_dst)
+static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
+                                              struct tevent_context *ev,
+                                              struct cli_state *cli,
+                                              const char *fname_src,
+                                              const char *fname_dst,
+                                              bool replace)
 {
        struct tevent_req *req = NULL, *subreq = NULL;
-       struct cli_rename_state *state = NULL;
+       struct cli_cifs_rename_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
+       req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
        if (req == NULL) {
                return NULL;
        }
 
+       if (replace) {
+               /*
+                * CIFS doesn't support replace
+                */
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return tevent_req_post(req, ev);
+       }
+
        SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
 
        bytes = talloc_array(state, uint8_t, 1);
@@ -1054,6 +1146,10 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        bytes = talloc_realloc(state, bytes, uint8_t,
                        talloc_get_size(bytes)+1);
        if (tevent_req_nomem(bytes, req)) {
@@ -1068,15 +1164,16 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
-                             1, state->vwv, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       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);
+       tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
        return req;
 }
 
-static void cli_rename_done(struct tevent_req *subreq)
+static void cli_cifs_rename_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                                subreq, struct tevent_req);
@@ -1095,7 +1192,10 @@ NTSTATUS cli_rename_recv(struct tevent_req *req)
        return tevent_req_simple_recv_ntstatus(req);
 }
 
-NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+NTSTATUS cli_rename(struct cli_state *cli,
+                   const char *fname_src,
+                   const char *fname_dst,
+                   bool replace)
 {
        TALLOC_CTX *frame = NULL;
        struct tevent_context *ev;
@@ -1103,9 +1203,7 @@ NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fn
        NTSTATUS status = NT_STATUS_OK;
 
        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_rename(cli,
-                                       fname_src,
-                                       fname_dst);
+               return cli_smb2_rename(cli, fname_src, fname_dst, replace);
        }
 
        frame = talloc_stackframe();
@@ -1124,14 +1222,13 @@ NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fn
                goto fail;
        }
 
-       req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
+       req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
        if (req == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1162,6 +1259,7 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_ntrename_internal_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state,
@@ -1184,6 +1282,10 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        bytes = talloc_realloc(state, bytes, uint8_t,
                        talloc_get_size(bytes)+1);
        if (tevent_req_nomem(bytes, req)) {
@@ -1198,7 +1300,8 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
-                             4, state->vwv, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       4, state->vwv, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -1208,16 +1311,9 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
 
 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, NULL, NULL, 0, NULL, NULL, NULL, NULL);
-       TALLOC_FREE(subreq);
-       if (tevent_req_nterror(req, status)) {
-               return;
-       }
-       tevent_req_done(req);
+       NTSTATUS status = cli_smb_recv(
+               subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
@@ -1271,8 +1367,7 @@ NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1333,8 +1428,7 @@ NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const cha
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1364,6 +1458,7 @@ struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_unlink_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
@@ -1385,7 +1480,12 @@ struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
+                               additional_flags2,
                                1, state->vwv, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -1421,7 +1521,7 @@ NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_a
        NTSTATUS status = NT_STATUS_OK;
 
        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_unlink(cli, fname);
+               return cli_smb2_unlink(cli, fname, NULL);
        }
 
        frame = talloc_stackframe();
@@ -1446,8 +1546,7 @@ NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_a
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1476,6 +1575,7 @@ struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_mkdir_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
@@ -1495,8 +1595,13 @@ struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
-                             0, NULL, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       0, NULL, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -1556,8 +1661,7 @@ NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1586,6 +1690,7 @@ struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_rmdir_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
@@ -1605,8 +1710,13 @@ struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
-                             0, NULL, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       0, NULL, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -1641,7 +1751,7 @@ NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
        NTSTATUS status = NT_STATUS_OK;
 
        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_rmdir(cli, dname);
+               return cli_smb2_rmdir(cli, dname, NULL);
        }
 
        frame = talloc_stackframe();
@@ -1666,8 +1776,7 @@ NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1688,12 +1797,8 @@ struct doc_state {
        uint8_t data[1];
 };
 
-static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
-{
-       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
-                                        NULL, 0, NULL, NULL, 0, NULL);
-       tevent_req_simple_finish_ntstatus(subreq, status);
-}
+static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
+static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
 
 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
@@ -1709,6 +1814,18 @@ struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               subreq = cli_smb2_delete_on_close_send(state, ev, cli,
+                                                      fnum, flag);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq,
+                                       cli_nt_delete_on_close_smb2_done,
+                                       req);
+               return req;
+       }
+
        /* Setup setup word. */
        SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
 
@@ -1722,6 +1839,7 @@ struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
        subreq = cli_trans_send(state,                  /* mem ctx. */
                                ev,                     /* event ctx. */
                                cli,                    /* cli_state. */
+                               0,                      /* additional_flags2 */
                                SMBtrans2,              /* cmd. */
                                NULL,                   /* pipe name. */
                                -1,                     /* fid. */
@@ -1740,10 +1858,25 @@ struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
+       tevent_req_set_callback(subreq,
+                               cli_nt_delete_on_close_smb1_done,
+                               req);
        return req;
 }
 
+static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
+{
+       NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
+                                        NULL, 0, NULL, NULL, 0, NULL);
+       tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
+{
+       NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
+       tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
 {
        return tevent_req_simple_recv_ntstatus(req);
@@ -1780,8 +1913,7 @@ NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -1812,6 +1944,7 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
                                             uint32_t ShareAccess,
                                             uint32_t CreateDisposition,
                                             uint32_t CreateOptions,
+                                            uint32_t ImpersonationLevel,
                                             uint8_t SecurityFlags)
 {
        struct tevent_req *req, *subreq;
@@ -1819,6 +1952,7 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
        uint16_t *vwv;
        uint8_t *bytes;
        size_t converted_len;
+       uint16_t additional_flags2 = 0;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
        if (req == NULL) {
@@ -1845,7 +1979,7 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
        SIVAL(vwv+17, 1, CreateDisposition);
        SIVAL(vwv+19, 1, CreateOptions |
                (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
-       SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
+       SIVAL(vwv+21, 1, ImpersonationLevel);
        SCVAL(vwv+23, 1, SecurityFlags);
 
        bytes = talloc_array(state, uint8_t, 0);
@@ -1853,6 +1987,10 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
                                   fname, strlen(fname)+1,
                                   &converted_len);
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        /* sigh. this copes with broken netapp filer behaviour */
        bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
 
@@ -1862,8 +2000,9 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
 
        SSVAL(vwv+2, 1, converted_len);
 
-       subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
-                             talloc_get_size(bytes), bytes);
+       subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
+                       additional_flags2, 24, vwv,
+                       talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -1933,13 +2072,14 @@ static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
 }
 
 struct cli_ntcreate_state {
-       NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
-                        struct smb_create_returns *cr);
        struct smb_create_returns cr;
        uint16_t fnum;
+       struct tevent_req *subreq;
 };
 
-static void cli_ntcreate_done(struct tevent_req *subreq);
+static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
+static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
+static bool cli_ntcreate_cancel(struct tevent_req *req);
 
 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
                                     struct tevent_context *ev,
@@ -1951,6 +2091,7 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
                                     uint32_t share_access,
                                     uint32_t create_disposition,
                                     uint32_t create_options,
+                                    uint32_t impersonation_level,
                                     uint8_t security_flags)
 {
        struct tevent_req *req, *subreq;
@@ -1962,31 +2103,61 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
        }
 
        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               state->recv = cli_smb2_create_fnum_recv;
-
                if (cli->use_oplocks) {
                        create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
                }
 
                subreq = cli_smb2_create_fnum_send(
-                       state, ev, cli, fname, create_flags, desired_access,
-                       file_attributes, share_access, create_disposition,
-                       create_options);
+                       state,
+                       ev,
+                       cli,
+                       fname,
+                       create_flags,
+                       impersonation_level,
+                       desired_access,
+                       file_attributes,
+                       share_access,
+                       create_disposition,
+                       create_options,
+                       NULL);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
        } else {
-               state->recv = cli_ntcreate1_recv;
                subreq = cli_ntcreate1_send(
                        state, ev, cli, fname, create_flags, desired_access,
                        file_attributes, share_access, create_disposition,
-                       create_options, security_flags);
-       }
-       if (tevent_req_nomem(subreq, req)) {
-               return tevent_req_post(req, ev);
+                       create_options, impersonation_level, security_flags);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
        }
-       tevent_req_set_callback(subreq, cli_ntcreate_done, req);
+
+       state->subreq = subreq;
+       tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
+
        return req;
 }
 
-static void cli_ntcreate_done(struct tevent_req *subreq)
+static void cli_ntcreate_done_nt1(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);
+       NTSTATUS status;
+
+       status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
@@ -1994,7 +2165,12 @@ static void cli_ntcreate_done(struct tevent_req *subreq)
                req, struct cli_ntcreate_state);
        NTSTATUS status;
 
-       status = state->recv(subreq, &state->fnum, &state->cr);
+       status = cli_smb2_create_fnum_recv(
+               subreq,
+               &state->fnum,
+               &state->cr,
+               NULL,
+               NULL);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
@@ -2002,6 +2178,13 @@ static void cli_ntcreate_done(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
+static bool cli_ntcreate_cancel(struct tevent_req *req)
+{
+       struct cli_ntcreate_state *state = tevent_req_data(
+               req, struct cli_ntcreate_state);
+       return tevent_req_cancel(state->subreq);
+}
+
 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
                           struct smb_create_returns *cr)
 {
@@ -2036,6 +2219,7 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
        TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev;
        struct tevent_req *req;
+       uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
@@ -2054,7 +2238,7 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
        req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
                                DesiredAccess, FileAttributes, ShareAccess,
                                CreateDisposition, CreateOptions,
-                               SecurityFlags);
+                               ImpersonationLevel, SecurityFlags);
        if (req == NULL) {
                goto fail;
        }
@@ -2098,6 +2282,7 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
        size_t secdesc_len;
        NTSTATUS status;
        size_t converted_len;
+       uint16_t additional_flags2 = 0;
 
        req = tevent_req_create(mem_ctx,
                                &state, struct cli_nttrans_create_state);
@@ -2138,6 +2323,10 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        SIVAL(param, 0, CreatFlags);
        SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
        SIVAL(param, 8, DesiredAccess);
@@ -2154,7 +2343,9 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
        SIVAL(param, 48, 0x02); /* ImpersonationLevel */
        SCVAL(param, 52, SecurityFlags);
 
-       subreq = cli_trans_send(state, ev, cli, SMBnttrans,
+       subreq = cli_trans_send(state, ev, cli,
+                               additional_flags2, /* additional_flags2 */
+                               SMBnttrans,
                                NULL, -1, /* name, fid */
                                NT_TRANSACT_CREATE, 0,
                                NULL, 0, 0, /* setup */
@@ -2290,6 +2481,7 @@ struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
        unsigned openfn;
        unsigned accessmode;
        uint8_t additional_flags;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
@@ -2357,11 +2549,15 @@ struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        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);
+                       additional_flags2, 15, state->vwv, 1, &state->bytes);
        if (subreq == NULL) {
                TALLOC_FREE(req);
                return NULL;
@@ -2600,22 +2796,22 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
  Close a file.
 ****************************************************************************/
 
-struct cli_close_state {
+struct cli_smb1_close_state {
        uint16_t vwv[3];
 };
 
-static void cli_close_done(struct tevent_req *subreq);
+static void cli_smb1_close_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
+struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
                                struct tevent_context *ev,
                                struct cli_state *cli,
                                uint16_t fnum,
                                struct tevent_req **psubreq)
 {
        struct tevent_req *req, *subreq;
-       struct cli_close_state *state;
+       struct cli_smb1_close_state *state;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
+       req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
        if (req == NULL) {
                return NULL;
        }
@@ -2623,34 +2819,72 @@ struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
        SSVAL(state->vwv+0, 0, fnum);
        SIVALS(state->vwv+1, 0, -1);
 
-       subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
-                                   0, NULL);
+       subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
+                               3, state->vwv, 0, NULL);
        if (subreq == NULL) {
                TALLOC_FREE(req);
                return NULL;
        }
-       tevent_req_set_callback(subreq, cli_close_done, req);
+       tevent_req_set_callback(subreq, cli_smb1_close_done, req);
        *psubreq = subreq;
        return req;
 }
 
+static void cli_smb1_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, NULL, NULL, 0, NULL, NULL, NULL, NULL);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
+
+struct cli_close_state {
+       int dummy;
+};
+
+static void cli_close_done(struct tevent_req *subreq);
+
 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
                                struct tevent_context *ev,
                                struct cli_state *cli,
                                uint16_t fnum)
 {
        struct tevent_req *req, *subreq;
+       struct cli_close_state *state;
        NTSTATUS status;
 
-       req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
+       req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
        if (req == NULL) {
                return NULL;
        }
 
-       status = smb1cli_req_chain_submit(&subreq, 1);
-       if (tevent_req_nterror(req, status)) {
-               return tevent_req_post(req, ev);
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               subreq = cli_smb2_close_fnum_send(state,
+                                               ev,
+                                               cli,
+                                               fnum);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+       } else {
+               struct tevent_req *ch_req = NULL;
+               subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               status = smb1cli_req_chain_submit(&ch_req, 1);
+               if (tevent_req_nterror(req, status)) {
+                       return tevent_req_post(req, ev);
+               }
        }
+
+       tevent_req_set_callback(subreq, cli_close_done, req);
        return req;
 }
 
@@ -2658,11 +2892,12 @@ static void cli_close_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       NTSTATUS status;
+       NTSTATUS status = NT_STATUS_OK;
+       bool err = tevent_req_is_nterror(subreq, &status);
 
-       status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
        TALLOC_FREE(subreq);
-       if (tevent_req_nterror(req, status)) {
+       if (err) {
+               tevent_req_nterror(req, status);
                return;
        }
        tevent_req_done(req);
@@ -2680,10 +2915,6 @@ NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_close_fnum(cli, fnum);
-       }
-
        frame = talloc_stackframe();
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
@@ -2706,8 +2937,7 @@ NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -2762,6 +2992,7 @@ struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
        subreq = cli_trans_send(state,                  /* mem ctx. */
                                ev,                     /* event ctx. */
                                cli,                    /* cli_state. */
+                               0,                      /* additional_flags2 */
                                SMBtrans2,              /* cmd. */
                                NULL,                   /* pipe name. */
                                -1,                     /* fid. */
@@ -2791,11 +3022,17 @@ NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
 
 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_ftruncate(cli, fnum, size);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -2820,8 +3057,7 @@ NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -2935,7 +3171,7 @@ struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
        SIVAL(state->data, 2, offset);
        SIVAL(state->data, 6, len);
 
-       subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
+       subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
                                8, state->vwv, 10, state->data);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -2994,8 +3230,7 @@ NTSTATUS cli_unlock(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3100,7 +3335,7 @@ struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
        SOFF_T_R(state->data, 4, offset);
        SOFF_T_R(state->data, 12, len);
 
-       subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
+       subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
                                8, state->vwv, 20, state->data);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -3163,8 +3398,7 @@ NTSTATUS cli_unlock64(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3249,6 +3483,7 @@ static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
        subreq = cli_trans_send(state,                  /* mem ctx. */
                                ev,                     /* event ctx. */
                                cli,                    /* cli_state. */
+                               0,                      /* additional_flags2 */
                                SMBtrans2,              /* cmd. */
                                NULL,                   /* pipe name. */
                                -1,                     /* fid. */
@@ -3334,8 +3569,7 @@ NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3398,8 +3632,7 @@ NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3443,7 +3676,7 @@ struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
        state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
        SSVAL(state->vwv+0,0,fnum);
 
-       subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
+       subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
                              1, state->vwv, 0, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -3555,8 +3788,7 @@ NTSTATUS cli_getattrE(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3593,6 +3825,7 @@ struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_getatr_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
@@ -3614,8 +3847,13 @@ struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
-                             0, NULL, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       0, NULL, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -3712,8 +3950,7 @@ NTSTATUS cli_getatr(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3762,7 +3999,7 @@ struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
        push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
                       smb1cli_conn_server_time_zone(cli->conn));
 
-       subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
+       subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
                              7, state->vwv, 0, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -3837,8 +4074,7 @@ NTSTATUS cli_setattrE(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3869,6 +4105,7 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_setatr_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
@@ -3902,8 +4139,13 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
-                             8, state->vwv, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       8, state->vwv, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -3969,8 +4211,7 @@ NTSTATUS cli_setatr(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -3982,7 +4223,7 @@ NTSTATUS cli_setatr(struct cli_state *cli,
 }
 
 /****************************************************************************
- Check for existance of a dir.
+ Check for existence of a dir.
 ****************************************************************************/
 
 static void cli_chkpath_done(struct tevent_req *subreq);
@@ -3999,6 +4240,7 @@ struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct cli_chkpath_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
@@ -4018,8 +4260,13 @@ struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
-                             0, NULL, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       0, NULL, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -4048,12 +4295,18 @@ NTSTATUS cli_chkpath_recv(struct tevent_req *req)
 
 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        char *path2 = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_chkpath(cli, path);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -4088,8 +4341,7 @@ NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -4125,7 +4377,7 @@ struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
+       subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
                              0, NULL, 0, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -4200,8 +4452,7 @@ NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -4212,7 +4463,8 @@ NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
        return status;
 }
 
-NTSTATUS cli_disk_size(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
+NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
+                      uint64_t *total, uint64_t *avail)
 {
        uint64_t sectors_per_block;
        uint64_t bytes_per_sector;
@@ -4220,7 +4472,7 @@ NTSTATUS cli_disk_size(struct cli_state *cli, uint64_t *bsize, uint64_t *total,
        NTSTATUS status;
 
        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_dskattr(cli, bsize, total, avail);
+               return cli_smb2_dskattr(cli, path, bsize, total, avail);
        }
 
        /*
@@ -4303,6 +4555,7 @@ struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req = NULL, *subreq = NULL;
        struct ctemp_state *state = NULL;
        uint8_t additional_flags = 0;
+       uint16_t additional_flags2 = 0;
        uint8_t *bytes = NULL;
 
        req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
@@ -4324,8 +4577,13 @@ struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
-                             3, state->vwv, talloc_get_size(bytes), bytes);
+                       additional_flags2,
+                       3, state->vwv, talloc_get_size(bytes), bytes);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -4424,8 +4682,7 @@ NTSTATUS cli_ctemp(struct cli_state *cli,
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -4503,10 +4760,19 @@ static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
                memcpy(p+4+ea_namelen+1, ea_val, ea_len);
        }
 
+       /*
+        * FIXME - if we want to do previous version path
+        * processing on an EA set call we need to turn this
+        * into calls to cli_trans_send()/cli_trans_recv()
+        * with a temporary event context, as cli_trans_send()
+        * have access to the additional_flags2 needed to
+        * send @GMT- paths. JRA.
+        */
+
        status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
                           setup, 1, 0,
                           param, param_len, 2,
-                          data,  data_len, CLI_BUFFER_SIZE,
+                          data,  data_len, 0,
                           NULL,
                           NULL, 0, NULL, /* rsetup */
                           NULL, 0, NULL, /* rparam */
@@ -4855,45 +5121,27 @@ static uint32_t open_flags_to_wire(int flags)
  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
 ****************************************************************************/
 
-struct posix_open_state {
+struct cli_posix_open_internal_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)
-{
-       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, 0, NULL,
-                               NULL, 0, NULL, &data, 12, &num_data);
-       TALLOC_FREE(subreq);
-       if (tevent_req_nterror(req, status)) {
-               return;
-       }
-       state->fnum = SVAL(data,2);
-       tevent_req_done(req);
-}
+static void cli_posix_open_internal_done(struct tevent_req *subreq);
 
 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
                                        const char *fname,
-                                       int flags,
-                                       mode_t mode,
-                                       bool is_dir)
+                                       uint32_t wire_flags,
+                                       mode_t mode)
 {
        struct tevent_req *req = NULL, *subreq = NULL;
-       struct posix_open_state *state = NULL;
-       uint32_t wire_flags = open_flags_to_wire(flags);
+       struct cli_posix_open_internal_state *state = NULL;
 
-       req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
+       req = tevent_req_create(
+               mem_ctx, &state, struct cli_posix_open_internal_state);
        if (req == NULL) {
                return NULL;
        }
@@ -4902,25 +5150,23 @@ static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
        SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
 
        /* Setup param array. */
-       state->param = talloc_array(state, uint8_t, 6);
+       state->param = talloc_zero_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);
 
-       state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
-                                  strlen(fname)+1, NULL);
+       state->param = trans2_bytes_push_str(
+               state->param,
+               smbXcli_conn_use_unicode(cli->conn),
+               fname,
+               strlen(fname)+1,
+               NULL);
 
        if (tevent_req_nomem(state->param, req)) {
                return tevent_req_post(req, ev);
        }
 
-       /* Setup data words. */
-       if (is_dir) {
-               wire_flags |= SMB_O_DIRECTORY;
-       }
-
        SIVAL(state->data,0,0); /* No oplock. */
        SIVAL(state->data,4,wire_flags);
        SIVAL(state->data,8,unix_perms_to_wire(mode));
@@ -4930,6 +5176,7 @@ static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
        subreq = cli_trans_send(state,                  /* mem ctx. */
                                ev,                     /* event ctx. */
                                cli,                    /* cli_state. */
+                               0,                      /* additional_flags2 */
                                SMBtrans2,              /* cmd. */
                                NULL,                   /* pipe name. */
                                -1,                     /* fid. */
@@ -4952,6 +5199,57 @@ static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
        return req;
 }
 
+static void cli_posix_open_internal_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_posix_open_internal_state *state = tevent_req_data(
+               req, struct cli_posix_open_internal_state);
+       NTSTATUS status;
+       uint8_t *data;
+       uint32_t num_data;
+
+       status = cli_trans_recv(
+               subreq,
+               state,
+               NULL,
+               NULL,
+               0,
+               NULL,
+               NULL,
+               0,
+               NULL,
+               &data,
+               12,
+               &num_data);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       state->fnum = SVAL(data,2);
+       tevent_req_done(req);
+}
+
+static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
+                                            uint16_t *pfnum)
+{
+       struct cli_posix_open_internal_state *state = tevent_req_data(
+               req, struct cli_posix_open_internal_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *pfnum = state->fnum;
+       return NT_STATUS_OK;
+}
+
+struct cli_posix_open_state {
+       uint16_t fnum;
+};
+
+static void cli_posix_open_done(struct tevent_req *subreq);
+
 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
@@ -4959,13 +5257,43 @@ struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
                                        int flags,
                                        mode_t mode)
 {
-       return cli_posix_open_internal_send(mem_ctx, ev,
-                               cli, fname, flags, mode, false);
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_posix_open_state *state = NULL;
+       uint32_t wire_flags;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct cli_posix_open_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       wire_flags = open_flags_to_wire(flags);
+
+       subreq = cli_posix_open_internal_send(
+               mem_ctx, ev, cli, fname, wire_flags, mode);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_posix_open_done, req);
+       return req;
+}
+
+static void cli_posix_open_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_posix_open_state *state = tevent_req_data(
+               req, struct cli_posix_open_state);
+       NTSTATUS status;
+
+       status = cli_posix_open_internal_recv(subreq, &state->fnum);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 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);
+       struct cli_posix_open_state *state = tevent_req_data(
+               req, struct cli_posix_open_state);
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
@@ -4986,7 +5314,7 @@ NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
        TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
-       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
@@ -4995,44 +5323,73 @@ NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
                status = NT_STATUS_INVALID_PARAMETER;
                goto fail;
        }
-
        ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
-
-       req = cli_posix_open_send(frame,
-                               ev,
-                               cli,
-                               fname,
-                               flags,
-                               mode);
+       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);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
-
        status = cli_posix_open_recv(req, pfnum);
-
  fail:
        TALLOC_FREE(frame);
        return status;
 }
 
+struct cli_posix_mkdir_state {
+       struct tevent_context *ev;
+       struct cli_state *cli;
+};
+
+static void cli_posix_mkdir_done(struct tevent_req *subreq);
+
 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
                                        const char *fname,
                                        mode_t mode)
 {
-       return cli_posix_open_internal_send(mem_ctx, ev,
-                               cli, fname, O_CREAT, mode, true);
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_posix_mkdir_state *state = NULL;
+       uint32_t wire_flags;
+
+       req = tevent_req_create(
+               mem_ctx, &state, struct cli_posix_mkdir_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+       state->cli = cli;
+
+       wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
+
+       subreq = cli_posix_open_internal_send(
+               mem_ctx, ev, cli, fname, wire_flags, mode);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
+       return req;
+}
+
+static void cli_posix_mkdir_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       NTSTATUS status;
+       uint16_t fnum;
+
+       status = cli_posix_open_internal_recv(subreq, &fnum);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
 }
 
 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
@@ -5045,7 +5402,7 @@ NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
        TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
-       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
@@ -5057,27 +5414,17 @@ NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
 
        ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
-
-       req = cli_posix_mkdir_send(frame,
-                               ev,
-                               cli,
-                               fname,
-                               mode);
+       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);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
-
        status = cli_posix_mkdir_recv(req);
-
  fail:
        TALLOC_FREE(frame);
        return status;
@@ -5128,13 +5475,43 @@ static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
        tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
+static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+struct cli_posix_unlink_state {
+       uint8_t dummy;
+};
+
+static void cli_posix_unlink_done(struct tevent_req *subreq);
+
 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
                                        const char *fname)
 {
-       return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
-                                             SMB_POSIX_UNLINK_FILE_TARGET);
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_posix_unlink_state *state;
+
+       req = tevent_req_create(
+               mem_ctx, &state, struct cli_posix_unlink_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       subreq = cli_posix_unlink_internal_send(
+               mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
+       return req;
+}
+
+static void cli_posix_unlink_done(struct tevent_req *subreq)
+{
+       NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
@@ -5176,8 +5553,7 @@ NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -5192,14 +5568,37 @@ NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
  rmdir - POSIX semantics.
 ****************************************************************************/
 
+struct cli_posix_rmdir_state {
+       uint8_t dummy;
+};
+
+static void cli_posix_rmdir_done(struct tevent_req *subreq);
+
 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct cli_state *cli,
                                        const char *fname)
 {
-       return cli_posix_unlink_internal_send(
-               mem_ctx, ev, cli, fname,
-               SMB_POSIX_UNLINK_DIRECTORY_TARGET);
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct cli_posix_rmdir_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       subreq = cli_posix_unlink_internal_send(
+               mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
+       return req;
+}
+
+static void cli_posix_rmdir_done(struct tevent_req *subreq)
+{
+       NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
@@ -5237,8 +5636,7 @@ NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
@@ -5254,12 +5652,15 @@ NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
 ****************************************************************************/
 
 struct cli_notify_state {
+       struct tevent_req *subreq;
        uint8_t setup[8];
        uint32_t num_changes;
        struct notify_change *changes;
 };
 
 static void cli_notify_done(struct tevent_req *subreq);
+static void cli_notify_done_smb2(struct tevent_req *subreq);
+static bool cli_notify_cancel(struct tevent_req *req);
 
 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
                                   struct tevent_context *ev,
@@ -5267,7 +5668,7 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
                                   uint32_t buffer_size,
                                   uint32_t completion_filter, bool recursive)
 {
-       struct tevent_req *req, *subreq;
+       struct tevent_req *req;
        struct cli_notify_state *state;
        unsigned old_timeout;
 
@@ -5276,6 +5677,31 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               /*
+                * Notifies should not time out
+                */
+               old_timeout = cli_set_timeout(cli, 0);
+
+               state->subreq = cli_smb2_notify_send(
+                       state,
+                       ev,
+                       cli,
+                       fnum,
+                       buffer_size,
+                       completion_filter,
+                       recursive);
+
+               cli_set_timeout(cli, old_timeout);
+
+               if (tevent_req_nomem(state->subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(
+                       state->subreq, cli_notify_done_smb2, req);
+               goto done;
+       }
+
        SIVAL(state->setup, 0, completion_filter);
        SSVAL(state->setup, 4, fnum);
        SSVAL(state->setup, 6, recursive);
@@ -5285,10 +5711,11 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
         */
        old_timeout = cli_set_timeout(cli, 0);
 
-       subreq = cli_trans_send(
+       state->subreq = cli_trans_send(
                state,                  /* mem ctx. */
                ev,                     /* event ctx. */
                cli,                    /* cli_state. */
+               0,                      /* additional_flags2 */
                SMBnttrans,             /* cmd. */
                NULL,                   /* pipe name. */
                -1,                     /* fid. */
@@ -5306,13 +5733,25 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
 
        cli_set_timeout(cli, old_timeout);
 
-       if (tevent_req_nomem(subreq, req)) {
+       if (tevent_req_nomem(state->subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_notify_done, req);
+       tevent_req_set_callback(state->subreq, cli_notify_done, req);
+done:
+       tevent_req_set_cancel_fn(req, cli_notify_cancel);
        return req;
 }
 
+static bool cli_notify_cancel(struct tevent_req *req)
+{
+       struct cli_notify_state *state = tevent_req_data(
+               req, struct cli_notify_state);
+       bool ok;
+
+       ok = tevent_req_cancel(state->subreq);
+       return ok;
+}
+
 static void cli_notify_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
@@ -5327,6 +5766,7 @@ static void cli_notify_done(struct tevent_req *subreq)
        status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
                                &params, 0, &num_params, NULL, 0, NULL);
        TALLOC_FREE(subreq);
+       state->subreq = NULL;
        if (tevent_req_nterror(req, status)) {
                DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
                return;
@@ -5384,6 +5824,26 @@ static void cli_notify_done(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
+static void cli_notify_done_smb2(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;
+
+       status = cli_smb2_notify_recv(
+               subreq,
+               state,
+               &state->changes,
+               &state->num_changes);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
+
 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                         uint32_t *pnum_changes,
                         struct notify_change **pchanges)
@@ -5406,11 +5866,13 @@ NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
                    TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
                    struct notify_change **pchanges)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame;
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -5455,6 +5917,7 @@ struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req, *subreq;
        struct cli_qpathinfo_state *state;
+       uint16_t additional_flags2 = 0;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
        if (req == NULL) {
@@ -5474,10 +5937,16 @@ struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
+                       !INFO_LEVEL_IS_UNIX(level)) {
+               additional_flags2 = FLAGS2_REPARSE_PATH;
+       }
+
        subreq = cli_trans_send(
                state,                  /* mem ctx. */
                ev,                     /* event ctx. */
                cli,                    /* cli_state. */
+               additional_flags2,      /* additional_flags2 */
                SMBtrans2,              /* cmd. */
                NULL,                   /* pipe name. */
                -1,                     /* fid. */
@@ -5608,6 +6077,7 @@ struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
                state,                  /* mem ctx. */
                ev,                     /* event ctx. */
                cli,                    /* cli_state. */
+               0,                      /* additional_flags2 */
                SMBtrans2,              /* cmd. */
                NULL,                   /* pipe name. */
                -1,                     /* fid. */
@@ -5731,7 +6201,7 @@ struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
        }
        SSVAL(state->vwv + 0, 0, fnum);
 
-       subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
+       subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
                              0, NULL);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -5823,8 +6293,9 @@ struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
        SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
 
        subreq = cli_trans_send(
-               state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
-               state->setup, ARRAY_SIZE(state->setup), 0,
+               state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
+               state->setup, ARRAY_SIZE(state->setup),
+               ARRAY_SIZE(state->setup),
                NULL, 0, 0,
                NULL, 0, ret_size);
        if (tevent_req_nomem(subreq, req)) {
@@ -5858,36 +6329,61 @@ NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 {
        struct cli_shadow_copy_data_state *state = tevent_req_data(
                req, struct cli_shadow_copy_data_state);
-       char **names;
-       int i, num_names;
+       char **names = NULL;
+       uint32_t i, num_names;
        uint32_t dlength;
+       uint8_t *endp = NULL;
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
+
+       if (state->num_data < 16) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
        num_names = IVAL(state->data, 4);
        dlength = IVAL(state->data, 8);
 
+       if (num_names > 0x7FFFFFFF) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
        if (!state->get_names) {
-               *pnum_names = num_names;
+               *pnum_names = (int)num_names;
                return NT_STATUS_OK;
        }
 
-       if (dlength+12 > state->num_data) {
+       if (dlength + 12 < 12) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+       if (dlength + 12 > state->num_data) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+       if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
+                       state->num_data) {
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
+
        names = talloc_array(mem_ctx, char *, num_names);
        if (names == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
+       endp = state->data + state->num_data;
+
        for (i=0; i<num_names; i++) {
                bool ret;
                uint8_t *src;
                size_t converted_size;
 
                src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
+
+               if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
+                       return NT_STATUS_INVALID_NETWORK_RESPONSE;
+               }
+
                ret = convert_string_talloc(
                        names, CH_UTF16LE, CH_UNIX,
                        src, 2 * sizeof(SHADOW_COPY_LABEL),
@@ -5897,7 +6393,7 @@ NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                        return NT_STATUS_INVALID_NETWORK_RESPONSE;
                }
        }
-       *pnum_names = num_names;
+       *pnum_names = (int)num_names;
        *pnames = names;
        return NT_STATUS_OK;
 }
@@ -5906,11 +6402,22 @@ NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
                              uint16_t fnum, bool get_names,
                              char ***pnames, int *pnum_names)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
+        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_shadow_copy_data(mem_ctx,
+                                       cli,
+                                       fnum,
+                                       get_names,
+                                       pnames,
+                                       pnum_names);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight