Add the strlen to push to smb_bytes_push_str, return the converted size
[nivanova/samba-autobuild/.git] / source3 / libsmb / clifile.c
index 2fb5b456cc4fe664bc12ec136b83922999410c94..3b6585b7e79875e88386949f8165f24856e1aede 100644 (file)
@@ -6,7 +6,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#define NO_SYSLOG
-
 #include "includes.h"
 
 /****************************************************************************
  Creates new name (sym)linked to oldname.
 ****************************************************************************/
 
-static BOOL cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, BOOL hard_link)
+static bool cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, bool hard_link)
 {
        unsigned int data_len = 0;
        unsigned int param_len = 0;
        uint16 setup = TRANSACT2_SETPATHINFO;
-       char param[sizeof(pstring)+6];
-       pstring data;
+       char *param;
+       char *data;
        char *rparam=NULL, *rdata=NULL;
        char *p;
        size_t oldlen = 2*(strlen(oldname)+1);
        size_t newlen = 2*(strlen(newname)+1);
 
-       memset(param, 0, sizeof(param));
+       param = SMB_MALLOC_ARRAY(char, 6+newlen+2);
+
+       if (!param) {
+               return false;
+       }
+
+       data = SMB_MALLOC_ARRAY(char, oldlen+2);
+
+       if (!data) {
+               SAFE_FREE(param);
+               return false;
+       }
+
        SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
+       SIVAL(param,2,0);
        p = &param[6];
 
-       p += clistr_push(cli, p, newname, MIN(newlen, sizeof(param)-6), STR_TERMINATE);
+       p += clistr_push(cli, p, newname, newlen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
        p = data;
-       p += clistr_push(cli, p, oldname, MIN(oldlen,sizeof(data)), STR_TERMINATE);
+       p += clistr_push(cli, p, oldname, oldlen, STR_TERMINATE);
        data_len = PTR_DIFF(p, data);
 
        if (!cli_send_trans(cli, SMBtrans2,
-               NULL,                        /* name */
-               -1, 0,                          /* fid, flags */
-               &setup, 1, 0,                   /* setup, length, max */
-               param, param_len, 2,            /* param, length, max */
-               (char *)&data,  data_len, cli->max_xmit /* data, length, max */
-               )) {
-                       return False;
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               SAFE_FREE(data);
+               SAFE_FREE(param);
+               return false;
        }
 
+       SAFE_FREE(data);
+       SAFE_FREE(param);
+
        if (!cli_receive_trans(cli, SMBtrans2,
-               &rparam, &param_len,
-               &rdata, &data_len)) {
-                       return False;
+                       &rparam, &param_len,
+                       &rdata, &data_len)) {
+                       return false;
        }
 
+       SAFE_FREE(data);
+       SAFE_FREE(param);
        SAFE_FREE(rdata);
        SAFE_FREE(rparam);
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
@@ -134,7 +151,7 @@ mode_t wire_perms_to_unix(uint32 perms)
 /****************************************************************************
  Return the file type from the wire filetype for UNIX extensions.
 ****************************************************************************/
-                                                                                                                
+
 static mode_t unix_filetype_from_wire(uint32 wire_type)
 {
        switch (wire_type) {
@@ -171,20 +188,26 @@ static mode_t unix_filetype_from_wire(uint32 wire_type)
  Do a POSIX getfacl (UNIX extensions).
 ****************************************************************************/
 
-BOOL cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf)
+bool cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf)
 {
        unsigned int param_len = 0;
        unsigned int data_len = 0;
        uint16 setup = TRANSACT2_QPATHINFO;
-       char param[sizeof(pstring)+6];
+       char *param;
+       size_t nlen = 2*(strlen(name)+1);
        char *rparam=NULL, *rdata=NULL;
        char *p;
 
+       param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+       if (!param) {
+               return false;
+       }
+
        p = param;
-       memset(p, 0, 6);
+       memset(p, '\0', 6);
        SSVAL(p, 0, SMB_QUERY_POSIX_ACL);
        p += 6;
-       p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
+       p += clistr_push(cli, p, name, nlen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
        if (!cli_send_trans(cli, SMBtrans2,
@@ -194,70 +217,81 @@ BOOL cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size,
                param, param_len, 2,         /* param, length, max */
                NULL,  0, cli->max_xmit      /* data, length, max */
                )) {
-                       return False;
+               SAFE_FREE(param);
+               return false;
        }
 
+       SAFE_FREE(param);
+
        if (!cli_receive_trans(cli, SMBtrans2,
-               &rparam, &param_len,
-               &rdata, &data_len)) {
-                       return False;
+                       &rparam, &param_len,
+                       &rdata, &data_len)) {
+               return false;
        }
 
        if (data_len < 6) {
                SAFE_FREE(rdata);
                SAFE_FREE(rparam);
-               return False;
+               return false;
        }
 
        SAFE_FREE(rparam);
        *retbuf = rdata;
        *prb_size = (size_t)data_len;
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  Stat a file (UNIX extensions).
 ****************************************************************************/
 
-BOOL cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
+bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
 {
        unsigned int param_len = 0;
        unsigned int data_len = 0;
        uint16 setup = TRANSACT2_QPATHINFO;
-       char param[sizeof(pstring)+6];
+       char *param;
+       size_t nlen = 2*(strlen(name)+1);
        char *rparam=NULL, *rdata=NULL;
        char *p;
 
        ZERO_STRUCTP(sbuf);
 
+       param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+       if (!param) {
+               return false;
+       }
        p = param;
-       memset(p, 0, 6);
+       memset(p, '\0', 6);
        SSVAL(p, 0, SMB_QUERY_FILE_UNIX_BASIC);
        p += 6;
-       p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
+       p += clistr_push(cli, p, name, nlen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
        if (!cli_send_trans(cli, SMBtrans2,
-               NULL,                        /* name */
-               -1, 0,                       /* fid, flags */
-               &setup, 1, 0,                /* setup, length, max */
-               param, param_len, 2,         /* param, length, max */
-               NULL,  0, cli->max_xmit      /* data, length, max */
-               )) {
-                       return False;
+                       NULL,                        /* name */
+                       -1, 0,                       /* fid, flags */
+                       &setup, 1, 0,                /* setup, length, max */
+                       param, param_len, 2,         /* param, length, max */
+                       NULL,  0, cli->max_xmit      /* data, length, max */
+                       )) {
+               SAFE_FREE(param);
+               return false;
        }
 
+       SAFE_FREE(param);
+
        if (!cli_receive_trans(cli, SMBtrans2,
-               &rparam, &param_len,
-               &rdata, &data_len)) {
-                       return False;
+                       &rparam, &param_len,
+                       &rdata, &data_len)) {
+               return false;
        }
 
        if (data_len < 96) {
                SAFE_FREE(rdata);
                SAFE_FREE(rparam);
-               return False;
+               return false;
        }
 
        sbuf->st_size = IVAL2_TO_SMB_BIG_UINT(rdata,0);     /* total size, in bytes */
@@ -268,9 +302,10 @@ BOOL cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbu
        /* assume 512 byte blocks */
        sbuf->st_blocks /= 512;
 #endif
-       sbuf->st_ctime = interpret_long_date(rdata + 16);    /* time of last change */
-       sbuf->st_atime = interpret_long_date(rdata + 24);    /* time of last access */
-       sbuf->st_mtime = interpret_long_date(rdata + 32);    /* time of last modification */
+       set_ctimespec(sbuf, interpret_long_date(rdata + 16));    /* time of last change */
+       set_atimespec(sbuf, interpret_long_date(rdata + 24));    /* time of last access */
+       set_mtimespec(sbuf, interpret_long_date(rdata + 32));    /* time of last modification */
+
        sbuf->st_uid = (uid_t) IVAL(rdata,40);      /* user ID of owner */
        sbuf->st_gid = (gid_t) IVAL(rdata,48);      /* group ID of owner */
        sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56));
@@ -288,14 +323,14 @@ BOOL cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbu
        SAFE_FREE(rdata);
        SAFE_FREE(rparam);
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  Symlink a file (UNIX extensions).
 ****************************************************************************/
 
-BOOL cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
+bool cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
 {
        return cli_link_internal(cli, oldname, newname, False);
 }
@@ -304,7 +339,7 @@ BOOL cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *ne
  Hard a file (UNIX extensions).
 ****************************************************************************/
 
-BOOL cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
+bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
 {
        return cli_link_internal(cli, oldname, newname, True);
 }
@@ -313,24 +348,32 @@ BOOL cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *n
  Chmod or chown a file internal (UNIX extensions).
 ****************************************************************************/
 
-static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32 mode, uint32 uid, uint32 gid)
+static bool cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32 mode, uint32 uid, uint32 gid)
 {
        unsigned int data_len = 0;
        unsigned int param_len = 0;
        uint16 setup = TRANSACT2_SETPATHINFO;
-       char param[sizeof(pstring)+6];
+       size_t nlen = 2*(strlen(fname)+1);
+       char *param;
        char data[100];
        char *rparam=NULL, *rdata=NULL;
        char *p;
 
-       memset(param, 0, sizeof(param));
+       param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
+       if (!param) {
+               return false;
+       }
+       memset(param, '\0', 6);
        memset(data, 0, sizeof(data));
+
        SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
        p = &param[6];
 
-       p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
+       memset(data, 0xff, 40); /* Set all sizes/times to no change. */
+
        SIVAL(data,40,uid);
        SIVAL(data,48,gid);
        SIVAL(data,84,mode);
@@ -338,34 +381,37 @@ static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fna
        data_len = 100;
 
        if (!cli_send_trans(cli, SMBtrans2,
-               NULL,                        /* name */
-               -1, 0,                          /* fid, flags */
-               &setup, 1, 0,                   /* setup, length, max */
-               param, param_len, 2,            /* param, length, max */
-               (char *)&data,  data_len, cli->max_xmit /* data, length, max */
-               )) {
-                       return False;
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       (char *)&data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               SAFE_FREE(param);
+               return False;
        }
 
+       SAFE_FREE(param);
+
        if (!cli_receive_trans(cli, SMBtrans2,
-               &rparam, &param_len,
-               &rdata, &data_len)) {
-                       return False;
+                       &rparam, &param_len,
+                       &rdata, &data_len)) {
+               return false;
        }
 
        SAFE_FREE(rdata);
        SAFE_FREE(rparam);
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  chmod a file (UNIX extensions).
 ****************************************************************************/
 
-BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
+bool cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
 {
-       return cli_unix_chmod_chown_internal(cli, fname, 
+       return cli_unix_chmod_chown_internal(cli, fname,
                unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
 }
 
@@ -373,23 +419,24 @@ BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
  chown a file (UNIX extensions).
 ****************************************************************************/
 
-BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
+bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
 {
-       return cli_unix_chmod_chown_internal(cli, fname, SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
+       return cli_unix_chmod_chown_internal(cli, fname,
+                       SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
 }
 
 /****************************************************************************
  Rename a file.
 ****************************************************************************/
 
-BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+bool cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,1, 0, True);
+       cli_set_message(cli->outbuf,1, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBmv);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -399,34 +446,38 @@ BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname_src,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
        *p++ = 4;
-       p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname_dst,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
        cli_send_smb(cli);
-       if (!cli_receive_smb(cli))
-               return False;
+       if (!cli_receive_smb(cli)) {
+               return false;
+       }
 
-       if (cli_is_error(cli))
-               return False;
+       if (cli_is_error(cli)) {
+               return false;
+       }
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  NT Rename a file.
 ****************************************************************************/
 
-BOOL cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+bool cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 4, 0, True);
+       cli_set_message(cli->outbuf, 4, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBntrename);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -437,34 +488,38 @@ BOOL cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fnam
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname_src,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
        *p++ = 4;
-       p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname_dst,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
        cli_send_smb(cli);
-       if (!cli_receive_smb(cli))
-               return False;
+       if (!cli_receive_smb(cli)) {
+               return false;
+       }
 
-       if (cli_is_error(cli))
-               return False;
+       if (cli_is_error(cli)) {
+               return false;
+       }
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  NT hardlink a file.
 ****************************************************************************/
 
-BOOL cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+bool cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 4, 0, True);
+       cli_set_message(cli->outbuf, 4, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBntrename);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -475,78 +530,93 @@ BOOL cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *f
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname_src,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
        *p++ = 4;
-       p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname_dst,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
        cli_send_smb(cli);
-       if (!cli_receive_smb(cli))
-               return False;
+       if (!cli_receive_smb(cli)) {
+               return false;
+       }
 
-       if (cli_is_error(cli))
-               return False;
+       if (cli_is_error(cli)) {
+               return false;
+       }
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  Delete a file.
 ****************************************************************************/
 
-BOOL cli_unlink(struct cli_state *cli, const char *fname)
+bool cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,1, 0,True);
+       cli_set_message(cli->outbuf,1, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBunlink);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
 
-       SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
-  
+       SSVAL(cli->outbuf,smb_vwv0, attrs);
+
        p = smb_buf(cli->outbuf);
-       *p++ = 4;      
-       p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+       *p++ = 4;
+       p += clistr_push(cli, p, fname,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
        cli_send_smb(cli);
        if (!cli_receive_smb(cli)) {
-               return False;
+               return false;
        }
 
        if (cli_is_error(cli)) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
+}
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+
+bool cli_unlink(struct cli_state *cli, const char *fname)
+{
+       return cli_unlink_full(cli, fname, aSYSTEM | aHIDDEN);
 }
 
 /****************************************************************************
  Create a directory.
 ****************************************************************************/
 
-BOOL cli_mkdir(struct cli_state *cli, const char *dname)
+bool cli_mkdir(struct cli_state *cli, const char *dname)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,0, 0,True);
+       cli_set_message(cli->outbuf,0, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBmkdir);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
 
        p = smb_buf(cli->outbuf);
-       *p++ = 4;      
-       p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+       *p++ = 4;
+       p += clistr_push(cli, p, dname,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
@@ -566,47 +636,48 @@ BOOL cli_mkdir(struct cli_state *cli, const char *dname)
  Remove a directory.
 ****************************************************************************/
 
-BOOL cli_rmdir(struct cli_state *cli, const char *dname)
+bool cli_rmdir(struct cli_state *cli, const char *dname)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,0, 0, True);
+       cli_set_message(cli->outbuf,0, 0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBrmdir);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
 
        p = smb_buf(cli->outbuf);
-       *p++ = 4;      
-       p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+       *p++ = 4;
+       p += clistr_push(cli, p, dname,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
        cli_send_smb(cli);
        if (!cli_receive_smb(cli)) {
-               return False;
+               return false;
        }
 
        if (cli_is_error(cli)) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
  Set or clear the delete on close flag.
 ****************************************************************************/
 
-int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
+int cli_nt_delete_on_close(struct cli_state *cli, int fnum, bool flag)
 {
        unsigned int data_len = 1;
        unsigned int param_len = 6;
        uint16 setup = TRANSACT2_SETFILEINFO;
-       pstring param;
+       char param[6];
        unsigned char data;
        char *rparam=NULL, *rdata=NULL;
 
@@ -617,25 +688,25 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
        data = flag ? 1 : 0;
 
        if (!cli_send_trans(cli, SMBtrans2,
-                                               NULL,                        /* name */
-                                               -1, 0,                          /* fid, flags */
-                                               &setup, 1, 0,                   /* setup, length, max */
-                                               param, param_len, 2,            /* param, length, max */
-                                               (char *)&data,  data_len, cli->max_xmit /* data, length, max */
-                                               )) {
-               return False;
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       (char *)&data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               return false;
        }
 
        if (!cli_receive_trans(cli, SMBtrans2,
-                                               &rparam, &param_len,
-                                               &rdata, &data_len)) {
-               return False;
+                       &rparam, &param_len,
+                       &rdata, &data_len)) {
+               return false;
        }
 
        SAFE_FREE(rdata);
        SAFE_FREE(rparam);
 
-       return True;
+       return true;
 }
 
 /****************************************************************************
@@ -643,11 +714,11 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
  Used in smbtorture.
 ****************************************************************************/
 
-int cli_nt_create_full(struct cli_state *cli, const char *fname, 
-                uint32 CreatFlags, uint32 DesiredAccess,
-                uint32 FileAttributes, uint32 ShareAccess,
-                uint32 CreateDisposition, uint32 CreateOptions,
-                uint8 SecuityFlags)
+int cli_nt_create_full(struct cli_state *cli, const char *fname,
+                      uint32 CreatFlags, uint32 DesiredAccess,
+                      uint32 FileAttributes, uint32 ShareAccess,
+                      uint32 CreateDisposition, uint32 CreateOptions,
+                      uint8 SecurityFlags)
 {
        char *p;
        int len;
@@ -655,7 +726,7 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,24,0,True);
+       cli_set_message(cli->outbuf,24,0, true);
 
        SCVAL(cli->outbuf,smb_com,SMBntcreateX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -664,7 +735,7 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname,
        SSVAL(cli->outbuf,smb_vwv0,0xFF);
        if (cli->use_oplocks)
                CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
-       
+
        SIVAL(cli->outbuf,smb_ntcreate_Flags, CreatFlags);
        SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
        SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess);
@@ -673,16 +744,18 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname,
        SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, CreateDisposition);
        SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, CreateOptions);
        SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
-       SCVAL(cli->outbuf,smb_ntcreate_SecurityFlags, SecuityFlags);
+       SCVAL(cli->outbuf,smb_ntcreate_SecurityFlags, SecurityFlags);
 
        p = smb_buf(cli->outbuf);
        /* this alignment and termination is critical for netapp filers. Don't change */
        p += clistr_align_out(cli, p, 0);
-       len = clistr_push(cli, p, fname, -1, 0);
+       len = clistr_push(cli, p, fname,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), 0);
        p += len;
        SSVAL(cli->outbuf,smb_ntcreate_NameLength, len);
        /* sigh. this copes with broken netapp filer behaviour */
-       p += clistr_push(cli, p, "", -1, STR_TERMINATE);
+       p += clistr_push(cli, p, "",
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
@@ -705,7 +778,57 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname,
 int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess)
 {
        return cli_nt_create_full(cli, fname, 0, DesiredAccess, 0,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_EXISTS_OPEN, 0x0, 0x0);
+                               FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0);
+}
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
+                           const char *str, size_t str_len,
+                           size_t *pconverted_size)
+{
+       size_t buflen;
+       char *converted;
+       size_t converted_size;
+
+       if (buf == NULL) {
+               return NULL;
+       }
+
+       buflen = talloc_get_size(buf);
+       /*
+        * We're pushing into an SMB buffer, align odd
+        */
+       if (ucs2 && (buflen % 2 == 0)) {
+               buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
+               if (buf == NULL) {
+                       return NULL;
+               }
+               buf[buflen] = '\0';
+               buflen += 1;
+       }
+
+       if (!convert_string_allocate(talloc_tos(), CH_UNIX,
+                                    ucs2 ? CH_UTF16LE : CH_DOS,
+                                    str, str_len, &converted,
+                                    &converted_size, true)) {
+               return NULL;
+       }
+
+       buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
+                                  buflen + converted_size);
+       if (buf == NULL) {
+               TALLOC_FREE(converted);
+               return NULL;
+       }
+
+       memcpy(buf + buflen, converted, converted_size);
+
+       TALLOC_FREE(converted);
+
+       if (pconverted_size) {
+               *pconverted_size = converted_size;
+       }
+
+       return buf;
 }
 
 /****************************************************************************
@@ -713,14 +836,20 @@ int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess
  WARNING: if you open with O_WRONLY then getattrE won't work!
 ****************************************************************************/
 
-int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
+struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+                               struct cli_state *cli,
+                               const char *fname, int flags, int share_mode)
 {
-       char *p;
-       unsigned openfn=0;
-       unsigned accessmode=0;
-
-       if (flags & O_CREAT)
+       unsigned openfn = 0;
+       unsigned accessmode = 0;
+       uint8_t additional_flags = 0;
+       uint8_t *bytes;
+       uint16_t vwv[15];
+       struct async_req *result;
+
+       if (flags & O_CREAT) {
                openfn |= (1<<4);
+       }
        if (!(flags & O_EXCL)) {
                if (flags & O_TRUNC)
                        openfn |= (1<<1);
@@ -734,7 +863,7 @@ int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode
                accessmode |= 2;
        } else if ((flags & O_ACCMODE) == O_WRONLY) {
                accessmode |= 1;
-       } 
+       }
 
 #if defined(O_SYNC)
        if ((flags & O_SYNC) == O_SYNC) {
@@ -746,80 +875,225 @@ int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode
                accessmode = 0xFF;
        }
 
-       memset(cli->outbuf,'\0',smb_size);
-       memset(cli->inbuf,'\0',smb_size);
-
-       set_message(cli->outbuf,15,0,True);
-
-       SCVAL(cli->outbuf,smb_com,SMBopenX);
-       SSVAL(cli->outbuf,smb_tid,cli->cnum);
-       cli_setup_packet(cli);
-
-       SSVAL(cli->outbuf,smb_vwv0,0xFF);
-       SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
-       SSVAL(cli->outbuf,smb_vwv3,accessmode);
-       SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
-       SSVAL(cli->outbuf,smb_vwv5,0);
-       SSVAL(cli->outbuf,smb_vwv8,openfn);
+       SCVAL(vwv + 0, 0, 0xFF);
+       SCVAL(vwv + 0, 1, 0);
+       SSVAL(vwv + 1, 0, 0);
+       SSVAL(vwv + 2, 0, 0);  /* no additional info */
+       SSVAL(vwv + 3, 0, accessmode);
+       SSVAL(vwv + 4, 0, aSYSTEM | aHIDDEN);
+       SSVAL(vwv + 5, 0, 0);
+       SIVAL(vwv + 6, 0, 0);
+       SSVAL(vwv + 8, 0, openfn);
+       SIVAL(vwv + 9, 0, 0);
+       SIVAL(vwv + 11, 0, 0);
+       SIVAL(vwv + 13, 0, 0);
 
        if (cli->use_oplocks) {
                /* if using oplocks then ask for a batch oplock via
                    core and extended methods */
-               SCVAL(cli->outbuf,smb_flg, CVAL(cli->outbuf,smb_flg)|
-                       FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK);
-               SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
+               additional_flags =
+                       FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
+               SSVAL(vwv+2, 0, SVAL(vwv+2, 0) | 6);
        }
-  
-       p = smb_buf(cli->outbuf);
-       p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
 
-       cli_setup_bcc(cli, p);
+       bytes = talloc_array(talloc_tos(), uint8_t, 0);
+       bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
+                                  strlen(fname)+1, NULL);
+       if (bytes == NULL) {
+               return NULL;
+       }
 
-       cli_send_smb(cli);
-       if (!cli_receive_smb(cli)) {
-               return -1;
+       result = cli_request_send(mem_ctx, ev, cli, SMBopenX, additional_flags,
+                                 15, vwv, 0, talloc_get_size(bytes), bytes);
+       TALLOC_FREE(bytes);
+       return result;
+}
+
+NTSTATUS cli_open_recv(struct async_req *req, int *fnum)
+{
+       uint8_t wct;
+       uint16_t *vwv;
+       uint16_t num_bytes;
+       uint8_t *bytes;
+       NTSTATUS status;
+
+       if (async_req_is_error(req, &status)) {
+               return status;
        }
 
-       if (cli_is_error(cli)) {
-               return -1;
+       status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (wct < 3) {
+               return NT_STATUS_INVALID_NETWORK_RESPONSE;
+       }
+
+       *fnum = SVAL(vwv+2, 0);
+
+       return NT_STATUS_OK;
+}
+
+int cli_open(struct cli_state *cli, const char *fname, int flags,
+            int share_mode)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct async_req *req;
+       int result = -1;
+
+       if (cli->fd_event != NULL) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+               goto fail;
        }
 
-       return SVAL(cli->inbuf,smb_vwv2);
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+
+       req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
+       if (req == NULL) {
+               goto fail;
+       }
+
+       while (req->state < ASYNC_REQ_DONE) {
+               event_loop_once(ev);
+       }
+
+       cli_open_recv(req, &result);
+ fail:
+       TALLOC_FREE(frame);
+       return result;
 }
 
 /****************************************************************************
  Close a file.
 ****************************************************************************/
 
-BOOL cli_close(struct cli_state *cli, int fnum)
+struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+                                struct cli_state *cli, int fnum)
 {
-       memset(cli->outbuf,'\0',smb_size);
-       memset(cli->inbuf,'\0',smb_size);
+       uint16_t vwv[3];
 
-       set_message(cli->outbuf,3,0,True);
+       SSVAL(vwv+0, 0, fnum);
+       SIVALS(vwv+1, 0, -1);
 
-       SCVAL(cli->outbuf,smb_com,SMBclose);
-       SSVAL(cli->outbuf,smb_tid,cli->cnum);
-       cli_setup_packet(cli);
+       return cli_request_send(mem_ctx, ev, cli, SMBclose, 0, 3, vwv, 0,
+                               0, NULL);
+}
 
-       SSVAL(cli->outbuf,smb_vwv0,fnum);
-       SIVALS(cli->outbuf,smb_vwv1,-1);
+NTSTATUS cli_close_recv(struct async_req *req)
+{
+       uint8_t wct;
+       uint16_t *vwv;
+       uint16_t num_bytes;
+       uint8_t *bytes;
+       NTSTATUS status;
 
-       cli_send_smb(cli);
-       if (!cli_receive_smb(cli)) {
+       if (async_req_is_error(req, &status)) {
+               return status;
+       }
+
+       return cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+}
+
+bool cli_close(struct cli_state *cli, int fnum)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct event_context *ev;
+       struct async_req *req;
+       bool result = false;
+
+       if (cli->fd_event != NULL) {
+               /*
+                * Can't use sync call while an async call is in flight
+                */
+               cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+               goto fail;
+       }
+
+       ev = event_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+
+       req = cli_close_send(frame, ev, cli, fnum);
+       if (req == NULL) {
+               goto fail;
+       }
+
+       while (req->state < ASYNC_REQ_DONE) {
+               event_loop_once(ev);
+       }
+
+       result = NT_STATUS_IS_OK(cli_close_recv(req));
+ fail:
+       TALLOC_FREE(frame);
+       return result;
+}
+
+/****************************************************************************
+ Truncate a file to a specified size
+****************************************************************************/
+
+bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size)
+{
+       unsigned int param_len = 6;
+       unsigned int data_len = 8;
+       uint16 setup = TRANSACT2_SETFILEINFO;
+       char param[6];
+       unsigned char data[8];
+       char *rparam=NULL, *rdata=NULL;
+       int saved_timeout = cli->timeout;
+
+       SSVAL(param,0,fnum);
+       SSVAL(param,2,SMB_SET_FILE_END_OF_FILE_INFO);
+       SSVAL(param,4,0);
+
+        SBVAL(data, 0, size);
+
+       if (!cli_send_trans(cli, SMBtrans2,
+                            NULL,                    /* name */
+                            -1, 0,                   /* fid, flags */
+                            &setup, 1, 0,            /* setup, length, max */
+                            param, param_len, 2,     /* param, length, max */
+                            (char *)&data,  data_len,/* data, length, ... */
+                            cli->max_xmit)) {        /* ... max */
+               cli->timeout = saved_timeout;
+               return False;
+       }
+
+       if (!cli_receive_trans(cli, SMBtrans2,
+                               &rparam, &param_len,
+                               &rdata, &data_len)) {
+               cli->timeout = saved_timeout;
+               SAFE_FREE(rdata);
+               SAFE_FREE(rparam);
                return False;
        }
 
-       return !cli_is_error(cli);
+       cli->timeout = saved_timeout;
+
+       SAFE_FREE(rdata);
+       SAFE_FREE(rparam);
+
+       return True;
 }
 
 
 /****************************************************************************
- send a lock with a specified locktype 
+ send a lock with a specified locktype
  this is used for testing LOCKING_ANDX_CANCEL_LOCK
 ****************************************************************************/
-NTSTATUS cli_locktype(struct cli_state *cli, int fnum, 
-                     uint32 offset, uint32 len, int timeout, unsigned char locktype)
+
+NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
+                     uint32 offset, uint32 len,
+                     int timeout, unsigned char locktype)
 {
        char *p;
        int saved_timeout = cli->timeout;
@@ -827,7 +1101,7 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0', smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -865,12 +1139,12 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
        return cli_nt_error(cli);
 }
 
-
 /****************************************************************************
  Lock a file.
  note that timeout is in units of 2 milliseconds
 ****************************************************************************/
-BOOL cli_lock(struct cli_state *cli, int fnum, 
+
+bool cli_lock(struct cli_state *cli, int fnum,
              uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
 {
        char *p;
@@ -879,7 +1153,7 @@ BOOL cli_lock(struct cli_state *cli, int fnum,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0', smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -925,14 +1199,14 @@ BOOL cli_lock(struct cli_state *cli, int fnum,
  Unlock a file.
 ****************************************************************************/
 
-BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
+bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -967,8 +1241,8 @@ BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
  Lock a file with 64 bit offsets.
 ****************************************************************************/
 
-BOOL cli_lock64(struct cli_state *cli, int fnum, 
-               SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type)
+bool cli_lock64(struct cli_state *cli, int fnum,
+               uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
 {
        char *p;
         int saved_timeout = cli->timeout;
@@ -984,7 +1258,7 @@ BOOL cli_lock64(struct cli_state *cli, int fnum,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0', smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1028,7 +1302,7 @@ BOOL cli_lock64(struct cli_state *cli, int fnum,
  Unlock a file with 64 bit offsets.
 ****************************************************************************/
 
-BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+bool cli_unlock64(struct cli_state *cli, int fnum, uint64_t offset, uint64_t len)
 {
        char *p;
 
@@ -1039,7 +1313,7 @@ BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBlockingX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1070,19 +1344,123 @@ BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_
        return True;
 }
 
+/****************************************************************************
+ Get/unlock a POSIX lock on a file - internal function.
+****************************************************************************/
+
+static bool cli_posix_lock_internal(struct cli_state *cli, int fnum,
+               uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type)
+{
+       unsigned int param_len = 4;
+       unsigned int data_len = POSIX_LOCK_DATA_SIZE;
+       uint16 setup = TRANSACT2_SETFILEINFO;
+       char param[4];
+       unsigned char data[POSIX_LOCK_DATA_SIZE];
+       char *rparam=NULL, *rdata=NULL;
+       int saved_timeout = cli->timeout;
+
+       SSVAL(param,0,fnum);
+       SSVAL(param,2,SMB_SET_POSIX_LOCK);
+
+       switch (lock_type) {
+               case READ_LOCK:
+                       SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
+                       break;
+               case WRITE_LOCK:
+                       SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
+                       break;
+               case UNLOCK_LOCK:
+                       SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+                       break;
+               default:
+                       return False;
+       }
+
+       if (wait_lock) {
+               SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
+               cli->timeout = 0x7FFFFFFF;
+       } else {
+               SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
+       }
+
+       SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
+       SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
+       SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
+
+       if (!cli_send_trans(cli, SMBtrans2,
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       (char *)&data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               cli->timeout = saved_timeout;
+               return False;
+       }
+
+       if (!cli_receive_trans(cli, SMBtrans2,
+                               &rparam, &param_len,
+                               &rdata, &data_len)) {
+               cli->timeout = saved_timeout;
+               SAFE_FREE(rdata);
+               SAFE_FREE(rparam);
+               return False;
+       }
+
+       cli->timeout = saved_timeout;
+
+       SAFE_FREE(rdata);
+       SAFE_FREE(rparam);
+
+       return True;
+}
+
+/****************************************************************************
+ POSIX Lock a file.
+****************************************************************************/
+
+bool cli_posix_lock(struct cli_state *cli, int fnum,
+                       uint64_t offset, uint64_t len,
+                       bool wait_lock, enum brl_type lock_type)
+{
+       if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
+               return False;
+       }
+       return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
+}
+
+/****************************************************************************
+ POSIX Unlock a file.
+****************************************************************************/
+
+bool cli_posix_unlock(struct cli_state *cli, int fnum, uint64_t offset, uint64_t len)
+{
+       return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
+}
+
+/****************************************************************************
+ POSIX Get any lock covering a file.
+****************************************************************************/
+
+bool cli_posix_getlock(struct cli_state *cli, int fnum, uint64_t *poffset, uint64_t *plen)
+{
+       return True;
+}
 
 /****************************************************************************
  Do a SMBgetattrE call.
 ****************************************************************************/
 
-BOOL cli_getattrE(struct cli_state *cli, int fd, 
-                 uint16 *attr, SMB_OFF_T *size, 
-                 time_t *c_time, time_t *a_time, time_t *m_time)
+bool cli_getattrE(struct cli_state *cli, int fd,
+                 uint16 *attr, SMB_OFF_T *size,
+                 time_t *change_time,
+                  time_t *access_time,
+                  time_t *write_time)
 {
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,1,0,True);
+       cli_set_message(cli->outbuf,1,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBgetattrE);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1094,7 +1472,7 @@ BOOL cli_getattrE(struct cli_state *cli, int fd,
        if (!cli_receive_smb(cli)) {
                return False;
        }
-       
+
        if (cli_is_error(cli)) {
                return False;
        }
@@ -1107,16 +1485,16 @@ BOOL cli_getattrE(struct cli_state *cli, int fd,
                *attr = SVAL(cli->inbuf,smb_vwv10);
        }
 
-       if (c_time) {
-               *c_time = make_unix_date2(cli->inbuf+smb_vwv0);
+       if (change_time) {
+               *change_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv0);
        }
 
-       if (a_time) {
-               *a_time = make_unix_date2(cli->inbuf+smb_vwv2);
+       if (access_time) {
+               *access_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv2);
        }
 
-       if (m_time) {
-               *m_time = make_unix_date2(cli->inbuf+smb_vwv4);
+       if (write_time) {
+               *write_time = cli_make_unix_date2(cli, cli->inbuf+smb_vwv4);
        }
 
        return True;
@@ -1126,15 +1504,15 @@ BOOL cli_getattrE(struct cli_state *cli, int fd,
  Do a SMBgetatr call
 ****************************************************************************/
 
-BOOL cli_getatr(struct cli_state *cli, const char *fname, 
-               uint16 *attr, SMB_OFF_T *size, time_t *t)
+bool cli_getatr(struct cli_state *cli, const char *fname,
+               uint16 *attr, SMB_OFF_T *size, time_t *write_time)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBgetatr);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1142,7 +1520,8 @@ BOOL cli_getatr(struct cli_state *cli, const char *fname,
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
@@ -1150,7 +1529,7 @@ BOOL cli_getatr(struct cli_state *cli, const char *fname,
        if (!cli_receive_smb(cli)) {
                return False;
        }
-       
+
        if (cli_is_error(cli)) {
                return False;
        }
@@ -1159,15 +1538,14 @@ BOOL cli_getatr(struct cli_state *cli, const char *fname,
                *size = IVAL(cli->inbuf, smb_vwv3);
        }
 
-       if (t) {
-               *t = make_unix_date3(cli->inbuf+smb_vwv1);
+       if (write_time) {
+               *write_time = cli_make_unix_date3(cli, cli->inbuf+smb_vwv1);
        }
 
        if (attr) {
                *attr = SVAL(cli->inbuf,smb_vwv0);
        }
 
-
        return True;
 }
 
@@ -1175,8 +1553,10 @@ BOOL cli_getatr(struct cli_state *cli, const char *fname,
  Do a SMBsetattrE call.
 ****************************************************************************/
 
-BOOL cli_setattrE(struct cli_state *cli, int fd,
-                 time_t c_time, time_t a_time, time_t m_time)
+bool cli_setattrE(struct cli_state *cli, int fd,
+                 time_t change_time,
+                  time_t access_time,
+                  time_t write_time)
 
 {
        char *p;
@@ -1184,16 +1564,16 @@ BOOL cli_setattrE(struct cli_state *cli, int fd,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,7,0,True);
+       cli_set_message(cli->outbuf,7,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBsetattrE);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
 
        SSVAL(cli->outbuf,smb_vwv0, fd);
-       put_dos_date2(cli->outbuf,smb_vwv1, c_time);
-       put_dos_date2(cli->outbuf,smb_vwv3, a_time);
-       put_dos_date2(cli->outbuf,smb_vwv5, m_time);
+       cli_put_dos_date2(cli, cli->outbuf,smb_vwv1, change_time);
+       cli_put_dos_date2(cli, cli->outbuf,smb_vwv3, access_time);
+       cli_put_dos_date2(cli, cli->outbuf,smb_vwv5, write_time);
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
@@ -1204,7 +1584,7 @@ BOOL cli_setattrE(struct cli_state *cli, int fd,
        if (!cli_receive_smb(cli)) {
                return False;
        }
-       
+
        if (cli_is_error(cli)) {
                return False;
        }
@@ -1216,25 +1596,26 @@ BOOL cli_setattrE(struct cli_state *cli, int fd,
  Do a SMBsetatr call.
 ****************************************************************************/
 
-BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
+bool cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
 {
        char *p;
 
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,8,0,True);
+       cli_set_message(cli->outbuf,8,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBsetatr);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
 
        SSVAL(cli->outbuf,smb_vwv0, attr);
-       put_dos_date3(cli->outbuf,smb_vwv1, t);
+       cli_put_dos_date3(cli, cli->outbuf,smb_vwv1, t);
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, fname,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
        *p++ = 4;
 
        cli_setup_bcc(cli, p);
@@ -1243,7 +1624,7 @@ BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
        if (!cli_receive_smb(cli)) {
                return False;
        }
-       
+
        if (cli_is_error(cli)) {
                return False;
        }
@@ -1254,32 +1635,47 @@ BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
 /****************************************************************************
  Check for existance of a dir.
 ****************************************************************************/
-BOOL cli_chkpath(struct cli_state *cli, const char *path)
+
+bool cli_chkpath(struct cli_state *cli, const char *path)
 {
-       pstring path2;
+       char *path2 = NULL;
        char *p;
-       
-       pstrcpy(path2,path);
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       path2 = talloc_strdup(frame, path);
+       if (!path2) {
+               TALLOC_FREE(frame);
+               return false;
+       }
        trim_char(path2,'\0','\\');
-       if (!*path2)
-               *path2 = '\\';
-       
+       if (!*path2) {
+               path2 = talloc_strdup(frame, "\\");
+               if (!path2) {
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+       }
+
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
-       SCVAL(cli->outbuf,smb_com,SMBchkpth);
+       cli_set_message(cli->outbuf,0,0,True);
+       SCVAL(cli->outbuf,smb_com,SMBcheckpath);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, path2, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, path2,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
        cli_send_smb(cli);
        if (!cli_receive_smb(cli)) {
+               TALLOC_FREE(frame);
                return False;
        }
 
+       TALLOC_FREE(frame);
+
        if (cli_is_error(cli)) return False;
 
        return True;
@@ -1289,10 +1685,10 @@ BOOL cli_chkpath(struct cli_state *cli, const char *path)
  Query disk space.
 ****************************************************************************/
 
-BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+bool cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
 {
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
+       cli_set_message(cli->outbuf,0,0,True);
        SCVAL(cli->outbuf,smb_com,SMBdskattr);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -1305,7 +1701,7 @@ BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
        *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
        *total = SVAL(cli->inbuf,smb_vwv0);
        *avail = SVAL(cli->inbuf,smb_vwv3);
-       
+
        return True;
 }
 
@@ -1321,7 +1717,7 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,3,0,True);
+       cli_set_message(cli->outbuf,3,0,True);
 
        SCVAL(cli->outbuf,smb_com,SMBctemp);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -1332,7 +1728,8 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
 
        p = smb_buf(cli->outbuf);
        *p++ = 4;
-       p += clistr_push(cli, p, path, -1, STR_TERMINATE);
+       p += clistr_push(cli, p, path,
+                       cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
 
        cli_setup_bcc(cli, p);
 
@@ -1350,20 +1747,22 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
        p = smb_buf(cli->inbuf);
        p += 4;
        len = smb_buflen(cli->inbuf) - 4;
-       if (len <= 0) return -1;
+       if (len <= 0 || len > PATH_MAX) return -1;
 
        if (tmp_path) {
-               pstring path2;
-               clistr_pull(cli, path2, p, 
-                           sizeof(path2), len, STR_ASCII);
-               *tmp_path = SMB_STRDUP(path2);
+               char *path2 = SMB_MALLOC_ARRAY(char, len+1);
+               if (!path2) {
+                       return -1;
+               }
+               clistr_pull(cli->inbuf, path2, p,
+                           len+1, len, STR_ASCII);
+               *tmp_path = path2;
        }
 
        return SVAL(cli->inbuf,smb_vwv0);
 }
 
-
-/* 
+/*
    send a raw ioctl - used by the torture code
 */
 NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *blob)
@@ -1371,7 +1770,7 @@ NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 3, 0, True);
+       cli_set_message(cli->outbuf, 3, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBioctl);
        cli_setup_packet(cli);
 
@@ -1388,7 +1787,7 @@ NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *
                return cli_nt_error(cli);
        }
 
-       *blob = data_blob(NULL, 0);
+       *blob = data_blob_null;
 
        return NT_STATUS_OK;
 }
@@ -1397,43 +1796,55 @@ NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *
  Set an extended attribute utility fn.
 *********************************************************/
 
-static BOOL cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigned int param_len,
+static bool cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigned int param_len,
                        const char *ea_name, const char *ea_val, size_t ea_len)
-{      
+{
        unsigned int data_len = 0;
        char *data = NULL;
        char *rparam=NULL, *rdata=NULL;
        char *p;
        size_t ea_namelen = strlen(ea_name);
 
-       data_len = 4 + 4 + ea_namelen + 1 + ea_len;
-       data = SMB_MALLOC(data_len);
-       if (!data) {
-               return False;
+       if (ea_namelen == 0 && ea_len == 0) {
+               data_len = 4;
+               data = (char *)SMB_MALLOC(data_len);
+               if (!data) {
+                       return False;
+               }
+               p = data;
+               SIVAL(p,0,data_len);
+       } else {
+               data_len = 4 + 4 + ea_namelen + 1 + ea_len;
+               data = (char *)SMB_MALLOC(data_len);
+               if (!data) {
+                       return False;
+               }
+               p = data;
+               SIVAL(p,0,data_len);
+               p += 4;
+               SCVAL(p, 0, 0); /* EA flags. */
+               SCVAL(p, 1, ea_namelen);
+               SSVAL(p, 2, ea_len);
+               memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
+               memcpy(p+4+ea_namelen+1, ea_val, ea_len);
        }
-       p = data;
-       SIVAL(p,0,data_len);
-       p += 4;
-       SCVAL(p, 0, 0); /* EA flags. */
-       SCVAL(p, 1, ea_namelen);
-       SSVAL(p, 2, ea_len);
-       memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
-       memcpy(p+4+ea_namelen+1, ea_val, ea_len);
 
        if (!cli_send_trans(cli, SMBtrans2,
-               NULL,                        /* name */
-               -1, 0,                          /* fid, flags */
-               &setup, 1, 0,                   /* setup, length, max */
-               param, param_len, 2,            /* param, length, max */
-               data,  data_len, cli->max_xmit /* data, length, max */
-               )) {
-                       return False;
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               SAFE_FREE(data);
+               return False;
        }
 
        if (!cli_receive_trans(cli, SMBtrans2,
-               &rparam, &param_len,
-               &rdata, &data_len)) {
-                       return False;
+                       &rparam, &param_len,
+                       &rdata, &data_len)) {
+                       SAFE_FREE(data);
+               return false;
        }
 
        SAFE_FREE(data);
@@ -1447,29 +1858,36 @@ static BOOL cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigne
  Set an extended attribute on a pathname.
 *********************************************************/
 
-BOOL cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
+bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
 {
        uint16 setup = TRANSACT2_SETPATHINFO;
        unsigned int param_len = 0;
-       char param[sizeof(pstring)+6];
+       char *param;
        size_t srclen = 2*(strlen(path)+1);
        char *p;
+       bool ret;
 
-       memset(param, 0, sizeof(param));
+       param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+       if (!param) {
+               return false;
+       }
+       memset(param, '\0', 6);
        SSVAL(param,0,SMB_INFO_SET_EA);
        p = &param[6];
 
-       p += clistr_push(cli, p, path, MIN(srclen, sizeof(param)-6), STR_TERMINATE);
+       p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
-       return cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
+       ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
+       SAFE_FREE(param);
+       return ret;
 }
 
 /*********************************************************
  Set an extended attribute on an fnum.
 *********************************************************/
 
-BOOL cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const char *ea_val, size_t ea_len)
+bool cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const char *ea_val, size_t ea_len)
 {
        char param[6];
        uint16 setup = TRANSACT2_SETFILEINFO;
@@ -1482,10 +1900,10 @@ BOOL cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const
 }
 
 /*********************************************************
- Get an extended attribute list tility fn.
+ Get an extended attribute list utility fn.
 *********************************************************/
 
-static BOOL cli_get_ea_list(struct cli_state *cli,
+static bool cli_get_ea_list(struct cli_state *cli,
                uint16 setup, char *param, unsigned int param_len,
                TALLOC_CTX *ctx,
                size_t *pnum_eas,
@@ -1497,11 +1915,13 @@ static BOOL cli_get_ea_list(struct cli_state *cli,
        char *p;
        size_t ea_size;
        size_t num_eas;
-       BOOL ret = False;
+       bool ret = False;
        struct ea_struct *ea_list;
 
        *pnum_eas = 0;
-       *pea_list = NULL;
+       if (pea_list) {
+               *pea_list = NULL;
+       }
 
        if (!cli_send_trans(cli, SMBtrans2,
                        NULL,           /* Name */
@@ -1608,31 +2028,39 @@ static BOOL cli_get_ea_list(struct cli_state *cli,
  Get an extended attribute list from a pathname.
 *********************************************************/
 
-BOOL cli_get_ea_list_path(struct cli_state *cli, const char *path,
+bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
                TALLOC_CTX *ctx,
                size_t *pnum_eas,
                struct ea_struct **pea_list)
 {
        uint16 setup = TRANSACT2_QPATHINFO;
        unsigned int param_len = 0;
-       char param[sizeof(pstring)+6];
+       char *param;
        char *p;
+       size_t srclen = 2*(strlen(path)+1);
+       bool ret;
 
+       param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+       if (!param) {
+               return false;
+       }
        p = param;
        memset(p, 0, 6);
        SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
        p += 6;
-       p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
+       p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
-       return cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
+       ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
+       SAFE_FREE(param);
+       return ret;
 }
 
 /*********************************************************
  Get an extended attribute list from an fnum.
 *********************************************************/
 
-BOOL cli_get_ea_list_fnum(struct cli_state *cli, int fnum,
+bool cli_get_ea_list_fnum(struct cli_state *cli, int fnum,
                TALLOC_CTX *ctx,
                size_t *pnum_eas,
                struct ea_struct **pea_list)
@@ -1646,3 +2074,216 @@ BOOL cli_get_ea_list_fnum(struct cli_state *cli, int fnum,
 
        return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
 }
+
+/****************************************************************************
+ Convert open "flags" arg to uint32 on wire.
+****************************************************************************/
+
+static uint32 open_flags_to_wire(int flags)
+{
+       int open_mode = flags & O_ACCMODE;
+       uint32 ret = 0;
+
+       switch (open_mode) {
+               case O_WRONLY:
+                       ret |= SMB_O_WRONLY;
+                       break;
+               case O_RDWR:
+                       ret |= SMB_O_RDWR;
+                       break;
+               default:
+               case O_RDONLY:
+                       ret |= SMB_O_RDONLY;
+                       break;
+       }
+
+       if (flags & O_CREAT) {
+               ret |= SMB_O_CREAT;
+       }
+       if (flags & O_EXCL) {
+               ret |= SMB_O_EXCL;
+       }
+       if (flags & O_TRUNC) {
+               ret |= SMB_O_TRUNC;
+       }
+#if defined(O_SYNC)
+       if (flags & O_SYNC) {
+               ret |= SMB_O_SYNC;
+       }
+#endif /* O_SYNC */
+       if (flags & O_APPEND) {
+               ret |= SMB_O_APPEND;
+       }
+#if defined(O_DIRECT)
+       if (flags & O_DIRECT) {
+               ret |= SMB_O_DIRECT;
+       }
+#endif
+#if defined(O_DIRECTORY)
+       if (flags & O_DIRECTORY) {
+               ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+               ret |= SMB_O_DIRECTORY;
+       }
+#endif
+       return ret;
+}
+
+/****************************************************************************
+ Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
+****************************************************************************/
+
+static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int flags, mode_t mode, bool is_dir)
+{
+       unsigned int data_len = 0;
+       unsigned int param_len = 0;
+       uint16 setup = TRANSACT2_SETPATHINFO;
+       char *param;
+       char data[18];
+       char *rparam=NULL, *rdata=NULL;
+       char *p;
+       int fnum = -1;
+       uint32 wire_flags = open_flags_to_wire(flags);
+       size_t srclen = 2*(strlen(fname)+1);
+
+       param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+       if (!param) {
+               return false;
+       }
+       memset(param, '\0', 6);
+       SSVAL(param,0, SMB_POSIX_PATH_OPEN);
+       p = &param[6];
+
+       p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
+       param_len = PTR_DIFF(p, param);
+
+       if (is_dir) {
+               wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+               wire_flags |= SMB_O_DIRECTORY;
+       }
+
+       p = data;
+       SIVAL(p,0,0); /* No oplock. */
+       SIVAL(p,4,wire_flags);
+       SIVAL(p,8,unix_perms_to_wire(mode));
+       SIVAL(p,12,0); /* Top bits of perms currently undefined. */
+       SSVAL(p,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
+
+       data_len = 18;
+
+       if (!cli_send_trans(cli, SMBtrans2,
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       (char *)&data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               SAFE_FREE(param);
+               return -1;
+       }
+
+       SAFE_FREE(param);
+
+       if (!cli_receive_trans(cli, SMBtrans2,
+               &rparam, &param_len,
+               &rdata, &data_len)) {
+                       return -1;
+       }
+
+       fnum = SVAL(rdata,2);
+
+       SAFE_FREE(rdata);
+       SAFE_FREE(rparam);
+
+       return fnum;
+}
+
+/****************************************************************************
+ open - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode)
+{
+       return cli_posix_open_internal(cli, fname, flags, mode, False);
+}
+
+/****************************************************************************
+ mkdir - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
+{
+       return (cli_posix_open_internal(cli, fname, O_CREAT, mode, True) == -1) ? -1 : 0;
+}
+
+/****************************************************************************
+ unlink or rmdir - POSIX semantics.
+****************************************************************************/
+
+static bool cli_posix_unlink_internal(struct cli_state *cli, const char *fname, bool is_dir)
+{
+       unsigned int data_len = 0;
+       unsigned int param_len = 0;
+       uint16 setup = TRANSACT2_SETPATHINFO;
+       char *param;
+       char data[2];
+       char *rparam=NULL, *rdata=NULL;
+       char *p;
+       size_t srclen = 2*(strlen(fname)+1);
+
+       param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+       if (!param) {
+               return false;
+       }
+       memset(param, '\0', 6);
+       SSVAL(param,0, SMB_POSIX_PATH_UNLINK);
+       p = &param[6];
+
+       p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
+       param_len = PTR_DIFF(p, param);
+
+       SSVAL(data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
+                       SMB_POSIX_UNLINK_FILE_TARGET);
+       data_len = 2;
+
+       if (!cli_send_trans(cli, SMBtrans2,
+                       NULL,                        /* name */
+                       -1, 0,                          /* fid, flags */
+                       &setup, 1, 0,                   /* setup, length, max */
+                       param, param_len, 2,            /* param, length, max */
+                       (char *)&data,  data_len, cli->max_xmit /* data, length, max */
+                       )) {
+               SAFE_FREE(param);
+               return False;
+       }
+
+       SAFE_FREE(param);
+
+       if (!cli_receive_trans(cli, SMBtrans2,
+               &rparam, &param_len,
+               &rdata, &data_len)) {
+                       return False;
+       }
+
+       SAFE_FREE(rdata);
+       SAFE_FREE(rparam);
+
+       return True;
+}
+
+/****************************************************************************
+ unlink - POSIX semantics.
+****************************************************************************/
+
+bool cli_posix_unlink(struct cli_state *cli, const char *fname)
+{
+       return cli_posix_unlink_internal(cli, fname, False);
+}
+
+/****************************************************************************
+ rmdir - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_rmdir(struct cli_state *cli, const char *fname)
+{
+       return cli_posix_unlink_internal(cli, fname, True);
+}