Removed version number from file header.
[kai/samba.git] / source3 / smbd / reply.c
index a401be1357e70b63e6b800eb43ff6743fa1a8101..c7f805122db4d1d2db24d3b3ea1875c2544a457b 100644 (file)
@@ -1,9 +1,9 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    Main SMB reply routines
    Copyright (C) Andrew Tridgell 1992-1998
-   
+   Copyright (C) Andrew Bartlett      2001
+
    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
 
 /* look in server.c for some explanation of these variables */
 extern int Protocol;
-extern int DEBUGLEVEL;
 extern int max_send;
 extern int max_recv;
 extern char magic_char;
 extern BOOL case_sensitive;
 extern BOOL case_preserve;
 extern BOOL short_case_preserve;
-extern userdom_struct current_user_info;
 extern pstring global_myname;
-extern fstring global_myworkgroup;
 extern int global_oplock_break;
-uint32 global_client_caps = 0;
 unsigned int smb_echo_count = 0;
 
-/****************************************************************************
-report a possible attack via the password buffer overflow bug
-****************************************************************************/
-
-static void overflow_attack(int len)
-{
-       if( DEBUGLVL( 0 ) ) {
-               dbgtext( "ERROR: Invalid password length %d.\n", len );
-               dbgtext( "Your machine may be under attack by someone " );
-               dbgtext( "attempting to exploit an old bug.\n" );
-               dbgtext( "Attack was from IP = %s.\n", client_addr() );
-       }
-       exit_server("possible attack");
-}
+extern fstring remote_machine;
+extern BOOL global_encrypted_passwords_negotiated;
 
 
 /****************************************************************************
@@ -68,7 +52,7 @@ int reply_special(char *inbuf,char *outbuf)
        int msg_type = CVAL(inbuf,0);
        int msg_flags = CVAL(inbuf,1);
        pstring name1,name2;
-       extern fstring remote_machine;
+
        extern fstring local_machine;
        int len;
        char name_type = 0;
@@ -81,8 +65,8 @@ int reply_special(char *inbuf,char *outbuf)
        
        switch (msg_type) {
        case 0x81: /* session request */
-               CVAL(outbuf,0) = 0x82;
-               CVAL(outbuf,3) = 0;
+               SCVAL(outbuf,0,0x82);
+               SCVAL(outbuf,3,0);
                if (name_len(inbuf+4) > 50 || 
                    name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
                        DEBUG(0,("Invalid name length in session request\n"));
@@ -97,6 +81,7 @@ int reply_special(char *inbuf,char *outbuf)
                remote_machine[15] = 0;
                trim_string(remote_machine," "," ");
                strlower(remote_machine);
+               alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
 
                fstrcpy(local_machine,name1);
                len = strlen(local_machine);
@@ -106,11 +91,15 @@ int reply_special(char *inbuf,char *outbuf)
                }
                trim_string(local_machine," "," ");
                strlower(local_machine);
+               alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
+
+               DEBUG(2,("netbios connect: local=%s remote=%s\n",
+                       local_machine, remote_machine ));
 
                if (name_type == 'R') {
                        /* We are being asked for a pathworks session --- 
                           no thanks! */
-                       CVAL(outbuf, 0) = 0x83;
+                       SCVAL(outbuf, 0,0x83);
                        break;
                }
 
@@ -124,16 +113,14 @@ int reply_special(char *inbuf,char *outbuf)
                reload_services(True);
                reopen_logs();
 
-               if (lp_status(-1)) {
-                       claim_connection(NULL,"",MAXSTATUS,True);
-               }
+               claim_connection(NULL,"",MAXSTATUS,True);
 
                break;
                
        case 0x89: /* session keepalive request 
                      (some old clients produce this?) */
-               CVAL(outbuf,0) = 0x85;
-               CVAL(outbuf,3) = 0;
+               SCVAL(outbuf,0,SMBkeepalive);
+               SCVAL(outbuf,3,0);
                break;
                
        case 0x82: /* positive session response */
@@ -142,7 +129,7 @@ int reply_special(char *inbuf,char *outbuf)
                DEBUG(0,("Unexpected session response\n"));
                break;
                
-       case 0x85: /* session keepalive */
+       case SMBkeepalive: /* session keepalive */
        default:
                return(0);
        }
@@ -154,54 +141,6 @@ int reply_special(char *inbuf,char *outbuf)
 }
 
 
-/*******************************************************************
-work out what error to give to a failed connection
-********************************************************************/
-
-static int connection_error(char *inbuf,char *outbuf,int ecode)
-{
-       if (ecode == ERRnoipc || ecode == ERRnosuchshare)
-               return(ERROR(ERRDOS,ecode));
-
-       return(ERROR(ERRSRV,ecode));
-}
-
-
-
-/****************************************************************************
-  parse a share descriptor string
-****************************************************************************/
-static void parse_connect(char *p,char *service,char *user,
-                         char *password,int *pwlen,char *dev)
-{
-  char *p2;
-
-  DEBUG(4,("parsing connect string %s\n",p));
-    
-  p2 = strrchr(p,'\\');
-  if (p2 == NULL)
-    fstrcpy(service,p);
-  else
-    fstrcpy(service,p2+1);
-  
-  p += strlen(p) + 2;
-  
-  fstrcpy(password,p);
-  *pwlen = strlen(password);
-
-  p += strlen(p) + 2;
-
-  fstrcpy(dev,p);
-  
-  *user = 0;
-  p = strchr(service,'%');
-  if (p != NULL)
-    {
-      *p = 0;
-      fstrcpy(user,p+1);
-    }
-}
-
 /****************************************************************************
  Reply to a tcon.
 ****************************************************************************/
@@ -209,46 +148,40 @@ static void parse_connect(char *p,char *service,char *user,
 int reply_tcon(connection_struct *conn,
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       BOOL doencrypt = SMBENCRYPT();
        pstring service;
-       pstring user;
        pstring password;
        pstring dev;
        int outsize = 0;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int pwlen=0;
-       int ecode = -1;
+       NTSTATUS nt_status;
+       char *p;
+       DATA_BLOB password_blob;
+       
        START_PROFILE(SMBtcon);
 
-       *service = *user = *password = *dev = 0;
+       *service = *password = *dev = 0;
 
-       parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
-
-    /*
-     * Ensure the user and password names are in UNIX codepage format.
-     */
+       p = smb_buf(inbuf)+1;
+       p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
+       pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
+       p += pwlen;
+       p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
 
-    dos_to_unix(user,True);
-       if (!doencrypt)
-       dos_to_unix(password,True);
+       p = strrchr_m(service,'\\');
+       if (p) {
+               pstrcpy(service, p+1);
+       }
 
-       /*
-        * Pass the user through the NT -> unix user mapping
-        * function.
-        */
-   
-       (void)map_username(user);
+       password_blob = data_blob(password, pwlen+1);
 
-       /*
-        * Do any UNIX username case mangling.
-        */
-       (void)Get_Pwnam( user, True);
+       conn = make_connection(service,password_blob,dev,vuid,&nt_status);
 
-       conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
+       data_blob_clear_free(&password_blob);
   
        if (!conn) {
                END_PROFILE(SMBtcon);
-               return(connection_error(inbuf,outbuf,ecode));
+               return ERROR_NT(nt_status);
        }
   
        outsize = set_message(outbuf,2,0,True);
@@ -256,8 +189,8 @@ int reply_tcon(connection_struct *conn,
        SSVAL(outbuf,smb_vwv1,conn->cnum);
        SSVAL(outbuf,smb_tid,conn->cnum);
   
-       DEBUG(3,("tcon service=%s user=%s cnum=%d\n", 
-                service, user, conn->cnum));
+       DEBUG(3,("tcon service=%s cnum=%d\n", 
+                service, conn->cnum));
   
        END_PROFILE(SMBtcon);
        return(outsize);
@@ -266,20 +199,21 @@ int reply_tcon(connection_struct *conn,
 /****************************************************************************
  Reply to a tcon and X.
 ****************************************************************************/
+
 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
        fstring service;
-       pstring user;
-       pstring password;
+       DATA_BLOB password;
        pstring devicename;
-       int ecode = -1;
+       NTSTATUS nt_status;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
        pstring path;
        char *p, *q;
-       START_PROFILE(SMBtconX);
-       
-       *service = *user = *password = *devicename = 0;
+       extern BOOL global_encrypted_passwords_negotiated;
+       START_PROFILE(SMBtconX);        
+
+       *service = *devicename = 0;
 
        /* we might have to close an old one */
        if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
@@ -287,59 +221,53 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
        if (passlen > MAX_PASS_LEN) {
-               overflow_attack(passlen);
+               return ERROR_DOS(ERRDOS,ERRbuftoosmall);
        }
  
-       memcpy(password,smb_buf(inbuf),passlen);
-       password[passlen]=0;    
+       if (global_encrypted_passwords_negotiated) {
+               password = data_blob(smb_buf(inbuf),passlen);
+       } else {
+               password = data_blob(smb_buf(inbuf),passlen+1);
+               /* Ensure correct termination */
+               password.data[passlen]=0;    
+       }
+
        p = smb_buf(inbuf) + passlen;
-       p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE|STR_CONVERT);
+       p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
 
-       if (passlen != 24) {
-               if (strequal(password," "))
-                       *password = 0;
-               passlen = strlen(password);
-       }
-       
-       q = strchr(path+2,'\\');
-       if (!q) {
-               END_PROFILE(SMBtconX);
-               return(ERROR(ERRDOS,ERRnosuchshare));
-       }
-       fstrcpy(service,q+1);
-       q = strchr(service,'%');
-       if (q) {
-               *q++ = 0;
-               fstrcpy(user,q);
+       /*
+        * the service name can be either: \\server\share
+        * or share directly like on the DELL PowerVault 705
+        */
+       if (*path=='\\') {      
+               q = strchr_m(path+2,'\\');
+               if (!q) {
+                       END_PROFILE(SMBtconX);
+                       return(ERROR_DOS(ERRDOS,ERRnosuchshare));
+               }
+               fstrcpy(service,q+1);
        }
-       p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_CONVERT|STR_ASCII);
+       else
+               fstrcpy(service,path);
+               
+       p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_ASCII);
 
        DEBUG(4,("Got device type %s\n",devicename));
 
-       /*
-        * Pass the user through the NT -> unix user mapping
-        * function.
-        */
-       
-       (void)map_username(user);
-       
-       /*
-        * Do any UNIX username case mangling.
-        */
-       (void)Get_Pwnam(user, True);
-       
-       conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
+       conn = make_connection(service,password,devicename,vuid,&nt_status);
        
+       data_blob_clear_free(&password);
+
        if (!conn) {
                END_PROFILE(SMBtconX);
-               return(connection_error(inbuf,outbuf,ecode));
+               return ERROR_NT(nt_status);
        }
 
        if (Protocol < PROTOCOL_NT1) {
                set_message(outbuf,2,0,True);
                p = smb_buf(outbuf);
-               p += srvstr_push(inbuf, outbuf, p, devicename, -1, 
-                                STR_CONVERT|STR_TERMINATE|STR_ASCII);
+               p += srvstr_push(outbuf, p, devicename, -1, 
+                                STR_TERMINATE|STR_ASCII);
                set_message_end(outbuf,p);
        } else {
                /* NT sets the fstype of IPC$ to the null string */
@@ -348,10 +276,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                set_message(outbuf,3,0,True);
 
                p = smb_buf(outbuf);
-               p += srvstr_push(inbuf, outbuf, p, devicename, -1, 
-                                STR_CONVERT|STR_TERMINATE|STR_ASCII);
-               p += srvstr_push(inbuf, outbuf, p, fsname, -1, 
-                                STR_CONVERT|STR_TERMINATE);
+               p += srvstr_push(outbuf, p, devicename, -1, 
+                                STR_TERMINATE|STR_ASCII);
+               p += srvstr_push(outbuf, p, fsname, -1, 
+                                STR_TERMINATE);
                
                set_message_end(outbuf,p);
                
@@ -363,8 +291,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
   
-       DEBUG(3,("tconX service=%s user=%s\n",
-                service, user));
+       DEBUG(3,("tconX service=%s \n",
+                service));
   
        /* set the incoming and outgoing tid to the just created one */
        SSVAL(inbuf,smb_tid,conn->cnum);
@@ -386,7 +314,7 @@ int reply_unknown(char *inbuf,char *outbuf)
        DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
                 smb_fn_name(type), type, type));
   
-       return(ERROR(ERRSRV,ERRunknownsmb));
+       return(ERROR_DOS(ERRSRV,ERRunknownsmb));
 }
 
 
@@ -413,7 +341,7 @@ int reply_ioctl(connection_struct *conn,
                break;
            default:
                END_PROFILE(SMBioctl);
-               return(ERROR(ERRSRV,ERRnosupport));
+               return(ERROR_DOS(ERRSRV,ERRnosupport));
        }
 
        outsize = set_message(outbuf,8,replysize+1,True);
@@ -426,8 +354,8 @@ int reply_ioctl(connection_struct *conn,
        {
            case IOCTL_QUERY_JOB_INFO:              
                SSVAL(p,0,fsp->print_jobid);             /* Job number */
-               StrnCpy(p+2, global_myname, 15);         /* Our NetBIOS name */
-               StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
+               srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII);
+               srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII);
                break;
        }
 
@@ -436,839 +364,183 @@ int reply_ioctl(connection_struct *conn,
 }
 
 /****************************************************************************
- always return an error: it's just a matter of which one...
- ****************************************************************************/
-static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
-                                char *smb_passwd, int smb_passlen,
-                                char *smb_nt_passwd, int smb_nt_passlen)
+  reply to a chkpth
+****************************************************************************/
+int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  /* check if trust account exists */
-  SAM_ACCOUNT  *sam_trust_acct = NULL; 
-  uint16       acct_ctrl;
-
-  if (lp_security() == SEC_USER) {
-    sam_trust_acct = pdb_getsampwnam(user);
-  } else {
-    DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
-    SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-    return(ERROR(0, NT_STATUS_LOGON_FAILURE));
-  }
+  int outsize = 0;
+  int mode;
+  pstring name;
+  BOOL ok = False;
+  BOOL bad_path = False;
+  SMB_STRUCT_STAT sbuf;
+  START_PROFILE(SMBchkpth);
 
-  if (sam_trust_acct == NULL) {
-    /* lkclXXXX: workstation entry doesn't exist */
-    DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
-    SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-    return(ERROR(0, NT_STATUS_NO_SUCH_USER));
-  } else {
-    if ((smb_passlen != 24) || (smb_nt_passlen != 24)) {
-      DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
-      SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-      return(ERROR(0, NT_STATUS_LOGON_FAILURE));
-    }
+  srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
 
-    if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) {
-      DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
-      SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-      return(ERROR(0, NT_STATUS_LOGON_FAILURE));
-    }
+  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
 
-    acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct);
-    if (acct_ctrl & ACB_DOMTRUST) {
-      DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
-      SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-      return(ERROR(0, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT));
-    }
+  unix_convert(name,conn,0,&bad_path,&sbuf);
 
-    if (acct_ctrl & ACB_SVRTRUST) {
-      DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
-      SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-      return(ERROR(0, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT));
-    }
+  mode = SVAL(inbuf,smb_vwv0);
 
-    if (acct_ctrl & ACB_WSTRUST) {
-      DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
-      SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-      return(ERROR(0, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT));
-    }
+  if (check_name(name,conn)) {
+    if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0)
+      ok = S_ISDIR(sbuf.st_mode);
   }
 
-  /* don't know what to do: indicate logon failure */
-  SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-  return(ERROR(0, NT_STATUS_LOGON_FAILURE));
-}
+  if (!ok) {
+    /* We special case this - as when a Windows machine
+       is parsing a path is steps through the components
+       one at a time - if a component fails it expects
+       ERRbadpath, not ERRbadfile.
+     */
+    if(errno == ENOENT) {
+           return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+    }
 
-/****************************************************************************
- Create a UNIX user on demand.
-****************************************************************************/
+    return(UNIXERROR(ERRDOS,ERRbadpath));
+  }
 
-int smb_create_user(char *unix_user, char *homedir)
-{
-  pstring add_script;
-  int ret;
-
-  pstrcpy(add_script, lp_adduser_script());
-  if (! *add_script) return -1;
-  all_string_sub(add_script, "%u", unix_user, sizeof(pstring));
-  if (homedir)
-    all_string_sub(add_script, "%H", homedir, sizeof(pstring));
-  ret = smbrun(add_script,NULL,False);
-  DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
-  return ret;
-}
+  outsize = set_message(outbuf,0,0,True);
 
-/****************************************************************************
- Delete a UNIX user on demand.
-****************************************************************************/
+  DEBUG(3,("chkpth %s mode=%d\n", name, mode));
 
-static int smb_delete_user(char *unix_user)
-{
-  pstring del_script;
-  int ret;
-
-  pstrcpy(del_script, lp_deluser_script());
-  if (! *del_script) return -1;
-  all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
-  ret = smbrun(del_script,NULL,False);
-  DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
-  return ret;
+  END_PROFILE(SMBchkpth);
+  return(outsize);
 }
 
-/****************************************************************************
- Check user is in correct domain if required
-****************************************************************************/
-
-static BOOL check_domain_match(char *user, char *domain) 
-{
-  /*
-   * If we aren't serving to trusted domains, we must make sure that
-   * the validation request comes from an account in the same domain
-   * as the Samba server
-   */
-
-  if (!lp_allow_trusted_domains() &&
-      !strequal(lp_workgroup(), domain) ) {
-      DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
-      return False;
-  } else {
-      return True;
-  }
-}
 
 /****************************************************************************
- Check for a valid username and password in security=server mode.
+  reply to a getatr
 ****************************************************************************/
-
-static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
-                                  char *smb_apasswd, int smb_apasslen,
-                                  char *smb_ntpasswd, int smb_ntpasslen)
+int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  BOOL ret = False;
-
-  if(lp_security() != SEC_SERVER)
-    return False;
-
-  if (!check_domain_match(orig_user, domain))
-     return False;
+  pstring fname;
+  int outsize = 0;
+  SMB_STRUCT_STAT sbuf;
+  BOOL ok = False;
+  int mode=0;
+  SMB_OFF_T size=0;
+  time_t mtime=0;
+  BOOL bad_path = False;
+  char *p;
+  START_PROFILE(SMBgetatr);
 
-  ret = server_validate(orig_user, domain, 
-                            smb_apasswd, smb_apasslen, 
-                            smb_ntpasswd, smb_ntpasslen);
-  if(ret) {
-    struct passwd *pwd;
+  p = smb_buf(inbuf) + 1;
+  p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
 
-    /*
-     * User validated ok against Domain controller.
-     * If the admin wants us to try and create a UNIX
-     * user on the fly, do so.
-     * Note that we can never delete users when in server
-     * level security as we never know if it was a failure
-     * due to a bad password, or the user really doesn't exist.
-     */
-    if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) {
-      smb_create_user(unix_user, NULL);
+  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+  
+  /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
+     under WfWg - weird! */
+  if (! (*fname))
+  {
+    mode = aHIDDEN | aDIR;
+    if (!CAN_WRITE(conn)) mode |= aRONLY;
+    size = 0;
+    mtime = 0;
+    ok = True;
+  }
+  else
+  {
+    unix_convert(fname,conn,0,&bad_path,&sbuf);
+    if (check_name(fname,conn))
+    {
+      if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
+      {
+        mode = dos_mode(conn,fname,&sbuf);
+        size = sbuf.st_size;
+        mtime = sbuf.st_mtime;
+        if (mode & aDIR)
+          size = 0;
+        ok = True;
+      }
+      else
+        DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+    }
+  }
+  
+  if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
     }
 
-    if(lp_adduser_script() && pwd) {
-      SMB_STRUCT_STAT st;
+    END_PROFILE(SMBgetatr);
+    return(UNIXERROR(ERRDOS,ERRbadfile));
+  }
+  outsize = set_message(outbuf,10,0,True);
 
-      /*
-       * Also call smb_create_user if the users home directory
-       * doesn't exist. Used with winbindd to allow the script to
-       * create the home directory for a user mapped with winbindd.
-       */
+  SSVAL(outbuf,smb_vwv0,mode);
+  if(lp_dos_filetime_resolution(SNUM(conn)) )
+    put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
+  else
+    put_dos_date3(outbuf,smb_vwv1,mtime);
+  SIVAL(outbuf,smb_vwv3,(uint32)size);
 
-      if (pwd->pw_shell && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
-        smb_create_user(unix_user, pwd->pw_dir);
-    }
+  if (Protocol >= PROTOCOL_NT1) {
+         SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
   }
-
-  return ret;
+  
+  DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
+  
+  END_PROFILE(SMBgetatr);
+  return(outsize);
 }
 
+
 /****************************************************************************
- Check for a valid username and password in security=domain mode.
+  reply to a setatr
 ****************************************************************************/
-
-static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user, 
-                                  char *smb_apasswd, int smb_apasslen,
-                                  char *smb_ntpasswd, int smb_ntpasslen)
+int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  BOOL ret = False;
-  BOOL user_exists = True;
-  struct passwd *pwd;
-
-  if(lp_security() != SEC_DOMAIN)
-    return False;
-
-  if (!check_domain_match(orig_user, domain))
-     return False;
-
-  ret = domain_client_validate(orig_user, domain,
-                                smb_apasswd, smb_apasslen,
-                                smb_ntpasswd, smb_ntpasslen,
-                                &user_exists);
-
-  if(ret) {
-    /*
-     * User validated ok against Domain controller.
-     * If the admin wants us to try and create a UNIX
-     * user on the fly, do so.
-     */
-    if(user_exists && lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True))) {
-      smb_create_user(unix_user, NULL);
-    }
+  pstring fname;
+  int outsize = 0;
+  BOOL ok=False;
+  int mode;
+  time_t mtime;
+  SMB_STRUCT_STAT sbuf;
+  BOOL bad_path = False;
+  char *p;
 
-    if(lp_adduser_script() && pwd) {
-      SMB_STRUCT_STAT st;
+  START_PROFILE(SMBsetatr);
 
-      /*
-       * Also call smb_create_user if the users home directory
-       * doesn't exist. Used with winbindd to allow the script to
-       * create the home directory for a user mapped with winbindd.
-       */
+  p = smb_buf(inbuf) + 1;
+  p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+  unix_convert(fname,conn,0,&bad_path,&sbuf);
 
-      if (pwd->pw_shell && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
-        smb_create_user(unix_user, pwd->pw_dir);
+  mode = SVAL(inbuf,smb_vwv0);
+  mtime = make_unix_date3(inbuf+smb_vwv1);
+  
+  if (VALID_STAT_OF_DIR(sbuf))
+    mode |= aDIR;
+  if (check_name(fname,conn))
+    ok =  (file_chmod(conn,fname,mode,NULL) == 0);
+  if (ok)
+    ok = set_filetime(conn,fname,mtime);
+  
+  if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
     }
 
-  } else {
-    /*
-     * User failed to validate ok against Domain controller.
-     * If the failure was "user doesn't exist" and admin 
-     * wants us to try and delete that UNIX user on the fly,
-     * do so.
-     */
-    if(!user_exists && lp_deluser_script() && smb_getpwnam(unix_user,True)) {
-      smb_delete_user(unix_user);
-    }
+    END_PROFILE(SMBsetatr);
+    return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
-
-  return ret;
-}
-
-/****************************************************************************
- Return a bad password error configured for the correct client type.
-****************************************************************************/       
-
-static int bad_password_error(char *inbuf,char *outbuf)
-{
-  enum remote_arch_types ra_type = get_remote_arch();
-
-  if(((ra_type == RA_WINNT) || (ra_type == RA_WIN2K)) &&
-      (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32 ))) {
-    SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-    return(ERROR(0,NT_STATUS_LOGON_FAILURE));
-  }
-
-  return(ERROR(ERRSRV,ERRbadpw));
-}
-
-/****************************************************************************
-reply to a session setup command
-****************************************************************************/
-
-int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
-  uint16 sess_vuid;
-  gid_t gid;
-  uid_t uid;
-  int   smb_bufsize;    
-  int   smb_apasslen = 0;   
-  pstring smb_apasswd;
-  int   smb_ntpasslen = 0;   
-  pstring smb_ntpasswd;
-  BOOL valid_nt_password = False;
-  BOOL valid_lm_password = False;
-  pstring user;
-  pstring orig_user;
-  fstring domain;
-  fstring native_os;
-  fstring native_lanman;
-  BOOL guest=False;
-  static BOOL done_sesssetup = False;
-  BOOL doencrypt = SMBENCRYPT();
-  START_PROFILE(SMBsesssetupX);
-
-  *smb_apasswd = 0;
-  *smb_ntpasswd = 0;
-  
-  smb_bufsize = SVAL(inbuf,smb_vwv2);
-
-  if (Protocol < PROTOCOL_NT1) {
-    smb_apasslen = SVAL(inbuf,smb_vwv7);
-    if (smb_apasslen > MAX_PASS_LEN)
-      overflow_attack(smb_apasslen);
-
-    memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
-    smb_apasswd[smb_apasslen] = 0;
-    pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
-    /*
-     * Incoming user is in DOS codepage format. Convert
-     * to UNIX.
-     */
-    dos_to_unix(user,True);
-  
-    if (!doencrypt && (lp_security() != SEC_SERVER)) {
-      smb_apasslen = strlen(smb_apasswd);
-    }
-  } else {
-    uint16 passlen1 = SVAL(inbuf,smb_vwv7);
-    uint16 passlen2 = SVAL(inbuf,smb_vwv8);
-    enum remote_arch_types ra_type = get_remote_arch();
-    char *p = smb_buf(inbuf);    
-
-    if(global_client_caps == 0)
-      global_client_caps = IVAL(inbuf,smb_vwv11);
-
-    /* client_caps is used as final determination if client is NT or Win95. 
-       This is needed to return the correct error codes in some
-       circumstances.
-     */
-    
-    if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
-      if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
-        set_remote_arch( RA_WIN95);
-      }
-    }
-
-    if (passlen1 != 24 && passlen2 != 24)
-      doencrypt = False;
-
-    if (passlen1 > MAX_PASS_LEN) {
-      overflow_attack(passlen1);
-    }
-
-    passlen1 = MIN(passlen1, MAX_PASS_LEN);
-    passlen2 = MIN(passlen2, MAX_PASS_LEN);
-
-    if(!doencrypt) {
-       /* both Win95 and WinNT stuff up the password lengths for
-          non-encrypting systems. Uggh. 
-      
-          if passlen1==24 its a win95 system, and its setting the
-          password length incorrectly. Luckily it still works with the
-          default code because Win95 will null terminate the password
-          anyway 
-
-          if passlen1>0 and passlen2>0 then maybe its a NT box and its
-          setting passlen2 to some random value which really stuffs
-          things up. we need to fix that one.  */
-
-      if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
-        passlen2 = 0;
-    }
-
-    if (lp_restrict_anonymous()) {
-      /* there seems to be no reason behind the differences in MS clients formatting
-       * various info like the domain, NativeOS, and NativeLanMan fields. Win95
-       * in particular seems to have an extra null byte between the username and the
-       * domain, or the password length calculation is wrong, which throws off the
-       * string extraction routines below.  This makes the value of domain be the
-       * empty string, which fails the restrict anonymous check further down.
-       * This compensates for that, and allows browsing to work in mixed NT and
-       * win95 environments even when restrict anonymous is true. AAB
-       */
-      dump_data(100, p, 0x70);
-      DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
-      if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
-        DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
-        DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
-        DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
-        passlen1 = 1;
-      }
-    }
-
-    if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
-      /* Save the lanman2 password and the NT md4 password. */
-      smb_apasslen = passlen1;
-      memcpy(smb_apasswd,p,smb_apasslen);
-      smb_apasswd[smb_apasslen] = 0;
-      smb_ntpasslen = passlen2;
-      memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
-      smb_ntpasswd[smb_ntpasslen] = 0;
-
-      /*
-       * Ensure the plaintext passwords are in UNIX format.
-       */
-      if(!doencrypt) {
-        dos_to_unix(smb_apasswd,True);
-        dos_to_unix(smb_ntpasswd,True);
-      }
-
-    } else {
-      /* we use the first password that they gave */
-      smb_apasslen = passlen1;
-      StrnCpy(smb_apasswd,p,smb_apasslen);      
-      /*
-       * Ensure the plaintext password is in UNIX format.
-       */
-      dos_to_unix(smb_apasswd,True);
-      
-      /* trim the password */
-      smb_apasslen = strlen(smb_apasswd);
-
-      /* wfwg sometimes uses a space instead of a null */
-      if (strequal(smb_apasswd," ")) {
-        smb_apasslen = 0;
-        *smb_apasswd = 0;
-      }
-    }
-    
-    p += passlen1 + passlen2;
-    p += srvstr_pull(inbuf, user, p, sizeof(user), -1, STR_CONVERT|STR_TERMINATE);
-    /*
-     * Incoming user and domain are in DOS codepage format. Convert
-     * to UNIX.
-     */
-    p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
-                    -1, STR_CONVERT|STR_TERMINATE);
-    p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
-                    -1, STR_CONVERT|STR_TERMINATE);
-    p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
-                    -1, STR_CONVERT|STR_TERMINATE);
-    DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            domain,native_os,native_lanman));
-  }
-
-  DEBUG(3,("sesssetupX:name=[%s]\n",user));
-
-  /* If name ends in $ then I think it's asking about whether a */
-  /* computer with that name (minus the $) has access. For now */
-  /* say yes to everything ending in $. */
-
-  if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
-    END_PROFILE(SMBsesssetupX);
-    return session_trust_account(conn, inbuf, outbuf, user, 
-                                 smb_apasswd, smb_apasslen,
-                                 smb_ntpasswd, smb_ntpasslen);
-  }
-
-  if (done_sesssetup && lp_restrict_anonymous()) {
-    /* tests show that even if browsing is done over already validated connections
-     * without a username and password the domain is still provided, which it
-     * wouldn't be if it was a purely anonymous connection.  So, in order to
-     * restrict anonymous, we only deny connections that have no session
-     * information.  If a domain has been provided, then it's not a purely
-     * anonymous connection. AAB
-     */
-    if (!*user && !*smb_apasswd && !*domain) {
-      DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
-      END_PROFILE(SMBsesssetupX);
-      return(ERROR(ERRDOS,ERRnoaccess));
-    }
-  }
-
-  /* If no username is sent use the guest account */
-  if (!*user) {
-    pstrcpy(user,lp_guestaccount(-1));
-    /* If no user and no password then set guest flag. */
-    if( *smb_apasswd == 0)
-      guest = True;
-  }
-
-  pstrcpy(current_user_info.smb_name,user);
-
-  reload_services(True);
-
-  /*
-   * Save the username before mapping. We will use
-   * the original username sent to us for security=server
-   * and security=domain checking.
-   */
-
-  pstrcpy( orig_user, user);
-
-  /* if the username exists as a domain/username pair on the unix system then use 
-     that */
-  if (!sys_getpwnam(user)) {
-         pstring user2;
-
-         slprintf(user2,sizeof(user2),"%s%s%s", dos_to_unix(domain,False), 
-                  lp_winbind_separator(), user);
-
-         if (sys_getpwnam(user2)) {
-                 DEBUG(3,("Using unix username %s\n", user2));
-                 pstrcpy(user, user2);
-         }
-  }
-
-  /*
-   * Pass the user through the NT -> unix user mapping
-   * function.
-   */
-   
-  (void)map_username(user);
-
-  /*
-   * Do any UNIX username case mangling.
-   */
-  smb_getpwnam(user, True);
-
-  add_session_user(user);
-
-  /*
-   * Check if the given username was the guest user with no password.
-   */
-
-  if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
-    guest = True;
-
-  /* 
-   * Check with orig_user for security=server and
-   * security=domain.
-   */
-
-  if (!guest && !check_server_security(orig_user, domain, user, 
-         smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
-      !check_domain_security(orig_user, domain, user, smb_apasswd,
-         smb_apasslen, smb_ntpasswd, smb_ntpasslen) &&
-      !check_hosts_equiv(user))
-  {
-
-    /* 
-     * If we get here then the user wasn't guest and the remote
-     * authentication methods failed. Check the authentication
-     * methods on this local server.
-     *
-     * If an NT password was supplied try and validate with that
-     * first. This is superior as the passwords are mixed case 
-     * 128 length unicode.
-      */
-
-    if(smb_ntpasslen)
-    {
-      if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
-        DEBUG(2,("NT Password did not match for user '%s'!\n", user));
-      else
-        valid_nt_password = True;
-    } 
-    
-    
-    /* check the LanMan password only if necessary and if allowed 
-       by lp_lanman_auth() */
-    if (!valid_nt_password && lp_lanman_auth())
-    {
-      DEBUG(2,("Defaulting to Lanman password for %s\n", user));
-      valid_lm_password = password_ok(user, smb_apasswd,smb_apasslen,NULL);
-    }
-      
-
-    /* The true branch will be executed if 
-       (1) the NT password failed (or was not tried), and 
-       (2) LanMan authentication failed (or was disabled) 
-     */
-    if (!valid_nt_password && !valid_lm_password)
-    {
-      if (lp_security() >= SEC_USER) 
-      {
-        if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
-        {
-          DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
-                 END_PROFILE(SMBsesssetupX);
-          return bad_password_error(inbuf,outbuf);
-        }
-
-        if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
-        {
-          if (smb_getpwnam(user,True))
-          {
-            DEBUG(1,("Rejecting user '%s': bad password\n", user));
-               END_PROFILE(SMBsesssetupX);
-            return bad_password_error(inbuf,outbuf);
-          }
-        }
-
-        /*
-         * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
-         * Then always map to guest account - as done below.
-         */
-      }
-
-      if (*smb_apasswd || !smb_getpwnam(user,True))
-         pstrcpy(user,lp_guestaccount(-1));
-      DEBUG(3,("Registered username %s for guest access\n",user));
-      guest = True;
-    }
-  }
-
-  if (!smb_getpwnam(user,True)) {
-    DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
-    pstrcpy(user,lp_guestaccount(-1));
-    guest = True;
-  }
-
-  if (!strequal(user,lp_guestaccount(-1)) &&
-      lp_servicenumber(user) < 0)      
-  {
-       add_home_service(user,get_user_home_dir(user));
-  }
-
-
-  /* it's ok - setup a reply */
-  if (Protocol < PROTOCOL_NT1) {
-    set_message(outbuf,3,0,True);
-  } else {
-    char *p;
-    set_message(outbuf,3,0,True);
-    p = smb_buf(outbuf);
-    p += srvstr_push(inbuf, outbuf, p, "Unix", -1, STR_TERMINATE|STR_CONVERT);
-    p += srvstr_push(inbuf, outbuf, p, "Samba", -1, STR_TERMINATE|STR_CONVERT);
-    p += srvstr_push(inbuf, outbuf, p, global_myworkgroup, -1, STR_TERMINATE|STR_CONVERT);
-    set_message_end(outbuf,p);
-    /* perhaps grab OS version here?? */
-  }
-
-  /* Set the correct uid in the outgoing and incoming packets
-     We will use this on future requests to determine which
-     user we should become.
-     */
-  {
-    const struct passwd *pw = smb_getpwnam(user,False);
-    if (!pw) {
-      DEBUG(1,("Username %s is invalid on this system\n",user));
-      END_PROFILE(SMBsesssetupX);
-      return bad_password_error(inbuf,outbuf);
-    }
-    gid = pw->pw_gid;
-    uid = pw->pw_uid;
-  }
-
-  if (guest)
-    SSVAL(outbuf,smb_vwv2,1);
-
-  /* register the name and uid as being validated, so further connections
-     to a uid can get through without a password, on the same VC */
-
-  sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest);
-  SSVAL(outbuf,smb_uid,sess_vuid);
-  SSVAL(inbuf,smb_uid,sess_vuid);
-
-  if (!done_sesssetup)
-    max_send = MIN(max_send,smb_bufsize);
-
-  DEBUG(6,("Client requested max send size of %d\n", max_send));
-
-  done_sesssetup = True;
-
-  END_PROFILE(SMBsesssetupX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
-}
-
-
-/****************************************************************************
-  reply to a chkpth
-****************************************************************************/
-int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
-  int outsize = 0;
-  int mode;
-  pstring name;
-  BOOL ok = False;
-  BOOL bad_path = False;
-  SMB_STRUCT_STAT sbuf;
-  START_PROFILE(SMBchkpth);
-
-  srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
-
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-
-  unix_convert(name,conn,0,&bad_path,&sbuf);
-
-  mode = SVAL(inbuf,smb_vwv0);
-
-  if (check_name(name,conn)) {
-    if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0)
-      ok = S_ISDIR(sbuf.st_mode);
-  }
-
-  if (!ok)
-  {
-    /* We special case this - as when a Windows machine
-       is parsing a path is steps through the components
-       one at a time - if a component fails it expects
-       ERRbadpath, not ERRbadfile.
-     */
-    if(errno == ENOENT)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-
-#if 0
-    /* Ugly - NT specific hack - maybe not needed ? (JRA) */
-    if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
-       (get_remote_arch() == RA_WINNT))
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbaddirectory;
-    }
-#endif
-
-    return(UNIXERROR(ERRDOS,ERRbadpath));
-  }
-
-  outsize = set_message(outbuf,0,0,True);
-
-  DEBUG(3,("chkpth %s mode=%d\n", name, mode));
-
-  END_PROFILE(SMBchkpth);
-  return(outsize);
-}
-
-
-/****************************************************************************
-  reply to a getatr
-****************************************************************************/
-int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
-  pstring fname;
-  int outsize = 0;
-  SMB_STRUCT_STAT sbuf;
-  BOOL ok = False;
-  int mode=0;
-  SMB_OFF_T size=0;
-  time_t mtime=0;
-  BOOL bad_path = False;
-  char *p;
-  START_PROFILE(SMBgetatr);
-
-  p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
-
-  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
-  
-  /* if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && dfs_redirect(fname,conn)) return(dfs_path_error(inbuf,outbuf)); 
-   */
-  /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
-     under WfWg - weird! */
-  if (! (*fname))
-  {
-    mode = aHIDDEN | aDIR;
-    if (!CAN_WRITE(conn)) mode |= aRONLY;
-    size = 0;
-    mtime = 0;
-    ok = True;
-  }
-  else
-  {
-    unix_convert(fname,conn,0,&bad_path,&sbuf);
-    if (check_name(fname,conn))
-    {
-      if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
-      {
-        mode = dos_mode(conn,fname,&sbuf);
-        size = sbuf.st_size;
-        mtime = sbuf.st_mtime;
-        if (mode & aDIR)
-          size = 0;
-        ok = True;
-      }
-      else
-        DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
-    }
-  }
-  
-  if (!ok)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-
-    END_PROFILE(SMBgetatr);
-    return(UNIXERROR(ERRDOS,ERRbadfile));
-  }
-  outsize = set_message(outbuf,10,0,True);
-
-  SSVAL(outbuf,smb_vwv0,mode);
-  if(lp_dos_filetime_resolution(SNUM(conn)) )
-    put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
-  else
-    put_dos_date3(outbuf,smb_vwv1,mtime);
-  SIVAL(outbuf,smb_vwv3,(uint32)size);
-
-  if (Protocol >= PROTOCOL_NT1) {
-         SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
-  }
-  
-  DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
-  
-  END_PROFILE(SMBgetatr);
-  return(outsize);
-}
-
-
-/****************************************************************************
-  reply to a setatr
-****************************************************************************/
-int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
-  pstring fname;
-  int outsize = 0;
-  BOOL ok=False;
-  int mode;
-  time_t mtime;
-  SMB_STRUCT_STAT sbuf;
-  BOOL bad_path = False;
-  char *p;
-
-  START_PROFILE(SMBsetatr);
-
-  p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
-  unix_convert(fname,conn,0,&bad_path,&sbuf);
-
-  mode = SVAL(inbuf,smb_vwv0);
-  mtime = make_unix_date3(inbuf+smb_vwv1);
-  
-  if (VALID_STAT_OF_DIR(sbuf))
-    mode |= aDIR;
-  if (check_name(fname,conn))
-    ok =  (file_chmod(conn,fname,mode,NULL) == 0);
-  if (ok)
-    ok = set_filetime(conn,fname,mtime);
-  
-  if (!ok)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-
-    END_PROFILE(SMBsetatr);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-  outsize = set_message(outbuf,0,0,True);
-  
-  DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
-  
-  END_PROFILE(SMBsetatr);
-  return(outsize);
+  outsize = set_message(outbuf,0,0,True);
+  
+  DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
+  
+  END_PROFILE(SMBsetatr);
+  return(outsize);
 }
 
 
@@ -1318,7 +590,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   char *p;
   BOOL ok = False;
   int status_len;
-  char *path;
+  pstring path;
   char status[21];
   int dptr_num= -1;
   BOOL check_descend = False;
@@ -1336,9 +608,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   outsize = set_message(outbuf,1,3,True);
   maxentries = SVAL(inbuf,smb_vwv0); 
   dirtype = SVAL(inbuf,smb_vwv1);
-  path = smb_buf(inbuf) + 1;
-  status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
-
+  p = smb_buf(inbuf) + 1;
+  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+  p++;
+  status_len = SVAL(p, 0);
+  p += 2;
   
   /* dirtype &= ~aDIR; */
   
@@ -1347,15 +621,15 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     SMB_STRUCT_STAT sbuf;
     pstring dir2;
 
-    pstrcpy(directory,smb_buf(inbuf)+1);
-    pstrcpy(dir2,smb_buf(inbuf)+1);
+    pstrcpy(directory,path);
+    pstrcpy(dir2,path);
     unix_convert(directory,conn,0,&bad_path,&sbuf);
     unix_format(dir2);
 
     if (!check_name(directory,conn))
       can_open = False;
 
-    p = strrchr(dir2,'/');
+    p = strrchr_m(dir2,'/');
     if (p == NULL) 
     {
       pstrcpy(mask,dir2);
@@ -1367,7 +641,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
       pstrcpy(mask,p+1);
     }
 
-    p = strrchr(directory,'/');
+    p = strrchr_m(directory,'/');
     if (!p) 
       *directory = 0;
     else
@@ -1376,11 +650,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     if (strlen(directory) == 0)
       pstrcpy(directory,"./");
     memset((char *)status,'\0',21);
-    CVAL(status,0) = dirtype;
+    SCVAL(status,0,dirtype);
   }
   else
   {
-    memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+    memcpy(status,p,21);
     dirtype = CVAL(status,0) & 0x1F;
     conn->dirptr = dptr_fetch(status+12,&dptr_num);      
     if (!conn->dirptr)
@@ -1411,7 +685,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
           return (UNIXERROR(ERRDOS,ERRnofids));
         }
                END_PROFILE(SMBsearch);
-        return(ERROR(ERRDOS,ERRnofids));
+        return ERROR_DOS(ERRDOS,ERRnofids);
       }
       dptr_set_wcard(dptr_num, strdup(mask));
     }
@@ -1460,7 +734,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   if (numentries == 0 || !ok)
   {
-    CVAL(outbuf,smb_rcls) = ERRDOS;
+    SCVAL(outbuf,smb_rcls,ERRDOS);
     SSVAL(outbuf,smb_err,ERRnofiles);
     dptr_close(&dptr_num);
   }
@@ -1471,7 +745,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   if(ok && expect_close && numentries == 0 && status_len == 0)
   {
-    CVAL(outbuf,smb_rcls) = ERRDOS;
+    SCVAL(outbuf,smb_rcls,ERRDOS);
     SSVAL(outbuf,smb_err,ERRnofiles);
     /* Also close the dptr - we know it's gone */
     dptr_close(&dptr_num);
@@ -1483,7 +757,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   SSVAL(outbuf,smb_vwv0,numentries);
   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
-  CVAL(smb_buf(outbuf),0) = 5;
+  SCVAL(smb_buf(outbuf),0,5);
   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
 
   if (Protocol >= PROTOCOL_NT1) {
@@ -1521,14 +795,14 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   outsize = set_message(outbuf,1,0,True);
   p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE|STR_CONVERT);
+  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
   p++;
   status_len = SVAL(p,0);
   p += 2;
 
   if (status_len == 0) {
     END_PROFILE(SMBfclose);
-    return(ERROR(ERRSRV,ERRsrverror));
+    return ERROR_DOS(ERRSRV,ERRsrverror);
   }
 
   memcpy(status,p,21);
@@ -1599,7 +873,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     DEBUG(3,("attempt to open a directory %s\n",fname));
     close_file(fsp,False);
     END_PROFILE(SMBopen);
-    return(ERROR(ERRDOS,ERRnoaccess));
+    return ERROR_DOS(ERRDOS,ERRnoaccess);
   }
   
   outsize = set_message(outbuf,7,0,True);
@@ -1613,11 +887,11 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SSVAL(outbuf,smb_vwv6,rmode);
 
   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
     
   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   END_PROFILE(SMBopen);
   return(outsize);
 }
@@ -1658,7 +932,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
            return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
     } else {
                END_PROFILE(SMBopenX);
-        return (ERROR(ERRSRV,ERRaccess));
+        return ERROR_DOS(ERRSRV,ERRaccess);
     }
   }
 
@@ -1691,7 +965,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
   if (fmode & aDIR) {
     close_file(fsp,False);
     END_PROFILE(SMBopenX);
-    return(ERROR(ERRDOS,ERRnoaccess));
+    return ERROR_DOS(ERRDOS,ERRnoaccess);
   }
 
   /* If the caller set the extended oplock request bit
@@ -1713,11 +987,11 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
    */
 
   if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
 
   if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
 
   set_message(outbuf,15,0,True);
@@ -1828,11 +1102,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SSVAL(outbuf,smb_vwv0,fsp->fnum);
 
   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
  
   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
  
   DEBUG( 2, ( "new file %s\n", fname ) );
   DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
@@ -1849,19 +1123,21 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
   pstring fname;
-  pstring fname2;
   int outsize = 0;
   int createmode;
   mode_t unixmode;
   BOOL bad_path = False;
   files_struct *fsp;
   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+  int tmpfd;
   SMB_STRUCT_STAT sbuf;
+  char *p, *s;
+
   START_PROFILE(SMBctemp);
 
   createmode = SVAL(inbuf,smb_vwv0);
-  pstrcpy(fname,smb_buf(inbuf)+1);
-  pstrcat(fname,"/TMXXXXXX");
+  srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
+  pstrcat(fname,"\\TMXXXXXX");
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
@@ -1869,20 +1145,26 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   
   unixmode = unix_mode(conn,createmode,fname);
   
-  pstrcpy(fname2,(char *)smbd_mktemp(fname));
-  /* This file should not exist. */
-  ZERO_STRUCT(sbuf);
-  vfs_stat(conn,fname2,&sbuf);
+  tmpfd = smb_mkstemp(fname);
+  if (tmpfd == -1) {
+      END_PROFILE(SMBctemp);
+      return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
+
+  vfs_stat(conn,fname,&sbuf);
 
   /* Open file in dos compatibility share mode. */
-  /* We should fail if file exists. */
-  fsp = open_file_shared(conn,fname2,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
-                   (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unixmode, oplock_request, NULL, NULL);
+  /* We should fail if file does not exist. */
+  fsp = open_file_shared(conn,fname,&sbuf,
+                        SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
+                        FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
+                        unixmode, oplock_request, NULL, NULL);
 
-  if (!fsp)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
+  /* close fd from smb_mkstemp() */
+  close(tmpfd);
+
+       if (!fsp) {
+               if((errno == ENOENT) && bad_path) {
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
@@ -1890,408 +1172,413 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  outsize = set_message(outbuf,1,2 + strlen(fname2),True);
+  outsize = set_message(outbuf,1,0,True);
   SSVAL(outbuf,smb_vwv0,fsp->fnum);
-  CVAL(smb_buf(outbuf),0) = 4;
-  pstrcpy(smb_buf(outbuf) + 1,fname2);
+
+  /* the returned filename is relative to the directory */
+  s = strrchr_m(fname, '/');
+  if (!s) {
+         s = fname;
+  } else {
+         s++;
+  }
+
+  p = smb_buf(outbuf);
+  SSVALS(p, 0, -1); /* what is this? not in spec */
+  SSVAL(p, 2, strlen(s));
+  p += 4;
+  p += srvstr_push(outbuf, p, s, -1, STR_ASCII);
+  outsize = set_message_end(outbuf, p);
 
   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+         SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
   
-  if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+  if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+         SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
 
-  DEBUG( 2, ( "created temp file %s\n", fname2 ) );
+  DEBUG( 2, ( "created temp file %s\n", fname ) );
   DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
-        fname2, fsp->fd, createmode, (int)unixmode ) );
+        fname, fsp->fd, createmode, (int)unixmode ) );
 
   END_PROFILE(SMBctemp);
   return(outsize);
 }
 
-
-/*******************************************************************
-check if a user is allowed to delete a file
-********************************************************************/
-static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
-{
-  SMB_STRUCT_STAT sbuf;
-  int fmode;
-
-  if (!CAN_WRITE(conn)) return(False);
-
-  if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
-  fmode = dos_mode(conn,fname,&sbuf);
-  if (fmode & aDIR) return(False);
-  if (!lp_delete_readonly(SNUM(conn))) {
-    if (fmode & aRONLY) return(False);
-  }
-  if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
-    return(False);
-  if (!check_file_sharing(conn,fname,False)) return(False);
-  return(True);
-}
-
-/****************************************************************************
- The guts of the unlink command, split out so it may be called by the NT SMB
- code.
-****************************************************************************/
-
-int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
-                                        int dirtype, char *name)
-{
-  pstring directory;
-  pstring mask;
-  char *p;
-  int count=0;
-  int error = ERRnoaccess;
-  BOOL has_wild;
-  BOOL exists=False;
-  BOOL bad_path = False;
-  BOOL rc = True;
-  SMB_STRUCT_STAT sbuf;
-
-  *directory = *mask = 0;
-
-  rc = unix_convert(name,conn,0,&bad_path,&sbuf);
-
-  p = strrchr(name,'/');
-  if (!p) {
-    pstrcpy(directory,"./");
-    pstrcpy(mask,name);
-  } else {
-    *p = 0;
-    pstrcpy(directory,name);
-    pstrcpy(mask,p+1);
-  }
-
-  /*
-   * We should only check the mangled cache
-   * here if unix_convert failed. This means
-   * that the path in 'mask' doesn't exist
-   * on the file system and so we need to look
-   * for a possible mangle. This patch from
-   * Tine Smukavec <valentin.smukavec@hermes.si>.
-   */
-
-  if (!rc && is_mangled(mask))
-    check_mangled_cache( mask );
-
-  has_wild = ms_has_wild(mask);
-
-  if (!has_wild) {
-    pstrcat(directory,"/");
-    pstrcat(directory,mask);
-    if (can_delete(directory,conn,dirtype) && !vfs_unlink(conn,directory))
-      count++;
-    if (!count)
-      exists = vfs_file_exist(conn,directory,&sbuf);    
-  } else {
-    void *dirptr = NULL;
-    char *dname;
-
-    if (check_name(directory,conn))
-      dirptr = OpenDir(conn, directory, True);
-
-    /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
-       the pattern matches against the long name, otherwise the short name 
-       We don't implement this yet XXXX
-       */
-
-    if (dirptr)
-      {
-       error = ERRbadfile;
-
-       if (strequal(mask,"????????.???"))
-         pstrcpy(mask,"*");
-
-       while ((dname = ReadDirName(dirptr)))
-         {
-           pstring fname;
-           pstrcpy(fname,dname);
-           
-           if(!mask_match(fname, mask, case_sensitive)) continue;
-
-           error = ERRnoaccess;
-           slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-           if (!can_delete(fname,conn,dirtype)) continue;
-           if (!vfs_unlink(conn,fname)) count++;
-           DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
-         }
-       CloseDir(dirptr);
-      }
-  }
-  
-  if (count == 0) {
-    if (exists)
-      return(ERROR(ERRDOS,error));
-    else {
-      if((errno == ENOENT) && bad_path) {
-        unix_ERR_class = ERRDOS;
-        unix_ERR_code = ERRbadpath;
-      }
-      return(UNIXERROR(ERRDOS,error));
-    }
-  }
-  
-  return 0;
+/*******************************************************************
+ Check if a user is allowed to delete a file.
+********************************************************************/
+
+static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
+{
+       SMB_STRUCT_STAT sbuf;
+       int fmode;
+
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+
+       if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0)
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+       fmode = dos_mode(conn,fname,&sbuf);
+       if (fmode & aDIR)
+               return NT_STATUS_FILE_IS_A_DIRECTORY;
+       if (!lp_delete_readonly(SNUM(conn))) {
+               if (fmode & aRONLY)
+                       return NT_STATUS_CANNOT_DELETE;
+       }
+       if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
+               return NT_STATUS_CANNOT_DELETE;
+
+       if (!check_file_sharing(conn,fname,False))
+               return NT_STATUS_SHARING_VIOLATION;
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
- Reply to a unlink
+ The guts of the unlink command, split out so it may be called by the NT SMB
+ code.
 ****************************************************************************/
 
-int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
 {
-  int outsize = 0;
-  pstring name;
-  int dirtype;
-  START_PROFILE(SMBunlink);
-
-  dirtype = SVAL(inbuf,smb_vwv0);
-
-  srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+       pstring directory;
+       pstring mask;
+       char *p;
+       int count=0;
+       NTSTATUS error = NT_STATUS_OK;
+       BOOL has_wild;
+       BOOL exists=False;
+       BOOL bad_path = False;
+       BOOL rc = True;
+       SMB_STRUCT_STAT sbuf;
+       
+       *directory = *mask = 0;
+       
+       rc = unix_convert(name,conn,0,&bad_path,&sbuf);
+       
+       p = strrchr_m(name,'/');
+       if (!p) {
+               pstrcpy(directory,"./");
+               pstrcpy(mask,name);
+       } else {
+               *p = 0;
+               pstrcpy(directory,name);
+               pstrcpy(mask,p+1);
+       }
+       
+       /*
+        * We should only check the mangled cache
+        * here if unix_convert failed. This means
+        * that the path in 'mask' doesn't exist
+        * on the file system and so we need to look
+        * for a possible mangle. This patch from
+        * Tine Smukavec <valentin.smukavec@hermes.si>.
+        */
+       
+       if (!rc && is_mangled(mask))
+               check_mangled_cache( mask );
+       
+       has_wild = ms_has_wild(mask);
+       
+       if (!has_wild) {
+               pstrcat(directory,"/");
+               pstrcat(directory,mask);
+               error = can_delete(directory,conn,dirtype);
+               if (!NT_STATUS_IS_OK(error)) return error;
 
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+               if (vfs_unlink(conn,directory) == 0) {
+                       count++;
+               }
+               if (!count)
+                       exists = vfs_file_exist(conn,directory,&sbuf);    
+       } else {
+               void *dirptr = NULL;
+               char *dname;
+               
+               if (check_name(directory,conn))
+                       dirptr = OpenDir(conn, directory, True);
+               
+               /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
+                  the pattern matches against the long name, otherwise the short name 
+                  We don't implement this yet XXXX
+               */
+               
+               if (dirptr) {
+                       error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       
+                       if (strequal(mask,"????????.???"))
+                               pstrcpy(mask,"*");
 
-  DEBUG(3,("reply_unlink : %s\n",name));
+                       while ((dname = ReadDirName(dirptr))) {
+                               pstring fname;
+                               pstrcpy(fname,dname);
+                               
+                               if(!mask_match(fname, mask, case_sensitive)) continue;
+                               
+                               slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+                               error = can_delete(fname,conn,dirtype);
+                               if (!NT_STATUS_IS_OK(error)) continue;
+                               if (vfs_unlink(conn,fname) == 0) count++;
+                               DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
+                       }
+                       CloseDir(dirptr);
+               }
+       }
+       
+       if (count == 0 && NT_STATUS_IS_OK(error)) {
+               error = map_nt_error_from_unix(errno);
+       }
 
-  outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name);
-  if(outsize == 0) {
+       return error;
+}
 
-    /*
-     * Win2k needs a changenotify request response before it will
-     * update after a rename..
-     */
+/****************************************************************************
+ Reply to a unlink
+****************************************************************************/
 
-    process_pending_change_notify_queue((time_t)0);
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
+                int dum_buffsize)
+{
+       int outsize = 0;
+       pstring name;
+       int dirtype;
+       NTSTATUS status;
+       START_PROFILE(SMBunlink);
+       
+       dirtype = SVAL(inbuf,smb_vwv0);
+       
+       srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+       
+       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       
+       DEBUG(3,("reply_unlink : %s\n",name));
+       
+       status = unlink_internals(conn, dirtype, name);
+       if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
 
-  outsize = set_message(outbuf,0,0,True);
-  }
+       /*
+        * Win2k needs a changenotify request response before it will
+        * update after a rename..
+        */
+       process_pending_change_notify_queue((time_t)0);
+       
+       outsize = set_message(outbuf,0,0,True);
   
-  END_PROFILE(SMBunlink);
-  return(outsize);
+       END_PROFILE(SMBunlink);
+       return outsize;
 }
 
+/****************************************************************************
+ Fail for readbraw.
+****************************************************************************/
+
+void fail_readraw(void)
+{
+       pstring errstr;
+       slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
+               strerror(errno) );
+       exit_server(errstr);
+}
 
 /****************************************************************************
-   reply to a readbraw (core+ protocol)
+ Reply to a readbraw (core+ protocol).
 ****************************************************************************/
 
 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
 {
-  size_t maxcount,mincount;
-  size_t nread = 0;
-  SMB_OFF_T startpos;
-  char *header = outbuf;
-  ssize_t ret=0;
-  files_struct *fsp;
-  START_PROFILE(SMBreadbraw);
+       ssize_t maxcount,mincount;
+       size_t nread = 0;
+       SMB_OFF_T startpos;
+       char *header = outbuf;
+       ssize_t ret=0;
+       files_struct *fsp;
+       START_PROFILE(SMBreadbraw);
 
-  /*
-   * Special check if an oplock break has been issued
-   * and the readraw request croses on the wire, we must
-   * return a zero length response here.
-   */
+       /*
+        * Special check if an oplock break has been issued
+        * and the readraw request croses on the wire, we must
+        * return a zero length response here.
+        */
 
-  if(global_oplock_break)
-  {
-    _smb_setlen(header,0);
-    transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-    DEBUG(5,("readbraw - oplock break finished\n"));
-    END_PROFILE(SMBreadbraw);
-    return -1;
-  }
+       if(global_oplock_break) {
+               _smb_setlen(header,0);
+               if (write_data(smbd_server_fd(),header,4) != 4)
+                       fail_readraw();
+               DEBUG(5,("readbraw - oplock break finished\n"));
+               END_PROFILE(SMBreadbraw);
+               return -1;
+       }
 
-  fsp = file_fsp(inbuf,smb_vwv0);
-
-  if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
-         /*
-          * fsp could be NULL here so use the value from the packet. JRA.
-          */
-         DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
-         _smb_setlen(header,0);
-         transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-         END_PROFILE(SMBreadbraw);
-         return(-1);
-  }
+       fsp = file_fsp(inbuf,smb_vwv0);
 
-  CHECK_FSP(fsp,conn);
+       if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+               /*
+                * fsp could be NULL here so use the value from the packet. JRA.
+                */
+               DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
+               _smb_setlen(header,0);
+               if (write_data(smbd_server_fd(),header,4) != 4)
+                       fail_readraw();
+               END_PROFILE(SMBreadbraw);
+               return(-1);
+       }
+
+       CHECK_FSP(fsp,conn);
 
-  flush_write_cache(fsp, READRAW_FLUSH);
+       flush_write_cache(fsp, READRAW_FLUSH);
 
-  startpos = IVAL(inbuf,smb_vwv1);
-  if(CVAL(inbuf,smb_wct) == 10) {
-    /*
-     * This is a large offset (64 bit) read.
-     */
+       startpos = IVAL(inbuf,smb_vwv1);
+       if(CVAL(inbuf,smb_wct) == 10) {
+               /*
+                * This is a large offset (64 bit) read.
+                */
 #ifdef LARGE_SMB_OFF_T
 
-    startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
+               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
 
 #else /* !LARGE_SMB_OFF_T */
 
-    /*
-     * Ensure we haven't been sent a >32 bit offset.
-     */
+               /*
+                * Ensure we haven't been sent a >32 bit offset.
+                */
 
-    if(IVAL(inbuf,smb_vwv8) != 0) {
-      DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
+               if(IVAL(inbuf,smb_vwv8) != 0) {
+                       DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
-      _smb_setlen(header,0);
-      transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-      END_PROFILE(SMBreadbraw);
-      return(-1);
-    }
+                       _smb_setlen(header,0);
+                       if (write_data(smbd_server_fd(),header,4) != 4)
+                               fail_readraw();
+                       END_PROFILE(SMBreadbraw);
+                       return(-1);
+               }
 
 #endif /* LARGE_SMB_OFF_T */
 
-    if(startpos < 0) {
-      DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
-            (double)startpos ));
-         _smb_setlen(header,0);
-         transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-         END_PROFILE(SMBreadbraw);
-         return(-1);
-    }      
-  }
-  maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
-  mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
+               if(startpos < 0) {
+                       DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
+                       _smb_setlen(header,0);
+                       if (write_data(smbd_server_fd(),header,4) != 4)
+                               fail_readraw();
+                       END_PROFILE(SMBreadbraw);
+                       return(-1);
+               }      
+       }
+       maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
+       mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
 
-  /* ensure we don't overrun the packet size */
-  maxcount = MIN(65535,maxcount);
-  maxcount = MAX(mincount,maxcount);
+       /* ensure we don't overrun the packet size */
+       maxcount = MIN(65535,maxcount);
+       maxcount = MAX(mincount,maxcount);
 
-  if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK))
-  {
-    SMB_OFF_T size = fsp->size;
-    SMB_OFF_T sizeneeded = startpos + maxcount;
-           
-    if (size < sizeneeded)
-    {
-      SMB_STRUCT_STAT st;
-      if (vfs_fstat(fsp,fsp->fd,&st) == 0)
-        size = st.st_size;
-      if (!fsp->can_write) 
-        fsp->size = size;
-    }
+       if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               SMB_OFF_T size = fsp->size;
+               SMB_OFF_T sizeneeded = startpos + maxcount;
+  
+               if (size < sizeneeded) {
+                       SMB_STRUCT_STAT st;
+                       if (vfs_fstat(fsp,fsp->fd,&st) == 0)
+                               size = st.st_size;
+                       if (!fsp->can_write) 
+                               fsp->size = size;
+               }
 
-    nread = MIN(maxcount,(size - startpos));     
-  }
+               if (startpos >= size)
+                       nread = 0;
+               else
+                       nread = MIN(maxcount,(size - startpos));          
+       }
 
-  if (nread < mincount)
-    nread = 0;
+       if (nread < mincount)
+               nread = 0;
   
-  DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
-             fsp->fnum, (double)startpos,
-             (int)maxcount, (int)mincount, (int)nread ) );
+       DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
+                               (int)maxcount, (int)mincount, (int)nread ) );
   
-#if UNSAFE_READRAW
-  {
-    BOOL seek_fail = False;
-    int predict=0;
-    _smb_setlen(header,nread);
-
-    if ((nread-predict) > 0) {
-      if(conn->vfs_ops.seek(fsp,fsp->fd,startpos + predict) == -1) {
-        DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
-        ret = 0;
-        seek_fail = True;
-      } 
-    }
-
-    if(!seek_fail)
-      ret = (ssize_t)vfs_transfer_file(-1, fsp, fsp->fd, Client, NULL,
-                                   (SMB_OFF_T)(nread-predict),header,4+predict, 
-                                   startpos+predict);
-  }
-
-  if (ret != nread+4)
-    DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
-            fsp->fsp_name,startpos,nread,ret));
-
-#else /* UNSAFE_READRAW */
-  ret = read_file(fsp,header+4,startpos,nread);
-  if (ret < mincount) ret = 0;
+       if (nread > 0) {
+               ret = read_file(fsp,header+4,startpos,nread);
+               if (ret < mincount)
+                       ret = 0;
+       }
 
-  _smb_setlen(header,ret);
-  transfer_file(0,smbd_server_fd(),0,header,4+ret,0);
-#endif /* UNSAFE_READRAW */
+       _smb_setlen(header,ret);
+       if (write_data(smbd_server_fd(),header,4+ret) != 4+ret)
+               fail_readraw();
 
-  DEBUG(5,("readbraw finished\n"));
-  END_PROFILE(SMBreadbraw);
-  return -1;
+       DEBUG(5,("readbraw finished\n"));
+       END_PROFILE(SMBreadbraw);
+       return -1;
 }
 
-
 /****************************************************************************
   reply to a lockread (core+ protocol)
 ****************************************************************************/
 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
 {
-  ssize_t nread = -1;
-  char *data;
-  int outsize = 0;
-  SMB_OFF_T startpos;
-  size_t numtoread;
-  int eclass;
-  uint32 ecode;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBlockread);
+       ssize_t nread = -1;
+       char *data;
+       int outsize = 0;
+       SMB_OFF_T startpos;
+       size_t numtoread;
+       NTSTATUS status;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBlockread);
 
-  CHECK_FSP(fsp,conn);
-  CHECK_READ(fsp);
-  CHECK_ERROR(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_READ(fsp);
 
-  release_level_2_oplocks_on_change(fsp);
+       release_level_2_oplocks_on_change(fsp);
 
-  numtoread = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv2);
+       numtoread = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv2);
   
-  outsize = set_message(outbuf,5,3,True);
-  numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
-  data = smb_buf(outbuf) + 3;
-  /*
-   * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
-   * protocol request that predates the read/write lock concept. 
-   * Thus instead of asking for a read lock here we need to ask
-   * for a write lock. JRA.
-   */
+       outsize = set_message(outbuf,5,3,True);
+       numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
+       data = smb_buf(outbuf) + 3;
+       
+       /*
+        * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
+        * protocol request that predates the read/write lock concept. 
+        * Thus instead of asking for a read lock here we need to ask
+        * for a write lock. JRA.
+        */
+       
+       status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), 
+                        (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
 
-  if(!do_lock( fsp, conn, (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) {
-    if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
-      /*
-       * A blocking lock was requested. Package up
-       * this smb into a queued request and push it
-       * onto the blocking lock queue.
-       */
-      if(push_blocking_lock_request(inbuf, length, -1, 0))
+       if (NT_STATUS_V(status)) {
+               if (lp_blocking_locks(SNUM(conn))) {
+                       /*
+                        * A blocking lock was requested. Package up
+                        * this smb into a queued request and push it
+                        * onto the blocking lock queue.
+                        */
+                       if(push_blocking_lock_request(inbuf, length, -1, 0))
+                               END_PROFILE(SMBlockread);
+                       return -1;
+               }
                END_PROFILE(SMBlockread);
-        return -1;
-    }
-    END_PROFILE(SMBlockread);
-    return (ERROR(eclass,ecode));
-  }
-
-  nread = read_file(fsp,data,startpos,numtoread);
-
-  if (nread < 0) {
-    END_PROFILE(SMBlockread);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+               return ERROR_NT(status);
+       }
 
-  outsize += nread;
-  SSVAL(outbuf,smb_vwv0,nread);
-  SSVAL(outbuf,smb_vwv5,nread+3);
-  SSVAL(smb_buf(outbuf),1,nread);
+       nread = read_file(fsp,data,startpos,numtoread);
 
-  DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
-            fsp->fnum, (int)numtoread, (int)nread ) );
+       if (nread < 0) {
+               END_PROFILE(SMBlockread);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+       
+       outsize += nread;
+       SSVAL(outbuf,smb_vwv0,nread);
+       SSVAL(outbuf,smb_vwv5,nread+3);
+       SSVAL(smb_buf(outbuf),1,nread);
+       
+       DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
+                fsp->fnum, (int)numtoread, (int)nread));
 
-  END_PROFILE(SMBlockread);
-  return(outsize);
+       END_PROFILE(SMBlockread);
+       return(outsize);
 }
 
 
@@ -2311,23 +1598,23 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
   CHECK_FSP(fsp,conn);
   CHECK_READ(fsp);
-  CHECK_ERROR(fsp);
 
   numtoread = SVAL(inbuf,smb_vwv1);
   startpos = IVAL(inbuf,smb_vwv2);
-  
+
+
   outsize = set_message(outbuf,5,3,True);
   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
   data = smb_buf(outbuf) + 3;
   
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
     END_PROFILE(SMBread);
-    return(ERROR(ERRDOS,ERRlock));     
+    return ERROR_DOS(ERRDOS,ERRlock);
   }
 
   if (numtoread > 0)
     nread = read_file(fsp,data,startpos,numtoread);
-  
+
   if (nread < 0) {
     END_PROFILE(SMBread);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2336,7 +1623,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
   outsize += nread;
   SSVAL(outbuf,smb_vwv0,nread);
   SSVAL(outbuf,smb_vwv5,nread+3);
-  CVAL(smb_buf(outbuf),0) = 1;
+  SCVAL(smb_buf(outbuf),0,1);
   SSVAL(smb_buf(outbuf),1,nread);
   
   DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
@@ -2368,7 +1655,6 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 
   CHECK_FSP(fsp,conn);
   CHECK_READ(fsp);
-  CHECK_ERROR(fsp);
 
   set_message(outbuf,12,0,True);
   data = smb_buf(outbuf);
@@ -2390,19 +1676,19 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
       DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
       END_PROFILE(SMBreadX);
-      return(ERROR(ERRDOS,ERRbadaccess));
+      return ERROR_DOS(ERRDOS,ERRbadaccess);
     }
 
 #endif /* LARGE_SMB_OFF_T */
 
   }
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
     END_PROFILE(SMBreadX);
-    return(ERROR(ERRDOS,ERRlock));
+    return ERROR_DOS(ERRDOS,ERRlock);
   }
   nread = read_file(fsp,data,startpos,smb_maxcnt);
-  
+
   if (nread < 0) {
     END_PROFILE(SMBreadX);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2425,233 +1711,268 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 
 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-  ssize_t nwritten=0;
-  ssize_t total_written=0;
-  size_t numtowrite=0;
-  size_t tcount;
-  SMB_OFF_T startpos;
-  char *data=NULL;
-  BOOL write_through;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  int outsize = 0;
-  START_PROFILE(SMBwritebraw);
+       ssize_t nwritten=0;
+       ssize_t total_written=0;
+       size_t numtowrite=0;
+       size_t tcount;
+       SMB_OFF_T startpos;
+       char *data=NULL;
+       BOOL write_through;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       int outsize = 0;
+       START_PROFILE(SMBwritebraw);
 
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
-  CHECK_ERROR(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
   
-  tcount = IVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv3);
-  write_through = BITSETW(inbuf+smb_vwv7,0);
-
-  /* We have to deal with slightly different formats depending
-     on whether we are using the core+ or lanman1.0 protocol */
-  if(Protocol <= PROTOCOL_COREPLUS) {
-    numtowrite = SVAL(smb_buf(inbuf),-2);
-    data = smb_buf(inbuf);
-  } else {
-    numtowrite = SVAL(inbuf,smb_vwv10);
-    data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
-  }
+       tcount = IVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv3);
+       write_through = BITSETW(inbuf+smb_vwv7,0);
 
-  /* force the error type */
-  CVAL(inbuf,smb_com) = SMBwritec;
-  CVAL(outbuf,smb_com) = SMBwritec;
+       /* We have to deal with slightly different formats depending
+               on whether we are using the core+ or lanman1.0 protocol */
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
-    END_PROFILE(SMBwritebraw);
-    return(ERROR(ERRDOS,ERRlock));
-  }
+       if(Protocol <= PROTOCOL_COREPLUS) {
+               numtowrite = SVAL(smb_buf(inbuf),-2);
+               data = smb_buf(inbuf);
+       } else {
+               numtowrite = SVAL(inbuf,smb_vwv10);
+               data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
+       }
 
-  if (numtowrite>0)
-    nwritten = write_file(fsp,data,startpos,numtowrite);
+       /* force the error type */
+       SCVAL(inbuf,smb_com,SMBwritec);
+       SCVAL(outbuf,smb_com,SMBwritec);
+
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+               END_PROFILE(SMBwritebraw);
+               return(ERROR_DOS(ERRDOS,ERRlock));
+       }
+
+       if (numtowrite>0)
+               nwritten = write_file(fsp,data,startpos,numtowrite);
   
-  DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
-          fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
+       DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
+               fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
 
-  if (nwritten < numtowrite)  {
-    END_PROFILE(SMBwritebraw);
-    return(UNIXERROR(ERRHRD,ERRdiskfull));
-  }
+       if (nwritten < numtowrite)  {
+               END_PROFILE(SMBwritebraw);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
 
-  total_written = nwritten;
+       total_written = nwritten;
 
-  /* Return a message to the redirector to tell it
-     to send more bytes */
-  CVAL(outbuf,smb_com) = SMBwritebraw;
-  SSVALS(outbuf,smb_vwv0,-1);
-  outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
-  send_smb(smbd_server_fd(),outbuf);
+       /* Return a message to the redirector to tell it to send more bytes */
+       SCVAL(outbuf,smb_com,SMBwritebraw);
+       SSVALS(outbuf,smb_vwv0,-1);
+       outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+       if (!send_smb(smbd_server_fd(),outbuf))
+               exit_server("reply_writebraw: send_smb failed.");
   
-  /* Now read the raw data into the buffer and write it */
-  if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
-    exit_server("secondary writebraw failed");
-  }
+       /* Now read the raw data into the buffer and write it */
+       if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
+               exit_server("secondary writebraw failed");
+       }
   
-  /* Even though this is not an smb message, smb_len
-     returns the generic length of an smb message */
-  numtowrite = smb_len(inbuf);
+       /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
+       numtowrite = smb_len(inbuf);
 
-  if (tcount > nwritten+numtowrite) {
-    DEBUG(3,("Client overestimated the write %d %d %d\n",
-            (int)tcount,(int)nwritten,(int)numtowrite));
-  }
+       /* Set up outbuf to return the correct return */
+       outsize = set_message(outbuf,1,0,True);
+       SCVAL(outbuf,smb_com,SMBwritec);
+       SSVAL(outbuf,smb_vwv0,total_written);
 
-  nwritten = vfs_transfer_file(smbd_server_fd(), NULL, -1, fsp,
-                              (SMB_OFF_T)numtowrite,NULL,0, 
-                              startpos+nwritten);
-  total_written += nwritten;
-  
-  /* Set up outbuf to return the correct return */
-  outsize = set_message(outbuf,1,0,True);
-  CVAL(outbuf,smb_com) = SMBwritec;
-  SSVAL(outbuf,smb_vwv0,total_written);
+       if (numtowrite != 0) {
 
-  if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
-    SSVAL(outbuf,smb_err,ERRdiskfull);      
-  }
+               if (numtowrite > BUFFER_SIZE) {
+                       DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
+                               (unsigned int)numtowrite ));
+                       exit_server("secondary writebraw failed");
+               }
 
-  if ((lp_syncalways(SNUM(conn)) || write_through) && 
-      lp_strict_sync(SNUM(conn)))
-      sync_file(conn,fsp);
+               if (tcount > nwritten+numtowrite) {
+                       DEBUG(3,("Client overestimated the write %d %d %d\n",
+                               (int)tcount,(int)nwritten,(int)numtowrite));
+               }
 
-  DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
-          fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
+               if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
+                       DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
+                               strerror(errno) ));
+                       exit_server("secondary writebraw failed");
+               }
 
-  /* we won't return a status if write through is not selected - this 
-     follows what WfWg does */
-  END_PROFILE(SMBwritebraw);
-  if (!write_through && total_written==tcount) {
-    return(-1);
-  }
+               nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
+
+               if (nwritten < (ssize_t)numtowrite) {
+                       SCVAL(outbuf,smb_rcls,ERRHRD);
+                       SSVAL(outbuf,smb_err,ERRdiskfull);      
+               }
+
+               if (nwritten > 0)
+                       total_written += nwritten;
+       }
+       if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn)))
+               sync_file(conn,fsp);
+
+       DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
+               fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
+
+       /* we won't return a status if write through is not selected - this follows what WfWg does */
+       END_PROFILE(SMBwritebraw);
+       if (!write_through && total_written==tcount) {
+               /*
+                * Fix for "rabbit pellet" mode, trigger an early TCP ack by
+                * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
+                */
+               if (!send_keepalive(smbd_server_fd()))
+                       exit_server("reply_writebraw: send of keepalive failed");
+               return(-1);
+       }
 
-  return(outsize);
+       return(outsize);
 }
 
 /****************************************************************************
   reply to a writeunlock (core+)
 ****************************************************************************/
 
-int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, 
+                     int size, int dum_buffsize)
 {
-  ssize_t nwritten = -1;
-  size_t numtowrite;
-  SMB_OFF_T startpos;
-  char *data;
-  int eclass;
-  uint32 ecode;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  int outsize = 0;
-  START_PROFILE(SMBwriteunlock);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
-  CHECK_ERROR(fsp);
+       ssize_t nwritten = -1;
+       size_t numtowrite;
+       SMB_OFF_T startpos;
+       char *data;
+       NTSTATUS status;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       int outsize = 0;
+       START_PROFILE(SMBwriteunlock);
+       
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
 
-  numtowrite = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv2);
-  data = smb_buf(inbuf) + 3;
+       numtowrite = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv2);
+       data = smb_buf(inbuf) + 3;
   
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
-    END_PROFILE(SMBwriteunlock);
-    return(ERROR(ERRDOS,ERRlock));
-  }
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, 
+                     WRITE_LOCK,False)) {
+               END_PROFILE(SMBwriteunlock);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-  /* The special X/Open SMB protocol handling of
-     zero length writes is *NOT* done for
-     this call */
-  if(numtowrite == 0)
-    nwritten = 0;
-  else
-    nwritten = write_file(fsp,data,startpos,numtowrite);
+       /* The special X/Open SMB protocol handling of
+          zero length writes is *NOT* done for
+          this call */
+       if(numtowrite == 0)
+               nwritten = 0;
+       else
+               nwritten = write_file(fsp,data,startpos,numtowrite);
   
-  if (lp_syncalways(SNUM(conn)))
-      sync_file(conn,fsp);
-
-  if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
-    END_PROFILE(SMBwriteunlock);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  if(!do_unlock(fsp, conn, (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode)) {
-    END_PROFILE(SMBwriteunlock);
-    return(ERROR(eclass,ecode));
-  }
+       if (lp_syncalways(SNUM(conn)))
+               sync_file(conn,fsp);
 
-  outsize = set_message(outbuf,1,0,True);
-  
-  SSVAL(outbuf,smb_vwv0,nwritten);
-  
-  DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
-             fsp->fnum, (int)numtowrite, (int)nwritten ) );
+       if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+               END_PROFILE(SMBwriteunlock);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
 
-  END_PROFILE(SMBwriteunlock);
-  return(outsize);
+       status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, 
+                          (SMB_BIG_UINT)startpos);
+       if (NT_STATUS_V(status)) {
+               END_PROFILE(SMBwriteunlock);
+               return ERROR_NT(status);
+       }
+       
+       outsize = set_message(outbuf,1,0,True);
+       
+       SSVAL(outbuf,smb_vwv0,nwritten);
+       
+       DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
+                fsp->fnum, (int)numtowrite, (int)nwritten));
+       
+       END_PROFILE(SMBwriteunlock);
+       return outsize;
 }
 
+
 /****************************************************************************
-  reply to a write
+ Reply to a write.
 ****************************************************************************/
+
 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
 {
-  size_t numtowrite;
-  ssize_t nwritten = -1;
-  SMB_OFF_T startpos;
-  char *data;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  int outsize = 0;
-  START_PROFILE(SMBwrite);
+       size_t numtowrite;
+       ssize_t nwritten = -1;
+       SMB_OFF_T startpos;
+       char *data;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       int outsize = 0;
+       START_PROFILE(SMBwrite);
 
-  /* If it's an IPC, pass off the pipe handler. */
-  if (IS_IPC(conn)) {
-    END_PROFILE(SMBwrite);
-    return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
-  }
+       /* If it's an IPC, pass off the pipe handler. */
+       if (IS_IPC(conn)) {
+               END_PROFILE(SMBwrite);
+               return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
+       }
 
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
-  CHECK_ERROR(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
 
-  numtowrite = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv2);
-  data = smb_buf(inbuf) + 3;
+       numtowrite = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv2);
+       data = smb_buf(inbuf) + 3;
   
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
-    END_PROFILE(SMBwrite);
-    return(ERROR(ERRDOS,ERRlock));
-  }
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+               END_PROFILE(SMBwrite);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-  /* X/Open SMB protocol says that if smb_vwv1 is
-     zero then the file size should be extended or
-     truncated to the size given in smb_vwv[2-3] */
-  if(numtowrite == 0) {
-      nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
-  } else
-    nwritten = write_file(fsp,data,startpos,numtowrite);
+       /*
+        * X/Open SMB protocol says that if smb_vwv1 is
+        * zero then the file size should be extended or
+        * truncated to the size given in smb_vwv[2-3].
+        */
+
+       if(numtowrite == 0) {
+               /*
+                * This is actually an allocate call, and set EOF. JRA.
+                */
+               nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
+               if (nwritten < 0) {
+                       END_PROFILE(SMBwrite);
+                       return ERROR_NT(NT_STATUS_DISK_FULL);
+               }
+               nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
+               if (nwritten < 0) {
+                       END_PROFILE(SMBwrite);
+                       return ERROR_NT(NT_STATUS_DISK_FULL);
+               }
+       } else
+               nwritten = write_file(fsp,data,startpos,numtowrite);
   
-  if (lp_syncalways(SNUM(conn)))
-    sync_file(conn,fsp);
+       if (lp_syncalways(SNUM(conn)))
+               sync_file(conn,fsp);
 
-  if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
-    END_PROFILE(SMBwrite);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+               END_PROFILE(SMBwrite);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
 
-  outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(outbuf,1,0,True);
   
-  SSVAL(outbuf,smb_vwv0,nwritten);
+       SSVAL(outbuf,smb_vwv0,nwritten);
 
-  if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
-    SSVAL(outbuf,smb_err,ERRdiskfull);      
-  }
+       if (nwritten < (ssize_t)numtowrite) {
+               SCVAL(outbuf,smb_rcls,ERRHRD);
+               SSVAL(outbuf,smb_err,ERRdiskfull);      
+       }
   
-  DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
-          fsp->fnum, (int)numtowrite, (int)nwritten));
+       DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
 
-  END_PROFILE(SMBwrite);
-  return(outsize);
+       END_PROFILE(SMBwrite);
+       return(outsize);
 }
 
 
@@ -2666,7 +1987,9 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
   ssize_t nwritten = -1;
   unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
+  unsigned int smblen = smb_len(inbuf);
   char *data;
+  BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
   START_PROFILE(SMBwriteX);
 
   /* If it's an IPC, pass off the pipe handler. */
@@ -2677,11 +2000,14 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
 
   CHECK_FSP(fsp,conn);
   CHECK_WRITE(fsp);
-  CHECK_ERROR(fsp);
 
-  if(smb_doff > smb_len(inbuf)) {
+  /* Deal with possible LARGE_WRITEX */
+  if (large_writeX)
+    numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
+
+  if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
     END_PROFILE(SMBwriteX);
-    return(ERROR(ERRDOS,ERRbadmem));
+    return ERROR_DOS(ERRDOS,ERRbadmem);
   }
 
   data = smb_base(inbuf) + smb_doff;
@@ -2703,15 +2029,15 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
       DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
       END_PROFILE(SMBwriteX);
-      return(ERROR(ERRDOS,ERRbadaccess));
+      return ERROR_DOS(ERRDOS,ERRbadaccess);
     }
 
 #endif /* LARGE_SMB_OFF_T */
   }
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
     END_PROFILE(SMBwriteX);
-    return(ERROR(ERRDOS,ERRlock));
+    return ERROR_DOS(ERRDOS,ERRlock);
   }
 
   /* X/Open SMB protocol says that, unlike SMBwrite
@@ -2731,9 +2057,11 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
   set_message(outbuf,6,0,True);
   
   SSVAL(outbuf,smb_vwv2,nwritten);
-  
+  if (large_writeX)
+    SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
+
   if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
+    SCVAL(outbuf,smb_rcls,ERRHRD);
     SSVAL(outbuf,smb_err,ERRdiskfull);      
   }
 
@@ -2762,7 +2090,6 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
   START_PROFILE(SMBlseek);
 
   CHECK_FSP(fsp,conn);
-  CHECK_ERROR(fsp);
 
   flush_write_cache(fsp, SEEK_FLUSH);
 
@@ -2836,24 +2163,21 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-  int outsize = set_message(outbuf,0,0,True);
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBflush);
-
-  if (fsp) {
-         CHECK_FSP(fsp,conn);
-         CHECK_ERROR(fsp);
-  }
+       int outsize = set_message(outbuf,0,0,True);
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBflush);
 
-  if (!fsp) {
-         file_sync_all(conn);
-  } else {
+       CHECK_FSP(fsp,conn);
+       
+       if (!fsp) {
+               file_sync_all(conn);
+       } else {
                sync_file(conn,fsp);
-  }
-
-  DEBUG(3,("flush\n"));
-  END_PROFILE(SMBflush);
-  return(outsize);
+       }
+       
+       DEBUG(3,("flush\n"));
+       END_PROFILE(SMBflush);
+       return(outsize);
 }
 
 
@@ -2902,12 +2226,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        if(!fsp || (fsp->conn != conn)) {
                END_PROFILE(SMBclose);
-               return(ERROR(ERRDOS,ERRbadfid));
-       }
-
-       if(HAS_CACHED_ERROR(fsp)) {
-               eclass = fsp->wbmpx_ptr->wr_errclass;
-               err = fsp->wbmpx_ptr->wr_error;
+               return ERROR_DOS(ERRDOS,ERRbadfid);
        }
 
        if(fsp->is_directory || fsp->stat_open) {
@@ -2922,21 +2241,10 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Close ordinary file.
                 */
                int close_err;
+               pstring file_name;
 
-               /*
-                * If there was a modify time outstanding,
-                * try and set it here.
-                */
-               if(fsp->pending_modtime)
-                       set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
-
-               /*
-                * Now take care of any time sent in the close.
-                */
-               mtime = make_unix_date3(inbuf+smb_vwv1);
-               
-               /* try and set the date */
-               set_filetime(conn, fsp->fsp_name,mtime);
+               /* Save the name for time set in close. */
+               pstrcpy( file_name, fsp->fsp_name);
 
                DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
                         fsp->fd, fsp->fnum,
@@ -2953,12 +2261,22 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                        END_PROFILE(SMBclose);
                        return (UNIXERROR(ERRHRD,ERRgeneral));
                }
+
+               /*
+                * Now take care of any time sent in the close.
+                */
+
+               mtime = make_unix_date3(inbuf+smb_vwv1);
+               
+               /* try and set the date */
+               set_filetime(conn, file_name, mtime);
+
        }  
 
        /* We have a cached error */
        if(eclass || err) {
                END_PROFILE(SMBclose);
-               return(ERROR(eclass,err));
+               return ERROR_DOS(eclass,err);
        }
 
        END_PROFILE(SMBclose);
@@ -2985,16 +2303,15 @@ int reply_writeclose(connection_struct *conn,
 
        CHECK_FSP(fsp,conn);
        CHECK_WRITE(fsp);
-       CHECK_ERROR(fsp);
 
        numtowrite = SVAL(inbuf,smb_vwv1);
        startpos = IVAL(inbuf,smb_vwv2);
        mtime = make_unix_date3(inbuf+smb_vwv4);
        data = smb_buf(inbuf) + 1;
   
-       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
                END_PROFILE(SMBwriteclose);
-               return(ERROR(ERRDOS,ERRlock));
+               return ERROR_DOS(ERRDOS,ERRlock);
        }
   
        nwritten = write_file(fsp,data,startpos,numtowrite);
@@ -3034,13 +2351,11 @@ int reply_lock(connection_struct *conn,
 {
        int outsize = set_message(outbuf,0,0,True);
        SMB_BIG_UINT count,offset;
-       int eclass;
-       uint32 ecode;
+       NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBlock);
 
        CHECK_FSP(fsp,conn);
-       CHECK_ERROR(fsp);
 
        release_level_2_oplocks_on_change(fsp);
 
@@ -3050,20 +2365,21 @@ int reply_lock(connection_struct *conn,
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
                 fsp->fd, fsp->fnum, (double)offset, (double)count));
 
-       if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode)) {
-          if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
-           /*
-             * A blocking lock was requested. Package up
-             * this smb into a queued request and push it
-             * onto the blocking lock queue.
-             */
-            if(push_blocking_lock_request(inbuf, length, -1, 0)) {
-             END_PROFILE(SMBlock);
-              return -1;
-           }
-          }
-         END_PROFILE(SMBlock);
-         return (ERROR(eclass,ecode));
+       status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
+       if (NT_STATUS_V(status)) {
+               if (lp_blocking_locks(SNUM(conn))) {
+                       /*
+                        * A blocking lock was requested. Package up
+                        * this smb into a queued request and push it
+                        * onto the blocking lock queue.
+                        */
+                       if(push_blocking_lock_request(inbuf, length, -1, 0)) {
+                               END_PROFILE(SMBlock);
+                               return -1;
+                       }
+               }
+               END_PROFILE(SMBlock);
+               return ERROR_NT(status);
        }
 
        END_PROFILE(SMBlock);
@@ -3074,31 +2390,31 @@ int reply_lock(connection_struct *conn,
 /****************************************************************************
   reply to a unlock
 ****************************************************************************/
-int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, 
+                int dum_buffsize)
 {
-  int outsize = set_message(outbuf,0,0,True);
-  SMB_BIG_UINT count,offset;
-  int eclass;
-  uint32 ecode;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBunlock);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_ERROR(fsp);
-
-  count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
-  offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
+       int outsize = set_message(outbuf,0,0,True);
+       SMB_BIG_UINT count,offset;
+       NTSTATUS status;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBunlock);
 
-  if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode)) {
-    END_PROFILE(SMBunlock);
-    return (ERROR(eclass,ecode));
-  }
+       CHECK_FSP(fsp,conn);
+       
+       count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+       offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
+       
+       status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
+       if (NT_STATUS_V(status)) {
+               END_PROFILE(SMBunlock);
+               return ERROR_NT(status);
+       }
 
-  DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
-        fsp->fd, fsp->fnum, (double)offset, (double)count ) );
-  
-  END_PROFILE(SMBunlock);
-  return(outsize);
+       DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+                   fsp->fd, fsp->fnum, (double)offset, (double)count ) );
+       
+       END_PROFILE(SMBunlock);
+       return(outsize);
 }
 
 
@@ -3117,7 +2433,7 @@ int reply_tdis(connection_struct *conn,
        if (!conn) {
                DEBUG(4,("Invalid connection in tdis\n"));
                END_PROFILE(SMBtdis);
-               return(ERROR(ERRSRV,ERRinvnid));
+               return ERROR_DOS(ERRSRV,ERRinvnid);
        }
 
        conn->used = False;
@@ -3158,7 +2474,8 @@ int reply_echo(connection_struct *conn,
 
                smb_setlen(outbuf,outsize - 4);
 
-               send_smb(smbd_server_fd(),outbuf);
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("reply_echo: send_smb failed.");
        }
 
        DEBUG(3,("echo %d times\n", smb_reverb));
@@ -3182,11 +2499,11 @@ int reply_printopen(connection_struct *conn,
        
        if (!CAN_PRINT(conn)) {
                END_PROFILE(SMBsplopen);
-               return(ERROR(ERRDOS,ERRnoaccess));
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
 
        /* Open for exclusive use, write only. */
-       fsp = print_fsp_open(conn,"dos.prn");
+       fsp = print_fsp_open(conn, NULL);
 
        if (!fsp) {
                END_PROFILE(SMBsplopen);
@@ -3216,11 +2533,10 @@ int reply_printclose(connection_struct *conn,
        START_PROFILE(SMBsplclose);
 
        CHECK_FSP(fsp,conn);
-       CHECK_ERROR(fsp);
 
        if (!CAN_PRINT(conn)) {
                END_PROFILE(SMBsplclose);
-               return(ERROR(ERRDOS,ERRnoaccess));
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
   
        DEBUG(3,("printclose fd=%d fnum=%d\n",
@@ -3256,12 +2572,12 @@ int reply_printqueue(connection_struct *conn,
           get it right (tridge) */
        if (!CAN_PRINT(conn)) {
                END_PROFILE(SMBsplretq);
-               return(ERROR(ERRDOS,ERRnoaccess));
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
 
        SSVAL(outbuf,smb_vwv0,0);
        SSVAL(outbuf,smb_vwv1,0);
-       CVAL(smb_buf(outbuf),0) = 1;
+       SCVAL(smb_buf(outbuf),0,1);
        SSVAL(smb_buf(outbuf),1,0);
   
        DEBUG(3,("printqueue start_index=%d max_count=%d\n",
@@ -3269,8 +2585,9 @@ int reply_printqueue(connection_struct *conn,
 
        {
                print_queue_struct *queue = NULL;
+               print_status_struct status;
                char *p = smb_buf(outbuf) + 3;
-               int count = print_queue_status(SNUM(conn), &queue,NULL);
+               int count = print_queue_status(SNUM(conn), &queue, &status);
                int num_to_get = ABS(max_count);
                int first = (max_count>0?start_index:start_index+max_count+1);
                int i;
@@ -3283,11 +2600,11 @@ int reply_printqueue(connection_struct *conn,
 
                for (i=first;i<first+num_to_get;i++) {
                        put_dos_date2(p,0,queue[i].time);
-                       CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
+                       SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
                        SSVAL(p,5, queue[i].job);
                        SIVAL(p,7,queue[i].size);
-                       CVAL(p,11) = 0;
-                       StrnCpy(p+12,queue[i].user,16);
+                       SCVAL(p,11,0);
+                       srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII);
                        p += 28;
                }
 
@@ -3295,11 +2612,11 @@ int reply_printqueue(connection_struct *conn,
                        outsize = set_message(outbuf,2,28*count+3,False); 
                        SSVAL(outbuf,smb_vwv0,count);
                        SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
-                       CVAL(smb_buf(outbuf),0) = 1;
+                       SCVAL(smb_buf(outbuf),0,1);
                        SSVAL(smb_buf(outbuf),1,28*count);
                }
 
-               if (queue) free(queue);
+               SAFE_FREE(queue);
          
                DEBUG(3,("%d entries returned in queue\n",count));
        }
@@ -3322,12 +2639,11 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
   
   if (!CAN_PRINT(conn)) {
     END_PROFILE(SMBsplwr);
-    return(ERROR(ERRDOS,ERRnoaccess));
+    return ERROR_DOS(ERRDOS,ERRnoaccess);
   }
 
   CHECK_FSP(fsp,conn);
   CHECK_WRITE(fsp);
-  CHECK_ERROR(fsp);
 
   numtowrite = SVAL(smb_buf(inbuf),1);
   data = smb_buf(inbuf) + 3;
@@ -3348,111 +2664,102 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
  The guts of the mkdir command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
-int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory)
+NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
 {
-  BOOL bad_path = False;
-  SMB_STRUCT_STAT sbuf;
-  int ret= -1;
-  
-  unix_convert(directory,conn,0,&bad_path,&sbuf);
-  
-  if (check_name(directory, conn))
-    ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
-  
-  if (ret < 0)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  return ret;
+       BOOL bad_path = False;
+       SMB_STRUCT_STAT sbuf;
+       int ret= -1;
+       
+       unix_convert(directory,conn,0,&bad_path,&sbuf);
+       
+       if (check_name(directory, conn))
+               ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
+       
+       if (ret == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+       
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
-  reply to a mkdir
+ Reply to a mkdir.
 ****************************************************************************/
+
 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring directory;
-  int outsize;
-  START_PROFILE(SMBmkdir);
+       pstring directory;
+       int outsize;
+       NTSTATUS status;
+       START_PROFILE(SMBmkdir);
  
-  pstrcpy(directory,smb_buf(inbuf) + 1);
+       srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+
+       status = mkdir_internal(conn, directory);
+       if (!NT_STATUS_IS_OK(status))
+               return ERROR_NT(status);
 
-  outsize=mkdir_internal(conn, inbuf, outbuf, directory);
-  if(outsize == 0)
-    outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,True);
 
-  DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
+       DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
 
-  END_PROFILE(SMBmkdir);
-  return(outsize);
+       END_PROFILE(SMBmkdir);
+       return(outsize);
 }
 
 /****************************************************************************
-Static function used by reply_rmdir to delete an entire directory
-tree recursively.
+ Static function used by reply_rmdir to delete an entire directory
+ tree recursively. Return False on ok, True on fail.
 ****************************************************************************/
 
 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
-  char *dname = NULL;
-  BOOL ret = False;
-  void *dirptr = OpenDir(NULL, directory, False);
+       char *dname = NULL;
+       BOOL ret = False;
+       void *dirptr = OpenDir(conn, directory, False);
 
-  if(dirptr == NULL)
-    return True;
+       if(dirptr == NULL)
+               return True;
 
-  while((dname = ReadDirName(dirptr)))
-  {
-    pstring fullname;
-    SMB_STRUCT_STAT st;
+       while((dname = ReadDirName(dirptr))) {
+               pstring fullname;
+               SMB_STRUCT_STAT st;
 
-    if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-      continue;
+               if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+                       continue;
 
-    /* Construct the full name. */
-    if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
-    {
-      errno = ENOMEM;
-      ret = True;
-      break;
-    }
-    pstrcpy(fullname, directory);
-    pstrcat(fullname, "/");
-    pstrcat(fullname, dname);
+               /* Construct the full name. */
+               if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+                       errno = ENOMEM;
+                       ret = True;
+                       break;
+               }
 
-    if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname,False), &st) != 0)
-    {
-      ret = True;
-      break;
-    }
+               pstrcpy(fullname, directory);
+               pstrcat(fullname, "/");
+               pstrcat(fullname, dname);
 
-    if(st.st_mode & S_IFDIR)
-    {
-      if(recursive_rmdir(conn, fullname)!=0)
-      {
-        ret = True;
-        break;
-      }
-      if(vfs_rmdir(conn,fullname) != 0)
-      {
-        ret = True;
-        break;
-      }
-    }
-    else if(vfs_unlink(conn,fullname) != 0)
-    {
-      ret = True;
-      break;
-    }
-  }
-  CloseDir(dirptr);
-  return ret;
+               if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) {
+                       ret = True;
+                       break;
+               }
+
+               if(st.st_mode & S_IFDIR) {
+                       if(recursive_rmdir(conn, fullname)!=0) {
+                               ret = True;
+                               break;
+                       }
+                       if(vfs_rmdir(conn,fullname) != 0) {
+                               ret = True;
+                               break;
+                       }
+               } else if(vfs_unlink(conn,fullname) != 0) {
+                       ret = True;
+                       break;
+               }
+       }
+       CloseDir(dirptr);
+       return ret;
 }
 
 /****************************************************************************
@@ -3461,86 +2768,77 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 
 BOOL rmdir_internals(connection_struct *conn, char *directory)
 {
-  BOOL ok;
-
-  ok = (vfs_rmdir(conn,directory) == 0);
-  if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
-  {
-    /* 
-     * Check to see if the only thing in this directory are
-     * vetoed files/directories. If so then delete them and
-     * retry. If we fail to delete any of them (and we *don't*
-     * do a recursive delete) then fail the rmdir.
-     */
-    BOOL all_veto_files = True;
-    char *dname;
-    void *dirptr = OpenDir(conn, directory, False);
-
-    if(dirptr != NULL)
-    {
-      int dirpos = TellDir(dirptr);
-      while ((dname = ReadDirName(dirptr)))
-      {
-        if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-          continue;
-        if(!IS_VETO_PATH(conn, dname))
-        {
-          all_veto_files = False;
-          break;
-        }
-      }
-      if(all_veto_files)
-      {
-        SeekDir(dirptr,dirpos);
-        while ((dname = ReadDirName(dirptr)))
-        {
-          pstring fullname;
-          SMB_STRUCT_STAT st;
-
-          if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-            continue;
+       BOOL ok;
+
+       ok = (vfs_rmdir(conn,directory) == 0);
+       if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+               /* 
+                * Check to see if the only thing in this directory are
+                * vetoed files/directories. If so then delete them and
+                * retry. If we fail to delete any of them (and we *don't*
+                * do a recursive delete) then fail the rmdir.
+                */
+               BOOL all_veto_files = True;
+               char *dname;
+               void *dirptr = OpenDir(conn, directory, False);
 
-          /* Construct the full name. */
-          if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
-          {
-            errno = ENOMEM;
-            break;
-          }
-          pstrcpy(fullname, directory);
-          pstrcat(fullname, "/");
-          pstrcat(fullname, dname);
-                     
-          if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname, False), &st) != 0)
-            break;
-          if(st.st_mode & S_IFDIR)
-          {
-            if(lp_recursive_veto_delete(SNUM(conn)))
-            {
-              if(recursive_rmdir(conn, fullname) != 0)
-                break;
-            }
-            if(vfs_rmdir(conn,fullname) != 0)
-              break;
-          }
-          else if(vfs_unlink(conn,fullname) != 0)
-            break;
-        }
-        CloseDir(dirptr);
-        /* Retry the rmdir */
-        ok = (vfs_rmdir(conn,directory) == 0);
-      }
-      else
-        CloseDir(dirptr);
-    }
-    else
-      errno = ENOTEMPTY;
-  }
-          
-  if (!ok)
-    DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
-          directory,strerror(errno)));
+               if(dirptr != NULL) {
+                       int dirpos = TellDir(dirptr);
+                       while ((dname = ReadDirName(dirptr))) {
+                               if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+                                       continue;
+                               if(!IS_VETO_PATH(conn, dname)) {
+                                       all_veto_files = False;
+                                       break;
+                               }
+                       }
 
-  return ok;
+                       if(all_veto_files) {
+                               SeekDir(dirptr,dirpos);
+                               while ((dname = ReadDirName(dirptr))) {
+                                       pstring fullname;
+                                       SMB_STRUCT_STAT st;
+
+                                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+                                               continue;
+
+                                       /* Construct the full name. */
+                                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+                                               errno = ENOMEM;
+                                               break;
+                                       }
+
+                                       pstrcpy(fullname, directory);
+                                       pstrcat(fullname, "/");
+                                       pstrcat(fullname, dname);
+                     
+                                       if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
+                                               break;
+                                       if(st.st_mode & S_IFDIR) {
+                                               if(lp_recursive_veto_delete(SNUM(conn))) {
+                                                       if(recursive_rmdir(conn, fullname) != 0)
+                                                               break;
+                                               }
+                                               if(vfs_rmdir(conn,fullname) != 0)
+                                                       break;
+                                       } else if(vfs_unlink(conn,fullname) != 0)
+                                               break;
+                               }
+                               CloseDir(dirptr);
+                               /* Retry the rmdir */
+                               ok = (vfs_rmdir(conn,directory) == 0);
+                       } else {
+                               CloseDir(dirptr);
+                       }
+               } else {
+                       errno = ENOTEMPTY;
+               }
+       }
+
+       if (!ok)
+               DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
+
+       return ok;
 }
 
 /****************************************************************************
@@ -3556,7 +2854,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SMB_STRUCT_STAT sbuf;
   START_PROFILE(SMBrmdir);
 
-  pstrcpy(directory,smb_buf(inbuf) + 1);
+  srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
 
   RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
 
@@ -3597,21 +2895,21 @@ static BOOL resolve_wildcards(char *name1,char *name2)
   fstring ext1,ext2;
   char *p,*p2;
 
-  name1 = strrchr(name1,'/');
-  name2 = strrchr(name2,'/');
+  name1 = strrchr_m(name1,'/');
+  name2 = strrchr_m(name2,'/');
 
   if (!name1 || !name2) return(False);
   
   fstrcpy(root1,name1);
   fstrcpy(root2,name2);
-  p = strrchr(root1,'.');
+  p = strrchr_m(root1,'.');
   if (p) {
     *p = 0;
     fstrcpy(ext1,p+1);
   } else {
     fstrcpy(ext1,"");    
   }
-  p = strrchr(root2,'.');
+  p = strrchr_m(root2,'.');
   if (p) {
     *p = 0;
     fstrcpy(ext2,p+1);
@@ -3653,26 +2951,26 @@ static BOOL resolve_wildcards(char *name1,char *name2)
 }
 
 /*******************************************************************
-check if a user is allowed to rename a file
+ Check if a user is allowed to rename a file.
 ********************************************************************/
-static BOOL can_rename(char *fname,connection_struct *conn)
+
+static NTSTATUS can_rename(char *fname,connection_struct *conn)
 {
-  SMB_STRUCT_STAT sbuf;
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_ACCESS_DENIED;
 
-  if (!CAN_WRITE(conn)) return(False);
+       if (!check_file_sharing(conn,fname,True))
+               return NT_STATUS_SHARING_VIOLATION;
 
-  if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) return(False);
-  if (!check_file_sharing(conn,fname,True)) return(False);
-  return(True);
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
  The guts of the rename command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
-int rename_internals(connection_struct *conn, 
-                    char *inbuf, char *outbuf, char *name, 
-                    char *newname, BOOL replace_if_exists)
+
+NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists)
 {
        pstring directory;
        pstring mask;
@@ -3682,11 +2980,9 @@ int rename_internals(connection_struct *conn,
        BOOL bad_path1 = False;
        BOOL bad_path2 = False;
        int count=0;
-       int error = ERRnoaccess;
-       BOOL exists=False;
+       NTSTATUS error = NT_STATUS_OK;
        BOOL rc = True;
        SMB_STRUCT_STAT sbuf1, sbuf2;
-       pstring zdirectory;
 
        *directory = *mask = 0;
 
@@ -3702,7 +2998,7 @@ int rename_internals(connection_struct *conn,
         * as this is checked in resolve_wildcards().
         */
        
-       p = strrchr(name,'/');
+       p = strrchr_m(name,'/');
        if (!p) {
                pstrcpy(directory,".");
                pstrcpy(mask,name);
@@ -3722,8 +3018,20 @@ int rename_internals(connection_struct *conn,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
+#if 0
        if (!rc && is_mangled(mask))
                check_mangled_cache( mask );
+#endif
+       if (!rc)
+       {
+               char *unmangled;
+               
+               unmangled = dos_unmangle(mask);
+               if (unmangled)
+                       strncpy(mask, unmangled, strlen(unmangled) + 1);
+                       
+               SAFE_FREE(unmangled);
+       }
 
        has_wild = ms_has_wild(mask);
 
@@ -3738,7 +3046,7 @@ int rename_internals(connection_struct *conn,
                pstrcat(directory,mask);
                
                /* Ensure newname contains a '/' also */
-               if(strrchr(newname,'/') == 0) {
+               if(strrchr_m(newname,'/') == 0) {
                        pstring tmpstr;
                        
                        pstrcpy(tmpstr, "./");
@@ -3746,7 +3054,8 @@ int rename_internals(connection_struct *conn,
                        pstrcpy(newname, tmpstr);
                }
                
-               DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
+               DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
+directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
                         case_sensitive, case_preserve, short_case_preserve, directory, 
                         newname, newname_last_component, is_short_name));
 
@@ -3771,7 +3080,7 @@ int rename_internals(connection_struct *conn,
                         * Note that we guarantee that newname contains a '/'
                         * character above.
                         */
-                       p = strrchr(newname,'/');
+                       p = strrchr_m(newname,'/');
                        pstrcpy(newname_modified_last_component,p+1);
                        
                        if(strcsequal(newname_modified_last_component, 
@@ -3783,37 +3092,77 @@ int rename_internals(connection_struct *conn,
                                pstrcpy(p+1, newname_last_component);
                        }
                }
-               
-                pstrcpy(zdirectory, dos_to_unix(directory, False));
-               if(replace_if_exists) {
-                       /*
-                        * NT SMB specific flag - rename can overwrite
-                        * file with the same name so don't check for
-                        * vfs_file_exist().
-                        */
+       
+               resolve_wildcards(directory,newname);
+       
+               /*
+                * The source object must exist.
+                */
 
-                       if(resolve_wildcards(directory,newname) &&
-                          can_rename(directory,conn) &&
-                          !conn->vfs_ops.rename(conn,zdirectory,
-                                                dos_to_unix(newname,False)))
-                               count++;
-               } else {
-                       if (resolve_wildcards(directory,newname) && 
-                           can_rename(directory,conn) && 
-                           !vfs_file_exist(conn,newname,NULL) &&
-                           !conn->vfs_ops.rename(conn,zdirectory,
-                                                 dos_to_unix(newname,False)))
-                               count++;
+               if (!vfs_object_exist(conn, directory, NULL)) {
+                       DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
+                               directory,newname));
+
+                       if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
+                               /*
+                                * Must return different errors depending on whether the parent
+                                * directory existed or not.
+                                */
+
+                               p = strrchr_m(directory, '/');
+                               if (!p)
+                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                               *p = '\0';
+                               if (vfs_object_exist(conn, directory, NULL))
+                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                       }
+                       error = map_nt_error_from_unix(errno);
+                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                               get_nt_error_msg(error), directory,newname));
+
+                       return error;
                }
 
-               DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
-                         directory,newname));
-               
-               if (!count) exists = vfs_file_exist(conn,directory,NULL);
-               if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
-                       exists = True;
-                       error = ERRrename;
+               error = can_rename(directory,conn);
+
+               if (!NT_STATUS_IS_OK(error)) {
+                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                               get_nt_error_msg(error), directory,newname));
+                       return error;
+               }
+
+               /*
+                * If the src and dest names are identical - including case,
+                * don't do the rename, just return success.
+                */
+
+               if (strcsequal(directory, newname)) {
+                       DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
+                       return NT_STATUS_OK;
+               }
+
+               if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
+                       DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
+                               directory,newname));
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+
+               if(conn->vfs_ops.rename(conn,directory, newname) == 0) {
+                       DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
+                               directory,newname));
+                       return NT_STATUS_OK;    
                }
+
+               if (errno == ENOTDIR || errno == EISDIR)
+                       error = NT_STATUS_OBJECT_NAME_COLLISION;
+               else
+                       error = map_nt_error_from_unix(errno);
+               
+               DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                       get_nt_error_msg(error), directory,newname));
+
+               return error;
        } else {
                /*
                 * Wildcards - process each file that matches.
@@ -3826,7 +3175,7 @@ int rename_internals(connection_struct *conn,
                        dirptr = OpenDir(conn, directory, True);
                
                if (dirptr) {
-                       error = ERRbadfile;
+                       error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                        
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
@@ -3839,9 +3188,10 @@ int rename_internals(connection_struct *conn,
                                if(!mask_match(fname, mask, case_sensitive))
                                        continue;
                                
-                               error = ERRnoaccess;
+                               error = NT_STATUS_ACCESS_DENIED;
                                slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
-                               if (!can_rename(fname,conn)) {
+                               error = can_rename(fname,conn);
+                               if (!NT_STATUS_IS_OK(error)) {
                                        DEBUG(6,("rename %s refused\n", fname));
                                        continue;
                                }
@@ -3856,12 +3206,11 @@ int rename_internals(connection_struct *conn,
                                if (!replace_if_exists && 
                                     vfs_file_exist(conn,destname, NULL)) {
                                        DEBUG(6,("file_exist %s\n", destname));
-                                       error = 183;
+                                       error = NT_STATUS_OBJECT_NAME_COLLISION;
                                        continue;
                                }
                                
-                               if (!conn->vfs_ops.rename(conn,dos_to_unix(fname,False),
-                                                          dos_to_unix(destname,False)))
+                               if (!conn->vfs_ops.rename(conn,fname,destname))
                                        count++;
                                DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
                        }
@@ -3869,137 +3218,132 @@ int rename_internals(connection_struct *conn,
                }
        }
        
-       if (count == 0) {
-               if (exists)
-                       return(ERROR(ERRDOS,error));
-               else {
-                       if((errno == ENOENT) && (bad_path1 || bad_path2)) {
-                               unix_ERR_class = ERRDOS;
-                               unix_ERR_code = ERRbadpath;
-                       }
-                       return(UNIXERROR(ERRDOS,error));
-               }
+       if (count == 0 && NT_STATUS_IS_OK(error)) {
+               error = map_nt_error_from_unix(errno);
        }
        
-       return 0;
+       return error;
 }
 
 /****************************************************************************
  Reply to a mv.
 ****************************************************************************/
 
-int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
+            int dum_buffsize)
 {
-  int outsize = 0;
-  pstring name;
-  pstring newname;
-  char *p;
-
-  START_PROFILE(SMBmv);
-
-  p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
-  p++;
-  p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
-
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-  RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+       int outsize = 0;
+       pstring name;
+       pstring newname;
+       char *p;
+       NTSTATUS status;
 
-  DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+       START_PROFILE(SMBmv);
 
-  outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
-  if(outsize == 0) {
+       p = smb_buf(inbuf) + 1;
+       p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
+       p++;
+       p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+       
+       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+       
+       DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+       
+       status = rename_internals(conn, name, newname, False);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ERROR_NT(status);
+       }
 
        /*
-     * Win2k needs a changenotify request response before it will
-     * update after a rename..
-     */
-
-    process_pending_change_notify_queue((time_t)0);
-
-    outsize = set_message(outbuf,0,0,True);
-  }
+        * Win2k needs a changenotify request response before it will
+        * update after a rename..
+        */     
+       process_pending_change_notify_queue((time_t)0);
+       outsize = set_message(outbuf,0,0,True);
   
-  END_PROFILE(SMBmv);
-  return(outsize);
+       END_PROFILE(SMBmv);
+       return(outsize);
 }
 
 /*******************************************************************
-  copy a file as part of a reply_copy
-  ******************************************************************/
+ Copy a file as part of a reply_copy.
+******************************************************************/
 
 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
                      int count,BOOL target_is_directory, int *err_ret)
 {
-  int Access,action;
-  SMB_STRUCT_STAT src_sbuf, sbuf2;
-  SMB_OFF_T ret=-1;
-  files_struct *fsp1,*fsp2;
-  pstring dest;
+       int Access,action;
+       SMB_STRUCT_STAT src_sbuf, sbuf2;
+       SMB_OFF_T ret=-1;
+       files_struct *fsp1,*fsp2;
+       pstring dest;
   
-  *err_ret = 0;
+       *err_ret = 0;
 
-  pstrcpy(dest,dest1);
-  if (target_is_directory) {
-    char *p = strrchr(src,'/');
-    if (p) 
-      p++;
-    else
-      p = src;
-    pstrcat(dest,"/");
-    pstrcat(dest,p);
-  }
+       pstrcpy(dest,dest1);
+       if (target_is_directory) {
+               char *p = strrchr_m(src,'/');
+               if (p) 
+                       p++;
+               else
+                       p = src;
+               pstrcat(dest,"/");
+               pstrcat(dest,p);
+       }
 
-  if (!vfs_file_exist(conn,src,&src_sbuf))
-    return(False);
+       if (!vfs_file_exist(conn,src,&src_sbuf))
+               return(False);
 
-  fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
-                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
+       fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                       (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
 
-  if (!fsp1) {
-         return(False);
-  }
+       if (!fsp1)
+               return(False);
 
-  if (!target_is_directory && count)
-    ofun = FILE_EXISTS_OPEN;
+       if (!target_is_directory && count)
+               ofun = FILE_EXISTS_OPEN;
 
-  vfs_stat(conn,dest,&sbuf2);
-  fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
-                  ofun,src_sbuf.st_mode,0,&Access,&action);
+       if (vfs_stat(conn,dest,&sbuf2) == -1)
+               ZERO_STRUCTP(&sbuf2);
 
-  if (!fsp2) {
-    close_file(fsp1,False);
-    return(False);
-  }
+       fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
+                       ofun,src_sbuf.st_mode,0,&Access,&action);
 
-  if ((ofun&3) == 1) {
-    if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
-      DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
-               strerror(errno) ));
-      /*
-       * Stop the copy from occurring.
-       */
-      ret = -1;
-      src_sbuf.st_size = 0;
-    }
-  }
+       if (!fsp2) {
+               close_file(fsp1,False);
+               return(False);
+       }
+
+       if ((ofun&3) == 1) {
+               if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
+                       DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
+                       /*
+                        * Stop the copy from occurring.
+                        */
+                       ret = -1;
+                       src_sbuf.st_size = 0;
+               }
+       }
   
-  if (src_sbuf.st_size)
-    ret = vfs_transfer_file(-1, fsp1, -1, fsp2, src_sbuf.st_size, NULL, 0, 0);
+       if (src_sbuf.st_size)
+               ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
 
-  close_file(fsp1,False);
-  /*
-   * As we are opening fsp1 read-only we only expect
-   * an error on close on fsp2 if we are out of space.
-   * Thus we don't look at the error return from the
-   * close of fsp1.
-   */
-  *err_ret = close_file(fsp2,False);
+       close_file(fsp1,False);
 
-  return(ret == (SMB_OFF_T)src_sbuf.st_size);
-}
+       /* Ensure the modtime is set correctly on the destination file. */
+       fsp2->pending_modtime = src_sbuf.st_mtime;
 
+       /*
+        * As we are opening fsp1 read-only we only expect
+        * an error on close on fsp2 if we are out of space.
+        * Thus we don't look at the error return from the
+        * close of fsp1.
+        */
+       *err_ret = close_file(fsp2,False);
 
+       return(ret == (SMB_OFF_T)src_sbuf.st_size);
+}
 
 /****************************************************************************
   reply to a file copy.
@@ -4038,7 +3382,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     /* can't currently handle inter share copies XXXX */
     DEBUG(3,("Rejecting inter-share copy\n"));
     END_PROFILE(SMBcopy);
-    return(ERROR(ERRSRV,ERRinvdevice));
+    return ERROR_DOS(ERRSRV,ERRinvdevice);
   }
 
   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
@@ -4051,22 +3395,22 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
   if ((flags&1) && target_is_directory) {
     END_PROFILE(SMBcopy);
-    return(ERROR(ERRDOS,ERRbadfile));
+    return ERROR_DOS(ERRDOS,ERRbadfile);
   }
 
   if ((flags&2) && !target_is_directory) {
     END_PROFILE(SMBcopy);
-    return(ERROR(ERRDOS,ERRbadpath));
+    return ERROR_DOS(ERRDOS,ERRbadpath);
   }
 
   if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
     /* wants a tree copy! XXXX */
     DEBUG(3,("Rejecting tree copy\n"));
     END_PROFILE(SMBcopy);
-    return(ERROR(ERRSRV,ERRerror));    
+    return ERROR_DOS(ERRSRV,ERRerror);
   }
 
-  p = strrchr(name,'/');
+  p = strrchr_m(name,'/');
   if (!p) {
     pstrcpy(directory,"./");
     pstrcpy(mask,name);
@@ -4085,8 +3429,21 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
    * Tine Smukavec <valentin.smukavec@hermes.si>.
    */
 
-  if (!rc && is_mangled(mask))
-    check_mangled_cache( mask );
+#if 0
+       if (!rc && is_mangled(mask))
+               check_mangled_cache( mask );
+#endif
+       if (!rc)
+       {
+               char *unmangled;
+               
+               unmangled = dos_unmangle(mask);
+               if (unmangled)
+                       strncpy(mask, unmangled, strlen(unmangled) + 1);
+                       
+               SAFE_FREE(unmangled);
+       }
+
 
   has_wild = ms_has_wild(mask);
 
@@ -4145,7 +3502,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
     if (exists) {
       END_PROFILE(SMBcopy);
-      return(ERROR(ERRDOS,error));
+      return ERROR_DOS(ERRDOS,error);
     } else
     {
       if((errno == ENOENT) && (bad_path1 || bad_path2))
@@ -4179,11 +3536,10 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   snum = SNUM(conn);
   if (!CAN_SETDIR(snum)) {
     END_PROFILE(pathworks_setdir);
-    return(ERROR(ERRDOS,ERRnoaccess));
+    return ERROR_DOS(ERRDOS,ERRnoaccess);
   }
-  
-  pstrcpy(newdir,smb_buf(inbuf) + 1);
-  strlower(newdir);
+
+  srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE);
   
   if (strlen(newdir) == 0) {
          ok = True;
@@ -4196,11 +3552,11 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   
   if (!ok) {
          END_PROFILE(pathworks_setdir);
-         return(ERROR(ERRDOS,ERRbadpath));
+         return ERROR_DOS(ERRDOS,ERRbadpath);
   }
   
   outsize = set_message(outbuf,0,0,True);
-  CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
+  SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
   
   DEBUG(3,("setdir %s\n", newdir));
 
@@ -4208,6 +3564,18 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   return(outsize);
 }
 
+/****************************************************************************
+ Get a lock pid, dealing with large count requests.
+****************************************************************************/
+
+uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
+{
+       if(!large_file_format)
+               return SVAL(data,SMB_LPID_OFFSET(data_offset));
+       else
+               return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
+}
+
 /****************************************************************************
  Get a lock count, dealing with large count requests.
 ****************************************************************************/
@@ -4246,506 +3614,347 @@ SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format
   return count;
 }
 
+#if !defined(HAVE_LONGLONG)
 /****************************************************************************
- Get a lock offset, dealing with large offset requests.
-****************************************************************************/
-
-SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
-{
-  SMB_BIG_UINT offset = 0;
-
-  *err = False;
-
-  if(!large_file_format) {
-    offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
-  } else {
-
-#if defined(HAVE_LONGLONG)
-    offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
-            ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
-#else /* HAVE_LONGLONG */
-
-    /*
-     * NT4.x seems to be broken in that it sends large file (64 bit)
-     * lockingX calls even if the CAP_LARGE_FILES was *not*
-     * negotiated. For boxes without large unsigned ints mangle the
-     * lock offset by mapping the top 32 bits onto the lower 32.
-     */
-      
-    if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
-      uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
-      uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
-      uint32 new_low = 0;
-
-      if((new_low = map_lock_offset(high, low)) == 0) {
-        *err = True;
-        return (SMB_BIG_UINT)-1;
-      }
-
-      DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
-            (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
-      SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
-      SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
-    }
-
-    offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
-#endif /* HAVE_LONGLONG */
-  }
-
-  return offset;
-}
-
-/****************************************************************************
-  reply to a lockingX request
+ Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
 ****************************************************************************/
-
-int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+static uint32 map_lock_offset(uint32 high, uint32 low)
 {
-  files_struct *fsp = file_fsp(inbuf,smb_vwv2);
-  unsigned char locktype = CVAL(inbuf,smb_vwv3);
-  unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
-  uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
-  uint16 num_locks = SVAL(inbuf,smb_vwv7);
-  SMB_BIG_UINT count = 0, offset = 0;
-  int32 lock_timeout = IVAL(inbuf,smb_vwv4);
-  int i;
-  char *data;
-  uint32 ecode=0, dummy2;
-  int eclass=0, dummy1;
-  BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
-  BOOL err;
-  START_PROFILE(SMBlockingX);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_ERROR(fsp);
-
-  data = smb_buf(inbuf);
-
-  /* Check if this is an oplock break on a file
-     we have granted an oplock on.
-   */
-  if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
-  {
-       /* Client can insist on breaking to none. */
-       BOOL break_to_none = (oplocklevel == 0);
-
-    DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
-              fsp->fnum, (unsigned int)oplocklevel ));
-
-    /*
-     * Make sure we have granted an exclusive or batch oplock on this file.
-     */
-
-    if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-    {
-      DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
-no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
-
-      /* if this is a pure oplock break request then don't send a reply */
-      if (num_locks == 0 && num_ulocks == 0) {
-       END_PROFILE(SMBlockingX);
-        return -1;
-      } else {
-       END_PROFILE(SMBlockingX);
-        return ERROR(ERRDOS,ERRlock);
-      }
-    }
-
-    if (remove_oplock(fsp, break_to_none) == False) {
-      DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
-            fsp->fsp_name ));
-    }
-
-    /* if this is a pure oplock break request then don't send a reply */
-    if (num_locks == 0 && num_ulocks == 0)
-    {
-      /* Sanity check - ensure a pure oplock break is not a
-         chained request. */
-      if(CVAL(inbuf,smb_vwv0) != 0xff)
-        DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
-                 (unsigned int)CVAL(inbuf,smb_vwv0) ));
-      END_PROFILE(SMBlockingX);
-      return -1;
-    }
-  }
-
-  /*
-   * We do this check *after* we have checked this is not a oplock break
-   * response message. JRA.
-   */
-
-  release_level_2_oplocks_on_change(fsp);
-
-  /* Data now points at the beginning of the list
-     of smb_unlkrng structs */
-  for(i = 0; i < (int)num_ulocks; i++) {
-    count = get_lock_count( data, i, large_file_format);
-    offset = get_lock_offset( data, i, large_file_format, &err);
-
-    /*
-     * There is no error code marked "stupid client bug".... :-).
-     */
-    if(err) {
-      END_PROFILE(SMBlockingX);
-      return ERROR(ERRDOS,ERRnoaccess);
-    }
-
-    DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
-          (double)offset, (double)count, fsp->fsp_name ));
-
-    if(!do_unlock(fsp,conn,count,offset, &eclass, &ecode)) {
-      END_PROFILE(SMBlockingX);
-      return ERROR(eclass,ecode);
-    }
-  }
-
-  /* Setup the timeout in seconds. */
-  lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
-
-  /* Now do any requested locks */
-  data += ((large_file_format ? 20 : 10)*num_ulocks);
-
-  /* Data now points at the beginning of the list
-     of smb_lkrng structs */
-
-  for(i = 0; i < (int)num_locks; i++) {
-    count = get_lock_count( data, i, large_file_format);
-    offset = get_lock_offset( data, i, large_file_format, &err);
-
-    /*
-     * There is no error code marked "stupid client bug".... :-).
-     */
-    if(err) {
-      END_PROFILE(SMBlockingX);
-      return ERROR(ERRDOS,ERRnoaccess);
-    }
-    DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
-          (double)offset, (double)count, fsp->fsp_name ));
-
-    if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
-                &eclass, &ecode)) {
-      if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
-        /*
-         * A blocking lock was requested. Package up
-         * this smb into a queued request and push it
-         * onto the blocking lock queue.
-         */
-        if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) {
-         END_PROFILE(SMBlockingX);
-          return -1;
-       }
-      }
-      break;
-    }
-  }
-
-  /* If any of the above locks failed, then we must unlock
-     all of the previous locks (X/Open spec). */
-  if(i != num_locks && num_locks != 0) {
-    /*
-     * Ensure we don't do a remove on the lock that just failed,
-     * as under POSIX rules, if we have a lock already there, we
-     * will delete it (and we shouldn't) .....
-     */
-    for(i--; i >= 0; i--) {
-      count = get_lock_count( data, i, large_file_format);
-      offset = get_lock_offset( data, i, large_file_format, &err);
-
-      /*
-       * There is no error code marked "stupid client bug".... :-).
-       */
-      if(err) {
-       END_PROFILE(SMBlockingX);
-        return ERROR(ERRDOS,ERRnoaccess);
-      }
+       unsigned int i;
+       uint32 mask = 0;
+       uint32 highcopy = high;
  
-      do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
-    }
-    END_PROFILE(SMBlockingX);
-    return ERROR(eclass,ecode);
-  }
-
-  set_message(outbuf,2,0,True);
-  
-  DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
-       fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
-
-  END_PROFILE(SMBlockingX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
-}
-
-
-/****************************************************************************
-  reply to a SMBreadbmpx (read block multiplex) request
-****************************************************************************/
-int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
-  ssize_t nread = -1;
-  ssize_t total_read;
-  char *data;
-  SMB_OFF_T startpos;
-  int outsize;
-  size_t maxcount;
-  int max_per_packet;
-  size_t tcount;
-  int pad;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBreadBmpx);
-
-  /* this function doesn't seem to work - disable by default */
-  if (!lp_readbmpx()) {
-    END_PROFILE(SMBreadBmpx);
-    return(ERROR(ERRSRV,ERRuseSTD));
-  }
-
-  outsize = set_message(outbuf,8,0,True);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_READ(fsp);
-  CHECK_ERROR(fsp);
-
-  startpos = IVAL(inbuf,smb_vwv1);
-  maxcount = SVAL(inbuf,smb_vwv3);
-
-  data = smb_buf(outbuf);
-  pad = ((long)data)%4;
-  if (pad) pad = 4 - pad;
-  data += pad;
+       /*
+        * Try and find out how many significant bits there are in high.
+        */
+       for(i = 0; highcopy; i++)
+               highcopy >>= 1;
+       /*
+        * We use 31 bits not 32 here as POSIX
+        * lock offsets may not be negative.
+        */
+       mask = (~0) << (31 - i);
+       if(low & mask)
+               return 0; /* Fail. */
+       high <<= (31 - i);
+       return (high|low);
+}
+#endif /* !defined(HAVE_LONGLONG) */
 
-  max_per_packet = bufsize-(outsize+pad);
-  tcount = maxcount;
-  total_read = 0;
+/****************************************************************************
+ Get a lock offset, dealing with large offset requests.
+****************************************************************************/
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
-    END_PROFILE(SMBreadBmpx);
-    return(ERROR(ERRDOS,ERRlock));
-  }
+SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
+{
+  SMB_BIG_UINT offset = 0;
 
-  do
-    {
-      size_t N = MIN(max_per_packet,tcount-total_read);
-  
-      nread = read_file(fsp,data,startpos,N);
+  *err = False;
 
-      if (nread <= 0) nread = 0;
+  if(!large_file_format) {
+    offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
+  } else {
 
-      if (nread < (ssize_t)N)
-        tcount = total_read + nread;
+#if defined(HAVE_LONGLONG)
+    offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+            ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
 
-      set_message(outbuf,8,nread,False);
-      SIVAL(outbuf,smb_vwv0,startpos);
-      SSVAL(outbuf,smb_vwv2,tcount);
-      SSVAL(outbuf,smb_vwv6,nread);
-      SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
+    /*
+     * NT4.x seems to be broken in that it sends large file (64 bit)
+     * lockingX calls even if the CAP_LARGE_FILES was *not*
+     * negotiated. For boxes without large unsigned ints mangle the
+     * lock offset by mapping the top 32 bits onto the lower 32.
+     */
+      
+    if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
+      uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+      uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+      uint32 new_low = 0;
 
-      send_smb(smbd_server_fd(),outbuf);
+      if((new_low = map_lock_offset(high, low)) == 0) {
+        *err = True;
+        return (SMB_BIG_UINT)-1;
+      }
 
-      total_read += nread;
-      startpos += nread;
+      DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
+            (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
+      SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
+      SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
     }
-  while (total_read < (ssize_t)tcount);
 
-  END_PROFILE(SMBreadBmpx);
-  return(-1);
+    offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+  }
+
+  return offset;
 }
 
 /****************************************************************************
-  reply to a SMBwritebmpx (write block multiplex primary) request
+  reply to a lockingX request
 ****************************************************************************/
 
-int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-  size_t numtowrite;
-  ssize_t nwritten = -1;
-  int outsize = 0;
-  SMB_OFF_T startpos;
-  size_t tcount;
-  BOOL write_through;
-  int smb_doff;
-  char *data;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBwriteBmpx);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
-  CHECK_ERROR(fsp);
-
-  tcount = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv3);
-  write_through = BITSETW(inbuf+smb_vwv7,0);
-  numtowrite = SVAL(inbuf,smb_vwv10);
-  smb_doff = SVAL(inbuf,smb_vwv11);
+       files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+       unsigned char locktype = CVAL(inbuf,smb_vwv3);
+       unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+       uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
+       uint16 num_locks = SVAL(inbuf,smb_vwv7);
+       SMB_BIG_UINT count = 0, offset = 0;
+       uint16 lock_pid;
+       int32 lock_timeout = IVAL(inbuf,smb_vwv4);
+       int i;
+       char *data;
+       BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
+       BOOL err;
+       NTSTATUS status;
 
-  data = smb_base(inbuf) + smb_doff;
+       START_PROFILE(SMBlockingX);
+       
+       CHECK_FSP(fsp,conn);
+       
+       data = smb_buf(inbuf);
+       
+       /* Check if this is an oplock break on a file
+          we have granted an oplock on.
+       */
+       if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
+               /* Client can insist on breaking to none. */
+               BOOL break_to_none = (oplocklevel == 0);
+               
+               DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
+                        (unsigned int)oplocklevel, fsp->fnum ));
 
-  /* If this fails we need to send an SMBwriteC response,
-     not an SMBwritebmpx - set this up now so we don't forget */
-  CVAL(outbuf,smb_com) = SMBwritec;
+               /*
+                * Make sure we have granted an exclusive or batch oplock on this file.
+                */
+               
+               if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+                       DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
-    END_PROFILE(SMBwriteBmpx);
-    return(ERROR(ERRDOS,ERRlock));
-  }
+                       /* if this is a pure oplock break request then don't send a reply */
+                       if (num_locks == 0 && num_ulocks == 0) {
+                               END_PROFILE(SMBlockingX);
+                               return -1;
+                       } else {
+                               END_PROFILE(SMBlockingX);
+                               return ERROR_DOS(ERRDOS,ERRlock);
+                       }
+               }
 
-  nwritten = write_file(fsp,data,startpos,numtowrite);
+               if (remove_oplock(fsp, break_to_none) == False) {
+                       DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
+                                fsp->fsp_name ));
+               }
+               
+               /* if this is a pure oplock break request then don't send a reply */
+               if (num_locks == 0 && num_ulocks == 0) {
+                       /* Sanity check - ensure a pure oplock break is not a
+                          chained request. */
+                       if(CVAL(inbuf,smb_vwv0) != 0xff)
+                               DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+                                        (unsigned int)CVAL(inbuf,smb_vwv0) ));
+                       END_PROFILE(SMBlockingX);
+                       return -1;
+               }
+       }
 
-  if(lp_syncalways(SNUM(conn)) || write_through)
-      sync_file(conn,fsp);
-  
-  if(nwritten < (ssize_t)numtowrite) {
-    END_PROFILE(SMBwriteBmpx);
-    return(UNIXERROR(ERRHRD,ERRdiskfull));
-  }
+       /*
+        * We do this check *after* we have checked this is not a oplock break
+        * response message. JRA.
+        */
+       
+       release_level_2_oplocks_on_change(fsp);
+       
+       /* Data now points at the beginning of the list
+          of smb_unlkrng structs */
+       for(i = 0; i < (int)num_ulocks; i++) {
+               lock_pid = get_lock_pid( data, i, large_file_format);
+               count = get_lock_count( data, i, large_file_format);
+               offset = get_lock_offset( data, i, large_file_format, &err);
+               
+               /*
+                * There is no error code marked "stupid client bug".... :-).
+                */
+               if(err) {
+                       END_PROFILE(SMBlockingX);
+                       return ERROR_DOS(ERRDOS,ERRnoaccess);
+               }
 
-  /* If the maximum to be written to this file
-     is greater than what we just wrote then set
-     up a secondary struct to be attached to this
-     fd, we will use this to cache error messages etc. */
-  if((ssize_t)tcount > nwritten) 
-  {
-    write_bmpx_struct *wbms;
-    if(fsp->wbmpx_ptr != NULL)
-      wbms = fsp->wbmpx_ptr; /* Use an existing struct */
-    else
-      wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
-    if(!wbms)
-    {
-      DEBUG(0,("Out of memory in reply_readmpx\n"));
-      END_PROFILE(SMBwriteBmpx);
-      return(ERROR(ERRSRV,ERRnoresource));
-    }
-    wbms->wr_mode = write_through;
-    wbms->wr_discard = False; /* No errors yet */
-    wbms->wr_total_written = nwritten;
-    wbms->wr_errclass = 0;
-    wbms->wr_error = 0;
-    fsp->wbmpx_ptr = wbms;
-  }
+               DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
+                         (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+               
+               status = do_unlock(fsp,conn,lock_pid,count,offset);
+               if (NT_STATUS_V(status)) {
+                       END_PROFILE(SMBlockingX);
+                       return ERROR_NT(status);
+               }
+       }
 
-  /* We are returning successfully, set the message type back to
-     SMBwritebmpx */
-  CVAL(outbuf,smb_com) = SMBwriteBmpx;
-  
-  outsize = set_message(outbuf,1,0,True);
-  
-  SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
-  
-  DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
-           fsp->fnum, (int)numtowrite, (int)nwritten ) );
-
-  if (write_through && tcount==nwritten) {
-    /* we need to send both a primary and a secondary response */
-    smb_setlen(outbuf,outsize - 4);
-    send_smb(smbd_server_fd(),outbuf);
-
-    /* now the secondary */
-    outsize = set_message(outbuf,1,0,True);
-    CVAL(outbuf,smb_com) = SMBwritec;
-    SSVAL(outbuf,smb_vwv0,nwritten);
-  }
+       /* Setup the timeout in seconds. */
+       lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+       
+       /* Now do any requested locks */
+       data += ((large_file_format ? 20 : 10)*num_ulocks);
+       
+       /* Data now points at the beginning of the list
+          of smb_lkrng structs */
+       
+       for(i = 0; i < (int)num_locks; i++) {
+               lock_pid = get_lock_pid( data, i, large_file_format);
+               count = get_lock_count( data, i, large_file_format);
+               offset = get_lock_offset( data, i, large_file_format, &err);
+               
+               /*
+                * There is no error code marked "stupid client bug".... :-).
+                */
+               if(err) {
+                       END_PROFILE(SMBlockingX);
+                       return ERROR_DOS(ERRDOS,ERRnoaccess);
+               }
+               
+               DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n",
+                         (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+               
+               status = do_lock(fsp,conn,lock_pid, count,offset, 
+                                ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
+               if (NT_STATUS_V(status)) {
+                       if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
+                               /*
+                                * A blocking lock was requested. Package up
+                                * this smb into a queued request and push it
+                                * onto the blocking lock queue.
+                                */
+                               if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) {
+                                       END_PROFILE(SMBlockingX);
+                                       return -1;
+                               }
+                       }
+                       break;
+               }
+       }
+       
+       /* If any of the above locks failed, then we must unlock
+          all of the previous locks (X/Open spec). */
+       if (i != num_locks && num_locks != 0) {
+               /*
+                * Ensure we don't do a remove on the lock that just failed,
+                * as under POSIX rules, if we have a lock already there, we
+                * will delete it (and we shouldn't) .....
+                */
+               for(i--; i >= 0; i--) {
+                       lock_pid = get_lock_pid( data, i, large_file_format);
+                       count = get_lock_count( data, i, large_file_format);
+                       offset = get_lock_offset( data, i, large_file_format, &err);
+                       
+                       /*
+                        * There is no error code marked "stupid client bug".... :-).
+                        */
+                       if(err) {
+                               END_PROFILE(SMBlockingX);
+                               return ERROR_DOS(ERRDOS,ERRnoaccess);
+                       }
+                       
+                       do_unlock(fsp,conn,lock_pid,count,offset);
+               }
+               END_PROFILE(SMBlockingX);
+               return ERROR_NT(status);
+       }
 
-  END_PROFILE(SMBwriteBmpx);
-  return(outsize);
+       set_message(outbuf,2,0,True);
+       
+       DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+                   fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
+       
+       END_PROFILE(SMBlockingX);
+       return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
-
 /****************************************************************************
-  reply to a SMBwritebs (write block multiplex secondary) request
+ Reply to a SMBreadbmpx (read block multiplex) request.
 ****************************************************************************/
-int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
-{
-  size_t numtowrite;
-  ssize_t nwritten = -1;
-  int outsize = 0;
-  SMB_OFF_T startpos;
-  size_t tcount;
-  BOOL write_through;
-  int smb_doff;
-  char *data;
-  write_bmpx_struct *wbms;
-  BOOL send_response = False; 
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBwriteBs);
 
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
+int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
+{
+       ssize_t nread = -1;
+       ssize_t total_read;
+       char *data;
+       SMB_OFF_T startpos;
+       int outsize;
+       size_t maxcount;
+       int max_per_packet;
+       size_t tcount;
+       int pad;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBreadBmpx);
 
-  tcount = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv2);
-  numtowrite = SVAL(inbuf,smb_vwv6);
-  smb_doff = SVAL(inbuf,smb_vwv7);
+       /* this function doesn't seem to work - disable by default */
+       if (!lp_readbmpx()) {
+               END_PROFILE(SMBreadBmpx);
+               return ERROR_DOS(ERRSRV,ERRuseSTD);
+       }
 
-  data = smb_base(inbuf) + smb_doff;
+       outsize = set_message(outbuf,8,0,True);
 
-  /* We need to send an SMBwriteC response, not an SMBwritebs */
-  CVAL(outbuf,smb_com) = SMBwritec;
+       CHECK_FSP(fsp,conn);
+       CHECK_READ(fsp);
 
-  /* This fd should have an auxiliary struct attached,
-     check that it does */
-  wbms = fsp->wbmpx_ptr;
-  if(!wbms) {
-    END_PROFILE(SMBwriteBs);
-    return(-1);
-  }
+       startpos = IVAL(inbuf,smb_vwv1);
+       maxcount = SVAL(inbuf,smb_vwv3);
 
-  /* If write through is set we can return errors, else we must
-     cache them */
-  write_through = wbms->wr_mode;
+       data = smb_buf(outbuf);
+       pad = ((long)data)%4;
+       if (pad)
+               pad = 4 - pad;
+       data += pad;
 
-  /* Check for an earlier error */
-  if(wbms->wr_discard) {
-    END_PROFILE(SMBwriteBs);
-    return -1; /* Just discard the packet */
-  }
+       max_per_packet = bufsize-(outsize+pad);
+       tcount = maxcount;
+       total_read = 0;
 
-  nwritten = write_file(fsp,data,startpos,numtowrite);
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               END_PROFILE(SMBreadBmpx);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-  if(lp_syncalways(SNUM(conn)) || write_through)
-    sync_file(conn,fsp);
+       do {
+               size_t N = MIN(max_per_packet,tcount-total_read);
   
-  if (nwritten < (ssize_t)numtowrite)
-  {
-    if(write_through)
-    {
-      /* We are returning an error - we can delete the aux struct */
-      if (wbms) free((char *)wbms);
-      fsp->wbmpx_ptr = NULL;
-      END_PROFILE(SMBwriteBs);
-      return(ERROR(ERRHRD,ERRdiskfull));
-    }
-    END_PROFILE(SMBwriteBs);
-    return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
-  }
+               nread = read_file(fsp,data,startpos,N);
 
-  /* Increment the total written, if this matches tcount
-     we can discard the auxiliary struct (hurrah !) and return a writeC */
-  wbms->wr_total_written += nwritten;
-  if(wbms->wr_total_written >= tcount)
-  {
-    if (write_through)
-    {
-      outsize = set_message(outbuf,1,0,True);
-      SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
-      send_response = True;
-    }
+               if (nread <= 0)
+                       nread = 0;
 
-    free((char *)wbms);
-    fsp->wbmpx_ptr = NULL;
-  }
+               if (nread < (ssize_t)N)
+                       tcount = total_read + nread;
 
-  if(send_response) {
-    END_PROFILE(SMBwriteBs);
-    return(outsize);
-  }
+               set_message(outbuf,8,nread,False);
+               SIVAL(outbuf,smb_vwv0,startpos);
+               SSVAL(outbuf,smb_vwv2,tcount);
+               SSVAL(outbuf,smb_vwv6,nread);
+               SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
 
-  END_PROFILE(SMBwriteBs);
-  return(-1);
-}
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("reply_readbmpx: send_smb failed.");
 
+               total_read += nread;
+               startpos += nread;
+       } while (total_read < (ssize_t)tcount);
+
+       END_PROFILE(SMBreadBmpx);
+       return(-1);
+}
 
 /****************************************************************************
-  reply to a SMBsetattrE
+ Reply to a SMBsetattrE.
 ****************************************************************************/
 
 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
@@ -4758,7 +3967,6 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
   outsize = set_message(outbuf,0,0,True);
 
   CHECK_FSP(fsp,conn);
-  CHECK_ERROR(fsp);
 
   /* Convert the DOS times into unix times. Ignore create
      time as UNIX can't set this.
@@ -4791,7 +3999,7 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
   /* Set the date on this file */
   if(file_utime(conn, fsp->fsp_name, &unix_times)) {
     END_PROFILE(SMBsetattrE);
-    return(ERROR(ERRDOS,ERRnoaccess));
+    return ERROR_DOS(ERRDOS,ERRnoaccess);
   }
   
   DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
@@ -4802,8 +4010,199 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
 }
 
 
+/* Back from the dead for OS/2..... JRA. */
+
+/****************************************************************************
+ Reply to a SMBwritebmpx (write block multiplex primary) request.
+****************************************************************************/
+
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+       size_t numtowrite;
+       ssize_t nwritten = -1;
+       int outsize = 0;
+       SMB_OFF_T startpos;
+       size_t tcount;
+       BOOL write_through;
+       int smb_doff;
+       char *data;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBwriteBmpx);
+
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
+       CHECK_ERROR(fsp);
+
+       tcount = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv3);
+       write_through = BITSETW(inbuf+smb_vwv7,0);
+       numtowrite = SVAL(inbuf,smb_vwv10);
+       smb_doff = SVAL(inbuf,smb_vwv11);
+
+       data = smb_base(inbuf) + smb_doff;
+
+       /* If this fails we need to send an SMBwriteC response,
+               not an SMBwritebmpx - set this up now so we don't forget */
+       SCVAL(outbuf,smb_com,SMBwritec);
+
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
+               END_PROFILE(SMBwriteBmpx);
+               return(ERROR_DOS(ERRDOS,ERRlock));
+       }
+
+       nwritten = write_file(fsp,data,startpos,numtowrite);
+
+       if(lp_syncalways(SNUM(conn)) || write_through)
+               sync_file(conn,fsp);
+  
+       if(nwritten < (ssize_t)numtowrite) {
+               END_PROFILE(SMBwriteBmpx);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
+
+       /* If the maximum to be written to this file
+               is greater than what we just wrote then set
+               up a secondary struct to be attached to this
+               fd, we will use this to cache error messages etc. */
+
+       if((ssize_t)tcount > nwritten) {
+               write_bmpx_struct *wbms;
+               if(fsp->wbmpx_ptr != NULL)
+                       wbms = fsp->wbmpx_ptr; /* Use an existing struct */
+               else
+                       wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
+               if(!wbms) {
+                       DEBUG(0,("Out of memory in reply_readmpx\n"));
+                       END_PROFILE(SMBwriteBmpx);
+                       return(ERROR_DOS(ERRSRV,ERRnoresource));
+               }
+               wbms->wr_mode = write_through;
+               wbms->wr_discard = False; /* No errors yet */
+               wbms->wr_total_written = nwritten;
+               wbms->wr_errclass = 0;
+               wbms->wr_error = 0;
+               fsp->wbmpx_ptr = wbms;
+       }
+
+       /* We are returning successfully, set the message type back to
+               SMBwritebmpx */
+       SCVAL(outbuf,smb_com,SMBwriteBmpx);
+  
+       outsize = set_message(outbuf,1,0,True);
+  
+       SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
+  
+       DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
+                       fsp->fnum, (int)numtowrite, (int)nwritten ) );
+
+       if (write_through && tcount==nwritten) {
+               /* We need to send both a primary and a secondary response */
+               smb_setlen(outbuf,outsize - 4);
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("reply_writebmpx: send_smb failed.");
+
+               /* Now the secondary */
+               outsize = set_message(outbuf,1,0,True);
+               SCVAL(outbuf,smb_com,SMBwritec);
+               SSVAL(outbuf,smb_vwv0,nwritten);
+       }
+
+       END_PROFILE(SMBwriteBmpx);
+       return(outsize);
+}
+
+/****************************************************************************
+ Reply to a SMBwritebs (write block multiplex secondary) request.
+****************************************************************************/
+
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+       size_t numtowrite;
+       ssize_t nwritten = -1;
+       int outsize = 0;
+       SMB_OFF_T startpos;
+       size_t tcount;
+       BOOL write_through;
+       int smb_doff;
+       char *data;
+       write_bmpx_struct *wbms;
+       BOOL send_response = False; 
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBwriteBs);
+
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
+
+       tcount = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv2);
+       numtowrite = SVAL(inbuf,smb_vwv6);
+       smb_doff = SVAL(inbuf,smb_vwv7);
+
+       data = smb_base(inbuf) + smb_doff;
+
+       /* We need to send an SMBwriteC response, not an SMBwritebs */
+       SCVAL(outbuf,smb_com,SMBwritec);
+
+       /* This fd should have an auxiliary struct attached,
+               check that it does */
+       wbms = fsp->wbmpx_ptr;
+       if(!wbms) {
+               END_PROFILE(SMBwriteBs);
+               return(-1);
+       }
+
+       /* If write through is set we can return errors, else we must cache them */
+       write_through = wbms->wr_mode;
+
+       /* Check for an earlier error */
+       if(wbms->wr_discard) {
+               END_PROFILE(SMBwriteBs);
+               return -1; /* Just discard the packet */
+       }
+
+       nwritten = write_file(fsp,data,startpos,numtowrite);
+
+       if(lp_syncalways(SNUM(conn)) || write_through)
+               sync_file(conn,fsp);
+  
+       if (nwritten < (ssize_t)numtowrite) {
+               if(write_through) {
+                       /* We are returning an error - we can delete the aux struct */
+                       if (wbms)
+                               free((char *)wbms);
+                       fsp->wbmpx_ptr = NULL;
+                       END_PROFILE(SMBwriteBs);
+                       return(ERROR_DOS(ERRHRD,ERRdiskfull));
+               }
+               END_PROFILE(SMBwriteBs);
+               return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+       }
+
+       /* Increment the total written, if this matches tcount
+               we can discard the auxiliary struct (hurrah !) and return a writeC */
+       wbms->wr_total_written += nwritten;
+       if(wbms->wr_total_written >= tcount) {
+               if (write_through) {
+                       outsize = set_message(outbuf,1,0,True);
+                       SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
+                       send_response = True;
+               }
+
+               free((char *)wbms);
+               fsp->wbmpx_ptr = NULL;
+       }
+
+       if(send_response) {
+               END_PROFILE(SMBwriteBs);
+               return(outsize);
+       }
+
+       END_PROFILE(SMBwriteBs);
+       return(-1);
+}
+
 /****************************************************************************
-  reply to a SMBgetattrE
+ Reply to a SMBgetattrE.
 ****************************************************************************/
 
 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
@@ -4817,7 +4216,6 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
   outsize = set_message(outbuf,11,0,True);
 
   CHECK_FSP(fsp,conn);
-  CHECK_ERROR(fsp);
 
   /* Do an fstat on this file */
   if(vfs_fstat(fsp,fsp->fd, &sbuf)) {