smbd: flush pending writetime update when flushing file
[Samba.git] / source3 / smbd / smb2_flush.c
blob86dd14844e640a17d714a877243b5117e1cd9363
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "libcli/security/security.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_SMB2
31 static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
32 struct tevent_context *ev,
33 struct smbd_smb2_request *smb2req,
34 struct files_struct *fsp);
35 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req);
37 static void smbd_smb2_request_flush_done(struct tevent_req *subreq);
38 NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
40 NTSTATUS status;
41 const uint8_t *inbody;
42 uint64_t in_file_id_persistent;
43 uint64_t in_file_id_volatile;
44 struct files_struct *in_fsp;
45 struct tevent_req *subreq;
47 status = smbd_smb2_request_verify_sizes(req, 0x18);
48 if (!NT_STATUS_IS_OK(status)) {
49 return smbd_smb2_request_error(req, status);
51 inbody = SMBD_SMB2_IN_BODY_PTR(req);
53 in_file_id_persistent = BVAL(inbody, 0x08);
54 in_file_id_volatile = BVAL(inbody, 0x10);
56 in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
57 if (in_fsp == NULL) {
58 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
61 subreq = smbd_smb2_flush_send(req, req->sconn->ev_ctx,
62 req, in_fsp);
63 if (subreq == NULL) {
64 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
66 tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
68 return smbd_smb2_request_pending_queue(req, subreq, 500);
71 static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
73 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
74 struct smbd_smb2_request);
75 DATA_BLOB outbody;
76 NTSTATUS status;
77 NTSTATUS error; /* transport error */
79 status = smbd_smb2_flush_recv(subreq);
80 TALLOC_FREE(subreq);
81 if (!NT_STATUS_IS_OK(status)) {
82 error = smbd_smb2_request_error(req, status);
83 if (!NT_STATUS_IS_OK(error)) {
84 smbd_server_connection_terminate(req->xconn,
85 nt_errstr(error));
86 return;
88 return;
91 outbody = smbd_smb2_generate_outbody(req, 0x04);
92 if (outbody.data == NULL) {
93 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
94 if (!NT_STATUS_IS_OK(error)) {
95 smbd_server_connection_terminate(req->xconn,
96 nt_errstr(error));
97 return;
99 return;
102 SSVAL(outbody.data, 0x00, 0x04); /* struct size */
103 SSVAL(outbody.data, 0x02, 0); /* reserved */
105 error = smbd_smb2_request_done(req, outbody, NULL);
106 if (!NT_STATUS_IS_OK(error)) {
107 smbd_server_connection_terminate(req->xconn,
108 nt_errstr(error));
109 return;
113 struct smbd_smb2_flush_state {
114 struct smbd_smb2_request *smb2req;
115 struct files_struct *fsp;
118 static void smbd_smb2_flush_done(struct tevent_req *subreq);
120 static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
121 struct tevent_context *ev,
122 struct smbd_smb2_request *smb2req,
123 struct files_struct *fsp)
125 struct tevent_req *req;
126 struct tevent_req *subreq;
127 struct smbd_smb2_flush_state *state;
128 struct smb_request *smbreq;
129 int ret;
131 req = tevent_req_create(mem_ctx, &state,
132 struct smbd_smb2_flush_state);
133 if (req == NULL) {
134 return NULL;
136 state->smb2req = smb2req;
137 state->fsp = fsp;
139 DEBUG(10,("smbd_smb2_flush: %s - %s\n",
140 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
142 smbreq = smbd_smb2_fake_smb_request(smb2req);
143 if (tevent_req_nomem(smbreq, req)) {
144 return tevent_req_post(req, ev);
147 if (IS_IPC(smbreq->conn)) {
148 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
149 return tevent_req_post(req, ev);
152 if (!CHECK_WRITE(fsp)) {
153 bool allow_dir_flush = false;
154 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
156 if (!fsp->is_directory) {
157 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
158 return tevent_req_post(req, ev);
162 * Directories are not writable in the conventional
163 * sense, but if opened with *either*
164 * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
165 * they can be flushed.
168 if ((fsp->access_mask & flush_access) != 0) {
169 allow_dir_flush = true;
172 if (allow_dir_flush == false) {
173 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
174 return tevent_req_post(req, ev);
178 if (fsp->fh->fd == -1) {
179 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
180 return tevent_req_post(req, ev);
183 if (!lp_strict_sync(SNUM(smbreq->conn))) {
185 * No strict sync. Don't really do
186 * anything here.
188 tevent_req_done(req);
189 return tevent_req_post(req, ev);
192 ret = flush_write_cache(fsp, SAMBA_SYNC_FLUSH);
193 if (ret == -1) {
194 tevent_req_nterror(req, map_nt_error_from_unix(errno));
195 return tevent_req_post(req, ev);
198 subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
199 if (tevent_req_nomem(subreq, req)) {
200 return tevent_req_post(req, ev);
203 tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
205 /* Ensure any close request knows about this outstanding IO. */
206 if (!aio_add_req_to_fsp(fsp, req)) {
207 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
208 return tevent_req_post(req, ev);
211 return req;
215 static void smbd_smb2_flush_done(struct tevent_req *subreq)
217 struct tevent_req *req = tevent_req_callback_data(
218 subreq, struct tevent_req);
219 struct smbd_smb2_flush_state *state = tevent_req_data(
220 req, struct smbd_smb2_flush_state);
221 int ret;
222 struct vfs_aio_state vfs_aio_state;
224 ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
225 TALLOC_FREE(subreq);
226 if (ret == -1) {
227 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
228 return;
230 if (state->fsp->modified) {
231 trigger_write_time_update_immediate(state->fsp);
233 tevent_req_done(req);
236 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
238 NTSTATUS status;
240 if (tevent_req_is_nterror(req, &status)) {
241 tevent_req_received(req);
242 return status;
245 tevent_req_received(req);
246 return NT_STATUS_OK;