[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / open.c
index a5a8eacda00f973af5315c682201110746396bf9..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;
 }
 
 /****************************************************************************
  Close the file associated with a fsp.
 ****************************************************************************/
 
-int fd_close(struct connection_struct *conn,
-            files_struct *fsp)
+NTSTATUS fd_close(struct connection_struct *conn, files_struct *fsp)
 {
        if (fsp->fh->fd == -1) {
-               return 0; /* What we used to call a stat open. */
+               return NT_STATUS_OK; /* What we used to call a stat open. */
        }
        if (fsp->fh->ref_count > 1) {
-               return 0; /* Shared handle. Only close last reference. */
+               return NT_STATUS_OK; /* Shared handle. Only close last reference. */
        }
        return fd_close_posix(conn, fsp);
 }
@@ -115,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
@@ -140,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) ));
@@ -155,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)));
@@ -168,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;
        }
 
@@ -175,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,
@@ -188,7 +202,9 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 
  out:
 
+       TALLOC_FREE(ctx);
        vfs_ChDir(conn,saved_dir);
+       return status;
 }
 
 /****************************************************************************
@@ -197,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,
@@ -206,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);
@@ -288,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) {
@@ -309,8 +328,8 @@ static NTSTATUS open_file(files_struct *fsp,
                                                            fsp);
                        }
 
-                       notify_action(conn, parent_dir, name, -1,
-                                     NOTIFY_ACTION_ADDED);
+                       notify_fname(conn, NOTIFY_ACTION_ADDED,
+                                    FILE_NOTIFY_CHANGE_FILE_NAME, path);
                }
 
        } else {
@@ -333,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;
                }
@@ -352,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)) {
@@ -369,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;
        }
 
@@ -501,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);
        }
 
@@ -511,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",
@@ -540,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);
@@ -644,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)
 {
@@ -652,7 +672,7 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
        BOOL valid_entry = False;
        BOOL delay_it = False;
        BOOL have_level2 = False;
-       BOOL ret;
+       NTSTATUS status;
        char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
 
        if (oplock_request & INTERNAL_OPEN_ONLY) {
@@ -728,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);
@@ -740,10 +760,13 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
                SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
        }
 
-       ret = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST,
-                              msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
-       if (!ret) {
-               DEBUG(3, ("Could not send oplock break message\n"));
+       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)));
        }
 
        return True;
@@ -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.) */
@@ -1117,8 +1144,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        int flags2=0;
        BOOL file_existed = VALID_STAT(*psbuf);
        BOOL def_acl = False;
-       SMB_DEV_T dev = 0;
-       SMB_INO_T inode = 0;
+       BOOL posix_open = False;
+       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;
@@ -1126,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;
@@ -1135,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.
@@ -1150,15 +1179,21 @@ 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;
        }
 
-       /* We add aARCH to this as this mode is only used if the file is
-        * created new. */
-       unx_mode = unix_mode(conn, new_dos_attributes | aARCH, fname,
-                            parent_dir);
+       if (new_dos_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               posix_open = True;
+               unx_mode = (mode_t)(new_dos_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
+               new_dos_attributes = 0;
+       } else {
+               /* We add aARCH to this as this mode is only used if the file is
+                * created new. */
+               unx_mode = unix_mode(conn, new_dos_attributes | aARCH, fname,
+                                    parent_dir);
+       }
 
        DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x "
                   "access_mask=0x%x share_access=0x%x "
@@ -1168,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;
 
@@ -1179,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);
@@ -1196,9 +1241,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return status;
        } 
 
-       new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
-       if (file_existed) {
-               existing_dos_attributes = dos_mode(conn, fname, psbuf);
+       if (!posix_open) {
+               new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
+               if (file_existed) {
+                       existing_dos_attributes = dos_mode(conn, fname, psbuf);
+               }
        }
 
        /* ignore any oplock requests if oplocks are disabled */
@@ -1293,7 +1340,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        /* We only care about matching attributes on file exists and
         * overwrite. */
 
-       if (file_existed && ((create_disposition == FILE_OVERWRITE) ||
+       if (!posix_open && file_existed && ((create_disposition == FILE_OVERWRITE) ||
                             (create_disposition == FILE_OVERWRITE_IF))) {
                if (!open_match_attributes(conn, fname,
                                           existing_dos_attributes,
@@ -1358,7 +1405,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 #endif /* O_SYNC */
   
-       if (!CAN_WRITE(conn)) {
+       if (posix_open & (access_mask & FILE_APPEND_DATA)) {
+               flags2 |= O_APPEND;
+       }
+
+       if (!posix_open && !CAN_WRITE(conn)) {
                /*
                 * We should really return a permission denied error if either
                 * O_CREAT or O_TRUNC are set, but for compatibility with
@@ -1385,13 +1436,14 @@ 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
                                              * requested access_mask after
                                              * the open is done. */
+       fsp->posix_open = posix_open;
+
        /* Ensure no SAMBA_PRIVATE bits can be set. */
        fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
 
@@ -1400,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);
 
@@ -1414,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;
@@ -1432,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;
@@ -1460,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);
 
@@ -1535,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);
                                }
                        }
 
@@ -1585,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);
 
@@ -1614,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);
 
@@ -1629,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;
 
@@ -1640,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
@@ -1650,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;
                }
@@ -1743,34 +1835,39 @@ 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))) {
-                       file_set_dosmode(conn, fname,
+                       if (!posix_open) {
+                               file_set_dosmode(conn, fname,
                                         new_dos_attributes | aARCH, NULL,
                                         parent_dir);
+                       }
                }
        }
 
@@ -1779,7 +1876,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * selected.
         */
 
-       if (!file_existed && !def_acl) {
+       if (!posix_open && !file_existed && !def_acl) {
 
                int saved_errno = errno; /* We might get ENOSYS in the next
                                          * call.. */
@@ -1820,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++;
@@ -1850,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.
@@ -1872,21 +1971,23 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
  Close the fchmod file fd - ensure no locks are lost.
 ****************************************************************************/
 
-int close_file_fchmod(files_struct *fsp)
+NTSTATUS close_file_fchmod(files_struct *fsp)
 {
-       int ret = fd_close(fsp->conn, fsp);
+       NTSTATUS status = fd_close(fsp->conn, fsp);
        file_free(fsp);
-       return ret;
+       return status;
 }
 
-static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
-                              SMB_STRUCT_STAT *psbuf)
+static NTSTATUS mkdir_internal(connection_struct *conn,
+                               const char *name,
+                               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 "
@@ -1899,14 +2000,19 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                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;
        }
 
-       mode = unix_mode(conn, aDIR, name, parent_dir);
+       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);
        }
 
@@ -1925,19 +2031,29 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                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);
        }
 
-       /*
-        * Check if high bits should have been set,
-        * then (if bits are missing): add them.
-        * Consider bits automagically set by UNIX, i.e. SGID bit from parent
-        * dir.
-        */
-       if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && (mode & ~psbuf->st_mode)) {
-               SMB_VFS_CHMOD(conn, name,
-                             psbuf->st_mode | (mode & ~psbuf->st_mode));
+       if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
+               /*
+                * Check if high bits should have been set,
+                * then (if bits are missing): add them.
+                * Consider bits automagically set by UNIX, i.e. SGID bit from parent
+                * dir.
+                */
+               if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && (mode & ~psbuf->st_mode)) {
+                       SMB_VFS_CHMOD(conn, name,
+                                     psbuf->st_mode | (mode & ~psbuf->st_mode));
+               }
        }
 
        /* Change the owner if required. */
@@ -1945,8 +2061,8 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
        }
 
-       notify_action(conn, parent_dir, dirname, FILE_NOTIFY_CHANGE_DIR_NAME,
-                     NOTIFY_ACTION_ADDED);
+       notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
+                    name);
 
        return NT_STATUS_OK;
 }
@@ -1956,12 +2072,14 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
 ****************************************************************************/
 
 NTSTATUS open_directory(connection_struct *conn,
+                       struct smb_request *req,
                        const char *fname,
                        SMB_STRUCT_STAT *psbuf,
                        uint32 access_mask,
                        uint32 share_access,
                        uint32 create_disposition,
                        uint32 create_options,
+                       uint32 file_attributes,
                        int *pinfo,
                        files_struct **result)
 {
@@ -1973,12 +2091,13 @@ NTSTATUS open_directory(connection_struct *conn,
 
        DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
                 "share_access = 0x%x create_options = 0x%x, "
-                "create_disposition = 0x%x\n",
+                "create_disposition = 0x%x, file_attributes = 0x%x\n",
                 fname,
                 (unsigned int)access_mask,
                 (unsigned int)share_access,
                 (unsigned int)create_options,
-                (unsigned int)create_disposition));
+                (unsigned int)create_disposition,
+                (unsigned int)file_attributes));
 
        if (is_ntfs_stream_name(fname)) {
                DEBUG(0,("open_directory: %s is a stream name!\n", fname ));
@@ -2005,7 +2124,11 @@ NTSTATUS open_directory(connection_struct *conn,
                        /* If directory exists error. If directory doesn't
                         * exist create. */
 
-                       status = mkdir_internal(conn, fname, psbuf);
+                       status = mkdir_internal(conn,
+                                               fname,
+                                               file_attributes,
+                                               psbuf);
+
                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(2, ("open_directory: unable to create "
                                          "%s. Error was %s\n", fname,
@@ -2022,7 +2145,10 @@ NTSTATUS open_directory(connection_struct *conn,
                         * exist create.
                         */
 
-                       status = mkdir_internal(conn, fname, psbuf);
+                       status = mkdir_internal(conn,
+                                               fname,
+                                               file_attributes,
+                                               psbuf);
 
                        if (NT_STATUS_IS_OK(status)) {
                                info = FILE_WAS_CREATED;
@@ -2062,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;
@@ -2080,9 +2205,11 @@ NTSTATUS open_directory(connection_struct *conn,
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = True;
        fsp->is_stat = False;
+       fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False;
+
        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);
 
@@ -2102,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. */
@@ -2141,10 +2268,14 @@ 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, 0, NULL, &fsp);
+                               FILE_CREATE,
+                               0,
+                               FILE_ATTRIBUTE_DIRECTORY,
+                               NULL,
+                               &fsp);
 
        if (NT_STATUS_IS_OK(status)) {
                close_file(fsp, NORMAL_CLOSE);
@@ -2157,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;
@@ -2184,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;
@@ -2210,33 +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 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 ));