r23469: Fix a comment
[sfrench/samba-autobuild/.git] / source / smbd / reply.c
index 7cb086841d63e017f00c9b95127c3efdf5a9fc9a..272c3966ba3f468de865c2b9a8b5037d435b0389 100644 (file)
@@ -44,9 +44,12 @@ extern BOOL global_encrypted_passwords_negotiated;
  set.
 ****************************************************************************/
 
+/* Custom version for processing POSIX paths. */
+#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
+
 NTSTATUS check_path_syntax_internal(pstring destname,
                                    const pstring srcname,
-                                   BOOL windows_path,
+                                   BOOL posix_path,
                                    BOOL *p_last_component_contains_wcard)
 {
        char *d = destname;
@@ -57,13 +60,13 @@ NTSTATUS check_path_syntax_internal(pstring destname,
        *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')) {
@@ -78,7 +81,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" ! */
 
                                /*
@@ -108,8 +111,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 +122,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;
                                }
@@ -177,7 +180,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
 NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
 {
        BOOL ignore;
-       return check_path_syntax_internal(destname, srcname, True, &ignore);
+       return check_path_syntax_internal(destname, srcname, False, &ignore);
 }
 
 /****************************************************************************
@@ -188,7 +191,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
 
 NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
 {
-       return check_path_syntax_internal(destname, srcname, True, p_contains_wcard);
+       return check_path_syntax_internal(destname, srcname, False, p_contains_wcard);
 }
 
 /****************************************************************************
@@ -197,10 +200,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(pstring destname, const pstring srcname)
 {
        BOOL ignore;
-       return check_path_syntax_internal(destname, srcname, False, &ignore);
+       return check_path_syntax_internal(destname, srcname, True, &ignore);
 }
 
 /****************************************************************************
@@ -225,6 +228,16 @@ size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t de
 
        *contains_wcard = False;
 
+       if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+               /* 
+                * For a DFS path the function parse_dfs_path()
+                * will do the path processing, just make a copy.
+                */
+               pstrcpy(dest, tmppath);
+               *err = NT_STATUS_OK;
+               return ret;
+       }
+
        if (lp_posix_pathnames()) {
                *err = check_path_syntax_posix(dest, tmppath);
        } else {
@@ -252,6 +265,17 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len
        } else {
                ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
        }
+
+       if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+               /* 
+                * For a DFS path the function parse_dfs_path()
+                * will do the path processing, just make a copy.
+                */
+               pstrcpy(dest, tmppath);
+               *err = NT_STATUS_OK;
+               return ret;
+       }
+
        if (lp_posix_pathnames()) {
                *err = check_path_syntax_posix(dest, tmppath);
        } else {
@@ -279,7 +303,7 @@ int reply_special(char *inbuf,char *outbuf)
        
        memset(outbuf,'\0',smb_size);
 
-       smb_setlen(outbuf,0);
+       smb_setlen(inbuf,outbuf,0);
        
        switch (msg_type) {
        case 0x81: /* session request */
@@ -397,7 +421,7 @@ int reply_tcon(connection_struct *conn,
                return ERROR_NT(nt_status);
        }
   
-       outsize = set_message(outbuf,2,0,True);
+       outsize = set_message(inbuf,outbuf,2,0,True);
        SSVAL(outbuf,smb_vwv0,max_recv);
        SSVAL(outbuf,smb_vwv1,conn->cnum);
        SSVAL(outbuf,smb_tid,conn->cnum);
@@ -428,6 +452,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        int passlen = SVAL(inbuf,smb_vwv3);
        pstring path;
        char *p, *q;
+       uint16 tcon_flags = SVAL(inbuf,smb_vwv2);
        
        START_PROFILE(SMBtconX);        
 
@@ -444,13 +469,22 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
  
        if (global_encrypted_passwords_negotiated) {
                password = data_blob(smb_buf(inbuf),passlen);
+               if (lp_security() == SEC_SHARE) {
+                       /*
+                        * Security = share always has a pad byte
+                        * after the password.
+                        */
+                       p = smb_buf(inbuf) + passlen + 1;
+               } else {
+                       p = smb_buf(inbuf) + passlen;
+               }
        } else {
                password = data_blob(smb_buf(inbuf),passlen+1);
                /* Ensure correct termination */
-               password.data[passlen]=0;    
+               password.data[passlen]=0;
+               p = smb_buf(inbuf) + passlen + 1;
        }
 
-       p = smb_buf(inbuf) + passlen;
        p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
 
        /*
@@ -489,16 +523,36 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                server_devicetype = "A:";
 
        if (Protocol < PROTOCOL_NT1) {
-               set_message(outbuf,2,0,True);
+               set_message(inbuf,outbuf,2,0,True);
                p = smb_buf(outbuf);
                p += srvstr_push(outbuf, p, server_devicetype, -1, 
                                 STR_TERMINATE|STR_ASCII);
-               set_message_end(outbuf,p);
+               set_message_end(inbuf,outbuf,p);
        } else {
                /* NT sets the fstype of IPC$ to the null string */
                const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
                
-               set_message(outbuf,3,0,True);
+               if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
+                       /* Return permissions. */
+                       uint32 perm1 = 0;
+                       uint32 perm2 = 0;
+
+                       set_message(inbuf,outbuf,7,0,True);
+
+                       if (IS_IPC(conn)) {
+                               perm1 = FILE_ALL_ACCESS;
+                               perm2 = FILE_ALL_ACCESS;
+                       } else {
+                               perm1 = CAN_WRITE(conn) ?
+                                               SHARE_ALL_ACCESS :
+                                               SHARE_READ_ONLY;
+                       }
+
+                       SIVAL(outbuf, smb_vwv3, perm1);
+                       SIVAL(outbuf, smb_vwv5, perm2);
+               } else {
+                       set_message(inbuf,outbuf,3,0,True);
+               }
 
                p = smb_buf(outbuf);
                p += srvstr_push(outbuf, p, server_devicetype, -1, 
@@ -506,7 +560,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                p += srvstr_push(outbuf, p, fstype, -1, 
                                 STR_TERMINATE);
                
-               set_message_end(outbuf,p);
+               set_message_end(inbuf,outbuf,p);
                
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
@@ -569,7 +623,7 @@ int reply_ioctl(connection_struct *conn,
                return(ERROR_DOS(ERRSRV,ERRnosupport));
        }
 
-       outsize = set_message(outbuf,8,replysize+1,True);
+       outsize = set_message(inbuf,outbuf,8,replysize+1,True);
        SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
        SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
        SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
@@ -632,7 +686,14 @@ 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)));
 
@@ -658,7 +719,7 @@ int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
                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;
@@ -711,7 +772,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! */
@@ -747,7 +815,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                }
        }
   
-       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)) ) {
@@ -790,7 +858,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)) {
@@ -798,6 +873,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
@@ -807,12 +888,6 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(NT_STATUS_ACCESS_DENIED);
        }
 
-       status = check_name(conn, fname);
-       if (!NT_STATUS_IS_OK(status)) {
-               END_PROFILE(SMBsetatr);
-               return ERROR_NT(status);
-       }
-
        mode = SVAL(inbuf,smb_vwv0);
        mtime = srv_make_unix_date3(inbuf+smb_vwv1);
   
@@ -828,12 +903,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 ) );
   
@@ -856,7 +931,7 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
                return(UNIXERROR(ERRHRD,ERRgeneral));
        }
   
-       outsize = set_message(outbuf,5,0,True);
+       outsize = set_message(inbuf,outbuf,5,0,True);
        
        if (Protocol <= PROTOCOL_LANMAN2) {
                double total_space, free_space;
@@ -935,7 +1010,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                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;
@@ -945,7 +1020,14 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(nt_status);
        }
 
-       RESOLVE_DFSPATH_WCARD(path, conn, inbuf, outbuf);
+       nt_status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path, &mask_contains_wcard);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               END_PROFILE(SMBsearch);
+               if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(nt_status);
+       }
   
        p++;
        status_len = SVAL(p, 0);
@@ -955,16 +1037,13 @@ 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);
 
                nt_status = check_name(conn, directory);
                if (!NT_STATUS_IS_OK(nt_status)) {
@@ -972,23 +1051,16 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                        return ERROR_NT(nt_status);
                }
 
-               p = strrchr_m(dir2,'/');
-               if (p == NULL) {
-                       pstrcpy(mask,dir2);
-                       *dir2 = 0;
-               } else {
-                       *p = 0;
-                       pstrcpy(mask,p+1);
-               }
-
                p = strrchr_m(directory,'/');
                if (!p) {
-                       *directory = 0;
+                       pstrcpy(mask,directory);
+                       pstrcpy(directory,".");
                } else {
                        *p = 0;
+                       pstrcpy(mask,p+1);
                }
 
-               if (strlen(directory) == 0) {
+               if (*directory == '\0') {
                        pstrcpy(directory,".");
                }
                memset((char *)status,'\0',21);
@@ -1008,6 +1080,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                }
                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);
        }
 
        p = smb_buf(outbuf) + 3;
@@ -1105,7 +1182,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        SSVAL(outbuf,smb_flg2, (SVAL(outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
          
        outsize += DIR_STRUCT_SIZE*numentries;
-       smb_setlen(outbuf,outsize - 4);
+       smb_setlen(inbuf,outbuf,outsize - 4);
   
        if ((! *directory) && dptr_path(dptr_num))
                slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
@@ -1140,7 +1217,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return reply_unknown(inbuf, outbuf);
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        p = smb_buf(inbuf) + 1;
        p += srvstr_get_path_wcard(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, &path_contains_wcard);
        if (!NT_STATUS_IS_OK(err)) {
@@ -1203,7 +1280,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)) {
@@ -1211,6 +1295,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);
@@ -1246,7 +1336,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
   
-       outsize = set_message(outbuf,7,0,True);
+       outsize = set_message(inbuf,outbuf,7,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
        SSVAL(outbuf,smb_vwv1,fattr);
        if(lp_dos_filetime_resolution(SNUM(conn)) ) {
@@ -1321,7 +1411,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)) {
@@ -1329,6 +1426,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,
@@ -1409,9 +1512,9 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
        if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
-               set_message(outbuf,19,0,True);
+               set_message(inbuf,outbuf,19,0,True);
        } else {
-               set_message(outbuf,15,0,True);
+               set_message(inbuf,outbuf,15,0,True);
        }
        SSVAL(outbuf,smb_vwv2,fsp->fnum);
        SSVAL(outbuf,smb_vwv3,fattr);
@@ -1453,7 +1556,7 @@ int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,
 
        invalidate_vuid(vuid);
 
-       set_message(outbuf,2,0,True);
+       set_message(inbuf,outbuf,2,0,True);
 
        DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
 
@@ -1471,7 +1574,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        int com;
        int outsize = 0;
        uint32 fattr = SVAL(inbuf,smb_vwv0);
-       struct utimbuf times;
+       struct timespec ts[2];
        files_struct *fsp;
        int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
        SMB_STRUCT_STAT sbuf;
@@ -1485,7 +1588,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)) {
@@ -1493,7 +1596,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)) {
@@ -1501,6 +1611,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));
        }
@@ -1532,10 +1648,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))) {
@@ -1583,13 +1699,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) {
@@ -1621,7 +1750,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
 
        /* the returned filename is relative to the directory */
@@ -1640,7 +1769,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 #endif
        namelen = srvstr_push(outbuf, p, s, -1, STR_ASCII|STR_TERMINATE);
        p += namelen;
-       outsize = set_message_end(outbuf, p);
+       outsize = set_message_end(inbuf,outbuf, p);
 
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
                SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
@@ -1662,7 +1791,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  Check if a user is allowed to rename a file.
 ********************************************************************/
 
-static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open)
 {
        files_struct *fsp;
        uint32 fmode;
@@ -1683,7 +1812,10 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
 
        status = open_file_ntcreate(conn, fname, pst,
                                DELETE_ACCESS,
-                               FILE_SHARE_READ|FILE_SHARE_WRITE,
+                               /* If we're checking our fsp don't deny for delete. */
+                               self_open ?
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE :
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
                                FILE_OPEN,
                                0,
                                FILE_ATTRIBUTE_NORMAL,
@@ -1698,11 +1830,11 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype,
 }
 
 /*******************************************************************
- 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;
@@ -1710,7 +1842,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;
@@ -1803,10 +1935,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);
 }
 
 /****************************************************************************
@@ -1859,17 +2000,18 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
                if (dirtype == 0) {
                        dirtype = FILE_ATTRIBUTE_NORMAL;
                }
-               status = can_delete(conn,directory,dirtype,can_defer);
+
+               status = check_name(conn, directory);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
 
-               if (SMB_VFS_UNLINK(conn,directory) == 0) {
-                       count++;
-                       notify_fname(conn, directory,
-                                    FILE_NOTIFY_CHANGE_FILE,
-                                    NOTIFY_ACTION_REMOVED);
+               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;
@@ -1921,19 +2063,21 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
                        }
                                
                        slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-                       status = can_delete(conn, fname, dirtype, can_defer);
+
+                       status = check_name(conn, fname);
                        if (!NT_STATUS_IS_OK(status)) {
-                               continue;
+                               CloseDir(dir_hnd);
+                               return status;
                        }
-                       if (SMB_VFS_UNLINK(conn,fname) == 0) {
-                               count++;
-                               DEBUG(3,("unlink_internals: succesful unlink "
-                                        "[%s]\n",fname));
-                               notify_action(conn, directory, dname,
-                                             FILE_NOTIFY_CHANGE_FILE,
-                                             NOTIFY_ACTION_REMOVED);
+
+                       status = do_unlink(conn, fname, dirtype, can_defer);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               continue;
                        }
-                               
+
+                       count++;
+                       DEBUG(3,("unlink_internals: succesful unlink [%s]\n",
+                                fname));
                }
                CloseDir(dir_hnd);
        }
@@ -1967,8 +2111,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));
        
@@ -1982,7 +2133,7 @@ int reply_unlink(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);
   
        END_PROFILE(SMBunlink);
        return outsize;
@@ -2000,39 +2151,42 @@ static void fail_readraw(void)
        exit_server_cleanly(errstr);
 }
 
-#if defined(WITH_SENDFILE)
 /****************************************************************************
  Fake (read/write) sendfile. Returns -1 on read or write fail.
 ****************************************************************************/
 
-static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize)
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, size_t bufsize)
 {
-       ssize_t ret=0;
+       size_t tosend = nread;
 
-       /* Paranioa check... */
-       if (nread > bufsize) {
-               fail_readraw();
-       }
+       while (tosend > 0) {
+               ssize_t ret;
+               size_t cur_read;
 
-       if (nread > 0) {
-               ret = read_file(fsp,buf,startpos,nread);
+               if (tosend > bufsize) {
+                       cur_read = bufsize;
+               } else {
+                       cur_read = tosend;
+               }
+               ret = read_file(fsp,buf,startpos,cur_read);
                if (ret == -1) {
                        return -1;
                }
-       }
 
-       /* If we had a short read, fill with zeros. */
-       if (ret < nread) {
-               memset(buf, '\0', nread - ret);
-       }
+               /* If we had a short read, fill with zeros. */
+               if (ret < cur_read) {
+                       memset(buf, '\0', cur_read - ret);
+               }
 
-       if (write_data(smbd_server_fd(),buf,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.
@@ -2089,12 +2243,12 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
                        exit_server_cleanly("send_file_readbraw sendfile failed");
                }
 
+               return;
        }
-
-  normal_readbraw:
-
 #endif
 
+normal_readbraw:
+
        if (nread > 0) {
                ret = read_file(fsp,outbuf+4,startpos,nread);
 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
@@ -2253,7 +2407,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        numtoread = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
   
-       outsize = set_message(outbuf,5,3,True);
+       outsize = set_message(inbuf,outbuf,5,3,True);
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
        data = smb_buf(outbuf) + 3;
        
@@ -2265,14 +2419,16 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
         * Note that the requested lock size is unaffected by max_recv.
         */
        
-       br_lck = do_lock(fsp,
+       br_lck = do_lock(smbd_messaging_context(),
+                       fsp,
                        (uint32)SVAL(inbuf,smb_pid), 
                        (SMB_BIG_UINT)numtoread,
                        (SMB_BIG_UINT)startpos,
                        WRITE_LOCK,
                        WINDOWS_LOCK,
                        False, /* Non-blocking lock. */
-                       &status);
+                       &status,
+                       NULL);
        TALLOC_FREE(br_lck);
 
        if (NT_STATUS_V(status)) {
@@ -2334,7 +2490,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
        numtoread = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
 
-       outsize = set_message(outbuf,5,3,True);
+       outsize = set_message(inbuf,outbuf,5,3,True);
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
        /*
         * The requested read size cannot be greater than max_recv. JRA.
@@ -2374,6 +2530,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
        return(outsize);
 }
 
+/****************************************************************************
+ Setup readX header.
+****************************************************************************/
+
+static int setup_readX_header(char *inbuf, char *outbuf, size_t smb_maxcnt)
+{
+       int outsize;
+       char *data = smb_buf(outbuf);
+
+       SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
+       SSVAL(outbuf,smb_vwv5,smb_maxcnt);
+       SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
+       SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
+       SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
+       SCVAL(outbuf,smb_vwv0,0xFF);
+       outsize = set_message(inbuf, outbuf,12,smb_maxcnt,False);
+       /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
+       _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
+       return outsize;
+}
+
 /****************************************************************************
  Reply to a read and X - possibly using sendfile.
 ****************************************************************************/
@@ -2381,10 +2558,27 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
 int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
                files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
 {
+       SMB_STRUCT_STAT sbuf;
        int outsize = 0;
        ssize_t nread = -1;
        char *data = smb_buf(outbuf);
 
+       if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) {
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       if (startpos > sbuf.st_size) {
+               smb_maxcnt = 0;
+       }
+
+       if (smb_maxcnt > (sbuf.st_size - startpos)) {
+               smb_maxcnt = (sbuf.st_size - startpos);
+       }
+
+       if (smb_maxcnt == 0) {
+               goto normal_read;
+       }
+
 #if defined(WITH_SENDFILE)
        /*
         * We can only use sendfile on a non-chained packet 
@@ -2394,34 +2588,16 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
 
        if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) &&
            lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
-               SMB_STRUCT_STAT sbuf;
                DATA_BLOB header;
 
-               if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1)
-                       return(UNIXERROR(ERRDOS,ERRnoaccess));
-
-               if (startpos > sbuf.st_size)
-                       goto normal_read;
-
-               if (smb_maxcnt > (sbuf.st_size - startpos))
-                       smb_maxcnt = (sbuf.st_size - startpos);
-
-               if (smb_maxcnt == 0)
-                       goto normal_read;
-
                /* 
                 * Set up the packet header before send. We
                 * assume here the sendfile will work (get the
                 * correct amount of data).
                 */
 
-               SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
-               SSVAL(outbuf,smb_vwv5,smb_maxcnt);
-               SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
-               SSVAL(outbuf,smb_vwv7,((smb_maxcnt >> 16) & 1));
-               SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
-               SCVAL(outbuf,smb_vwv0,0xFF);
-               set_message(outbuf,12,smb_maxcnt,False);
+               setup_readX_header(inbuf,outbuf,smb_maxcnt);
+               set_message(inbuf,outbuf,12,smb_maxcnt,False);
                header.data = (uint8 *)outbuf;
                header.length = data - outbuf;
                header.free = NULL;
@@ -2466,28 +2642,40 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                return -1;
        }
 
-  normal_read:
-
 #endif
 
-       nread = read_file(fsp,data,startpos,smb_maxcnt);
-  
-       if (nread < 0) {
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
-       }
+normal_read:
 
-       outsize = set_message(outbuf,12,nread,False);
-       SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
-       SSVAL(outbuf,smb_vwv5,nread);
-       SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
-       SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
-       SSVAL(smb_buf(outbuf),-2,nread);
-  
-       DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
-               fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+       if ((smb_maxcnt & 0xFF0000) > 0x10000) {
+               int sendlen = setup_readX_header(inbuf,outbuf,smb_maxcnt) - smb_maxcnt;
+               /* Send out the header. */
+               if (write_data(smbd_server_fd(),outbuf,sendlen) != sendlen) {
+                       DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
+                               fsp->fsp_name, strerror(errno) ));
+                       exit_server_cleanly("send_file_readX sendfile failed");
+               }
+               if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
+                                       len_outbuf - (data-outbuf))) == -1) {
+                       DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+                               fsp->fsp_name, strerror(errno) ));
+                       exit_server_cleanly("send_file_readX: fake_sendfile failed");
+               }
+               return -1;
+       } else {
+               nread = read_file(fsp,data,startpos,smb_maxcnt);
 
-       /* Returning the number of bytes we want to send back - including header. */
-       return outsize;
+               if (nread < 0) {
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+
+               outsize = setup_readX_header(inbuf, outbuf,nread);
+
+               DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
+                       fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+
+               /* Returning the number of bytes we want to send back - including header. */
+               return outsize;
+       }
 }
 
 /****************************************************************************
@@ -2500,6 +2688,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
        ssize_t nread = -1;
        size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
+       BOOL big_readX = False;
 #if 0
        size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
 #endif
@@ -2517,17 +2706,25 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return(ERROR_DOS(ERRDOS,ERRbadaccess));
        }
 
-       set_message(outbuf,12,0,True);
+       set_message(inbuf,outbuf,12,0,True);
 
        if (global_client_caps & CAP_LARGE_READX) {
-               if (SVAL(inbuf,smb_vwv7) == 1) {
-                       smb_maxcnt |= (1<<16);
-               }
-               if (smb_maxcnt > BUFFER_SIZE) {
-                       DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n",
-                               (unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE));
-                       END_PROFILE(SMBreadX);
-                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               size_t upper_size = SVAL(inbuf,smb_vwv7);
+               smb_maxcnt |= (upper_size<<16);
+               if (upper_size > 1) {
+                       /* Can't do this on a chained packet. */
+                       if ((CVAL(inbuf,smb_vwv0) != 0xFF)) {
+                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                       }
+                       /* We currently don't do this on signed or sealed data. */
+                       if (srv_is_signing_active() || srv_encryption_on()) {
+                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                       }
+                       /* Is there room in the reply for this data ? */
+                       if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2)))  {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       big_readX = True;
                }
        }
 
@@ -2560,14 +2757,16 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                return ERROR_DOS(ERRDOS,ERRlock);
        }
 
-       if (schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
+       if (!big_readX && schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
                END_PROFILE(SMBreadX);
                return -1;
        }
 
        nread = send_file_readX(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt);
-       if (nread != -1)
+       /* Only call chain_reply if not an error. */
+       if (nread != -1 && SVAL(outbuf,smb_rcls) == 0) {
                nread = chain_reply(inbuf,outbuf,length,bufsize);
+       }
 
        END_PROFILE(SMBreadX);
        return nread;
@@ -2639,7 +2838,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        /* Return a message to the redirector to tell it to send more bytes */
        SCVAL(outbuf,smb_com,SMBwritebraw);
        SSVALS(outbuf,smb_vwv0,-1);
-       outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+       outsize = set_message(inbuf,outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
        show_msg(outbuf);
        if (!send_smb(smbd_server_fd(),outbuf))
                exit_server_cleanly("reply_writebraw: send_smb failed.");
@@ -2653,7 +2852,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        numtowrite = smb_len(inbuf);
 
        /* Set up outbuf to return the correct return */
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SCVAL(outbuf,smb_com,SMBwritec);
 
        if (numtowrite != 0) {
@@ -2765,7 +2964,8 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
        }
 
        if (numtowrite) {
-               status = do_unlock(fsp,
+               status = do_unlock(smbd_messaging_context(),
+                               fsp,
                                (uint32)SVAL(inbuf,smb_pid),
                                (SMB_BIG_UINT)numtowrite, 
                                (SMB_BIG_UINT)startpos,
@@ -2777,7 +2977,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
                }
        }
        
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        
        SSVAL(outbuf,smb_vwv0,nwritten);
        
@@ -2855,7 +3055,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVAL(outbuf,smb_vwv0,nwritten);
 
@@ -2898,7 +3098,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
                return(ERROR_DOS(ERRDOS,ERRbadaccess));
        }
 
-       set_message(outbuf,6,0,True);
+       set_message(inbuf,outbuf,6,0,True);
   
        /* Deal with possible LARGE_WRITEX */
        if (large_writeX) {
@@ -3045,7 +3245,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
        fsp->fh->pos = res;
   
-       outsize = set_message(outbuf,2,0,True);
+       outsize = set_message(inbuf,outbuf,2,0,True);
        SIVAL(outbuf,smb_vwv0,res);
   
        DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
@@ -3061,7 +3261,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        uint16 fnum = SVAL(inbuf,smb_vwv0);
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBflush);
@@ -3093,7 +3293,7 @@ int reply_exit(connection_struct *conn,
 
        file_close_pid(SVAL(inbuf,smb_pid),SVAL(inbuf,smb_uid));
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        DEBUG(3,("exit\n"));
 
@@ -3108,13 +3308,12 @@ int reply_exit(connection_struct *conn,
 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 int dum_buffsize)
 {
+       NTSTATUS status = NT_STATUS_OK;
        int outsize = 0;
-       time_t mtime;
-       int32 eclass = 0, err = 0;
        files_struct *fsp = NULL;
        START_PROFILE(SMBclose);
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        /* If it's an IPC, pass off to the pipe handler. */
        if (IS_IPC(conn)) {
@@ -3138,12 +3337,11 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Special case - close NT SMB directory handle.
                 */
                DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
-               close_file(fsp,NORMAL_CLOSE);
+               status = close_file(fsp,NORMAL_CLOSE);
        } else {
                /*
                 * Close ordinary file.
                 */
-               int close_err;
 
                DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
                         fsp->fh->fd, fsp->fnum,
@@ -3153,8 +3351,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Take care of any time sent in the close.
                 */
 
-               mtime = srv_make_unix_date3(inbuf+smb_vwv1);
-               fsp_set_pending_modtime(fsp, mtime);
+               fsp_set_pending_modtime(fsp,
+                               convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv1)));
 
                /*
                 * close_file() returns the unix errno if an error
@@ -3162,17 +3360,12 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * a disk full error. If not then it was probably an I/O error.
                 */
  
-               if((close_err = close_file(fsp,NORMAL_CLOSE)) != 0) {
-                       errno = close_err;
-                       END_PROFILE(SMBclose);
-                       return (UNIXERROR(ERRHRD,ERRgeneral));
-               }
+               status = close_file(fsp,NORMAL_CLOSE);
        }  
 
-       /* We have a cached error */
-       if(eclass || err) {
+       if(!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBclose);
-               return ERROR_DOS(eclass,err);
+               return ERROR_NT(status);
        }
 
        END_PROFILE(SMBclose);
@@ -3189,10 +3382,10 @@ int reply_writeclose(connection_struct *conn,
        size_t numtowrite;
        ssize_t nwritten = -1;
        int outsize = 0;
-       int close_err = 0;
+       NTSTATUS close_status = NT_STATUS_OK;
        SMB_OFF_T startpos;
        char *data;
-       time_t mtime;
+       struct timespec mtime;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBwriteclose);
 
@@ -3203,7 +3396,7 @@ int reply_writeclose(connection_struct *conn,
 
        numtowrite = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
-       mtime = srv_make_unix_date3(inbuf+smb_vwv4);
+       mtime = convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv4));
        data = smb_buf(inbuf) + 1;
   
        if (numtowrite && is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
@@ -3213,7 +3406,7 @@ int reply_writeclose(connection_struct *conn,
   
        nwritten = write_file(fsp,data,startpos,numtowrite);
 
-       set_filetime(conn, fsp->fsp_name,mtime);
+       set_filetime(conn, fsp->fsp_name, mtime);
   
        /*
         * More insanity. W2K only closes the file if writelen > 0.
@@ -3223,7 +3416,7 @@ int reply_writeclose(connection_struct *conn,
        if (numtowrite) {
                DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
                        fsp->fsp_name ));
-               close_err = close_file(fsp,NORMAL_CLOSE);
+               close_status = close_file(fsp,NORMAL_CLOSE);
        }
 
        DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
@@ -3235,13 +3428,12 @@ int reply_writeclose(connection_struct *conn,
                return(UNIXERROR(ERRHRD,ERRdiskfull));
        }
  
-       if(close_err != 0) {
-               errno = close_err;
+       if(!NT_STATUS_IS_OK(close_status)) {
                END_PROFILE(SMBwriteclose);
-               return(UNIXERROR(ERRHRD,ERRgeneral));
+               return ERROR_NT(close_status);
        }
  
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVAL(outbuf,smb_vwv0,nwritten);
        END_PROFILE(SMBwriteclose);
@@ -3258,7 +3450,7 @@ int reply_writeclose(connection_struct *conn,
 int reply_lock(connection_struct *conn,
               char *inbuf,char *outbuf, int length, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        SMB_BIG_UINT count,offset;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -3276,14 +3468,16 @@ int reply_lock(connection_struct *conn,
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
                 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
 
-       br_lck = do_lock(fsp,
+       br_lck = do_lock(smbd_messaging_context(),
+                       fsp,
                        (uint32)SVAL(inbuf,smb_pid),
                        count,
                        offset,
                        WRITE_LOCK,
                        WINDOWS_LOCK,
                        False, /* Non-blocking lock. */
-                       &status);
+                       &status,
+                       NULL);
 
        TALLOC_FREE(br_lck);
 
@@ -3303,7 +3497,7 @@ int reply_lock(connection_struct *conn,
 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, 
                 int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        SMB_BIG_UINT count,offset;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -3314,7 +3508,8 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
        count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
        offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
        
-       status = do_unlock(fsp,
+       status = do_unlock(smbd_messaging_context(),
+                       fsp,
                        (uint32)SVAL(inbuf,smb_pid),
                        count,
                        offset,
@@ -3343,7 +3538,7 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
 int reply_tdis(connection_struct *conn, 
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        uint16 vuid;
        START_PROFILE(SMBtdis);
 
@@ -3374,7 +3569,7 @@ int reply_echo(connection_struct *conn,
        int smb_reverb = SVAL(inbuf,smb_vwv0);
        int seq_num;
        unsigned int data_len = smb_buflen(inbuf);
-       int outsize = set_message(outbuf,1,data_len,True);
+       int outsize = set_message(inbuf,outbuf,1,data_len,True);
        START_PROFILE(SMBecho);
 
        if (data_len > BUFFER_SIZE) {
@@ -3395,7 +3590,7 @@ int reply_echo(connection_struct *conn,
        for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
                SSVAL(outbuf,smb_vwv0,seq_num);
 
-               smb_setlen(outbuf,outsize - 4);
+               smb_setlen(inbuf,outbuf,outsize - 4);
 
                show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
@@ -3436,7 +3631,7 @@ int reply_printopen(connection_struct *conn,
                return(ERROR_NT(status));
        }
 
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
   
        DEBUG(3,("openprint fd=%d fnum=%d\n",
@@ -3453,9 +3648,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);
@@ -3468,12 +3663,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);
@@ -3487,7 +3681,7 @@ int reply_printclose(connection_struct *conn,
 int reply_printqueue(connection_struct *conn,
                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       int outsize = set_message(outbuf,2,3,True);
+       int outsize = set_message(inbuf,outbuf,2,3,True);
        int max_count = SVAL(inbuf,smb_vwv0);
        int start_index = SVAL(inbuf,smb_vwv1);
        START_PROFILE(SMBsplretq);
@@ -3535,7 +3729,7 @@ int reply_printqueue(connection_struct *conn,
                }
 
                if (count > 0) {
-                       outsize = set_message(outbuf,2,28*count+3,False); 
+                       outsize = set_message(inbuf,outbuf,2,28*count+3,False); 
                        SSVAL(outbuf,smb_vwv0,count);
                        SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
                        SCVAL(smb_buf(outbuf),0,1);
@@ -3558,7 +3752,7 @@ int reply_printqueue(connection_struct *conn,
 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
        int numtowrite;
-       int outsize = set_message(outbuf,0,0,False);
+       int outsize = set_message(inbuf,outbuf,0,0,False);
        char *data;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
 
@@ -3607,7 +3801,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)) {
@@ -3615,6 +3816,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)));
@@ -3636,7 +3843,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 ) );
 
@@ -3707,16 +3914,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) {
-               notify_fname(conn, directory, FILE_NOTIFY_CHANGE_DIR_NAME,
-                            NOTIFY_ACTION_REMOVED);
-               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))) {
@@ -3790,13 +4014,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);
        }
 
-       notify_fname(conn, directory, FILE_NOTIFY_CHANGE_DIR_NAME,
-                    NOTIFY_ACTION_REMOVED);
+       notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                    FILE_NOTIFY_CHANGE_DIR_NAME,
+                    directory);
 
-       return True;
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -3817,7 +4042,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)) {
@@ -3832,12 +4064,13 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        }
 
        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 ) );
   
@@ -3860,7 +4093,6 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
        char *p,*p2, *pname1, *pname2;
        int available_space, actual_space;
        
-
        pname1 = strrchr_m(name1,'/');
        pname2 = strrchr_m(name2,'/');
 
@@ -3937,12 +4169,12 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
 ****************************************************************************/
 
 static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck,
-                               SMB_DEV_T dev, SMB_INO_T inode, const char *newname)
+                             struct file_id id, const char *newname)
 {
        files_struct *fsp;
        BOOL did_rename = False;
 
-       for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
+       for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
                /* fsp_name is a relative path under the fsp. To change this for other
                   sharepaths we need to manipulate relative paths. */
                /* TODO - create the absolute path and manipulate the newname
@@ -3950,20 +4182,21 @@ static void rename_open_files(connection_struct *conn, struct share_mode_lock *l
                if (fsp->conn != conn) {
                        continue;
                }
-               DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n",
-                       fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode,
+               DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n",
+                         fsp->fnum, file_id_static_string(&fsp->file_id),
                        fsp->fsp_name, newname ));
                string_set(&fsp->fsp_name, newname);
                did_rename = True;
        }
 
        if (!did_rename) {
-               DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n",
-                       (unsigned int)dev, (double)inode, newname ));
+               DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
+                         file_id_static_string(&id), newname ));
        }
 
        /* Send messages to all smbd's (not ourself) that the name has changed. */
-       rename_share_filename(lck, conn->connectpath, newname);
+       rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
+                             newname);
 }
 
 /****************************************************************************
@@ -3999,7 +4232,7 @@ static BOOL rename_path_prefix_equal(const char *src, const char *dest)
  Rename an open file - given an fsp.
 ****************************************************************************/
 
-NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, uint32 attrs, BOOL replace_if_exists)
+NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstring newname, uint32 attrs, BOOL replace_if_exists)
 {
        SMB_STRUCT_STAT sbuf;
        pstring newname_last_component;
@@ -4010,10 +4243,18 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
        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;
@@ -4073,10 +4314,21 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       status = can_rename(conn,newname,attrs,&sbuf);
+       /* Ensure we have a valid stat struct for the source. */
+       if (fsp->fh->fd != -1) {
+               if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       } else {
+               if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       }
 
-       if (dest_exists && !NT_STATUS_IS_OK(status)) {
-               DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+       status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
                        nt_errstr(status), fsp->fsp_name,newname));
                if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
                        status = NT_STATUS_ACCESS_DENIED;
@@ -4087,12 +4339,36 @@ 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);
 
        if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
+               uint32 create_options = fsp->fh->private_options;
+
                DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
                        fsp->fsp_name,newname));
-               rename_open_files(conn, lck, fsp->dev, fsp->inode, newname);
+
+               rename_open_files(conn, lck, fsp->file_id, newname);
+
+               /*
+                * A rename acts as a new file create w.r.t. allowing an initial delete
+                * on close, probably because in Windows there is a new handle to the
+                * new file. If initial delete on close was requested but not
+                * originally set, we need to set it here. This is probably not 100% correct,
+                * but will work for the CIFSFS client which in non-posix mode
+                * depends on these semantics. JRA.
+                */
+
+               set_allow_initial_delete_on_close(lck, fsp, True);
+
+               if (create_options & FILE_DELETE_ON_CLOSE) {
+                       status = can_set_delete_on_close(fsp, True, 0);
+
+                       if (NT_STATUS_IS_OK(status)) {
+                               /* Note that here we set the *inital* delete on close flag,
+                                * not the regular one. The magic gets handled in close. */
+                               fsp->initial_delete_on_close = True;
+                       }
+               }
                TALLOC_FREE(lck);
                return NT_STATUS_OK;    
        }
@@ -4111,12 +4387,60 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
        return status;
 }
 
+/*
+ * Do the notify calls from a rename
+ */
+
+static void notify_rename(connection_struct *conn, BOOL is_dir,
+                         const char *oldpath, const char *newpath)
+{
+       char *olddir, *newdir;
+       const char *oldname, *newname;
+       uint32 mask;
+
+       mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
+               : FILE_NOTIFY_CHANGE_FILE_NAME;
+
+       if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
+           || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
+               TALLOC_FREE(olddir);
+               return;
+       }
+
+       if (strcmp(olddir, newdir) == 0) {
+               notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
+               notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
+       }
+       else {
+               notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
+               notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
+       }
+       TALLOC_FREE(olddir);
+       TALLOC_FREE(newdir);
+
+       /* this is a strange one. w2k3 gives an additional event for
+          CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
+          files, but not directories */
+       if (!is_dir) {
+               notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES
+                            |FILE_NOTIFY_CHANGE_CREATION,
+                            newpath);
+       }
+}
+
 /****************************************************************************
  The guts of the rename command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
 
-NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, 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;
@@ -4127,18 +4451,23 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
        NTSTATUS status = NT_STATUS_OK;
        SMB_STRUCT_STAT sbuf1, sbuf2;
        struct share_mode_lock *lck = NULL;
+       struct smb_Dir *dir_hnd = NULL;
+       const char *dname;
+       long offset = 0;
+       pstring destname;
+       struct file_id id;
 
        *directory = *mask = 0;
 
        ZERO_STRUCT(sbuf1);
        ZERO_STRUCT(sbuf2);
 
-       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;
        }
@@ -4172,10 +4501,11 @@ 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 (!has_wild) {
+       if (!src_has_wild) {
                /*
                 * No wildcards - just process the one file.
                 */
@@ -4194,11 +4524,29 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
                        pstrcpy(newname, tmpstr);
                }
                
-               DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
-directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", 
-                        conn->case_sensitive, conn->case_preserve, conn->short_case_preserve, directory, 
-                        newname, last_component_dest, is_short_name));
+               DEBUG(3, ("rename_internals: case_sensitive = %d, "
+                         "case_preserve = %d, short case preserve = %d, "
+                         "directory = %s, newname = %s, "
+                         "last_component_dest = %s, is_8_3 = %d\n", 
+                         conn->case_sensitive, conn->case_preserve,
+                         conn->short_case_preserve, directory, 
+                         newname, last_component_dest, is_short_name));
+
+               /* Ensure the source name is valid for us to access. */
+               status = check_name(conn, directory);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
+               /* The dest name still may have wildcards. */
+               if (dest_has_wild) {
+                       if (!resolve_wildcards(directory,newname)) {
+                               DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n", 
+                                         directory,newname));
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
+                               
                /*
                 * Check for special case with case preserving and not
                 * case sensitive, if directory and newname are identical,
@@ -4233,42 +4581,22 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        }
                }
        
-               resolve_wildcards(directory,newname);
-       
-               /*
-                * The source object must exist.
-                */
-
-               if (!vfs_object_exist(conn, directory, &sbuf1)) {
-                       DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
-                               directory,newname));
-
-                       if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
-                               /*
-                                * Must return different errors depending on whether the parent
-                                * directory existed or not.
-                                */
-
-                               p = strrchr_m(directory, '/');
-                               if (!p)
-                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                               *p = '\0';
-                               if (vfs_object_exist(conn, directory, NULL))
-                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                       }
-                       status = map_nt_error_from_unix(errno);
-                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
-                               nt_errstr(status), directory,newname));
-
+               /* Ensure the dest name is valid for us to access. */
+               status = check_name(conn, newname);
+               if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
 
-               status = can_rename(conn,directory,attrs,&sbuf1);
+               /*
+                * The source object must exist, and it may not have a
+                * conflicting share mode.
+                */
+               status = can_rename(conn,directory,attrs,&sbuf1,False);
 
                if (!NT_STATUS_IS_OK(status)) {
-                       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;
                }
 
@@ -4277,15 +4605,18 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                 * don't do the rename, just return success.
                 */
 
+               id = file_id_sbuf(&sbuf1);
+
                if (strcsequal(directory, newname)) {
-                       rename_open_files(conn, NULL, sbuf1.st_dev, sbuf1.st_ino, newname);
-                       DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
+                       DEBUG(3, ("rename_internals: identical names in "
+                                 "rename %s - returning success\n",
+                                 directory));
                        return NT_STATUS_OK;
                }
 
                if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
-                       DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
-                               directory,newname));
+                       DEBUG(3,("rename_internals: dest exists doing "
+                                "rename %s -> %s\n", directory, newname));
                        return NT_STATUS_OBJECT_NAME_COLLISION;
                }
 
@@ -4293,13 +4624,15 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
-               lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL);
+               lck = get_share_mode_lock(NULL, id, NULL, NULL);
 
                if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
-                       DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
-                               directory,newname));
-                       rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname);
+                       DEBUG(3,("rename_internals: succeeded doing rename "
+                                "on %s -> %s\n", directory, newname));
+                       rename_open_files(conn, lck, id, newname);
                        TALLOC_FREE(lck);
+                       notify_rename(conn, S_ISDIR(sbuf1.st_mode),
+                                     directory, newname);
                        return NT_STATUS_OK;    
                }
 
@@ -4314,122 +4647,132 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        nt_errstr(status), directory,newname));
 
                return status;
-       } else {
-               /*
-                * Wildcards - process each file that matches.
-                */
-               struct smb_Dir *dir_hnd = NULL;
-               const char *dname;
-               long offset = 0;
-               pstring destname;
-               
-               if (strequal(mask,"????????.???"))
-                       pstrcpy(mask,"*");
+       }
+
+       /*
+        * Wildcards - process each file that matches.
+        */
+       if (strequal(mask,"????????.???")) {
+               pstrcpy(mask,"*");
+       }
                        
-               status = check_name(conn, directory);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+       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);
-               }
+       dir_hnd = OpenDir(conn, directory, mask, attrs);
+       if (dir_hnd == NULL) {
+               return map_nt_error_from_unix(errno);
+       }
                
-               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))) {
+               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);
+               status = NT_STATUS_ACCESS_DENIED;
+               slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname);
+
+               /* Ensure the source name is valid for us to access. */
+               status = check_name(conn, fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+
+               /*
+                * can_rename does an open_file_ntcreate which needs a valid
+                * stat in case the file exists
+                */
+
+               ZERO_STRUCT(sbuf1);
+               SMB_VFS_STAT(conn, fname, &sbuf1);
+
+               status = can_rename(conn,fname,attrs,&sbuf1,False);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(6, ("rename %s refused: %s\n", fname,
+                                 nt_errstr(status)));
+                       continue;
+               }
+               pstrcpy(destname,newname);
                        
-                       if (!resolve_wildcards(fname,destname)) {
-                               DEBUG(6,("resolve_wildcards %s %s failed\n", 
-                                                fname, destname));
-                               continue;
-                       }
+               if (!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;
-                       }
+               /* Ensure the dest name is valid for us to access. */
+               status = check_name(conn, destname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
-                       if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) {
-                               DEBUG(6,("file_exist %s\n", destname));
-                               status = NT_STATUS_OBJECT_NAME_COLLISION;
-                               continue;
-                       }
-                               
-                       if (rename_path_prefix_equal(fname, destname)) {
-                               return NT_STATUS_SHARING_VIOLATION;
-                       }
+               id = file_id_sbuf(&sbuf1);
 
-                       lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, NULL, NULL);
+               if (strcsequal(fname,destname)) {
+                       DEBUG(3,("rename_internals: identical names "
+                                "in wildcard rename %s - success\n",
+                                fname));
+                       count++;
+                       status = NT_STATUS_OK;
+                       continue;
+               }
 
-                       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));
+               if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) {
+                       DEBUG(6,("file_exist %s\n", destname));
+                       status = NT_STATUS_OBJECT_NAME_COLLISION;
+                       continue;
+               }
+                               
+               if (rename_path_prefix_equal(fname, destname)) {
+                       return NT_STATUS_SHARING_VIOLATION;
                }
-               CloseDir(dir_hnd);
-       }
 
-#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;
-                       }
+               lck = get_share_mode_lock(NULL, id, NULL, NULL);
+
+               if (!SMB_VFS_RENAME(conn,fname,destname)) {
+                       rename_open_files(conn, lck, id, newname);
+                       count++;
+                       status = NT_STATUS_OK;
                }
-#endif
+               TALLOC_FREE(lck);
+               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);
@@ -4451,30 +4794,45 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        char *p;
        uint32 attrs = SVAL(inbuf,smb_vwv0);
        NTSTATUS status;
-       BOOL 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))) {
@@ -4484,7 +4842,7 @@ int reply_mv(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);
   
        END_PROFILE(SMBmv);
        return(outsize);
@@ -4498,8 +4856,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;
@@ -4508,7 +4870,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) {
@@ -4585,7 +4946,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
@@ -4593,10 +4954,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) {
@@ -4620,14 +4981,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        int count=0;
        int error = ERRnoaccess;
        int err = 0;
-       BOOL has_wild;
-       BOOL exists=False;
        int tid2 = SVAL(inbuf,smb_vwv0);
        int ofun = SVAL(inbuf,smb_vwv1);
        int flags = SVAL(inbuf,smb_vwv2);
        BOOL target_is_directory=False;
-       BOOL 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);
@@ -4635,12 +4994,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        *directory = *mask = 0;
 
        p = smb_buf(inbuf);
-       p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard1);
+       p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &source_has_wild);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcopy);
                return ERROR_NT(status);
        }
-       p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path_contains_wcard2);
+       p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wild);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBcopy);
                return ERROR_NT(status);
@@ -4655,16 +5014,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);
@@ -4708,25 +5082,38 @@ 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;
@@ -4765,13 +5152,27 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                        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))) {
+                       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));
+
+                       status = copy_file(conn,fname,destname,ofun,
+                                       count,target_is_directory);
+                       if (NT_STATUS_IS_OK(status)) {
                                count++;
                        }
-                       DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
                }
                CloseDir(dir_hnd);
        }
@@ -4788,7 +5189,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);
@@ -4820,7 +5221,14 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
   
-       RESOLVE_DFSPATH(newdir, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(pathworks_setdir);
+               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)) {
@@ -4830,7 +5238,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                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));
@@ -5107,7 +5515,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                          "pid %u, file %s\n", (double)offset, (double)count,
                          (unsigned int)lock_pid, fsp->fsp_name ));
                
-               status = do_unlock(fsp,
+               status = do_unlock(smbd_messaging_context(),
+                               fsp,
                                lock_pid,
                                count,
                                offset,
@@ -5179,15 +5588,18 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                        BOOL blocking_lock = lock_timeout ? True : False;
                        BOOL defer_lock = False;
                        struct byte_range_lock *br_lck;
+                       uint32 block_smbpid;
 
-                       br_lck = do_lock(fsp,
+                       br_lck = do_lock(smbd_messaging_context(),
+                                       fsp,
                                        lock_pid,
                                        count,
                                        offset, 
                                        lock_type,
                                        WINDOWS_LOCK,
                                        blocking_lock,
-                                       &status);
+                                       &status,
+                                       &block_smbpid);
 
                        if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
                                /* Windows internal resolution for blocking locks seems
@@ -5224,7 +5636,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                                        lock_type,
                                                        WINDOWS_LOCK,
                                                        offset,
-                                                       count)) {
+                                                       count,
+                                                       block_smbpid)) {
                                        TALLOC_FREE(br_lck);
                                        END_PROFILE(SMBlockingX);
                                        return -1;
@@ -5266,7 +5679,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                return ERROR_DOS(ERRDOS,ERRnoaccess);
                        }
                        
-                       do_unlock(fsp,
+                       do_unlock(smbd_messaging_context(),
+                               fsp,
                                lock_pid,
                                count,
                                offset,
@@ -5276,7 +5690,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                return ERROR_NT(status);
        }
 
-       set_message(outbuf,2,0,True);
+       set_message(inbuf,outbuf,2,0,True);
        
        DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
                  fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
@@ -5312,7 +5726,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
                return ERROR_DOS(ERRSRV,ERRuseSTD);
        }
 
-       outsize = set_message(outbuf,8,0,True);
+       outsize = set_message(inbuf,outbuf,8,0,True);
 
        CHECK_FSP(fsp,conn);
        if (!CHECK_READ(fsp,inbuf)) {
@@ -5348,7 +5762,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
                if (nread < (ssize_t)N)
                        tcount = total_read + nread;
 
-               set_message(outbuf,8,nread+pad,False);
+               set_message(inbuf,outbuf,8,nread+pad,False);
                SIVAL(outbuf,smb_vwv0,startpos);
                SSVAL(outbuf,smb_vwv2,tcount);
                SSVAL(outbuf,smb_vwv6,nread);
@@ -5372,12 +5786,12 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
 
 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-       struct utimbuf unix_times;
+       struct timespec ts[2];
        int outsize = 0;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBsetattrE);
 
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
 
        if(!fsp || (fsp->conn != conn)) {
                END_PROFILE(SMBsetattrE);
@@ -5389,15 +5803,15 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
         * time as UNIX can't set this.
         */
 
-       unix_times.actime = srv_make_unix_date2(inbuf+smb_vwv3);
-       unix_times.modtime = srv_make_unix_date2(inbuf+smb_vwv5);
+       ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv3)); /* atime. */
+       ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv5)); /* mtime. */
   
        /* 
         * Patch from Ray Frush <frush@engr.colostate.edu>
         * Sometimes times are sent as zero - ignore them.
         */
 
-       if (null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+       if (null_timespec(ts[0]) && null_timespec(ts[1])) {
                /* Ignore request */
                if( DEBUGLVL( 3 ) ) {
                        dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
@@ -5405,20 +5819,22 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
                }
                END_PROFILE(SMBsetattrE);
                return(outsize);
-       } else if (!null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+       } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) {
                /* set modify time = to access time if modify time was unset */
-               unix_times.modtime = unix_times.actime;
+               ts[1] = ts[0];
        }
 
        /* Set the date on this file */
        /* Should we set pending modtime here ? JRA */
-       if(file_utime(conn, fsp->fsp_name, &unix_times)) {
+       if(file_ntimes(conn, fsp->fsp_name, ts)) {
                END_PROFILE(SMBsetattrE);
                return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
   
-       DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
-               fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
+       DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
+               fsp->fnum,
+               (unsigned int)ts[0].tv_sec,
+               (unsigned int)ts[1].tv_sec));
 
        END_PROFILE(SMBsetattrE);
        return(outsize);
@@ -5506,7 +5922,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
                SMBwritebmpx */
        SCVAL(outbuf,smb_com,SMBwriteBmpx);
   
-       outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(inbuf,outbuf,1,0,True);
   
        SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
   
@@ -5515,13 +5931,13 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        if (write_through && tcount==nwritten) {
                /* We need to send both a primary and a secondary response */
-               smb_setlen(outbuf,outsize - 4);
+               smb_setlen(inbuf,outbuf,outsize - 4);
                show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
                        exit_server_cleanly("reply_writebmpx: send_smb failed.");
 
                /* Now the secondary */
-               outsize = set_message(outbuf,1,0,True);
+               outsize = set_message(inbuf,outbuf,1,0,True);
                SCVAL(outbuf,smb_com,SMBwritec);
                SSVAL(outbuf,smb_vwv0,nwritten);
        }
@@ -5607,7 +6023,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
        wbms->wr_total_written += nwritten;
        if(wbms->wr_total_written >= tcount) {
                if (write_through) {
-                       outsize = set_message(outbuf,1,0,True);
+                       outsize = set_message(inbuf,outbuf,1,0,True);
                        SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
                        send_response = True;
                }
@@ -5637,7 +6053,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
        START_PROFILE(SMBgetattrE);
 
-       outsize = set_message(outbuf,11,0,True);
+       outsize = set_message(inbuf,outbuf,11,0,True);
 
        if(!fsp || (fsp->conn != conn)) {
                END_PROFILE(SMBgetattrE);