[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[sfrench/samba-autobuild/.git] / source3 / smbd / open.c
index c9e29cf0e5a6dfcc5195aaa2c6dab42c9501da4a..fbc6f9ab64103d07d3fff69c8c8443e6106fddb7 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
-extern struct generic_mapping file_generic_mapping;
+extern const struct generic_mapping file_generic_mapping;
 extern struct current_user current_user;
 extern userdom_struct current_user_info;
-extern uint16 global_smbpid;
 extern BOOL global_client_failed_oplock_break;
 
 struct deferred_open_record {
        BOOL delayed_for_oplocks;
-       SMB_DEV_T dev;
-       SMB_INO_T inode;
+       struct file_id id;
 };
 
 /****************************************************************************
  fd support routines - attempt to do a dos_open.
 ****************************************************************************/
 
-static BOOL fd_open(struct connection_struct *conn,
+static NTSTATUS fd_open(struct connection_struct *conn,
                    const char *fname, 
                    files_struct *fsp,
                    int flags,
                    mode_t mode)
 {
-       int sav;
+       NTSTATUS status = NT_STATUS_OK;
 
 #ifdef O_NOFOLLOW
-       if (!lp_symlinks(SNUM(conn))) {
+       /* 
+        * Never follow symlinks on a POSIX client. The
+        * client should be doing this.
+        */
+
+       if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
                flags |= O_NOFOLLOW;
        }
 #endif
 
        fsp->fh->fd = SMB_VFS_OPEN(conn,fname,fsp,flags,mode);
-       sav = errno;
+       if (fsp->fh->fd == -1) {
+               status = map_nt_error_from_unix(errno);
+       }
 
        DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
                    fname, flags, (int)mode, fsp->fh->fd,
                (fsp->fh->fd == -1) ? strerror(errno) : "" ));
 
-       errno = sav;
-       return fsp->fh->fd != -1;
+       return status;
 }
 
 /****************************************************************************
@@ -114,22 +117,26 @@ static void change_file_owner_to_parent(connection_struct *conn,
                  (unsigned int)parent_st.st_uid ));
 }
 
-static void change_dir_owner_to_parent(connection_struct *conn,
+static NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
                                       const char *inherit_from_dir,
                                       const char *fname,
                                       SMB_STRUCT_STAT *psbuf)
 {
-       pstring saved_dir;
+       char *saved_dir = NULL;
        SMB_STRUCT_STAT sbuf;
        SMB_STRUCT_STAT parent_st;
+       TALLOC_CTX *ctx = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_OK;
        int ret;
 
        ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st);
        if (ret == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to stat parent "
                         "directory %s. Error was %s\n",
                         inherit_from_dir, strerror(errno) ));
-               return;
+               TALLOC_FREE(ctx);
+               return status;
        }
 
        /* We've already done an lstat into psbuf, and we know it's a
@@ -139,14 +146,19 @@ static void change_dir_owner_to_parent(connection_struct *conn,
           should work on any UNIX (thanks tridge :-). JRA.
        */
 
-       if (!vfs_GetWd(conn,saved_dir)) {
+       saved_dir = vfs_GetWd(ctx,conn);
+       if (!saved_dir) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to get "
-                        "current working directory\n"));
-               return;
+                        "current working directory. Error was %s\n",
+                        strerror(errno)));
+               TALLOC_FREE(ctx);
+               return status;
        }
 
        /* Chdir into the new path. */
        if (vfs_ChDir(conn, fname) == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to change "
                         "current working directory to %s. Error "
                         "was %s\n", fname, strerror(errno) ));
@@ -154,6 +166,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
        }
 
        if (SMB_VFS_STAT(conn,".",&sbuf) == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to stat "
                         "directory '.' (%s) Error was %s\n",
                         fname, strerror(errno)));
@@ -167,6 +180,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
                DEBUG(0,("change_dir_owner_to_parent: "
                         "device/inode/mode on directory %s changed. "
                         "Refusing to chown !\n", fname ));
+               status = NT_STATUS_ACCESS_DENIED;
                goto out;
        }
 
@@ -174,6 +188,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
        ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1);
        unbecome_root();
        if (ret == -1) {
+               status = map_nt_error_from_unix(errno);
                DEBUG(10,("change_dir_owner_to_parent: failed to chown "
                          "directory %s to parent directory uid %u. "
                          "Error was %s\n", fname,
@@ -187,7 +202,9 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 
  out:
 
+       TALLOC_FREE(ctx);
        vfs_ChDir(conn,saved_dir);
+       return status;
 }
 
 /****************************************************************************
@@ -196,6 +213,7 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 
 static NTSTATUS open_file(files_struct *fsp,
                          connection_struct *conn,
+                         struct smb_request *req,
                          const char *parent_dir,
                          const char *name,
                          const char *path,
@@ -205,6 +223,7 @@ static NTSTATUS open_file(files_struct *fsp,
                          uint32 access_mask, /* client requested access mask. */
                          uint32 open_access_mask) /* what we're actually using in the open. */
 {
+       NTSTATUS status = NT_STATUS_OK;
        int accmode = (flags & O_ACCMODE);
        int local_flags = flags;
        BOOL file_existed = VALID_STAT(*psbuf);
@@ -287,11 +306,12 @@ static NTSTATUS open_file(files_struct *fsp,
                }
 
                /* Actually do the open */
-               if (!fd_open(conn, path, fsp, local_flags, unx_mode)) {
+               status = fd_open(conn, path, fsp, local_flags, unx_mode);
+               if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
                                 "(flags=%d)\n",
-                                path,strerror(errno),local_flags,flags));
-                       return map_nt_error_from_unix(errno);
+                                path,nt_errstr(status),local_flags,flags));
+                       return status;
                }
 
                if ((local_flags & O_CREAT) && !file_existed) {
@@ -332,7 +352,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
                /* For a non-io open, this stat failing means file not found. JRA */
                if (ret == -1) {
-                       NTSTATUS status = map_nt_error_from_unix(errno);
+                       status = map_nt_error_from_unix(errno);
                        fd_close(conn, fsp);
                        return status;
                }
@@ -351,10 +371,9 @@ static NTSTATUS open_file(files_struct *fsp,
        }
 
        fsp->mode = psbuf->st_mode;
-       fsp->inode = psbuf->st_ino;
-       fsp->dev = psbuf->st_dev;
-       fsp->vuid = current_user.vuid;
-       fsp->file_pid = global_smbpid;
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+       fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
+       fsp->file_pid = req ? req->smbpid : 0;
        fsp->can_lock = True;
        fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
        if (!CAN_WRITE(conn)) {
@@ -368,9 +387,8 @@ static NTSTATUS open_file(files_struct *fsp,
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = False;
        fsp->is_stat = False;
-       if (conn->aio_write_behind_list
-           && is_in_path(path, conn->aio_write_behind_list,
-                         conn->case_sensitive)) {
+       if (conn->aio_write_behind_list &&
+           is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) {
                fsp->aio_write_behind = True;
        }
 
@@ -500,9 +518,10 @@ static void validate_my_share_entries(int num,
 
        if (is_deferred_open_entry(share_entry) &&
            !open_was_deferred(share_entry->op_mid)) {
-               pstring str;
-               pstr_sprintf(str, "Got a deferred entry without a request: "
-                            "PANIC: %s\n", share_mode_str(num, share_entry));
+               char *str = talloc_asprintf(talloc_tos(),
+                       "Got a deferred entry without a request: "
+                       "PANIC: %s\n",
+                       share_mode_str(num, share_entry));
                smb_panic(str);
        }
 
@@ -510,7 +529,7 @@ static void validate_my_share_entries(int num,
                return;
        }
 
-       fsp = file_find_dif(share_entry->dev, share_entry->inode,
+       fsp = file_find_dif(share_entry->id,
                            share_entry->share_file_id);
        if (!fsp) {
                DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
@@ -539,11 +558,12 @@ static void validate_my_share_entries(int num,
 
  panic:
        {
-               pstring str;
+               char *str;
                DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
                         share_mode_str(num, share_entry) ));
-               slprintf(str, sizeof(str)-1, "validate_my_share_entries: "
-                        "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
+               str = talloc_asprintf(talloc_tos(),
+                       "validate_my_share_entries: "
+                       "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
                         fsp->fsp_name, (unsigned int)fsp->oplock_type,
                         (unsigned int)share_entry->op_type );
                smb_panic(str);
@@ -643,6 +663,7 @@ static BOOL is_delete_request(files_struct *fsp) {
 
 static BOOL delay_for_oplocks(struct share_mode_lock *lck,
                              files_struct *fsp,
+                             uint16 mid,
                              int pass_number,
                              int oplock_request)
 {
@@ -727,7 +748,7 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
 
        DEBUG(10, ("Sending break request to PID %s\n",
                   procid_str_static(&exclusive->pid)));
-       exclusive->op_mid = get_current_mid();
+       exclusive->op_mid = mid;
 
        /* Create the message. */
        share_mode_entry_to_message(msg, exclusive);
@@ -739,8 +760,10 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
                SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
        }
 
-       status = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST,
-                                 msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
+       status = messaging_send_buf(smbd_messaging_context(), exclusive->pid,
+                                   MSG_SMB_BREAK_REQUEST,
+                                   (uint8 *)msg,
+                                   MSG_SMB_SHARE_MODE_ENTRY_SIZE);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3, ("Could not send oplock break message: %s\n",
                          nt_errstr(status)));
@@ -765,9 +788,9 @@ static BOOL request_timed_out(struct timeval request_time,
 static void defer_open(struct share_mode_lock *lck,
                       struct timeval request_time,
                       struct timeval timeout,
+                      struct smb_request *req,
                       struct deferred_open_record *state)
 {
-       uint16 mid = get_current_mid();
        int i;
 
        /* Paranoia check */
@@ -779,9 +802,9 @@ static void defer_open(struct share_mode_lock *lck,
                        continue;
                }
 
-               if (procid_is_me(&e->pid) && (e->op_mid == mid)) {
+               if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) {
                        DEBUG(0, ("Trying to defer an already deferred "
-                                 "request: mid=%d, exiting\n", mid));
+                                 "request: mid=%d, exiting\n", req->mid));
                        exit_server("attempt to defer a deferred request");
                }
        }
@@ -792,13 +815,13 @@ static void defer_open(struct share_mode_lock *lck,
                  "open entry for mid %u\n",
                  (unsigned int)request_time.tv_sec,
                  (unsigned int)request_time.tv_usec,
-                 (unsigned int)mid));
+                 (unsigned int)req->mid));
 
-       if (!push_deferred_smb_message(mid, request_time, timeout,
+       if (!push_deferred_smb_message(req, request_time, timeout,
                                       (char *)state, sizeof(*state))) {
                exit_server("push_deferred_smb_message failed");
        }
-       add_deferred_open(lck, mid, request_time, state->dev, state->inode);
+       add_deferred_open(lck, req->mid, request_time, state->id);
 
        /*
         * Push the MID of this packet on the signing queue.
@@ -807,7 +830,7 @@ static void defer_open(struct share_mode_lock *lck,
         * of incrementing the response sequence number.
         */
 
-       srv_defer_sign_response(mid);
+       srv_defer_sign_response(req->mid);
 }
 
 
@@ -866,8 +889,10 @@ static BOOL open_match_attributes(connection_struct *conn,
 ****************************************************************************/
 
 static files_struct *fcb_or_dos_open(connection_struct *conn,
-                                    const char *fname, SMB_DEV_T dev,
-                                    SMB_INO_T inode,
+                                    const char *fname, 
+                                    struct file_id id,
+                                    uint16 file_pid,
+                                    uint16 vuid,
                                     uint32 access_mask,
                                     uint32 share_access,
                                     uint32 create_options)
@@ -878,7 +903,7 @@ static files_struct *fcb_or_dos_open(connection_struct *conn,
        DEBUG(5,("fcb_or_dos_open: attempting old open semantics for "
                 "file %s.\n", fname ));
 
-       for(fsp = file_find_di_first(dev, inode); fsp;
+       for(fsp = file_find_di_first(id); fsp;
            fsp = file_find_di_next(fsp)) {
 
                DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, "
@@ -890,8 +915,8 @@ static files_struct *fcb_or_dos_open(connection_struct *conn,
                          (unsigned int)fsp->access_mask ));
 
                if (fsp->fh->fd != -1 &&
-                   fsp->vuid == current_user.vuid &&
-                   fsp->file_pid == global_smbpid &&
+                   fsp->vuid == vuid &&
+                   fsp->file_pid == file_pid &&
                    (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
                                                 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
                    (fsp->access_mask & FILE_WRITE_DATA) &&
@@ -1060,7 +1085,9 @@ BOOL map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func
 
 }
 
-static void schedule_defer_open(struct share_mode_lock *lck, struct timeval request_time)
+static void schedule_defer_open(struct share_mode_lock *lck,
+                               struct timeval request_time,
+                               struct smb_request *req)
 {
        struct deferred_open_record state;
 
@@ -1088,11 +1115,10 @@ static void schedule_defer_open(struct share_mode_lock *lck, struct timeval requ
           a 1 second delay for share mode conflicts. */
 
        state.delayed_for_oplocks = True;
-       state.dev = lck->dev;
-       state.inode = lck->ino;
+       state.id = lck->id;
 
        if (!request_timed_out(request_time, timeout)) {
-               defer_open(lck, request_time, timeout, &state);
+               defer_open(lck, request_time, timeout, req, &state);
        }
 }
 
@@ -1101,6 +1127,7 @@ static void schedule_defer_open(struct share_mode_lock *lck, struct timeval requ
 ****************************************************************************/
 
 NTSTATUS open_file_ntcreate(connection_struct *conn,
+                           struct smb_request *req,
                            const char *fname,
                            SMB_STRUCT_STAT *psbuf,
                            uint32 access_mask,         /* access bits (FILE_READ_DATA etc.) */
@@ -1118,8 +1145,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        BOOL file_existed = VALID_STAT(*psbuf);
        BOOL def_acl = False;
        BOOL posix_open = False;
-       SMB_DEV_T dev = 0;
-       SMB_INO_T inode = 0;
+       BOOL new_file_created = False;
+       struct file_id id;
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
        files_struct *fsp = NULL;
        mode_t new_unx_mode = (mode_t)0;
@@ -1127,7 +1154,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        int info;
        uint32 existing_dos_attributes = 0;
        struct pending_message_list *pml = NULL;
-       uint16 mid = get_current_mid();
        struct timeval request_time = timeval_zero();
        struct share_mode_lock *lck = NULL;
        uint32 open_access_mask = access_mask;
@@ -1136,6 +1162,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        char *parent_dir;
        const char *newname;
 
+       ZERO_STRUCT(id);
+
        if (conn->printer) {
                /* 
                 * Printers are handled completely differently.
@@ -1151,7 +1179,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return print_fsp_open(conn, fname, result);
        }
 
-       if (!parent_dirname_talloc(tmp_talloc_ctx(), fname, &parent_dir,
+       if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
                                   &newname)) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1175,7 +1203,17 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                   create_disposition, create_options, unx_mode,
                   oplock_request));
 
-       if ((pml = get_open_deferred_message(mid)) != NULL) {
+       if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) {
+               DEBUG(0, ("No smb request but not an internal only open!\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       /*
+        * Only non-internal opens can be deferred at all
+        */
+
+       if ((req != NULL)
+           && ((pml = get_open_deferred_message(req->mid)) != NULL)) {
                struct deferred_open_record *state =
                        (struct deferred_open_record *)pml->private_data.data;
 
@@ -1186,16 +1224,16 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                request_time = pml->request_time;
 
                /* Remove the deferred open entry under lock. */
-               lck = get_share_mode_lock(NULL, state->dev, state->inode, NULL, NULL);
+               lck = get_share_mode_lock(NULL, state->id, NULL, NULL);
                if (lck == NULL) {
                        DEBUG(0, ("could not get share mode lock\n"));
                } else {
-                       del_deferred_open_entry(lck, mid);
+                       del_deferred_open_entry(lck, req->mid);
                        TALLOC_FREE(lck);
                }
 
                /* Ensure we don't reprocess this message. */
-               remove_deferred_open_smb_message(mid);
+               remove_deferred_open_smb_message(req->mid);
        }
 
        status = check_name(conn, fname);
@@ -1398,8 +1436,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return status;
        }
 
-       fsp->dev = psbuf->st_dev;
-       fsp->inode = psbuf->st_ino;
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
        fsp->share_access = share_access;
        fsp->fh->private_options = create_options;
        fsp->access_mask = open_access_mask; /* We change this to the
@@ -1415,10 +1452,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        if (file_existed) {
-               dev = psbuf->st_dev;
-               inode = psbuf->st_ino;
+               id = vfs_file_id_from_sbuf(conn, psbuf);
 
-               lck = get_share_mode_lock(NULL, dev, inode,
+               lck = get_share_mode_lock(NULL, id,
                                          conn->connectpath,
                                          fname);
 
@@ -1429,8 +1465,10 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
 
                /* First pass - send break only on batch oplocks. */
-               if (delay_for_oplocks(lck, fsp, 1, oplock_request)) {
-                       schedule_defer_open(lck, request_time);
+               if ((req != NULL)
+                   && delay_for_oplocks(lck, fsp, req->mid, 1,
+                                        oplock_request)) {
+                       schedule_defer_open(lck, request_time, req);
                        TALLOC_FREE(lck);
                        file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
@@ -1447,8 +1485,10 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                         * status again. */
                        /* Second pass - send break for both batch or
                         * exclusive oplocks. */
-                       if (delay_for_oplocks(lck, fsp, 2, oplock_request)) {
-                               schedule_defer_open(lck, request_time);
+                       if ((req != NULL)
+                            && delay_for_oplocks(lck, fsp, req->mid, 2,
+                                                 oplock_request)) {
+                               schedule_defer_open(lck, request_time, req);
                                TALLOC_FREE(lck);
                                file_free(fsp);
                                return NT_STATUS_SHARING_VIOLATION;
@@ -1475,10 +1515,20 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                             NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
                                files_struct *fsp_dup;
 
+                               if (req == NULL) {
+                                       DEBUG(0, ("DOS open without an SMB "
+                                                 "request!\n"));
+                                       TALLOC_FREE(lck);
+                                       file_free(fsp);
+                                       return NT_STATUS_INTERNAL_ERROR;
+                               }
+
                                /* Use the client requested access mask here,
                                 * not the one we open with. */
-                               fsp_dup = fcb_or_dos_open(conn, fname, dev,
-                                                         inode, access_mask,
+                               fsp_dup = fcb_or_dos_open(conn, fname, id,
+                                                         req->smbpid,
+                                                         req->vuid,
+                                                         access_mask,
                                                          share_access,
                                                          create_options);
 
@@ -1550,13 +1600,13 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                                   a 1 second delay for share mode conflicts. */
 
                                state.delayed_for_oplocks = False;
-                               state.dev = dev;
-                               state.inode = inode;
+                               state.id = id;
 
-                               if (!request_timed_out(request_time,
-                                                      timeout)) {
+                               if ((req != NULL)
+                                   && !request_timed_out(request_time,
+                                                         timeout)) {
                                        defer_open(lck, request_time, timeout,
-                                                  &state);
+                                                  req, &state);
                                }
                        }
 
@@ -1600,7 +1650,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * open_file strips any O_TRUNC flags itself.
         */
 
-       fsp_open = open_file(fsp, conn, parent_dir, newname, fname, psbuf,
+       fsp_open = open_file(fsp, conn, req, parent_dir, newname, fname, psbuf,
                             flags|flags2, unx_mode, access_mask,
                             open_access_mask);
 
@@ -1629,10 +1679,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                 * Nadav Danieli <nadavd@exanet.com>. JRA.
                 */
 
-               dev = fsp->dev;
-               inode = fsp->inode;
+               id = fsp->file_id;
 
-               lck = get_share_mode_lock(NULL, dev, inode,
+               lck = get_share_mode_lock(NULL, id,
                                          conn->connectpath,
                                          fname);
 
@@ -1644,10 +1693,37 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
+               /* First pass - send break only on batch oplocks. */
+               if ((req != NULL)
+                   && delay_for_oplocks(lck, fsp, req->mid, 1,
+                                        oplock_request)) {
+                       schedule_defer_open(lck, request_time, req);
+                       TALLOC_FREE(lck);
+                       fd_close(conn, fsp);
+                       file_free(fsp);
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
+
                status = open_mode_check(conn, fname, lck,
                                         access_mask, share_access,
                                         create_options, &file_existed);
 
+               if (NT_STATUS_IS_OK(status)) {
+                       /* We might be going to allow this open. Check oplock
+                        * status again. */
+                       /* Second pass - send break for both batch or
+                        * exclusive oplocks. */
+                       if ((req != NULL)
+                           && delay_for_oplocks(lck, fsp, req->mid, 2,
+                                                oplock_request)) {
+                               schedule_defer_open(lck, request_time, req);
+                               TALLOC_FREE(lck);
+                               fd_close(conn, fsp);
+                               file_free(fsp);
+                               return NT_STATUS_SHARING_VIOLATION;
+                       }
+               }
+
                if (!NT_STATUS_IS_OK(status)) {
                        struct deferred_open_record state;
 
@@ -1655,8 +1731,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        file_free(fsp);
 
                        state.delayed_for_oplocks = False;
-                       state.dev = dev;
-                       state.inode = inode;
+                       state.id = id;
 
                        /* Do it all over again immediately. In the second
                         * round we will find that the file existed and handle
@@ -1665,8 +1740,10 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                         * "goto top of this function", but don't tell
                         * anybody... */
 
-                       defer_open(lck, request_time, timeval_zero(),
-                                  &state);
+                       if (req != NULL) {
+                               defer_open(lck, request_time, timeval_zero(),
+                                          req, &state);
+                       }
                        TALLOC_FREE(lck);
                        return status;
                }
@@ -1758,28 +1835,31 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        fsp->oplock_type = NO_OPLOCK;
                }
        }
-       set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type);
 
-       if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
-           info == FILE_WAS_SUPERSEDED) {
+       if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) {
+               new_file_created = True;
+       }
 
-               /* Handle strange delete on close create semantics. */
-               if (create_options & FILE_DELETE_ON_CLOSE) {
-                       status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+       set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created);
 
-                       if (!NT_STATUS_IS_OK(status)) {
-                               /* Remember to delete the mode we just added. */
-                               del_share_mode(lck, fsp);
-                               TALLOC_FREE(lck);
-                               fd_close(conn,fsp);
-                               file_free(fsp);
-                               return status;
-                       }
-                       /* Note that here we set the *inital* delete on close flag,
-                          not the regular one. The magic gets handled in close. */
-                       fsp->initial_delete_on_close = True;
+       /* Handle strange delete on close create semantics. */
+       if ((create_options & FILE_DELETE_ON_CLOSE) && can_set_initial_delete_on_close(lck)) {
+               status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       /* Remember to delete the mode we just added. */
+                       del_share_mode(lck, fsp);
+                       TALLOC_FREE(lck);
+                       fd_close(conn,fsp);
+                       file_free(fsp);
+                       return status;
                }
+               /* Note that here we set the *inital* delete on close flag,
+                  not the regular one. The magic gets handled in close. */
+               fsp->initial_delete_on_close = True;
+       }
        
+       if (new_file_created) {
                /* Files should be initially set as archive */
                if (lp_map_archive(SNUM(conn)) ||
                    lp_store_dos_attributes(SNUM(conn))) {
@@ -1837,7 +1917,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
        /* If this is a successful open, we must remove any deferred open
         * records. */
-       del_deferred_open_entry(lck, mid);
+       if (req != NULL) {
+               del_deferred_open_entry(lck, req->mid);
+       }
        TALLOC_FREE(lck);
 
        conn->num_files_open++;
@@ -1867,8 +1949,8 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
 
        /* note! we must use a non-zero desired access or we don't get
            a real file descriptor. Oh what a twisted web we weave. */
-       status = open_file(fsp, conn, NULL, NULL, fname, psbuf, O_WRONLY, 0,
-                          FILE_WRITE_DATA, FILE_WRITE_DATA);
+       status = open_file(fsp, conn, NULL, NULL, NULL, fname, psbuf, O_WRONLY,
+                          0, FILE_WRITE_DATA, FILE_WRITE_DATA);
 
        /* 
         * This is not a user visible file open.
@@ -1901,11 +1983,11 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                                uint32 file_attributes,
                                SMB_STRUCT_STAT *psbuf)
 {
-       int ret= -1;
        mode_t mode;
        char *parent_dir;
        const char *dirname;
        NTSTATUS status;
+       bool posix_open = false;
 
        if(!CAN_WRITE(conn)) {
                DEBUG(5,("mkdir_internal: failing create on read-only share "
@@ -1918,18 +2000,19 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return status;
        }
 
-       if (!parent_dirname_talloc(tmp_talloc_ctx(), name, &parent_dir,
+       if (!parent_dirname_talloc(talloc_tos(), name, &parent_dir,
                                   &dirname)) {
                return NT_STATUS_NO_MEMORY;
        }
 
        if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               posix_open = true;
                mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
        } else {
                mode = unix_mode(conn, aDIR, name, parent_dir);
        }
 
-       if ((ret=SMB_VFS_MKDIR(conn, name, mode)) != 0) {
+       if (SMB_VFS_MKDIR(conn, name, mode) != 0) {
                return map_nt_error_from_unix(errno);
        }
 
@@ -1948,6 +2031,14 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       if (lp_store_dos_attributes(SNUM(conn))) {
+               if (!posix_open) {
+                       file_set_dosmode(conn, name,
+                                file_attributes | aDIR, NULL,
+                                parent_dir);
+               }
+       }
+
        if (lp_inherit_perms(SNUM(conn))) {
                inherit_access_acl(conn, parent_dir, name, mode);
        }
@@ -1981,6 +2072,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
 ****************************************************************************/
 
 NTSTATUS open_directory(connection_struct *conn,
+                       struct smb_request *req,
                        const char *fname,
                        SMB_STRUCT_STAT *psbuf,
                        uint32 access_mask,
@@ -2096,10 +2188,9 @@ NTSTATUS open_directory(connection_struct *conn,
         */
        
        fsp->mode = psbuf->st_mode;
-       fsp->inode = psbuf->st_ino;
-       fsp->dev = psbuf->st_dev;
-       fsp->vuid = current_user.vuid;
-       fsp->file_pid = global_smbpid;
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+       fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
+       fsp->file_pid = req ? req->smbpid : 0;
        fsp->can_lock = False;
        fsp->can_read = False;
        fsp->can_write = False;
@@ -2118,7 +2209,7 @@ NTSTATUS open_directory(connection_struct *conn,
 
        string_set(&fsp->fsp_name,fname);
 
-       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode,
+       lck = get_share_mode_lock(NULL, fsp->file_id,
                                  conn->connectpath,
                                  fname);
 
@@ -2138,7 +2229,7 @@ NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
-       set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK);
+       set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK, True);
 
        /* For directories the delete on close bit at open time seems
           always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
@@ -2177,7 +2268,7 @@ NTSTATUS create_directory(connection_struct *conn, const char *directory)
 
        SET_STAT_INVALID(sbuf);
        
-       status = open_directory(conn, directory, &sbuf,
+       status = open_directory(conn, NULL, directory, &sbuf,
                                FILE_READ_ATTRIBUTES, /* Just a stat open */
                                FILE_SHARE_NONE, /* Ignored for stat opens */
                                FILE_CREATE,
@@ -2197,8 +2288,9 @@ NTSTATUS create_directory(connection_struct *conn, const char *directory)
  Open a pseudo-file (no locking checks - a 'stat' open).
 ****************************************************************************/
 
-NTSTATUS open_file_stat(connection_struct *conn, const char *fname,
-                       SMB_STRUCT_STAT *psbuf, files_struct **result)
+NTSTATUS open_file_stat(connection_struct *conn, struct smb_request *req,
+                       const char *fname, SMB_STRUCT_STAT *psbuf,
+                       files_struct **result)
 {
        files_struct *fsp = NULL;
        NTSTATUS status;
@@ -2224,10 +2316,9 @@ NTSTATUS open_file_stat(connection_struct *conn, const char *fname,
         */
        
        fsp->mode = psbuf->st_mode;
-       fsp->inode = psbuf->st_ino;
-       fsp->dev = psbuf->st_dev;
-       fsp->vuid = current_user.vuid;
-       fsp->file_pid = global_smbpid;
+       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
+       fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
+       fsp->file_pid = req ? req->smbpid : 0;
        fsp->can_lock = False;
        fsp->can_read = False;
        fsp->can_write = False;
@@ -2250,34 +2341,37 @@ NTSTATUS open_file_stat(connection_struct *conn, const char *fname,
  smbd process.
 ****************************************************************************/
 
-void msg_file_was_renamed(int msg_type, struct process_id src,
-                         void *buf, size_t len, void *private_data)
+void msg_file_was_renamed(struct messaging_context *msg,
+                         void *private_data,
+                         uint32_t msg_type,
+                         struct server_id server_id,
+                         DATA_BLOB *data)
 {
        files_struct *fsp;
-       char *frm = (char *)buf;
-       SMB_DEV_T dev;
-       SMB_INO_T inode;
+       char *frm = (char *)data->data;
+       struct file_id id;
        const char *sharepath;
        const char *newname;
        size_t sp_len;
 
-       if (buf == NULL || len < MSG_FILE_RENAMED_MIN_SIZE + 2) {
-                DEBUG(0, ("msg_file_was_renamed: Got invalid msg len %d\n", (int)len));
+       if (data->data == NULL
+           || data->length < MSG_FILE_RENAMED_MIN_SIZE + 2) {
+                DEBUG(0, ("msg_file_was_renamed: Got invalid msg len %d\n",
+                         (int)data->length));
                 return;
         }
 
        /* Unpack the message. */
-       dev = DEV_T_VAL(frm,0);
-       inode = INO_T_VAL(frm,8);
+       pull_file_id_16(frm, &id);
        sharepath = &frm[16];
        newname = sharepath + strlen(sharepath) + 1;
        sp_len = strlen(sharepath);
 
        DEBUG(10,("msg_file_was_renamed: Got rename message for sharepath %s, new name %s, "
-               "dev %x, inode  %.0f\n",
-               sharepath, newname, (unsigned int)dev, (double)inode ));
+               "file_id %s\n",
+                 sharepath, newname, file_id_string_tos(&id)));
 
-       for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
+       for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
                if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) {
                        DEBUG(10,("msg_file_was_renamed: renaming file fnum %d from %s -> %s\n",
                                fsp->fnum, fsp->fsp_name, newname ));