win9x was suffered a case of the blues during a domain logon.
[kai/samba.git] / source / smbd / reply.c
index 334a48e338568dbe0eaf5d2cee92fe7cad0c71c6..1a1c84efed590996cf17ee82caeb0e5b1a0a9ee0 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   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
@@ -24,7 +23,6 @@
    makes to handle specific protocols
 */
 
-
 #include "includes.h"
 
 /* look in server.c for some explanation of these variables */
@@ -35,32 +33,13 @@ 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 int global_oplock_break;
-uint32 global_client_caps = 0;
 unsigned int smb_echo_count = 0;
 
-extern fstring remote_machine;
 extern BOOL global_encrypted_passwords_negotiated;
 
 /****************************************************************************
-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() );
-       }
-}
-
-
-/****************************************************************************
-  reply to an special message 
+ Reply to an special message.
 ****************************************************************************/
 
 int reply_special(char *inbuf,char *outbuf)
@@ -70,10 +49,11 @@ int reply_special(char *inbuf,char *outbuf)
        int msg_flags = CVAL(inbuf,1);
        pstring name1,name2;
 
-       extern fstring local_machine;
        int len;
        char name_type = 0;
        
+       static BOOL already_got_session = False;
+
        *name1 = *name2 = 0;
        
        memset(outbuf,'\0',smb_size);
@@ -82,8 +62,13 @@ int reply_special(char *inbuf,char *outbuf)
        
        switch (msg_type) {
        case 0x81: /* session request */
-               CVAL(outbuf,0) = 0x82;
-               CVAL(outbuf,3) = 0;
+               
+               if (already_got_session) {
+                       exit_server("multiple session request not permitted");
+               }
+               
+               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"));
@@ -94,29 +79,24 @@ int reply_special(char *inbuf,char *outbuf)
                DEBUG(2,("netbios connect: name1=%s name2=%s\n",
                         name1,name2));      
 
-               fstrcpy(remote_machine,name2);
-               remote_machine[15] = 0;
-               trim_string(remote_machine," "," ");
-               strlower(remote_machine);
-               alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
+               name1[15] = 0;
 
-               fstrcpy(local_machine,name1);
-               len = strlen(local_machine);
+               len = strlen(name2);
                if (len == 16) {
-                       name_type = local_machine[15];
-                       local_machine[15] = 0;
+                       name_type = name2[15];
+                       name2[15] = 0;
                }
-               trim_string(local_machine," "," ");
-               strlower(local_machine);
-               alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
+
+               set_local_machine_name(name1, True);
+               set_remote_machine_name(name2, True);
 
                DEBUG(2,("netbios connect: local=%s remote=%s\n",
-                       local_machine, remote_machine ));
+                       get_local_machine_name(), get_remote_machine_name() ));
 
                if (name_type == 'R') {
                        /* We are being asked for a pathworks session --- 
                           no thanks! */
-                       CVAL(outbuf, 0) = 0x83;
+                       SCVAL(outbuf, 0,0x83);
                        break;
                }
 
@@ -124,20 +104,21 @@ int reply_special(char *inbuf,char *outbuf)
                   of possibly valid usernames if we are operating
                   in share mode security */
                if (lp_security() == SEC_SHARE) {
-                       add_session_user(remote_machine);
+                       add_session_user(get_remote_machine_name());
                }
 
                reload_services(True);
                reopen_logs();
 
-               claim_connection(NULL,"",MAXSTATUS,True);
+               claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
 
+               already_got_session = 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 */
@@ -146,7 +127,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);
        }
@@ -157,7 +138,6 @@ int reply_special(char *inbuf,char *outbuf)
        return(outsize);
 }
 
-
 /****************************************************************************
  Reply to a tcon.
 ****************************************************************************/
@@ -165,30 +145,39 @@ int reply_special(char *inbuf,char *outbuf)
 int reply_tcon(connection_struct *conn,
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       pstring service;
+       const char *service;
+       pstring service_buf;
        pstring password;
-       pstring dev;
+       fstring dev;
        int outsize = 0;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int pwlen=0;
        NTSTATUS nt_status;
        char *p;
-
+       DATA_BLOB password_blob;
+       
        START_PROFILE(SMBtcon);
 
-       *service = *password = *dev = 0;
+       *service_buf = *password = *dev = 0;
 
        p = smb_buf(inbuf)+1;
-       p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
-       p += srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
-       p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
+       p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service_buf), STR_TERMINATE) + 1;
+       pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1;
+       p += pwlen;
+       p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1;
 
-       p = strrchr_m(service,'\\');
+       p = strrchr_m(service_buf,'\\');
        if (p) {
-               pstrcpy(service, p+1);
+               service = p+1;
+       } else {
+               service = service_buf;
        }
 
-       conn = make_connection(service,password,pwlen,dev,vuid,&nt_status);
+       password_blob = data_blob(password, pwlen+1);
+
+       conn = make_connection(service,password_blob,dev,vuid,&nt_status);
+
+       data_blob_clear_free(&password_blob);
   
        if (!conn) {
                END_PROFILE(SMBtcon);
@@ -214,16 +203,17 @@ int reply_tcon(connection_struct *conn,
 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
        fstring service;
-       pstring password;
-       pstring devicename;
+       DATA_BLOB password;
+       fstring devicename;
        NTSTATUS nt_status;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
        pstring path;
        char *p, *q;
-       START_PROFILE(SMBtconX);
-       
-       *service = *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) {
@@ -231,21 +221,20 @@ 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));
+               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);
+       p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
 
-       if (passlen != 24) {
-               if (strequal(password," "))
-                       *password = 0;
-               passlen = strlen(password);
-       }
-       
        /*
         * the service name can be either: \\server\share
         * or share directly like on the DELL PowerVault 705
@@ -265,8 +254,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 
        DEBUG(4,("Got device type %s\n",devicename));
 
-       conn = make_connection(service,password,passlen,devicename,vuid,&nt_status);
+       conn = make_connection(service,password,devicename,vuid,&nt_status);
        
+       data_blob_clear_free(&password);
+
        if (!conn) {
                END_PROFILE(SMBtconX);
                return ERROR_NT(nt_status);
@@ -280,12 +271,25 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                set_message_end(outbuf,p);
        } else {
                /* NT sets the fstype of IPC$ to the null string */
-               char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+               const char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+               const char *devicetype;
 
                set_message(outbuf,3,0,True);
-
+               if ( IS_IPC(conn) )
+                       devicetype = "IPC";
+               else if ( IS_PRINT(conn) )
+                       devicetype = "LPT:";
+               else 
+                       devicetype = "A:";
+
+               p = smb_buf(outbuf);
+               p += srvstr_push(outbuf, p, IS_IPC(conn) ? "IPC" : devicetype, -1, 
+                                STR_TERMINATE|STR_ASCII);
+               p += srvstr_push(outbuf, p, fsname, -1, 
+                                STR_TERMINATE);
                p = smb_buf(outbuf);
-               p += srvstr_push(outbuf, p, devicename, -1, 
+               p += srvstr_push(outbuf, p, IS_IPC(conn) ? "IPC" : devicename, -1, 
                                 STR_TERMINATE|STR_ASCII);
                p += srvstr_push(outbuf, p, fsname, -1, 
                                 STR_TERMINATE);
@@ -294,7 +298,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
-               SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS); 
+               SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
+                               (lp_csc_policy(SNUM(conn)) << 2));
                
                init_dfsroot(conn, inbuf, outbuf);
        }
@@ -311,10 +316,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
-
 /****************************************************************************
-  reply to an unknown type
+ Reply to an unknown type.
 ****************************************************************************/
+
 int reply_unknown(char *inbuf,char *outbuf)
 {
        int type;
@@ -326,10 +331,10 @@ int reply_unknown(char *inbuf,char *outbuf)
        return(ERROR_DOS(ERRSRV,ERRunknownsmb));
 }
 
-
 /****************************************************************************
-  reply to an ioctl
+ Reply to an ioctl.
 ****************************************************************************/
+
 int reply_ioctl(connection_struct *conn,
                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -343,8 +348,7 @@ int reply_ioctl(connection_struct *conn,
 
        DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
 
-       switch (ioctl_code)
-       {
+       switch (ioctl_code) {
            case IOCTL_QUERY_JOB_INFO:
                replysize = 32;
                break;
@@ -359,13 +363,14 @@ int reply_ioctl(connection_struct *conn,
        SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
        p = smb_buf(outbuf) + 1;          /* Allow for alignment */
 
-       switch (ioctl_code)
-       {
-           case IOCTL_QUERY_JOB_INFO:              
-               SSVAL(p,0,fsp->print_jobid);             /* Job number */
-               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;
+       switch (ioctl_code) {
+               case IOCTL_QUERY_JOB_INFO:                  
+               {
+                       SSVAL(p,0,fsp->rap_print_jobid);             /* Job number */
+                       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;
+               }
        }
 
        END_PROFILE(SMBioctl);
@@ -373,1200 +378,887 @@ int reply_ioctl(connection_struct *conn,
 }
 
 /****************************************************************************
-reply to a session setup command
+ Reply to a chkpth.
 ****************************************************************************/
 
-int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
-  int sess_vuid;
-  gid_t gid;
-  uid_t uid;
-  char* full_name;
-  int   smb_bufsize;    
-  int   smb_apasslen = 0;   
-  pstring smb_apasswd;
-  int   smb_ntpasslen = 0;   
-  pstring smb_ntpasswd;
-  pstring user;
-  pstring orig_user;
-  fstring domain;
-  fstring native_os;
-  fstring native_lanman;
-  BOOL guest=False;
-  static BOOL done_sesssetup = False;
-  BOOL doencrypt = global_encrypted_passwords_negotiated;
-  START_PROFILE(SMBsesssetupX);
-
-  *smb_apasswd = *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);
-           return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
-    }
-
-    memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
-    srvstr_pull(inbuf, user, smb_buf(inbuf)+smb_apasslen, sizeof(user), -1, STR_TERMINATE);
-    
-    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);
-           return ERROR_DOS(ERRDOS,ERRbuftoosmall);
-    }
-
-    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;
-      }
-    }
-
-    /* Save the lanman2 password and the NT md4 password. */
-    smb_apasslen = passlen1;
-    memcpy(smb_apasswd,p,smb_apasslen);
-
-    smb_ntpasslen = passlen2;
-    memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
-
-    if (smb_apasslen != 24 || !doencrypt) {
-           /* 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_TERMINATE);
-    /*
-     * Incoming user and domain are in DOS codepage format. Convert
-     * to UNIX.
-     */
-    p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
-                    -1, STR_TERMINATE);
-    p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
-                    -1, STR_TERMINATE);
-    p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
-                    -1, STR_TERMINATE);
-    DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            domain,native_os,native_lanman));
-  }
-  
-  /* don't allow for weird usernames or domains */
-  alpha_strcpy(user, user, ". _-$", sizeof(user));
-  alpha_strcpy(domain, domain, ". _-", sizeof(domain));
-  if (strstr(user, "..") || strstr(domain,"..")) {
-         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-  }
-
-  if (lp_security() == SEC_SHARE) {
-         /* in share level we should ignore any passwords */
-         smb_ntpasslen = 0;
-         smb_apasslen = 0;
-         guest = True;
-  }
-
-
-  DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",user, domain, remote_machine));
-
-  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_DOS(ERRDOS,ERRnoaccess);
-    }
-  }
-
-  /* If no username is sent use the guest account */
-  if (!*user) {
-         pstrcpy(user,lp_guestaccount(-1));
-         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);
-
-  /*
-   * Always try the "DOMAIN\user" lookup first, as this is the most
-   * specific case. If this fails then try the simple "user" lookup.
-   * But don't do this for guests, as this is always a local user.
-   */
-  if (!guest) {
-    pstring dom_user;
-    /* Work out who's who */
-    slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s",
-            domain, lp_winbind_separator(), user);
-    if (sys_getpwnam(dom_user) != NULL) {
-      pstrcpy(user, dom_user);
-      DEBUG(3,("Using unix username %s\n", dom_user));
-    }
-
-    /*
-     * 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);
-
-  if (!guest) {
-         NTSTATUS nt_status;
-         nt_status = pass_check_smb(orig_user, user, 
-                                    domain, remote_machine,
-                                    (unsigned char *)smb_apasswd, 
-                                    smb_apasslen, 
-                                    (unsigned char *)smb_ntpasswd,
-                                    smb_ntpasslen);
-         
-         if NT_STATUS_IS_OK(nt_status) {
-
-         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
-                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
-                     (lp_map_to_guest() ==  MAP_TO_GUEST_ON_BAD_PASSWORD)) {
-                         DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
-                         pstrcpy(user,lp_guestaccount(-1));
-                         guest = True;
-                 } else {
-                         /* Match WinXP and don't give the game away */
-                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-                 }
-         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
-                 if (lp_map_to_guest() ==  MAP_TO_GUEST_ON_BAD_PASSWORD) {
-                         pstrcpy(user,lp_guestaccount(-1));
-                         DEBUG(3,("Registered username %s for guest access\n",user));
-                         guest = True;
-                 } else {
-                         /* Match WinXP and don't give the game away */
-                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-                 }
-         } else {
-                 return ERROR_NT(nt_status);
-         }
-  }
-  
-  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(outbuf, p, "Unix", -1, STR_TERMINATE);
-    p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
-    p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
-    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 ERROR_NT(NT_STATUS_LOGON_FAILURE);
-    }
-    gid = pw->pw_gid;
-    uid = pw->pw_uid;
-    full_name = pw->pw_gecos;
-  }
-
-  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,orig_user,domain,guest, full_name);
-  
-  if (sess_vuid == -1) {
-      return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-  }
-
-  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);
+       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);
+       srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE);
 
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
 
-  unix_convert(name,conn,0,&bad_path,&sbuf);
+       unix_convert(name,conn,0,&bad_path,&sbuf);
 
-  mode = SVAL(inbuf,smb_vwv0);
+       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 (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) {
-           return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
-    }
+       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);
 
-    return(UNIXERROR(ERRDOS,ERRbadpath));
-  }
+               return(UNIXERROR(ERRDOS,ERRbadpath));
+       }
 
-  outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,True);
 
-  DEBUG(3,("chkpth %s mode=%d\n", name, mode));
+       DEBUG(3,("chkpth %s mode=%d\n", name, mode));
 
-  END_PROFILE(SMBchkpth);
-  return(outsize);
+       END_PROFILE(SMBchkpth);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a getatr
+ 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);
+       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_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE);
+
+       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)));
-    }
-  }
+       /* 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));
-  }
+       if (!ok) {
+               set_bad_path_error(errno, bad_path);
+               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 */
-  }
+       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) | FLAGS2_IS_LONG_NAME);
   
-  DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
+       DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
   
-  END_PROFILE(SMBgetatr);
-  return(outsize);
+       END_PROFILE(SMBgetatr);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a setatr
+ 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);
+       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_buf(inbuf, fname, p, sizeof(fname), 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 (VALID_STAT_OF_DIR(sbuf))
+               mode |= aDIR;
+       else
+               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));
-  }
+       if (!ok) {
+               set_bad_path_error(errno, bad_path);
+               END_PROFILE(SMBsetatr);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
  
-  outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,True);
   
-  DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
+       DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
   
-  END_PROFILE(SMBsetatr);
-  return(outsize);
+       END_PROFILE(SMBsetatr);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a dskattr
+ Reply to a dskattr.
 ****************************************************************************/
+
 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  int outsize = 0;
-  SMB_BIG_UINT dfree,dsize,bsize;
-  START_PROFILE(SMBdskattr);
-  
-  conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
-  
-  outsize = set_message(outbuf,5,0,True);
+       int outsize = 0;
+       SMB_BIG_UINT dfree,dsize,bsize;
+       START_PROFILE(SMBdskattr);
+
+       conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
   
-  SSVAL(outbuf,smb_vwv0,dsize);
-  SSVAL(outbuf,smb_vwv1,bsize/512);
-  SSVAL(outbuf,smb_vwv2,512);
-  SSVAL(outbuf,smb_vwv3,dfree);
+       outsize = set_message(outbuf,5,0,True);
+       
+       if (Protocol <= PROTOCOL_LANMAN2) {
+               double total_space, free_space;
+               /* we need to scale this to a number that DOS6 can handle. We
+                  use floating point so we can handle large drives on systems
+                  that don't have 64 bit integers 
 
-  DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+                  we end up displaying a maximum of 2G to DOS systems
+               */
+               total_space = dsize * (double)bsize;
+               free_space = dfree * (double)bsize;
 
-  END_PROFILE(SMBdskattr);
-  return(outsize);
-}
+               dsize = (total_space+63*512) / (64*512);
+               dfree = (free_space+63*512) / (64*512);
+               
+               if (dsize > 0xFFFF) dsize = 0xFFFF;
+               if (dfree > 0xFFFF) dfree = 0xFFFF;
+
+               SSVAL(outbuf,smb_vwv0,dsize);
+               SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
+               SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */
+               SSVAL(outbuf,smb_vwv3,dfree);
+       } else {
+               SSVAL(outbuf,smb_vwv0,dsize);
+               SSVAL(outbuf,smb_vwv1,bsize/512);
+               SSVAL(outbuf,smb_vwv2,512);
+               SSVAL(outbuf,smb_vwv3,dfree);
+       }
 
+       DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+
+       END_PROFILE(SMBdskattr);
+       return(outsize);
+}
 
 /****************************************************************************
-  reply to a search
 Can be called from SMBsearch, SMBffirst or SMBfunique.
+ Reply to a search.
+ Can be called from SMBsearch, SMBffirst or SMBfunique.
 ****************************************************************************/
+
 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring mask;
-  pstring directory;
-  pstring fname;
-  SMB_OFF_T size;
-  int mode;
-  time_t date;
-  int dirtype;
-  int outsize = 0;
-  int numentries = 0;
-  BOOL finished = False;
-  int maxentries;
-  int i;
-  char *p;
-  BOOL ok = False;
-  int status_len;
-  pstring path;
-  char status[21];
-  int dptr_num= -1;
-  BOOL check_descend = False;
-  BOOL expect_close = False;
-  BOOL can_open = True;
-  BOOL bad_path = False;
-  START_PROFILE(SMBsearch);
-
-  *mask = *directory = *fname = 0;
-
-  /* If we were called as SMBffirst then we must expect close. */
-  if(CVAL(inbuf,smb_com) == SMBffirst)
-    expect_close = True;
-  
-  outsize = set_message(outbuf,1,3,True);
-  maxentries = SVAL(inbuf,smb_vwv0); 
-  dirtype = SVAL(inbuf,smb_vwv1);
-  p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
-  p++;
-  status_len = SVAL(p, 0);
-  p += 2;
+       pstring mask;
+       pstring directory;
+       pstring fname;
+       SMB_OFF_T size;
+       int mode;
+       time_t date;
+       int dirtype;
+       int outsize = 0;
+       int numentries = 0;
+       BOOL finished = False;
+       int maxentries;
+       int i;
+       char *p;
+       BOOL ok = False;
+       int status_len;
+       pstring path;
+       char status[21];
+       int dptr_num= -1;
+       BOOL check_descend = False;
+       BOOL expect_close = False;
+       BOOL can_open = True;
+       BOOL bad_path = False;
+       START_PROFILE(SMBsearch);
+
+       *mask = *directory = *fname = 0;
+
+       /* If we were called as SMBffirst then we must expect close. */
+       if(CVAL(inbuf,smb_com) == SMBffirst)
+               expect_close = True;
   
-  /* dirtype &= ~aDIR; */
+       outsize = set_message(outbuf,1,3,True);
+       maxentries = SVAL(inbuf,smb_vwv0); 
+       dirtype = SVAL(inbuf,smb_vwv1);
+       p = smb_buf(inbuf) + 1;
+       p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
+       p++;
+       status_len = SVAL(p, 0);
+       p += 2;
   
-  if (status_len == 0)
-  {
-    SMB_STRUCT_STAT sbuf;
-    pstring dir2;
-
-    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_m(dir2,'/');
-    if (p == NULL) 
-    {
-      pstrcpy(mask,dir2);
-      *dir2 = 0;
-    }
-    else
-    {
-      *p = 0;
-      pstrcpy(mask,p+1);
-    }
-
-    p = strrchr_m(directory,'/');
-    if (!p) 
-      *directory = 0;
-    else
-      *p = 0;
-
-    if (strlen(directory) == 0)
-      pstrcpy(directory,"./");
-    memset((char *)status,'\0',21);
-    CVAL(status,0) = dirtype;
-  }
-  else
-  {
-    memcpy(status,p,21);
-    dirtype = CVAL(status,0) & 0x1F;
-    conn->dirptr = dptr_fetch(status+12,&dptr_num);      
-    if (!conn->dirptr)
-      goto SearchEmpty;
-    string_set(&conn->dirpath,dptr_path(dptr_num));
-    fstrcpy(mask, dptr_wcard(dptr_num));
-  }
-
-  if (can_open)
-  {
-    p = smb_buf(outbuf) + 3;
-      
-    ok = True;
+       /* dirtype &= ~aDIR; */
+
+       if (status_len == 0) {
+               SMB_STRUCT_STAT sbuf;
+               pstring dir2;
+
+               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_m(dir2,'/');
+               if (p == NULL) {
+                       pstrcpy(mask,dir2);
+                       *dir2 = 0;
+               } else {
+                       *p = 0;
+                       pstrcpy(mask,p+1);
+               }
+
+               p = strrchr_m(directory,'/');
+               if (!p) 
+                       *directory = 0;
+               else
+                       *p = 0;
+
+               if (strlen(directory) == 0)
+                       pstrcpy(directory,".");
+               memset((char *)status,'\0',21);
+               SCVAL(status,0,(dirtype & 0x1F));
+       } else {
+               int status_dirtype;
+
+               memcpy(status,p,21);
+               status_dirtype = CVAL(status,0) & 0x1F;
+               if (status_dirtype != (dirtype & 0x1F))
+                       dirtype = status_dirtype;
+
+               conn->dirptr = dptr_fetch(status+12,&dptr_num);      
+               if (!conn->dirptr)
+                       goto SearchEmpty;
+               string_set(&conn->dirpath,dptr_path(dptr_num));
+               pstrcpy(mask, dptr_wcard(dptr_num));
+       }
+
+       if (can_open) {
+               p = smb_buf(outbuf) + 3;
+               ok = True;
      
-    if (status_len == 0)
-    {
-      dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
-      if (dptr_num < 0)
-      {
-        if(dptr_num == -2)
-        {
-          if((errno == ENOENT) && bad_path)
-          {
-            unix_ERR_class = ERRDOS;
-            unix_ERR_code = ERRbadpath;
-          }
-                END_PROFILE(SMBsearch);
-          return (UNIXERROR(ERRDOS,ERRnofids));
-        }
-               END_PROFILE(SMBsearch);
-        return ERROR_DOS(ERRDOS,ERRnofids);
-      }
-      dptr_set_wcard(dptr_num, strdup(mask));
-    }
-
-    DEBUG(4,("dptr_num is %d\n",dptr_num));
-
-    if (ok)
-    {
-      if ((dirtype&0x1F) == aVOLID)
-      {          
-        memcpy(p,status,21);
-        make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
-        dptr_fill(p+12,dptr_num);
-        if (dptr_zero(p+12) && (status_len==0))
-          numentries = 1;
-        else
-          numentries = 0;
-        p += DIR_STRUCT_SIZE;
-      }
-      else 
-      {
-        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-              conn->dirpath,lp_dontdescend(SNUM(conn))));
-        if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
-          check_descend = True;
-
-        for (i=numentries;(i<maxentries) && !finished;i++)
-        {
-          finished = 
-            !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
-          if (!finished)
-          {
-            memcpy(p,status,21);
-            make_dir_struct(p,mask,fname,size,mode,date);
-            dptr_fill(p+12,dptr_num);
-            numentries++;
-         }
-         p += DIR_STRUCT_SIZE;
-        }
-      }
-       } /* if (ok ) */
-  }
+               if (status_len == 0) {
+                       dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
+                       if (dptr_num < 0) {
+                               if(dptr_num == -2) {
+                                       set_bad_path_error(errno, bad_path);
+                                       END_PROFILE(SMBsearch);
+                                       return (UNIXERROR(ERRDOS,ERRnofids));
+                               }
+                               END_PROFILE(SMBsearch);
+                               return ERROR_DOS(ERRDOS,ERRnofids);
+                       }
+                       dptr_set_wcard(dptr_num, strdup(mask));
+                       dptr_set_attr(dptr_num, dirtype);
+               } else {
+                       dirtype = dptr_attr(dptr_num);
+               }
+
+               DEBUG(4,("dptr_num is %d\n",dptr_num));
+
+               if (ok) {
+                       if ((dirtype&0x1F) == aVOLID) {   
+                               memcpy(p,status,21);
+                               make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
+                               dptr_fill(p+12,dptr_num);
+                               if (dptr_zero(p+12) && (status_len==0))
+                                       numentries = 1;
+                               else
+                                       numentries = 0;
+                               p += DIR_STRUCT_SIZE;
+                       } else {
+                               DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
+                               conn->dirpath,lp_dontdescend(SNUM(conn))));
+                               if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
+                                       check_descend = True;
+
+                               for (i=numentries;(i<maxentries) && !finished;i++) {
+                                       finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
+                                       if (!finished) {
+                                               memcpy(p,status,21);
+                                               make_dir_struct(p,mask,fname,size,mode,date);
+                                               dptr_fill(p+12,dptr_num);
+                                               numentries++;
+                                       }
+                                       p += DIR_STRUCT_SIZE;
+                               }
+                       }
+               } /* if (ok ) */
+       }
 
 
   SearchEmpty:
 
-  if (numentries == 0 || !ok)
-  {
-    CVAL(outbuf,smb_rcls) = ERRDOS;
-    SSVAL(outbuf,smb_err,ERRnofiles);
-    dptr_close(&dptr_num);
-  }
-
-  /* If we were called as SMBffirst with smb_search_id == NULL
-     and no entries were found then return error and close dirptr 
-     (X/Open spec) */
-
-  if(ok && expect_close && numentries == 0 && status_len == 0)
-  {
-    CVAL(outbuf,smb_rcls) = ERRDOS;
-    SSVAL(outbuf,smb_err,ERRnofiles);
-    /* Also close the dptr - we know it's gone */
-    dptr_close(&dptr_num);
-  }
-
-  /* If we were called as SMBfunique, then we can close the dirptr now ! */
-  if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
-    dptr_close(&dptr_num);
-
-  SSVAL(outbuf,smb_vwv0,numentries);
-  SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
-  CVAL(smb_buf(outbuf),0) = 5;
-  SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
-
-  if (Protocol >= PROTOCOL_NT1) {
-    SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
-  }
+       if (numentries == 0 || !ok) {
+               SCVAL(outbuf,smb_rcls,ERRDOS);
+               SSVAL(outbuf,smb_err,ERRnofiles);
+               dptr_close(&dptr_num);
+       }
+
+       /* If we were called as SMBffirst with smb_search_id == NULL
+               and no entries were found then return error and close dirptr 
+               (X/Open spec) */
+
+       if(ok && expect_close && numentries == 0 && status_len == 0) {
+               SCVAL(outbuf,smb_rcls,ERRDOS);
+               SSVAL(outbuf,smb_err,ERRnofiles);
+               /* Also close the dptr - we know it's gone */
+               dptr_close(&dptr_num);
+       }
+
+       /* If we were called as SMBfunique, then we can close the dirptr now ! */
+       if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
+               dptr_close(&dptr_num);
+
+       SSVAL(outbuf,smb_vwv0,numentries);
+       SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
+       SCVAL(smb_buf(outbuf),0,5);
+       SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
+
+       if (Protocol >= PROTOCOL_NT1)
+               SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
   
-  outsize += DIR_STRUCT_SIZE*numentries;
-  smb_setlen(outbuf,outsize - 4);
+       outsize += DIR_STRUCT_SIZE*numentries;
+       smb_setlen(outbuf,outsize - 4);
   
-  if ((! *directory) && dptr_path(dptr_num))
-    slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
+       if ((! *directory) && dptr_path(dptr_num))
+               slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
 
-  DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
-        smb_fn_name(CVAL(inbuf,smb_com)), 
-        mask, directory, dirtype, numentries, maxentries ) );
+       DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
+               smb_fn_name(CVAL(inbuf,smb_com)), 
+               mask, directory, dirtype, numentries, maxentries ) );
 
-  END_PROFILE(SMBsearch);
-  return(outsize);
+       END_PROFILE(SMBsearch);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a fclose (stop directory search)
+ Reply to a fclose (stop directory search).
 ****************************************************************************/
+
 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  int outsize = 0;
-  int status_len;
-  pstring path;
-  char status[21];
-  int dptr_num= -2;
-  char *p;
+       int outsize = 0;
+       int status_len;
+       pstring path;
+       char status[21];
+       int dptr_num= -2;
+       char *p;
 
-  START_PROFILE(SMBfclose);
+       START_PROFILE(SMBfclose);
 
-  outsize = set_message(outbuf,1,0,True);
-  p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
-  p++;
-  status_len = SVAL(p,0);
-  p += 2;
+       outsize = set_message(outbuf,1,0,True);
+       p = smb_buf(inbuf) + 1;
+       p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
+       p++;
+       status_len = SVAL(p,0);
+       p += 2;
 
-  if (status_len == 0) {
-    END_PROFILE(SMBfclose);
-    return ERROR_DOS(ERRSRV,ERRsrverror);
-  }
+       if (status_len == 0) {
+               END_PROFILE(SMBfclose);
+               return ERROR_DOS(ERRSRV,ERRsrverror);
+       }
 
-  memcpy(status,p,21);
+       memcpy(status,p,21);
 
-  if(dptr_fetch(status+12,&dptr_num)) {
-    /*  Close the dptr - we know it's gone */
-    dptr_close(&dptr_num);
-  }
+       if(dptr_fetch(status+12,&dptr_num)) {
+               /*  Close the dptr - we know it's gone */
+               dptr_close(&dptr_num);
+       }
 
-  SSVAL(outbuf,smb_vwv0,0);
+       SSVAL(outbuf,smb_vwv0,0);
 
-  DEBUG(3,("search close\n"));
+       DEBUG(3,("search close\n"));
 
-  END_PROFILE(SMBfclose);
-  return(outsize);
+       END_PROFILE(SMBfclose);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to an open
+ Reply to an open.
 ****************************************************************************/
 
 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring fname;
-  int outsize = 0;
-  int fmode=0;
-  int share_mode;
-  SMB_OFF_T size = 0;
-  time_t mtime=0;
-  mode_t unixmode;
-  int rmode=0;
-  SMB_STRUCT_STAT sbuf;
-  BOOL bad_path = False;
-  files_struct *fsp;
-  int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
-  START_PROFILE(SMBopen);
+       pstring fname;
+       int outsize = 0;
+       int fmode=0;
+       int share_mode;
+       SMB_OFF_T size = 0;
+       time_t mtime=0;
+       mode_t unixmode;
+       int rmode=0;
+       SMB_STRUCT_STAT sbuf;
+       BOOL bad_path = False;
+       files_struct *fsp;
+       int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+       START_PROFILE(SMBopen);
  
-  share_mode = SVAL(inbuf,smb_vwv0);
+       share_mode = SVAL(inbuf,smb_vwv0);
 
-  srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE);
 
-  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
-  unix_convert(fname,conn,0,&bad_path,&sbuf);
+       unix_convert(fname,conn,0,&bad_path,&sbuf);
     
-  unixmode = unix_mode(conn,aARCH,fname);
+       unixmode = unix_mode(conn,aARCH,fname);
       
-  fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
-                   unixmode, oplock_request,&rmode,NULL);
-
-  if (!fsp)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    END_PROFILE(SMBopen);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  size = sbuf.st_size;
-  fmode = dos_mode(conn,fname,&sbuf);
-  mtime = sbuf.st_mtime;
-
-  if (fmode & aDIR) {
-    DEBUG(3,("attempt to open a directory %s\n",fname));
-    close_file(fsp,False);
-    END_PROFILE(SMBopen);
-    return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
+       fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                       unixmode, oplock_request,&rmode,NULL);
+
+       if (!fsp) {
+               set_bad_path_error(errno, bad_path);
+               END_PROFILE(SMBopen);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       size = sbuf.st_size;
+       fmode = dos_mode(conn,fname,&sbuf);
+       mtime = sbuf.st_mtime;
+
+       if (fmode & aDIR) {
+               DEBUG(3,("attempt to open a directory %s\n",fname));
+               close_file(fsp,False);
+               END_PROFILE(SMBopen);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
+       }
   
-  outsize = set_message(outbuf,7,0,True);
-  SSVAL(outbuf,smb_vwv0,fsp->fnum);
-  SSVAL(outbuf,smb_vwv1,fmode);
-  if(lp_dos_filetime_resolution(SNUM(conn)) )
-    put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
-  else
-    put_dos_date3(outbuf,smb_vwv2,mtime);
-  SIVAL(outbuf,smb_vwv4,(uint32)size);
-  SSVAL(outbuf,smb_vwv6,rmode);
-
-  if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
-  }
+       outsize = set_message(outbuf,7,0,True);
+       SSVAL(outbuf,smb_vwv0,fsp->fnum);
+       SSVAL(outbuf,smb_vwv1,fmode);
+       if(lp_dos_filetime_resolution(SNUM(conn)) )
+               put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
+       else
+               put_dos_date3(outbuf,smb_vwv2,mtime);
+       SIVAL(outbuf,smb_vwv4,(uint32)size);
+       SSVAL(outbuf,smb_vwv6,rmode);
+
+       if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+               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;
-  END_PROFILE(SMBopen);
-  return(outsize);
+       if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+               SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+       END_PROFILE(SMBopen);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to an open and X
+ Reply to an open and X.
 ****************************************************************************/
+
 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-  pstring fname;
-  int smb_mode = SVAL(inbuf,smb_vwv3);
-  int smb_attr = SVAL(inbuf,smb_vwv5);
-  /* Breakout the oplock request bits so we can set the
-     reply bits separately. */
-  BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
-  BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
-  BOOL oplock_request = ex_oplock_request | core_oplock_request;
+       pstring fname;
+       int smb_mode = SVAL(inbuf,smb_vwv3);
+       int smb_attr = SVAL(inbuf,smb_vwv5);
+       /* Breakout the oplock request bits so we can set the
+               reply bits separately. */
+       BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+       BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+       BOOL oplock_request = ex_oplock_request | core_oplock_request;
 #if 0
-  int open_flags = SVAL(inbuf,smb_vwv2);
-  int smb_sattr = SVAL(inbuf,smb_vwv4); 
-  uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
+       int open_flags = SVAL(inbuf,smb_vwv2);
+       int smb_sattr = SVAL(inbuf,smb_vwv4); 
+       uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
 #endif
-  int smb_ofun = SVAL(inbuf,smb_vwv8);
-  mode_t unixmode;
-  SMB_OFF_T size=0;
-  int fmode=0,mtime=0,rmode=0;
-  SMB_STRUCT_STAT sbuf;
-  int smb_action = 0;
-  BOOL bad_path = False;
-  files_struct *fsp;
-  START_PROFILE(SMBopenX);
-
-  /* If it's an IPC, pass off the pipe handler. */
-  if (IS_IPC(conn)) {
-    if (lp_nt_pipe_support()) {
-           END_PROFILE(SMBopenX);
-           return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
-    } else {
-               END_PROFILE(SMBopenX);
-        return ERROR_DOS(ERRSRV,ERRaccess);
-    }
-  }
+       int smb_ofun = SVAL(inbuf,smb_vwv8);
+       mode_t unixmode;
+       SMB_OFF_T size=0;
+       int fmode=0,mtime=0,rmode=0;
+       SMB_STRUCT_STAT sbuf;
+       int smb_action = 0;
+       BOOL bad_path = False;
+       files_struct *fsp;
+       START_PROFILE(SMBopenX);
+
+       /* If it's an IPC, pass off the pipe handler. */
+       if (IS_IPC(conn)) {
+               if (lp_nt_pipe_support()) {
+                       END_PROFILE(SMBopenX);
+                       return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
+               } else {
+                       END_PROFILE(SMBopenX);
+                       return ERROR_DOS(ERRSRV,ERRaccess);
+               }
+       }
 
-  /* XXXX we need to handle passed times, sattr and flags */
-  srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
+       /* XXXX we need to handle passed times, sattr and flags */
+       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
 
-  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
-  unix_convert(fname,conn,0,&bad_path,&sbuf);
+       unix_convert(fname,conn,0,&bad_path,&sbuf);
     
-  unixmode = unix_mode(conn,smb_attr | aARCH, fname);
+       unixmode = unix_mode(conn,smb_attr | aARCH, fname);
       
-  fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
-                      oplock_request, &rmode,&smb_action);
+       fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
+                       oplock_request, &rmode,&smb_action);
       
-  if (!fsp)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    END_PROFILE(SMBopenX);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  size = sbuf.st_size;
-  fmode = dos_mode(conn,fname,&sbuf);
-  mtime = sbuf.st_mtime;
-  if (fmode & aDIR) {
-    close_file(fsp,False);
-    END_PROFILE(SMBopenX);
-    return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
-
-  /* If the caller set the extended oplock request bit
-     and we granted one (by whatever means) - set the
-     correct bit for extended oplock reply.
-   */
-
-  if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    smb_action |= EXTENDED_OPLOCK_GRANTED;
-  }
-
-  if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-    smb_action |= EXTENDED_OPLOCK_GRANTED;
-  }
-
-  /* If the caller set the core oplock request bit
-     and we granted one (by whatever means) - set the
-     correct bit for core oplock reply.
-   */
-
-  if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
-  }
-
-  if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
-  }
-
-  set_message(outbuf,15,0,True);
-  SSVAL(outbuf,smb_vwv2,fsp->fnum);
-  SSVAL(outbuf,smb_vwv3,fmode);
-  if(lp_dos_filetime_resolution(SNUM(conn)) )
-    put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
-  else
-    put_dos_date3(outbuf,smb_vwv4,mtime);
-  SIVAL(outbuf,smb_vwv6,(uint32)size);
-  SSVAL(outbuf,smb_vwv8,rmode);
-  SSVAL(outbuf,smb_vwv11,smb_action);
-
-  END_PROFILE(SMBopenX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
-}
+       if (!fsp) {
+               set_bad_path_error(errno, bad_path);
+               END_PROFILE(SMBopenX);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       size = sbuf.st_size;
+       fmode = dos_mode(conn,fname,&sbuf);
+       mtime = sbuf.st_mtime;
+       if (fmode & aDIR) {
+               close_file(fsp,False);
+               END_PROFILE(SMBopenX);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
+       }
+
+       /* If the caller set the extended oplock request bit
+               and we granted one (by whatever means) - set the
+               correct bit for extended oplock reply.
+       */
+
+       if (ex_oplock_request && lp_fake_oplocks(SNUM(conn)))
+               smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+       if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+               smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+       /* If the caller set the core oplock request bit
+               and we granted one (by whatever means) - set the
+               correct bit for core oplock reply.
+       */
+
+       if (core_oplock_request && lp_fake_oplocks(SNUM(conn)))
+               SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+
+       if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+               SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
+
+       set_message(outbuf,15,0,True);
+       SSVAL(outbuf,smb_vwv2,fsp->fnum);
+       SSVAL(outbuf,smb_vwv3,fmode);
+       if(lp_dos_filetime_resolution(SNUM(conn)) )
+               put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
+       else
+               put_dos_date3(outbuf,smb_vwv4,mtime);
+       SIVAL(outbuf,smb_vwv6,(uint32)size);
+       SSVAL(outbuf,smb_vwv8,rmode);
+       SSVAL(outbuf,smb_vwv11,smb_action);
 
+       END_PROFILE(SMBopenX);
+       return chain_reply(inbuf,outbuf,length,bufsize);
+}
 
 /****************************************************************************
-  reply to a SMBulogoffX
+ Reply to a SMBulogoffX.
 ****************************************************************************/
+
 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-  uint16 vuid = SVAL(inbuf,smb_uid);
-  user_struct *vuser = get_valid_user_struct(vuid);
-  START_PROFILE(SMBulogoffX);
+       uint16 vuid = SVAL(inbuf,smb_uid);
+       user_struct *vuser = get_valid_user_struct(vuid);
+       START_PROFILE(SMBulogoffX);
 
-  if(vuser == 0) {
-    DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
-  }
+       if(vuser == 0)
+               DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
 
-  /* in user level security we are supposed to close any files
-     open by this user */
-  if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
-         file_close_user(vuid);
-  }
+       /* in user level security we are supposed to close any files
+               open by this user */
+       if ((vuser != 0) && (lp_security() != SEC_SHARE))
+               file_close_user(vuid);
 
-  invalidate_vuid(vuid);
+       invalidate_vuid(vuid);
 
-  set_message(outbuf,2,0,True);
+       set_message(outbuf,2,0,True);
 
-  DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
+       DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
 
-  END_PROFILE(SMBulogoffX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
+       END_PROFILE(SMBulogoffX);
+       return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
-
 /****************************************************************************
-  reply to a mknew or a create
+ Reply to a mknew or a create.
 ****************************************************************************/
+
 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring fname;
-  int com;
-  int outsize = 0;
-  int createmode;
-  mode_t unixmode;
-  int ofun = 0;
-  BOOL bad_path = False;
-  files_struct *fsp;
-  int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
-  SMB_STRUCT_STAT sbuf;
-  START_PROFILE(SMBcreate);
+       pstring fname;
+       int com;
+       int outsize = 0;
+       int createmode;
+       mode_t unixmode;
+       int ofun = 0;
+       BOOL bad_path = False;
+       files_struct *fsp;
+       int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+       SMB_STRUCT_STAT sbuf;
+       START_PROFILE(SMBcreate);
  
-  com = SVAL(inbuf,smb_com);
+       com = SVAL(inbuf,smb_com);
 
-  createmode = SVAL(inbuf,smb_vwv0);
-  srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE);
+       createmode = SVAL(inbuf,smb_vwv0);
+       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), STR_TERMINATE);
 
-  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
-  unix_convert(fname,conn,0,&bad_path,&sbuf);
+       unix_convert(fname,conn,0,&bad_path,&sbuf);
 
-  if (createmode & aVOLID) {
-      DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
-  }
+       if (createmode & aVOLID)
+               DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
   
-  unixmode = unix_mode(conn,createmode,fname);
+       unixmode = unix_mode(conn,createmode,fname);
   
-  if(com == SMBmknew)
-  {
-    /* We should fail if file exists. */
-    ofun = FILE_CREATE_IF_NOT_EXIST;
-  }
-  else
-  {
-    /* SMBcreate - Create if file doesn't exist, truncate if it does. */
-    ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
-  }
-
-  /* Open file in dos compatibility share mode. */
-  fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
-                   ofun, unixmode, oplock_request, NULL, NULL);
+       if(com == SMBmknew) {
+               /* We should fail if file exists. */
+               ofun = FILE_CREATE_IF_NOT_EXIST;
+       } else {
+               /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+               ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
+       }
+
+       /* Open file in dos compatibility share mode. */
+       fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
+                       ofun, unixmode, oplock_request, NULL, NULL);
   
-  if (!fsp)
-  {
-    if((errno == ENOENT) && bad_path) 
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    END_PROFILE(SMBcreate);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       if (!fsp) {
+               set_bad_path_error(errno, bad_path);
+               END_PROFILE(SMBcreate);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
  
-  outsize = set_message(outbuf,1,0,True);
-  SSVAL(outbuf,smb_vwv0,fsp->fnum);
-
-  if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
-  }
+       outsize = set_message(outbuf,1,0,True);
+       SSVAL(outbuf,smb_vwv0,fsp->fnum);
+
+       if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+               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, ( "new file %s\n", fname ) );
-  DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
-        fname, fsp->fd, createmode, (int)unixmode ) );
+       DEBUG( 2, ( "new file %s\n", fname ) );
+       DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n", fname, fsp->fd, createmode, (int)unixmode ) );
 
-  END_PROFILE(SMBcreate);
-  return(outsize);
+       END_PROFILE(SMBcreate);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a create temporary file
+ Reply to a create temporary file.
 ****************************************************************************/
+
 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring fname;
-  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);
-  srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
-  pstrcat(fname,"\\TMXXXXXX");
-
-  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
-
-  unix_convert(fname,conn,0,&bad_path,&sbuf);
+       pstring fname;
+       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);
+       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE);
+       pstrcat(fname,"\\TMXXXXXX");
+
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+       unix_convert(fname,conn,0,&bad_path,&sbuf);
   
-  unixmode = unix_mode(conn,createmode,fname);
+       unixmode = unix_mode(conn,createmode,fname);
   
-  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 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);
-
-  /* close fd from smb_mkstemp() */
-  close(tmpfd);
-
-  if (!fsp)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    END_PROFILE(SMBctemp);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  outsize = set_message(outbuf,1,0,True);
-  SSVAL(outbuf,smb_vwv0,fsp->fnum);
-
-  /* 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;
-  }
+       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 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);
+
+       /* close fd from smb_mkstemp() */
+       close(tmpfd);
+
+       if (!fsp) {
+               set_bad_path_error(errno, bad_path);
+               END_PROFILE(SMBctemp);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       outsize = set_message(outbuf,1,0,True);
+       SSVAL(outbuf,smb_vwv0,fsp->fnum);
+
+       /* 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)))
+               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", fname ) );
-  DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
-        fname, fsp->fd, createmode, (int)unixmode ) );
+       DEBUG( 2, ( "created temp file %s\n", fname ) );
+       DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
+                       fname, fsp->fd, createmode, (int)unixmode ) );
 
-  END_PROFILE(SMBctemp);
-  return(outsize);
+       END_PROFILE(SMBctemp);
+       return(outsize);
 }
 
+/*******************************************************************
+ Check if a user is allowed to rename a file.
+********************************************************************/
+
+static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst)
+{
+       int smb_action;
+       int access_mode;
+       files_struct *fsp;
+
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+       
+       if (S_ISDIR(pst->st_mode))
+               return NT_STATUS_OK;
+
+       /* We need a better way to return NT status codes from open... */
+       unix_ERR_class = 0;
+       unix_ERR_code = 0;
+
+       fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
+               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
+
+       if (!fsp) {
+               NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
+               if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+                       ret = NT_STATUS_SHARING_VIOLATION;
+               unix_ERR_class = 0;
+               unix_ERR_code = 0;
+               return ret;
+       }
+       close_file(fsp,False);
+       return NT_STATUS_OK;
+}
 
 /*******************************************************************
-check if a user is allowed to delete a file
+ 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;
+       int smb_action;
+       int access_mode;
+       files_struct *fsp;
 
-       if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED;
+       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;
+       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 (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 & 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;
+       /* We need a better way to return NT status codes from open... */
+       unix_ERR_class = 0;
+       unix_ERR_code = 0;
+
+       fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
+               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
 
+       if (!fsp) {
+               NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
+               if (!NT_STATUS_IS_OK(unix_ERR_ntstatus))
+                       ret = unix_ERR_ntstatus;
+               else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+                       ret = NT_STATUS_SHARING_VIOLATION;
+               unix_ERR_class = 0;
+               unix_ERR_code = 0;
+               unix_ERR_ntstatus = NT_STATUS_OK;
+               return ret;
+       }
+       close_file(fsp,False);
        return NT_STATUS_OK;
 }
 
@@ -1583,7 +1275,6 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
        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;
@@ -1594,7 +1285,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
        
        p = strrchr_m(name,'/');
        if (!p) {
-               pstrcpy(directory,"./");
+               pstrcpy(directory,".");
                pstrcpy(mask,name);
        } else {
                *p = 0;
@@ -1611,8 +1302,8 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
        
-       if (!rc && is_mangled(mask))
-               check_mangled_cache( mask );
+       if (!rc && mangle_is_mangled(mask))
+               mangle_check_cache( mask );
        
        has_wild = ms_has_wild(mask);
        
@@ -1625,11 +1316,9 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                if (vfs_unlink(conn,directory) == 0) {
                        count++;
                }
-               if (!count)
-                       exists = vfs_file_exist(conn,directory,&sbuf);    
        } else {
                void *dirptr = NULL;
-               char *dname;
+               const char *dname;
                
                if (check_name(directory,conn))
                        dirptr = OpenDir(conn, directory, True);
@@ -1683,7 +1372,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        
        dirtype = SVAL(inbuf,smb_vwv0);
        
-       srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE);
        
        RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
        
@@ -1711,22 +1400,74 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 void fail_readraw(void)
 {
        pstring errstr;
-       slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)\n",
+       slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
                strerror(errno) );
        exit_server(errstr);
 }
 
+/****************************************************************************
+ Use sendfile in readbraw.
+****************************************************************************/
+
+void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
+               ssize_t mincount, char *outbuf)
+{
+       ssize_t ret=0;
+
+#if defined(WITH_SENDFILE)
+       /*
+        * We can only use sendfile on a non-chained packet and on a file
+        * that is exclusively oplocked. reply_readbraw has already checked the length.
+        */
+
+       if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) &&
+                       EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) {
+               DATA_BLOB header;
+
+               _smb_setlen(outbuf,nread);
+               header.data = outbuf;
+               header.length = 4;
+               header.free = NULL;
+
+               if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
+                       /*
+                        * Special hack for broken Linux with no 64 bit clean sendfile. If we
+                        * return ENOSYS then pretend we just got a normal read.
+                        */
+                       if (errno == ENOSYS)
+                               goto normal_read;
+
+                       DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
+                               fsp->fsp_name, strerror(errno) ));
+                       exit_server("send_file_readbraw sendfile failed");
+               }
+
+       }
+
+  normal_read:
+#endif
+
+       if (nread > 0) {
+               ret = read_file(fsp,outbuf+4,startpos,nread);
+               if (ret < mincount)
+                       ret = 0;
+       }
+
+       _smb_setlen(outbuf,ret);
+       if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
+               fail_readraw();
+}
+
 /****************************************************************************
  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;
+       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);
 
@@ -1763,7 +1504,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
 
        flush_write_cache(fsp, READRAW_FLUSH);
 
-       startpos = IVAL(inbuf,smb_vwv1);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
        if(CVAL(inbuf,smb_wct) == 10) {
                /*
                 * This is a large offset (64 bit) read.
@@ -1830,15 +1571,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
        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 (nread > 0) {
-               ret = read_file(fsp,header+4,startpos,nread);
-               if (ret < mincount)
-                       ret = 0;
-       }
-
-       _smb_setlen(header,ret);
-       if (write_data(smbd_server_fd(),header,4+ret) != 4+ret)
-               fail_readraw();
+       send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf);
 
        DEBUG(5,("readbraw finished\n"));
        END_PROFILE(SMBreadbraw);
@@ -1846,8 +1579,9 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
 }
 
 /****************************************************************************
-  reply to a lockread (core+ protocol)
+ 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;
@@ -1865,7 +1599,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        release_level_2_oplocks_on_change(fsp);
 
        numtoread = SVAL(inbuf,smb_vwv1);
-       startpos = IVAL(inbuf,smb_vwv2);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
   
        outsize = set_message(outbuf,5,3,True);
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
@@ -1878,19 +1612,21 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
         * for a write lock. JRA.
         */
        
-       status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), 
+       status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), 
                         (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
 
        if (NT_STATUS_V(status)) {
-               if (lp_blocking_locks(SNUM(conn))) {
+               if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
                        /*
                         * 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(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
+                                                               (SMB_BIG_UINT)numtoread)) {
                                END_PROFILE(SMBlockread);
-                       return -1;
+                               return -1;
+                       }
                }
                END_PROFILE(SMBlockread);
                return ERROR_NT(status);
@@ -1915,132 +1651,209 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a read
+ Reply to a read.
 ****************************************************************************/
 
 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-  size_t numtoread;
-  ssize_t nread = 0;
-  char *data;
-  SMB_OFF_T startpos;
-  int outsize = 0;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBread);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_READ(fsp);
+       size_t numtoread;
+       ssize_t nread = 0;
+       char *data;
+       SMB_OFF_T startpos;
+       int outsize = 0;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBread);
 
-  numtoread = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv2);
+       CHECK_FSP(fsp,conn);
+       CHECK_READ(fsp);
 
+       numtoread = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
 
-  outsize = set_message(outbuf,5,3,True);
-  numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
-  data = smb_buf(outbuf) + 3;
+       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,False)) {
-    END_PROFILE(SMBread);
-    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));
-  }
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               END_PROFILE(SMBread);
+               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));
+       }
   
-  outsize += nread;
-  SSVAL(outbuf,smb_vwv0,nread);
-  SSVAL(outbuf,smb_vwv5,nread+3);
-  CVAL(smb_buf(outbuf),0) = 1;
-  SSVAL(smb_buf(outbuf),1,nread);
+       outsize += nread;
+       SSVAL(outbuf,smb_vwv0,nread);
+       SSVAL(outbuf,smb_vwv5,nread+3);
+       SCVAL(smb_buf(outbuf),0,1);
+       SSVAL(smb_buf(outbuf),1,nread);
   
-  DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
-            fsp->fnum, (int)numtoread, (int)nread ) );
+       DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
+               fsp->fnum, (int)numtoread, (int)nread ) );
 
-  END_PROFILE(SMBread);
-  return(outsize);
+       END_PROFILE(SMBread);
+       return(outsize);
 }
 
+/****************************************************************************
+ Reply to a read and X - possibly using sendfile.
+****************************************************************************/
+
+int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, 
+               files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
+{
+       ssize_t nread = -1;
+       char *data = smb_buf(outbuf);
+
+#if defined(WITH_SENDFILE)
+       /*
+        * We can only use sendfile on a non-chained packet and on a file
+        * that is exclusively oplocked.
+        */
+
+       if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
+                       lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) {
+               SMB_STRUCT_STAT sbuf;
+               DATA_BLOB header;
+
+               if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1)
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+               if (startpos > sbuf.st_size)
+                       goto normal_read;
+
+               if (smb_maxcnt > (sbuf.st_size - startpos))
+                       smb_maxcnt = (sbuf.st_size - startpos);
+
+               if (smb_maxcnt == 0)
+                       goto normal_read;
+
+               /* 
+                * Set up the packet header before send. We
+                * assume here the sendfile will work (get the
+                * correct amount of data).
+                */
+
+               SSVAL(outbuf,smb_vwv5,smb_maxcnt);
+               SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+               SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
+               SCVAL(outbuf,smb_vwv0,0xFF);
+               set_message(outbuf,12,smb_maxcnt,False);
+               header.data = outbuf;
+               header.length = data - outbuf;
+               header.free = NULL;
+
+               if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
+                       /*
+                        * Special hack for broken Linux with no 64 bit clean sendfile. If we
+                        * return ENOSYS then pretend we just got a normal read.
+                        */
+                       if (errno == ENOSYS)
+                               goto normal_read;
+
+                       DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
+                               fsp->fsp_name, strerror(errno) ));
+                       exit_server("send_file_readX sendfile failed");
+               }
+
+               DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
+                       fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+               return -1;
+       }
+
+  normal_read:
+
+#endif
+
+       nread = read_file(fsp,data,startpos,smb_maxcnt);
+  
+       if (nread < 0) {
+               END_PROFILE(SMBreadX);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       SSVAL(outbuf,smb_vwv5,nread);
+       SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+       SSVAL(smb_buf(outbuf),-2,nread);
+  
+       DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
+               fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+
+       return nread;
+}
 
 /****************************************************************************
-  reply to a read and X
+ Reply to a read and X.
 ****************************************************************************/
+
 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-  files_struct *fsp = file_fsp(inbuf,smb_vwv2);
-  SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
-  size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
-  size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
-  ssize_t nread = -1;
-  char *data;
-  START_PROFILE(SMBreadX);
-
-  /* If it's an IPC, pass off the pipe handler. */
-  if (IS_IPC(conn)) {
-    END_PROFILE(SMBreadX);
-    return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
-  }
-
-  CHECK_FSP(fsp,conn);
-  CHECK_READ(fsp);
-
-  set_message(outbuf,12,0,True);
-  data = smb_buf(outbuf);
-
-  if(CVAL(inbuf,smb_wct) == 12) {
+       files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+       SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
+       ssize_t nread = -1;
+       size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+#if 0
+       size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
+#endif
+
+       START_PROFILE(SMBreadX);
+
+       /* If it's an IPC, pass off the pipe handler. */
+       if (IS_IPC(conn)) {
+               END_PROFILE(SMBreadX);
+               return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
+       }
+
+       CHECK_FSP(fsp,conn);
+       CHECK_READ(fsp);
+
+       set_message(outbuf,12,0,True);
+
+       if(CVAL(inbuf,smb_wct) == 12) {
 #ifdef LARGE_SMB_OFF_T
-    /*
-     * This is a large offset (64 bit) read.
-     */
-    startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
+               /*
+                * This is a large offset (64 bit) read.
+                */
+               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 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_vwv10) != 0) {
-      DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
+               if(IVAL(inbuf,smb_vwv10) != 0) {
+                       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_DOS(ERRDOS,ERRbadaccess);
-    }
+                       END_PROFILE(SMBreadX);
+                       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,False)) {
-    END_PROFILE(SMBreadX);
-    return ERROR_DOS(ERRDOS,ERRlock);
-  }
-  nread = read_file(fsp,data,startpos,smb_maxcnt);
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               END_PROFILE(SMBreadX);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-  if (nread < 0) {
-    END_PROFILE(SMBreadX);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-  
-  SSVAL(outbuf,smb_vwv5,nread);
-  SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
-  SSVAL(smb_buf(outbuf),-2,nread);
-  
-  DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
-             fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
+       nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt);
+       if (nread != -1)
+               nread = chain_reply(inbuf,outbuf,length,bufsize);
 
-  END_PROFILE(SMBreadX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
+       END_PROFILE(SMBreadX);
+       return nread;
 }
 
 /****************************************************************************
-  reply to a writebraw (core+ or LANMAN1.0 protocol)
+ Reply to a writebraw (core+ or LANMAN1.0 protocol).
 ****************************************************************************/
 
 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
@@ -2060,7 +1873,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        CHECK_WRITE(fsp);
   
        tcount = IVAL(inbuf,smb_vwv1);
-       startpos = IVAL(inbuf,smb_vwv3);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
        write_through = BITSETW(inbuf+smb_vwv7,0);
 
        /* We have to deal with slightly different formats depending
@@ -2075,8 +1888,8 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        }
 
        /* force the error type */
-       CVAL(inbuf,smb_com) = SMBwritec;
-       CVAL(outbuf,smb_com) = SMBwritec;
+       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);
@@ -2089,7 +1902,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        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)  {
+       if (nwritten < (ssize_t)numtowrite)  {
                END_PROFILE(SMBwritebraw);
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
@@ -2097,11 +1910,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        total_written = nwritten;
 
        /* Return a message to the redirector to tell it to send more bytes */
-       CVAL(outbuf,smb_com) = SMBwritebraw;
+       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.\n");
+               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) {
@@ -2113,7 +1926,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        /* Set up outbuf to return the correct return */
        outsize = set_message(outbuf,1,0,True);
-       CVAL(outbuf,smb_com) = SMBwritec;
+       SCVAL(outbuf,smb_com,SMBwritec);
        SSVAL(outbuf,smb_vwv0,total_written);
 
        if (numtowrite != 0) {
@@ -2138,7 +1951,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
                nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
 
                if (nwritten < (ssize_t)numtowrite) {
-                       CVAL(outbuf,smb_rcls) = ERRHRD;
+                       SCVAL(outbuf,smb_rcls,ERRHRD);
                        SSVAL(outbuf,smb_err,ERRdiskfull);      
                }
 
@@ -2155,12 +1968,15 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        /* 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) {
+
+#if RABBIT_PELLET_FIX
                /*
                 * 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");
+#endif
                return(-1);
        }
 
@@ -2168,7 +1984,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
 }
 
 /****************************************************************************
-  reply to a writeunlock (core+)
+ Reply to a writeunlock (core+).
 ****************************************************************************/
 
 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, 
@@ -2187,7 +2003,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
        CHECK_WRITE(fsp);
 
        numtowrite = SVAL(inbuf,smb_vwv1);
-       startpos = IVAL(inbuf,smb_vwv2);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
        data = smb_buf(inbuf) + 3;
   
        if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, 
@@ -2209,7 +2025,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
 
        if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
                END_PROFILE(SMBwriteunlock);
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
 
        status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, 
@@ -2230,260 +2046,276 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
        return outsize;
 }
 
-
 /****************************************************************************
  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);
-
-  /* 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);
-
-  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,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) {
-      /* This is actually an allocate call, not 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);
-      }
-  } else
-    nwritten = write_file(fsp,data,startpos,numtowrite);
-  
-  if (lp_syncalways(SNUM(conn)))
-    sync_file(conn,fsp);
+       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(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
-    END_PROFILE(SMBwrite);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       /* 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);
+       }
 
-  outsize = set_message(outbuf,1,0,True);
-  
-  SSVAL(outbuf,smb_vwv0,nwritten);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
 
-  if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
-    SSVAL(outbuf,smb_err,ERRdiskfull);      
-  }
+       numtowrite = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
+       data = smb_buf(inbuf) + 3;
   
-  DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
-          fsp->fnum, (int)numtowrite, (int)nwritten));
-
-  END_PROFILE(SMBwrite);
-  return(outsize);
-}
-
-
-/****************************************************************************
-  reply to a write and X
-****************************************************************************/
-int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
-  files_struct *fsp = file_fsp(inbuf,smb_vwv2);
-  SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
-  size_t numtowrite = SVAL(inbuf,smb_vwv10);
-  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. */
-  if (IS_IPC(conn)) {
-    END_PROFILE(SMBwriteX);
-    return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
-  }
-
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
-
-  /* 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_DOS(ERRDOS,ERRbadmem);
-  }
-
-  data = smb_base(inbuf) + smb_doff;
-
-  if(CVAL(inbuf,smb_wct) == 14) {
-#ifdef LARGE_SMB_OFF_T
-    /*
-     * This is a large offset (64 bit) write.
-     */
-    startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+               END_PROFILE(SMBwrite);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-#else /* !LARGE_SMB_OFF_T */
+       /*
+        * 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].
+        */
 
-    /*
-     * Ensure we haven't been sent a >32 bit offset.
-     */
+       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(IVAL(inbuf,smb_vwv12) != 0) {
-      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_DOS(ERRDOS,ERRbadaccess);
-    }
+       if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+               END_PROFILE(SMBwrite);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
 
-#endif /* LARGE_SMB_OFF_T */
-  }
-
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
-    END_PROFILE(SMBwriteX);
-    return ERROR_DOS(ERRDOS,ERRlock);
-  }
-
-  /* X/Open SMB protocol says that, unlike SMBwrite
-     if the length is zero then NO truncation is
-     done, just a write of zero. To truncate a file,
-     use SMBwrite. */
-  if(numtowrite == 0)
-    nwritten = 0;
-  else
-    nwritten = write_file(fsp,data,startpos,numtowrite);
+       outsize = set_message(outbuf,1,0,True);
   
-  if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
-    END_PROFILE(SMBwriteX);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       SSVAL(outbuf,smb_vwv0,nwritten);
 
-  set_message(outbuf,6,0,True);
+       if (nwritten < (ssize_t)numtowrite) {
+               SCVAL(outbuf,smb_rcls,ERRHRD);
+               SSVAL(outbuf,smb_err,ERRdiskfull);      
+       }
   
-  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;
-    SSVAL(outbuf,smb_err,ERRdiskfull);      
-  }
+       DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
 
-  DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
-          fsp->fnum, (int)numtowrite, (int)nwritten));
-
-  if (lp_syncalways(SNUM(conn)) || write_through)
-    sync_file(conn,fsp);
-
-  END_PROFILE(SMBwriteX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
+       END_PROFILE(SMBwrite);
+       return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a lseek
+ Reply to a write and X.
 ****************************************************************************/
 
-int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-  SMB_OFF_T startpos;
-  SMB_OFF_T res= -1;
-  int mode,umode;
-  int outsize = 0;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBlseek);
+       files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+       SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
+       size_t numtowrite = SVAL(inbuf,smb_vwv10);
+       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);
 
-  CHECK_FSP(fsp,conn);
+       /* If it's an IPC, pass off the pipe handler. */
+       if (IS_IPC(conn)) {
+               END_PROFILE(SMBwriteX);
+               return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
+       }
 
-  flush_write_cache(fsp, SEEK_FLUSH);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
 
-  mode = SVAL(inbuf,smb_vwv1) & 3;
-  startpos = IVALS(inbuf,smb_vwv2);
+       /* Deal with possible LARGE_WRITEX */
+       if (large_writeX)
+               numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
 
-  switch (mode) {
-    case 0: umode = SEEK_SET; break;
-    case 1: umode = SEEK_CUR; break;
-    case 2: umode = SEEK_END; break;
-    default:
-      umode = SEEK_SET; break;
-  }
+       if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
+               END_PROFILE(SMBwriteX);
+               return ERROR_DOS(ERRDOS,ERRbadmem);
+       }
 
-  if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) {
-    /*
-     * Check for the special case where a seek before the start
-     * of the file sets the offset to zero. Added in the CIFS spec,
-     * section 4.2.7.
-     */
+       data = smb_base(inbuf) + smb_doff;
 
-    if(errno == EINVAL) {
-      SMB_OFF_T current_pos = startpos;
+       if(CVAL(inbuf,smb_wct) == 14) {
+#ifdef LARGE_SMB_OFF_T
+               /*
+                * This is a large offset (64 bit) write.
+                */
+               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
 
-      if(umode == SEEK_CUR) {
+#else /* !LARGE_SMB_OFF_T */
 
-        if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
-                       END_PROFILE(SMBlseek);
-          return(UNIXERROR(ERRDOS,ERRnoaccess));
-       }
+               /*
+                * Ensure we haven't been sent a >32 bit offset.
+                */
 
-        current_pos += startpos;
+               if(IVAL(inbuf,smb_vwv12) != 0) {
+                       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_DOS(ERRDOS,ERRbadaccess);
+               }
 
-      } else if (umode == SEEK_END) {
+#endif /* LARGE_SMB_OFF_T */
+       }
+
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+               END_PROFILE(SMBwriteX);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
+
+       /* X/Open SMB protocol says that, unlike SMBwrite
+       if the length is zero then NO truncation is
+       done, just a write of zero. To truncate a file,
+       use SMBwrite. */
+
+       if(numtowrite == 0)
+               nwritten = 0;
+       else
+               nwritten = write_file(fsp,data,startpos,numtowrite);
+  
+       if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+               END_PROFILE(SMBwriteX);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
+
+       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) {
+               SCVAL(outbuf,smb_rcls,ERRHRD);
+               SSVAL(outbuf,smb_err,ERRdiskfull);      
+       }
+
+       DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
+               fsp->fnum, (int)numtowrite, (int)nwritten));
+
+       if (lp_syncalways(SNUM(conn)) || write_through)
+               sync_file(conn,fsp);
+
+       END_PROFILE(SMBwriteX);
+       return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+/****************************************************************************
+ Reply to a lseek.
+****************************************************************************/
 
-        SMB_STRUCT_STAT sbuf;
+int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+       SMB_OFF_T startpos;
+       SMB_OFF_T res= -1;
+       int mode,umode;
+       int outsize = 0;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBlseek);
+
+       CHECK_FSP(fsp,conn);
+
+       flush_write_cache(fsp, SEEK_FLUSH);
 
-        if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) {
-                 END_PROFILE(SMBlseek);
-          return(UNIXERROR(ERRDOS,ERRnoaccess));
+       mode = SVAL(inbuf,smb_vwv1) & 3;
+       /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
+       startpos = (SMB_OFF_T)IVALS(inbuf,smb_vwv2);
+
+       switch (mode) {
+               case 0:
+                       umode = SEEK_SET;
+                       break;
+               case 1:
+                       umode = SEEK_CUR;
+                       break;
+               case 2:
+                       umode = SEEK_END;
+                       break;
+               default:
+                       umode = SEEK_SET;
+                       break;
        }
 
-        current_pos += sbuf.st_size;
-      }
+       if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) {
+               /*
+                * Check for the special case where a seek before the start
+                * of the file sets the offset to zero. Added in the CIFS spec,
+                * section 4.2.7.
+                */
+
+               if(errno == EINVAL) {
+                       SMB_OFF_T current_pos = startpos;
+
+                       if(umode == SEEK_CUR) {
+
+                               if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
+                                       END_PROFILE(SMBlseek);
+                                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+                               }
+
+                               current_pos += startpos;
+
+                       } else if (umode == SEEK_END) {
+
+                               SMB_STRUCT_STAT sbuf;
+
+                               if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) {
+                                       END_PROFILE(SMBlseek);
+                                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+                               }
+
+                               current_pos += sbuf.st_size;
+                       }
  
-      if(current_pos < 0)
-        res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET);
-    }
+                       if(current_pos < 0)
+                               res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET);
+               }
 
-    if(res == -1) {
-      END_PROFILE(SMBlseek);
-      return(UNIXERROR(ERRDOS,ERRnoaccess));
-    }
-  }
+               if(res == -1) {
+                       END_PROFILE(SMBlseek);
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+       }
 
-  fsp->pos = res;
+       fsp->pos = res;
   
-  outsize = set_message(outbuf,2,0,True);
-  SIVAL(outbuf,smb_vwv0,res);
+       outsize = set_message(outbuf,2,0,True);
+       SIVAL(outbuf,smb_vwv0,res);
   
-  DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
-          fsp->fnum, (double)startpos, (double)res, mode));
+       DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
+               fsp->fnum, (double)startpos, (double)res, mode));
 
-  END_PROFILE(SMBlseek);
-  return(outsize);
+       END_PROFILE(SMBlseek);
+       return(outsize);
 }
 
 /****************************************************************************
-  reply to a flush
+ Reply to a flush.
 ****************************************************************************/
 
 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
@@ -2505,10 +2337,10 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a exit
+ Reply to a exit.
 ****************************************************************************/
+
 int reply_exit(connection_struct *conn, 
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -2522,10 +2354,10 @@ int reply_exit(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
  Reply to a close - has to deal with closing a directory opened by NT SMB's.
 ****************************************************************************/
+
 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 int dum_buffsize)
 {
@@ -2554,10 +2386,9 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                return ERROR_DOS(ERRDOS,ERRbadfid);
        }
 
-       if(fsp->is_directory || fsp->stat_open) {
+       if(fsp->is_directory) {
                /*
-                * Special case - close NT SMB directory or stat file
-                * handle.
+                * Special case - close NT SMB directory handle.
                 */
                DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
                close_file(fsp,True);
@@ -2566,21 +2397,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,
@@ -2597,6 +2417,16 @@ 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 */
@@ -2609,9 +2439,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a writeclose (Core+ protocol)
+ Reply to a writeclose (Core+ protocol).
 ****************************************************************************/
 
 int reply_writeclose(connection_struct *conn,
@@ -2631,7 +2460,7 @@ int reply_writeclose(connection_struct *conn,
        CHECK_WRITE(fsp);
 
        numtowrite = SVAL(inbuf,smb_vwv1);
-       startpos = IVAL(inbuf,smb_vwv2);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
        mtime = make_unix_date3(inbuf+smb_vwv4);
        data = smb_buf(inbuf) + 1;
   
@@ -2650,9 +2479,9 @@ int reply_writeclose(connection_struct *conn,
                 fsp->fnum, (int)numtowrite, (int)nwritten,
                 conn->num_files_open));
   
-       if (nwritten <= 0) {
+       if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
                END_PROFILE(SMBwriteclose);
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
  
        if(close_err != 0) {
@@ -2668,10 +2497,10 @@ int reply_writeclose(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a lock
+ Reply to a lock.
 ****************************************************************************/
+
 int reply_lock(connection_struct *conn,
               char *inbuf,char *outbuf, int length, int dum_buffsize)
 {
@@ -2691,15 +2520,15 @@ 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));
 
-       status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
+       status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
        if (NT_STATUS_V(status)) {
-               if (lp_blocking_locks(SNUM(conn))) {
+               if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
                        /*
                         * 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(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
                                END_PROFILE(SMBlock);
                                return -1;
                        }
@@ -2712,10 +2541,10 @@ int reply_lock(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a unlock
+ Reply to a unlock.
 ****************************************************************************/
+
 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, 
                 int dum_buffsize)
 {
@@ -2743,10 +2572,10 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a tdis
+ Reply to a tdis.
 ****************************************************************************/
+
 int reply_tdis(connection_struct *conn, 
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -2770,11 +2599,10 @@ int reply_tdis(connection_struct *conn,
        return outsize;
 }
 
-
-
 /****************************************************************************
-  reply to a echo
+ Reply to a echo.
 ****************************************************************************/
+
 int reply_echo(connection_struct *conn,
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -2801,7 +2629,7 @@ int reply_echo(connection_struct *conn,
                smb_setlen(outbuf,outsize - 4);
 
                if (!send_smb(smbd_server_fd(),outbuf))
-                       exit_server("reply_echo: send_smb failed.\n");
+                       exit_server("reply_echo: send_smb failed.");
        }
 
        DEBUG(3,("echo %d times\n", smb_reverb));
@@ -2812,10 +2640,10 @@ int reply_echo(connection_struct *conn,
        return -1;
 }
 
-
 /****************************************************************************
-  reply to a printopen
+ Reply to a printopen.
 ****************************************************************************/
+
 int reply_printopen(connection_struct *conn, 
                    char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -2829,7 +2657,7 @@ int reply_printopen(connection_struct *conn,
        }
 
        /* Open for exclusive use, write only. */
-       fsp = print_fsp_open(conn);
+       fsp = print_fsp_open(conn, NULL);
 
        if (!fsp) {
                END_PROFILE(SMBsplopen);
@@ -2846,10 +2674,10 @@ int reply_printopen(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a printclose
+ Reply to a printclose.
 ****************************************************************************/
+
 int reply_printclose(connection_struct *conn,
                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -2880,10 +2708,10 @@ int reply_printclose(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a printqueue
+ Reply to a printqueue.
 ****************************************************************************/
+
 int reply_printqueue(connection_struct *conn,
                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
@@ -2903,7 +2731,7 @@ int reply_printqueue(connection_struct *conn,
 
        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",
@@ -2911,8 +2739,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;
@@ -2925,11 +2754,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;
-                       srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII);
+                       SCVAL(p,11,0);
+                       srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII);
                        p += 28;
                }
 
@@ -2937,7 +2766,7 @@ 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);
                }
 
@@ -2950,45 +2779,46 @@ int reply_printqueue(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a printwrite
+ Reply to a printwrite.
 ****************************************************************************/
+
 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  int numtowrite;
-  int outsize = set_message(outbuf,0,0,True);
-  char *data;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBsplwr);
+       int numtowrite;
+       int outsize = set_message(outbuf,0,0,True);
+       char *data;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+       START_PROFILE(SMBsplwr);
   
-  if (!CAN_PRINT(conn)) {
-    END_PROFILE(SMBsplwr);
-    return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
+       if (!CAN_PRINT(conn)) {
+               END_PROFILE(SMBsplwr);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
+       }
 
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
 
-  numtowrite = SVAL(smb_buf(inbuf),1);
-  data = smb_buf(inbuf) + 3;
+       numtowrite = SVAL(smb_buf(inbuf),1);
+       data = smb_buf(inbuf) + 3;
   
-  if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
-    END_PROFILE(SMBsplwr);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
+               END_PROFILE(SMBsplwr);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
 
-  DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
+       DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
   
-  END_PROFILE(SMBsplwr);
-  return(outsize);
+       END_PROFILE(SMBsplwr);
+       return(outsize);
 }
 
-
 /****************************************************************************
  The guts of the mkdir command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
+
 NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
 {
        BOOL bad_path = False;
@@ -3001,6 +2831,9 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
                ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
        
        if (ret == -1) {
+               NTSTATUS nterr = set_bad_path_error(errno, bad_path);
+               if (!NT_STATUS_IS_OK(nterr))
+                       return nterr;
                return map_nt_error_from_unix(errno);
        }
        
@@ -3018,10 +2851,13 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        NTSTATUS status;
        START_PROFILE(SMBmkdir);
  
-       srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE);
+
+       RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
 
        status = mkdir_internal(conn, directory);
-       if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+       if (!NT_STATUS_IS_OK(status))
+               return ERROR_NT(status);
 
        outsize = set_message(outbuf,0,0,True);
 
@@ -3038,7 +2874,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
-       char *dname = NULL;
+       const char *dname = NULL;
        BOOL ret = False;
        void *dirptr = OpenDir(conn, directory, False);
 
@@ -3103,7 +2939,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
                 * do a recursive delete) then fail the rmdir.
                 */
                BOOL all_veto_files = True;
-               char *dname;
+               const char *dname;
                void *dirptr = OpenDir(conn, directory, False);
 
                if(dirptr != NULL) {
@@ -3171,130 +3007,112 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
 
 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring directory;
-  int outsize = 0;
-  BOOL ok = False;
-  BOOL bad_path = False;
-  SMB_STRUCT_STAT sbuf;
-  START_PROFILE(SMBrmdir);
+       pstring directory;
+       int outsize = 0;
+       BOOL ok = False;
+       BOOL bad_path = False;
+       SMB_STRUCT_STAT sbuf;
+       START_PROFILE(SMBrmdir);
 
-  srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE);
 
-  RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+       RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
 
-  unix_convert(directory,conn, NULL,&bad_path,&sbuf);
+       unix_convert(directory,conn, NULL,&bad_path,&sbuf);
   
-  if (check_name(directory,conn))
-  {
-    dptr_closepath(directory,SVAL(inbuf,smb_pid));
-    ok = rmdir_internals(conn, directory);
-  }
+       if (check_name(directory,conn)) {
+               dptr_closepath(directory,SVAL(inbuf,smb_pid));
+               ok = rmdir_internals(conn, directory);
+       }
   
-  if (!ok)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    END_PROFILE(SMBrmdir);
-    return(UNIXERROR(ERRDOS,ERRbadpath));
-  }
+       if (!ok) {
+               set_bad_path_error(errno, bad_path);
+               END_PROFILE(SMBrmdir);
+               return(UNIXERROR(ERRDOS,ERRbadpath));
+       }
  
-  outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,True);
   
-  DEBUG( 3, ( "rmdir %s\n", directory ) );
+       DEBUG( 3, ( "rmdir %s\n", directory ) );
   
-  END_PROFILE(SMBrmdir);
-  return(outsize);
+       END_PROFILE(SMBrmdir);
+       return(outsize);
 }
 
-
 /*******************************************************************
-resolve wildcards in a filename rename
+ Resolve wildcards in a filename rename.
 ********************************************************************/
+
 static BOOL resolve_wildcards(char *name1,char *name2)
 {
-  fstring root1,root2;
-  fstring ext1,ext2;
-  char *p,*p2;
+       fstring root1,root2;
+       fstring ext1,ext2;
+       char *p,*p2;
 
-  name1 = strrchr_m(name1,'/');
-  name2 = strrchr_m(name2,'/');
+       name1 = strrchr_m(name1,'/');
+       name2 = strrchr_m(name2,'/');
 
-  if (!name1 || !name2) return(False);
+       if (!name1 || !name2)
+               return(False);
   
-  fstrcpy(root1,name1);
-  fstrcpy(root2,name2);
-  p = strrchr_m(root1,'.');
-  if (p) {
-    *p = 0;
-    fstrcpy(ext1,p+1);
-  } else {
-    fstrcpy(ext1,"");    
-  }
-  p = strrchr_m(root2,'.');
-  if (p) {
-    *p = 0;
-    fstrcpy(ext2,p+1);
-  } else {
-    fstrcpy(ext2,"");    
-  }
-
-  p = root1;
-  p2 = root2;
-  while (*p2) {
-    if (*p2 == '?') {
-      *p2 = *p;
-      p2++;
-    } else {
-      p2++;
-    }
-    if (*p) p++;
-  }
-
-  p = ext1;
-  p2 = ext2;
-  while (*p2) {
-    if (*p2 == '?') {
-      *p2 = *p;
-      p2++;
-    } else {
-      p2++;
-    }
-    if (*p) p++;
-  }
-
-  pstrcpy(name2,root2);
-  if (ext2[0]) {
-    pstrcat(name2,".");
-    pstrcat(name2,ext2);
-  }
-
-  return(True);
-}
+       fstrcpy(root1,name1);
+       fstrcpy(root2,name2);
+       p = strrchr_m(root1,'.');
+       if (p) {
+               *p = 0;
+               fstrcpy(ext1,p+1);
+       } else {
+               fstrcpy(ext1,"");    
+       }
+       p = strrchr_m(root2,'.');
+       if (p) {
+               *p = 0;
+               fstrcpy(ext2,p+1);
+       } else {
+               fstrcpy(ext2,"");    
+       }
 
-/*******************************************************************
-check if a user is allowed to rename a file
-********************************************************************/
-static BOOL can_rename(char *fname,connection_struct *conn)
-{
-  SMB_STRUCT_STAT sbuf;
+       p = root1;
+       p2 = root2;
+       while (*p2) {
+               if (*p2 == '?') {
+                       *p2 = *p;
+                       p2++;
+               } else {
+                       p2++;
+               }
+               if (*p)
+                       p++;
+       }
 
-  if (!CAN_WRITE(conn)) return(False);
+       p = ext1;
+       p2 = ext2;
+       while (*p2) {
+               if (*p2 == '?') {
+                       *p2 = *p;
+                       p2++;
+               } else {
+                       p2++;
+               }
+               if (*p)
+                       p++;
+       }
 
-  if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False);
-  if (!check_file_sharing(conn,fname,True)) return(False);
-  return(True);
+       pstrcpy(name2,root2);
+       if (ext2[0]) {
+               pstrcat(name2,".");
+               pstrcat(name2,ext2);
+       }
+
+       return(True);
 }
 
 /****************************************************************************
  The guts of the rename command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
-NTSTATUS rename_internals(connection_struct *conn, 
-                         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;
@@ -3305,7 +3123,6 @@ NTSTATUS rename_internals(connection_struct *conn,
        BOOL bad_path2 = False;
        int count=0;
        NTSTATUS error = NT_STATUS_OK;
-       BOOL exists=False;
        BOOL rc = True;
        SMB_STRUCT_STAT sbuf1, sbuf2;
 
@@ -3343,8 +3160,8 @@ NTSTATUS rename_internals(connection_struct *conn,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!rc && is_mangled(mask))
-               check_mangled_cache( mask );
+       if (!rc && mangle_is_mangled(mask))
+               mangle_check_cache( mask );
 
        has_wild = ms_has_wild(mask);
 
@@ -3352,7 +3169,7 @@ NTSTATUS rename_internals(connection_struct *conn,
                /*
                 * No wildcards - just process the one file.
                 */
-               BOOL is_short_name = is_8_3(name, True);
+               BOOL is_short_name = mangle_is_8_3(name, True);
 
                /* Add a terminating '/' to the directory name. */
                pstrcat(directory,"/");
@@ -3367,7 +3184,8 @@ NTSTATUS 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));
 
@@ -3404,40 +3222,83 @@ NTSTATUS rename_internals(connection_struct *conn,
                                pstrcpy(p+1, newname_last_component);
                        }
                }
-               
-               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,directory,newname) == 0)
-                               count++;
-               } else {
-                       if (resolve_wildcards(directory,newname) && 
-                           can_rename(directory,conn) && 
-                           !vfs_file_exist(conn,newname,NULL) &&
-                           conn->vfs_ops.rename(conn,directory,newname) == 0)
-                               count++;
+               if (!vfs_object_exist(conn, directory, &sbuf1)) {
+                       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",
+                               nt_errstr(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 = NT_STATUS_OBJECT_NAME_COLLISION;
+               error = can_rename(directory,conn,&sbuf1);
+
+               if (!NT_STATUS_IS_OK(error)) {
+                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                               nt_errstr(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",
+                       nt_errstr(error), directory,newname));
+
+               return error;
        } else {
                /*
                 * Wildcards - process each file that matches.
                 */
                void *dirptr = NULL;
-               char *dname;
+               const char *dname;
                pstring destname;
                
                if (check_name(directory,conn))
@@ -3459,7 +3320,13 @@ NTSTATUS rename_internals(connection_struct *conn,
                                
                                error = NT_STATUS_ACCESS_DENIED;
                                slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
-                               if (!can_rename(fname,conn)) {
+                               if (!vfs_object_exist(conn, fname, &sbuf1)) {
+                                       error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                                       DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error)));
+                                       continue;
+                               }
+                               error = can_rename(fname,conn,&sbuf1);
+                               if (!NT_STATUS_IS_OK(error)) {
                                        DEBUG(6,("rename %s refused\n", fname));
                                        continue;
                                }
@@ -3509,9 +3376,9 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        START_PROFILE(SMBmv);
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
+       p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE);
        p++;
-       p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+       p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE);
        
        RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
        RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
@@ -3598,6 +3465,10 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
                ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
 
        close_file(fsp1,False);
+
+       /* 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.
@@ -3610,209 +3481,213 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
 }
 
 /****************************************************************************
-  reply to a file copy.
-  ****************************************************************************/
+ Reply to a file copy.
+****************************************************************************/
+
 int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  int outsize = 0;
-  pstring name;
-  pstring directory;
-  pstring mask,newname;
-  char *p;
-  int count=0;
-  int error = ERRnoaccess;
-  int err = 0;
-  BOOL has_wild;
-  BOOL exists=False;
-  int tid2 = SVAL(inbuf,smb_vwv0);
-  int ofun = SVAL(inbuf,smb_vwv1);
-  int flags = SVAL(inbuf,smb_vwv2);
-  BOOL target_is_directory=False;
-  BOOL bad_path1 = False;
-  BOOL bad_path2 = False;
-  BOOL rc = True;
-  SMB_STRUCT_STAT sbuf1, sbuf2;
-  START_PROFILE(SMBcopy);
-
-  *directory = *mask = 0;
-
-  p = smb_buf(inbuf);
-  p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
-  p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+       int outsize = 0;
+       pstring name;
+       pstring directory;
+       pstring mask,newname;
+       char *p;
+       int count=0;
+       int error = ERRnoaccess;
+       int err = 0;
+       BOOL has_wild;
+       BOOL exists=False;
+       int tid2 = SVAL(inbuf,smb_vwv0);
+       int ofun = SVAL(inbuf,smb_vwv1);
+       int flags = SVAL(inbuf,smb_vwv2);
+       BOOL target_is_directory=False;
+       BOOL bad_path1 = False;
+       BOOL bad_path2 = False;
+       BOOL rc = True;
+       SMB_STRUCT_STAT sbuf1, sbuf2;
+
+       START_PROFILE(SMBcopy);
+
+       *directory = *mask = 0;
+
+       p = smb_buf(inbuf);
+       p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE);
+       p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE);
    
-  DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
+       DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
    
-  if (tid2 != conn->cnum) {
-    /* can't currently handle inter share copies XXXX */
-    DEBUG(3,("Rejecting inter-share copy\n"));
-    END_PROFILE(SMBcopy);
-    return ERROR_DOS(ERRSRV,ERRinvdevice);
-  }
-
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-  RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
-
-  rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
-  unix_convert(newname,conn,0,&bad_path2,&sbuf2);
-
-  target_is_directory = VALID_STAT_OF_DIR(sbuf2);
-
-  if ((flags&1) && target_is_directory) {
-    END_PROFILE(SMBcopy);
-    return ERROR_DOS(ERRDOS,ERRbadfile);
-  }
-
-  if ((flags&2) && !target_is_directory) {
-    END_PROFILE(SMBcopy);
-    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_DOS(ERRSRV,ERRerror);
-  }
-
-  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);
-    if (resolve_wildcards(directory,newname) && 
-       copy_file(directory,newname,conn,ofun,
-                 count,target_is_directory,&err)) count++;
-    if(!count && err) {
-               errno = err;
+       if (tid2 != conn->cnum) {
+               /* can't currently handle inter share copies XXXX */
+               DEBUG(3,("Rejecting inter-share copy\n"));
                END_PROFILE(SMBcopy);
-               return(UNIXERROR(ERRHRD,ERRgeneral));
+               return ERROR_DOS(ERRSRV,ERRinvdevice);
        }
-    if (!count) exists = vfs_file_exist(conn,directory,NULL);
-  } else {
-    void *dirptr = NULL;
-    char *dname;
-    pstring destname;
 
-    if (check_name(directory,conn))
-      dirptr = OpenDir(conn, directory, True);
+       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
 
-    if (dirptr) {
-       error = ERRbadfile;
+       rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
+       unix_convert(newname,conn,0,&bad_path2,&sbuf2);
 
-       if (strequal(mask,"????????.???"))
-         pstrcpy(mask,"*");
+       target_is_directory = VALID_STAT_OF_DIR(sbuf2);
 
-       while ((dname = ReadDirName(dirptr))) {
-           pstring fname;
-           pstrcpy(fname,dname);
-           
-           if(!mask_match(fname, mask, case_sensitive))
-                       continue;
+       if ((flags&1) && target_is_directory) {
+               END_PROFILE(SMBcopy);
+               return ERROR_DOS(ERRDOS,ERRbadfile);
+       }
 
-           error = ERRnoaccess;
-           slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-           pstrcpy(destname,newname);
-           if (resolve_wildcards(fname,destname) && 
-               copy_file(fname,destname,conn,ofun,
-                         count,target_is_directory,&err)) count++;
-           DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
-         }
-       CloseDir(dirptr);
-    }
-  }
+       if ((flags&2) && !target_is_directory) {
+               END_PROFILE(SMBcopy);
+               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_DOS(ERRSRV,ERRerror);
+       }
+
+       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 && mangle_is_mangled(mask))
+               mangle_check_cache( mask );
+
+       has_wild = ms_has_wild(mask);
+
+       if (!has_wild) {
+               pstrcat(directory,"/");
+               pstrcat(directory,mask);
+               if (resolve_wildcards(directory,newname) &&
+                               copy_file(directory,newname,conn,ofun, count,target_is_directory,&err))
+                       count++;
+               if(!count && err) {
+                       errno = err;
+                       END_PROFILE(SMBcopy);
+                       return(UNIXERROR(ERRHRD,ERRgeneral));
+               }
+               if (!count) {
+                       exists = vfs_file_exist(conn,directory,NULL);
+               }
+       } else {
+               void *dirptr = NULL;
+               const char *dname;
+               pstring destname;
+
+               if (check_name(directory,conn))
+                       dirptr = OpenDir(conn, directory, True);
+
+               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);
+                               pstrcpy(destname,newname);
+                               if (resolve_wildcards(fname,destname) && 
+                                               copy_file(fname,destname,conn,ofun,
+                                               count,target_is_directory,&err))
+                                       count++;
+                               DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
+                       }
+                       CloseDir(dirptr);
+               }
+       }
   
-  if (count == 0) {
-    if(err) {
-      /* Error on close... */
-      errno = err;
-      END_PROFILE(SMBcopy);
-      return(UNIXERROR(ERRHRD,ERRgeneral));
-    }
-
-    if (exists) {
-      END_PROFILE(SMBcopy);
-      return ERROR_DOS(ERRDOS,error);
-    } else
-    {
-      if((errno == ENOENT) && (bad_path1 || bad_path2))
-      {
-        unix_ERR_class = ERRDOS;
-        unix_ERR_code = ERRbadpath;
-      }
-      END_PROFILE(SMBcopy);
-      return(UNIXERROR(ERRDOS,error));
-    }
-  }
+       if (count == 0) {
+               if(err) {
+                       /* Error on close... */
+                       errno = err;
+                       END_PROFILE(SMBcopy);
+                       return(UNIXERROR(ERRHRD,ERRgeneral));
+               }
+
+               if (exists) {
+                       END_PROFILE(SMBcopy);
+                       return ERROR_DOS(ERRDOS,error);
+               } else {
+                       if((errno == ENOENT) && (bad_path1 || bad_path2)) {
+                               unix_ERR_class = ERRDOS;
+                               unix_ERR_code = ERRbadpath;
+                       }
+                       END_PROFILE(SMBcopy);
+                       return(UNIXERROR(ERRDOS,error));
+               }
+       }
   
-  outsize = set_message(outbuf,1,0,True);
-  SSVAL(outbuf,smb_vwv0,count);
+       outsize = set_message(outbuf,1,0,True);
+       SSVAL(outbuf,smb_vwv0,count);
 
-  END_PROFILE(SMBcopy);
-  return(outsize);
+       END_PROFILE(SMBcopy);
+       return(outsize);
 }
 
 /****************************************************************************
-  reply to a setdir
+ Reply to a setdir.
 ****************************************************************************/
+
 int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  int snum;
-  int outsize = 0;
-  BOOL ok = False;
-  pstring newdir;
-  START_PROFILE(pathworks_setdir);
+       int snum;
+       int outsize = 0;
+       BOOL ok = False;
+       pstring newdir;
+
+       START_PROFILE(pathworks_setdir);
   
-  snum = SNUM(conn);
-  if (!CAN_SETDIR(snum)) {
-    END_PROFILE(pathworks_setdir);
-    return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
+       snum = SNUM(conn);
+       if (!CAN_SETDIR(snum)) {
+               END_PROFILE(pathworks_setdir);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
+       }
 
-  srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), STR_TERMINATE);
   
-  if (strlen(newdir) == 0) {
-         ok = True;
-  } else {
-         ok = vfs_directory_exist(conn,newdir,NULL);
-         if (ok) {
-                 string_set(&conn->connectpath,newdir);
-         }
-  }
+       if (strlen(newdir) == 0) {
+               ok = True;
+       } else {
+               ok = vfs_directory_exist(conn,newdir,NULL);
+               if (ok)
+                       string_set(&conn->connectpath,newdir);
+       }
   
-  if (!ok) {
-         END_PROFILE(pathworks_setdir);
-         return ERROR_DOS(ERRDOS,ERRbadpath);
-  }
+       if (!ok) {
+               END_PROFILE(pathworks_setdir);
+               return ERROR_DOS(ERRDOS,ERRbadpath);
+       }
   
-  outsize = set_message(outbuf,0,0,True);
-  CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
+       outsize = set_message(outbuf,0,0,True);
+       SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
   
-  DEBUG(3,("setdir %s\n", newdir));
+       DEBUG(3,("setdir %s\n", newdir));
 
-  END_PROFILE(pathworks_setdir);
-  return(outsize);
+       END_PROFILE(pathworks_setdir);
+       return(outsize);
 }
 
 /****************************************************************************
@@ -3824,7 +3699,7 @@ 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));
+               return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
 }
 
 /****************************************************************************
@@ -3833,42 +3708,43 @@ uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
 
 SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
 {
-  SMB_BIG_UINT count = 0;
+       SMB_BIG_UINT count = 0;
 
-  if(!large_file_format) {
-    count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
-  } else {
+       if(!large_file_format) {
+               count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
+       } else {
 
 #if defined(HAVE_LONGLONG)
-    count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
-            ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
+               count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+                       ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_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 truncate the
-     * lock count by dropping the top 32 bits.
-     */
-
-    if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
-      DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
-            (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
-            (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
-      SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
-    }
-
-    count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+               /*
+                * 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 truncate the
+                * lock count by dropping the top 32 bits.
+                */
+
+               if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+                       DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
+                               (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+                               (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+                               SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
+               }
+
+               count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
 #endif /* HAVE_LONGLONG */
-  }
+       }
 
-  return count;
+       return count;
 }
 
 #if !defined(HAVE_LONGLONG)
 /****************************************************************************
  Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
 ****************************************************************************/
+
 static uint32 map_lock_offset(uint32 high, uint32 low)
 {
        unsigned int i;
@@ -3904,51 +3780,51 @@ static uint32 map_lock_offset(uint32 high, uint32 low)
 
 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
 {
-  SMB_BIG_UINT offset = 0;
+       SMB_BIG_UINT offset = 0;
 
-  *err = False;
+       *err = False;
 
-  if(!large_file_format) {
-    offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
-  } else {
+       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)));
+               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.
-     */
+               /*
+                * 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));
+               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;
+       return offset;
 }
 
 /****************************************************************************
-  reply to a lockingX request
+ Reply to a lockingX request.
 ****************************************************************************/
 
 int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
@@ -3972,6 +3848,13 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
        CHECK_FSP(fsp,conn);
        
        data = smb_buf(inbuf);
+
+       if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) {
+               /* we don't support these - and CANCEL_LOCK makes w2k
+                  and XP reboot so I don't really want to be
+                  compatible! (tridge) */
+               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+       }
        
        /* Check if this is an oplock break on a file
           we have granted an oplock on.
@@ -4051,7 +3934,8 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
        }
 
        /* Setup the timeout in seconds. */
-       lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+
+       lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
        
        /* Now do any requested locks */
        data += ((large_file_format ? 20 : 10)*num_ulocks);
@@ -4072,19 +3956,20 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
                        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 ));
+               DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n",
+                       (double)offset, (double)count, (unsigned int)lock_pid,
+                       fsp->fsp_name, (int)lock_timeout ));
                
-               status = do_lock(fsp,conn,lock_pid, count,offset, 
+               status = do_lock_spin(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))) {
+                       if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
                                /*
                                 * 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)) {
+                               if(push_blocking_lock_request(inbuf, length, lock_timeout, i, lock_pid, offset, count)) {
                                        END_PROFILE(SMBlockingX);
                                        return -1;
                                }
@@ -4129,183 +4014,378 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
        return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
-
 /****************************************************************************
-  reply to a SMBreadbmpx (read block multiplex) request
+ 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_DOS(ERRSRV,ERRuseSTD);
-  }
-
-  outsize = set_message(outbuf,8,0,True);
-
-  CHECK_FSP(fsp,conn);
-  CHECK_READ(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;
-
-  max_per_packet = bufsize-(outsize+pad);
-  tcount = maxcount;
-  total_read = 0;
-
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
-    END_PROFILE(SMBreadBmpx);
-    return ERROR_DOS(ERRDOS,ERRlock);
-  }
-
-  do
-    {
-      size_t N = MIN(max_per_packet,tcount-total_read);
+       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_DOS(ERRSRV,ERRuseSTD);
+       }
+
+       outsize = set_message(outbuf,8,0,True);
+
+       CHECK_FSP(fsp,conn);
+       CHECK_READ(fsp);
+
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
+       maxcount = SVAL(inbuf,smb_vwv3);
+
+       data = smb_buf(outbuf);
+       pad = ((long)data)%4;
+       if (pad)
+               pad = 4 - pad;
+       data += pad;
+
+       max_per_packet = bufsize-(outsize+pad);
+       tcount = maxcount;
+       total_read = 0;
+
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               END_PROFILE(SMBreadBmpx);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
+
+       do {
+               size_t N = MIN(max_per_packet,tcount-total_read);
   
-      nread = read_file(fsp,data,startpos,N);
+               nread = read_file(fsp,data,startpos,N);
 
-      if (nread <= 0) nread = 0;
+               if (nread <= 0)
+                       nread = 0;
 
-      if (nread < (ssize_t)N)
-        tcount = total_read + nread;
+               if (nread < (ssize_t)N)
+                       tcount = total_read + nread;
 
-      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));
+               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));
 
-      if (!send_smb(smbd_server_fd(),outbuf))
-        exit_server("reply_readbmpx: send_smb failed.\n");
+               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);
+               total_read += nread;
+               startpos += nread;
+       } while (total_read < (ssize_t)tcount);
 
-  END_PROFILE(SMBreadBmpx);
-  return(-1);
+       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)
 {
-  struct utimbuf unix_times;
-  int outsize = 0;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBsetattrE);
+       struct utimbuf unix_times;
+       int outsize = 0;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBsetattrE);
+
+       outsize = set_message(outbuf,0,0,True);
+
+       if(!fsp || (fsp->conn != conn)) {
+               END_PROFILE(SMBgetattrE);
+               return ERROR_DOS(ERRDOS,ERRbadfid);
+       }
+
+       /*
+        * Convert the DOS times into unix times. Ignore create
+        * time as UNIX can't set this.
+        */
+
+       unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
+       unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
+  
+       /* 
+        * Patch from Ray Frush <frush@engr.colostate.edu>
+        * Sometimes times are sent as zero - ignore them.
+        */
+
+       if ((unix_times.actime == 0) && (unix_times.modtime == 0)) {
+               /* Ignore request */
+               if( DEBUGLVL( 3 ) ) {
+                       dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
+                       dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
+               }
+               END_PROFILE(SMBsetattrE);
+               return(outsize);
+       } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) {
+               /* set modify time = to access time if modify time was 0 */
+               unix_times.modtime = unix_times.actime;
+       }
+
+       /* Set the date on this file */
+       if(file_utime(conn, fsp->fsp_name, &unix_times)) {
+               END_PROFILE(SMBsetattrE);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
+       }
+  
+       DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
+               fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
+
+       END_PROFILE(SMBsetattrE);
+       return(outsize);
+}
+
+
+/* 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);
 
-  outsize = set_message(outbuf,0,0,True);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
+       CHECK_ERROR(fsp);
+
+       tcount = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
+       write_through = BITSETW(inbuf+smb_vwv7,0);
+       numtowrite = SVAL(inbuf,smb_vwv10);
+       smb_doff = SVAL(inbuf,smb_vwv11);
 
-  CHECK_FSP(fsp,conn);
+       data = smb_base(inbuf) + smb_doff;
 
-  /* Convert the DOS times into unix times. Ignore create
-     time as UNIX can't set this.
-     */
-  unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
-  unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
+       /* 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);
   
-  /* 
-   * Patch from Ray Frush <frush@engr.colostate.edu>
-   * Sometimes times are sent as zero - ignore them.
-   */
-
-  if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
-  {
-    /* Ignore request */
-    if( DEBUGLVL( 3 ) )
-      {
-      dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
-      dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
-      }
-    END_PROFILE(SMBsetattrE);
-    return(outsize);
-  }
-  else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
-  {
-    /* set modify time = to access time if modify time was 0 */
-    unix_times.modtime = unix_times.actime;
-  }
-
-  /* Set the date on this file */
-  if(file_utime(conn, fsp->fsp_name, &unix_times)) {
-    END_PROFILE(SMBsetattrE);
-    return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
+       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, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
-            fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
+       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.");
 
-  END_PROFILE(SMBsetattrE);
-  return(outsize);
+               /* 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_TO_SMB_OFF_T(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)
 {
-  SMB_STRUCT_STAT sbuf;
-  int outsize = 0;
-  int mode;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBgetattrE);
+       SMB_STRUCT_STAT sbuf;
+       int outsize = 0;
+       int mode;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBgetattrE);
 
-  outsize = set_message(outbuf,11,0,True);
+       outsize = set_message(outbuf,11,0,True);
 
-  CHECK_FSP(fsp,conn);
+       if(!fsp || (fsp->conn != conn)) {
+               END_PROFILE(SMBgetattrE);
+               return ERROR_DOS(ERRDOS,ERRbadfid);
+       }
 
-  /* Do an fstat on this file */
-  if(vfs_fstat(fsp,fsp->fd, &sbuf)) {
-    END_PROFILE(SMBgetattrE);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       /* Do an fstat on this file */
+       if(fsp_stat(fsp, &sbuf)) {
+               END_PROFILE(SMBgetattrE);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
   
-  mode = dos_mode(conn,fsp->fsp_name,&sbuf);
+       mode = dos_mode(conn,fsp->fsp_name,&sbuf);
   
-  /* Convert the times into dos times. Set create
-     date to be last modify date as UNIX doesn't save
-     this */
-  put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
-  put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
-  put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
-  if (mode & aDIR)
-    {
-      SIVAL(outbuf,smb_vwv6,0);
-      SIVAL(outbuf,smb_vwv8,0);
-    }
-  else
-    {
-      SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
-      SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
-    }
-  SSVAL(outbuf,smb_vwv10, mode);
+       /*
+        * Convert the times into dos times. Set create
+        * date to be last modify date as UNIX doesn't save
+        * this.
+        */
+
+       put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
+       put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
+       put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
+
+       if (mode & aDIR) {
+               SIVAL(outbuf,smb_vwv6,0);
+               SIVAL(outbuf,smb_vwv8,0);
+       } else {
+               SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
+               SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
+       }
+       SSVAL(outbuf,smb_vwv10, mode);
   
-  DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
+       DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
   
-  END_PROFILE(SMBgetattrE);
-  return(outsize);
+       END_PROFILE(SMBgetattrE);
+       return(outsize);
 }