s3: smbd: Fix log spam. Change a normal error message from DBG_ERR (level 0) to DBG_I...
[Samba.git] / source3 / smbd / smb2_flush.c
blob5c8c171e418e94f1f5f0b7c6059678d0658db92c
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 bool is_compound = false;
130 bool is_last_in_compound = false;
132 req = tevent_req_create(mem_ctx, &state,
133 struct smbd_smb2_flush_state);
134 if (req == NULL) {
135 return NULL;
137 state->smb2req = smb2req;
138 state->fsp = fsp;
140 DEBUG(10,("smbd_smb2_flush: %s - %s\n",
141 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
143 smbreq = smbd_smb2_fake_smb_request(smb2req);
144 if (tevent_req_nomem(smbreq, req)) {
145 return tevent_req_post(req, ev);
148 if (IS_IPC(smbreq->conn)) {
149 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
150 return tevent_req_post(req, ev);
153 if (!CHECK_WRITE(fsp)) {
154 bool allow_dir_flush = false;
155 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
157 if (!fsp->fsp_flags.is_directory) {
158 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
159 return tevent_req_post(req, ev);
163 * Directories are not writable in the conventional
164 * sense, but if opened with *either*
165 * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
166 * they can be flushed.
169 if ((fsp->access_mask & flush_access) != 0) {
170 allow_dir_flush = true;
173 if (allow_dir_flush == false) {
174 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
175 return tevent_req_post(req, ev);
179 if (fsp_get_io_fd(fsp) == -1) {
180 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
181 return tevent_req_post(req, ev);
184 if (!lp_strict_sync(SNUM(smbreq->conn))) {
186 * No strict sync. Don't really do
187 * anything here.
189 tevent_req_done(req);
190 return tevent_req_post(req, ev);
193 subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
194 if (tevent_req_nomem(subreq, req)) {
195 return tevent_req_post(req, ev);
198 tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
200 is_compound = smbd_smb2_is_compound(smb2req);
201 is_last_in_compound = smbd_smb2_is_last_in_compound(smb2req);
203 if (is_compound && !is_last_in_compound) {
205 * Can't go async if we're not the
206 * last request in a compound request.
207 * Cause this request to complete synchronously.
209 smb2_request_set_async_internal(state->smb2req, true);
212 /* Ensure any close request knows about this outstanding IO. */
213 if (!aio_add_req_to_fsp(fsp, req)) {
214 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
215 return tevent_req_post(req, ev);
218 return req;
222 static void smbd_smb2_flush_done(struct tevent_req *subreq)
224 struct tevent_req *req = tevent_req_callback_data(
225 subreq, struct tevent_req);
226 struct smbd_smb2_flush_state *state = tevent_req_data(
227 req, struct smbd_smb2_flush_state);
228 int ret;
229 struct vfs_aio_state vfs_aio_state;
231 ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
232 TALLOC_FREE(subreq);
233 if (ret == -1) {
234 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
235 return;
237 if (state->fsp->fsp_flags.modified) {
238 trigger_write_time_update_immediate(state->fsp);
240 tevent_req_done(req);
243 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
245 NTSTATUS status;
247 if (tevent_req_is_nterror(req, &status)) {
248 tevent_req_received(req);
249 return status;
252 tevent_req_received(req);
253 return NT_STATUS_OK;