r6633: Added "check_path_syntax_posix()" in preparation for handling
[samba.git] / source3 / smbd / reply.c
index 22cbf45e21ca46f31d341d57c512a89118ffad2b..e1131c56ed59bc5c478b202b0878ac03bba5dd4c 100644 (file)
 extern enum protocol_types Protocol;
 extern int max_send;
 extern int max_recv;
-extern char magic_char;
 extern int global_oplock_break;
 unsigned int smb_echo_count = 0;
 extern uint32 global_client_caps;
 
+extern struct current_user current_user;
 extern BOOL global_encrypted_passwords_negotiated;
 
 /****************************************************************************
- Ensure we check the path in *exactly* the same way as W2K.
+ Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
  We're assuming here that '/' is not the second byte in any multibyte char
  set (a safe assumption). '\\' *may* be the second byte in a multibyte char
  set.
 ****************************************************************************/
 
-NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_wcard_names)
+NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
 {
        char *d = destname;
        const char *s = srcname;
@@ -118,21 +118,133 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_w
                }
 
                if (!(*s & 0x80)) {
-                       if (allow_wcard_names) {
-                               *d++ = *s++;
-                       } else {
-                               switch (*s) {
-                                       case '*':
-                                       case '?':
-                                       case '<':
-                                       case '>':
-                                       case '"':
-                                               return NT_STATUS_OBJECT_NAME_INVALID;
-                                       default:
-                                               *d++ = *s++;
+                       switch (*s) {
+                               case '*':
+                               case '?':
+                               case '<':
+                               case '>':
+                               case '"':
+                                       return NT_STATUS_OBJECT_NAME_INVALID;
+                               default:
+                                       *d++ = *s++;
+                                       break;
+                       }
+               } else {
+                       switch(next_mb_char_size(s)) {
+                               case 4:
+                                       *d++ = *s++;
+                               case 3:
+                                       *d++ = *s++;
+                               case 2:
+                                       *d++ = *s++;
+                               case 1:
+                                       *d++ = *s++;
+                                       break;
+                               default:
+                                       DEBUG(0,("check_path_syntax: character length assumptions invalid !\n"));
+                                       *d = '\0';
+                                       return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
+               if (start_of_name_component && num_bad_components) {
+                       num_bad_components++;
+               }
+               start_of_name_component = False;
+       }
+
+       if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) {
+               if (num_bad_components > 1) {
+                       ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               }
+       }
+
+       *d = '\0';
+       return ret;
+}
+
+/****************************************************************************
+ Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
+ path or anything including wildcards.
+ We're assuming here that '/' is not the second byte in any multibyte char
+ set (a safe assumption). '\\' *may* be the second byte in a multibyte char
+ set.
+****************************************************************************/
+
+NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname)
+{
+       char *d = destname;
+       const char *s = srcname;
+       NTSTATUS ret = NT_STATUS_OK;
+       BOOL start_of_name_component = True;
+       unsigned int num_bad_components = 0;
+
+       while (*s) {
+               if (IS_DIRECTORY_SEP(*s)) {
+                       /*
+                        * Safe to assume is not the second part of a mb char as this is handled below.
+                        */
+                       /* Eat multiple '/' or '\\' */
+                       while (IS_DIRECTORY_SEP(*s)) {
+                               s++;
+                       }
+                       if ((d != destname) && (*s != '\0')) {
+                               /* We only care about non-leading or trailing '/' or '\\' */
+                               *d++ = '/';
+                       }
+
+                       start_of_name_component = True;
+                       continue;
+               }
+
+               if (start_of_name_component) {
+                       if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
+                               /* Uh oh - "/../" or "\\..\\"  or "/..\0" or "\\..\0" ! */
+
+                               /*
+                                * No mb char starts with '.' so we're safe checking the directory separator here.
+                                */
+
+                               /* If  we just added a '/' - delete it */
+                               if ((d > destname) && (*(d-1) == '/')) {
+                                       *(d-1) = '\0';
+                                       d--;
+                               }
+
+                               /* Are we at the start ? Can't go back further if so. */
+                               if (d <= destname) {
+                                       ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+                                       break;
+                               }
+                               /* Go back one level... */
+                               /* We know this is safe as '/' cannot be part of a mb sequence. */
+                               /* NOTE - if this assumption is invalid we are not in good shape... */
+                               /* Decrement d first as d points to the *next* char to write into. */
+                               for (d--; d > destname; d--) {
+                                       if (*d == '/')
                                                break;
                                }
+                               s += 2; /* Else go past the .. */
+                               /* We're still at the start of a name component, just the previous one. */
+
+                               if (num_bad_components) {
+                                       /* Hmmm. Should we only decrement the bad_components if
+                                          we're removing a bad component ? Need to check this. JRA. */
+                                       num_bad_components--;
+                               }
+
+                               continue;
+
+                       } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) {
+                               /* Component of pathname can't be "." only. */
+                               ret =  NT_STATUS_OBJECT_NAME_INVALID;
+                               num_bad_components++;
+                               *d++ = *s++;
+                               continue;
                        }
+               }
+
+               if (!(*s & 0x80)) {
+                       *d++ = *s++;
                } else {
                        switch(next_mb_char_size(s)) {
                                case 4:
@@ -145,7 +257,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_w
                                        *d++ = *s++;
                                        break;
                                default:
-                                       DEBUG(0,("check_path_syntax: character length assumptions invalid !\n"));
+                                       DEBUG(0,("check_path_syntax_wcard: character length assumptions invalid !\n"));
                                        *d = '\0';
                                        return NT_STATUS_INVALID_PARAMETER;
                        }
@@ -159,15 +271,103 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname, BOOL allow_w
        if (NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_NAME_INVALID)) {
                /* For some strange reason being called from findfirst changes
                   the num_components number to cause the error return to change. JRA. */
-               if (allow_wcard_names) {
-                       if (num_bad_components > 2) {
-                               ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               if (num_bad_components > 2) {
+                       ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               }
+       }
+
+       *d = '\0';
+       return ret;
+}
+
+/****************************************************************************
+ Check the path for a POSIX client.
+ We're assuming here that '/' is not the second byte in any multibyte char
+ set (a safe assumption).
+****************************************************************************/
+
+NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+{
+       char *d = destname;
+       const char *s = srcname;
+       NTSTATUS ret = NT_STATUS_OK;
+       BOOL start_of_name_component = True;
+
+       while (*s) {
+               if (*s == '/') {
+                       /*
+                        * Safe to assume is not the second part of a mb char as this is handled below.
+                        */
+                       /* Eat multiple '/' or '\\' */
+                       while (*s == '/') {
+                               s++;
+                       }
+                       if ((d != destname) && (*s != '\0')) {
+                               /* We only care about non-leading or trailing '/' */
+                               *d++ = '/';
+                       }
+
+                       start_of_name_component = True;
+                       continue;
+               }
+
+               if (start_of_name_component) {
+                       if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
+                               /* Uh oh - "/../" or "/..\0" ! */
+
+                               /*
+                                * No mb char starts with '.' so we're safe checking the directory separator here.
+                                */
+
+                               /* If  we just added a '/' - delete it */
+                               if ((d > destname) && (*(d-1) == '/')) {
+                                       *(d-1) = '\0';
+                                       d--;
+                               }
+
+                               /* Are we at the start ? Can't go back further if so. */
+                               if (d <= destname) {
+                                       ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+                                       break;
+                               }
+                               /* Go back one level... */
+                               /* We know this is safe as '/' cannot be part of a mb sequence. */
+                               /* NOTE - if this assumption is invalid we are not in good shape... */
+                               /* Decrement d first as d points to the *next* char to write into. */
+                               for (d--; d > destname; d--) {
+                                       if (*d == '/')
+                                               break;
+                               }
+                               s += 2; /* Else go past the .. */
+                               continue;
+
+                       } else if ((s[0] == '.') && ((s[1] == '\0') || (s[1] == '/'))) {
+                               /* Eat the '.' */
+                               s++;
+                               continue;
                        }
+               }
+
+               if (!(*s & 0x80)) {
+                       *d++ = *s++;
                } else {
-                       if (num_bad_components > 1) {
-                               ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                       switch(next_mb_char_size(s)) {
+                               case 4:
+                                       *d++ = *s++;
+                               case 3:
+                                       *d++ = *s++;
+                               case 2:
+                                       *d++ = *s++;
+                               case 1:
+                                       *d++ = *s++;
+                                       break;
+                               default:
+                                       DEBUG(0,("check_path_syntax_posix: character length assumptions invalid !\n"));
+                                       *d = '\0';
+                                       return NT_STATUS_INVALID_PARAMETER;
                        }
                }
+               start_of_name_component = False;
        }
 
        *d = '\0';
@@ -192,7 +392,11 @@ 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);
        }
-       *err = check_path_syntax(dest, tmppath, allow_wcard_names);
+       if (allow_wcard_names) {
+               *err = check_path_syntax_wcard(dest, tmppath);
+       } else {
+               *err = check_path_syntax(dest, tmppath);
+       }
        return ret;
 }
 
@@ -361,7 +565,6 @@ 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;
-       extern BOOL global_encrypted_passwords_negotiated;
        
        START_PROFILE(SMBtconX);        
 
@@ -701,6 +904,8 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
 
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+  
        unix_convert(fname,conn,0,&bad_path,&sbuf);
        if (bad_path) {
                END_PROFILE(SMBsetatr);
@@ -749,7 +954,10 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
        SMB_BIG_UINT dfree,dsize,bsize;
        START_PROFILE(SMBdskattr);
 
-       SMB_VFS_DISK_FREE(conn,".",True,&bsize,&dfree,&dsize);
+       if (SMB_VFS_DISK_FREE(conn,".",True,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+               END_PROFILE(SMBdskattr);
+               return(UNIXERROR(ERRHRD,ERRgeneral));
+       }
   
        outsize = set_message(outbuf,5,0,True);
        
@@ -816,6 +1024,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        BOOL can_open = True;
        BOOL bad_path = False;
        NTSTATUS nt_status;
+       BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
+
        START_PROFILE(SMBsearch);
 
        *mask = *directory = *fname = 0;
@@ -833,6 +1043,9 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                END_PROFILE(SMBsearch);
                return ERROR_NT(nt_status);
        }
+
+       RESOLVE_DFSPATH_WCARD(path, conn, inbuf, outbuf);
+  
        p++;
        status_len = SVAL(p, 0);
        p += 2;
@@ -899,8 +1112,10 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                                END_PROFILE(SMBsearch);
                                return ERROR_DOS(ERRDOS,ERRnofids);
                        }
-                       dptr_set_wcard(dptr_num, SMB_STRDUP(mask));
-                       dptr_set_attr(dptr_num, dirtype);
+                       if (!dptr_set_wcard_and_attributes(dptr_num, mask, dirtype)) {
+                               END_PROFILE(SMBsearch);
+                               return ERROR_DOS(ERRDOS,ERRnomem);
+                       }
                } else {
                        dirtype = dptr_attr(dptr_num);
                }
@@ -910,7 +1125,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                if (ok) {
                        if ((dirtype&0x1F) == aVOLID) {   
                                memcpy(p,status,21);
-                               make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0,conn->case_sensitive);
+                               make_dir_struct(p,"???????????",volume_label(SNUM(conn)),
+                                               0,aVOLID,0,!allow_long_path_components);
                                dptr_fill(p+12,dptr_num);
                                if (dptr_zero(p+12) && (status_len==0))
                                        numentries = 1;
@@ -930,7 +1146,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                                        finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
                                        if (!finished) {
                                                memcpy(p,status,21);
-                                               make_dir_struct(p,mask,fname,size,mode,date,conn->case_sensitive);
+                                               make_dir_struct(p,mask,fname,size, mode,date,
+                                                               !allow_long_path_components);
                                                dptr_fill(p+12,dptr_num);
                                                numentries++;
                                                p += DIR_STRUCT_SIZE;
@@ -947,27 +1164,36 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                and no entries were found then return error and close dirptr 
                (X/Open spec) */
 
-       if(ok && expect_close && numentries == 0 && status_len == 0) {
-               /* Close the dptr - we know it's gone */
+       if (numentries == 0 || !ok) {
                dptr_close(&dptr_num);
-               return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
-       } else if (numentries == 0 || !ok) {
+       } else if(ok && expect_close && status_len == 0) {
+               /* Close the dptr - we know it's gone */
                dptr_close(&dptr_num);
-               return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
        }
 
        /* If we were called as SMBfunique, then we can close the dirptr now ! */
-       if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
+       if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique) {
                dptr_close(&dptr_num);
+       }
+
+       if ((numentries == 0) && !ms_has_wild(mask)) {
+               return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
+       }
 
        SSVAL(outbuf,smb_vwv0,numentries);
        SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
        SCVAL(smb_buf(outbuf),0,5);
        SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
 
-       if (Protocol >= PROTOCOL_NT1)
-               SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
-  
+       /* The replies here are never long name. */
+       SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
+       if (!allow_long_path_components) {
+               SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) & (~FLAGS2_LONG_PATH_COMPONENTS));
+       }
+
+       /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
+       SSVAL(outbuf,smb_flg2, (SVAL(outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
+         
        outsize += DIR_STRUCT_SIZE*numentries;
        smb_setlen(outbuf,outsize - 4);
   
@@ -1073,7 +1299,6 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                END_PROFILE(SMBopen);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
@@ -1136,6 +1361,9 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        BOOL bad_path = False;
        files_struct *fsp;
        NTSTATUS status;
+       SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9);
+       ssize_t retval = -1;
+
        START_PROFILE(SMBopenX);
 
        /* If it's an IPC, pass off the pipe handler. */
@@ -1163,7 +1391,17 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                END_PROFILE(SMBopenX);
                return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
        }
-    
+
+       /* Strange open mode mapping. */
+       if (smb_ofun == 0) {
+               if (GET_OPEN_MODE(smb_mode) == DOS_OPEN_EXEC) {
+                       smb_ofun = FILE_EXISTS_FAIL | FILE_CREATE_IF_NOT_EXIST;
+               } else {
+                       END_PROFILE(SMBopenX);
+                       return ERROR_FORCE_DOS(ERRDOS, ERRbadaccess);
+               }
+       }
+
        fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr,
                        oplock_request, &rmode,&smb_action);
       
@@ -1171,13 +1409,31 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                END_PROFILE(SMBopenX);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
        }
 
        size = sbuf.st_size;
+
+       /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
+          if the file is truncated or created. */
+       if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
+               fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
+               if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
+                       close_file(fsp,False);
+                       END_PROFILE(SMBntcreateX);
+                       return ERROR_NT(NT_STATUS_DISK_FULL);
+               }
+               retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
+               if (retval < 0) {
+                       close_file(fsp,False);
+                       END_PROFILE(SMBwrite);
+                       return ERROR_NT(NT_STATUS_DISK_FULL);
+               }
+               size = get_allocation_size(conn,fsp,&sbuf);
+       }
+
        fmode = dos_mode(conn,fname,&sbuf);
        mtime = sbuf.st_mtime;
        if (fmode & aDIR) {
@@ -1305,7 +1561,6 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                END_PROFILE(SMBcreate);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
@@ -1389,7 +1644,6 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                END_PROFILE(SMBctemp);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
@@ -1433,7 +1687,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(char *fname,connection_struct *conn, uint16 dirtype, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst)
 {
        int smb_action;
        int access_mode;
@@ -1451,20 +1705,19 @@ static NTSTATUS can_rename(char *fname,connection_struct *conn, uint16 dirtype,
                return NT_STATUS_OK;
 
        /* We need a better way to return NT status codes from open... */
-       unix_ERR_class = 0;
-       unix_ERR_code = 0;
+       set_saved_error_triple(0, 0, NT_STATUS_OK);
 
        fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
                (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
 
        if (!fsp) {
-               NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
-               if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
-                       ret = NT_STATUS_SHARING_VIOLATION;
-               unix_ERR_class = 0;
-               unix_ERR_code = 0;
-               unix_ERR_ntstatus = NT_STATUS_OK;
-               return ret;
+               NTSTATUS ret;
+               if (get_saved_error_triple(NULL, NULL, &ret)) {
+                       set_saved_error_triple(0, 0, NT_STATUS_OK);
+                       return ret;
+               }
+               set_saved_error_triple(0, 0, NT_STATUS_OK);
+               return NT_STATUS_ACCESS_DENIED;
        }
        close_file(fsp,False);
        return NT_STATUS_OK;
@@ -1474,7 +1727,7 @@ static NTSTATUS can_rename(char *fname,connection_struct *conn, uint16 dirtype,
  Check if a user is allowed to delete a file.
 ********************************************************************/
 
-static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOOL bad_path)
+NTSTATUS can_delete(connection_struct *conn, char *fname, int dirtype, BOOL bad_path, BOOL check_is_at_open)
 {
        SMB_STRUCT_STAT sbuf;
        int fmode;
@@ -1515,25 +1768,31 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOO
        if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
                return NT_STATUS_NO_SUCH_FILE;
 
-       /* We need a better way to return NT status codes from open... */
-       unix_ERR_class = 0;
-       unix_ERR_code = 0;
+       if (check_is_at_open) {
+               if (!can_delete_file_in_directory(conn, fname)) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+       } else {
+               /* On open checks the open itself will check the share mode, so
+                  don't do it here as we'll get it wrong. */
 
-       fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
-               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
+               /* We need a better way to return NT status codes from open... */
+               set_saved_error_triple(0, 0, NT_STATUS_OK);
 
-       if (!fsp) {
-               NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
-               if (!NT_STATUS_IS_OK(unix_ERR_ntstatus))
-                       ret = unix_ERR_ntstatus;
-               else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
-                       ret = NT_STATUS_SHARING_VIOLATION;
-               unix_ERR_class = 0;
-               unix_ERR_code = 0;
-               unix_ERR_ntstatus = NT_STATUS_OK;
-               return ret;
+               fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
+                       (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action);
+
+               if (!fsp) {
+                       NTSTATUS ret;
+                       if (get_saved_error_triple(NULL, NULL, &ret)) {
+                               set_saved_error_triple(0, 0, NT_STATUS_OK);
+                               return ret;
+                       }
+                       set_saved_error_triple(0, 0, NT_STATUS_OK);
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+               close_file(fsp,False);
        }
-       close_file(fsp,False);
        return NT_STATUS_OK;
 }
 
@@ -1587,13 +1846,13 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
        
-       if (!rc && mangle_is_mangled(mask))
-               mangle_check_cache( mask, sizeof(pstring)-1 );
+       if (!rc && mangle_is_mangled(mask,SNUM(conn)))
+               mangle_check_cache( mask, sizeof(pstring)-1, SNUM(conn));
        
        if (!has_wild) {
                pstrcat(directory,"/");
                pstrcat(directory,mask);
-               error = can_delete(directory,conn,dirtype,bad_path);
+               error = can_delete(conn,directory,dirtype,bad_path,False);
                if (!NT_STATUS_IS_OK(error))
                        return error;
 
@@ -1601,28 +1860,34 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                        count++;
                }
        } else {
-               void *dirptr = NULL;
+               struct smb_Dir *dir_hnd = NULL;
                const char *dname;
                
                if (check_name(directory,conn))
-                       dirptr = OpenDir(conn, directory, True);
+                       dir_hnd = OpenDir(conn, directory);
                
                /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
                   the pattern matches against the long name, otherwise the short name 
                   We don't implement this yet XXXX
                */
                
-               if (dirptr) {
+               if (dir_hnd) {
+                       long offset = 0;
                        error = NT_STATUS_NO_SUCH_FILE;
-                       
+
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
 
-                       while ((dname = ReadDirName(dirptr))) {
+                       while ((dname = ReadDirName(dir_hnd, &offset))) {
+                               SMB_STRUCT_STAT st;
                                pstring fname;
                                BOOL sys_direntry = False;
                                pstrcpy(fname,dname);
 
+                               if (!is_visible_file(conn, directory, dname, &st, True)) {
+                                       continue;
+                               }
+
                                /* Quick check for "." and ".." */
                                if (fname[0] == '.') {
                                        if (!fname[1] || (fname[1] == '.' && !fname[2])) {
@@ -1645,7 +1910,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                                }
 
                                slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-                               error = can_delete(fname,conn,dirtype,bad_path);
+                               error = can_delete(conn,fname,dirtype,bad_path,False);
                                if (!NT_STATUS_IS_OK(error)) {
                                        continue;
                                }
@@ -1653,7 +1918,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                                        count++;
                                DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
                        }
-                       CloseDir(dirptr);
+                       CloseDir(dir_hnd);
                }
        }
        
@@ -1685,7 +1950,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
        
-       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
        
        DEBUG(3,("reply_unlink : %s\n",name));
        
@@ -1693,7 +1958,6 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        if (!NT_STATUS_IS_OK(status)) {
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return ERROR_NT(status);
@@ -1783,6 +2047,11 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
                header.free = NULL;
 
                if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
+                       /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
+                       if (errno == ENOSYS) {
+                               goto normal_readbraw;
+                       }
+
                        /*
                         * Special hack for broken Linux with no working sendfile. If we
                         * return EINTR we sent the header but not the rest of the data.
@@ -1808,6 +2077,8 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
 
        }
 
+  normal_readbraw:
+
 #endif
 
        if (nread > 0) {
@@ -1832,7 +2103,6 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
 
 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int out_buffsize)
 {
-       extern struct current_user current_user;
        ssize_t maxcount,mincount;
        size_t nread = 0;
        SMB_OFF_T startpos;
@@ -1952,6 +2222,9 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
        return -1;
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
 /****************************************************************************
  Reply to a lockread (core+ protocol).
 ****************************************************************************/
@@ -2045,6 +2318,9 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
        return(outsize);
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
 /****************************************************************************
  Reply to a read.
 ****************************************************************************/
@@ -2157,12 +2433,18 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                header.length = data - outbuf;
                header.free = NULL;
 
-               if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
+               if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt)) == -1) {
+                       /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
+                       if (errno == ENOSYS) {
+                               goto normal_read;
+                       }
+
                        /*
                         * Special hack for broken Linux with no working sendfile. If we
                         * return EINTR we sent the header but not the rest of the data.
                         * Fake this up by doing read/write calls.
                         */
+
                        if (errno == EINTR) {
                                /* Ensure we don't do this again. */
                                set_use_sendfile(SNUM(conn), False);
@@ -2174,7 +2456,10 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                                                fsp->fsp_name, strerror(errno) ));
                                        exit_server("send_file_readX: fake_sendfile failed");
                                }
-                               return nread;
+                               DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
+                                       fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+                               /* Returning -1 here means successful sendfile. */
+                               return -1;
                        }
 
                        DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
@@ -2184,6 +2469,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
 
                DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
                        fsp->fnum, (int)smb_maxcnt, (int)nread ) );
+               /* Returning -1 here means successful sendfile. */
                return -1;
        }
 
@@ -2208,6 +2494,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
        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;
 }
 
@@ -2422,6 +2709,9 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        return(outsize);
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
 /****************************************************************************
  Reply to a writeunlock (core+).
 ****************************************************************************/
@@ -2486,6 +2776,9 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
        return outsize;
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
 /****************************************************************************
  Reply to a write.
 ****************************************************************************/
@@ -2791,7 +3084,6 @@ int reply_exit(connection_struct *conn,
 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 int dum_buffsize)
 {
-       extern struct current_user current_user;
        int outsize = 0;
        time_t mtime;
        int32 eclass = 0, err = 0;
@@ -2837,6 +3129,13 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                         fsp->fd, fsp->fnum,
                         conn->num_files_open));
  
+               /*
+                * Take care of any time sent in the close.
+                */
+
+               mtime = make_unix_date3(inbuf+smb_vwv1);
+               fsp_set_pending_modtime(fsp, mtime);
+
                /*
                 * close_file() returns the unix errno if an error
                 * was detected on close - normally this is due to
@@ -2848,16 +3147,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                        END_PROFILE(SMBclose);
                        return (UNIXERROR(ERRHRD,ERRgeneral));
                }
-
-               /*
-                * Now take care of any time sent in the close.
-                */
-
-               mtime = make_unix_date3(inbuf+smb_vwv1);
-               
-               /* try and set the date */
-               set_filetime(conn, file_name, mtime);
-
        }  
 
        /* We have a cached error */
@@ -2937,6 +3226,9 @@ int reply_writeclose(connection_struct *conn,
        return(outsize);
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
 /****************************************************************************
  Reply to a lock.
 ****************************************************************************/
@@ -3017,6 +3309,9 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
        return(outsize);
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
 /****************************************************************************
  Reply to a tdis.
 ****************************************************************************/
@@ -3268,29 +3563,32 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
  code. 
 ****************************************************************************/
 
-NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
+NTSTATUS mkdir_internal(connection_struct *conn, const pstring directory, BOOL bad_path)
 {
-       BOOL bad_path = False;
-       SMB_STRUCT_STAT sbuf;
        int ret= -1;
        
-       unix_convert(directory,conn,0,&bad_path,&sbuf);
-
-       if( strchr_m(directory, ':')) {
-               return NT_STATUS_NOT_A_DIRECTORY;
-       }
-
-       if (ms_has_wild(directory)) {
-               return NT_STATUS_OBJECT_NAME_INVALID;
+       if(!CAN_WRITE(conn)) {
+               DEBUG(5,("mkdir_internal: failing create on read-only share %s\n", lp_servicename(SNUM(conn))));
+               errno = EACCES;
+               return map_nt_error_from_unix(errno);
        }
 
        if (bad_path) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
-       if (check_name(directory, conn))
-               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
-       
+       if (!check_name(directory, conn)) {
+               if(errno == ENOENT) {
+                       if (bad_path) {
+                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                       } else {
+                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       }
+               }
+               return map_nt_error_from_unix(errno);
+       }
+
+       ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
        if (ret == -1) {
                if(errno == ENOENT) {
                        return NT_STATUS_OBJECT_NAME_NOT_FOUND;
@@ -3310,6 +3608,9 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        pstring directory;
        int outsize;
        NTSTATUS status;
+       BOOL bad_path = False;
+       SMB_STRUCT_STAT sbuf;
+
        START_PROFILE(SMBmkdir);
  
        srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False);
@@ -3320,12 +3621,38 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
        RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
 
-       status = mkdir_internal(conn, directory);
+       unix_convert(directory,conn,0,&bad_path,&sbuf);
+
+       if( is_ntfs_stream_name(directory)) {
+               DEBUG(5,("reply_mkdir: failing create on filename %s with colon in name\n", directory));
+               END_PROFILE(SMBmkdir);
+               return ERROR_FORCE_DOS(ERRDOS, ERRinvalidname);
+       }
+
+       status = mkdir_internal(conn, directory,bad_path);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBmkdir);
                return ERROR_NT(status);
        }
 
+       if (lp_inherit_owner(SNUM(conn))) {
+               /* Ensure we're checking for a symlink here.... */
+               /* We don't want to get caught by a symlink racer. */
+
+               if(SMB_VFS_LSTAT(conn,directory, &sbuf) != 0) {
+                       END_PROFILE(SMBmkdir);
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+                                                                                                                                                   
+               if(!S_ISDIR(sbuf.st_mode)) {
+                       DEBUG(0,("reply_mkdir: %s is not a directory !\n", directory ));
+                       END_PROFILE(SMBmkdir);
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+
+               change_owner_to_parent(conn, NULL, directory, &sbuf);
+       }
+
        outsize = set_message(outbuf,0,0,True);
 
        DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
@@ -3343,18 +3670,22 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
        const char *dname = NULL;
        BOOL ret = False;
-       void *dirptr = OpenDir(conn, directory, False);
+       long offset = 0;
+       struct smb_Dir *dir_hnd = OpenDir(conn, directory);
 
-       if(dirptr == NULL)
+       if(dir_hnd == NULL)
                return True;
 
-       while((dname = ReadDirName(dirptr))) {
+       while((dname = ReadDirName(dir_hnd, &offset))) {
                pstring fullname;
                SMB_STRUCT_STAT st;
 
                if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
                        continue;
 
+               if (!is_visible_file(conn, directory, dname, &st, False))
+                       continue;
+
                /* Construct the full name. */
                if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
                        errno = ENOMEM;
@@ -3385,7 +3716,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
                        break;
                }
        }
-       CloseDir(dirptr);
+       CloseDir(dir_hnd);
        return ret;
 }
 
@@ -3396,6 +3727,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 BOOL rmdir_internals(connection_struct *conn, char *directory)
 {
        BOOL ok;
+       SMB_STRUCT_STAT st;
 
        ok = (SMB_VFS_RMDIR(conn,directory) == 0);
        if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
@@ -3407,13 +3739,15 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
                 */
                BOOL all_veto_files = True;
                const char *dname;
-               void *dirptr = OpenDir(conn, directory, False);
+               struct smb_Dir *dir_hnd = OpenDir(conn, directory);
 
-               if(dirptr != NULL) {
-                       int dirpos = TellDir(dirptr);
-                       while ((dname = ReadDirName(dirptr))) {
+               if(dir_hnd != NULL) {
+                       long dirpos = TellDir(dir_hnd);
+                       while ((dname = ReadDirName(dir_hnd,&dirpos))) {
                                if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
                                        continue;
+                               if (!is_visible_file(conn, directory, dname, &st, False))
+                                       continue;
                                if(!IS_VETO_PATH(conn, dname)) {
                                        all_veto_files = False;
                                        break;
@@ -3421,13 +3755,14 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
                        }
 
                        if(all_veto_files) {
-                               SeekDir(dirptr,dirpos);
-                               while ((dname = ReadDirName(dirptr))) {
+                               SeekDir(dir_hnd,dirpos);
+                               while ((dname = ReadDirName(dir_hnd,&dirpos))) {
                                        pstring fullname;
-                                       SMB_STRUCT_STAT st;
 
                                        if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
                                                continue;
+                                       if (!is_visible_file(conn, directory, dname, &st, False))
+                                               continue;
 
                                        /* Construct the full name. */
                                        if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
@@ -3451,11 +3786,11 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
                                        } else if(SMB_VFS_UNLINK(conn,fullname) != 0)
                                                break;
                                }
-                               CloseDir(dirptr);
+                               CloseDir(dir_hnd);
                                /* Retry the rmdir */
                                ok = (SMB_VFS_RMDIR(conn,directory) == 0);
                        } else {
-                               CloseDir(dirptr);
+                               CloseDir(dir_hnd);
                        }
                } else {
                        errno = ENOTEMPTY;
@@ -3707,7 +4042,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       error = can_rename(newname,conn,attrs,&sbuf);
+       error = can_rename(conn,newname,attrs,&sbuf);
 
        if (dest_exists && !NT_STATUS_IS_OK(error)) {
                DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
@@ -3813,8 +4148,8 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!rc && mangle_is_mangled(mask))
-               mangle_check_cache( mask, sizeof(pstring)-1 );
+       if (!rc && mangle_is_mangled(mask,SNUM(conn)))
+               mangle_check_cache( mask, sizeof(pstring)-1, SNUM(conn));
 
        has_wild = ms_has_wild(mask);
 
@@ -3822,7 +4157,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui
                /*
                 * No wildcards - just process the one file.
                 */
-               BOOL is_short_name = mangle_is_8_3(name, True);
+               BOOL is_short_name = mangle_is_8_3(name, True, SNUM(conn));
 
                /* Add a terminating '/' to the directory name. */
                pstrcat(directory,"/");
@@ -3913,7 +4248,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                        return NT_STATUS_OBJECT_PATH_NOT_FOUND;
                }
 
-               error = can_rename(directory,conn,attrs,&sbuf1);
+               error = can_rename(conn,directory,attrs,&sbuf1);
 
                if (!NT_STATUS_IS_OK(error)) {
                        DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
@@ -3958,21 +4293,22 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                /*
                 * Wildcards - process each file that matches.
                 */
-               void *dirptr = NULL;
+               struct smb_Dir *dir_hnd = NULL;
                const char *dname;
                pstring destname;
                
                if (check_name(directory,conn))
-                       dirptr = OpenDir(conn, directory, True);
+                       dir_hnd = OpenDir(conn, directory);
                
-               if (dirptr) {
+               if (dir_hnd) {
+                       long offset = 0;
                        error = NT_STATUS_NO_SUCH_FILE;
 /*                     Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */
                        
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
                        
-                       while ((dname = ReadDirName(dirptr))) {
+                       while ((dname = ReadDirName(dir_hnd, &offset))) {
                                pstring fname;
                                BOOL sysdir_entry = False;
 
@@ -3989,6 +4325,9 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                                        }
                                }
 
+                               if (!is_visible_file(conn, directory, dname, &sbuf1, False))
+                                       continue;
+
                                if(!mask_match(fname, mask, conn->case_sensitive))
                                        continue;
                                
@@ -4004,7 +4343,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                                        DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error)));
                                        continue;
                                }
-                               error = can_rename(fname,conn,attrs,&sbuf1);
+                               error = can_rename(conn,fname,attrs,&sbuf1);
                                if (!NT_STATUS_IS_OK(error)) {
                                        DEBUG(6,("rename %s refused\n", fname));
                                        continue;
@@ -4039,7 +4378,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
                                }
                                DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
                        }
-                       CloseDir(dirptr);
+                       CloseDir(dir_hnd);
                }
 
                if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) {
@@ -4087,8 +4426,8 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
        
-       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf);
        
        DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
        
@@ -4097,7 +4436,6 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                END_PROFILE(SMBmv);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return ERROR_NT(status);
@@ -4183,7 +4521,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        close_file(fsp1,False);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       fsp2->pending_modtime = src_sbuf.st_mtime;
+       fsp_set_pending_modtime( fsp2, src_sbuf.st_mtime);
 
        /*
         * As we are opening fsp1 read-only we only expect
@@ -4247,8 +4585,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_DOS(ERRSRV,ERRinvdevice);
        }
 
-       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf);
 
        rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
        unix_convert(newname,conn,0,&bad_path2,&sbuf2);
@@ -4291,8 +4629,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!rc && mangle_is_mangled(mask))
-               mangle_check_cache( mask, sizeof(pstring)-1 );
+       if (!rc && mangle_is_mangled(mask, SNUM(conn)))
+               mangle_check_cache( mask, sizeof(pstring)-1, SNUM(conn));
 
        has_wild = ms_has_wild(mask);
 
@@ -4311,23 +4649,27 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                        exists = vfs_file_exist(conn,directory,NULL);
                }
        } else {
-               void *dirptr = NULL;
+               struct smb_Dir *dir_hnd = NULL;
                const char *dname;
                pstring destname;
 
                if (check_name(directory,conn))
-                       dirptr = OpenDir(conn, directory, True);
+                       dir_hnd = OpenDir(conn, directory);
 
-               if (dirptr) {
+               if (dir_hnd) {
+                       long offset = 0;
                        error = ERRbadfile;
 
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
 
-                       while ((dname = ReadDirName(dirptr))) {
+                       while ((dname = ReadDirName(dir_hnd, &offset))) {
                                pstring fname;
                                pstrcpy(fname,dname);
     
+                               if (!is_visible_file(conn, directory, dname, &sbuf1, False))
+                                       continue;
+
                                if(!mask_match(fname, mask, conn->case_sensitive))
                                        continue;
 
@@ -4340,7 +4682,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                                        count++;
                                DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
                        }
-                       CloseDir(dirptr);
+                       CloseDir(dir_hnd);
                }
        }
   
@@ -4357,8 +4699,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                        return ERROR_DOS(ERRDOS,error);
                } else {
                        if((errno == ENOENT) && (bad_path1 || bad_path2)) {
-                               unix_ERR_class = ERRDOS;
-                               unix_ERR_code = ERRbadpath;
+                               set_saved_error_triple(ERRDOS, ERRbadpath, NT_STATUS_OK);
                        }
                        END_PROFILE(SMBcopy);
                        return(UNIXERROR(ERRDOS,error));
@@ -4398,6 +4739,8 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
   
+       RESOLVE_DFSPATH(newdir, conn, inbuf, outbuf);
+
        if (strlen(newdir) == 0) {
                ok = True;
        } else {
@@ -4420,6 +4763,9 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        return(outsize);
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
+
 /****************************************************************************
  Get a lock pid, dealing with large count requests.
 ****************************************************************************/
@@ -4757,6 +5103,9 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
        return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ALL
+
 /****************************************************************************
  Reply to a SMBreadbmpx (read block multiplex) request.
 ****************************************************************************/
@@ -4863,7 +5212,7 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
         * Sometimes times are sent as zero - ignore them.
         */
 
-       if ((unix_times.actime == 0) && (unix_times.modtime == 0)) {
+       if (null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
                /* Ignore request */
                if( DEBUGLVL( 3 ) ) {
                        dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
@@ -4871,12 +5220,13 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
                }
                END_PROFILE(SMBsetattrE);
                return(outsize);
-       } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) {
-               /* set modify time = to access time if modify time was 0 */
+       } else if (!null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+               /* set modify time = to access time if modify time was unset */
                unix_times.modtime = unix_times.actime;
        }
 
        /* Set the date on this file */
+       /* Should we set pending modtime here ? JRA */
        if(file_utime(conn, fsp->fsp_name, &unix_times)) {
                END_PROFILE(SMBsetattrE);
                return ERROR_DOS(ERRDOS,ERRnoaccess);
@@ -4911,7 +5261,9 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        CHECK_FSP(fsp,conn);
        CHECK_WRITE(fsp);
-       CHECK_ERROR(fsp);
+       if (HAS_CACHED_ERROR(fsp)) {
+               return(CACHED_ERROR(fsp));
+       }
 
        tcount = SVAL(inbuf,smb_vwv1);
        startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
@@ -5054,8 +5406,12 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
                        END_PROFILE(SMBwriteBs);
                        return(ERROR_DOS(ERRHRD,ERRdiskfull));
                }
+               wbms->wr_errclass = ERRHRD;
+               wbms->wr_error = ERRdiskfull;
+               wbms->wr_status = NT_STATUS_DISK_FULL;
+               wbms->wr_discard = True;
                END_PROFILE(SMBwriteBs);
-               return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+               return -1;
        }
 
        /* Increment the total written, if this matches tcount
@@ -5116,13 +5472,14 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
        put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
+       /* Should we check pending modtime here ? JRA */
        put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
 
        if (mode & aDIR) {
                SIVAL(outbuf,smb_vwv6,0);
                SIVAL(outbuf,smb_vwv8,0);
        } else {
-               uint32 allocation_size = get_allocation_size(fsp, &sbuf);
+               uint32 allocation_size = get_allocation_size(conn,fsp, &sbuf);
                SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
                SIVAL(outbuf,smb_vwv8,allocation_size);
        }