s3:libsmb: pass impersonation_level to cli_smb2_create_fnum_send()
[garming/samba-autobuild/.git] / source3 / libsmb / clifile.c
index f2e4ac22310dccc57f344590210803629d9a431b..dc3751aa821351e0d9d9df8a6af3aa9da9e6ce41 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. */
 
-struct cli_rename_state {
+       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);
+}
+
+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);
        }
@@ -1271,8 +1374,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 +1435,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 +1465,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 +1487,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);
@@ -1446,8 +1553,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 +1582,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 +1602,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);
        }
@@ -1525,11 +1637,17 @@ NTSTATUS cli_mkdir_recv(struct tevent_req *req)
 
 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_mkdir(cli, dname);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -1550,8 +1668,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;
        }
 
@@ -1580,6 +1697,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);
@@ -1599,8 +1717,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);
        }
@@ -1629,11 +1752,17 @@ NTSTATUS cli_rmdir_recv(struct tevent_req *req)
 
 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_rmdir(cli, dname);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -1654,8 +1783,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;
        }
 
@@ -1676,12 +1804,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,
@@ -1697,6 +1821,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);
 
@@ -1710,6 +1846,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. */
@@ -1728,10 +1865,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);
@@ -1768,8 +1920,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;
        }
 
@@ -1780,32 +1931,36 @@ NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
        return status;
 }
 
-struct cli_ntcreate_state {
+struct cli_ntcreate1_state {
        uint16_t vwv[24];
        uint16_t fnum;
+       struct smb_create_returns cr;
+       struct tevent_req *subreq;
 };
 
-static void cli_ntcreate_done(struct tevent_req *subreq);
+static void cli_ntcreate1_done(struct tevent_req *subreq);
+static bool cli_ntcreate1_cancel(struct tevent_req *req);
 
-struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
-                                    struct tevent_context *ev,
-                                    struct cli_state *cli,
-                                    const char *fname,
-                                    uint32_t CreatFlags,
-                                    uint32_t DesiredAccess,
-                                    uint32_t FileAttributes,
-                                    uint32_t ShareAccess,
-                                    uint32_t CreateDisposition,
-                                    uint32_t CreateOptions,
-                                    uint8_t SecurityFlags)
+static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct cli_state *cli,
+                                            const char *fname,
+                                            uint32_t CreatFlags,
+                                            uint32_t DesiredAccess,
+                                            uint32_t FileAttributes,
+                                            uint32_t ShareAccess,
+                                            uint32_t CreateDisposition,
+                                            uint32_t CreateOptions,
+                                            uint8_t SecurityFlags)
 {
        struct tevent_req *req, *subreq;
-       struct cli_ntcreate_state *state;
+       struct cli_ntcreate1_state *state;
        uint16_t *vwv;
        uint8_t *bytes;
        size_t converted_len;
+       uint16_t additional_flags2 = 0;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+       req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
        if (req == NULL) {
                return NULL;
        }
@@ -1838,6 +1993,10 @@ struct tevent_req *cli_ntcreate_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);
 
@@ -1847,38 +2006,164 @@ struct tevent_req *cli_ntcreate_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);
        }
-       tevent_req_set_callback(subreq, cli_ntcreate_done, req);
+       tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
+
+       state->subreq = subreq;
+       tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
+
        return req;
 }
 
-static void cli_ntcreate_done(struct tevent_req *subreq)
+static void cli_ntcreate1_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct cli_ntcreate_state *state = tevent_req_data(
-               req, struct cli_ntcreate_state);
+       struct cli_ntcreate1_state *state = tevent_req_data(
+               req, struct cli_ntcreate1_state);
        uint8_t wct;
        uint16_t *vwv;
        uint32_t num_bytes;
        uint8_t *bytes;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv,
+       status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
                              &num_bytes, &bytes);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       state->cr.oplock_level = CVAL(vwv+2, 0);
        state->fnum = SVAL(vwv+2, 1);
+       state->cr.create_action = IVAL(vwv+3, 1);
+       state->cr.creation_time = BVAL(vwv+5, 1);
+       state->cr.last_access_time = BVAL(vwv+9, 1);
+       state->cr.last_write_time = BVAL(vwv+13, 1);
+       state->cr.change_time   = BVAL(vwv+17, 1);
+       state->cr.file_attributes = IVAL(vwv+21, 1);
+       state->cr.allocation_size = BVAL(vwv+23, 1);
+       state->cr.end_of_file   = BVAL(vwv+27, 1);
+
+       tevent_req_done(req);
+}
+
+static bool cli_ntcreate1_cancel(struct tevent_req *req)
+{
+       struct cli_ntcreate1_state *state = tevent_req_data(
+               req, struct cli_ntcreate1_state);
+       return tevent_req_cancel(state->subreq);
+}
+
+static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
+                                  uint16_t *pfnum,
+                                  struct smb_create_returns *cr)
+{
+       struct cli_ntcreate1_state *state = tevent_req_data(
+               req, struct cli_ntcreate1_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *pfnum = state->fnum;
+       if (cr != NULL) {
+               *cr = state->cr;
+       }
+       return NT_STATUS_OK;
+}
+
+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 bool cli_ntcreate_cancel(struct tevent_req *req);
+
+struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev,
+                                    struct cli_state *cli,
+                                    const char *fname,
+                                    uint32_t create_flags,
+                                    uint32_t desired_access,
+                                    uint32_t file_attributes,
+                                    uint32_t share_access,
+                                    uint32_t create_disposition,
+                                    uint32_t create_options,
+                                    uint8_t security_flags)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_ntcreate_state *state;
+       uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+
+       req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       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,
+                       impersonation_level, desired_access,
+                       file_attributes, share_access, create_disposition,
+                       create_options);
+       } 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);
+       }
+       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)
+{
+       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 = state->recv(subreq, &state->fnum, &state->cr);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
        tevent_req_done(req);
 }
 
-NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
+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)
 {
        struct cli_ntcreate_state *state = tevent_req_data(
                req, struct cli_ntcreate_state);
@@ -1887,7 +2172,12 @@ NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
-       *pfnum = state->fnum;
+       if (fnum != NULL) {
+               *fnum = state->fnum;
+       }
+       if (cr != NULL) {
+               *cr = state->cr;
+       }
        return NT_STATUS_OK;
 }
 
@@ -1900,12 +2190,13 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
                      uint32_t CreateDisposition,
                      uint32_t CreateOptions,
                      uint8_t SecurityFlags,
-                     uint16_t *pfid)
+                     uint16_t *pfid,
+                     struct smb_create_returns *cr)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev;
        struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_OK;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
@@ -1917,7 +2208,6 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
 
        ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
@@ -1926,16 +2216,14 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
                                CreateDisposition, CreateOptions,
                                SecurityFlags);
        if (req == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
-       status = cli_ntcreate_recv(req, pfid);
+       status = cli_ntcreate_recv(req, pfid, cr);
  fail:
        TALLOC_FREE(frame);
        return status;
@@ -1943,6 +2231,7 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
 
 struct cli_nttrans_create_state {
        uint16_t fnum;
+       struct smb_create_returns cr;
 };
 
 static void cli_nttrans_create_done(struct tevent_req *subreq);
@@ -1969,6 +2258,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);
@@ -2009,6 +2299,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);
@@ -2025,7 +2319,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 */
@@ -2055,12 +2351,24 @@ static void cli_nttrans_create_done(struct tevent_req *subreq)
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       state->cr.oplock_level = CVAL(param, 0);
        state->fnum = SVAL(param, 2);
+       state->cr.create_action = IVAL(param, 4);
+       state->cr.creation_time = BVAL(param, 12);
+       state->cr.last_access_time = BVAL(param, 20);
+       state->cr.last_write_time = BVAL(param, 28);
+       state->cr.change_time   = BVAL(param, 36);
+       state->cr.file_attributes = IVAL(param, 44);
+       state->cr.allocation_size = BVAL(param, 48);
+       state->cr.end_of_file   = BVAL(param, 56);
+
        TALLOC_FREE(param);
        tevent_req_done(req);
 }
 
-NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
+NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
+                       uint16_t *fnum,
+                       struct smb_create_returns *cr)
 {
        struct cli_nttrans_create_state *state = tevent_req_data(
                req, struct cli_nttrans_create_state);
@@ -2070,6 +2378,9 @@ NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
                return status;
        }
        *fnum = state->fnum;
+       if (cr != NULL) {
+               *cr = state->cr;
+       }
        return NT_STATUS_OK;
 }
 
@@ -2085,7 +2396,8 @@ NTSTATUS cli_nttrans_create(struct cli_state *cli,
                            struct security_descriptor *secdesc,
                            struct ea_struct *eas,
                            int num_eas,
-                           uint16_t *pfid)
+                           uint16_t *pfid,
+                           struct smb_create_returns *cr)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev;
@@ -2114,7 +2426,7 @@ NTSTATUS cli_nttrans_create(struct cli_state *cli,
        if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
-       status = cli_nttrans_create_recv(req, pfid);
+       status = cli_nttrans_create_recv(req, pfid, cr);
  fail:
        TALLOC_FREE(frame);
        return status;
@@ -2145,6 +2457,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);
@@ -2212,11 +2525,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;
@@ -2326,6 +2643,7 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
        unsigned int openfn = 0;
        unsigned int dos_deny = 0;
        uint32_t access_mask, share_mode, create_disposition, create_options;
+       struct smb_create_returns cr;
 
        /* Do the initial mapping into OpenX parameters. */
        if (flags & O_CREAT) {
@@ -2406,7 +2724,8 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                                create_disposition,
                                create_options,
                                0,
-                               pfnum);
+                               pfnum,
+                               &cr);
 
        /* Try and cope will all varients of "we don't do this call"
           and fall back to openX. */
@@ -2423,6 +2742,25 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                goto try_openx;
        }
 
+       if (NT_STATUS_IS_OK(status) &&
+           (create_options & FILE_NON_DIRECTORY_FILE) &&
+           (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
+       {
+               /*
+                * Some (broken) servers return a valid handle
+                * for directories even if FILE_NON_DIRECTORY_FILE
+                * is set. Just close the handle and set the
+                * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
+                */
+               status = cli_close(cli, *pfnum);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+               /* Set this so libsmbclient can retrieve it. */
+               cli->raw_status = status;
+       }
+
        return status;
 
   try_openx:
@@ -2434,22 +2772,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;
        }
@@ -2457,34 +2795,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);
-       if (subreq == NULL) {
-               TALLOC_FREE(req);
-               return 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_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_set_callback(subreq, cli_close_done, req);
-       *psubreq = subreq;
-       return req;
+       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;
 }
 
@@ -2492,11 +2868,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);
@@ -2509,11 +2886,13 @@ NTSTATUS cli_close_recv(struct tevent_req *req)
 
 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -2534,8 +2913,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;
        }
 
@@ -2590,6 +2968,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. */
@@ -2619,11 +2998,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
@@ -2648,8 +3033,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;
        }
 
@@ -2763,7 +3147,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);
@@ -2822,8 +3206,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;
        }
 
@@ -2928,7 +3311,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);
@@ -2991,8 +3374,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;
        }
 
@@ -3077,6 +3459,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. */
@@ -3162,8 +3545,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;
        }
 
@@ -3226,8 +3608,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;
        }
 
@@ -3271,7 +3652,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);
@@ -3346,11 +3727,23 @@ NTSTATUS cli_getattrE(struct cli_state *cli,
                        time_t *access_time,
                        time_t *write_time)
 {
-       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_getattrE(cli,
+                                       fnum,
+                                       attr,
+                                       size,
+                                       change_time,
+                                       access_time,
+                                       write_time);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3371,8 +3764,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;
        }
 
@@ -3409,6 +3801,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);
@@ -3430,8 +3823,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);
        }
@@ -3493,11 +3891,21 @@ NTSTATUS cli_getatr(struct cli_state *cli,
                        off_t *size,
                        time_t *write_time)
 {
-       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_getatr(cli,
+                                       fname,
+                                       attr,
+                                       size,
+                                       write_time);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3518,8 +3926,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;
        }
 
@@ -3568,7 +3975,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);
@@ -3602,11 +4009,21 @@ NTSTATUS cli_setattrE(struct cli_state *cli,
                        time_t access_time,
                        time_t write_time)
 {
-       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_setattrE(cli,
+                                       fnum,
+                                       change_time,
+                                       access_time,
+                                       write_time);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3633,8 +4050,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;
        }
 
@@ -3665,6 +4081,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);
@@ -3698,8 +4115,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);
        }
@@ -3731,11 +4153,20 @@ NTSTATUS cli_setatr(struct cli_state *cli,
                uint16_t attr,
                time_t mtime)
 {
-       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_setatr(cli,
+                                       fname,
+                                       attr,
+                                       mtime);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3756,8 +4187,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;
        }
 
@@ -3769,7 +4199,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);
@@ -3786,6 +4216,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);
@@ -3805,8 +4236,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);
        }
@@ -3835,12 +4271,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
@@ -3875,8 +4317,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;
        }
 
@@ -3912,7 +4353,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);
@@ -3960,11 +4401,13 @@ NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *a
 
 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3985,8 +4428,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;
        }
 
@@ -3997,6 +4439,78 @@ NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
        return status;
 }
 
+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;
+       int old_bsize, old_total, old_avail;
+       NTSTATUS status;
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_dskattr(cli, path, bsize, total, avail);
+       }
+
+       /*
+        * Try the trans2 disk full size info call first.
+        * We already use this in SMBC_fstatvfs_ctx().
+        * Ignore 'actual_available_units' as we only
+        * care about the quota for the caller.
+        */
+
+       status = cli_get_fs_full_size_info(cli,
+                       total,
+                       avail,
+                       NULL,
+                       &sectors_per_block,
+                       &bytes_per_sector);
+
+        /* Try and cope will all varients of "we don't do this call"
+           and fall back to cli_dskattr. */
+
+       if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
+               goto try_dskattr;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (bsize) {
+               *bsize = sectors_per_block *
+                        bytes_per_sector;
+       }
+
+       return NT_STATUS_OK;
+
+  try_dskattr:
+
+       /* Old SMB1 core protocol fallback. */
+       status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       if (bsize) {
+               *bsize = (uint64_t)old_bsize;
+       }
+       if (total) {
+               *total = (uint64_t)old_total;
+       }
+       if (avail) {
+               *avail = (uint64_t)old_avail;
+       }
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Create and open a temporary file.
 ****************************************************************************/
@@ -4017,6 +4531,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);
@@ -4038,8 +4553,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);
        }
@@ -4138,8 +4658,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;
        }
 
@@ -4217,10 +4736,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 */
@@ -4240,11 +4768,22 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
        unsigned int param_len = 0;
        uint8_t *param;
        NTSTATUS status;
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_set_ea_path(cli,
+                                       path,
+                                       ea_name,
+                                       ea_val,
+                                       ea_len);
+       }
+
+       frame = talloc_stackframe();
 
-       param = talloc_array(talloc_tos(), uint8_t, 6);
+       param = talloc_array(frame, uint8_t, 6);
        if (!param) {
-               return NT_STATUS_NO_MEMORY;
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
        }
        SSVAL(param,0,SMB_INFO_SET_EA);
        SSVAL(param,2,0);
@@ -4257,7 +4796,10 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
 
        status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
                            ea_name, ea_val, ea_len);
-       talloc_free(frame);
+
+  fail:
+
+       TALLOC_FREE(frame);
        return status;
 }
 
@@ -4271,6 +4813,14 @@ NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
 {
        uint8_t param[6];
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_set_ea_fnum(cli,
+                                       fnum,
+                                       ea_name,
+                                       ea_val,
+                                       ea_len);
+       }
+
        memset(param, 0, 6);
        SSVAL(param,0,fnum);
        SSVAL(param,2,SMB_INFO_SET_EA);
@@ -4452,11 +5002,21 @@ NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
                size_t *pnum_eas,
                struct ea_struct **pea_list)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_get_ea_list_path(cli,
+                                       path,
+                                       ctx,
+                                       pnum_eas,
+                                       pea_list);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -4612,6 +5172,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. */
@@ -4695,8 +5256,7 @@ NTSTATUS cli_posix_open(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;
        }
 
@@ -4753,8 +5313,7 @@ NTSTATUS cli_posix_mkdir(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;
        }
 
@@ -4858,8 +5417,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;
        }
 
@@ -4919,8 +5477,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;
        }
 
@@ -4936,12 +5493,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,
@@ -4949,7 +5509,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;
 
@@ -4958,6 +5518,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);
@@ -4967,10 +5552,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. */
@@ -4988,13 +5574,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(
@@ -5009,6 +5607,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;
@@ -5066,6 +5665,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)
@@ -5088,11 +5707,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
@@ -5137,6 +5758,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) {
@@ -5156,10 +5778,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. */
@@ -5290,6 +5918,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. */
@@ -5413,7 +6042,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);
@@ -5505,8 +6134,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)) {
@@ -5540,36 +6170,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),
@@ -5579,7 +6234,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;
 }
@@ -5588,11 +6243,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