r23538: Fix for wild-card rename: We can't return directly on error, we need to
[sfrench/samba-autobuild/.git] / source / smbd / reply.c
index f633be374020beea8aa281d66ea3bb814dc7d3cc..41665e1676209cddc4dee47ccbe67e2c4cb22d77 100644 (file)
@@ -44,29 +44,31 @@ extern BOOL global_encrypted_passwords_negotiated;
  set.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax_internal(pstring destname,
-                                   const pstring srcname,
-                                   BOOL windows_path,
-                                   BOOL *p_last_component_contains_wcard)
+/* Custom version for processing POSIX paths. */
+#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
+
+static NTSTATUS check_path_syntax_internal(char *path,
+                                          BOOL posix_path,
+                                          BOOL *p_last_component_contains_wcard)
 {
-       char *d = destname;
-       const char *s = srcname;
+       char *d = path;
+       const char *s = path;
        NTSTATUS ret = NT_STATUS_OK;
        BOOL start_of_name_component = True;
 
        *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.
                         */
                        /* Eat multiple '/' or '\\' */
-                       while (IS_DIRECTORY_SEP(*s)) {
+                       while (IS_PATH_SEP(*s,posix_path)) {
                                s++;
                        }
-                       if ((d != destname) && (*s != '\0')) {
+                       if ((d != path) && (*s != '\0')) {
                                /* We only care about non-leading or trailing '/' or '\\' */
                                *d++ = '/';
                        }
@@ -78,7 +80,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
                }
 
                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" ! */
 
                                /*
@@ -86,13 +88,13 @@ NTSTATUS check_path_syntax_internal(pstring destname,
                                 */
 
                                /* If  we just added a '/' - delete it */
-                               if ((d > destname) && (*(d-1) == '/')) {
+                               if ((d > path) && (*(d-1) == '/')) {
                                        *(d-1) = '\0';
                                        d--;
                                }
 
                                /* Are we at the start ? Can't go back further if so. */
-                               if (d <= destname) {
+                               if (d <= path) {
                                        ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
                                        break;
                                }
@@ -100,7 +102,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
                                /* 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--) {
+                               for (d--; d > path; d--) {
                                        if (*d == '/')
                                                break;
                                }
@@ -108,8 +110,8 @@ NTSTATUS check_path_syntax_internal(pstring destname,
                                /* We're still at the start of a name component, just the previous one. */
                                continue;
 
-                       } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) {
-                               if (!windows_path) {
+                       } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
+                               if (posix_path) {
                                        /* Eat the '.' */
                                        s++;
                                        continue;
@@ -119,7 +121,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
                }
 
                if (!(*s & 0x80)) {
-                       if (windows_path) {
+                       if (!posix_path) {
                                if (*s <= 0x1f) {
                                        return NT_STATUS_OBJECT_NAME_INVALID;
                                }
@@ -174,10 +176,10 @@ NTSTATUS check_path_syntax_internal(pstring destname,
  No wildcards allowed.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax(char *path)
 {
        BOOL ignore;
-       return check_path_syntax_internal(destname, srcname, True, &ignore);
+       return check_path_syntax_internal(path, False, &ignore);
 }
 
 /****************************************************************************
@@ -186,9 +188,9 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
  a wildcard.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
+NTSTATUS check_path_syntax_wcard(char *path, BOOL *p_contains_wcard)
 {
-       return check_path_syntax_internal(destname, srcname, True, p_contains_wcard);
+       return check_path_syntax_internal(path, False, p_contains_wcard);
 }
 
 /****************************************************************************
@@ -197,10 +199,10 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
  set (a safe assumption).
 ****************************************************************************/
 
-static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax_posix(char *path)
 {
        BOOL ignore;
-       return check_path_syntax_internal(destname, srcname, False, &ignore);
+       return check_path_syntax_internal(path, True, &ignore);
 }
 
 /****************************************************************************
@@ -210,25 +212,32 @@ static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
 size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags,
                                NTSTATUS *err, BOOL *contains_wcard)
 {
-       pstring tmppath;
-       char *tmppath_ptr = tmppath;
        size_t ret;
 #ifdef DEVELOPER
        SMB_ASSERT(dest_len == sizeof(pstring));
 #endif
 
        if (src_len == 0) {
-               ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
+               ret = srvstr_pull_buf( inbuf, dest, src, dest_len, flags);
        } else {
-               ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
+               ret = srvstr_pull( inbuf, dest, src, dest_len, src_len, flags);
        }
 
        *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.
+                */
+               *err = NT_STATUS_OK;
+               return ret;
+       }
+
        if (lp_posix_pathnames()) {
-               *err = check_path_syntax_posix(dest, tmppath);
+               *err = check_path_syntax_posix(dest);
        } else {
-               *err = check_path_syntax_wcard(dest, tmppath, contains_wcard);
+               *err = check_path_syntax_wcard(dest, contains_wcard);
        }
 
        return ret;
@@ -240,22 +249,30 @@ size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t de
 
 size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err)
 {
-       pstring tmppath;
-       char *tmppath_ptr = tmppath;
        size_t ret;
 #ifdef DEVELOPER
        SMB_ASSERT(dest_len == sizeof(pstring));
 #endif
 
        if (src_len == 0) {
-               ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
+               ret = srvstr_pull_buf( inbuf, dest, src, dest_len, flags);
        } else {
-               ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
+               ret = srvstr_pull( inbuf, dest, 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.
+                */
+               *err = NT_STATUS_OK;
+               return ret;
        }
+
        if (lp_posix_pathnames()) {
-               *err = check_path_syntax_posix(dest, tmppath);
+               *err = check_path_syntax_posix(dest);
        } else {
-               *err = check_path_syntax(dest, tmppath);
+               *err = check_path_syntax(dest);
        }
 
        return ret;
@@ -279,7 +296,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 */
@@ -397,7 +414,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);
@@ -428,6 +445,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);        
 
@@ -444,13 +462,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);
 
        /*
@@ -489,16 +516,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, 
@@ -506,7 +553,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 */
@@ -569,7 +616,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 */
@@ -632,48 +679,66 @@ int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
                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)));
 
        status = unix_convert(conn, name, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
-               END_PROFILE(SMBcheckpath);
-               status = map_checkpath_error(inbuf, status);
-               return ERROR_NT(status);
+               goto path_err;
        }
 
-       if (check_name(name,conn) && (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0)) {
-               if (!S_ISDIR(sbuf.st_mode)) {
-                       END_PROFILE(SMBcheckpath);
-                       return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath);
-               }
-       } else {
-               /* 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.
-                        */
-                       END_PROFILE(SMBcheckpath);
-                       return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,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 (!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;
+       }
 
+       if (!S_ISDIR(sbuf.st_mode)) {
                END_PROFILE(SMBcheckpath);
-               return(UNIXERROR(ERRDOS,ERRbadpath));
+               return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath);
        }
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        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);
 }
 
 /****************************************************************************
@@ -700,7 +765,14 @@ 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! */
@@ -717,22 +789,26 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                        END_PROFILE(SMBgetatr);
                        return ERROR_NT(status);
                }
-               if (check_name(fname,conn) &&
-                               (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;
-                       }
-               } else {
-                       DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
+               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;
+               }
        }
   
-       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)) ) {
@@ -775,7 +851,14 @@ 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);
+       }
   
        status = unix_convert(conn, fname, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
@@ -783,6 +866,12 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                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
@@ -792,11 +881,6 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(NT_STATUS_ACCESS_DENIED);
        }
 
-       if (!check_name(fname,conn)) {
-               END_PROFILE(SMBsetatr);
-               return UNIXERROR(ERRDOS, ERRnoaccess);
-       }
-
        mode = SVAL(inbuf,smb_vwv0);
        mtime = srv_make_unix_date3(inbuf+smb_vwv1);
   
@@ -812,12 +896,12 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                }
        }
 
-       if (!set_filetime(conn,fname,mtime)) {
+       if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) {
                END_PROFILE(SMBsetatr);
                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 ) );
   
@@ -840,7 +924,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;
@@ -895,14 +979,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;
        NTSTATUS nt_status;
        BOOL mask_contains_wcard = False;
        BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
@@ -917,10 +999,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;
@@ -930,7 +1013,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);
@@ -940,37 +1030,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);
                nt_status = unix_convert(conn, directory, True, NULL, &sbuf);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        END_PROFILE(SMBsearch);
                        return ERROR_NT(nt_status);
                }
-               unix_format(dir2);
 
-               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 {
@@ -978,83 +1063,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 UNIXERROR(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);
        }
@@ -1083,7 +1175,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));
@@ -1118,7 +1210,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)) {
@@ -1181,7 +1273,14 @@ 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);
+       }
 
        status = unix_convert(conn, fname, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1189,6 +1288,12 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                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);
@@ -1224,7 +1329,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)) ) {
@@ -1299,7 +1404,14 @@ 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)) {
@@ -1307,6 +1419,12 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return ERROR_NT(status);
        }
 
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBopenX);
+               return ERROR_NT(status);
+       }
+
        if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun,
                                &access_mask,
                                &share_mode,
@@ -1387,9 +1505,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);
@@ -1431,7 +1549,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 ) );
 
@@ -1449,7 +1567,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);
-       struct utimbuf times;
+       struct timespec ts[2];
        files_struct *fsp;
        int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
        SMB_STRUCT_STAT sbuf;
@@ -1463,7 +1581,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  
        com = SVAL(inbuf,smb_com);
 
-       times.modtime = srv_make_unix_date3(inbuf + smb_vwv1);
+       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)) {
@@ -1471,7 +1589,14 @@ int reply_mknew(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(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)) {
@@ -1479,6 +1604,12 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBcreate);
+               return ERROR_NT(status);
+       }
+
        if (fattr & aVOLID) {
                DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
        }
@@ -1510,10 +1641,10 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
  
-       times.actime = sbuf.st_atime;
-       file_utime(conn, fname, &times);
+       ts[0] = get_atimespec(&sbuf); /* atime. */
+       file_ntimes(conn, fname, ts);
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
 
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
@@ -1561,13 +1692,26 @@ 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);
        }
+
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBctemp);
+               return ERROR_NT(status);
+       }
   
        tmpfd = smb_mkstemp(fname);
        if (tmpfd == -1) {
@@ -1599,7 +1743,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 */
@@ -1618,7 +1762,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);
@@ -1640,17 +1784,16 @@ 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, files_struct *fsp,
+                          uint16 dirtype, SMB_STRUCT_STAT *pst)
 {
-       files_struct *fsp;
        uint32 fmode;
-       NTSTATUS status;
 
        if (!CAN_WRITE(conn)) {
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
-       fmode = dos_mode(conn,fname,pst);
+       fmode = dos_mode(conn, fsp->fsp_name, pst);
        if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
                return NT_STATUS_NO_SUCH_FILE;
        }
@@ -1659,28 +1802,19 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
                return NT_STATUS_OK;
        }
 
-       status = open_file_ntcreate(conn, fname, pst,
-                               DELETE_ACCESS,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE,
-                               FILE_OPEN,
-                               0,
-                               FILE_ATTRIBUTE_NORMAL,
-                               0,
-                               NULL, &fsp);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if (fsp->access_mask & DELETE_ACCESS) {
+               return NT_STATUS_OK;
        }
-       close_file(fsp,NORMAL_CLOSE);
-       return NT_STATUS_OK;
+
+       return NT_STATUS_ACCESS_DENIED;
 }
 
 /*******************************************************************
- Check if a user is allowed to delete a file.
-********************************************************************/
+ * unlink a file with all relevant access checks
+ *******************************************************************/
 
-static NTSTATUS can_delete(connection_struct *conn, char *fname,
-                          uint32 dirtype, BOOL can_defer)
+static NTSTATUS do_unlink(connection_struct *conn, char *fname,
+                         uint32 dirtype, BOOL can_defer)
 {
        SMB_STRUCT_STAT sbuf;
        uint32 fattr;
@@ -1688,7 +1822,7 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname,
        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;
@@ -1781,10 +1915,19 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname,
                                    can_defer ? 0 : INTERNAL_OPEN_ONLY,
                                    NULL, &fsp);
 
-       if (NT_STATUS_IS_OK(status)) {
-               close_file(fsp,NORMAL_CLOSE);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("open_file_ntcreate failed: %s\n",
+                          nt_errstr(status)));
+               return status;
        }
-       return status;
+
+       /* 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);
 }
 
 /****************************************************************************
@@ -1837,67 +1980,86 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
                if (dirtype == 0) {
                        dirtype = FILE_ATTRIBUTE_NORMAL;
                }
-               status = can_delete(conn,directory,dirtype,can_defer);
-               if (!NT_STATUS_IS_OK(status))
+
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
                        return status;
+               }
 
-               if (SMB_VFS_UNLINK(conn,directory) == 0) {
-                       count++;
+               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 ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
                        return NT_STATUS_OBJECT_NAME_INVALID;
                }
 
-               if (strequal(mask,"????????.???"))
+               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;
-                       status = NT_STATUS_NO_SUCH_FILE;
+               status = NT_STATUS_NO_SUCH_FILE;
 
-                       while ((dname = ReadDirName(dir_hnd, &offset))) {
-                               SMB_STRUCT_STAT st;
-                               pstring fname;
-                               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])) {
-                                               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;
+                       }
                                
-                               slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-                               status = can_delete(conn, fname, dirtype,
-                                                   can_defer);
-                               if (!NT_STATUS_IS_OK(status)) {
-                                       continue;
-                               }
-                               if (SMB_VFS_UNLINK(conn,fname) == 0)
-                                       count++;
-                               DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
+                       slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+
+                       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(status)) {
@@ -1929,8 +2091,15 @@ 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));
        
@@ -1944,13 +2113,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;
@@ -1968,39 +2131,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,nread) != nread) {
-               return -1;
-       }       
+               if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
+                       return -1;
+               }
+               tosend -= cur_read;
+               startpos += cur_read;
+       }
 
        return (ssize_t)nread;
 }
-#endif
 
 /****************************************************************************
  Use sendfile in readbraw.
@@ -2057,12 +2223,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. */
@@ -2221,7 +2387,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;
        
@@ -2233,14 +2399,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)) {
@@ -2302,7 +2470,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.
@@ -2342,6 +2510,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.
 ****************************************************************************/
@@ -2349,47 +2538,46 @@ 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 defined(WITH_SENDFILE)
-       /*
-        * We can only use sendfile on a non-chained packet 
+       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 
         * but we can use on a non-oplocked file. tridge proved this
         * on a train in Germany :-). JRA.
         */
 
        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;
@@ -2434,28 +2622,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;
+       }
 }
 
 /****************************************************************************
@@ -2468,6 +2668,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
@@ -2485,17 +2686,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;
                }
        }
 
@@ -2528,14 +2737,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;
@@ -2556,6 +2767,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        BOOL write_through;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        int outsize = 0;
+       NTSTATUS status;
        START_PROFILE(SMBwritebraw);
 
        if (srv_is_signing_active()) {
@@ -2607,7 +2819,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.");
@@ -2621,7 +2833,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) {
@@ -2660,7 +2872,13 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
  
        SSVAL(outbuf,smb_vwv0,total_written);
 
-       sync_file(conn, fsp, write_through);
+       status = sync_file(conn, fsp, write_through);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
+                       fsp->fsp_name, nt_errstr(status) ));
+               END_PROFILE(SMBwritebraw);
+               return ERROR_NT(status);
+       }
 
        DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
                fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
@@ -2725,7 +2943,13 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
                nwritten = write_file(fsp,data,startpos,numtowrite);
        }
   
-       sync_file(conn, fsp, False /* write through */);
+       status = sync_file(conn, fsp, False /* write through */);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBwriteunlock);
+               DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
+                       fsp->fsp_name, nt_errstr(status) ));
+               return ERROR_NT(status);
+       }
 
        if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
                END_PROFILE(SMBwriteunlock);
@@ -2733,7 +2957,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,
@@ -2745,7 +2970,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);
        
@@ -2771,6 +2996,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
        char *data;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        int outsize = 0;
+       NTSTATUS status;
        START_PROFILE(SMBwrite);
 
        /* If it's an IPC, pass off the pipe handler. */
@@ -2781,6 +3007,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
 
        CHECK_FSP(fsp,conn);
        if (!CHECK_WRITE(fsp)) {
+               END_PROFILE(SMBwrite);
                return(ERROR_DOS(ERRDOS,ERRbadaccess));
        }
 
@@ -2816,14 +3043,20 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
        } else
                nwritten = write_file(fsp,data,startpos,numtowrite);
   
-       sync_file(conn, fsp, False);
+       status = sync_file(conn, fsp, False);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBwrite);
+               DEBUG(5,("reply_write: sync_file for %s returned %s\n",
+                       fsp->fsp_name, nt_errstr(status) ));
+               return ERROR_NT(status);
+       }
 
        if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
                END_PROFILE(SMBwrite);
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVAL(outbuf,smb_vwv0,nwritten);
 
@@ -2853,6 +3086,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
        unsigned int smblen = smb_len(inbuf);
        char *data;
        BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
+       NTSTATUS status;
        START_PROFILE(SMBwriteX);
 
        /* If it's an IPC, pass off the pipe handler. */
@@ -2866,7 +3100,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) {
@@ -2943,7 +3177,13 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
        DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
                fsp->fnum, (int)numtowrite, (int)nwritten));
 
-       sync_file(conn, fsp, write_through);
+       status = sync_file(conn, fsp, write_through);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBwriteX);
+               DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
+                       fsp->fsp_name, nt_errstr(status) ));
+               return ERROR_NT(status);
+       }
 
        END_PROFILE(SMBwriteX);
        return chain_reply(inbuf,outbuf,length,bufsize);
@@ -3013,7 +3253,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",
@@ -3029,7 +3269,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);
@@ -3040,7 +3280,13 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        if (!fsp) {
                file_sync_all(conn);
        } else {
-               sync_file(conn,fsp, True);
+               NTSTATUS status = sync_file(conn, fsp, True);
+               if (!NT_STATUS_IS_OK(status)) {
+                       END_PROFILE(SMBflush);
+                       DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
+                               fsp->fsp_name, nt_errstr(status) ));
+                       return ERROR_NT(status);
+               }
        }
        
        DEBUG(3,("flush\n"));
@@ -3061,7 +3307,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"));
 
@@ -3076,13 +3322,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)) {
@@ -3106,12 +3351,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;
 
                DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
                         fsp->fh->fd, fsp->fnum,
@@ -3121,8 +3365,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
@@ -3130,17 +3374,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);
@@ -3157,10 +3396,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);
 
@@ -3171,7 +3410,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)) {
@@ -3181,7 +3420,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.
@@ -3191,7 +3430,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",
@@ -3203,13 +3442,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);
@@ -3226,7 +3464,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);
@@ -3244,14 +3482,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);
 
@@ -3271,7 +3511,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);
@@ -3282,7 +3522,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,
@@ -3311,7 +3552,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);
 
@@ -3342,7 +3583,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) {
@@ -3363,7 +3604,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))
@@ -3404,7 +3645,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",
@@ -3421,9 +3662,9 @@ 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);
@@ -3436,12 +3677,11 @@ int reply_printclose(connection_struct *conn,
        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);
@@ -3455,7 +3695,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);
@@ -3503,7 +3743,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);
@@ -3526,7 +3766,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);
 
@@ -3575,7 +3815,14 @@ 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);
+       }
 
        status = unix_convert(conn, directory, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
@@ -3583,6 +3830,12 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
+       status = check_name(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBmkdir);
+               return ERROR_NT(status);
+       }
+  
        status = create_directory(conn, directory);
 
        DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
@@ -3604,7 +3857,7 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
 
@@ -3675,14 +3928,33 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
  The internals of the rmdir code - called elsewhere.
 ****************************************************************************/
 
-BOOL rmdir_internals(connection_struct *conn, const char *directory)
+NTSTATUS rmdir_internals(connection_struct *conn, const char *directory)
 {
        int ret;
        SMB_STRUCT_STAT st;
 
-       ret = SMB_VFS_RMDIR(conn,directory);
+       /* 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) {
-               return True;
+               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))) {
@@ -3756,10 +4028,14 @@ BOOL rmdir_internals(connection_struct *conn, const char *directory)
        if (ret != 0) {
                DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
                         "%s\n", directory,strerror(errno)));
-               return False;
+               return map_nt_error_from_unix(errno);
        }
 
-       return True;
+       notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                    FILE_NOTIFY_CHANGE_DIR_NAME,
+                    directory);
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -3780,7 +4056,14 @@ 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);
+       }
 
        status = unix_convert(conn, directory, False, NULL, &sbuf);
        if (!NT_STATUS_IS_OK(status)) {
@@ -3788,18 +4071,20 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
   
-       if (!check_name(directory,conn)) {
+       status = check_name(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBrmdir);
-               return UNIXERROR(ERRDOS, ERRbadpath);
+               return ERROR_NT(status);
        }
 
        dptr_closepath(directory,SVAL(inbuf,smb_pid));
-       if (!rmdir_internals(conn, directory)) {
+       status = rmdir_internals(conn, directory);
+       if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBrmdir);
-               return UNIXERROR(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 ) );
   
@@ -3822,7 +4107,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,'/');
 
@@ -3898,13 +4182,15 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
  asynchronously.
 ****************************************************************************/
 
-static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck,
-                               SMB_DEV_T dev, SMB_INO_T inode, const char *newname)
+static void rename_open_files(connection_struct *conn,
+                             struct share_mode_lock *lck,
+                             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(lck->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
@@ -3912,20 +4198,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(&lck->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);
 }
 
 /****************************************************************************
@@ -3957,25 +4244,75 @@ static BOOL rename_path_prefix_equal(const char *src, const char *dest)
        return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
 }
 
+/*
+ * 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);
+       }
+}
+
 /****************************************************************************
  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;
+       SMB_STRUCT_STAT sbuf, sbuf1;
        pstring newname_last_component;
        NTSTATUS status = NT_STATUS_OK;
-       BOOL dest_exists;
        struct share_mode_lock *lck = NULL;
+       BOOL dst_exists;
 
        ZERO_STRUCT(sbuf);
 
        status = unix_convert(conn, newname, False, newname_last_component, &sbuf);
-       if (!NT_STATUS_IS_OK(status)) {
+
+       /* 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;
@@ -4027,18 +4364,37 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
                return NT_STATUS_OK;
        }
 
-       dest_exists = vfs_object_exist(conn,newname,NULL);
+       /*
+        * Have vfs_object_exist also fill sbuf1
+        */
+       dst_exists = vfs_object_exist(conn, newname, &sbuf1);
 
-       if(!replace_if_exists && dest_exists) {
+       if(!replace_if_exists && dst_exists) {
                DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
                        fsp->fsp_name,newname));
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       status = can_rename(conn,newname,attrs,&sbuf);
+       if (dst_exists && file_find_di_first(file_id_sbuf(&sbuf1)) != NULL) {
+               DEBUG(3, ("rename_internals_fsp: Target file open\n"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
 
-       if (dest_exists && !NT_STATUS_IS_OK(status)) {
-               DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+       /* 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);
+               }
+       }
+
+       status = can_rename(conn, fsp, attrs, &sbuf);
+
+       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;
@@ -4049,12 +4405,45 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
                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);
+
+       /*
+        * We have the file open ourselves, so not being able to get the
+        * corresponding share mode lock is a fatal error.
+        */
+
+       SMB_ASSERT(lck != 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, newname);
+
+               notify_rename(conn, fsp->is_directory, fsp->fsp_name, 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;    
        }
@@ -4078,7 +4467,13 @@ 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;
@@ -4088,19 +4483,22 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
        int count=0;
        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;
 
        *directory = *mask = 0;
 
        ZERO_STRUCT(sbuf1);
        ZERO_STRUCT(sbuf2);
 
-       status = unix_convert(conn, name, has_wild, last_component_src, &sbuf1);
+       status = unix_convert(conn, name, src_has_wild, last_component_src, &sbuf1);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       status = unix_convert(conn, newname, True, last_component_dest, &sbuf2);
+       status = unix_convert(conn, newname, dest_has_wild, last_component_dest, &sbuf2);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -4134,10 +4532,13 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!VALID_STAT(sbuf1) && 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 (!src_has_wild) {
+               files_struct *fsp;
 
-       if (!has_wild) {
                /*
                 * No wildcards - just process the one file.
                 */
@@ -4156,237 +4557,160 @@ 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));
-
-               /*
-                * Check for special case with case preserving and not
-                * case sensitive, if directory and newname are identical,
-                * and the old last component differs from the original
-                * last component only by case, then we should allow
-                * the rename (user is trying to change the case of the
-                * filename).
-                */
-               if((conn->case_sensitive == False) && 
-                  (((conn->case_preserve == True) && 
-                    (is_short_name == False)) || 
-                   ((conn->short_case_preserve == True) && 
-                    (is_short_name == True))) &&
-                  strcsequal(directory, newname)) {
-                       pstring modified_last_component;
-
-                       /*
-                        * Get the last component of the modified name.
-                        * Note that we guarantee that newname contains a '/'
-                        * character above.
-                        */
-                       p = strrchr_m(newname,'/');
-                       pstrcpy(modified_last_component,p+1);
-                       
-                       if(strcsequal(modified_last_component, 
-                                     last_component_dest) == False) {
-                               /*
-                                * Replace the modified last component with
-                                * the original.
-                                */
-                               pstrcpy(p+1, last_component_dest);
-                       }
-               }
-       
-               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;
+               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));
+
+               /* 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;
                        }
-                       status = map_nt_error_from_unix(errno);
-                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
-                               nt_errstr(status), directory,newname));
-
-                       return status;
                }
-
-               status = can_rename(conn,directory,attrs,&sbuf1);
+                               
+               ZERO_STRUCT(sbuf1);
+               SMB_VFS_STAT(conn, directory, &sbuf1);
+
+               status = S_ISDIR(sbuf1.st_mode) ?
+                       open_directory(conn, directory, &sbuf1,
+                                      DELETE_ACCESS,
+                                      FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                      FILE_OPEN, 0, 0, NULL,
+                                      &fsp)
+                       : open_file_ntcreate(conn, directory, &sbuf1,
+                                            DELETE_ACCESS,
+                                            FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                            FILE_OPEN, 0, 0, 0, NULL,
+                                            &fsp);
 
                if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
-                               nt_errstr(status), directory,newname));
+                       DEBUG(3, ("Could not open rename source %s: %s\n",
+                                 directory, nt_errstr(status)));
                        return status;
                }
 
-               /*
-                * If the src and dest names are identical - including case,
-                * don't do the rename, just return success.
-                */
-
-               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));
-                       return NT_STATUS_OK;
-               }
+               status = rename_internals_fsp(conn, fsp, newname, attrs,
+                                             replace_if_exists);
 
-               if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
-                       DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
-                               directory,newname));
-                       return NT_STATUS_OBJECT_NAME_COLLISION;
-               }
+               close_file(fsp, NORMAL_CLOSE);
 
-               if (rename_path_prefix_equal(directory, newname)) {
-                       return NT_STATUS_SHARING_VIOLATION;
-               }
-
-               lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, 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);
-                       TALLOC_FREE(lck);
-                       return NT_STATUS_OK;    
-               }
-
-               TALLOC_FREE(lck);
-               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(status), directory,newname));
+               DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
+                         nt_errstr(status), directory,newname));
 
                return status;
-       } else {
-               /*
-                * Wildcards - process each file that matches.
-                */
-               struct smb_Dir *dir_hnd = NULL;
-               const char *dname;
-               pstring destname;
-               
-               if (strequal(mask,"????????.???"))
-                       pstrcpy(mask,"*");
+       }
+
+       /*
+        * 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;
-                       status = NT_STATUS_NO_SUCH_FILE;
-/*                     Was status = 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))) {
+               files_struct *fsp;
+               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) {
-                                       status = NT_STATUS_OBJECT_NAME_INVALID;
-                                       break;
-                               }
+               if (sysdir_entry) {
+                       status = NT_STATUS_OBJECT_NAME_INVALID;
+                       break;
+               }
 
-                               status = NT_STATUS_ACCESS_DENIED;
-                               slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
-                               if (!vfs_object_exist(conn, fname, &sbuf1)) {
-                                       status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                                       DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(status)));
-                                       continue;
-                               }
-                               status = can_rename(conn,fname,attrs,&sbuf1);
-                               if (!NT_STATUS_IS_OK(status)) {
-                                       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++;
-                                       status = NT_STATUS_OK;
-                                       continue;
-                               }
+               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));
-                                       status = NT_STATUS_OBJECT_NAME_COLLISION;
-                                       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;
-                               }
-
-                               lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL);
+               ZERO_STRUCT(sbuf1);
+               SMB_VFS_STAT(conn, fname, &sbuf1);
+
+               status = S_ISDIR(sbuf1.st_mode) ?
+                       open_directory(conn, fname, &sbuf1,
+                                      DELETE_ACCESS,
+                                      FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                      FILE_OPEN, 0, 0, NULL,
+                                      &fsp)
+                       : open_file_ntcreate(conn, fname, &sbuf1,
+                                            DELETE_ACCESS,
+                                            FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                            FILE_OPEN, 0, 0, 0, NULL,
+                                            &fsp);
 
-                               if (!SMB_VFS_RENAME(conn,fname,destname)) {
-                                       rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname);
-                                       count++;
-                                       status = NT_STATUS_OK;
-                               }
-                               TALLOC_FREE(lck);
-                               DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
-                       }
-                       CloseDir(dir_hnd);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(3,("rename_internals: open_file_ntcreate "
+                                "returned %s rename %s -> %s\n",
+                                nt_errstr(status), directory, newname));
+                       break;
                }
 
-#if 0
-       /* Don't think needed any more - JRA. */
-               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;
-                       }
+               status = rename_internals_fsp(conn, fsp, destname, attrs,
+                                             replace_if_exists);
+
+               close_file(fsp, NORMAL_CLOSE);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(3, ("rename_internals_fsp returned %s for "
+                                 "rename %s -> %s\n", nt_errstr(status),
+                                 directory, newname));
+                       break;
                }
-#endif
 
+               count++;
+
+               DEBUG(3,("rename_internals: doing rename on %s -> "
+                        "%s\n",fname,destname));
        }
-       
+       CloseDir(dir_hnd);
+
        if (count == 0 && NT_STATUS_IS_OK(status)) {
                status = map_nt_error_from_unix(errno);
        }
@@ -4407,30 +4731,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 path1_contains_wcard = False;
-       BOOL path2_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, &path1_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_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path2_contains_wcard);
+       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, path1_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))) {
@@ -4440,12 +4779,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);
@@ -4459,8 +4793,12 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  * TODO: check error codes on all callers
  */
 
-NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun,
-                  int count, BOOL target_is_directory)
+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;
@@ -4469,7 +4807,6 @@ NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun,
        uint32 dosattrs;
        uint32 new_create_disposition;
        NTSTATUS status;
-       int close_err;
  
        pstrcpy(dest,dest1);
        if (target_is_directory) {
@@ -4546,7 +4883,7 @@ NTSTATUS 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
@@ -4554,10 +4891,10 @@ NTSTATUS 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.
         */
-       close_err = close_file(fsp2,NORMAL_CLOSE);
+       status = close_file(fsp2,NORMAL_CLOSE);
 
-       if (close_err != 0) {
-               return map_nt_error_from_unix(close_err);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        if (ret != (SMB_OFF_T)src_sbuf.st_size) {
@@ -4581,14 +4918,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 path_contains_wcard1 = False;
-       BOOL path_contains_wcard2 = False;
+       BOOL source_has_wild = False;
+       BOOL dest_has_wild = False;
        SMB_STRUCT_STAT sbuf1, sbuf2;
        NTSTATUS status;
        START_PROFILE(SMBcopy);
@@ -4596,12 +4931,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);
@@ -4616,16 +4951,31 @@ 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);
+       }
 
-       status = unix_convert(conn, name, path_contains_wcard1, NULL, &sbuf1);
+       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, newname, path_contains_wcard2, NULL, &sbuf2);
+       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);
@@ -4669,63 +5019,99 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!VALID_STAT(sbuf1) && 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)
-                   && NT_STATUS_IS_OK(status = copy_file(
-                                              directory,newname,conn,ofun,
-                                              count,target_is_directory))) 
-                       count++;
-               if(!count && !NT_STATUS_IS_OK(status)) {
-                       END_PROFILE(SMBcopy);
+               if (dest_has_wild) {
+                       if (!resolve_wildcards(directory,newname)) {
+                               END_PROFILE(SMBcopy);
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
+               }
+
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
-               if (!count) {
-                       exists = vfs_file_exist(conn,directory,NULL);
+               
+               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)
-                                   && NT_STATUS_IS_OK(status = copy_file(
-                                                              fname,destname,conn,ofun,
-                                                              count,target_is_directory)))
-                                       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) {
@@ -4740,7 +5126,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                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);
@@ -4755,7 +5141,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;
 
@@ -4773,22 +5158,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));
@@ -5065,7 +5452,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,
@@ -5137,15 +5525,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
@@ -5182,7 +5573,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;
@@ -5224,7 +5616,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,
@@ -5234,7 +5627,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));
@@ -5270,7 +5663,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)) {
@@ -5306,7 +5699,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);
@@ -5330,12 +5723,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);
@@ -5347,15 +5740,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);
@@ -5363,20 +5756,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);
@@ -5400,6 +5795,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
        int smb_doff;
        char *data;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       NTSTATUS status;
        START_PROFILE(SMBwriteBmpx);
 
        CHECK_FSP(fsp,conn);
@@ -5429,7 +5825,13 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        nwritten = write_file(fsp,data,startpos,numtowrite);
 
-       sync_file(conn, fsp, write_through);
+       status = sync_file(conn, fsp, write_through);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBwriteBmpx);
+               DEBUG(5,("reply_writebmpx: sync_file for %s returned %s\n",
+                       fsp->fsp_name, nt_errstr(status) ));
+               return ERROR_NT(status);
+       }
   
        if(nwritten < (ssize_t)numtowrite) {
                END_PROFILE(SMBwriteBmpx);
@@ -5464,7 +5866,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 */
   
@@ -5473,13 +5875,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);
        }
@@ -5505,6 +5907,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
        write_bmpx_struct *wbms;
        BOOL send_response = False; 
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       NTSTATUS status;
        START_PROFILE(SMBwriteBs);
 
        CHECK_FSP(fsp,conn);
@@ -5541,9 +5944,9 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
 
        nwritten = write_file(fsp,data,startpos,numtowrite);
 
-       sync_file(conn, fsp, write_through);
+       status = sync_file(conn, fsp, write_through);
   
-       if (nwritten < (ssize_t)numtowrite) {
+       if (nwritten < (ssize_t)numtowrite || !NT_STATUS_IS_OK(status)) {
                if(write_through) {
                        /* We are returning an error - we can delete the aux struct */
                        if (wbms)
@@ -5565,7 +5968,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;
                }
@@ -5595,7 +5998,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);