r23469: Fix a comment
[sfrench/samba-autobuild/.git] / source / smbd / reply.c
index 282779fcd3560c5c61de8ea0b87b5c4a4005f192..272c3966ba3f468de865c2b9a8b5037d435b0389 100644 (file)
@@ -3,7 +3,7 @@
    Main SMB reply routines
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Andrew Bartlett      2001
-   Copyright (C) Jeremy Allison 1992-2004.
+   Copyright (C) Jeremy Allison 1992-2007.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -36,143 +36,6 @@ extern uint32 global_client_caps;
 extern struct current_user current_user;
 extern BOOL global_encrypted_passwords_negotiated;
 
-/****************************************************************************
- Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
- We're assuming here that '/' is not the second byte in any multibyte char
- set (a safe assumption). '\\' *may* be the second byte in a multibyte char
- set.
-****************************************************************************/
-
-NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
-{
-       char *d = destname;
-       const char *s = srcname;
-       NTSTATUS ret = NT_STATUS_OK;
-       BOOL start_of_name_component = True;
-       unsigned int num_bad_components = 0;
-
-       while (*s) {
-               if (IS_DIRECTORY_SEP(*s)) {
-                       /*
-                        * Safe to assume is not the second part of a mb char as this is handled below.
-                        */
-                       /* Eat multiple '/' or '\\' */
-                       while (IS_DIRECTORY_SEP(*s)) {
-                               s++;
-                       }
-                       if ((d != destname) && (*s != '\0')) {
-                               /* We only care about non-leading or trailing '/' or '\\' */
-                               *d++ = '/';
-                       }
-
-                       start_of_name_component = True;
-                       continue;
-               }
-
-               if (start_of_name_component) {
-                       if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
-                               /* Uh oh - "/../" or "\\..\\"  or "/..\0" or "\\..\0" ! */
-
-                               /*
-                                * No mb char starts with '.' so we're safe checking the directory separator here.
-                                */
-
-                               /* If  we just added a '/' - delete it */
-                               if ((d > destname) && (*(d-1) == '/')) {
-                                       *(d-1) = '\0';
-                                       d--;
-                               }
-
-                               /* Are we at the start ? Can't go back further if so. */
-                               if (d <= destname) {
-                                       ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
-                                       break;
-                               }
-                               /* Go back one level... */
-                               /* We know this is safe as '/' cannot be part of a mb sequence. */
-                               /* NOTE - if this assumption is invalid we are not in good shape... */
-                               /* Decrement d first as d points to the *next* char to write into. */
-                               for (d--; d > destname; d--) {
-                                       if (*d == '/')
-                                               break;
-                               }
-                               s += 2; /* Else go past the .. */
-                               /* We're still at the start of a name component, just the previous one. */
-
-                               if (num_bad_components) {
-                                       /* Hmmm. Should we only decrement the bad_components if
-                                          we're removing a bad component ? Need to check this. JRA. */
-                                       num_bad_components--;
-                               }
-
-                               continue;
-
-                       } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) {
-                               /* Component of pathname can't be "." only. */
-                               ret =  NT_STATUS_OBJECT_NAME_INVALID;
-                               num_bad_components++;
-                               *d++ = *s++;
-                               continue;
-                       }
-               }
-
-               if (!(*s & 0x80)) {
-                       if (*s <= 0x1f) {
-                               return NT_STATUS_OBJECT_NAME_INVALID;
-                       }
-                       switch (*s) {
-                               case '*':
-                               case '?':
-                               case '<':
-                               case '>':
-                               case '"':
-                                       return NT_STATUS_OBJECT_NAME_INVALID;
-                               default:
-                                       *d++ = *s++;
-                                       break;
-                       }
-               } else {
-                       size_t siz;
-                       /* Get the size of the next MB character. */
-                       next_codepoint(s,&siz);
-                       switch(siz) {
-                               case 5:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 4:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 3:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 2:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 1:
-                                       *d++ = *s++;
-                                       break;
-                               default:
-                                       DEBUG(0,("check_path_syntax: character length assumptions invalid !\n"));
-                                       *d = '\0';
-                                       return NT_STATUS_INVALID_PARAMETER;
-                       }
-               }
-               if (start_of_name_component && num_bad_components) {
-                       num_bad_components++;
-               }
-               start_of_name_component = False;
-       }
-
-       if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) {
-               if (num_bad_components > 1) {
-                       ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
-               }
-       }
-
-       *d = '\0';
-       return ret;
-}
-
 /****************************************************************************
  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
  path or anything including wildcards.
@@ -181,23 +44,29 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
  set.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
+/* Custom version for processing POSIX paths. */
+#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
+
+NTSTATUS check_path_syntax_internal(pstring destname,
+                                   const pstring srcname,
+                                   BOOL posix_path,
+                                   BOOL *p_last_component_contains_wcard)
 {
        char *d = destname;
        const char *s = srcname;
        NTSTATUS ret = NT_STATUS_OK;
        BOOL start_of_name_component = True;
-       unsigned int num_bad_components = 0;
 
-       *p_contains_wcard = False;
+       *p_last_component_contains_wcard = False;
 
        while (*s) {
-               if (IS_DIRECTORY_SEP(*s)) {
+               if (IS_PATH_SEP(*s,posix_path)) {
                        /*
-                        * Safe to assume is not the second part of a mb char as this is handled below.
+                        * Safe to assume is not the second part of a mb char
+                        * as this is handled below.
                         */
                        /* Eat multiple '/' or '\\' */
-                       while (IS_DIRECTORY_SEP(*s)) {
+                       while (IS_PATH_SEP(*s,posix_path)) {
                                s++;
                        }
                        if ((d != destname) && (*s != '\0')) {
@@ -206,11 +75,13 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
                        }
 
                        start_of_name_component = True;
+                       /* New component. */
+                       *p_last_component_contains_wcard = False;
                        continue;
                }
 
                if (start_of_name_component) {
-                       if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
+                       if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
                                /* Uh oh - "/../" or "\\..\\"  or "/..\0" or "\\..\0" ! */
 
                                /*
@@ -238,36 +109,30 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
                                }
                                s += 2; /* Else go past the .. */
                                /* We're still at the start of a name component, just the previous one. */
-
-                               if (num_bad_components) {
-                                       /* Hmmm. Should we only decrement the bad_components if
-                                          we're removing a bad component ? Need to check this. JRA. */
-                                       num_bad_components--;
-                               }
-
                                continue;
 
-                       } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) {
-                               /* Component of pathname can't be "." only. */
-                               ret =  NT_STATUS_OBJECT_NAME_INVALID;
-                               num_bad_components++;
-                               *d++ = *s++;
-                               continue;
+                       } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
+                               if (posix_path) {
+                                       /* Eat the '.' */
+                                       s++;
+                                       continue;
+                               }
                        }
+
                }
 
                if (!(*s & 0x80)) {
-                       if (*s <= 0x1f) {
-                               return NT_STATUS_OBJECT_NAME_INVALID;
-                       }
-                       if (!*p_contains_wcard) {
+                       if (!posix_path) {
+                               if (*s <= 0x1f) {
+                                       return NT_STATUS_OBJECT_NAME_INVALID;
+                               }
                                switch (*s) {
                                        case '*':
                                        case '?':
                                        case '<':
                                        case '>':
                                        case '"':
-                                               *p_contains_wcard = True;
+                                               *p_last_component_contains_wcard = True;
                                                break;
                                        default:
                                                break;
@@ -295,130 +160,50 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
                                        *d++ = *s++;
                                        break;
                                default:
-                                       DEBUG(0,("check_path_syntax_wcard: character length assumptions invalid !\n"));
+                                       DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
                                        *d = '\0';
                                        return NT_STATUS_INVALID_PARAMETER;
                        }
                }
-               if (start_of_name_component && num_bad_components) {
-                       num_bad_components++;
-               }
                start_of_name_component = False;
        }
 
-       if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) {
-               /* For some strange reason being called from findfirst changes
-                  the num_components number to cause the error return to change. JRA. */
-               if (num_bad_components > 2) {
-                       ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
-               }
-       }
-
        *d = '\0';
        return ret;
 }
 
 /****************************************************************************
- Check the path for a POSIX client.
- We're assuming here that '/' is not the second byte in any multibyte char
- set (a safe assumption).
+ Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
+ No wildcards allowed.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
 {
-       char *d = destname;
-       const char *s = srcname;
-       NTSTATUS ret = NT_STATUS_OK;
-       BOOL start_of_name_component = True;
-
-       while (*s) {
-               if (*s == '/') {
-                       /*
-                        * Safe to assume is not the second part of a mb char as this is handled below.
-                        */
-                       /* Eat multiple '/' or '\\' */
-                       while (*s == '/') {
-                               s++;
-                       }
-                       if ((d != destname) && (*s != '\0')) {
-                               /* We only care about non-leading or trailing '/' */
-                               *d++ = '/';
-                       }
-
-                       start_of_name_component = True;
-                       continue;
-               }
-
-               if (start_of_name_component) {
-                       if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
-                               /* Uh oh - "/../" or "/..\0" ! */
-
-                               /*
-                                * No mb char starts with '.' so we're safe checking the directory separator here.
-                                */
-
-                               /* If  we just added a '/' - delete it */
-                               if ((d > destname) && (*(d-1) == '/')) {
-                                       *(d-1) = '\0';
-                                       d--;
-                               }
+       BOOL ignore;
+       return check_path_syntax_internal(destname, srcname, False, &ignore);
+}
 
-                               /* Are we at the start ? Can't go back further if so. */
-                               if (d <= destname) {
-                                       ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
-                                       break;
-                               }
-                               /* Go back one level... */
-                               /* We know this is safe as '/' cannot be part of a mb sequence. */
-                               /* NOTE - if this assumption is invalid we are not in good shape... */
-                               /* Decrement d first as d points to the *next* char to write into. */
-                               for (d--; d > destname; d--) {
-                                       if (*d == '/')
-                                               break;
-                               }
-                               s += 2; /* Else go past the .. */
-                               continue;
+/****************************************************************************
+ Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
+ Wildcards allowed - p_contains_wcard returns true if the last component contained
+ a wildcard.
+****************************************************************************/
 
-                       } else if ((s[0] == '.') && ((s[1] == '\0') || (s[1] == '/'))) {
-                               /* Eat the '.' */
-                               s++;
-                               continue;
-                       }
-               }
+NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
+{
+       return check_path_syntax_internal(destname, srcname, False, p_contains_wcard);
+}
 
-               if (!(*s & 0x80)) {
-                       *d++ = *s++;
-               } else {
-                       size_t siz;
-                       /* Get the size of the next MB character. */
-                       next_codepoint(s,&siz);
-                       switch(siz) {
-                               case 5:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 4:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 3:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 2:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 1:
-                                       *d++ = *s++;
-                                       break;
-                               default:
-                                       DEBUG(0,("check_path_syntax_posix: character length assumptions invalid !\n"));
-                                       *d = '\0';
-                                       return NT_STATUS_INVALID_PARAMETER;
-                       }
-               }
-               start_of_name_component = False;
-       }
+/****************************************************************************
+ Check the path for a POSIX client.
+ We're assuming here that '/' is not the second byte in any multibyte char
+ set (a safe assumption).
+****************************************************************************/
 
-       *d = '\0';
-       return ret;
+NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+{
+       BOOL ignore;
+       return check_path_syntax_internal(destname, srcname, True, &ignore);
 }
 
 /****************************************************************************
@@ -443,6 +228,16 @@ size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t de
 
        *contains_wcard = False;
 
+       if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+               /* 
+                * For a DFS path the function parse_dfs_path()
+                * will do the path processing, just make a copy.
+                */
+               pstrcpy(dest, tmppath);
+               *err = NT_STATUS_OK;
+               return ret;
+       }
+
        if (lp_posix_pathnames()) {
                *err = check_path_syntax_posix(dest, tmppath);
        } else {
@@ -470,6 +265,17 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len
        } else {
                ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
        }
+
+       if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+               /* 
+                * For a DFS path the function parse_dfs_path()
+                * will do the path processing, just make a copy.
+                */
+               pstrcpy(dest, tmppath);
+               *err = NT_STATUS_OK;
+               return ret;
+       }
+
        if (lp_posix_pathnames()) {
                *err = check_path_syntax_posix(dest, tmppath);
        } else {
@@ -497,7 +303,7 @@ int reply_special(char *inbuf,char *outbuf)
        
        memset(outbuf,'\0',smb_size);
 
-       smb_setlen(outbuf,0);
+       smb_setlen(inbuf,outbuf,0);
        
        switch (msg_type) {
        case 0x81: /* session request */
@@ -615,7 +421,7 @@ int reply_tcon(connection_struct *conn,
                return ERROR_NT(nt_status);
        }
   
-       outsize = set_message(outbuf,2,0,True);
+       outsize = set_message(inbuf,outbuf,2,0,True);
        SSVAL(outbuf,smb_vwv0,max_recv);
        SSVAL(outbuf,smb_vwv1,conn->cnum);
        SSVAL(outbuf,smb_tid,conn->cnum);
@@ -646,6 +452,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        int passlen = SVAL(inbuf,smb_vwv3);
        pstring path;
        char *p, *q;
+       uint16 tcon_flags = SVAL(inbuf,smb_vwv2);
        
        START_PROFILE(SMBtconX);        
 
@@ -662,13 +469,22 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
  
        if (global_encrypted_passwords_negotiated) {
                password = data_blob(smb_buf(inbuf),passlen);
+               if (lp_security() == SEC_SHARE) {
+                       /*
+                        * Security = share always has a pad byte
+                        * after the password.
+                        */
+                       p = smb_buf(inbuf) + passlen + 1;
+               } else {
+                       p = smb_buf(inbuf) + passlen;
+               }
        } else {
                password = data_blob(smb_buf(inbuf),passlen+1);
                /* Ensure correct termination */
-               password.data[passlen]=0;    
+               password.data[passlen]=0;
+               p = smb_buf(inbuf) + passlen + 1;
        }
 
-       p = smb_buf(inbuf) + passlen;
        p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
 
        /*
@@ -707,16 +523,36 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                server_devicetype = "A:";
 
        if (Protocol < PROTOCOL_NT1) {
-               set_message(outbuf,2,0,True);
+               set_message(inbuf,outbuf,2,0,True);
                p = smb_buf(outbuf);
                p += srvstr_push(outbuf, p, server_devicetype, -1, 
                                 STR_TERMINATE|STR_ASCII);
-               set_message_end(outbuf,p);
+               set_message_end(inbuf,outbuf,p);
        } else {
                /* NT sets the fstype of IPC$ to the null string */
                const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
                
-               set_message(outbuf,3,0,True);
+               if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
+                       /* Return permissions. */
+                       uint32 perm1 = 0;
+                       uint32 perm2 = 0;
+
+                       set_message(inbuf,outbuf,7,0,True);
+
+                       if (IS_IPC(conn)) {
+                               perm1 = FILE_ALL_ACCESS;
+                               perm2 = FILE_ALL_ACCESS;
+                       } else {
+                               perm1 = CAN_WRITE(conn) ?
+                                               SHARE_ALL_ACCESS :
+                                               SHARE_READ_ONLY;
+                       }
+
+                       SIVAL(outbuf, smb_vwv3, perm1);
+                       SIVAL(outbuf, smb_vwv5, perm2);
+               } else {
+                       set_message(inbuf,outbuf,3,0,True);
+               }
 
                p = smb_buf(outbuf);
                p += srvstr_push(outbuf, p, server_devicetype, -1, 
@@ -724,7 +560,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                p += srvstr_push(outbuf, p, fstype, -1, 
                                 STR_TERMINATE);
                
-               set_message_end(outbuf,p);
+               set_message_end(inbuf,outbuf,p);
                
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
@@ -787,7 +623,7 @@ int reply_ioctl(connection_struct *conn,
                return(ERROR_DOS(ERRSRV,ERRnosupport));
        }
 
-       outsize = set_message(outbuf,8,replysize+1,True);
+       outsize = set_message(inbuf,outbuf,8,replysize+1,True);
        SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
        SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
        SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
@@ -815,78 +651,101 @@ int reply_ioctl(connection_struct *conn,
 }
 
 /****************************************************************************
- Reply to a chkpth.
+ Strange checkpath NTSTATUS mapping.
+****************************************************************************/
+
+static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status)
+{
+       /* Strange DOS error code semantics only for checkpath... */
+       if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
+               if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
+                       /* We need to map to ERRbadpath */
+                       return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               }
+       }
+       return status;
+}
+       
+/****************************************************************************
+ Reply to a checkpath.
 ****************************************************************************/
 
-int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
        int outsize = 0;
        pstring name;
-       BOOL ok = False;
-       BOOL bad_path = False;
        SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
 
-       START_PROFILE(SMBchkpth);
+       START_PROFILE(SMBcheckpath);
 
        srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
-               END_PROFILE(SMBchkpth);
-
-               /* Strange DOS error code semantics only for chkpth... */
-               if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
-                       if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
-                               /* We need to map to ERRbadpath */
-                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                       }
-               }
+               END_PROFILE(SMBcheckpath);
+               status = map_checkpath_error(inbuf, status);
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       END_PROFILE(SMBcheckpath);
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               goto path_err;
+       }
+
+       DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(inbuf,smb_vwv0)));
 
-       unix_convert(name,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
-               END_PROFILE(SMBchkpth);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       status = unix_convert(conn, name, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto path_err;
        }
 
-       if (check_name(name,conn)) {
-               if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0)
-                       if (!(ok = S_ISDIR(sbuf.st_mode))) {
-                               END_PROFILE(SMBchkpth);
-                               return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath);
-                       }
+       status = check_name(conn, name);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status)));
+               goto path_err;
        }
 
-       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) {
-                       /*
-                        * Windows returns different error codes if
-                        * the parent directory is valid but not the
-                        * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
-                        * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
-                        * if the path is invalid. This is different from set_bad_path_error()
-                        * in the non-NT error case.
-                        */
-                       END_PROFILE(SMBchkpth);
-                       return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath);
-               }
+       if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
+               DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
+               status = map_nt_error_from_unix(errno);
+               goto path_err;
+       }
 
-               END_PROFILE(SMBchkpth);
-               return(UNIXERROR(ERRDOS,ERRbadpath));
+       if (!S_ISDIR(sbuf.st_mode)) {
+               END_PROFILE(SMBcheckpath);
+               return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath);
        }
 
-       outsize = set_message(outbuf,0,0,False);
-       DEBUG(3,("chkpth %s mode=%d\n", name, (int)SVAL(inbuf,smb_vwv0)));
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
-       END_PROFILE(SMBchkpth);
-       return(outsize);
+       END_PROFILE(SMBcheckpath);
+       return outsize;
+
+  path_err:
+
+       END_PROFILE(SMBcheckpath);
+
+       /* 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.
+       */
+       status = map_checkpath_error(inbuf, status);
+       if(NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               /*
+                * Windows returns different error codes if
+                * the parent directory is valid but not the
+                * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
+                * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
+                * if the path is invalid.
+                */
+               return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath);
+       }
+
+       return ERROR_NT(status);
 }
 
 /****************************************************************************
@@ -898,11 +757,9 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        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;
        NTSTATUS status;
 
@@ -915,43 +772,50 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBgetatr);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
   
        /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
                under WfWg - weird! */
-       if (! (*fname)) {
+       if (*fname == '\0') {
                mode = aHIDDEN | aDIR;
-               if (!CAN_WRITE(conn))
+               if (!CAN_WRITE(conn)) {
                        mode |= aRONLY;
+               }
                size = 0;
                mtime = 0;
-               ok = True;
        } else {
-               unix_convert(fname,conn,0,&bad_path,&sbuf);
-               if (bad_path) {
+               status = unix_convert(conn, fname, False, NULL,&sbuf);
+               if (!NT_STATUS_IS_OK(status)) {
                        END_PROFILE(SMBgetatr);
-                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
-               }
-               if (check_name(fname,conn)) {
-                       if (VALID_STAT(sbuf) || SMB_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)));
-                       }
+                       return ERROR_NT(status);
+               }
+               status = check_name(conn, fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
+                       END_PROFILE(SMBgetatr);
+                       return ERROR_NT(status);
+               }
+               if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
+                       DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
+                       return UNIXERROR(ERRDOS,ERRbadfile);
+               }
+
+               mode = dos_mode(conn,fname,&sbuf);
+               size = sbuf.st_size;
+               mtime = sbuf.st_mtime;
+               if (mode & aDIR) {
+                       size = 0;
                }
        }
   
-       if (!ok) {
-               END_PROFILE(SMBgetatr);
-               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadfile);
-       }
-       outsize = set_message(outbuf,10,0,True);
+       outsize = set_message(inbuf,outbuf,10,0,True);
 
        SSVAL(outbuf,smb_vwv0,mode);
        if(lp_dos_filetime_resolution(SNUM(conn)) ) {
@@ -965,7 +829,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                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,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
   
        END_PROFILE(SMBgetatr);
        return(outsize);
@@ -979,11 +843,9 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 {
        pstring fname;
        int outsize = 0;
-       BOOL ok=False;
        int mode;
        time_t mtime;
        SMB_STRUCT_STAT sbuf;
-       BOOL bad_path = False;
        char *p;
        NTSTATUS status;
 
@@ -996,12 +858,34 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBsetatr);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
   
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBsetatr);
+               return ERROR_NT(status);
+       }
+
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBsetatr);
+               return ERROR_NT(status);
+       }
+
+       if (fname[0] == '.' && fname[1] == '\0') {
+               /*
+                * Not sure here is the right place to catch this
+                * condition. Might be moved to somewhere else later -- vl
+                */
                END_PROFILE(SMBsetatr);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(NT_STATUS_ACCESS_DENIED);
        }
 
        mode = SVAL(inbuf,smb_vwv0);
@@ -1013,22 +897,18 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                else
                        mode &= ~aDIR;
 
-               if (check_name(fname,conn)) {
-                       ok = (file_set_dosmode(conn,fname,mode,&sbuf,False) == 0);
+               if (file_set_dosmode(conn,fname,mode,&sbuf,False) != 0) {
+                       END_PROFILE(SMBsetatr);
+                       return UNIXERROR(ERRDOS, ERRnoaccess);
                }
-       } else {
-               ok = True;
        }
 
-       if (ok)
-               ok = set_filetime(conn,fname,mtime);
-  
-       if (!ok) {
+       if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) {
                END_PROFILE(SMBsetatr);
-               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
+               return UNIXERROR(ERRDOS, ERRnoaccess);
        }
  
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
   
        DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
   
@@ -1051,7 +931,7 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
                return(UNIXERROR(ERRHRD,ERRgeneral));
        }
   
-       outsize = set_message(outbuf,5,0,True);
+       outsize = set_message(inbuf,outbuf,5,0,True);
        
        if (Protocol <= PROTOCOL_LANMAN2) {
                double total_space, free_space;
@@ -1106,15 +986,12 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        unsigned int maxentries = 0;
        BOOL finished = False;
        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;
        NTSTATUS nt_status;
        BOOL mask_contains_wcard = False;
        BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
@@ -1129,10 +1006,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        *mask = *directory = *fname = 0;
 
        /* If we were called as SMBffirst then we must expect close. */
-       if(CVAL(inbuf,smb_com) == SMBffirst)
+       if(CVAL(inbuf,smb_com) == SMBffirst) {
                expect_close = True;
+       }
   
-       outsize = set_message(outbuf,1,3,True);
+       outsize = set_message(inbuf,outbuf,1,3,True);
        maxentries = SVAL(inbuf,smb_vwv0); 
        dirtype = SVAL(inbuf,smb_vwv1);
        p = smb_buf(inbuf) + 1;
@@ -1142,7 +1020,14 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(nt_status);
        }
 
-       RESOLVE_DFSPATH_WCARD(path, conn, inbuf, outbuf);
+       nt_status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path, &mask_contains_wcard);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               END_PROFILE(SMBsearch);
+               if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(nt_status);
+       }
   
        p++;
        status_len = SVAL(p, 0);
@@ -1152,33 +1037,32 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
        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);
+               nt_status = unix_convert(conn, directory, True, NULL, &sbuf);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       END_PROFILE(SMBsearch);
+                       return ERROR_NT(nt_status);
+               }
 
-               if (!check_name(directory,conn))
-                       can_open = False;
+               nt_status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       END_PROFILE(SMBsearch);
+                       return ERROR_NT(nt_status);
+               }
 
-               p = strrchr_m(dir2,'/');
-               if (p == NULL) {
-                       pstrcpy(mask,dir2);
-                       *dir2 = 0;
+               p = strrchr_m(directory,'/');
+               if (!p) {
+                       pstrcpy(mask,directory);
+                       pstrcpy(directory,".");
                } else {
                        *p = 0;
                        pstrcpy(mask,p+1);
                }
 
-               p = strrchr_m(directory,'/');
-               if (!p) 
-                       *directory = 0;
-               else
-                       *p = 0;
-
-               if (strlen(directory) == 0)
+               if (*directory == '\0') {
                        pstrcpy(directory,".");
+               }
                memset((char *)status,'\0',21);
                SCVAL(status,0,(dirtype & 0x1F));
        } else {
@@ -1186,83 +1070,90 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
                memcpy(status,p,21);
                status_dirtype = CVAL(status,0) & 0x1F;
-               if (status_dirtype != (dirtype & 0x1F))
+               if (status_dirtype != (dirtype & 0x1F)) {
                        dirtype = status_dirtype;
+               }
 
                conn->dirptr = dptr_fetch(status+12,&dptr_num);      
-               if (!conn->dirptr)
+               if (!conn->dirptr) {
                        goto SearchEmpty;
+               }
                string_set(&conn->dirpath,dptr_path(dptr_num));
                pstrcpy(mask, dptr_wcard(dptr_num));
+               /*
+                * For a 'continue' search we have no string. So
+                * check from the initial saved string.
+                */
+               mask_contains_wcard = ms_has_wild(mask);
        }
 
-       if (can_open) {
-               p = smb_buf(outbuf) + 3;
-               ok = True;
+       p = smb_buf(outbuf) + 3;
      
-               if (status_len == 0) {
-                       dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype);
-                       if (dptr_num < 0) {
-                               if(dptr_num == -2) {
-                                       END_PROFILE(SMBsearch);
-                                       return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnofids);
-                               }
-                               END_PROFILE(SMBsearch);
-                               return ERROR_DOS(ERRDOS,ERRnofids);
-                       }
+       if (status_len == 0) {
+               nt_status = dptr_create(conn,
+                                       directory,
+                                       True,
+                                       expect_close,
+                                       SVAL(inbuf,smb_pid),
+                                       mask,
+                                       mask_contains_wcard,
+                                       dirtype,
+                                       &conn->dirptr);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       return ERROR_NT(nt_status);
+               }
+               dptr_num = dptr_dnum(conn->dirptr);
+       } else {
+               dirtype = dptr_attr(dptr_num);
+       }
+
+       DEBUG(4,("dptr_num is %d\n",dptr_num));
+
+       if ((dirtype&0x1F) == aVOLID) {   
+               memcpy(p,status,21);
+               make_dir_struct(p,"???????????",volume_label(SNUM(conn)),
+                               0,aVOLID,0,!allow_long_path_components);
+               dptr_fill(p+12,dptr_num);
+               if (dptr_zero(p+12) && (status_len==0)) {
+                       numentries = 1;
                } else {
-                       dirtype = dptr_attr(dptr_num);
+                       numentries = 0;
                }
+               p += DIR_STRUCT_SIZE;
+       } else {
+               unsigned int i;
+               maxentries = MIN(maxentries, ((BUFFER_SIZE - (p - outbuf))/DIR_STRUCT_SIZE));
 
-               DEBUG(4,("dptr_num is %d\n",dptr_num));
+               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;
+               }
 
-               if (ok) {
-                       if ((dirtype&0x1F) == aVOLID) {   
+               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,"???????????",volume_label(SNUM(conn)),
-                                               0,aVOLID,0,!allow_long_path_components);
-                               dptr_fill(p+12,dptr_num);
-                               if (dptr_zero(p+12) && (status_len==0))
-                                       numentries = 1;
-                               else
-                                       numentries = 0;
-                               p += DIR_STRUCT_SIZE;
-                       } else {
-                               unsigned int i;
-                               maxentries = MIN(maxentries, ((BUFFER_SIZE - (p - outbuf))/DIR_STRUCT_SIZE));
-
-                               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,
-                                                               !allow_long_path_components);
-                                               if (!dptr_fill(p+12,dptr_num)) {
-                                                       break;
-                                               }
-                                               numentries++;
-                                               p += DIR_STRUCT_SIZE;
-                                       }
+                               make_dir_struct(p,mask,fname,size, mode,date,
+                                               !allow_long_path_components);
+                               if (!dptr_fill(p+12,dptr_num)) {
+                                       break;
                                }
+                               numentries++;
+                               p += DIR_STRUCT_SIZE;
                        }
-               } /* if (ok ) */
+               }
        }
 
-
   SearchEmpty:
 
        /* 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 (numentries == 0 || !ok) {
+       if (numentries == 0) {
                dptr_close(&dptr_num);
-       } else if(ok && expect_close && status_len == 0) {
+       } else if(expect_close && status_len == 0) {
                /* Close the dptr - we know it's gone */
                dptr_close(&dptr_num);
        }
@@ -1291,7 +1182,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        SSVAL(outbuf,smb_flg2, (SVAL(outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
          
        outsize += DIR_STRUCT_SIZE*numentries;
-       smb_setlen(outbuf,outsize - 4);
+       smb_setlen(inbuf,outbuf,outsize - 4);
   
        if ((! *directory) && dptr_path(dptr_num))
                slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
@@ -1326,7 +1217,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return reply_unknown(inbuf, outbuf);
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        p = smb_buf(inbuf) + 1;
        p += srvstr_get_path_wcard(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, &path_contains_wcard);
        if (!NT_STATUS_IS_OK(err)) {
@@ -1370,7 +1261,6 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        time_t mtime=0;
        int info;
        SMB_STRUCT_STAT sbuf;
-       BOOL bad_path = False;
        files_struct *fsp;
        int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
        int deny_mode;
@@ -1390,14 +1280,27 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBopen);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
 
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBopen);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
     
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBopen);
+               return ERROR_NT(status);
+       }
+
        if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN,
                        &access_mask, &share_mode, &create_disposition, &create_options)) {
                END_PROFILE(SMBopen);
@@ -1433,7 +1336,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
   
-       outsize = set_message(outbuf,7,0,True);
+       outsize = set_message(inbuf,outbuf,7,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
        SSVAL(outbuf,smb_vwv1,fattr);
        if(lp_dos_filetime_resolution(SNUM(conn)) ) {
@@ -1475,12 +1378,10 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
 #endif
        int smb_ofun = SVAL(inbuf,smb_vwv8);
-       SMB_OFF_T size=0;
        uint32 fattr=0;
        int mtime=0;
        SMB_STRUCT_STAT sbuf;
        int smb_action = 0;
-       BOOL bad_path = False;
        files_struct *fsp;
        NTSTATUS status;
        SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9);
@@ -1510,12 +1411,25 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBopenX);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBopenX);
+               return ERROR_NT(status);
+       }
 
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBopenX);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
 
        if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun,
@@ -1545,8 +1459,6 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return ERROR_NT(status);
        }
 
-       size = sbuf.st_size;
-
        /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
           if the file is truncated or created. */
        if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
@@ -1562,7 +1474,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                        END_PROFILE(SMBopenX);
                        return ERROR_NT(NT_STATUS_DISK_FULL);
                }
-               size = get_allocation_size(conn,fsp,&sbuf);
+               sbuf.st_size = get_allocation_size(conn,fsp,&sbuf);
        }
 
        fattr = dos_mode(conn,fname,&sbuf);
@@ -1600,9 +1512,9 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
        if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
-               set_message(outbuf,19,0,True);
+               set_message(inbuf,outbuf,19,0,True);
        } else {
-               set_message(outbuf,15,0,True);
+               set_message(inbuf,outbuf,15,0,True);
        }
        SSVAL(outbuf,smb_vwv2,fsp->fnum);
        SSVAL(outbuf,smb_vwv3,fattr);
@@ -1611,7 +1523,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        } else {
                srv_put_dos_date3(outbuf,smb_vwv4,mtime);
        }
-       SIVAL(outbuf,smb_vwv6,(uint32)size);
+       SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
        SSVAL(outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
        SSVAL(outbuf,smb_vwv11,smb_action);
 
@@ -1644,7 +1556,7 @@ int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,
 
        invalidate_vuid(vuid);
 
-       set_message(outbuf,2,0,True);
+       set_message(inbuf,outbuf,2,0,True);
 
        DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
 
@@ -1662,7 +1574,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        int com;
        int outsize = 0;
        uint32 fattr = SVAL(inbuf,smb_vwv0);
-       BOOL bad_path = False;
+       struct timespec ts[2];
        files_struct *fsp;
        int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
        SMB_STRUCT_STAT sbuf;
@@ -1676,18 +1588,33 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  
        com = SVAL(inbuf,smb_com);
 
+       ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(inbuf + smb_vwv1)); /* mtime. */
+
        srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcreate);
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcreate);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcreate);
+               return ERROR_NT(status);
+       }
 
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcreate);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
 
        if (fattr & aVOLID) {
@@ -1721,7 +1648,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
  
-       outsize = set_message(outbuf,1,0,True);
+       ts[0] = get_atimespec(&sbuf); /* atime. */
+       file_ntimes(conn, fname, ts);
+
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
 
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
@@ -1748,7 +1678,6 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        pstring fname;
        int outsize = 0;
        uint32 fattr = SVAL(inbuf,smb_vwv0);
-       BOOL bad_path = False;
        files_struct *fsp;
        int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
        int tmpfd;
@@ -1770,12 +1699,25 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                pstrcat(fname,"TMXXXXXX");
        }
 
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBctemp);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBctemp);
+               return ERROR_NT(status);
+       }
 
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBctemp);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
   
        tmpfd = smb_mkstemp(fname);
@@ -1808,7 +1750,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
 
        /* the returned filename is relative to the directory */
@@ -1827,7 +1769,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 #endif
        namelen = srvstr_push(outbuf, p, s, -1, STR_ASCII|STR_TERMINATE);
        p += namelen;
-       outsize = set_message_end(outbuf, p);
+       outsize = set_message_end(inbuf,outbuf, p);
 
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
                SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
@@ -1849,7 +1791,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  Check if a user is allowed to rename a file.
 ********************************************************************/
 
-static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open)
 {
        files_struct *fsp;
        uint32 fmode;
@@ -1870,7 +1812,10 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
 
        status = open_file_ntcreate(conn, fname, pst,
                                DELETE_ACCESS,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE,
+                               /* If we're checking our fsp don't deny for delete. */
+                               self_open ?
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE :
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
                                FILE_OPEN,
                                0,
                                FILE_ATTRIBUTE_NORMAL,
@@ -1878,46 +1823,82 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
                                NULL, &fsp);
 
        if (!NT_STATUS_IS_OK(status)) {
-               return NT_STATUS_ACCESS_DENIED;
+               return status;
        }
        close_file(fsp,NORMAL_CLOSE);
        return NT_STATUS_OK;
 }
 
 /*******************************************************************
- Check if a user is allowed to delete a file.
-********************************************************************/
+ * unlink a file with all relevant access checks
+ *******************************************************************/
 
-NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL bad_path, BOOL check_is_at_open)
+static NTSTATUS do_unlink(connection_struct *conn, char *fname,
+                         uint32 dirtype, BOOL can_defer)
 {
        SMB_STRUCT_STAT sbuf;
        uint32 fattr;
        files_struct *fsp;
+       uint32 dirtype_orig = dirtype;
        NTSTATUS status;
 
-       DEBUG(10,("can_delete: %s, dirtype = %d\n", fname, dirtype ));
+       DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype ));
 
        if (!CAN_WRITE(conn)) {
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
        if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
-               if(errno == ENOENT) {
-                       if (bad_path) {
-                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                       } else {
-                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                       }
-               }
                return map_nt_error_from_unix(errno);
        }
 
        fattr = dos_mode(conn,fname,&sbuf);
 
+       if (dirtype & FILE_ATTRIBUTE_NORMAL) {
+               dirtype = aDIR|aARCH|aRONLY;
+       }
+
+       dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
+       if (!dirtype) {
+               return NT_STATUS_NO_SUCH_FILE;
+       }
+
+       if (!dir_check_ftype(conn, fattr, dirtype)) {
+               if (fattr & aDIR) {
+                       return NT_STATUS_FILE_IS_A_DIRECTORY;
+               }
+               return NT_STATUS_NO_SUCH_FILE;
+       }
+
+       if (dirtype_orig & 0x8000) {
+               /* These will never be set for POSIX. */
+               return NT_STATUS_NO_SUCH_FILE;
+       }
+
+#if 0
+       if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
+                return NT_STATUS_FILE_IS_A_DIRECTORY;
+        }
+
+        if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
+                return NT_STATUS_NO_SUCH_FILE;
+        }
+
+       if (dirtype & 0xFF00) {
+               /* These will never be set for POSIX. */
+               return NT_STATUS_NO_SUCH_FILE;
+       }
+
+       dirtype &= 0xFF;
+       if (!dirtype) {
+               return NT_STATUS_NO_SUCH_FILE;
+       }
+
        /* Can't delete a directory. */
        if (fattr & aDIR) {
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
+#endif
 
 #if 0 /* JRATEST */
        else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
@@ -1936,38 +1917,37 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b
          from Windows Explorer).
        */
 
-       if (!check_is_at_open && !lp_delete_readonly(SNUM(conn))) {
+       if (!lp_delete_readonly(SNUM(conn))) {
                if (fattr & aRONLY) {
                        return NT_STATUS_CANNOT_DELETE;
                }
        }
-       if ((fattr & ~dirtype) & (aHIDDEN | aSYSTEM)) {
-               return NT_STATUS_NO_SUCH_FILE;
-       }
 
-       if (check_is_at_open) {
-               if (!can_delete_file_in_directory(conn, fname)) {
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-       } else {
-               /* On open checks the open itself will check the share mode, so
-                  don't do it here as we'll get it wrong. */
-
-               status = open_file_ntcreate(conn, fname, &sbuf,
-                                       DELETE_ACCESS,
-                                       FILE_SHARE_NONE,
-                                       FILE_OPEN,
-                                       0,
-                                       FILE_ATTRIBUTE_NORMAL,
-                                       0,
-                                       NULL, &fsp);
+       /* On open checks the open itself will check the share mode, so
+          don't do it here as we'll get it wrong. */
 
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-               close_file(fsp,NORMAL_CLOSE);
+       status = open_file_ntcreate(conn, fname, &sbuf,
+                                   DELETE_ACCESS,
+                                   FILE_SHARE_NONE,
+                                   FILE_OPEN,
+                                   0,
+                                   FILE_ATTRIBUTE_NORMAL,
+                                   can_defer ? 0 : INTERNAL_OPEN_ONLY,
+                                   NULL, &fsp);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("open_file_ntcreate failed: %s\n",
+                          nt_errstr(status)));
+               return status;
        }
-       return NT_STATUS_OK;
+
+       /* The set is across all open files on this dev/inode pair. */
+       if (!set_delete_on_close(fsp, True, &current_user.ut)) {
+               close_file(fsp, NORMAL_CLOSE);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       return close_file(fsp,NORMAL_CLOSE);
 }
 
 /****************************************************************************
@@ -1975,20 +1955,22 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b
  code.
 ****************************************************************************/
 
-NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, BOOL has_wild)
+NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
+                         char *name, BOOL has_wild, BOOL can_defer)
 {
        pstring directory;
        pstring mask;
        char *p;
        int count=0;
-       NTSTATUS error = NT_STATUS_OK;
-       BOOL bad_path = False;
-       BOOL rc = True;
+       NTSTATUS status = NT_STATUS_OK;
        SMB_STRUCT_STAT sbuf;
        
        *directory = *mask = 0;
        
-       rc = unix_convert(name,conn,0,&bad_path,&sbuf);
+       status = unix_convert(conn, name, has_wild, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
        
        p = strrchr_m(name,'/');
        if (!p) {
@@ -2009,87 +1991,102 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, B
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
        
-       if (!rc && mangle_is_mangled(mask,conn->params))
+       if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params))
                mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
        
        if (!has_wild) {
                pstrcat(directory,"/");
                pstrcat(directory,mask);
-               error = can_delete(conn,directory,dirtype,bad_path,False);
-               if (!NT_STATUS_IS_OK(error))
-                       return error;
+               if (dirtype == 0) {
+                       dirtype = FILE_ATTRIBUTE_NORMAL;
+               }
 
-               if (SMB_VFS_UNLINK(conn,directory) == 0) {
-                       count++;
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
+
+               status = do_unlink(conn,directory,dirtype,can_defer);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
+               count++;
        } else {
                struct smb_Dir *dir_hnd = NULL;
+               long offset = 0;
                const char *dname;
                
-               if (strequal(mask,"????????.???"))
+               if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+
+               if (strequal(mask,"????????.???")) {
                        pstrcpy(mask,"*");
+               }
+
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
-               if (check_name(directory,conn))
-                       dir_hnd = OpenDir(conn, directory, mask, dirtype);
+               dir_hnd = OpenDir(conn, directory, mask, dirtype);
+               if (dir_hnd == NULL) {
+                       return map_nt_error_from_unix(errno);
+               }
                
                /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
                   the pattern matches against the long name, otherwise the short name 
                   We don't implement this yet XXXX
                */
                
-               if (dir_hnd) {
-                       long offset = 0;
-                       error = NT_STATUS_NO_SUCH_FILE;
+               status = NT_STATUS_NO_SUCH_FILE;
 
-                       while ((dname = ReadDirName(dir_hnd, &offset))) {
-                               SMB_STRUCT_STAT st;
-                               pstring fname;
-                               BOOL sys_direntry = False;
-                               pstrcpy(fname,dname);
+               while ((dname = ReadDirName(dir_hnd, &offset))) {
+                       SMB_STRUCT_STAT st;
+                       pstring fname;
+                       pstrcpy(fname,dname);
 
-                               if (!is_visible_file(conn, directory, dname, &st, True)) {
-                                       continue;
-                               }
+                       if (!is_visible_file(conn, directory, dname, &st, True)) {
+                               continue;
+                       }
 
-                               /* Quick check for "." and ".." */
-                               if (fname[0] == '.') {
-                                       if (!fname[1] || (fname[1] == '.' && !fname[2])) {
-                                               if ((dirtype & FILE_ATTRIBUTE_DIRECTORY) && (dirtype & FILE_ATTRIBUTE_SYSTEM)) {
-                                                       sys_direntry = True;
-                                               } else {
-                                                       continue;
-                                               }
-                                       }
+                       /* Quick check for "." and ".." */
+                       if (fname[0] == '.') {
+                               if (!fname[1] || (fname[1] == '.' && !fname[2])) {
+                                       continue;
                                }
+                       }
 
-                               if(!mask_match(fname, mask, conn->case_sensitive))
-                                       continue;
+                       if(!mask_match(fname, mask, conn->case_sensitive)) {
+                               continue;
+                       }
                                
-                               if (sys_direntry) {
-                                       error = NT_STATUS_OBJECT_NAME_INVALID;
-                                       DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n",
-                                               fname, mask));
-                                       break;
-                               }
+                       slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
 
-                               slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-                               error = can_delete(conn,fname,dirtype,bad_path,False);
-                               if (!NT_STATUS_IS_OK(error)) {
-                                       continue;
-                               }
-                               if (SMB_VFS_UNLINK(conn,fname) == 0)
-                                       count++;
-                               DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
+                       status = check_name(conn, fname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               CloseDir(dir_hnd);
+                               return status;
+                       }
+
+                       status = do_unlink(conn, fname, dirtype, can_defer);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               continue;
                        }
-                       CloseDir(dir_hnd);
+
+                       count++;
+                       DEBUG(3,("unlink_internals: succesful unlink [%s]\n",
+                                fname));
                }
+               CloseDir(dir_hnd);
        }
        
-       if (count == 0 && NT_STATUS_IS_OK(error)) {
-               error = map_nt_error_from_unix(errno);
+       if (count == 0 && NT_STATUS_IS_OK(status)) {
+               status = map_nt_error_from_unix(errno);
        }
 
-       return error;
+       return status;
 }
 
 /****************************************************************************
@@ -2114,12 +2111,20 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                END_PROFILE(SMBunlink);
                return ERROR_NT(status);
        }
-       
-       RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
+
+       status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &path_contains_wcard);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBunlink);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
        
        DEBUG(3,("reply_unlink : %s\n",name));
        
-       status = unlink_internals(conn, dirtype, name, path_contains_wcard);
+       status = unlink_internals(conn, dirtype, name, path_contains_wcard,
+                                 True);
        if (!NT_STATUS_IS_OK(status)) {
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
@@ -2128,13 +2133,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
 
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */
-       process_pending_change_notify_queue((time_t)0);
-       
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
   
        END_PROFILE(SMBunlink);
        return outsize;
@@ -2152,39 +2151,42 @@ static void fail_readraw(void)
        exit_server_cleanly(errstr);
 }
 
-#if defined(WITH_SENDFILE)
 /****************************************************************************
  Fake (read/write) sendfile. Returns -1 on read or write fail.
 ****************************************************************************/
 
-static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize)
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, size_t bufsize)
 {
-       ssize_t ret=0;
+       size_t tosend = nread;
 
-       /* Paranioa check... */
-       if (nread > bufsize) {
-               fail_readraw();
-       }
+       while (tosend > 0) {
+               ssize_t ret;
+               size_t cur_read;
 
-       if (nread > 0) {
-               ret = read_file(fsp,buf,startpos,nread);
+               if (tosend > bufsize) {
+                       cur_read = bufsize;
+               } else {
+                       cur_read = tosend;
+               }
+               ret = read_file(fsp,buf,startpos,cur_read);
                if (ret == -1) {
                        return -1;
                }
-       }
 
-       /* If we had a short read, fill with zeros. */
-       if (ret < nread) {
-               memset(buf, '\0', nread - ret);
+               /* If we had a short read, fill with zeros. */
+               if (ret < cur_read) {
+                       memset(buf, '\0', cur_read - ret);
+               }
+
+               if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
+                       return -1;
+               }
+               tosend -= cur_read;
+               startpos += cur_read;
        }
 
-       if (write_data(smbd_server_fd(),buf,nread) != nread) {
-               return -1;
-       }       
-
        return (ssize_t)nread;
 }
-#endif
 
 /****************************************************************************
  Use sendfile in readbraw.
@@ -2241,12 +2243,12 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
                        exit_server_cleanly("send_file_readbraw sendfile failed");
                }
 
+               return;
        }
-
-  normal_readbraw:
-
 #endif
 
+normal_readbraw:
+
        if (nread > 0) {
                ret = read_file(fsp,outbuf+4,startpos,nread);
 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
@@ -2405,7 +2407,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        numtoread = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
   
-       outsize = set_message(outbuf,5,3,True);
+       outsize = set_message(inbuf,outbuf,5,3,True);
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
        data = smb_buf(outbuf) + 3;
        
@@ -2417,14 +2419,16 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
         * Note that the requested lock size is unaffected by max_recv.
         */
        
-       br_lck = do_lock(fsp,
+       br_lck = do_lock(smbd_messaging_context(),
+                       fsp,
                        (uint32)SVAL(inbuf,smb_pid), 
                        (SMB_BIG_UINT)numtoread,
                        (SMB_BIG_UINT)startpos,
                        WRITE_LOCK,
                        WINDOWS_LOCK,
                        False, /* Non-blocking lock. */
-                       &status);
+                       &status,
+                       NULL);
        TALLOC_FREE(br_lck);
 
        if (NT_STATUS_V(status)) {
@@ -2486,7 +2490,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        numtoread = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
 
-       outsize = set_message(outbuf,5,3,True);
+       outsize = set_message(inbuf,outbuf,5,3,True);
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
        /*
         * The requested read size cannot be greater than max_recv. JRA.
@@ -2526,6 +2530,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
        return(outsize);
 }
 
+/****************************************************************************
+ Setup readX header.
+****************************************************************************/
+
+static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
+{
+       int outsize;
+       char *data = smb_buf(outbuf);
+
+       SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
+       SSVAL(outbuf,smb_vwv5,smb_maxcnt);
+       SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+       SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
+       SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
+       SCVAL(outbuf,smb_vwv0,0xFF);
+       outsize = set_message(inbuf, outbuf,12,smb_maxcnt,False);
+       /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
+       _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
+       return outsize;
+}
+
 /****************************************************************************
  Reply to a read and X - possibly using sendfile.
 ****************************************************************************/
@@ -2533,10 +2558,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
 int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
                files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
 {
+       SMB_STRUCT_STAT sbuf;
        int outsize = 0;
        ssize_t nread = -1;
        char *data = smb_buf(outbuf);
 
+       if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) {
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       if (startpos > sbuf.st_size) {
+               smb_maxcnt = 0;
+       }
+
+       if (smb_maxcnt > (sbuf.st_size - startpos)) {
+               smb_maxcnt = (sbuf.st_size - startpos);
+       }
+
+       if (smb_maxcnt == 0) {
+               goto normal_read;
+       }
+
 #if defined(WITH_SENDFILE)
        /*
         * We can only use sendfile on a non-chained packet 
@@ -2546,34 +2588,16 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
 
        if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) &&
            lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
-               SMB_STRUCT_STAT sbuf;
                DATA_BLOB header;
 
-               if(SMB_VFS_FSTAT(fsp,fsp->fh->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_vwv2,0xFFFF); /* Remaining - must be -1. */
-               SSVAL(outbuf,smb_vwv5,smb_maxcnt);
-               SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
-               SSVAL(outbuf,smb_vwv7,((smb_maxcnt >> 16) & 1));
-               SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
-               SCVAL(outbuf,smb_vwv0,0xFF);
-               set_message(outbuf,12,smb_maxcnt,False);
+               setup_readX_header(inbuf,outbuf,smb_maxcnt);
+               set_message(inbuf,outbuf,12,smb_maxcnt,False);
                header.data = (uint8 *)outbuf;
                header.length = data - outbuf;
                header.free = NULL;
@@ -2618,28 +2642,40 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                return -1;
        }
 
-  normal_read:
-
 #endif
 
-       nread = read_file(fsp,data,startpos,smb_maxcnt);
-  
-       if (nread < 0) {
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
-       }
+normal_read:
 
-       outsize = set_message(outbuf,12,nread,False);
-       SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
-       SSVAL(outbuf,smb_vwv5,nread);
-       SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
-       SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
-       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 ) );
+       if ((smb_maxcnt & 0xFF0000) > 0x10000) {
+               int sendlen = setup_readX_header(inbuf,outbuf,smb_maxcnt) - smb_maxcnt;
+               /* Send out the header. */
+               if (write_data(smbd_server_fd(),outbuf,sendlen) != sendlen) {
+                       DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
+                               fsp->fsp_name, strerror(errno) ));
+                       exit_server_cleanly("send_file_readX sendfile failed");
+               }
+               if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
+                                       len_outbuf - (data-outbuf))) == -1) {
+                       DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+                               fsp->fsp_name, strerror(errno) ));
+                       exit_server_cleanly("send_file_readX: fake_sendfile failed");
+               }
+               return -1;
+       } else {
+               nread = read_file(fsp,data,startpos,smb_maxcnt);
 
-       /* Returning the number of bytes we want to send back - including header. */
-       return outsize;
+               if (nread < 0) {
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+
+               outsize = setup_readX_header(inbuf, outbuf,nread);
+
+               DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
+                       fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+
+               /* Returning the number of bytes we want to send back - including header. */
+               return outsize;
+       }
 }
 
 /****************************************************************************
@@ -2652,6 +2688,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
        ssize_t nread = -1;
        size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+       BOOL big_readX = False;
 #if 0
        size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
 #endif
@@ -2669,17 +2706,25 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return(ERROR_DOS(ERRDOS,ERRbadaccess));
        }
 
-       set_message(outbuf,12,0,True);
+       set_message(inbuf,outbuf,12,0,True);
 
        if (global_client_caps & CAP_LARGE_READX) {
-               if (SVAL(inbuf,smb_vwv7) == 1) {
-                       smb_maxcnt |= (1<<16);
-               }
-               if (smb_maxcnt > BUFFER_SIZE) {
-                       DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n",
-                               (unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE));
-                       END_PROFILE(SMBreadX);
-                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               size_t upper_size = SVAL(inbuf,smb_vwv7);
+               smb_maxcnt |= (upper_size<<16);
+               if (upper_size > 1) {
+                       /* Can't do this on a chained packet. */
+                       if ((CVAL(inbuf,smb_vwv0) != 0xFF)) {
+                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                       }
+                       /* We currently don't do this on signed or sealed data. */
+                       if (srv_is_signing_active() || srv_encryption_on()) {
+                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                       }
+                       /* Is there room in the reply for this data ? */
+                       if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2)))  {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       big_readX = True;
                }
        }
 
@@ -2712,14 +2757,16 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return ERROR_DOS(ERRDOS,ERRlock);
        }
 
-       if (schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
+       if (!big_readX && schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
                END_PROFILE(SMBreadX);
                return -1;
        }
 
        nread = send_file_readX(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt);
-       if (nread != -1)
+       /* Only call chain_reply if not an error. */
+       if (nread != -1 && SVAL(outbuf,smb_rcls) == 0) {
                nread = chain_reply(inbuf,outbuf,length,bufsize);
+       }
 
        END_PROFILE(SMBreadX);
        return nread;
@@ -2791,7 +2838,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        /* Return a message to the redirector to tell it to send more bytes */
        SCVAL(outbuf,smb_com,SMBwritebraw);
        SSVALS(outbuf,smb_vwv0,-1);
-       outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+       outsize = set_message(inbuf,outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
        show_msg(outbuf);
        if (!send_smb(smbd_server_fd(),outbuf))
                exit_server_cleanly("reply_writebraw: send_smb failed.");
@@ -2805,7 +2852,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        numtowrite = smb_len(inbuf);
 
        /* Set up outbuf to return the correct return */
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SCVAL(outbuf,smb_com,SMBwritec);
 
        if (numtowrite != 0) {
@@ -2917,7 +2964,8 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
        }
 
        if (numtowrite) {
-               status = do_unlock(fsp,
+               status = do_unlock(smbd_messaging_context(),
+                               fsp,
                                (uint32)SVAL(inbuf,smb_pid),
                                (SMB_BIG_UINT)numtowrite, 
                                (SMB_BIG_UINT)startpos,
@@ -2929,7 +2977,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
                }
        }
        
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        
        SSVAL(outbuf,smb_vwv0,nwritten);
        
@@ -3007,7 +3055,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVAL(outbuf,smb_vwv0,nwritten);
 
@@ -3050,7 +3098,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
                return(ERROR_DOS(ERRDOS,ERRbadaccess));
        }
 
-       set_message(outbuf,6,0,True);
+       set_message(inbuf,outbuf,6,0,True);
   
        /* Deal with possible LARGE_WRITEX */
        if (large_writeX) {
@@ -3197,7 +3245,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
        fsp->fh->pos = res;
   
-       outsize = set_message(outbuf,2,0,True);
+       outsize = set_message(inbuf,outbuf,2,0,True);
        SIVAL(outbuf,smb_vwv0,res);
   
        DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
@@ -3213,7 +3261,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        uint16 fnum = SVAL(inbuf,smb_vwv0);
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBflush);
@@ -3245,7 +3293,7 @@ int reply_exit(connection_struct *conn,
 
        file_close_pid(SVAL(inbuf,smb_pid),SVAL(inbuf,smb_uid));
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        DEBUG(3,("exit\n"));
 
@@ -3260,13 +3308,12 @@ int reply_exit(connection_struct *conn,
 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 int dum_buffsize)
 {
+       NTSTATUS status = NT_STATUS_OK;
        int outsize = 0;
-       time_t mtime;
-       int32 eclass = 0, err = 0;
        files_struct *fsp = NULL;
        START_PROFILE(SMBclose);
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        /* If it's an IPC, pass off to the pipe handler. */
        if (IS_IPC(conn)) {
@@ -3290,16 +3337,11 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Special case - close NT SMB directory handle.
                 */
                DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
-               close_file(fsp,NORMAL_CLOSE);
+               status = close_file(fsp,NORMAL_CLOSE);
        } else {
                /*
                 * Close ordinary file.
                 */
-               int close_err;
-               pstring file_name;
-
-               /* 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->fh->fd, fsp->fnum,
@@ -3309,8 +3351,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Take care of any time sent in the close.
                 */
 
-               mtime = srv_make_unix_date3(inbuf+smb_vwv1);
-               fsp_set_pending_modtime(fsp, mtime);
+               fsp_set_pending_modtime(fsp,
+                               convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv1)));
 
                /*
                 * close_file() returns the unix errno if an error
@@ -3318,17 +3360,12 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * a disk full error. If not then it was probably an I/O error.
                 */
  
-               if((close_err = close_file(fsp,NORMAL_CLOSE)) != 0) {
-                       errno = close_err;
-                       END_PROFILE(SMBclose);
-                       return (UNIXERROR(ERRHRD,ERRgeneral));
-               }
+               status = close_file(fsp,NORMAL_CLOSE);
        }  
 
-       /* We have a cached error */
-       if(eclass || err) {
+       if(!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBclose);
-               return ERROR_DOS(eclass,err);
+               return ERROR_NT(status);
        }
 
        END_PROFILE(SMBclose);
@@ -3345,10 +3382,10 @@ int reply_writeclose(connection_struct *conn,
        size_t numtowrite;
        ssize_t nwritten = -1;
        int outsize = 0;
-       int close_err = 0;
+       NTSTATUS close_status = NT_STATUS_OK;
        SMB_OFF_T startpos;
        char *data;
-       time_t mtime;
+       struct timespec mtime;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBwriteclose);
 
@@ -3359,7 +3396,7 @@ int reply_writeclose(connection_struct *conn,
 
        numtowrite = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
-       mtime = srv_make_unix_date3(inbuf+smb_vwv4);
+       mtime = convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv4));
        data = smb_buf(inbuf) + 1;
   
        if (numtowrite && is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
@@ -3369,7 +3406,7 @@ int reply_writeclose(connection_struct *conn,
   
        nwritten = write_file(fsp,data,startpos,numtowrite);
 
-       set_filetime(conn, fsp->fsp_name,mtime);
+       set_filetime(conn, fsp->fsp_name, mtime);
   
        /*
         * More insanity. W2K only closes the file if writelen > 0.
@@ -3379,7 +3416,7 @@ int reply_writeclose(connection_struct *conn,
        if (numtowrite) {
                DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
                        fsp->fsp_name ));
-               close_err = close_file(fsp,NORMAL_CLOSE);
+               close_status = close_file(fsp,NORMAL_CLOSE);
        }
 
        DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
@@ -3391,13 +3428,12 @@ int reply_writeclose(connection_struct *conn,
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
  
-       if(close_err != 0) {
-               errno = close_err;
+       if(!NT_STATUS_IS_OK(close_status)) {
                END_PROFILE(SMBwriteclose);
-               return(UNIXERROR(ERRHRD,ERRgeneral));
+               return ERROR_NT(close_status);
        }
  
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVAL(outbuf,smb_vwv0,nwritten);
        END_PROFILE(SMBwriteclose);
@@ -3414,7 +3450,7 @@ int reply_writeclose(connection_struct *conn,
 int reply_lock(connection_struct *conn,
               char *inbuf,char *outbuf, int length, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        SMB_BIG_UINT count,offset;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -3432,14 +3468,16 @@ int reply_lock(connection_struct *conn,
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
                 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
 
-       br_lck = do_lock(fsp,
+       br_lck = do_lock(smbd_messaging_context(),
+                       fsp,
                        (uint32)SVAL(inbuf,smb_pid),
                        count,
                        offset,
                        WRITE_LOCK,
                        WINDOWS_LOCK,
                        False, /* Non-blocking lock. */
-                       &status);
+                       &status,
+                       NULL);
 
        TALLOC_FREE(br_lck);
 
@@ -3459,7 +3497,7 @@ int reply_lock(connection_struct *conn,
 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, 
                 int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        SMB_BIG_UINT count,offset;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -3470,7 +3508,8 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
        count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
        offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
        
-       status = do_unlock(fsp,
+       status = do_unlock(smbd_messaging_context(),
+                       fsp,
                        (uint32)SVAL(inbuf,smb_pid),
                        count,
                        offset,
@@ -3499,7 +3538,7 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
 int reply_tdis(connection_struct *conn, 
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        uint16 vuid;
        START_PROFILE(SMBtdis);
 
@@ -3530,7 +3569,7 @@ int reply_echo(connection_struct *conn,
        int smb_reverb = SVAL(inbuf,smb_vwv0);
        int seq_num;
        unsigned int data_len = smb_buflen(inbuf);
-       int outsize = set_message(outbuf,1,data_len,True);
+       int outsize = set_message(inbuf,outbuf,1,data_len,True);
        START_PROFILE(SMBecho);
 
        if (data_len > BUFFER_SIZE) {
@@ -3551,7 +3590,7 @@ int reply_echo(connection_struct *conn,
        for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
                SSVAL(outbuf,smb_vwv0,seq_num);
 
-               smb_setlen(outbuf,outsize - 4);
+               smb_setlen(inbuf,outbuf,outsize - 4);
 
                show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
@@ -3592,7 +3631,7 @@ int reply_printopen(connection_struct *conn,
                return(ERROR_NT(status));
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
   
        DEBUG(3,("openprint fd=%d fnum=%d\n",
@@ -3609,27 +3648,26 @@ int reply_printopen(connection_struct *conn,
 int reply_printclose(connection_struct *conn,
                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-       int close_err = 0;
+       NTSTATUS status;
        START_PROFILE(SMBsplclose);
 
        CHECK_FSP(fsp,conn);
 
        if (!CAN_PRINT(conn)) {
                END_PROFILE(SMBsplclose);
-               return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+               return ERROR_NT(NT_STATUS_DOS(ERRSRV, ERRerror));
        }
   
        DEBUG(3,("printclose fd=%d fnum=%d\n",
                 fsp->fh->fd,fsp->fnum));
   
-       close_err = close_file(fsp,NORMAL_CLOSE);
+       status = close_file(fsp,NORMAL_CLOSE);
 
-       if(close_err != 0) {
-               errno = close_err;
+       if(!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBsplclose);
-               return(UNIXERROR(ERRHRD,ERRgeneral));
+               return ERROR_NT(status);
        }
 
        END_PROFILE(SMBsplclose);
@@ -3643,7 +3681,7 @@ int reply_printclose(connection_struct *conn,
 int reply_printqueue(connection_struct *conn,
                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,2,3,True);
+       int outsize = set_message(inbuf,outbuf,2,3,True);
        int max_count = SVAL(inbuf,smb_vwv0);
        int start_index = SVAL(inbuf,smb_vwv1);
        START_PROFILE(SMBsplretq);
@@ -3691,7 +3729,7 @@ int reply_printqueue(connection_struct *conn,
                }
 
                if (count > 0) {
-                       outsize = set_message(outbuf,2,28*count+3,False); 
+                       outsize = set_message(inbuf,outbuf,2,28*count+3,False); 
                        SSVAL(outbuf,smb_vwv0,count);
                        SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
                        SCVAL(smb_buf(outbuf),0,1);
@@ -3714,7 +3752,7 @@ int reply_printqueue(connection_struct *conn,
 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,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        char *data;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
 
@@ -3744,46 +3782,6 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
        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, const pstring directory, BOOL bad_path)
-{
-       int ret= -1;
-       
-       if(!CAN_WRITE(conn)) {
-               DEBUG(5,("mkdir_internal: failing create on read-only share %s\n", lp_servicename(SNUM(conn))));
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
-       if (bad_path) {
-               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-       }
-
-       if (!check_name(directory, conn)) {
-               if(errno == ENOENT) {
-                       if (bad_path) {
-                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                       } else {
-                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                       }
-               }
-               return map_nt_error_from_unix(errno);
-       }
-
-       ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
-       if (ret == -1) {
-               if(errno == ENOENT) {
-                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-               }
-               return map_nt_error_from_unix(errno);
-       }
-       
-       return NT_STATUS_OK;
-}
-
 /****************************************************************************
  Reply to a mkdir.
 ****************************************************************************/
@@ -3793,9 +3791,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        pstring directory;
        int outsize;
        NTSTATUS status;
-       BOOL bad_path = False;
        SMB_STRUCT_STAT sbuf;
-       files_struct *fsp;
 
        START_PROFILE(SMBmkdir);
  
@@ -3805,16 +3801,30 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBmkdir);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
 
-       unix_convert(directory,conn,0,&bad_path,&sbuf);
+       status = unix_convert(conn, directory, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBmkdir);
+               return ERROR_NT(status);
+       }
 
-       status = open_directory(conn, directory, &sbuf,
-                               FILE_READ_ATTRIBUTES, /* Just a stat open */
-                               FILE_SHARE_NONE, /* Ignored for stat opens */
-                               FILE_CREATE, 0, NULL, &fsp);
+       status = check_name(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBmkdir);
+               return ERROR_NT(status);
+       }
+  
+       status = create_directory(conn, directory);
 
-       DEBUG(1, ("open_directory returned %s\n", nt_errstr(status)));
+       DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
 
        if (!NT_STATUS_IS_OK(status)) {
 
@@ -3833,9 +3843,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       close_file(fsp, NORMAL_CLOSE);
-
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
 
@@ -3845,18 +3853,18 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
 /****************************************************************************
  Static function used by reply_rmdir to delete an entire directory
- tree recursively. Return False on ok, True on fail.
+ tree recursively. Return True on ok, False on fail.
 ****************************************************************************/
 
 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
        const char *dname = NULL;
-       BOOL ret = False;
+       BOOL ret = True;
        long offset = 0;
        struct smb_Dir *dir_hnd = OpenDir(conn, directory, NULL, 0);
 
        if(dir_hnd == NULL)
-               return True;
+               return False;
 
        while((dname = ReadDirName(dir_hnd, &offset))) {
                pstring fullname;
@@ -3871,7 +3879,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
                /* Construct the full name. */
                if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
                        errno = ENOMEM;
-                       ret = True;
+                       ret = False;
                        break;
                }
 
@@ -3880,21 +3888,21 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
                pstrcat(fullname, dname);
 
                if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
-                       ret = True;
+                       ret = False;
                        break;
                }
 
                if(st.st_mode & S_IFDIR) {
-                       if(recursive_rmdir(conn, fullname)!=0) {
-                               ret = True;
+                       if(!recursive_rmdir(conn, fullname)) {
+                               ret = False;
                                break;
                        }
                        if(SMB_VFS_RMDIR(conn,fullname) != 0) {
-                               ret = True;
+                               ret = False;
                                break;
                        }
                } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
-                       ret = True;
+                       ret = False;
                        break;
                }
        }
@@ -3906,83 +3914,114 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
  The internals of the rmdir code - called elsewhere.
 ****************************************************************************/
 
-BOOL rmdir_internals(connection_struct *conn, char *directory)
+NTSTATUS rmdir_internals(connection_struct *conn, const char *directory)
 {
-       BOOL ok;
+       int ret;
        SMB_STRUCT_STAT st;
 
-       ok = (SMB_VFS_RMDIR(conn,directory) == 0);
-       if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+       /* Might be a symlink. */
+       if(SMB_VFS_LSTAT(conn, directory, &st) != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       if (S_ISLNK(st.st_mode)) {
+               /* Is what it points to a directory ? */
+               if(SMB_VFS_STAT(conn, directory, &st) != 0) {
+                       return map_nt_error_from_unix(errno);
+               }
+               if (!(S_ISDIR(st.st_mode))) {
+                       return NT_STATUS_NOT_A_DIRECTORY;
+               }
+               ret = SMB_VFS_UNLINK(conn,directory);
+       } else {
+               ret = SMB_VFS_RMDIR(conn,directory);
+       }
+       if (ret == 0) {
+               notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                            FILE_NOTIFY_CHANGE_DIR_NAME,
+                            directory);
+               return NT_STATUS_OK;
+       }
+
+       if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
                /* 
                 * Check to see if the only thing in this directory are
                 * vetoed files/directories. If so then delete them and
                 * retry. If we fail to delete any of them (and we *don't*
                 * do a recursive delete) then fail the rmdir.
                 */
-               BOOL all_veto_files = True;
                const char *dname;
+               long dirpos = 0;
                struct smb_Dir *dir_hnd = OpenDir(conn, directory, NULL, 0);
 
-               if(dir_hnd != NULL) {
-                       long dirpos = 0;
-                       while ((dname = ReadDirName(dir_hnd,&dirpos))) {
-                               if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-                                       continue;
-                               if (!is_visible_file(conn, directory, dname, &st, False))
-                                       continue;
-                               if(!IS_VETO_PATH(conn, dname)) {
-                                       all_veto_files = False;
-                                       break;
-                               }
+               if(dir_hnd == NULL) {
+                       errno = ENOTEMPTY;
+                       goto err;
+               }
+
+               while ((dname = ReadDirName(dir_hnd,&dirpos))) {
+                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+                               continue;
+                       if (!is_visible_file(conn, directory, dname, &st, False))
+                               continue;
+                       if(!IS_VETO_PATH(conn, dname)) {
+                               CloseDir(dir_hnd);
+                               errno = ENOTEMPTY;
+                               goto err;
                        }
+               }
 
-                       if(all_veto_files) {
-                               RewindDir(dir_hnd,&dirpos);
-                               while ((dname = ReadDirName(dir_hnd,&dirpos))) {
-                                       pstring fullname;
+               /* We only have veto files/directories. Recursive delete. */
 
-                                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-                                               continue;
-                                       if (!is_visible_file(conn, directory, dname, &st, False))
-                                               continue;
+               RewindDir(dir_hnd,&dirpos);
+               while ((dname = ReadDirName(dir_hnd,&dirpos))) {
+                       pstring fullname;
 
-                                       /* Construct the full name. */
-                                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
-                                               errno = ENOMEM;
-                                               break;
-                                       }
+                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+                               continue;
+                       if (!is_visible_file(conn, directory, dname, &st, False))
+                               continue;
 
-                                       pstrcpy(fullname, directory);
-                                       pstrcat(fullname, "/");
-                                       pstrcat(fullname, dname);
-                     
-                                       if(SMB_VFS_LSTAT(conn,fullname, &st) != 0)
-                                               break;
-                                       if(st.st_mode & S_IFDIR) {
-                                               if(lp_recursive_veto_delete(SNUM(conn))) {
-                                                       if(recursive_rmdir(conn, fullname) != 0)
-                                                               break;
-                                               }
-                                               if(SMB_VFS_RMDIR(conn,fullname) != 0)
-                                                       break;
-                                       } else if(SMB_VFS_UNLINK(conn,fullname) != 0)
+                       /* Construct the full name. */
+                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+                               errno = ENOMEM;
+                               break;
+                       }
+
+                       pstrcpy(fullname, directory);
+                       pstrcat(fullname, "/");
+                       pstrcat(fullname, dname);
+                   
+                       if(SMB_VFS_LSTAT(conn,fullname, &st) != 0)
+                               break;
+                       if(st.st_mode & S_IFDIR) {
+                               if(lp_recursive_veto_delete(SNUM(conn))) {
+                                       if(!recursive_rmdir(conn, fullname))
                                                break;
                                }
-                               CloseDir(dir_hnd);
-                               /* Retry the rmdir */
-                               ok = (SMB_VFS_RMDIR(conn,directory) == 0);
-                       } else {
-                               CloseDir(dir_hnd);
-                       }
-               } else {
-                       errno = ENOTEMPTY;
+                               if(SMB_VFS_RMDIR(conn,fullname) != 0)
+                                       break;
+                       } else if(SMB_VFS_UNLINK(conn,fullname) != 0)
+                               break;
                }
+               CloseDir(dir_hnd);
+               /* Retry the rmdir */
+               ret = SMB_VFS_RMDIR(conn,directory);
        }
 
-       if (!ok)
-               DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
+  err:
 
-       return ok;
+       if (ret != 0) {
+               DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
+                        "%s\n", directory,strerror(errno)));
+               return map_nt_error_from_unix(errno);
+       }
+
+       notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                    FILE_NOTIFY_CHANGE_DIR_NAME,
+                    directory);
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -3993,8 +4032,6 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 {
        pstring directory;
        int outsize = 0;
-       BOOL ok = False;
-       BOOL bad_path = False;
        SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
        START_PROFILE(SMBrmdir);
@@ -4005,25 +4042,35 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBrmdir);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
 
-       unix_convert(directory,conn, NULL,&bad_path,&sbuf);
-       if (bad_path) {
+       status = unix_convert(conn, directory, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBrmdir);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
   
-       if (check_name(directory,conn)) {
-               dptr_closepath(directory,SVAL(inbuf,smb_pid));
-               ok = rmdir_internals(conn, directory);
+       status = check_name(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBrmdir);
+               return ERROR_NT(status);
        }
-  
-       if (!ok) {
+
+       dptr_closepath(directory,SVAL(inbuf,smb_pid));
+       status = rmdir_internals(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBrmdir);
-               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRbadpath);
+               return ERROR_NT(status);
        }
  
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
   
        DEBUG( 3, ( "rmdir %s\n", directory ) );
   
@@ -4046,7 +4093,6 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
        char *p,*p2, *pname1, *pname2;
        int available_space, actual_space;
        
-
        pname1 = strrchr_m(name1,'/');
        pname2 = strrchr_m(name2,'/');
 
@@ -4123,12 +4169,12 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
 ****************************************************************************/
 
 static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck,
-                               SMB_DEV_T dev, SMB_INO_T inode, const char *newname)
+                             struct file_id id, const char *newname)
 {
        files_struct *fsp;
        BOOL did_rename = False;
 
-       for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
+       for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
                /* fsp_name is a relative path under the fsp. To change this for other
                   sharepaths we need to manipulate relative paths. */
                /* TODO - create the absolute path and manipulate the newname
@@ -4136,20 +4182,21 @@ static void rename_open_files(connection_struct *conn, struct share_mode_lock *l
                if (fsp->conn != conn) {
                        continue;
                }
-               DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n",
-                       fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode,
+               DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n",
+                         fsp->fnum, file_id_static_string(&fsp->file_id),
                        fsp->fsp_name, newname ));
                string_set(&fsp->fsp_name, newname);
                did_rename = True;
        }
 
        if (!did_rename) {
-               DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n",
-                       (unsigned int)dev, (double)inode, newname ));
+               DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
+                         file_id_static_string(&id), newname ));
        }
 
        /* Send messages to all smbd's (not ourself) that the name has changed. */
-       rename_share_filename(lck, conn->connectpath, newname);
+       rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
+                             newname);
 }
 
 /****************************************************************************
@@ -4185,29 +4232,29 @@ static BOOL rename_path_prefix_equal(const char *src, const char *dest)
  Rename an open file - given an fsp.
 ****************************************************************************/
 
-NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, uint32 attrs, BOOL replace_if_exists)
+NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstring newname, uint32 attrs, BOOL replace_if_exists)
 {
        SMB_STRUCT_STAT sbuf;
-       BOOL bad_path = False;
        pstring newname_last_component;
-       NTSTATUS error = NT_STATUS_OK;
+       NTSTATUS status = NT_STATUS_OK;
        BOOL dest_exists;
-       BOOL rcdest = True;
        struct share_mode_lock *lck = NULL;
 
        ZERO_STRUCT(sbuf);
-       rcdest = unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf);
 
-       /* Quick check for "." and ".." */
-       if (!bad_path && newname_last_component[0] == '.') {
-               if (!newname_last_component[1] || (newname_last_component[1] == '.' && !newname_last_component[2])) {
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-       }
-       if (!rcdest && bad_path) {
-               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+       status = unix_convert(conn, newname, False, newname_last_component, &sbuf);
+
+       /* If an error we expect this to be NT_STATUS_OBJECT_PATH_NOT_FOUND */
+
+       if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, status)) {
+               return status;
        }
 
+       status = check_name(conn, newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+  
        /* Ensure newname contains a '/' */
        if(strrchr_m(newname,'/') == 0) {
                pstring tmpstr;
@@ -4267,26 +4314,61 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       error = can_rename(conn,newname,attrs,&sbuf);
+       /* Ensure we have a valid stat struct for the source. */
+       if (fsp->fh->fd != -1) {
+               if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       } else {
+               if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       }
 
-       if (dest_exists && !NT_STATUS_IS_OK(error)) {
-               DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
-                       nt_errstr(error), fsp->fsp_name,newname));
-               if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION))
-                       error = NT_STATUS_ACCESS_DENIED;
-               return error;
+       status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
+                       nt_errstr(status), fsp->fsp_name,newname));
+               if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
+                       status = NT_STATUS_ACCESS_DENIED;
+               return status;
        }
 
        if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
+       lck = get_share_mode_lock(NULL, fsp->file_id, NULL, NULL);
 
        if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
+               uint32 create_options = fsp->fh->private_options;
+
                DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
                        fsp->fsp_name,newname));
-               rename_open_files(conn, lck, fsp->dev, fsp->inode, newname);
+
+               rename_open_files(conn, lck, fsp->file_id, newname);
+
+               /*
+                * A rename acts as a new file create w.r.t. allowing an initial delete
+                * on close, probably because in Windows there is a new handle to the
+                * new file. If initial delete on close was requested but not
+                * originally set, we need to set it here. This is probably not 100% correct,
+                * but will work for the CIFSFS client which in non-posix mode
+                * depends on these semantics. JRA.
+                */
+
+               set_allow_initial_delete_on_close(lck, fsp, True);
+
+               if (create_options & FILE_DELETE_ON_CLOSE) {
+                       status = can_set_delete_on_close(fsp, True, 0);
+
+                       if (NT_STATUS_IS_OK(status)) {
+                               /* Note that here we set the *inital* delete on close flag,
+                                * not the regular one. The magic gets handled in close. */
+                               fsp->initial_delete_on_close = True;
+                       }
+               }
                TALLOC_FREE(lck);
                return NT_STATUS_OK;    
        }
@@ -4294,15 +4376,57 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
        TALLOC_FREE(lck);
 
        if (errno == ENOTDIR || errno == EISDIR) {
-               error = NT_STATUS_OBJECT_NAME_COLLISION;
+               status = NT_STATUS_OBJECT_NAME_COLLISION;
        } else {
-               error = map_nt_error_from_unix(errno);
+               status = map_nt_error_from_unix(errno);
        }
                
        DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
-               nt_errstr(error), fsp->fsp_name,newname));
+               nt_errstr(status), fsp->fsp_name,newname));
 
-       return error;
+       return status;
+}
+
+/*
+ * Do the notify calls from a rename
+ */
+
+static void notify_rename(connection_struct *conn, BOOL is_dir,
+                         const char *oldpath, const char *newpath)
+{
+       char *olddir, *newdir;
+       const char *oldname, *newname;
+       uint32 mask;
+
+       mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
+               : FILE_NOTIFY_CHANGE_FILE_NAME;
+
+       if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
+           || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
+               TALLOC_FREE(olddir);
+               return;
+       }
+
+       if (strcmp(olddir, newdir) == 0) {
+               notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
+               notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
+       }
+       else {
+               notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
+               notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
+       }
+       TALLOC_FREE(olddir);
+       TALLOC_FREE(newdir);
+
+       /* this is a strange one. w2k3 gives an additional event for
+          CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
+          files, but not directories */
+       if (!is_dir) {
+               notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES
+                            |FILE_NOTIFY_CHANGE_CREATION,
+                            newpath);
+       }
 }
 
 /****************************************************************************
@@ -4310,48 +4434,42 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
  code. 
 ****************************************************************************/
 
-NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, uint32 attrs, BOOL replace_if_exists, BOOL has_wild)
+NTSTATUS rename_internals(connection_struct *conn,
+                               pstring name,
+                               pstring newname,
+                               uint32 attrs,
+                               BOOL replace_if_exists,
+                               BOOL src_has_wild,
+                               BOOL dest_has_wild)
 {
        pstring directory;
        pstring mask;
        pstring last_component_src;
        pstring last_component_dest;
        char *p;
-       BOOL bad_path_src = False;
-       BOOL bad_path_dest = False;
        int count=0;
-       NTSTATUS error = NT_STATUS_OK;
-       BOOL rc = True;
-       BOOL rcdest = True;
+       NTSTATUS status = NT_STATUS_OK;
        SMB_STRUCT_STAT sbuf1, sbuf2;
        struct share_mode_lock *lck = NULL;
+       struct smb_Dir *dir_hnd = NULL;
+       const char *dname;
+       long offset = 0;
+       pstring destname;
+       struct file_id id;
 
        *directory = *mask = 0;
 
        ZERO_STRUCT(sbuf1);
        ZERO_STRUCT(sbuf2);
 
-       rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1);
-       if (!rc && bad_path_src) {
-               if (ms_has_wild(last_component_src))
-                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-       }
-
-       /* Quick check for "." and ".." */
-       if (last_component_src[0] == '.') {
-               if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) {
-                       return NT_STATUS_OBJECT_NAME_INVALID;
-               }
+       status = unix_convert(conn, name, src_has_wild, last_component_src, &sbuf1);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2);
-
-       /* Quick check for "." and ".." */
-       if (last_component_dest[0] == '.') {
-               if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) {
-                       return NT_STATUS_OBJECT_NAME_INVALID;
-               }
+       status = unix_convert(conn, newname, dest_has_wild, last_component_dest, &sbuf2);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        /*
@@ -4383,10 +4501,11 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!rc && mangle_is_mangled(mask, conn->params))
+       if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
                mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
+       }
 
-       if (!has_wild) {
+       if (!src_has_wild) {
                /*
                 * No wildcards - just process the one file.
                 */
@@ -4405,11 +4524,29 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
                        pstrcpy(newname, tmpstr);
                }
                
-               DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
-directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", 
-                        conn->case_sensitive, conn->case_preserve, conn->short_case_preserve, directory, 
-                        newname, last_component_dest, is_short_name));
+               DEBUG(3, ("rename_internals: case_sensitive = %d, "
+                         "case_preserve = %d, short case preserve = %d, "
+                         "directory = %s, newname = %s, "
+                         "last_component_dest = %s, is_8_3 = %d\n", 
+                         conn->case_sensitive, conn->case_preserve,
+                         conn->short_case_preserve, directory, 
+                         newname, last_component_dest, is_short_name));
+
+               /* Ensure the source name is valid for us to access. */
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
+               /* The dest name still may have wildcards. */
+               if (dest_has_wild) {
+                       if (!resolve_wildcards(directory,newname)) {
+                               DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n", 
+                                         directory,newname));
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
+                               
                /*
                 * Check for special case with case preserving and not
                 * case sensitive, if directory and newname are identical,
@@ -4444,49 +4581,23 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        }
                }
        
-               resolve_wildcards(directory,newname);
-       
-               /*
-                * The source object must exist.
-                */
-
-               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;
-               }
-
-               if (!rcdest && bad_path_dest) {
-                       if (ms_has_wild(last_component_dest))
-                               return NT_STATUS_OBJECT_NAME_INVALID;
-                       return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               /* Ensure the dest name is valid for us to access. */
+               status = check_name(conn, newname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
 
-               error = can_rename(conn,directory,attrs,&sbuf1);
+               /*
+                * The source object must exist, and it may not have a
+                * conflicting share mode.
+                */
+               status = can_rename(conn,directory,attrs,&sbuf1,False);
 
-               if (!NT_STATUS_IS_OK(error)) {
-                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
-                               nt_errstr(error), directory,newname));
-                       return error;
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(3,("rename_internals: Error %s rename %s -> "
+                                "%s\n", nt_errstr(status), directory,
+                                newname));
+                       return status;
                }
 
                /*
@@ -4494,15 +4605,18 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                 * don't do the rename, just return success.
                 */
 
+               id = file_id_sbuf(&sbuf1);
+
                if (strcsequal(directory, newname)) {
-                       rename_open_files(conn, NULL, sbuf1.st_dev, sbuf1.st_ino, newname);
-                       DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
+                       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));
+                       DEBUG(3,("rename_internals: dest exists doing "
+                                "rename %s -> %s\n", directory, newname));
                        return NT_STATUS_OBJECT_NAME_COLLISION;
                }
 
@@ -4510,139 +4624,161 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
-               lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL);
+               lck = get_share_mode_lock(NULL, id, NULL, NULL);
 
                if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
-                       DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
-                               directory,newname));
-                       rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname);
+                       DEBUG(3,("rename_internals: succeeded doing rename "
+                                "on %s -> %s\n", directory, newname));
+                       rename_open_files(conn, lck, id, newname);
                        TALLOC_FREE(lck);
+                       notify_rename(conn, S_ISDIR(sbuf1.st_mode),
+                                     directory, newname);
                        return NT_STATUS_OK;    
                }
 
                TALLOC_FREE(lck);
-               if (errno == ENOTDIR || errno == EISDIR)
-                       error = NT_STATUS_OBJECT_NAME_COLLISION;
-               else
-                       error = map_nt_error_from_unix(errno);
+               if (errno == ENOTDIR || errno == EISDIR) {
+                       status = NT_STATUS_OBJECT_NAME_COLLISION;
+               } else {
+                       status = map_nt_error_from_unix(errno);
+               }
                
                DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
-                       nt_errstr(error), directory,newname));
+                       nt_errstr(status), directory,newname));
 
-               return error;
-       } else {
-               /*
-                * Wildcards - process each file that matches.
-                */
-               struct smb_Dir *dir_hnd = NULL;
-               const char *dname;
-               pstring destname;
-               
-               if (strequal(mask,"????????.???"))
-                       pstrcpy(mask,"*");
+               return status;
+       }
+
+       /*
+        * Wildcards - process each file that matches.
+        */
+       if (strequal(mask,"????????.???")) {
+               pstrcpy(mask,"*");
+       }
                        
-               if (check_name(directory,conn))
-                       dir_hnd = OpenDir(conn, directory, mask, attrs);
+       status = check_name(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       
+       dir_hnd = OpenDir(conn, directory, mask, attrs);
+       if (dir_hnd == NULL) {
+               return map_nt_error_from_unix(errno);
+       }
                
-               if (dir_hnd) {
-                       long offset = 0;
-                       error = NT_STATUS_NO_SUCH_FILE;
-/*                     Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */
+       status = NT_STATUS_NO_SUCH_FILE;
+       /*
+        * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+        * - gentest fix. JRA
+        */
                        
-                       while ((dname = ReadDirName(dir_hnd, &offset))) {
-                               pstring fname;
-                               BOOL sysdir_entry = False;
+       while ((dname = ReadDirName(dir_hnd, &offset))) {
+               pstring fname;
+               BOOL sysdir_entry = False;
 
-                               pstrcpy(fname,dname);
+               pstrcpy(fname,dname);
                                
-                               /* Quick check for "." and ".." */
-                               if (fname[0] == '.') {
-                                       if (!fname[1] || (fname[1] == '.' && !fname[2])) {
-                                               if (attrs & aDIR) {
-                                                       sysdir_entry = True;
-                                               } else {
-                                                       continue;
-                                               }
-                                       }
+               /* Quick check for "." and ".." */
+               if (fname[0] == '.') {
+                       if (!fname[1] || (fname[1] == '.' && !fname[2])) {
+                               if (attrs & aDIR) {
+                                       sysdir_entry = True;
+                               } else {
+                                       continue;
                                }
+                       }
+               }
 
-                               if (!is_visible_file(conn, directory, dname, &sbuf1, False))
-                                       continue;
+               if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+                       continue;
+               }
 
-                               if(!mask_match(fname, mask, conn->case_sensitive))
-                                       continue;
+               if(!mask_match(fname, mask, conn->case_sensitive)) {
+                       continue;
+               }
                                
-                               if (sysdir_entry) {
-                                       error = NT_STATUS_OBJECT_NAME_INVALID;
-                                       break;
-                               }
+               if (sysdir_entry) {
+                       status = NT_STATUS_OBJECT_NAME_INVALID;
+                       break;
+               }
 
-                               error = NT_STATUS_ACCESS_DENIED;
-                               slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
-                               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(conn,fname,attrs,&sbuf1);
-                               if (!NT_STATUS_IS_OK(error)) {
-                                       DEBUG(6,("rename %s refused\n", fname));
-                                       continue;
-                               }
-                               pstrcpy(destname,newname);
-                               
-                               if (!resolve_wildcards(fname,destname)) {
-                                       DEBUG(6,("resolve_wildcards %s %s failed\n", 
-                                                 fname, destname));
-                                       continue;
-                               }
-                               
-                               if (strcsequal(fname,destname)) {
-                                       rename_open_files(conn, NULL, sbuf1.st_dev, sbuf1.st_ino, newname);
-                                       DEBUG(3,("rename_internals: identical names in wildcard rename %s - success\n", fname));
-                                       count++;
-                                       error = NT_STATUS_OK;
-                                       continue;
-                               }
+               status = NT_STATUS_ACCESS_DENIED;
+               slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname);
 
-                               if (!replace_if_exists && 
-                                    vfs_file_exist(conn,destname, NULL)) {
-                                       DEBUG(6,("file_exist %s\n", destname));
-                                       error = NT_STATUS_OBJECT_NAME_COLLISION;
-                                       continue;
-                               }
+               /* Ensure the source name is valid for us to access. */
+               status = check_name(conn, fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
+               /*
+                * can_rename does an open_file_ntcreate which needs a valid
+                * stat in case the file exists
+                */
+
+               ZERO_STRUCT(sbuf1);
+               SMB_VFS_STAT(conn, fname, &sbuf1);
+
+               status = can_rename(conn,fname,attrs,&sbuf1,False);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(6, ("rename %s refused: %s\n", fname,
+                                 nt_errstr(status)));
+                       continue;
+               }
+               pstrcpy(destname,newname);
+                       
+               if (!resolve_wildcards(fname,destname)) {
+                       DEBUG(6, ("resolve_wildcards %s %s failed\n", 
+                                 fname, destname));
+                       continue;
+               }
                                
-                               if (rename_path_prefix_equal(fname, destname)) {
-                                       return NT_STATUS_SHARING_VIOLATION;
-                               }
+               /* Ensure the dest name is valid for us to access. */
+               status = check_name(conn, destname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
-                               lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL);
+               id = file_id_sbuf(&sbuf1);
 
-                               if (!SMB_VFS_RENAME(conn,fname,destname)) {
-                                       rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname);
-                                       count++;
-                                       error = NT_STATUS_OK;
-                               }
-                               TALLOC_FREE(lck);
-                               DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
-                       }
-                       CloseDir(dir_hnd);
+               if (strcsequal(fname,destname)) {
+                       DEBUG(3,("rename_internals: identical names "
+                                "in wildcard rename %s - success\n",
+                                fname));
+                       count++;
+                       status = NT_STATUS_OK;
+                       continue;
                }
 
-               if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) {
-                       if (!rcdest && bad_path_dest) {
-                               if (ms_has_wild(last_component_dest))
-                                       return NT_STATUS_OBJECT_NAME_INVALID;
-                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                       }
+               if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) {
+                       DEBUG(6,("file_exist %s\n", destname));
+                       status = NT_STATUS_OBJECT_NAME_COLLISION;
+                       continue;
                }
+                               
+               if (rename_path_prefix_equal(fname, destname)) {
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
+
+               lck = get_share_mode_lock(NULL, id, NULL, NULL);
+
+               if (!SMB_VFS_RENAME(conn,fname,destname)) {
+                       rename_open_files(conn, lck, id, newname);
+                       count++;
+                       status = NT_STATUS_OK;
+               }
+               TALLOC_FREE(lck);
+               DEBUG(3,("rename_internals: doing rename on %s -> "
+                        "%s\n",fname,destname));
        }
-       
-       if (count == 0 && NT_STATUS_IS_OK(error)) {
-               error = map_nt_error_from_unix(errno);
+       CloseDir(dir_hnd);
+
+       if (count == 0 && NT_STATUS_IS_OK(status)) {
+               status = map_nt_error_from_unix(errno);
        }
        
-       return error;
+       return status;
 }
 
 /****************************************************************************
@@ -4658,29 +4794,45 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        char *p;
        uint32 attrs = SVAL(inbuf,smb_vwv0);
        NTSTATUS status;
-       BOOL path_contains_wcard = False;
+       BOOL src_has_wcard = False;
+       BOOL dest_has_wcard = False;
 
        START_PROFILE(SMBmv);
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard);
+       p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &src_has_wcard);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmv);
                return ERROR_NT(status);
        }
        p++;
-       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmv);
                return ERROR_NT(status);
        }
        
-       RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
-       RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf);
+       status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &src_has_wcard);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBmv);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBmv);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
        
        DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
        
-       status = rename_internals(conn, name, newname, attrs, False, path_contains_wcard);
+       status = rename_internals(conn, name, newname, attrs, False, src_has_wcard, dest_has_wcard);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmv);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
@@ -4690,12 +4842,7 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */     
-       process_pending_change_notify_queue((time_t)0);
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
   
        END_PROFILE(SMBmv);
        return(outsize);
@@ -4705,8 +4852,16 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  Copy a file as part of a reply_copy.
 ******************************************************************/
 
-BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
-                     int count,BOOL target_is_directory, int *err_ret)
+/*
+ * TODO: check error codes on all callers
+ */
+
+NTSTATUS copy_file(connection_struct *conn,
+                       char *src,
+                       char *dest1,
+                       int ofun,
+                       int count,
+                       BOOL target_is_directory)
 {
        SMB_STRUCT_STAT src_sbuf, sbuf2;
        SMB_OFF_T ret=-1;
@@ -4716,8 +4871,6 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        uint32 new_create_disposition;
        NTSTATUS status;
  
-       *err_ret = 0;
-
        pstrcpy(dest,dest1);
        if (target_is_directory) {
                char *p = strrchr_m(src,'/');
@@ -4731,7 +4884,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        }
 
        if (!vfs_file_exist(conn,src,&src_sbuf)) {
-               return(False);
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
        if (!target_is_directory && count) {
@@ -4739,7 +4892,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        } else {
                if (!map_open_params_to_ntcreate(dest1,0,ofun,
                                NULL, NULL, &new_create_disposition, NULL)) {
-                       return(False);
+                       return NT_STATUS_INVALID_PARAMETER;
                }
        }
 
@@ -4753,7 +4906,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
                        NULL, &fsp1);
 
        if (!NT_STATUS_IS_OK(status)) {
-               return(False);
+               return status;
        }
 
        dosattrs = dos_mode(conn, src, &src_sbuf);
@@ -4772,7 +4925,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
 
        if (!NT_STATUS_IS_OK(status)) {
                close_file(fsp1,ERROR_CLOSE);
-               return(False);
+               return status;
        }
 
        if ((ofun&3) == 1) {
@@ -4793,7 +4946,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        close_file(fsp1,NORMAL_CLOSE);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       fsp_set_pending_modtime( fsp2, src_sbuf.st_mtime);
+       fsp_set_pending_modtime( fsp2, get_mtimespec(&src_sbuf));
 
        /*
         * As we are opening fsp1 read-only we only expect
@@ -4801,9 +4954,17 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
         * Thus we don't look at the error return from the
         * close of fsp1.
         */
-       *err_ret = close_file(fsp2,NORMAL_CLOSE);
+       status = close_file(fsp2,NORMAL_CLOSE);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (ret != (SMB_OFF_T)src_sbuf.st_size) {
+               return NT_STATUS_DISK_FULL;
+       }
 
-       return(ret == (SMB_OFF_T)src_sbuf.st_size);
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -4820,17 +4981,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        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 path_contains_wcard1 = False;
-       BOOL path_contains_wcard2 = False;
-       BOOL rc = True;
+       BOOL source_has_wild = False;
+       BOOL dest_has_wild = False;
        SMB_STRUCT_STAT sbuf1, sbuf2;
        NTSTATUS status;
        START_PROFILE(SMBcopy);
@@ -4838,12 +4994,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        *directory = *mask = 0;
 
        p = smb_buf(inbuf);
-       p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard1);
+       p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &source_has_wild);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcopy);
                return ERROR_NT(status);
        }
-       p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path_contains_wcard2);
+       p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wild);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcopy);
                return ERROR_NT(status);
@@ -4858,11 +5014,35 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_DOS(ERRSRV,ERRinvdevice);
        }
 
-       RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
-       RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf);
+       status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &source_has_wild);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcopy);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
 
-       rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
-       unix_convert(newname,conn,0,&bad_path2,&sbuf2);
+       status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wild);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcopy);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       status = unix_convert(conn, name, source_has_wild, NULL, &sbuf1);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcopy);
+               return ERROR_NT(status);
+       }
+
+       status = unix_convert(conn, newname, dest_has_wild, NULL, &sbuf2);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcopy);
+               return ERROR_NT(status);
+       }
 
        target_is_directory = VALID_STAT_OF_DIR(sbuf2);
 
@@ -4902,61 +5082,99 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!rc && mangle_is_mangled(mask, conn->params))
+       if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
                mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
+       }
 
-       has_wild = path_contains_wcard1;
-
-       if (!has_wild) {
+       if (!source_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 (dest_has_wild) {
+                       if (!resolve_wildcards(directory,newname)) {
+                               END_PROFILE(SMBcopy);
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
                }
-               if (!count) {
-                       exists = vfs_file_exist(conn,directory,NULL);
+
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return ERROR_NT(status);
+               }
+               
+               status = check_name(conn, newname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return ERROR_NT(status);
+               }
+               
+               status = copy_file(conn,directory,newname,ofun,
+                                       count,target_is_directory);
+
+               if(!NT_STATUS_IS_OK(status)) {
+                       END_PROFILE(SMBcopy);
+                       return ERROR_NT(status);
+               } else {
+                       count++;
                }
        } else {
                struct smb_Dir *dir_hnd = NULL;
                const char *dname;
+               long offset = 0;
                pstring destname;
 
                if (strequal(mask,"????????.???"))
                        pstrcpy(mask,"*");
 
-               if (check_name(directory,conn))
-                       dir_hnd = OpenDir(conn, directory, mask, 0);
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return ERROR_NT(status);
+               }
+               
+               dir_hnd = OpenDir(conn, directory, mask, 0);
+               if (dir_hnd == NULL) {
+                       status = map_nt_error_from_unix(errno);
+                       return ERROR_NT(status);
+               }
 
-               if (dir_hnd) {
-                       long offset = 0;
-                       error = ERRbadfile;
+               error = ERRbadfile;
 
-                       while ((dname = ReadDirName(dir_hnd, &offset))) {
-                               pstring fname;
-                               pstrcpy(fname,dname);
+               while ((dname = ReadDirName(dir_hnd, &offset))) {
+                       pstring fname;
+                       pstrcpy(fname,dname);
     
-                               if (!is_visible_file(conn, directory, dname, &sbuf1, False))
-                                       continue;
+                       if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+                               continue;
+                       }
 
-                               if(!mask_match(fname, mask, conn->case_sensitive))
-                                       continue;
+                       if(!mask_match(fname, mask, conn->case_sensitive)) {
+                               continue;
+                       }
+
+                       error = ERRnoaccess;
+                       slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+                       pstrcpy(destname,newname);
+                       if (!resolve_wildcards(fname,destname)) {
+                               continue;
+                       }
+
+                       status = check_name(conn, fname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
+               
+                       status = check_name(conn, destname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
+               
+                       DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
 
-                               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));
+                       status = copy_file(conn,fname,destname,ofun,
+                                       count,target_is_directory);
+                       if (NT_STATUS_IS_OK(status)) {
+                               count++;
                        }
-                       CloseDir(dir_hnd);
                }
+               CloseDir(dir_hnd);
        }
   
        if (count == 0) {
@@ -4967,23 +5185,11 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                        return(UNIXERROR(ERRHRD,ERRgeneral));
                }
 
-               if (exists) {
-                       END_PROFILE(SMBcopy);
-                       return ERROR_DOS(ERRDOS,error);
-               } else {
-                       if((errno == ENOENT) && (bad_path1 || bad_path2) &&
-                          !use_nt_status()) {
-                               /* Samba 3.0.22 has ERRDOS/ERRbadpath in the
-                                * DOS error code case
-                                */
-                               return ERROR_DOS(ERRDOS, ERRbadpath);
-                       }
-                       END_PROFILE(SMBcopy);
-                       return(UNIXERROR(ERRDOS,error));
-               }
+               END_PROFILE(SMBcopy);
+               return ERROR_DOS(ERRDOS,error);
        }
   
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,count);
 
        END_PROFILE(SMBcopy);
@@ -4998,7 +5204,6 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 {
        int snum;
        int outsize = 0;
-       BOOL ok = False;
        pstring newdir;
        NTSTATUS status;
 
@@ -5016,22 +5221,24 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
   
-       RESOLVE_DFSPATH(newdir, conn, inbuf, outbuf);
-
-       if (strlen(newdir) == 0) {
-               ok = True;
-       } else {
-               ok = vfs_directory_exist(conn,newdir,NULL);
-               if (ok)
-                       set_conn_connectpath(conn,newdir);
-       }
-  
-       if (!ok) {
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(pathworks_setdir);
-               return ERROR_DOS(ERRDOS,ERRbadpath);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       if (strlen(newdir) != 0) {
+               if (!vfs_directory_exist(conn,newdir,NULL)) {
+                       END_PROFILE(pathworks_setdir);
+                       return ERROR_DOS(ERRDOS,ERRbadpath);
+               }
+               set_conn_connectpath(conn,newdir);
        }
   
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
        SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
   
        DEBUG(3,("setdir %s\n", newdir));
@@ -5308,7 +5515,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                          "pid %u, file %s\n", (double)offset, (double)count,
                          (unsigned int)lock_pid, fsp->fsp_name ));
                
-               status = do_unlock(fsp,
+               status = do_unlock(smbd_messaging_context(),
+                               fsp,
                                lock_pid,
                                count,
                                offset,
@@ -5380,15 +5588,18 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                        BOOL blocking_lock = lock_timeout ? True : False;
                        BOOL defer_lock = False;
                        struct byte_range_lock *br_lck;
+                       uint32 block_smbpid;
 
-                       br_lck = do_lock(fsp,
+                       br_lck = do_lock(smbd_messaging_context(),
+                                       fsp,
                                        lock_pid,
                                        count,
                                        offset, 
                                        lock_type,
                                        WINDOWS_LOCK,
                                        blocking_lock,
-                                       &status);
+                                       &status,
+                                       &block_smbpid);
 
                        if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
                                /* Windows internal resolution for blocking locks seems
@@ -5425,7 +5636,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                                        lock_type,
                                                        WINDOWS_LOCK,
                                                        offset,
-                                                       count)) {
+                                                       count,
+                                                       block_smbpid)) {
                                        TALLOC_FREE(br_lck);
                                        END_PROFILE(SMBlockingX);
                                        return -1;
@@ -5467,7 +5679,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                return ERROR_DOS(ERRDOS,ERRnoaccess);
                        }
                        
-                       do_unlock(fsp,
+                       do_unlock(smbd_messaging_context(),
+                               fsp,
                                lock_pid,
                                count,
                                offset,
@@ -5477,7 +5690,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                return ERROR_NT(status);
        }
 
-       set_message(outbuf,2,0,True);
+       set_message(inbuf,outbuf,2,0,True);
        
        DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
                  fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
@@ -5513,7 +5726,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
                return ERROR_DOS(ERRSRV,ERRuseSTD);
        }
 
-       outsize = set_message(outbuf,8,0,True);
+       outsize = set_message(inbuf,outbuf,8,0,True);
 
        CHECK_FSP(fsp,conn);
        if (!CHECK_READ(fsp,inbuf)) {
@@ -5549,7 +5762,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
                if (nread < (ssize_t)N)
                        tcount = total_read + nread;
 
-               set_message(outbuf,8,nread+pad,False);
+               set_message(inbuf,outbuf,8,nread+pad,False);
                SIVAL(outbuf,smb_vwv0,startpos);
                SSVAL(outbuf,smb_vwv2,tcount);
                SSVAL(outbuf,smb_vwv6,nread);
@@ -5573,12 +5786,12 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
 
 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-       struct utimbuf unix_times;
+       struct timespec ts[2];
        int outsize = 0;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBsetattrE);
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        if(!fsp || (fsp->conn != conn)) {
                END_PROFILE(SMBsetattrE);
@@ -5590,15 +5803,15 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
         * time as UNIX can't set this.
         */
 
-       unix_times.actime = srv_make_unix_date2(inbuf+smb_vwv3);
-       unix_times.modtime = srv_make_unix_date2(inbuf+smb_vwv5);
+       ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv3)); /* atime. */
+       ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv5)); /* mtime. */
   
        /* 
         * Patch from Ray Frush <frush@engr.colostate.edu>
         * Sometimes times are sent as zero - ignore them.
         */
 
-       if (null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+       if (null_timespec(ts[0]) && null_timespec(ts[1])) {
                /* Ignore request */
                if( DEBUGLVL( 3 ) ) {
                        dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
@@ -5606,20 +5819,22 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
                }
                END_PROFILE(SMBsetattrE);
                return(outsize);
-       } else if (!null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+       } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) {
                /* set modify time = to access time if modify time was unset */
-               unix_times.modtime = unix_times.actime;
+               ts[1] = ts[0];
        }
 
        /* Set the date on this file */
        /* Should we set pending modtime here ? JRA */
-       if(file_utime(conn, fsp->fsp_name, &unix_times)) {
+       if(file_ntimes(conn, fsp->fsp_name, ts)) {
                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 ) );
+       DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
+               fsp->fnum,
+               (unsigned int)ts[0].tv_sec,
+               (unsigned int)ts[1].tv_sec));
 
        END_PROFILE(SMBsetattrE);
        return(outsize);
@@ -5707,7 +5922,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
                SMBwritebmpx */
        SCVAL(outbuf,smb_com,SMBwriteBmpx);
   
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
   
@@ -5716,13 +5931,13 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        if (write_through && tcount==nwritten) {
                /* We need to send both a primary and a secondary response */
-               smb_setlen(outbuf,outsize - 4);
+               smb_setlen(inbuf,outbuf,outsize - 4);
                show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
                        exit_server_cleanly("reply_writebmpx: send_smb failed.");
 
                /* Now the secondary */
-               outsize = set_message(outbuf,1,0,True);
+               outsize = set_message(inbuf,outbuf,1,0,True);
                SCVAL(outbuf,smb_com,SMBwritec);
                SSVAL(outbuf,smb_vwv0,nwritten);
        }
@@ -5808,7 +6023,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
        wbms->wr_total_written += nwritten;
        if(wbms->wr_total_written >= tcount) {
                if (write_through) {
-                       outsize = set_message(outbuf,1,0,True);
+                       outsize = set_message(inbuf,outbuf,1,0,True);
                        SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
                        send_response = True;
                }
@@ -5838,7 +6053,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBgetattrE);
 
-       outsize = set_message(outbuf,11,0,True);
+       outsize = set_message(inbuf,outbuf,11,0,True);
 
        if(!fsp || (fsp->conn != conn)) {
                END_PROFILE(SMBgetattrE);