[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / open.c
index 62a4fe080766d8eda81c825ce65ceeb5f9f5660d..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 BOOL global_client_failed_oplock_break;
@@ -118,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
@@ -143,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) ));
@@ -158,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)));
@@ -171,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;
        }
 
@@ -178,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,
@@ -191,7 +202,9 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 
  out:
 
+       TALLOC_FREE(ctx);
        vfs_ChDir(conn,saved_dir);
+       return status;
 }
 
 /****************************************************************************
@@ -358,7 +371,7 @@ static NTSTATUS open_file(files_struct *fsp,
        }
 
        fsp->mode = psbuf->st_mode;
-       fsp->file_id = file_id_sbuf(psbuf);
+       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;
@@ -374,6 +387,10 @@ 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. */
@@ -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);
        }
 
@@ -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)
 {
@@ -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);
@@ -768,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 */
@@ -782,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");
                }
        }
@@ -795,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->id);
+       add_deferred_open(lck, req->mid, request_time, state->id);
 
        /*
         * Push the MID of this packet on the signing queue.
@@ -810,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);
 }
 
 
@@ -1065,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;
 
@@ -1096,7 +1118,7 @@ static void schedule_defer_open(struct share_mode_lock *lck, struct timeval requ
        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);
        }
 }
 
@@ -1157,7 +1179,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return print_fsp_open(conn, fname, result);
        }
 
-       if (!parent_dirname_talloc(tmp_talloc_ctx(), fname, &parent_dir,
+       if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
                                   &newname)) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1414,7 +1436,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return status;
        }
 
-       fsp->file_id = file_id_sbuf(psbuf);
+       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
@@ -1430,7 +1452,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        if (file_existed) {
-               id = file_id_sbuf(psbuf);
+               id = vfs_file_id_from_sbuf(conn, psbuf);
 
                lck = get_share_mode_lock(NULL, id,
                                          conn->connectpath,
@@ -1443,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;
@@ -1461,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;
@@ -1576,10 +1602,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                                state.delayed_for_oplocks = False;
                                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);
                                }
                        }
 
@@ -1667,8 +1694,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);
                        fd_close(conn, fsp);
                        file_free(fsp);
@@ -1684,8 +1713,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);
                                fd_close(conn, fsp);
                                file_free(fsp);
@@ -1709,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;
                }
@@ -1954,6 +1987,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
        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 "
@@ -1966,12 +2000,13 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return status;
        }
 
-       if (!parent_dirname_talloc(tmp_talloc_ctx(), name, &parent_dir,
+       if (!parent_dirname_talloc(talloc_tos(), name, &parent_dir,
                                   &dirname)) {
                return NT_STATUS_NO_MEMORY;
        }
 
        if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               posix_open = true;
                mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
        } else {
                mode = unix_mode(conn, aDIR, name, parent_dir);
@@ -1996,6 +2031,14 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       if (lp_store_dos_attributes(SNUM(conn))) {
+               if (!posix_open) {
+                       file_set_dosmode(conn, name,
+                                file_attributes | aDIR, NULL,
+                                parent_dir);
+               }
+       }
+
        if (lp_inherit_perms(SNUM(conn))) {
                inherit_access_acl(conn, parent_dir, name, mode);
        }
@@ -2145,7 +2188,7 @@ NTSTATUS open_directory(connection_struct *conn,
         */
        
        fsp->mode = psbuf->st_mode;
-       fsp->file_id = file_id_sbuf(psbuf);
+       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;
@@ -2273,7 +2316,7 @@ NTSTATUS open_file_stat(connection_struct *conn, struct smb_request *req,
         */
        
        fsp->mode = psbuf->st_mode;
-       fsp->file_id = file_id_sbuf(psbuf);
+       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;
@@ -2326,7 +2369,7 @@ void msg_file_was_renamed(struct messaging_context *msg,
 
        DEBUG(10,("msg_file_was_renamed: Got rename message for sharepath %s, new name %s, "
                "file_id %s\n",
-                 sharepath, newname, file_id_static_string(&id)));
+                 sharepath, newname, file_id_string_tos(&id)));
 
        for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
                if (memcmp(fsp->conn->connectpath, sharepath, sp_len) == 0) {