s3/smbd: change locking behavior when "lock spin time = 0".
[abartlet/samba.git/.git] / source3 / smbd / reply.c
index de187e902bf34935318027bae6d0aebae10a214d..b1a4e31951f3a0bf2f159fe6430e6828cb74ed47 100644 (file)
@@ -27,8 +27,6 @@
 #include "includes.h"
 #include "smbd/globals.h"
 
-extern enum protocol_types Protocol;
-
 /****************************************************************************
  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
  path or anything including wildcards.
@@ -65,14 +63,11 @@ static NTSTATUS check_path_syntax_internal(char *path,
                                if (strchr_m(&s[1], ':')) {
                                        return NT_STATUS_OBJECT_NAME_INVALID;
                                }
-                               if (StrCaseCmp(s, ":$DATA") != 0) {
-                                       return NT_STATUS_INVALID_PARAMETER;
-                               }
                                break;
                        }
                }
 
-               if (!posix_path && !stream_started && *s == ':') {
+               if ((*s == ':') && !posix_path && !stream_started) {
                        if (*p_last_component_contains_wcard) {
                                return NT_STATUS_OBJECT_NAME_INVALID;
                        }
@@ -709,7 +704,7 @@ void reply_tcon_and_X(struct smb_request *req)
        }
 
        if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
-               reply_doserror(req, ERRDOS, ERRbuftoosmall);
+               reply_force_doserror(req, ERRDOS, ERRbuftoosmall);
                END_PROFILE(SMBtconX);
                return;
        }
@@ -749,7 +744,7 @@ void reply_tcon_and_X(struct smb_request *req)
                q = strchr_m(path+2,'\\');
                if (!q) {
                        data_blob_clear_free(&password);
-                       reply_doserror(req, ERRDOS, ERRnosuchshare);
+                       reply_nterror(req, NT_STATUS_BAD_NETWORK_NAME);
                        END_PROFILE(SMBtconX);
                        return;
                }
@@ -790,7 +785,7 @@ void reply_tcon_and_X(struct smb_request *req)
        else
                server_devicetype = "A:";
 
-       if (Protocol < PROTOCOL_NT1) {
+       if (get_Protocol() < PROTOCOL_NT1) {
                reply_outbuf(req, 2, 0);
                if (message_push_string(&req->outbuf, server_devicetype,
                                        STR_TERMINATE|STR_ASCII) == -1) {
@@ -869,7 +864,7 @@ void reply_unknown_new(struct smb_request *req, uint8 type)
 {
        DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
                  smb_fn_name(type), type, type));
-       reply_doserror(req, ERRSRV, ERRunknownsmb);
+       reply_force_doserror(req, ERRSRV, ERRunknownsmb);
        return;
 }
 
@@ -906,7 +901,7 @@ void reply_ioctl(struct smb_request *req)
                    replysize = 32;
                    break;
            default:
-                   reply_doserror(req, ERRSRV, ERRnosupport);
+                   reply_force_doserror(req, ERRSRV, ERRnosupport);
                    END_PROFILE(SMBioctl);
                    return;
        }
@@ -925,7 +920,7 @@ void reply_ioctl(struct smb_request *req)
                        files_struct *fsp = file_fsp(
                                req, SVAL(req->vwv+0, 0));
                        if (!fsp) {
-                               reply_doserror(req, ERRDOS, ERRbadfid);
+                               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
                                END_PROFILE(SMBioctl);
                                return;
                        }
@@ -1144,7 +1139,7 @@ void reply_getatr(struct smb_request *req)
        }
        SIVAL(req->outbuf,smb_vwv3,(uint32)size);
 
-       if (Protocol >= PROTOCOL_NT1) {
+       if (get_Protocol() >= PROTOCOL_NT1) {
                SSVAL(req->outbuf, smb_flg2,
                      SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
        }
@@ -1269,7 +1264,7 @@ void reply_dskattr(struct smb_request *req)
 
        reply_outbuf(req, 5, 0);
 
-       if (Protocol <= PROTOCOL_LANMAN2) {
+       if (get_Protocol() <= PROTOCOL_LANMAN2) {
                double total_space, free_space;
                /* we need to scale this to a number that DOS6 can handle. We
                   use floating point so we can handle large drives on systems
@@ -1657,7 +1652,7 @@ void reply_fclose(struct smb_request *req)
        p += 2;
 
        if (status_len == 0) {
-               reply_doserror(req, ERRSRV, ERRsrverror);
+               reply_force_doserror(req, ERRSRV, ERRsrverror);
                END_PROFILE(SMBfclose);
                return;
        }
@@ -1743,7 +1738,7 @@ void reply_open(struct smb_request *req)
                                         OPENX_FILE_EXISTS_OPEN, &access_mask,
                                         &share_mode, &create_disposition,
                                         &create_options)) {
-               reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
+               reply_force_doserror(req, ERRDOS, ERRbadaccess);
                goto out;
        }
 
@@ -1794,7 +1789,8 @@ void reply_open(struct smb_request *req)
                DEBUG(3,("attempt to open a directory %s\n",
                         fsp_str_dbg(fsp)));
                close_file(req, fsp, ERROR_CLOSE);
-               reply_doserror(req, ERRDOS,ERRnoaccess);
+               reply_botherror(req, NT_STATUS_ACCESS_DENIED,
+                       ERRDOS, ERRnoaccess);
                goto out;
        }
 
@@ -1880,7 +1876,7 @@ void reply_open_and_X(struct smb_request *req)
                if (lp_nt_pipe_support()) {
                        reply_open_pipe_and_X(conn, req);
                } else {
-                       reply_doserror(req, ERRSRV, ERRaccess);
+                       reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
                }
                goto out;
        }
@@ -1915,7 +1911,7 @@ void reply_open_and_X(struct smb_request *req)
                                         &access_mask, &share_mode,
                                         &create_disposition,
                                         &create_options)) {
-               reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
+               reply_force_doserror(req, ERRDOS, ERRbadaccess);
                goto out;
        }
 
@@ -1968,7 +1964,7 @@ void reply_open_and_X(struct smb_request *req)
        mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
        if (fattr & aDIR) {
                close_file(req, fsp, ERROR_CLOSE);
-               reply_doserror(req, ERRDOS, ERRnoaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                goto out;
        }
 
@@ -2339,7 +2335,7 @@ void reply_ctemp(struct smb_request *req)
 ********************************************************************/
 
 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
-                          uint16 dirtype, SMB_STRUCT_STAT *pst)
+                       uint16 dirtype)
 {
        uint32 fmode;
 
@@ -2352,7 +2348,7 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
                return NT_STATUS_NO_SUCH_FILE;
        }
 
-       if (S_ISDIR(pst->st_ex_mode)) {
+       if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
                if (fsp->posix_open) {
                        return NT_STATUS_OK;
                }
@@ -2386,6 +2382,8 @@ static NTSTATUS do_unlink(connection_struct *conn,
        files_struct *fsp;
        uint32 dirtype_orig = dirtype;
        NTSTATUS status;
+       int ret;
+       bool posix_paths = lp_posix_pathnames();
 
        DEBUG(10,("do_unlink: %s, dirtype = %d\n",
                  smb_fname_str_dbg(smb_fname),
@@ -2395,7 +2393,12 @@ static NTSTATUS do_unlink(connection_struct *conn,
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
-       if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
+       if (posix_paths) {
+               ret = SMB_VFS_LSTAT(conn, smb_fname);
+       } else {
+               ret = SMB_VFS_LSTAT(conn, smb_fname);
+       }
+       if (ret != 0) {
                return map_nt_error_from_unix(errno);
        }
 
@@ -2452,24 +2455,6 @@ static NTSTATUS do_unlink(connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_INVALID;
 #endif /* JRATEST */
 
-       /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
-
-         On a Windows share, a file with read-only dosmode can be opened with
-         DELETE_ACCESS. But on a Samba share (delete readonly = no), it
-         fails with NT_STATUS_CANNOT_DELETE error.
-
-         This semantic causes a problem that a user can not
-         rename a file with read-only dosmode on a Samba share
-         from a Windows command prompt (i.e. cmd.exe, but can rename
-         from Windows Explorer).
-       */
-
-       if (!lp_delete_readonly(SNUM(conn))) {
-               if (fattr & aRONLY) {
-                       return NT_STATUS_CANNOT_DELETE;
-               }
-       }
-
        /* On open checks the open itself will check the share mode, so
           don't do it here as we'll get it wrong. */
 
@@ -2482,7 +2467,9 @@ static NTSTATUS do_unlink(connection_struct *conn,
                 FILE_SHARE_NONE,       /* share_access */
                 FILE_OPEN,             /* create_disposition*/
                 FILE_NON_DIRECTORY_FILE, /* create_options */
-                FILE_ATTRIBUTE_NORMAL, /* file_attributes */
+                                       /* file_attributes */
+                posix_paths ? FILE_FLAG_POSIX_SEMANTICS|0777 :
+                               FILE_ATTRIBUTE_NORMAL,
                 0,                     /* oplock_request */
                 0,                     /* allocation_size */
                 NULL,                  /* sd */
@@ -2496,6 +2483,16 @@ static NTSTATUS do_unlink(connection_struct *conn,
                return status;
        }
 
+       status = can_set_delete_on_close(fsp, fattr);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("do_unlink can_set_delete_on_close for file %s - "
+                       "(%s)\n",
+                       smb_fname_str_dbg(smb_fname),
+                       nt_errstr(status)));
+               close_file(req, fsp, NORMAL_CLOSE);
+               return status;
+       }
+
        /* The set is across all open files on this dev/inode pair. */
        if (!set_delete_on_close(fsp, True, &conn->server_info->utok)) {
                close_file(req, fsp, NORMAL_CLOSE);
@@ -2580,7 +2577,8 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
        } else {
                struct smb_Dir *dir_hnd = NULL;
                long offset = 0;
-               const char *dname;
+               const char *dname = NULL;
+               char *talloced = NULL;
 
                if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
                        status = NT_STATUS_OBJECT_NAME_INVALID;
@@ -2616,24 +2614,27 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                status = NT_STATUS_NO_SUCH_FILE;
 
                while ((dname = ReadDirName(dir_hnd, &offset,
-                                           &smb_fname->st))) {
+                                           &smb_fname->st, &talloced))) {
                        TALLOC_CTX *frame = talloc_stackframe();
 
                        if (!is_visible_file(conn, fname_dir, dname,
                                             &smb_fname->st, true)) {
                                TALLOC_FREE(frame);
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
                        /* Quick check for "." and ".." */
                        if (ISDOT(dname) || ISDOTDOT(dname)) {
                                TALLOC_FREE(frame);
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
                        if(!mask_match(dname, fname_mask,
                                       conn->case_sensitive)) {
                                TALLOC_FREE(frame);
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
@@ -2646,6 +2647,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                                TALLOC_FREE(dir_hnd);
                                status = NT_STATUS_NO_MEMORY;
                                TALLOC_FREE(frame);
+                               TALLOC_FREE(talloced);
                                goto out;
                        }
 
@@ -2653,12 +2655,14 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                TALLOC_FREE(frame);
+                               TALLOC_FREE(talloced);
                                goto out;
                        }
 
                        status = do_unlink(conn, req, smb_fname, dirtype);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(frame);
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
@@ -2667,6 +2671,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                                 smb_fname->base_name));
 
                        TALLOC_FREE(frame);
+                       TALLOC_FREE(talloced);
                }
                TALLOC_FREE(dir_hnd);
        }
@@ -3016,7 +3021,6 @@ void reply_readbraw(struct smb_request *req)
        SMB_OFF_T startpos;
        files_struct *fsp;
        struct lock_struct lock;
-       SMB_STRUCT_STAT st;
        SMB_OFF_T size = 0;
 
        START_PROFILE(SMBreadbraw);
@@ -3108,7 +3112,7 @@ void reply_readbraw(struct smb_request *req)
                        reply_readbraw_error();
                        END_PROFILE(SMBreadbraw);
                        return;
-               }      
+               }
        }
 
        maxcount = (SVAL(req->vwv+3, 0) & 0xFFFF);
@@ -3127,8 +3131,8 @@ void reply_readbraw(struct smb_request *req)
                return;
        }
 
-       if (SMB_VFS_FSTAT(fsp, &st) == 0) {
-               size = st.st_ex_size;
+       if (fsp_stat(fsp) == 0) {
+               size = fsp->fsp_name->st.st_ex_size;
        }
 
        if (startpos >= size) {
@@ -3195,7 +3199,7 @@ void reply_lockread(struct smb_request *req)
        }
 
        if (!CHECK_READ(fsp,req)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBlockread);
                return;
        }
@@ -3305,7 +3309,7 @@ void reply_read(struct smb_request *req)
        }
 
        if (!CHECK_READ(fsp,req)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBread);
                return;
        }
@@ -3335,7 +3339,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
            &lock);
 
        if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-               reply_doserror(req, ERRDOS,ERRlock);
+               reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                END_PROFILE(SMBread);
                return;
        }
@@ -3403,12 +3407,11 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
                            files_struct *fsp, SMB_OFF_T startpos,
                            size_t smb_maxcnt)
 {
-       SMB_STRUCT_STAT sbuf;
        ssize_t nread = -1;
        struct lock_struct lock;
        int saved_errno = 0;
 
-       if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+       if(fsp_stat(fsp) == -1) {
                reply_nterror(req, map_nt_error_from_unix(errno));
                return;
        }
@@ -3418,12 +3421,13 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
            &lock);
 
        if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-               reply_doserror(req, ERRDOS, ERRlock);
+               reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                return;
        }
 
-       if (!S_ISREG(sbuf.st_ex_mode) || (startpos > sbuf.st_ex_size)
-           || (smb_maxcnt > (sbuf.st_ex_size - startpos))) {
+       if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
+                       (startpos > fsp->fsp_name->st.st_ex_size)
+                       || (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
                /*
                 * We already know that we would do a short read, so don't
                 * try the sendfile() path.
@@ -3615,7 +3619,7 @@ void reply_read_and_X(struct smb_request *req)
        }
 
        if (!CHECK_READ(fsp,req)) {
-               reply_doserror(req, ERRDOS,ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBreadX);
                return;
        }
@@ -3666,7 +3670,7 @@ void reply_read_and_X(struct smb_request *req)
                                 "used and we don't support 64 bit offsets.\n",
                                 (unsigned int)IVAL(req->vwv+10, 0) ));
                        END_PROFILE(SMBreadX);
-                       reply_doserror(req, ERRDOS, ERRbadaccess);
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        return;
                }
 
@@ -3749,7 +3753,7 @@ void reply_writebraw(struct smb_request *req)
        }
 
        if (!CHECK_WRITE(fsp)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                error_to_writebrawerr(req);
                END_PROFILE(SMBwritebraw);
                return;
@@ -3762,7 +3766,7 @@ void reply_writebraw(struct smb_request *req)
        /* We have to deal with slightly different formats depending
                on whether we are using the core+ or lanman1.0 protocol */
 
-       if(Protocol <= PROTOCOL_COREPLUS) {
+       if(get_Protocol() <= PROTOCOL_COREPLUS) {
                numtowrite = SVAL(smb_buf(req->inbuf),-2);
                data = smb_buf(req->inbuf);
        } else {
@@ -3783,7 +3787,7 @@ void reply_writebraw(struct smb_request *req)
            &lock);
 
        if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-               reply_doserror(req, ERRDOS, ERRlock);
+               reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                error_to_writebrawerr(req);
                END_PROFILE(SMBwritebraw);
                return;
@@ -3799,7 +3803,7 @@ void reply_writebraw(struct smb_request *req)
                (int)nwritten, (int)write_through));
 
        if (nwritten < (ssize_t)numtowrite)  {
-               reply_doserror(req, ERRHRD, ERRdiskfull);
+               reply_nterror(req, NT_STATUS_DISK_FULL);
                error_to_writebrawerr(req);
                goto strict_unlock;
        }
@@ -3809,7 +3813,7 @@ void reply_writebraw(struct smb_request *req)
        /* Allocate a buffer of 64k + length. */
        buf = TALLOC_ARRAY(NULL, char, 65540);
        if (!buf) {
-               reply_doserror(req, ERRDOS, ERRnomem);
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
                error_to_writebrawerr(req);
                goto strict_unlock;
        }
@@ -3818,7 +3822,7 @@ void reply_writebraw(struct smb_request *req)
         * it to send more bytes */
 
        memcpy(buf, req->inbuf, smb_size);
-       srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+       srv_set_message(buf,get_Protocol()>PROTOCOL_COREPLUS?1:0,0,True);
        SCVAL(buf,smb_com,SMBwritebraw);
        SSVALS(buf,smb_vwv0,0xFFFF);
        show_msg(buf);
@@ -3965,7 +3969,7 @@ void reply_writeunlock(struct smb_request *req)
        }
 
        if (!CHECK_WRITE(fsp)) {
-               reply_doserror(req, ERRDOS,ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBwriteunlock);
                return;
        }
@@ -3980,7 +3984,7 @@ void reply_writeunlock(struct smb_request *req)
                    &lock);
 
                if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-                       reply_doserror(req, ERRDOS, ERRlock);
+                       reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        END_PROFILE(SMBwriteunlock);
                        return;
                }
@@ -4010,7 +4014,7 @@ void reply_writeunlock(struct smb_request *req)
        }
 
        if((nwritten < numtowrite) && (numtowrite != 0)) {
-               reply_doserror(req, ERRHRD, ERRdiskfull);
+               reply_nterror(req, NT_STATUS_DISK_FULL);
                goto strict_unlock;
        }
 
@@ -4086,7 +4090,7 @@ void reply_write(struct smb_request *req)
        }
 
        if (!CHECK_WRITE(fsp)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBwrite);
                return;
        }
@@ -4100,7 +4104,7 @@ void reply_write(struct smb_request *req)
            &lock);
 
        if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-               reply_doserror(req, ERRDOS, ERRlock);
+               reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                END_PROFILE(SMBwrite);
                return;
        }
@@ -4144,7 +4148,7 @@ void reply_write(struct smb_request *req)
        }
 
        if((nwritten == 0) && (numtowrite != 0)) {
-               reply_doserror(req, ERRHRD, ERRdiskfull);
+               reply_nterror(req, NT_STATUS_DISK_FULL);
                goto strict_unlock;
        }
 
@@ -4296,14 +4300,14 @@ void reply_write_and_X(struct smb_request *req)
                        return;
                }
                if (numtowrite != req->unread_bytes) {
-                       reply_doserror(req, ERRDOS, ERRbadmem);
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        END_PROFILE(SMBwriteX);
                        return;
                }
        } else {
                if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
                                smb_doff + numtowrite > smblen) {
-                       reply_doserror(req, ERRDOS, ERRbadmem);
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        END_PROFILE(SMBwriteX);
                        return;
                }
@@ -4312,7 +4316,7 @@ void reply_write_and_X(struct smb_request *req)
        /* If it's an IPC, pass off the pipe handler. */
        if (IS_IPC(conn)) {
                if (req->unread_bytes) {
-                       reply_doserror(req, ERRDOS, ERRbadmem);
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        END_PROFILE(SMBwriteX);
                        return;
                }
@@ -4331,7 +4335,7 @@ void reply_write_and_X(struct smb_request *req)
        }
 
        if (!CHECK_WRITE(fsp)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBwriteX);
                return;
        }
@@ -4355,7 +4359,7 @@ void reply_write_and_X(struct smb_request *req)
                        DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
                                 "used and we don't support 64 bit offsets.\n",
                                 (unsigned int)IVAL(req->vwv+12, 0) ));
-                       reply_doserror(req, ERRDOS, ERRbadaccess);
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        END_PROFILE(SMBwriteX);
                        return;
                }
@@ -4368,7 +4372,7 @@ void reply_write_and_X(struct smb_request *req)
            &lock);
 
        if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-               reply_doserror(req, ERRDOS, ERRlock);
+               reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                END_PROFILE(SMBwriteX);
                return;
        }
@@ -4397,7 +4401,7 @@ void reply_write_and_X(struct smb_request *req)
        }
 
        if((nwritten == 0) && (numtowrite != 0)) {
-               reply_doserror(req, ERRHRD, ERRdiskfull);
+               reply_nterror(req, NT_STATUS_DISK_FULL);
                goto strict_unlock;
        }
 
@@ -4488,16 +4492,15 @@ void reply_lseek(struct smb_request *req)
                if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
                        if(errno == EINVAL) {
                                SMB_OFF_T current_pos = startpos;
-                               SMB_STRUCT_STAT sbuf;
 
-                               if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+                               if(fsp_stat(fsp) == -1) {
                                        reply_nterror(req,
                                                map_nt_error_from_unix(errno));
                                        END_PROFILE(SMBlseek);
                                        return;
                                }
 
-                               current_pos += sbuf.st_ex_size;
+                               current_pos += fsp->fsp_name->st.st_ex_size;
                                if(current_pos < 0)
                                        res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
                        }
@@ -4609,7 +4612,7 @@ void reply_close(struct smb_request *req)
         */
 
        if(!fsp || (fsp->conn != conn) || (fsp->vuid != req->vuid)) {
-               reply_doserror(req, ERRDOS, ERRbadfid);
+               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
                END_PROFILE(SMBclose);
                return;
        }
@@ -4688,7 +4691,7 @@ void reply_writeclose(struct smb_request *req)
                return;
        }
        if (!CHECK_WRITE(fsp)) {
-               reply_doserror(req, ERRDOS,ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBwriteclose);
                return;
        }
@@ -4704,7 +4707,7 @@ void reply_writeclose(struct smb_request *req)
                    &lock);
 
                if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
-                       reply_doserror(req, ERRDOS,ERRlock);
+                       reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        END_PROFILE(SMBwriteclose);
                        return;
                }
@@ -4730,7 +4733,7 @@ void reply_writeclose(struct smb_request *req)
                 conn->num_files_open));
 
        if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
-               reply_doserror(req, ERRHRD, ERRdiskfull);
+               reply_nterror(req, NT_STATUS_DISK_FULL);
                goto strict_unlock;
        }
 
@@ -4880,7 +4883,7 @@ void reply_tdis(struct smb_request *req)
 
        if (!conn) {
                DEBUG(4,("Invalid connection in tdis\n"));
-               reply_doserror(req, ERRSRV, ERRinvnid);
+               reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
                END_PROFILE(SMBtdis);
                return;
        }
@@ -4969,7 +4972,6 @@ void reply_printopen(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
        files_struct *fsp;
-       SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
 
        START_PROFILE(SMBsplopen);
@@ -4981,7 +4983,7 @@ void reply_printopen(struct smb_request *req)
        }
 
        if (!CAN_PRINT(conn)) {
-               reply_doserror(req, ERRDOS, ERRnoaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBsplopen);
                return;
        }
@@ -4994,7 +4996,7 @@ void reply_printopen(struct smb_request *req)
        }
 
        /* Open for exclusive use, write only. */
-       status = print_fsp_open(req, conn, NULL, req->vuid, fsp, &sbuf);
+       status = print_fsp_open(req, conn, NULL, req->vuid, fsp);
 
        if (!NT_STATUS_IS_OK(status)) {
                file_free(req, fsp);
@@ -5039,7 +5041,7 @@ void reply_printclose(struct smb_request *req)
         }
 
        if (!CAN_PRINT(conn)) {
-               reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
+               reply_force_doserror(req, ERRSRV, ERRerror);
                END_PROFILE(SMBsplclose);
                return;
        }
@@ -5087,7 +5089,7 @@ void reply_printqueue(struct smb_request *req)
           one printer - I think we should now only accept it if they
           get it right (tridge) */
        if (!CAN_PRINT(conn)) {
-               reply_doserror(req, ERRDOS, ERRnoaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBsplretq);
                return;
        }
@@ -5181,13 +5183,13 @@ void reply_printwrite(struct smb_request *req)
         }
 
        if (!CAN_PRINT(conn)) {
-               reply_doserror(req, ERRDOS, ERRnoaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBsplwr);
                return;
        }
 
        if (!CHECK_WRITE(fsp)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                END_PROFILE(SMBsplwr);
                return;
        }
@@ -5281,248 +5283,6 @@ void reply_mkdir(struct smb_request *req)
        return;
 }
 
-/****************************************************************************
- Static function used by reply_rmdir to delete an entire directory
- tree recursively. Return True on ok, False on fail.
-****************************************************************************/
-
-static bool recursive_rmdir(TALLOC_CTX *ctx,
-                       connection_struct *conn,
-                       struct smb_filename *smb_dname)
-{
-       const char *dname = NULL;
-       bool ret = True;
-       long offset = 0;
-       SMB_STRUCT_STAT st;
-       struct smb_Dir *dir_hnd;
-
-       SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
-
-       dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
-       if(dir_hnd == NULL)
-               return False;
-
-       while((dname = ReadDirName(dir_hnd, &offset, &st))) {
-               struct smb_filename *smb_dname_full = NULL;
-               char *fullname = NULL;
-               bool do_break = true;
-               NTSTATUS status;
-
-               if (ISDOT(dname) || ISDOTDOT(dname)) {
-                       continue;
-               }
-
-               if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
-                                    false)) {
-                       continue;
-               }
-
-               /* Construct the full name. */
-               fullname = talloc_asprintf(ctx,
-                               "%s/%s",
-                               smb_dname->base_name,
-                               dname);
-               if (!fullname) {
-                       errno = ENOMEM;
-                       goto err_break;
-               }
-
-               status = create_synthetic_smb_fname(talloc_tos(), fullname,
-                                                   NULL, NULL,
-                                                   &smb_dname_full);
-               if (!NT_STATUS_IS_OK(status)) {
-                       goto err_break;
-               }
-
-               if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
-                       goto err_break;
-               }
-
-               if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
-                       if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
-                               goto err_break;
-                       }
-                       if(SMB_VFS_RMDIR(conn,
-                                        smb_dname_full->base_name) != 0) {
-                               goto err_break;
-                       }
-               } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
-                       goto err_break;
-               }
-
-               /* Successful iteration. */
-               do_break = false;
-
-        err_break:
-               TALLOC_FREE(smb_dname_full);
-               TALLOC_FREE(fullname);
-               if (do_break) {
-                       ret = false;
-                       break;
-               }
-       }
-       TALLOC_FREE(dir_hnd);
-       return ret;
-}
-
-/****************************************************************************
- The internals of the rmdir code - called elsewhere.
-****************************************************************************/
-
-NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
-                        connection_struct *conn,
-                        struct smb_filename *smb_dname)
-{
-       int ret;
-       SMB_STRUCT_STAT st;
-
-       SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
-
-       /* Might be a symlink. */
-       if(SMB_VFS_LSTAT(conn, smb_dname) != 0) {
-               return map_nt_error_from_unix(errno);
-       }
-
-       if (S_ISLNK(smb_dname->st.st_ex_mode)) {
-               /* Is what it points to a directory ? */
-               if(SMB_VFS_STAT(conn, smb_dname) != 0) {
-                       return map_nt_error_from_unix(errno);
-               }
-               if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
-                       return NT_STATUS_NOT_A_DIRECTORY;
-               }
-               ret = SMB_VFS_UNLINK(conn, smb_dname);
-       } else {
-               ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
-       }
-       if (ret == 0) {
-               notify_fname(conn, NOTIFY_ACTION_REMOVED,
-                            FILE_NOTIFY_CHANGE_DIR_NAME,
-                            smb_dname->base_name);
-               return NT_STATUS_OK;
-       }
-
-       if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
-               /*
-                * Check to see if the only thing in this directory are
-                * vetoed files/directories. If so then delete them and
-                * retry. If we fail to delete any of them (and we *don't*
-                * do a recursive delete) then fail the rmdir.
-                */
-               const char *dname;
-               long dirpos = 0;
-               struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
-                                                 smb_dname->base_name, NULL,
-                                                 0);
-
-               if(dir_hnd == NULL) {
-                       errno = ENOTEMPTY;
-                       goto err;
-               }
-
-               while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
-                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-                               continue;
-                       if (!is_visible_file(conn, smb_dname->base_name, dname,
-                                            &st, false))
-                               continue;
-                       if(!IS_VETO_PATH(conn, dname)) {
-                               TALLOC_FREE(dir_hnd);
-                               errno = ENOTEMPTY;
-                               goto err;
-                       }
-               }
-
-               /* We only have veto files/directories.
-                * Are we allowed to delete them ? */
-
-               if(!lp_recursive_veto_delete(SNUM(conn))) {
-                       TALLOC_FREE(dir_hnd);
-                       errno = ENOTEMPTY;
-                       goto err;
-               }
-
-               /* Do a recursive delete. */
-               RewindDir(dir_hnd,&dirpos);
-               while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
-                       struct smb_filename *smb_dname_full = NULL;
-                       char *fullname = NULL;
-                       bool do_break = true;
-                       NTSTATUS status;
-
-                       if (ISDOT(dname) || ISDOTDOT(dname)) {
-                               continue;
-                       }
-                       if (!is_visible_file(conn, smb_dname->base_name, dname,
-                                            &st, false)) {
-                               continue;
-                       }
-
-                       fullname = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       smb_dname->base_name,
-                                       dname);
-
-                       if(!fullname) {
-                               errno = ENOMEM;
-                               goto err_break;
-                       }
-
-                       status = create_synthetic_smb_fname(talloc_tos(),
-                                                           fullname, NULL,
-                                                           NULL,
-                                                           &smb_dname_full);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               errno = map_errno_from_nt_status(status);
-                               goto err_break;
-                       }
-
-                       if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
-                               goto err_break;
-                       }
-                       if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
-                               if(!recursive_rmdir(ctx, conn,
-                                                   smb_dname_full)) {
-                                       goto err_break;
-                               }
-                               if(SMB_VFS_RMDIR(conn,
-                                       smb_dname_full->base_name) != 0) {
-                                       goto err_break;
-                               }
-                       } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
-                               goto err_break;
-                       }
-
-                       /* Successful iteration. */
-                       do_break = false;
-
-                err_break:
-                       TALLOC_FREE(fullname);
-                       TALLOC_FREE(smb_dname_full);
-                       if (do_break)
-                               break;
-               }
-               TALLOC_FREE(dir_hnd);
-               /* Retry the rmdir */
-               ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
-       }
-
-  err:
-
-       if (ret != 0) {
-               DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
-                        "%s\n", smb_fname_str_dbg(smb_dname),
-                        strerror(errno)));
-               return map_nt_error_from_unix(errno);
-       }
-
-       notify_fname(conn, NOTIFY_ACTION_REMOVED,
-                    FILE_NOTIFY_CHANGE_DIR_NAME,
-                    smb_dname->base_name);
-
-       return NT_STATUS_OK;
-}
-
 /****************************************************************************
  Reply to a rmdir.
 ****************************************************************************/
@@ -5534,6 +5294,8 @@ void reply_rmdir(struct smb_request *req)
        char *directory = NULL;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
+       files_struct *fsp = NULL;
+       int info = 0;
        struct smbd_server_connection *sconn = smbd_server_conn;
 
        START_PROFILE(SMBrmdir);
@@ -5566,14 +5328,54 @@ void reply_rmdir(struct smb_request *req)
                goto out;
        }
 
-       dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
-       status = rmdir_internals(ctx, conn, smb_dname);
+       status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               smb_dname,                              /* fname */
+               DELETE_ACCESS,                          /* access_mask */
+               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+                       FILE_SHARE_DELETE),
+               FILE_OPEN,                              /* create_disposition*/
+               FILE_DIRECTORY_FILE,                    /* create_options */
+               FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
+               0,                                      /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &fsp,                                   /* result */
+               &info);                                 /* pinfo */
+
+       if (!NT_STATUS_IS_OK(status)) {
+               if (open_was_deferred(req->mid)) {
+                       /* We have re-scheduled this call. */
+                       goto out;
+               }
+               reply_nterror(req, status);
+               goto out;
+       }
+
+       status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
        if (!NT_STATUS_IS_OK(status)) {
+               close_file(req, fsp, ERROR_CLOSE);
                reply_nterror(req, status);
                goto out;
        }
 
-       reply_outbuf(req, 0, 0);
+       if (!set_delete_on_close(fsp, true, &conn->server_info->utok)) {
+               close_file(req, fsp, ERROR_CLOSE);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+               goto out;
+       }
+
+       status = close_file(req, fsp, NORMAL_CLOSE);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+       } else {
+               reply_outbuf(req, 0, 0);
+       }
+
+       dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
 
        DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
  out:
@@ -5844,25 +5646,17 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                        bool replace_if_exists)
 {
        TALLOC_CTX *ctx = talloc_tos();
-       struct smb_filename *smb_fname_src = NULL;
        struct smb_filename *smb_fname_dst = NULL;
-       SMB_STRUCT_STAT sbuf;
        NTSTATUS status = NT_STATUS_OK;
        struct share_mode_lock *lck = NULL;
        bool dst_exists, old_is_stream, new_is_stream;
 
-       ZERO_STRUCT(sbuf);
-
        status = check_name(conn, smb_fname_dst_in->base_name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       /* Make a copy of the src and dst smb_fname structs */
-       status = copy_smb_filename(ctx, fsp->fsp_name, &smb_fname_src);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto out;
-       }
+       /* Make a copy of the dst smb_fname structs */
 
        status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst);
        if (!NT_STATUS_IS_OK(status)) {
@@ -5890,8 +5684,8 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
         * filename).
         */
        if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
-           strequal(smb_fname_src->base_name, smb_fname_dst->base_name) &&
-           strequal(smb_fname_src->stream_name, smb_fname_dst->stream_name)) {
+           strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
+           strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
                char *last_slash;
                char *fname_dst_lcomp_base_mod = NULL;
                struct smb_filename *smb_fname_orig_lcomp = NULL;
@@ -5968,8 +5762,8 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
         * don't do the rename, just return success.
         */
 
-       if (strcsequal(smb_fname_src->base_name, smb_fname_dst->base_name) &&
-           strcsequal(smb_fname_src->stream_name,
+       if (strcsequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
+           strcsequal(fsp->fsp_name->stream_name,
                       smb_fname_dst->stream_name)) {
                DEBUG(3, ("rename_internals_fsp: identical names in rename %s "
                          "- returning success\n",
@@ -5978,7 +5772,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                goto out;
        }
 
-       old_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
+       old_is_stream = is_ntfs_stream_smb_fname(fsp->fsp_name);
        new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
 
        /* Return the correct error code if both names aren't streams. */
@@ -5996,7 +5790,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 
        if(!replace_if_exists && dst_exists) {
                DEBUG(3, ("rename_internals_fsp: dest exists doing rename "
-                         "%s -> %s\n", smb_fname_str_dbg(smb_fname_src),
+                         "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
                          smb_fname_str_dbg(smb_fname_dst)));
                status = NT_STATUS_OBJECT_NAME_COLLISION;
                goto out;
@@ -6015,38 +5809,23 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
        }
 
        /* Ensure we have a valid stat struct for the source. */
-       if (fsp->fh->fd != -1) {
-               if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
-                       status = map_nt_error_from_unix(errno);
-                       goto out;
-               }
-       } else {
-               int ret = -1;
-               if (fsp->posix_open) {
-                       ret = SMB_VFS_LSTAT(conn, smb_fname_src);
-               } else {
-
-                       ret = SMB_VFS_STAT(conn, smb_fname_src);
-               }
-               if (ret == -1) {
-                       status = map_nt_error_from_unix(errno);
-                       goto out;
-               }
-               sbuf = smb_fname_src->st;
+       status = vfs_stat_fsp(fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
-       status = can_rename(conn, fsp, attrs, &sbuf);
+       status = can_rename(conn, fsp, attrs);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
-                         nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
+                         nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
                          smb_fname_str_dbg(smb_fname_dst)));
                if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
                        status = NT_STATUS_ACCESS_DENIED;
                goto out;
        }
 
-       if (rename_path_prefix_equal(smb_fname_src, smb_fname_dst)) {
+       if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
                status = NT_STATUS_ACCESS_DENIED;
        }
 
@@ -6060,14 +5839,14 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 
        SMB_ASSERT(lck != NULL);
 
-       if(SMB_VFS_RENAME(conn, smb_fname_src, smb_fname_dst) == 0) {
+       if(SMB_VFS_RENAME(conn, fsp->fsp_name, smb_fname_dst) == 0) {
                uint32 create_options = fsp->fh->private_options;
 
                DEBUG(3, ("rename_internals_fsp: succeeded doing rename on "
-                         "%s -> %s\n", smb_fname_str_dbg(smb_fname_src),
+                         "%s -> %s\n", smb_fname_str_dbg(fsp->fsp_name),
                          smb_fname_str_dbg(smb_fname_dst)));
 
-               notify_rename(conn, fsp->is_directory, smb_fname_src,
+               notify_rename(conn, fsp->is_directory, fsp->fsp_name,
                              smb_fname_dst);
 
                rename_open_files(conn, lck, smb_fname_dst);
@@ -6082,7 +5861,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                 */
 
                if (create_options & FILE_DELETE_ON_CLOSE) {
-                       status = can_set_delete_on_close(fsp, True, 0);
+                       status = can_set_delete_on_close(fsp, 0);
 
                        if (NT_STATUS_IS_OK(status)) {
                                /* Note that here we set the *inital* delete on close flag,
@@ -6104,11 +5883,10 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
        }
 
        DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n",
-                 nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
+                 nt_errstr(status), smb_fname_str_dbg(fsp->fsp_name),
                  smb_fname_str_dbg(smb_fname_dst)));
 
  out:
-       TALLOC_FREE(smb_fname_src);
        TALLOC_FREE(smb_fname_dst);
 
        return status;
@@ -6135,7 +5913,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
        int count=0;
        NTSTATUS status = NT_STATUS_OK;
        struct smb_Dir *dir_hnd = NULL;
-       const char *dname;
+       const char *dname = NULL;
+       char *talloced = NULL;
        long offset = 0;
        int create_options = 0;
        bool posix_pathnames = lp_posix_pathnames();
@@ -6313,7 +6092,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
         * - gentest fix. JRA
         */
 
-       while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st))) {
+       while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st,
+                                   &talloced))) {
                files_struct *fsp = NULL;
                char *destname = NULL;
                bool sysdir_entry = False;
@@ -6323,16 +6103,19 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        if (attrs & aDIR) {
                                sysdir_entry = True;
                        } else {
+                               TALLOC_FREE(talloced);
                                continue;
                        }
                }
 
                if (!is_visible_file(conn, fname_src_dir, dname,
                                     &smb_fname_src->st, false)) {
+                       TALLOC_FREE(talloced);
                        continue;
                }
 
                if(!mask_match(dname, fname_src_mask, conn->case_sensitive)) {
+                       TALLOC_FREE(talloced);
                        continue;
                }
 
@@ -6356,6 +6139,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                                       &destname)) {
                        DEBUG(6, ("resolve_wildcards %s %s failed\n",
                                  smb_fname_src->base_name, destname));
+                       TALLOC_FREE(talloced);
                        continue;
                }
                if (!destname) {
@@ -6431,7 +6215,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                DEBUG(3,("rename_internals: doing rename on %s -> "
                         "%s\n", smb_fname_str_dbg(smb_fname_src),
                         smb_fname_str_dbg(smb_fname_src)));
-
+               TALLOC_FREE(talloced);
        }
        TALLOC_FREE(dir_hnd);
 
@@ -6440,6 +6224,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
        }
 
  out:
+       TALLOC_FREE(talloced);
        TALLOC_FREE(fname_src_dir);
        TALLOC_FREE(fname_src_mask);
        return status;
@@ -6768,7 +6553,7 @@ void reply_copy(struct smb_request *req)
        if (tid2 != conn->cnum) {
                /* can't currently handle inter share copies XXXX */
                DEBUG(3,("Rejecting inter-share copy\n"));
-               reply_doserror(req, ERRSRV, ERRinvdevice);
+               reply_nterror(req, NT_STATUS_BAD_DEVICE_TYPE);
                goto out;
        }
 
@@ -6807,19 +6592,19 @@ void reply_copy(struct smb_request *req)
        target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st);
 
        if ((flags&1) && target_is_directory) {
-               reply_doserror(req, ERRDOS, ERRbadfile);
+               reply_nterror(req, NT_STATUS_NO_SUCH_FILE);
                goto out;
        }
 
        if ((flags&2) && !target_is_directory) {
-               reply_doserror(req, ERRDOS, ERRbadpath);
+               reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
                goto out;
        }
 
        if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) {
                /* wants a tree copy! XXXX */
                DEBUG(3,("Rejecting tree copy\n"));
-               reply_doserror(req, ERRSRV, ERRerror);
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                goto out;
        }
 
@@ -6905,6 +6690,7 @@ void reply_copy(struct smb_request *req)
        } else {
                struct smb_Dir *dir_hnd = NULL;
                const char *dname = NULL;
+               char *talloced = NULL;
                long offset = 0;
 
                /*
@@ -6945,20 +6731,23 @@ void reply_copy(struct smb_request *req)
 
                /* Iterate over the src dir copying each entry to the dst. */
                while ((dname = ReadDirName(dir_hnd, &offset,
-                                           &smb_fname_src->st))) {
+                                           &smb_fname_src->st, &talloced))) {
                        char *destname = NULL;
 
                        if (ISDOT(dname) || ISDOTDOT(dname)) {
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
                        if (!is_visible_file(conn, fname_src_dir, dname,
                                             &smb_fname_src->st, false)) {
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
                        if(!mask_match(dname, fname_src_mask,
                                       conn->case_sensitive)) {
+                               TALLOC_FREE(talloced);
                                continue;
                        }
 
@@ -6972,6 +6761,7 @@ void reply_copy(struct smb_request *req)
 
                        if (!smb_fname_src->base_name) {
                                TALLOC_FREE(dir_hnd);
+                               TALLOC_FREE(talloced);
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
                                goto out;
                        }
@@ -6979,10 +6769,12 @@ void reply_copy(struct smb_request *req)
                        if (!resolve_wildcards(ctx, smb_fname_src->base_name,
                                               smb_fname_dst->base_name,
                                               &destname)) {
+                               TALLOC_FREE(talloced);
                                continue;
                        }
                        if (!destname) {
                                TALLOC_FREE(dir_hnd);
+                               TALLOC_FREE(talloced);
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
                                goto out;
                        }
@@ -6993,6 +6785,7 @@ void reply_copy(struct smb_request *req)
                        status = check_name(conn, smb_fname_src->base_name);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
+                               TALLOC_FREE(talloced);
                                reply_nterror(req, status);
                                goto out;
                        }
@@ -7000,6 +6793,7 @@ void reply_copy(struct smb_request *req)
                        status = check_name(conn, smb_fname_dst->base_name);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
+                               TALLOC_FREE(talloced);
                                reply_nterror(req, status);
                                goto out;
                        }
@@ -7014,12 +6808,14 @@ void reply_copy(struct smb_request *req)
                        if (NT_STATUS_IS_OK(status)) {
                                count++;
                        }
+
+                       TALLOC_FREE(talloced);
                }
                TALLOC_FREE(dir_hnd);
        }
 
        if (count == 0) {
-               reply_doserror(req, ERRDOS, error);
+               reply_nterror(req, dos_to_ntstatus(ERRDOS, error));
                goto out;
        }
 
@@ -7247,6 +7043,30 @@ NTSTATUS smbd_do_locking(struct smb_request *req,
                if (type & LOCKING_ANDX_CANCEL_LOCK) {
                        struct blocking_lock_record *blr = NULL;
 
+                       if (num_locks > 1) {
+                               /*
+                                * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
+                                * if the lock vector contains one entry. When given mutliple cancel
+                                * requests in a single PDU we expect the server to return an
+                                * error. Windows servers seem to accept the request but only
+                                * cancel the first lock.
+                                * JRA - Do what Windows does (tm) :-).
+                                */
+
+#if 0
+                               /* MS-CIFS (2.2.4.32.1) behavior. */
+                               return NT_STATUS_DOS(ERRDOS,
+                                               ERRcancelviolation);
+#else
+                               /* Windows behavior. */
+                               if (i != 0) {
+                                       DEBUG(10,("smbd_do_locking: ignoring subsequent "
+                                               "cancel request\n"));
+                                       continue;
+                               }
+#endif
+                       }
+
                        if (lp_blocking_locks(SNUM(conn))) {
 
                                /* Schedule a message to ourselves to
@@ -7300,13 +7120,22 @@ NTSTATUS smbd_do_locking(struct smb_request *req,
                                defer_lock = true;
                        }
 
-                       /* This heuristic seems to match W2K3 very well. If a
-                          lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
-                          it pretends we asked for a timeout of between 150 - 300 milliseconds as
-                          far as I can tell. Replacement for do_lock_spin(). JRA. */
+                       /* If a lock sent with timeout of zero would fail, and
+                        * this lock has been requested multiple times,
+                        * according to brl_lock_failed() we convert this
+                        * request to a blocking lock with a timeout of between
+                        * 150 - 300 milliseconds.
+                        *
+                        * If lp_lock_spin_time() has been set to 0, we skip
+                        * this blocking retry and fail immediately.
+                        *
+                        * Replacement for do_lock_spin(). JRA. */
 
-                       if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
-                                       NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
+                       if (br_lck && lp_blocking_locks(SNUM(conn)) &&
+                           lp_lock_spin_time() && !blocking_lock &&
+                           NT_STATUS_EQUAL((status),
+                               NT_STATUS_FILE_LOCK_CONFLICT))
+                       {
                                defer_lock = true;
                                timeout = lp_lock_spin_time();
                        }
@@ -7424,7 +7253,7 @@ void reply_lockingX(struct smb_request *req)
                /* we don't support these - and CANCEL_LOCK makes w2k
                   and XP reboot so I don't really want to be
                   compatible! (tridge) */
-               reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
+               reply_force_doserror(req, ERRDOS, ERRnoatomiclocks);
                END_PROFILE(SMBlockingX);
                return;
        }
@@ -7467,7 +7296,7 @@ void reply_lockingX(struct smb_request *req)
                                return;
                        } else {
                                END_PROFILE(SMBlockingX);
-                               reply_doserror(req, ERRDOS, ERRlock);
+                               reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                                return;
                        }
                }
@@ -7535,8 +7364,8 @@ void reply_lockingX(struct smb_request *req)
                 * There is no error code marked "stupid client bug".... :-).
                 */
                if(err) {
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        END_PROFILE(SMBlockingX);
-                       reply_doserror(req, ERRDOS, ERRnoaccess);
                        return;
                }
        }
@@ -7570,8 +7399,8 @@ void reply_lockingX(struct smb_request *req)
                 * There is no error code marked "stupid client bug".... :-).
                 */
                if(err) {
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        END_PROFILE(SMBlockingX);
-                       reply_doserror(req, ERRDOS, ERRnoaccess);
                        return;
                }
        }
@@ -7612,7 +7441,7 @@ void reply_lockingX(struct smb_request *req)
 void reply_readbmpx(struct smb_request *req)
 {
        START_PROFILE(SMBreadBmpx);
-       reply_doserror(req, ERRSRV, ERRuseSTD);
+       reply_force_doserror(req, ERRSRV, ERRuseSTD);
        END_PROFILE(SMBreadBmpx);
        return;
 }
@@ -7626,7 +7455,7 @@ void reply_readbmpx(struct smb_request *req)
 void reply_readbs(struct smb_request *req)
 {
        START_PROFILE(SMBreadBs);
-       reply_doserror(req, ERRSRV, ERRuseSTD);
+       reply_force_doserror(req, ERRSRV, ERRuseSTD);
        END_PROFILE(SMBreadBs);
        return;
 }
@@ -7653,7 +7482,7 @@ void reply_setattrE(struct smb_request *req)
        fsp = file_fsp(req, SVAL(req->vwv+0, 0));
 
        if(!fsp || (fsp->conn != conn)) {
-               reply_doserror(req, ERRDOS, ERRbadfid);
+               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
                goto out;
        }
 
@@ -7676,30 +7505,15 @@ void reply_setattrE(struct smb_request *req)
         */
 
        /* Ensure we have a valid stat struct for the source. */
-       if (fsp->fh->fd != -1) {
-               if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == -1) {
-                       status = map_nt_error_from_unix(errno);
-                       reply_nterror(req, status);
-                       goto out;
-               }
-       } else {
-               int ret = -1;
-
-               if (fsp->posix_open) {
-                       ret = SMB_VFS_LSTAT(conn, fsp->fsp_name);
-               } else {
-                       ret = SMB_VFS_STAT(conn, fsp->fsp_name);
-               }
-               if (ret == -1) {
-                       status = map_nt_error_from_unix(errno);
-                       reply_nterror(req, status);
-                       goto out;
-               }
+       status = vfs_stat_fsp(fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
        }
 
        status = smb_set_file_time(conn, fsp, fsp->fsp_name, &ft, true);
        if (!NT_STATUS_IS_OK(status)) {
-               reply_doserror(req, ERRDOS, ERRnoaccess);
+               reply_nterror(req, status);
                goto out;
        }
 
@@ -7727,7 +7541,7 @@ void reply_setattrE(struct smb_request *req)
 void reply_writebmpx(struct smb_request *req)
 {
        START_PROFILE(SMBwriteBmpx);
-       reply_doserror(req, ERRSRV, ERRuseSTD);
+       reply_force_doserror(req, ERRSRV, ERRuseSTD);
        END_PROFILE(SMBwriteBmpx);
        return;
 }
@@ -7741,7 +7555,7 @@ void reply_writebmpx(struct smb_request *req)
 void reply_writebs(struct smb_request *req)
 {
        START_PROFILE(SMBwriteBs);
-       reply_doserror(req, ERRSRV, ERRuseSTD);
+       reply_force_doserror(req, ERRSRV, ERRuseSTD);
        END_PROFILE(SMBwriteBs);
        return;
 }
@@ -7753,7 +7567,6 @@ void reply_writebs(struct smb_request *req)
 void reply_getattrE(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
-       SMB_STRUCT_STAT sbuf;
        int mode;
        files_struct *fsp;
        struct timespec create_ts;
@@ -7769,20 +7582,18 @@ void reply_getattrE(struct smb_request *req)
        fsp = file_fsp(req, SVAL(req->vwv+0, 0));
 
        if(!fsp || (fsp->conn != conn)) {
-               reply_doserror(req, ERRDOS, ERRbadfid);
+               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
                END_PROFILE(SMBgetattrE);
                return;
        }
 
        /* Do an fstat on this file */
-       if(fsp_stat(fsp, &sbuf)) {
+       if(fsp_stat(fsp)) {
                reply_nterror(req, map_nt_error_from_unix(errno));
                END_PROFILE(SMBgetattrE);
                return;
        }
 
-       fsp->fsp_name->st = sbuf;
-
        mode = dos_mode(conn, fsp->fsp_name);
 
        /*
@@ -7793,20 +7604,20 @@ void reply_getattrE(struct smb_request *req)
 
        reply_outbuf(req, 11, 0);
 
-       create_ts = get_create_timespec(fsp, fsp->fsp_name);
+       create_ts = get_create_timespec(conn, fsp, fsp->fsp_name);
        srv_put_dos_date2((char *)req->outbuf, smb_vwv0, create_ts.tv_sec);
        srv_put_dos_date2((char *)req->outbuf, smb_vwv2,
-                         convert_timespec_to_time_t(sbuf.st_ex_atime));
+                         convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_atime));
        /* Should we check pending modtime here ? JRA */
        srv_put_dos_date2((char *)req->outbuf, smb_vwv4,
-                         convert_timespec_to_time_t(sbuf.st_ex_mtime));
+                         convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime));
 
        if (mode & aDIR) {
                SIVAL(req->outbuf, smb_vwv6, 0);
                SIVAL(req->outbuf, smb_vwv8, 0);
        } else {
-               uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &sbuf);
-               SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_ex_size);
+               uint32 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp, &fsp->fsp_name->st);
+               SIVAL(req->outbuf, smb_vwv6, (uint32)fsp->fsp_name->st.st_ex_size);
                SIVAL(req->outbuf, smb_vwv8, allocation_size);
        }
        SSVAL(req->outbuf,smb_vwv10, mode);