s3:libsmb: get rid of cli_ucs2
[obnox/samba/samba-obnox.git] / source3 / libsmb / clifile.c
index 2a30d2cda9c92ab8978215feb8d541dd618b2e4a..3bdb49d6d40c560046ca682dadca3b6ce24b1e76 100644 (file)
@@ -27,6 +27,7 @@
 #include "trans2.h"
 #include "ntioctl.h"
 #include "libcli/security/secdesc.h"
+#include "../libcli/smb/smbXcli_base.h"
 
 /***********************************************************
  Common function for pushing stings, used by smb_bytes_push_str()
@@ -190,7 +191,7 @@ struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
        SSVAL(state->param, 0, level);
 
        state->param = trans2_bytes_push_str(
-               state->param, cli_ucs2(cli), path, strlen(path)+1, NULL);
+               state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
        if (tevent_req_nomem(state->param, req)) {
                return tevent_req_post(req, ev);
        }
@@ -244,7 +245,7 @@ NTSTATUS cli_setpathinfo(struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -301,7 +302,7 @@ 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, cli_ucs2(cli), oldname, strlen(oldname)+1, NULL);
+               state->data, smbXcli_conn_use_unicode(cli->conn), oldname, strlen(oldname)+1, NULL);
 
        subreq = cli_setpathinfo_send(
                state, ev, cli, level, newname,
@@ -347,7 +348,7 @@ NTSTATUS cli_posix_symlink(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -402,7 +403,7 @@ struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req = NULL, *subreq = NULL;
        struct readlink_state *state = NULL;
-       uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
+       uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
 
        req = tevent_req_create(mem_ctx, &state, struct readlink_state);
        if (req == NULL) {
@@ -463,7 +464,7 @@ NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
        }
        /* The returned data is a pushed string, not raw data. */
        if (!convert_string_talloc(state,
-                               cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, 
+                               smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS, 
                                CH_UNIX,
                                state->data,
                                state->num_data,
@@ -488,7 +489,7 @@ NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -552,7 +553,7 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -664,7 +665,7 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -795,7 +796,7 @@ NTSTATUS cli_posix_stat(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -908,7 +909,7 @@ NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -977,7 +978,7 @@ NTSTATUS cli_posix_chown(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1047,7 +1048,7 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
                                   strlen(fname_src)+1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -1060,7 +1061,7 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
        }
 
        bytes[talloc_get_size(bytes)-1] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
                                   strlen(fname_dst)+1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -1101,7 +1102,7 @@ NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fn
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1169,7 +1170,7 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
                                   strlen(fname_src)+1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -1182,7 +1183,7 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
        }
 
        bytes[talloc_get_size(bytes)-1] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
                                   strlen(fname_dst)+1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -1242,7 +1243,7 @@ NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1304,7 +1305,7 @@ NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const cha
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1369,7 +1370,7 @@ struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
                                   strlen(fname)+1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
@@ -1411,7 +1412,7 @@ NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_a
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1473,7 +1474,7 @@ struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
                                   strlen(dname)+1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
@@ -1515,7 +1516,7 @@ NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1577,7 +1578,7 @@ struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
                                   strlen(dname)+1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
@@ -1619,7 +1620,7 @@ NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1729,7 +1730,7 @@ NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1813,17 +1814,18 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
        SIVAL(vwv+13, 1, FileAttributes);
        SIVAL(vwv+15, 1, ShareAccess);
        SIVAL(vwv+17, 1, CreateDisposition);
-       SIVAL(vwv+19, 1, CreateOptions);
+       SIVAL(vwv+19, 1, CreateOptions |
+               (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
        SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
        SCVAL(vwv+23, 1, SecurityFlags);
 
        bytes = talloc_array(state, uint8_t, 0);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
                                   fname, strlen(fname)+1,
                                   &converted_len);
 
        /* sigh. this copes with broken netapp filer behaviour */
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -1892,7 +1894,7 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -1987,7 +1989,7 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       param = trans2_bytes_push_str(param, cli_ucs2(cli),
+       param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
                                      fname, strlen(fname),
                                      &converted_len);
        if (tevent_req_nomem(param, req)) {
@@ -2002,7 +2004,8 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
        SIVAL(param, 20, FileAttributes);
        SIVAL(param, 24, ShareAccess);
        SIVAL(param, 28, CreateDisposition);
-       SIVAL(param, 32, CreateOptions);
+       SIVAL(param, 32, CreateOptions |
+               (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
        SIVAL(param, 36, secdesc_len);
        SIVAL(param, 40, 0);     /* EA length*/
        SIVAL(param, 44, converted_len);
@@ -2076,7 +2079,7 @@ NTSTATUS cli_nttrans_create(struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -2109,90 +2112,87 @@ NTSTATUS cli_nttrans_create(struct cli_state *cli,
  WARNING: if you open with O_WRONLY then getattrE won't work!
 ****************************************************************************/
 
-struct cli_open_state {
-       struct tevent_context *ev;
-       struct cli_state *cli;
+struct cli_openx_state {
        const char *fname;
        uint16_t vwv[15];
        uint16_t fnum;
-       unsigned openfn;
-       unsigned dos_deny;
-       uint8_t additional_flags;
        struct iovec bytes;
 };
 
-static void cli_open_done(struct tevent_req *subreq);
-static void cli_open_ntcreate_done(struct tevent_req *subreq);
+static void cli_openx_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
+struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
                                   struct event_context *ev,
                                   struct cli_state *cli, const char *fname,
                                   int flags, int share_mode,
                                   struct tevent_req **psmbreq)
 {
        struct tevent_req *req, *subreq;
-       struct cli_open_state *state;
+       struct cli_openx_state *state;
+       unsigned openfn;
+       unsigned accessmode;
+       uint8_t additional_flags;
        uint8_t *bytes;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
+       req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
        if (req == NULL) {
                return NULL;
        }
-       state->ev = ev;
-       state->cli = cli;
-       state->fname = fname;
 
+       openfn = 0;
        if (flags & O_CREAT) {
-               state->openfn |= (1<<4);
+               openfn |= (1<<4);
        }
        if (!(flags & O_EXCL)) {
                if (flags & O_TRUNC)
-                       state->openfn |= (1<<1);
+                       openfn |= (1<<1);
                else
-                       state->openfn |= (1<<0);
+                       openfn |= (1<<0);
        }
 
-       state->dos_deny = (share_mode<<4);
+       accessmode = (share_mode<<4);
 
        if ((flags & O_ACCMODE) == O_RDWR) {
-               state->dos_deny |= 2;
+               accessmode |= 2;
        } else if ((flags & O_ACCMODE) == O_WRONLY) {
-               state->dos_deny |= 1;
+               accessmode |= 1;
        }
 
 #if defined(O_SYNC)
        if ((flags & O_SYNC) == O_SYNC) {
-               state->dos_deny |= (1<<14);
+               accessmode |= (1<<14);
        }
 #endif /* O_SYNC */
 
        if (share_mode == DENY_FCB) {
-               state->dos_deny = 0xFF;
+               accessmode = 0xFF;
        }
 
        SCVAL(state->vwv + 0, 0, 0xFF);
        SCVAL(state->vwv + 0, 1, 0);
        SSVAL(state->vwv + 1, 0, 0);
        SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
-       SSVAL(state->vwv + 3, 0, state->dos_deny);
+       SSVAL(state->vwv + 3, 0, accessmode);
        SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
        SSVAL(state->vwv + 5, 0, 0);
        SIVAL(state->vwv + 6, 0, 0);
-       SSVAL(state->vwv + 8, 0, state->openfn);
+       SSVAL(state->vwv + 8, 0, openfn);
        SIVAL(state->vwv + 9, 0, 0);
        SIVAL(state->vwv + 11, 0, 0);
        SIVAL(state->vwv + 13, 0, 0);
 
+       additional_flags = 0;
+
        if (cli->use_oplocks) {
                /* if using oplocks then ask for a batch oplock via
                    core and extended methods */
-               state->additional_flags =
+               additional_flags =
                        FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
                SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
        }
 
        bytes = talloc_array(state, uint8_t, 0);
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
                                   strlen(fname)+1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
@@ -2202,26 +2202,25 @@ struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
        state->bytes.iov_base = (void *)bytes;
        state->bytes.iov_len = talloc_get_size(bytes);
 
-       subreq = cli_smb_req_create(state, ev, cli, SMBopenX,
-                                   state->additional_flags,
+       subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
                                    15, state->vwv, 1, &state->bytes);
        if (subreq == NULL) {
                TALLOC_FREE(req);
                return NULL;
        }
-       tevent_req_set_callback(subreq, cli_open_done, req);
+       tevent_req_set_callback(subreq, cli_openx_done, req);
        *psmbreq = subreq;
        return req;
 }
 
-struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
                                 struct cli_state *cli, const char *fname,
                                 int flags, int share_mode)
 {
        struct tevent_req *req, *subreq;
        NTSTATUS status;
 
-       req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
+       req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
                              &subreq);
        if (req == NULL) {
                return NULL;
@@ -2234,76 +2233,31 @@ struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
        return req;
 }
 
-static void cli_open_done(struct tevent_req *subreq)
+static void cli_openx_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct cli_open_state *state = tevent_req_data(
-               req, struct cli_open_state);
+       struct cli_openx_state *state = tevent_req_data(
+               req, struct cli_openx_state);
        uint8_t wct;
        uint16_t *vwv;
        uint8_t *inbuf;
        NTSTATUS status;
-       uint32_t access_mask, share_mode, create_disposition, create_options;
 
        status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
                              NULL);
        TALLOC_FREE(subreq);
-
-       if (NT_STATUS_IS_OK(status)) {
-               state->fnum = SVAL(vwv+2, 0);
-               tevent_req_done(req);
-               return;
-       }
-
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
-               tevent_req_nterror(req, status);
-               return;
-       }
-
-       /*
-        * For the new shiny OS/X Lion SMB server, try a ntcreate
-        * fallback.
-        */
-
-       if (!map_open_params_to_ntcreate(state->fname, state->dos_deny,
-                                        state->openfn, &access_mask,
-                                        &share_mode, &create_disposition,
-                                        &create_options, NULL)) {
-               tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
-               return;
-       }
-
-       subreq = cli_ntcreate_send(state, state->ev, state->cli,
-                                  state->fname, 0, access_mask,
-                                  0, share_mode, create_disposition,
-                                  create_options, 0);
-       if (tevent_req_nomem(subreq, req)) {
-               return;
-       }
-       tevent_req_set_callback(subreq, cli_open_ntcreate_done, req);
-}
-
-static void cli_open_ntcreate_done(struct tevent_req *subreq)
-{
-       struct tevent_req *req = tevent_req_callback_data(
-               subreq, struct tevent_req);
-       struct cli_open_state *state = tevent_req_data(
-               req, struct cli_open_state);
-       NTSTATUS status;
-
-       status = cli_ntcreate_recv(subreq, &state->fnum);
-       TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       state->fnum = SVAL(vwv+2, 0);
        tevent_req_done(req);
 }
 
-NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
+NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
 {
-       struct cli_open_state *state = tevent_req_data(
-               req, struct cli_open_state);
+       struct cli_openx_state *state = tevent_req_data(
+               req, struct cli_openx_state);
        NTSTATUS status;
 
        if (tevent_req_is_nterror(req, &status)) {
@@ -2313,7 +2267,7 @@ NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
        return NT_STATUS_OK;
 }
 
-NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
+NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
             int share_mode, uint16_t *pfnum)
 {
        TALLOC_CTX *frame = talloc_stackframe();
@@ -2321,7 +2275,7 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -2335,7 +2289,7 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                goto fail;
        }
 
-       req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
+       req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
        if (req == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto fail;
@@ -2346,11 +2300,126 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                goto fail;
        }
 
-       status = cli_open_recv(req, pfnum);
+       status = cli_openx_recv(req, pfnum);
  fail:
        TALLOC_FREE(frame);
        return status;
 }
+/****************************************************************************
+ Synchronous wrapper function that does an NtCreateX open by preference
+ and falls back to openX if this fails.
+****************************************************************************/
+
+NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
+                       int share_mode_in, uint16_t *pfnum)
+{
+       NTSTATUS status;
+       unsigned int openfn = 0;
+       unsigned int dos_deny = 0;
+       uint32_t access_mask, share_mode, create_disposition, create_options;
+
+       /* Do the initial mapping into OpenX parameters. */
+       if (flags & O_CREAT) {
+               openfn |= (1<<4);
+       }
+       if (!(flags & O_EXCL)) {
+               if (flags & O_TRUNC)
+                       openfn |= (1<<1);
+               else
+                       openfn |= (1<<0);
+       }
+
+       dos_deny = (share_mode_in<<4);
+
+       if ((flags & O_ACCMODE) == O_RDWR) {
+               dos_deny |= 2;
+       } else if ((flags & O_ACCMODE) == O_WRONLY) {
+               dos_deny |= 1;
+       }
+
+#if defined(O_SYNC)
+       if ((flags & O_SYNC) == O_SYNC) {
+               dos_deny |= (1<<14);
+       }
+#endif /* O_SYNC */
+
+       if (share_mode_in == DENY_FCB) {
+               dos_deny = 0xFF;
+       }
+
+#if 0
+       /* Hmmm. This is what I think the above code
+          should look like if it's using the constants
+          we #define. JRA. */
+
+       if (flags & O_CREAT) {
+               openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
+       }
+       if (!(flags & O_EXCL)) {
+               if (flags & O_TRUNC)
+                       openfn |= OPENX_FILE_EXISTS_TRUNCATE;
+               else
+                       openfn |= OPENX_FILE_EXISTS_OPEN;
+       }
+
+       dos_deny = SET_DENY_MODE(share_mode_in);
+
+       if ((flags & O_ACCMODE) == O_RDWR) {
+               dos_deny |= DOS_OPEN_RDWR;
+       } else if ((flags & O_ACCMODE) == O_WRONLY) {
+               dos_deny |= DOS_OPEN_WRONLY;
+       }
+
+#if defined(O_SYNC)
+       if ((flags & O_SYNC) == O_SYNC) {
+               dos_deny |= FILE_SYNC_OPENMODE;
+       }
+#endif /* O_SYNC */
+
+       if (share_mode_in == DENY_FCB) {
+               dos_deny = 0xFF;
+       }
+#endif
+
+       if (!map_open_params_to_ntcreate(fname, dos_deny,
+                                       openfn, &access_mask,
+                                       &share_mode, &create_disposition,
+                                       &create_options, NULL)) {
+               goto try_openx;
+       }
+
+       status = cli_ntcreate(cli,
+                               fname,
+                               0,
+                               access_mask,
+                               0,
+                               share_mode,
+                               create_disposition,
+                               create_options,
+                               0,
+                               pfnum);
+
+       /* Try and cope will all varients of "we don't do this call"
+          and fall back to openX. */
+
+       if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
+                       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_openx;
+       }
+
+       return status;
+
+  try_openx:
+
+       return cli_openx(cli, fname, flags, share_mode_in, pfnum);
+}
 
 /****************************************************************************
  Close a file.
@@ -2436,7 +2505,7 @@ NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -2546,7 +2615,7 @@ NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -2723,7 +2792,7 @@ NTSTATUS cli_unlock(struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -2771,7 +2840,7 @@ NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
        int ltype;
        NTSTATUS status;
 
-       if (! (cli_state_capabilities(cli) & CAP_LARGE_FILES)) {
+       if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
                return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
        }
 
@@ -2888,11 +2957,11 @@ NTSTATUS cli_unlock64(struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (! (cli_state_capabilities(cli) & CAP_LARGE_FILES)) {
+       if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
                return cli_unlock(cli, fnum, offset, len);
        }
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3052,7 +3121,7 @@ NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3123,7 +3192,7 @@ NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3170,7 +3239,7 @@ struct cli_getattrE_state {
        uint16_t vwv[1];
        int zone_offset;
        uint16_t attr;
-       SMB_OFF_T size;
+       off_t size;
        time_t change_time;
        time_t access_time;
        time_t write_time;
@@ -3190,7 +3259,7 @@ struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       state->zone_offset = cli->serverzone;
+       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,
@@ -3220,7 +3289,7 @@ static void cli_getattrE_done(struct tevent_req *subreq)
                return;
        }
 
-       state->size = (SMB_OFF_T)IVAL(vwv+6,0);
+       state->size = (off_t)IVAL(vwv+6,0);
        state->attr = SVAL(vwv+10,0);
        state->change_time = make_unix_date2(vwv+0, state->zone_offset);
        state->access_time = make_unix_date2(vwv+2, state->zone_offset);
@@ -3231,7 +3300,7 @@ static void cli_getattrE_done(struct tevent_req *subreq)
 
 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
                        uint16_t *attr,
-                       SMB_OFF_T *size,
+                       off_t *size,
                        time_t *change_time,
                        time_t *access_time,
                        time_t *write_time)
@@ -3264,7 +3333,7 @@ NTSTATUS cli_getattrE_recv(struct tevent_req *req,
 NTSTATUS cli_getattrE(struct cli_state *cli,
                        uint16_t fnum,
                        uint16_t *attr,
-                       SMB_OFF_T *size,
+                       off_t *size,
                        time_t *change_time,
                        time_t *access_time,
                        time_t *write_time)
@@ -3274,7 +3343,7 @@ NTSTATUS cli_getattrE(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3320,7 +3389,7 @@ static void cli_getatr_done(struct tevent_req *subreq);
 struct cli_getatr_state {
        int zone_offset;
        uint16_t attr;
-       SMB_OFF_T size;
+       off_t size;
        time_t write_time;
 };
 
@@ -3339,14 +3408,14 @@ struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       state->zone_offset = cli->serverzone;
+       state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
 
        bytes = talloc_array(state, uint8_t, 1);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
                                   strlen(fname)+1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
@@ -3381,7 +3450,7 @@ static void cli_getatr_done(struct tevent_req *subreq)
        }
 
        state->attr = SVAL(vwv+0,0);
-       state->size = (SMB_OFF_T)IVAL(vwv+3,0);
+       state->size = (off_t)IVAL(vwv+3,0);
        state->write_time = make_unix_date3(vwv+1, state->zone_offset);
 
        tevent_req_done(req);
@@ -3389,7 +3458,7 @@ static void cli_getatr_done(struct tevent_req *subreq)
 
 NTSTATUS cli_getatr_recv(struct tevent_req *req,
                        uint16_t *attr,
-                       SMB_OFF_T *size,
+                       off_t *size,
                        time_t *write_time)
 {
        struct cli_getatr_state *state = tevent_req_data(
@@ -3414,7 +3483,7 @@ NTSTATUS cli_getatr_recv(struct tevent_req *req,
 NTSTATUS cli_getatr(struct cli_state *cli,
                        const char *fname,
                        uint16_t *attr,
-                       SMB_OFF_T *size,
+                       off_t *size,
                        time_t *write_time)
 {
        TALLOC_CTX *frame = talloc_stackframe();
@@ -3422,7 +3491,7 @@ NTSTATUS cli_getatr(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3486,11 +3555,11 @@ struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
 
        SSVAL(state->vwv+0, 0, fnum);
        push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
-                      cli->serverzone);
+                      smb1cli_conn_server_time_zone(cli->conn));
        push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
-                      cli->serverzone);
+                      smb1cli_conn_server_time_zone(cli->conn));
        push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
-                      cli->serverzone);
+                      smb1cli_conn_server_time_zone(cli->conn));
 
        subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
                              7, state->vwv, 0, NULL);
@@ -3531,7 +3600,7 @@ NTSTATUS cli_setattrE(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3597,14 +3666,14 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
        }
 
        SSVAL(state->vwv+0, 0, attr);
-       push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, cli->serverzone);
+       push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
 
        bytes = talloc_array(state, uint8_t, 1);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
                                   strlen(fname)+1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -3616,7 +3685,7 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
        }
 
        bytes[talloc_get_size(bytes)-1] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
                                   1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -3660,7 +3729,7 @@ NTSTATUS cli_setatr(struct cli_state *cli,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3722,7 +3791,7 @@ struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
                                   strlen(fname)+1, NULL);
 
        if (tevent_req_nomem(bytes, req)) {
@@ -3765,7 +3834,7 @@ NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
        char *path2 = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3890,7 +3959,7 @@ NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -3957,7 +4026,7 @@ struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        bytes[0] = 4;
-       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
+       bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
                                   strlen(path)+1, NULL);
        if (tevent_req_nomem(bytes, req)) {
                return tevent_req_post(req, ev);
@@ -4044,7 +4113,7 @@ NTSTATUS cli_ctemp(struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -4117,7 +4186,9 @@ static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
 
        if (ea_namelen == 0 && ea_len == 0) {
                data_len = 4;
-               data = (uint8_t *)SMB_MALLOC(data_len);
+               data = talloc_array(talloc_tos(),
+                               uint8_t,
+                               data_len);
                if (!data) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -4125,7 +4196,9 @@ static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
                SIVAL(p,0,data_len);
        } else {
                data_len = 4 + 4 + ea_namelen + 1 + ea_len;
-               data = (uint8_t *)SMB_MALLOC(data_len);
+               data = talloc_array(talloc_tos(),
+                               uint8_t,
+                               data_len);
                if (!data) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -4147,7 +4220,7 @@ static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
                           NULL, 0, NULL, /* rsetup */
                           NULL, 0, NULL, /* rparam */
                           NULL, 0, NULL); /* rdata */
-       SAFE_FREE(data);
+       talloc_free(data);
        return status;
 }
 
@@ -4172,14 +4245,14 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
        SSVAL(param,2,0);
        SSVAL(param,4,0);
 
-       param = trans2_bytes_push_str(param, cli_ucs2(cli),
+       param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
                                      path, strlen(path)+1,
                                      NULL);
        param_len = talloc_get_size(param);
 
        status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
                            ea_name, ea_val, ea_len);
-       SAFE_FREE(frame);
+       talloc_free(frame);
        return status;
 }
 
@@ -4379,7 +4452,7 @@ NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -4513,7 +4586,7 @@ static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
        memset(state->param, '\0', 6);
        SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
 
-       state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
+       state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
                                   strlen(fname)+1, NULL);
 
        if (tevent_req_nomem(state->param, req)) {
@@ -4592,7 +4665,7 @@ NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -4651,7 +4724,7 @@ NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -4757,7 +4830,7 @@ NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -4818,7 +4891,7 @@ NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -4873,6 +4946,7 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req, *subreq;
        struct cli_notify_state *state;
+       unsigned old_timeout;
 
        req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
        if (req == NULL) {
@@ -4883,6 +4957,11 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
        SSVAL(state->setup, 4, fnum);
        SSVAL(state->setup, 6, recursive);
 
+       /*
+        * Notifies should not time out
+        */
+       old_timeout = cli_set_timeout(cli, 0);
+
        subreq = cli_trans_send(
                state,                  /* mem ctx. */
                ev,                     /* event ctx. */
@@ -4902,6 +4981,8 @@ struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
                0,                      /* num data. */
                0);                     /* max returned data. */
 
+       cli_set_timeout(cli, old_timeout);
+
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -4932,13 +5013,13 @@ static void cli_notify_done(struct tevent_req *subreq)
        ofs = 0;
 
        while (num_params - ofs > 12) {
-               uint32_t len = IVAL(params, ofs);
+               uint32_t next = IVAL(params, ofs);
                state->num_changes += 1;
 
-               if ((len == 0) || (ofs+len >= num_params)) {
+               if ((next == 0) || (ofs+next >= num_params)) {
                        break;
                }
-               ofs += len;
+               ofs += next;
        }
 
        state->changes = talloc_array(state, struct notify_change,
@@ -4956,7 +5037,7 @@ static void cli_notify_done(struct tevent_req *subreq)
                ssize_t ret;
                char *name;
 
-               if ((next != 0) && (len+12 != next)) {
+               if (trans_oob(num_params, ofs + 12, len)) {
                        TALLOC_FREE(params);
                        tevent_req_nterror(
                                req, NT_STATUS_INVALID_NETWORK_RESPONSE);
@@ -4997,6 +5078,41 @@ NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
+                   uint32_t completion_filter, bool recursive,
+                   TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
+                   struct notify_change **pchanges)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       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 = tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
+                             completion_filter, recursive);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
 struct cli_qpathinfo_state {
        uint8_t *param;
        uint8_t *data;
@@ -5030,7 +5146,7 @@ struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
        }
        SSVAL(state->param, 0, level);
        state->param = trans2_bytes_push_str(
-               state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
+               state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
        if (tevent_req_nomem(state->param, req)) {
                return tevent_req_post(req, ev);
        }
@@ -5110,7 +5226,7 @@ NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -5247,7 +5363,7 @@ NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -5327,7 +5443,7 @@ NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */
@@ -5472,7 +5588,7 @@ NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (cli_has_async_calls(cli)) {
+       if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
                 */