vfs3: Pass "lease" through SMB_VFS_CREATE_FILE
[metze/samba/wip.git] / source3 / smbd / open.c
index ecc84b910fe0ce7e4e4782d567de3852b02c099b..4157280b084f49dfed9ef65c5ec4fa629a823b67 100644 (file)
@@ -840,8 +840,11 @@ static NTSTATUS open_file(files_struct *fsp,
                        }
                }
 
-               /* Actually do the open */
-               status = fd_open_atomic(conn, fsp, local_flags,
+               /*
+                * Actually do the open - if O_TRUNC is needed handle it
+                * below under the share mode lock.
+                */
+               status = fd_open_atomic(conn, fsp, local_flags & ~O_TRUNC,
                                unx_mode, p_file_created);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
@@ -871,7 +874,7 @@ static NTSTATUS open_file(files_struct *fsp,
                           in the stat struct in fsp->fsp_name. */
 
                        /* Inherit the ACL if required */
-                       if (lp_inherit_perms(SNUM(conn))) {
+                       if (lp_inherit_permissions(SNUM(conn))) {
                                inherit_access_posix_acl(conn, parent_dir,
                                                         smb_fname->base_name,
                                                         unx_mode);
@@ -1080,6 +1083,11 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
                return;
        }
 
+       if (share_entry->share_file_id == 0) {
+               /* INTERNAL_OPEN_ONLY */
+               return;
+       }
+
        if (!is_valid_share_mode_entry(share_entry)) {
                return;
        }
@@ -1148,7 +1156,7 @@ static bool has_delete_on_close(struct share_mode_lock *lck,
 
 /****************************************************************************
  Deal with share modes
- Invarient: Share mode must be locked on entry and exit.
+ Invariant: Share mode must be locked on entry and exit.
  Returns -1 on error, or number of share modes on success (may be zero).
 ****************************************************************************/
 
@@ -1559,23 +1567,28 @@ static void defer_open(struct share_mode_lock *lck,
                       struct smb_request *req,
                       struct deferred_open_record *state)
 {
+       struct deferred_open_record *open_rec;
+
        DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
                  "open entry for mid %llu\n",
                  (unsigned int)request_time.tv_sec,
                  (unsigned int)request_time.tv_usec,
                  (unsigned long long)req->mid));
 
-       if (!push_deferred_open_message_smb(req, request_time, timeout,
-                                      state->id, (char *)state, sizeof(*state))) {
+       open_rec = talloc(NULL, struct deferred_open_record);
+       if (open_rec == NULL) {
                TALLOC_FREE(lck);
-               exit_server("push_deferred_open_message_smb failed");
+               exit_server("talloc failed");
        }
+
+       *open_rec = *state;
+
        if (lck) {
                struct defer_open_state *watch_state;
                struct tevent_req *watch_req;
                bool ret;
 
-               watch_state = talloc(req->sconn, struct defer_open_state);
+               watch_state = talloc(open_rec, struct defer_open_state);
                if (watch_state == NULL) {
                        exit_server("talloc failed");
                }
@@ -1599,6 +1612,12 @@ static void defer_open(struct share_mode_lock *lck,
                        timeval_sum(&request_time, &timeout));
                SMB_ASSERT(ret);
        }
+
+       if (!push_deferred_open_message_smb(req, request_time, timeout,
+                                           state->id, open_rec)) {
+               TALLOC_FREE(lck);
+               exit_server("push_deferred_open_message_smb failed");
+       }
 }
 
 static void defer_open_done(struct tevent_req *req)
@@ -1738,6 +1757,7 @@ static NTSTATUS fcb_or_dos_open(struct smb_request *req,
 }
 
 static void schedule_defer_open(struct share_mode_lock *lck,
+                               struct file_id id,
                                struct timeval request_time,
                                struct smb_request *req)
 {
@@ -1768,7 +1788,7 @@ static void schedule_defer_open(struct share_mode_lock *lck,
 
        state.delayed_for_oplocks = True;
        state.async_open = false;
-       state.id = lck->data->id;
+       state.id = id;
 
        if (!request_timed_out(request_time, timeout)) {
                defer_open(lck, request_time, timeout, req, &state);
@@ -1924,11 +1944,9 @@ NTSTATUS smbd_calculate_access_mask(connection_struct *conn,
  Return true if this is a state pointer to an asynchronous create.
 ****************************************************************************/
 
-bool is_deferred_open_async(const void *ptr)
+bool is_deferred_open_async(const struct deferred_open_record *rec)
 {
-       const struct deferred_open_record *state = (const struct deferred_open_record *)ptr;
-
-       return state->async_open;
+       return rec->async_open;
 }
 
 static bool clear_ads(uint32_t create_disposition)
@@ -2124,9 +2142,12 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                   create_options, (unsigned int)unx_mode, oplock_request,
                   (unsigned int)private_flags));
 
-       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;
+       if (req == NULL) {
+               /* Ensure req == NULL means INTERNAL_OPEN_ONLY */
+               SMB_ASSERT(((oplock_request & INTERNAL_OPEN_ONLY) != 0));
+       } else {
+               /* And req != NULL means no INTERNAL_OPEN_ONLY */
+               SMB_ASSERT(((oplock_request & INTERNAL_OPEN_ONLY) == 0));
        }
 
        /*
@@ -2134,10 +2155,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
         */
 
        if (req) {
-               void *ptr;
+               struct deferred_open_record *open_rec;
                if (get_deferred_open_message_state(req,
                                &request_time,
-                               &ptr)) {
+                               &open_rec)) {
                        /* Remember the absolute time of the original
                           request with this mid. We'll use it later to
                           see if this has timed out. */
@@ -2145,7 +2166,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                        /* If it was an async create retry, the file
                           didn't exist. */
 
-                       if (is_deferred_open_async(ptr)) {
+                       if (is_deferred_open_async(open_rec)) {
                                SET_STAT_INVALID(smb_fname->st);
                                file_existed = false;
                        }
@@ -2412,7 +2433,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
 
                if (delay_for_oplock(fsp, 0, lck, false, create_disposition)) {
-                       schedule_defer_open(lck, request_time, req);
+                       schedule_defer_open(lck, fsp->file_id, request_time, req);
                        TALLOC_FREE(lck);
                        DEBUG(10, ("Sent oplock break request to kernel "
                                   "oplock holder\n"));
@@ -2425,7 +2446,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                 */
                state.delayed_for_oplocks = false;
                state.async_open = false;
-               state.id = lck->data->id;
+               state.id = fsp->file_id;
                defer_open(lck, request_time, timeval_set(0, 0), req, &state);
                TALLOC_FREE(lck);
                DEBUG(10, ("No Samba oplock around after EWOULDBLOCK. "
@@ -2525,7 +2546,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                    fsp, oplock_request, lck,
                    NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION),
                    create_disposition)) {
-               schedule_defer_open(lck, request_time, req);
+               schedule_defer_open(lck, fsp->file_id, request_time, req);
                TALLOC_FREE(lck);
                fd_close(fsp);
                return NT_STATUS_SHARING_VIOLATION;
@@ -2658,6 +2679,21 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                return status;
        }
 
+       /* Should we atomically (to the client at least) truncate ? */
+       if ((!new_file_created) &&
+           (flags2 & O_TRUNC) &&
+           (!S_ISFIFO(fsp->fsp_name->st.st_ex_mode))) {
+               int ret;
+
+               ret = vfs_set_filelen(fsp, 0);
+               if (ret != 0) {
+                       status = map_nt_error_from_unix(errno);
+                       TALLOC_FREE(lck);
+                       fd_close(fsp);
+                       return status;
+               }
+       }
+
        grant_fsp_oplock_type(fsp, lck, oplock_request);
 
        /*
@@ -2861,39 +2897,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-
-/****************************************************************************
- Open a file for for write to ensure that we can fchmod it.
-****************************************************************************/
-
-NTSTATUS open_file_fchmod(connection_struct *conn,
-                         struct smb_filename *smb_fname,
-                         files_struct **result)
-{
-       if (!VALID_STAT(smb_fname->st)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-        return SMB_VFS_CREATE_FILE(
-               conn,                                   /* conn */
-               NULL,                                   /* req */
-               0,                                      /* root_dir_fid */
-               smb_fname,                              /* fname */
-               FILE_WRITE_DATA,                        /* access_mask */
-               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
-                   FILE_SHARE_DELETE),
-               FILE_OPEN,                              /* create_disposition*/
-               0,                                      /* create_options */
-               0,                                      /* file_attributes */
-               INTERNAL_OPEN_ONLY,                     /* oplock_request */
-               0,                                      /* allocation_size */
-               0,                                      /* private_flags */
-               NULL,                                   /* sd */
-               NULL,                                   /* ea_list */
-               result,                                 /* result */
-               NULL);                                  /* pinfo */
-}
-
 static NTSTATUS mkdir_internal(connection_struct *conn,
                               struct smb_filename *smb_dname,
                               uint32 file_attributes)
@@ -2962,7 +2965,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                }
        }
 
-       if (lp_inherit_perms(SNUM(conn))) {
+       if (lp_inherit_permissions(SNUM(conn))) {
                inherit_access_posix_acl(conn, parent_dir,
                                         smb_dname->base_name, mode);
                need_re_stat = true;
@@ -3349,6 +3352,7 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req,
                FILE_DIRECTORY_FILE,                    /* create_options */
                FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
                0,                                      /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
@@ -3527,6 +3531,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
                         0,                     /* create_options */
                         FILE_ATTRIBUTE_NORMAL, /* file_attributes */
                         0,                     /* oplock_request */
+                        NULL,                  /* lease */
                         0,                     /* allocation_size */
                         NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* private_flags */
                         NULL,                  /* sd */
@@ -4281,6 +4286,7 @@ NTSTATUS create_file_default(connection_struct *conn,
                             uint32_t create_options,
                             uint32_t file_attributes,
                             uint32_t oplock_request,
+                            struct smb2_lease *lease,
                             uint64_t allocation_size,
                             uint32_t private_flags,
                             struct security_descriptor *sd,