tests/krb5: Clarify checksum type assertion message
[Samba.git] / source3 / smbd / smb2_flush.c
blob14eb3750e3654b4de523160b84acbf8440305057
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;
130 req = tevent_req_create(mem_ctx, &state,
131 struct smbd_smb2_flush_state);
132 if (req == NULL) {
133 return NULL;
135 state->smb2req = smb2req;
136 state->fsp = fsp;
138 DEBUG(10,("smbd_smb2_flush: %s - %s\n",
139 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
141 smbreq = smbd_smb2_fake_smb_request(smb2req);
142 if (tevent_req_nomem(smbreq, req)) {
143 return tevent_req_post(req, ev);
146 if (IS_IPC(smbreq->conn)) {
147 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
148 return tevent_req_post(req, ev);
151 if (!CHECK_WRITE(fsp)) {
152 bool allow_dir_flush = false;
153 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
155 if (!fsp->fsp_flags.is_directory) {
156 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
157 return tevent_req_post(req, ev);
161 * Directories are not writable in the conventional
162 * sense, but if opened with *either*
163 * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
164 * they can be flushed.
167 if ((fsp->access_mask & flush_access) != 0) {
168 allow_dir_flush = true;
171 if (allow_dir_flush == false) {
172 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
173 return tevent_req_post(req, ev);
177 if (fsp->fh->fd == -1) {
178 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
179 return tevent_req_post(req, ev);
182 if (!lp_strict_sync(SNUM(smbreq->conn))) {
184 * No strict sync. Don't really do
185 * anything here.
187 tevent_req_done(req);
188 return tevent_req_post(req, ev);
191 subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
192 if (tevent_req_nomem(subreq, req)) {
193 return tevent_req_post(req, ev);
196 tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
198 /* Ensure any close request knows about this outstanding IO. */
199 if (!aio_add_req_to_fsp(fsp, req)) {
200 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
201 return tevent_req_post(req, ev);
204 return req;
208 static void smbd_smb2_flush_done(struct tevent_req *subreq)
210 struct tevent_req *req = tevent_req_callback_data(
211 subreq, struct tevent_req);
212 struct smbd_smb2_flush_state *state = tevent_req_data(
213 req, struct smbd_smb2_flush_state);
214 int ret;
215 struct vfs_aio_state vfs_aio_state;
217 ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
218 TALLOC_FREE(subreq);
219 if (ret == -1) {
220 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
221 return;
223 if (state->fsp->fsp_flags.modified) {
224 trigger_write_time_update_immediate(state->fsp);
226 tevent_req_done(req);
229 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
231 NTSTATUS status;
233 if (tevent_req_is_nterror(req, &status)) {
234 tevent_req_received(req);
235 return status;
238 tevent_req_received(req);
239 return NT_STATUS_OK;