Change the other two places where we set a security descriptor given by the client...
[ambi/samba-autobuild/.git] / source3 / smbd / open.c
index 8a5273ef14e9f2b6c5c575c0fbaf8e9beb1af894..415f6adf2e2f6706183ef74b1d577202f8c5e39f 100644 (file)
@@ -35,6 +35,7 @@ extern const struct generic_mapping file_generic_mapping;
 
 struct deferred_open_record {
         bool delayed_for_oplocks;
+       bool async_open;
         struct file_id id;
 };
 
@@ -291,7 +292,26 @@ static NTSTATUS fd_open(struct connection_struct *conn,
 
        fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
        if (fsp->fh->fd == -1) {
-               status = map_nt_error_from_unix(errno);
+               int posix_errno = errno;
+#ifdef O_NOFOLLOW
+#if defined(ENOTSUP) && defined(OSF1)
+               /* handle special Tru64 errno */
+               if (errno == ENOTSUP) {
+                       posix_errno = ELOOP;
+               }
+#endif /* ENOTSUP */
+#ifdef EFTYPE
+               /* fix broken NetBSD errno */
+               if (errno == EFTYPE) {
+                       posix_errno = ELOOP;
+               }
+#endif /* EFTYPE */
+               /* fix broken FreeBSD errno */
+               if (errno == EMLINK) {
+                       posix_errno = ELOOP;
+               }
+#endif /* O_NOFOLLOW */
+               status = map_nt_error_from_unix(posix_errno);
                if (errno == EMFILE) {
                        static time_t last_warned = 0L;
 
@@ -513,6 +533,107 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
        return status;
 }
 
+/****************************************************************************
+ Open a file - returning a guaranteed ATOMIC indication of if the
+ file was created or not.
+****************************************************************************/
+
+static NTSTATUS fd_open_atomic(struct connection_struct *conn,
+                       files_struct *fsp,
+                       int flags,
+                       mode_t mode,
+                       bool *file_created)
+{
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       bool file_existed = VALID_STAT(fsp->fsp_name->st);
+
+       *file_created = false;
+
+       if (!(flags & O_CREAT)) {
+               /*
+                * We're not creating the file, just pass through.
+                */
+               return fd_open(conn, fsp, flags, mode);
+       }
+
+       if (flags & O_EXCL) {
+               /*
+                * Fail if already exists, just pass through.
+                */
+               status = fd_open(conn, fsp, flags, mode);
+               if (NT_STATUS_IS_OK(status)) {
+                       /*
+                        * Here we've opened with O_CREAT|O_EXCL
+                        * and got success. We *know* we created
+                        * this file.
+                        */
+                       *file_created = true;
+               }
+               return status;
+       }
+
+       /*
+        * Now it gets tricky. We have O_CREAT, but not O_EXCL.
+        * To know absolutely if we created the file or not,
+        * we can never call O_CREAT without O_EXCL. So if
+        * we think the file existed, try without O_CREAT|O_EXCL.
+        * If we think the file didn't exist, try with
+        * O_CREAT|O_EXCL. Keep bouncing between these two
+        * requests until either the file is created, or
+        * opened. Either way, we keep going until we get
+        * a returnable result (error, or open/create).
+        */
+
+       while(1) {
+               int curr_flags = flags;
+
+               if (file_existed) {
+                       /* Just try open, do not create. */
+                       curr_flags &= ~(O_CREAT);
+                       status = fd_open(conn, fsp, curr_flags, mode);
+                       if (NT_STATUS_EQUAL(status,
+                                       NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                               /*
+                                * Someone deleted it in the meantime.
+                                * Retry with O_EXCL.
+                                */
+                               file_existed = false;
+                               DEBUG(10,("fd_open_atomic: file %s existed. "
+                                       "Retry.\n",
+                                       smb_fname_str_dbg(fsp->fsp_name)));
+                                       continue;
+                       }
+               } else {
+                       /* Try create exclusively, fail if it exists. */
+                       curr_flags |= O_EXCL;
+                       status = fd_open(conn, fsp, curr_flags, mode);
+                       if (NT_STATUS_EQUAL(status,
+                                       NT_STATUS_OBJECT_NAME_COLLISION)) {
+                               /*
+                                * Someone created it in the meantime.
+                                * Retry without O_CREAT.
+                                */
+                               file_existed = true;
+                               DEBUG(10,("fd_open_atomic: file %s "
+                                       "did not exist. Retry.\n",
+                                       smb_fname_str_dbg(fsp->fsp_name)));
+                               continue;
+                       }
+                       if (NT_STATUS_IS_OK(status)) {
+                               /*
+                                * Here we've opened with O_CREAT|O_EXCL
+                                * and got success. We *know* we created
+                                * this file.
+                                */
+                               *file_created = true;
+                       }
+               }
+               /* Create is done, or failed. */
+               break;
+       }
+       return status;
+}
+
 /****************************************************************************
  Open a file.
 ****************************************************************************/
@@ -524,14 +645,14 @@ static NTSTATUS open_file(files_struct *fsp,
                          int flags,
                          mode_t unx_mode,
                          uint32 access_mask, /* client requested access mask. */
-                         uint32 open_access_mask) /* what we're actually using in the open. */
+                         uint32 open_access_mask, /* what we're actually using in the open. */
+                         bool *p_file_created)
 {
        struct smb_filename *smb_fname = fsp->fsp_name;
        NTSTATUS status = NT_STATUS_OK;
        int accmode = (flags & O_ACCMODE);
        int local_flags = flags;
        bool file_existed = VALID_STAT(fsp->fsp_name->st);
-       bool file_created = false;
 
        fsp->fh->fd = -1;
        errno = EPERM;
@@ -586,6 +707,7 @@ static NTSTATUS open_file(files_struct *fsp,
            (!file_existed && (local_flags & O_CREAT)) ||
            ((local_flags & O_TRUNC) == O_TRUNC) ) {
                const char *wild;
+               int ret;
 
                /*
                 * We can't actually truncate here as the file may be locked.
@@ -650,7 +772,8 @@ static NTSTATUS open_file(files_struct *fsp,
                }
 
                /* Actually do the open */
-               status = fd_open(conn, fsp, local_flags, unx_mode);
+               status = fd_open_atomic(conn, fsp, local_flags,
+                               unx_mode, p_file_created);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
                                 "(flags=%d)\n", smb_fname_str_dbg(smb_fname),
@@ -658,70 +781,24 @@ static NTSTATUS open_file(files_struct *fsp,
                        return status;
                }
 
-               if ((local_flags & O_CREAT) && !file_existed) {
-                       file_created = true;
-               }
-
-       } else {
-               fsp->fh->fd = -1; /* What we used to call a stat open. */
-               if (!file_existed) {
-                       /* File must exist for a stat open. */
-                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-               }
-
-               status = smbd_check_access_rights(conn,
-                               smb_fname,
-                               access_mask);
-
-               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
-                               fsp->posix_open &&
-                               S_ISLNK(smb_fname->st.st_ex_mode)) {
-                       /* This is a POSIX stat open for delete
-                        * or rename on a symlink that points
-                        * nowhere. Allow. */
-                       DEBUG(10,("open_file: allowing POSIX "
-                                 "open on bad symlink %s\n",
-                                 smb_fname_str_dbg(smb_fname)));
-                       status = NT_STATUS_OK;
-               }
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(10,("open_file: "
-                               "smbd_check_access_rights on file "
-                               "%s returned %s\n",
-                               smb_fname_str_dbg(smb_fname),
-                               nt_errstr(status) ));
-                       return status;
-               }
-       }
-
-       if (!file_existed) {
-               int ret;
-
-               if (fsp->fh->fd == -1) {
-                       ret = SMB_VFS_STAT(conn, smb_fname);
-               } else {
-                       ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
-                       /* If we have an fd, this stat should succeed. */
-                       if (ret == -1) {
-                               DEBUG(0,("Error doing fstat on open file %s "
-                                        "(%s)\n",
-                                        smb_fname_str_dbg(smb_fname),
-                                        strerror(errno) ));
-                       }
-               }
-
-               /* For a non-io open, this stat failing means file not found. JRA */
+               ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
                if (ret == -1) {
+                       /* If we have an fd, this stat should succeed. */
+                       DEBUG(0,("Error doing fstat on open file %s "
+                               "(%s)\n",
+                               smb_fname_str_dbg(smb_fname),
+                               strerror(errno) ));
                        status = map_nt_error_from_unix(errno);
                        fd_close(fsp);
                        return status;
                }
 
-               if (file_created) {
+               if (*p_file_created) {
+                       /* We created this file. */
+
                        bool need_re_stat = false;
                        /* Do all inheritance work after we've
-                          done a successful stat call and filled
+                          done a successful fstat call and filled
                           in the stat struct in fsp->fsp_name. */
 
                        /* Inherit the ACL if required */
@@ -740,17 +817,13 @@ static NTSTATUS open_file(files_struct *fsp,
                        }
 
                        if (need_re_stat) {
-                               if (fsp->fh->fd == -1) {
-                                       ret = SMB_VFS_STAT(conn, smb_fname);
-                               } else {
-                                       ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
-                                       /* If we have an fd, this stat should succeed. */
-                                       if (ret == -1) {
-                                               DEBUG(0,("Error doing fstat on open file %s "
-                                                        "(%s)\n",
-                                                        smb_fname_str_dbg(smb_fname),
-                                                        strerror(errno) ));
-                                       }
+                               ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
+                               /* If we have an fd, this stat should succeed. */
+                               if (ret == -1) {
+                                       DEBUG(0,("Error doing fstat on open file %s "
+                                                "(%s)\n",
+                                                smb_fname_str_dbg(smb_fname),
+                                                strerror(errno) ));
                                }
                        }
 
@@ -758,6 +831,37 @@ static NTSTATUS open_file(files_struct *fsp,
                                     FILE_NOTIFY_CHANGE_FILE_NAME,
                                     smb_fname->base_name);
                }
+       } else {
+               fsp->fh->fd = -1; /* What we used to call a stat open. */
+               if (!file_existed) {
+                       /* File must exist for a stat open. */
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               }
+
+               status = smbd_check_access_rights(conn,
+                               smb_fname,
+                               access_mask);
+
+               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+                               fsp->posix_open &&
+                               S_ISLNK(smb_fname->st.st_ex_mode)) {
+                       /* This is a POSIX stat open for delete
+                        * or rename on a symlink that points
+                        * nowhere. Allow. */
+                       DEBUG(10,("open_file: allowing POSIX "
+                                 "open on bad symlink %s\n",
+                                 smb_fname_str_dbg(smb_fname)));
+                       status = NT_STATUS_OK;
+               }
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10,("open_file: "
+                               "smbd_check_access_rights on file "
+                               "%s returned %s\n",
+                               smb_fname_str_dbg(smb_fname),
+                               nt_errstr(status) ));
+                       return status;
+               }
        }
 
        /*
@@ -776,13 +880,10 @@ static NTSTATUS open_file(files_struct *fsp,
        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)) {
-               fsp->can_write = False;
-       } else {
-               fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ?
-                       True : False;
-       }
+       fsp->can_read = ((access_mask & FILE_READ_DATA) != 0);
+       fsp->can_write =
+               CAN_WRITE(conn) &&
+               ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
        fsp->print_file = NULL;
        fsp->modified = False;
        fsp->sent_oplock_break = NO_BREAK_SENT;
@@ -894,9 +995,10 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
                                      int num,
                                      struct share_mode_entry *share_entry)
 {
+       struct server_id self = messaging_server_id(sconn->msg_ctx);
        files_struct *fsp;
 
-       if (!procid_is_me(&share_entry->pid)) {
+       if (!serverid_equal(&self, &share_entry->pid)) {
                return;
        }
 
@@ -984,12 +1086,23 @@ static NTSTATUS open_mode_check(connection_struct *conn,
                return NT_STATUS_OK;
        }
 
-       *file_existed = True;
-
        /* A delete on close prohibits everything */
 
        if (is_delete_on_close_set(lck, name_hash)) {
-               return NT_STATUS_DELETE_PENDING;
+               /*
+                * Check the delete on close token
+                * is valid. It could have been left
+                * after a server crash.
+                */
+               for(i = 0; i < lck->data->num_share_modes; i++) {
+                       if (!share_mode_stale_pid(lck->data, i)) {
+
+                               *file_existed = true;
+
+                               return NT_STATUS_DELETE_PENDING;
+                       }
+               }
+               return NT_STATUS_OK;
        }
 
        if (is_stat_open(access_mask)) {
@@ -1009,10 +1122,6 @@ static NTSTATUS open_mode_check(connection_struct *conn,
        }
 #endif
 
-       if (!lp_share_modes(SNUM(conn))) {
-               return NT_STATUS_OK;
-       }
-
        /* Now we check the share modes, after any oplock breaks. */
        for(i = 0; i < lck->data->num_share_modes; i++) {
 
@@ -1029,10 +1138,16 @@ static NTSTATUS open_mode_check(connection_struct *conn,
                                continue;
                        }
 
+                       *file_existed = true;
+
                        return NT_STATUS_SHARING_VIOLATION;
                }
        }
 
+       if (lck->data->num_share_modes != 0) {
+               *file_existed = true;
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -1128,6 +1243,10 @@ static void find_oplock_types(files_struct *fsp,
 
                if (BATCH_OPLOCK_TYPE(lck->data->share_modes[i].op_type)) {
                        /* batch - can only be one. */
+                       if (share_mode_stale_pid(lck->data, i)) {
+                               DEBUG(10, ("Found stale batch oplock\n"));
+                               continue;
+                       }
                        if (*pp_ex_or_batch || *pp_batch || *got_level2 || *got_no_oplock) {
                                smb_panic("Bad batch oplock entry.");
                        }
@@ -1135,6 +1254,10 @@ static void find_oplock_types(files_struct *fsp,
                }
 
                if (EXCLUSIVE_OPLOCK_TYPE(lck->data->share_modes[i].op_type)) {
+                       if (share_mode_stale_pid(lck->data, i)) {
+                               DEBUG(10, ("Found stale duplicate oplock\n"));
+                               continue;
+                       }
                        /* Exclusive or batch - can only be one. */
                        if (*pp_ex_or_batch || *got_level2 || *got_no_oplock) {
                                smb_panic("Bad exclusive or batch oplock entry.");
@@ -1144,6 +1267,11 @@ static void find_oplock_types(files_struct *fsp,
 
                if (LEVEL_II_OPLOCK_TYPE(lck->data->share_modes[i].op_type)) {
                        if (*pp_batch || *pp_ex_or_batch) {
+                               if (share_mode_stale_pid(lck->data, i)) {
+                                       DEBUG(10, ("Found stale LevelII "
+                                                  "oplock\n"));
+                                       continue;
+                               }
                                smb_panic("Bad levelII oplock entry.");
                        }
                        *got_level2 = true;
@@ -1151,6 +1279,11 @@ static void find_oplock_types(files_struct *fsp,
 
                if (lck->data->share_modes[i].op_type == NO_OPLOCK) {
                        if (*pp_batch || *pp_ex_or_batch) {
+                               if (share_mode_stale_pid(lck->data, i)) {
+                                       DEBUG(10, ("Found stale NO_OPLOCK "
+                                                  "entry\n"));
+                                       continue;
+                               }
                                smb_panic("Bad no oplock entry.");
                        }
                        *got_no_oplock = true;
@@ -1231,7 +1364,9 @@ static void grant_fsp_oplock_type(files_struct *fsp,
                DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
                        fsp->oplock_type, fsp_str_dbg(fsp)));
                return;
-       } else if (lp_locking(fsp->conn->params) && file_has_brlocks(fsp)) {
+       }
+
+       if (lp_locking(fsp->conn->params) && file_has_brlocks(fsp)) {
                DEBUG(10,("grant_fsp_oplock_type: file %s has byte range locks\n",
                        fsp_str_dbg(fsp)));
                fsp->oplock_type = NO_OPLOCK;
@@ -1281,8 +1416,8 @@ static void grant_fsp_oplock_type(files_struct *fsp,
                  fsp->oplock_type, fsp_str_dbg(fsp)));
 }
 
-bool request_timed_out(struct timeval request_time,
-                      struct timeval timeout)
+static bool request_timed_out(struct timeval request_time,
+                             struct timeval timeout)
 {
        struct timeval now, end_time;
        GetTimeOfDay(&now);
@@ -1300,20 +1435,24 @@ static void defer_open(struct share_mode_lock *lck,
                       struct smb_request *req,
                       struct deferred_open_record *state)
 {
-       int i;
+       struct server_id self = messaging_server_id(req->sconn->msg_ctx);
 
        /* Paranoia check */
 
-       for (i=0; i<lck->data->num_share_modes; i++) {
-               struct share_mode_entry *e = &lck->data->share_modes[i];
+       if (lck) {
+               int i;
 
-               if (is_deferred_open_entry(e) &&
-                   procid_is_me(&e->pid) &&
-                   (e->op_mid == req->mid)) {
-                       DEBUG(0, ("Trying to defer an already deferred "
-                               "request: mid=%llu, exiting\n",
-                               (unsigned long long)req->mid));
-                       exit_server("attempt to defer a deferred request");
+               for (i=0; i<lck->data->num_share_modes; i++) {
+                       struct share_mode_entry *e = &lck->data->share_modes[i];
+
+                       if (is_deferred_open_entry(e) &&
+                           serverid_equal(&self, &e->pid) &&
+                           (e->op_mid == req->mid)) {
+                               DEBUG(0, ("Trying to defer an already deferred "
+                                       "request: mid=%llu, exiting\n",
+                                       (unsigned long long)req->mid));
+                               exit_server("attempt to defer a deferred request");
+                       }
                }
        }
 
@@ -1329,8 +1468,9 @@ static void defer_open(struct share_mode_lock *lck,
                                       state->id, (char *)state, sizeof(*state))) {
                exit_server("push_deferred_open_message_smb failed");
        }
-       add_deferred_open(lck, req->mid, request_time,
-                         messaging_server_id(req->sconn->msg_ctx), state->id);
+       if (lck) {
+               add_deferred_open(lck, req->mid, request_time, self, state->id);
+       }
 }
 
 
@@ -1386,16 +1526,16 @@ bool open_match_attributes(connection_struct *conn,
  Try and find a duplicated file handle.
 ****************************************************************************/
 
-NTSTATUS fcb_or_dos_open(struct smb_request *req,
-                                    connection_struct *conn,
-                                    files_struct *fsp_to_dup_into,
-                                    const struct smb_filename *smb_fname,
-                                    struct file_id id,
-                                    uint16 file_pid,
-                                    uint16 vuid,
-                                    uint32 access_mask,
-                                    uint32 share_access,
-                                    uint32 create_options)
+static NTSTATUS fcb_or_dos_open(struct smb_request *req,
+                               connection_struct *conn,
+                               files_struct *fsp_to_dup_into,
+                               const struct smb_filename *smb_fname,
+                               struct file_id id,
+                               uint16 file_pid,
+                               uint64_t vuid,
+                               uint32 access_mask,
+                               uint32 share_access,
+                               uint32 create_options)
 {
        files_struct *fsp;
 
@@ -1406,9 +1546,9 @@ NTSTATUS fcb_or_dos_open(struct smb_request *req,
            fsp = file_find_di_next(fsp)) {
 
                DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, "
-                         "vuid = %u, file_pid = %u, private_options = 0x%x "
+                         "vuid = %llu, file_pid = %u, private_options = 0x%x "
                          "access_mask = 0x%x\n", fsp_str_dbg(fsp),
-                         fsp->fh->fd, (unsigned int)fsp->vuid,
+                         fsp->fh->fd, (unsigned long long)fsp->vuid,
                          (unsigned int)fsp->file_pid,
                          (unsigned int)fsp->fh->private_options,
                          (unsigned int)fsp->access_mask ));
@@ -1473,6 +1613,7 @@ static void schedule_defer_open(struct share_mode_lock *lck,
           a 1 second delay for share mode conflicts. */
 
        state.delayed_for_oplocks = True;
+       state.async_open = false;
        state.id = lck->data->id;
 
        if (!request_timed_out(request_time, timeout)) {
@@ -1480,6 +1621,27 @@ static void schedule_defer_open(struct share_mode_lock *lck,
        }
 }
 
+/****************************************************************************
+ Reschedule an open call that went asynchronous.
+****************************************************************************/
+
+static void schedule_async_open(struct timeval request_time,
+                               struct smb_request *req)
+{
+       struct deferred_open_record state;
+       struct timeval timeout;
+
+       timeout = timeval_set(20, 0);
+
+       ZERO_STRUCT(state);
+       state.delayed_for_oplocks = false;
+       state.async_open = true;
+
+       if (!request_timed_out(request_time, timeout)) {
+               defer_open(NULL, request_time, timeout, req, &state);
+       }
+}
+
 /****************************************************************************
  Work out what access_mask to use from what the client sent us.
 ****************************************************************************/
@@ -1602,6 +1764,17 @@ void remove_deferred_open_entry(struct file_id id, uint64_t mid,
        TALLOC_FREE(lck);
 }
 
+/****************************************************************************
+ Return true if this is a state pointer to an asynchronous create.
+****************************************************************************/
+
+bool is_deferred_open_async(const void *ptr)
+{
+       const struct deferred_open_record *state = (const struct deferred_open_record *)ptr;
+
+       return state->async_open;
+}
+
 /****************************************************************************
  Open a file with a share mode. Passed in an already created files_struct *.
 ****************************************************************************/
@@ -1637,6 +1810,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        uint32 open_access_mask = access_mask;
        NTSTATUS status;
        char *parent_dir;
+       SMB_STRUCT_STAT saved_stat = smb_fname->st;
 
        if (conn->printer) {
                /*
@@ -1706,16 +1880,23 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (get_deferred_open_message_state(req,
                                &request_time,
                                &ptr)) {
-
-                       struct deferred_open_record *state = (struct deferred_open_record *)ptr;
                        /* Remember the absolute time of the original
                           request with this mid. We'll use it later to
                           see if this has timed out. */
 
-                       /* Remove the deferred open entry under lock. */
-                       remove_deferred_open_entry(
-                               state->id, req->mid,
-                               messaging_server_id(req->sconn->msg_ctx));
+                       /* If it was an async create retry, the file
+                          didn't exist. */
+
+                       if (is_deferred_open_async(ptr)) {
+                               SET_STAT_INVALID(smb_fname->st);
+                               file_existed = false;
+                       } else {
+                               struct deferred_open_record *state = (struct deferred_open_record *)ptr;
+                               /* Remove the deferred open entry under lock. */
+                               remove_deferred_open_entry(
+                                       state->id, req->mid,
+                                       messaging_server_id(req->sconn->msg_ctx));
+                       }
 
                        /* Ensure we don't reprocess this message. */
                        remove_deferred_open_message_smb(req->sconn, req->mid);
@@ -2107,6 +2288,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                                   a 1 second delay for share mode conflicts. */
 
                                state.delayed_for_oplocks = False;
+                               state.async_open = false;
                                state.id = id;
 
                                if ((req != NULL)
@@ -2158,13 +2340,40 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
        fsp_open = open_file(fsp, conn, req, parent_dir,
                             flags|flags2, unx_mode, access_mask,
-                            open_access_mask);
+                            open_access_mask, &new_file_created);
 
        if (!NT_STATUS_IS_OK(fsp_open)) {
+               if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_RETRY)) {
+                       schedule_async_open(request_time, req);
+               }
                TALLOC_FREE(lck);
                return fsp_open;
        }
 
+       if (file_existed && !check_same_dev_ino(&saved_stat, &smb_fname->st)) {
+               /*
+                * The file did exist, but some other (local or NFS)
+                * process either renamed/unlinked and re-created the
+                * file with different dev/ino after we walked the path,
+                * but before we did the open. We could retry the
+                * open but it's a rare enough case it's easier to
+                * just fail the open to prevent creating any problems
+                * in the open file db having the wrong dev/ino key.
+                */
+               TALLOC_FREE(lck);
+               fd_close(fsp);
+               DEBUG(1,("open_file_ntcreate: file %s - dev/ino mismatch. "
+                       "Old (dev=0x%llu, ino =0x%llu). "
+                       "New (dev=0x%llu, ino=0x%llu). Failing open "
+                       " with NT_STATUS_ACCESS_DENIED.\n",
+                        smb_fname_str_dbg(smb_fname),
+                        (unsigned long long)saved_stat.st_ex_dev,
+                        (unsigned long long)saved_stat.st_ex_ino,
+                        (unsigned long long)smb_fname->st.st_ex_dev,
+                        (unsigned long long)smb_fname->st.st_ex_ino));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (!file_existed) {
                struct share_mode_entry *batch_entry = NULL;
                struct share_mode_entry *exclusive_entry = NULL;
@@ -2248,6 +2457,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                        struct deferred_open_record state;
 
                        state.delayed_for_oplocks = False;
+                       state.async_open = false;
                        state.id = id;
 
                        /* Do it all over again immediately. In the second
@@ -2280,7 +2490,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        SMB_ASSERT(lck != NULL);
 
        /* Delete streams if create_disposition requires it */
-       if (file_existed && clear_ads &&
+       if (!new_file_created && clear_ads &&
            !is_ntfs_stream_smb_fname(smb_fname)) {
                status = delete_all_streams(conn, smb_fname->base_name);
                if (!NT_STATUS_IS_OK(status)) {
@@ -2320,9 +2530,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
         * If requested, truncate the file.
         */
 
-       if (file_existed && (flags2&O_TRUNC)) {
+       if (!new_file_created && (flags2&O_TRUNC)) {
                /*
-                * We are modifing the file after open - update the stat
+                * We are modifying the file after open - update the stat
                 * struct..
                 */
                if ((SMB_VFS_FTRUNCATE(fsp, 0) == -1) ||
@@ -2356,14 +2566,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (is_stat_open(open_access_mask)) {
                        fsp->oplock_type = NO_OPLOCK;
                }
+       }
 
+       if (new_file_created) {
+               info = FILE_WAS_CREATED;
+       } else {
                if (flags2 & O_TRUNC) {
                        info = FILE_WAS_OVERWRITTEN;
                } else {
                        info = FILE_WAS_OPENED;
                }
-       } else {
-               info = FILE_WAS_CREATED;
        }
 
        if (pinfo) {
@@ -2375,7 +2587,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
         * file structs.
         */
 
-       if (!set_file_oplock(fsp, fsp->oplock_type)) {
+       status = set_file_oplock(fsp, fsp->oplock_type);
+       if (!NT_STATUS_IS_OK(status)) {
                /*
                 * Could not get the kernel oplock or there are byte-range
                 * locks on the file.
@@ -2404,13 +2617,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                fsp->initial_delete_on_close = True;
        }
 
-       if (info == FILE_WAS_OVERWRITTEN
-           || info == FILE_WAS_CREATED
-           || info == FILE_WAS_SUPERSEDED) {
-               new_file_created = True;
-       }
-
-       if (new_file_created) {
+       if (info != FILE_WAS_OPENED) {
                /* Files should be initially set as archive */
                if (lp_map_archive(SNUM(conn)) ||
                    lp_store_dos_attributes(SNUM(conn))) {
@@ -2438,7 +2645,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
         * selected.
         */
 
-       if (!posix_open && !file_existed && !def_acl) {
+       if (!posix_open && new_file_created && !def_acl) {
 
                int saved_errno = errno; /* We might get ENOSYS in the next
                                          * call.. */
@@ -2535,7 +2742,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
 
        if(access_mask & ~(conn->share_access)) {
                DEBUG(5,("mkdir_internal: failing share access "
-                        "%s\n", lp_servicename(SNUM(conn))));
+                        "%s\n", lp_servicename(talloc_tos(), SNUM(conn))));
                return NT_STATUS_ACCESS_DENIED;
        }
 
@@ -2634,22 +2841,6 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-/****************************************************************************
- Ensure we didn't get symlink raced on opening a directory.
-****************************************************************************/
-
-bool check_same_stat(const SMB_STRUCT_STAT *sbuf1,
-                       const SMB_STRUCT_STAT *sbuf2)
-{
-       if (sbuf1->st_ex_uid != sbuf2->st_ex_uid ||
-                       sbuf1->st_ex_gid != sbuf2->st_ex_gid ||
-                       sbuf1->st_ex_dev != sbuf2->st_ex_dev ||
-                       sbuf1->st_ex_ino != sbuf2->st_ex_ino) {
-               return false;
-       }
-       return true;
-}
-
 /****************************************************************************
  Open a directory from an NT SMB call.
 ****************************************************************************/
@@ -2678,8 +2869,10 @@ static NTSTATUS open_directory(connection_struct *conn,
                return NT_STATUS_NOT_A_DIRECTORY;
        }
 
-       /* Ensure we have a directory attribute. */
-       file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
+       if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
+               /* Ensure we have a directory attribute. */
+               file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
+       }
 
        DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
                 "share_access = 0x%x create_options = 0x%x, "
@@ -3019,8 +3212,8 @@ void msg_file_was_renamed(struct messaging_context *msg,
            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_str_dbg(fsp),
+                       DEBUG(10,("msg_file_was_renamed: renaming file %s from %s -> %s\n",
+                               fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
                                smb_fname_str_dbg(smb_fname)));
                        status = fsp_set_smb_fname(fsp, smb_fname);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -3032,10 +3225,10 @@ void msg_file_was_renamed(struct messaging_context *msg,
                           actually within this share and adjust newname accordingly. */
                        DEBUG(10,("msg_file_was_renamed: share mismatch (sharepath %s "
                                "not sharepath %s) "
-                               "fnum %d from %s -> %s\n",
+                               "%s from %s -> %s\n",
                                fsp->conn->connectpath,
                                sharepath,
-                               fsp->fnum,
+                               fsp_fnum_dbg(fsp),
                                fsp_str_dbg(fsp),
                                smb_fname_str_dbg(smb_fname)));
                }
@@ -3450,6 +3643,11 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                        fsp->base_fsp = base_fsp;
                }
 
+               if (allocation_size) {
+                       fsp->initial_allocation_size = smb_roundup(fsp->conn,
+                                                       allocation_size);
+               }
+
                status = open_file_ntcreate(conn,
                                            req,
                                            access_mask,
@@ -3534,6 +3732,8 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                        fsp->initial_allocation_size = smb_roundup(
                                fsp->conn, (uint64_t)fsp->fsp_name->st.st_ex_size);
                }
+       } else {
+               fsp->initial_allocation_size = 0;
        }
 
        if ((info == FILE_WAS_CREATED) && lp_nt_acl_support(SNUM(conn)) &&
@@ -3557,15 +3757,11 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
 
                        fsp->access_mask = FILE_GENERIC_ALL;
 
-                       /* Convert all the generic bits. */
-                       security_acl_map_generic(sd->dacl, &file_generic_mapping);
-                       security_acl_map_generic(sd->sacl, &file_generic_mapping);
-
                        if (sec_info_sent & (SECINFO_OWNER|
                                                SECINFO_GROUP|
                                                SECINFO_DACL|
                                                SECINFO_SACL)) {
-                               status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
+                               status = set_sd(fsp, sd, sec_info_sent);
                        }
 
                        fsp->access_mask = saved_access_mask;