r23150: Fix Samba3 in the build farm again. In the case where the
[sfrench/samba-autobuild/.git] / source / smbd / open.c
index 49dfad3bc00c50322ac0313557b738037bae610b..ccd12c6946d40a9755de164821cca04a0e79d8cb 100644 (file)
@@ -38,43 +38,48 @@ struct deferred_open_record {
  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);
 }
@@ -206,6 +211,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 +294,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,6 +316,8 @@ static NTSTATUS open_file(files_struct *fsp,
                                                            fsp);
                        }
 
+                       notify_fname(conn, NOTIFY_ACTION_ADDED,
+                                    FILE_NOTIFY_CHANGE_FILE_NAME, path);
                }
 
        } else {
@@ -331,7 +340,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;
                }
@@ -367,11 +376,6 @@ 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)) {
-               fsp->aio_write_behind = True;
-       }
 
        string_set(&fsp->fsp_name, path);
        fsp->wcp = NULL; /* Write cache pointer. */
@@ -650,7 +654,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) {
@@ -738,10 +742,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;
@@ -1115,6 +1122,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        int flags2=0;
        BOOL file_existed = VALID_STAT(*psbuf);
        BOOL def_acl = False;
+       BOOL posix_open = False;
+       BOOL new_file_created = False;
        SMB_DEV_T dev = 0;
        SMB_INO_T inode = 0;
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
@@ -1153,10 +1162,16 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                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 "
@@ -1194,9 +1209,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 */
@@ -1291,7 +1308,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,
@@ -1356,7 +1373,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
@@ -1390,6 +1411,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        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);
 
@@ -1627,6 +1650,15 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
+               /* First pass - send break only on batch oplocks. */
+               if (delay_for_oplocks(lck, fsp, 1, oplock_request)) {
+                       schedule_defer_open(lck, request_time);
+                       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);
@@ -1654,6 +1686,14 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        return status;
                }
 
+               if (delay_for_oplocks(lck, fsp, 2, oplock_request)) {
+                       schedule_defer_open(lck, request_time);
+                       TALLOC_FREE(lck);
+                       fd_close(conn, fsp);
+                       file_free(fsp);
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
+
                /*
                 * We exit this block with the share entry *locked*.....
                 */
@@ -1741,36 +1781,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. */
-                       set_delete_on_close_token(lck, &current_user.ut);
-                       lck->initial_delete_on_close = True;
-                       lck->modified = 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 +1822,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.. */
@@ -1872,17 +1915,18 @@ 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;
@@ -1904,9 +1948,13 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                return NT_STATUS_NO_MEMORY;
        }
 
-       mode = unix_mode(conn, aDIR, name, parent_dir);
+       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               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);
        }
 
@@ -1929,15 +1977,17 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                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,6 +1995,9 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
                change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
        }
 
+       notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
+                    name);
+
        return NT_STATUS_OK;
 }
 
@@ -1959,6 +2012,7 @@ NTSTATUS open_directory(connection_struct *conn,
                        uint32 share_access,
                        uint32 create_disposition,
                        uint32 create_options,
+                       uint32 file_attributes,
                        int *pinfo,
                        files_struct **result)
 {
@@ -1970,12 +2024,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 ));
@@ -2002,7 +2057,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,
@@ -2019,7 +2078,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;
@@ -2077,6 +2139,8 @@ 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,
@@ -2099,21 +2163,23 @@ 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. */
        if (create_options & FILE_DELETE_ON_CLOSE) {
                status = can_set_delete_on_close(fsp, True, 0);
-               if (!NT_STATUS_IS_OK(status)) {
+               if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
                        TALLOC_FREE(lck);
                        file_free(fsp);
                        return status;
                }
 
-               set_delete_on_close_token(lck, &current_user.ut);
-               lck->initial_delete_on_close = True;
-               lck->modified = True;
+               if (NT_STATUS_IS_OK(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;
+               }
        }
 
        TALLOC_FREE(lck);
@@ -2139,7 +2205,11 @@ NTSTATUS create_directory(connection_struct *conn, const char *directory)
        status = open_directory(conn, 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);
@@ -2205,18 +2275,24 @@ 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;
+       char *frm = (char *)data->data;
        SMB_DEV_T dev;
        SMB_INO_T inode;
        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",
+                         data->length));
                 return;
         }