dsdb: Align integer types
[Samba.git] / source3 / smbd / smb2_close.c
blobae0873e3bbea8b63a307c16992b7184ee0a88567
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 "lib/tevent_wait.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_SMB2
31 static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
32 struct tevent_context *ev,
33 struct smbd_smb2_request *smb2req,
34 struct files_struct *in_fsp,
35 uint16_t in_flags);
36 static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
37 uint16_t *out_flags,
38 struct timespec *out_creation_ts,
39 struct timespec *out_last_access_ts,
40 struct timespec *out_last_write_ts,
41 struct timespec *out_change_ts,
42 uint64_t *out_allocation_size,
43 uint64_t *out_end_of_file,
44 uint32_t *out_file_attributes);
46 static void smbd_smb2_request_close_done(struct tevent_req *subreq);
48 NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req)
50 const uint8_t *inbody;
51 uint16_t in_flags;
52 uint64_t in_file_id_persistent;
53 uint64_t in_file_id_volatile;
54 struct files_struct *in_fsp;
55 NTSTATUS status;
56 struct tevent_req *subreq;
58 status = smbd_smb2_request_verify_sizes(req, 0x18);
59 if (!NT_STATUS_IS_OK(status)) {
60 return smbd_smb2_request_error(req, status);
62 inbody = SMBD_SMB2_IN_BODY_PTR(req);
64 in_flags = SVAL(inbody, 0x02);
65 in_file_id_persistent = BVAL(inbody, 0x08);
66 in_file_id_volatile = BVAL(inbody, 0x10);
68 in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
69 if (in_fsp == NULL) {
70 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
73 subreq = smbd_smb2_close_send(req, req->sconn->ev_ctx,
74 req, in_fsp, in_flags);
75 if (subreq == NULL) {
76 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
78 tevent_req_set_callback(subreq, smbd_smb2_request_close_done, req);
80 return smbd_smb2_request_pending_queue(req, subreq, 500);
83 static void smbd_smb2_request_close_done(struct tevent_req *subreq)
85 struct smbd_smb2_request *req =
86 tevent_req_callback_data(subreq,
87 struct smbd_smb2_request);
88 DATA_BLOB outbody;
89 uint16_t out_flags = 0;
90 connection_struct *conn = req->tcon->compat;
91 struct timespec out_creation_ts = { 0, };
92 struct timespec out_last_access_ts = { 0, };
93 struct timespec out_last_write_ts = { 0, };
94 struct timespec out_change_ts = { 0, };
95 uint64_t out_allocation_size = 0;
96 uint64_t out_end_of_file = 0;
97 uint32_t out_file_attributes = 0;
98 NTSTATUS status;
99 NTSTATUS error;
101 status = smbd_smb2_close_recv(subreq,
102 &out_flags,
103 &out_creation_ts,
104 &out_last_access_ts,
105 &out_last_write_ts,
106 &out_change_ts,
107 &out_allocation_size,
108 &out_end_of_file,
109 &out_file_attributes);
110 TALLOC_FREE(subreq);
111 if (!NT_STATUS_IS_OK(status)) {
112 error = smbd_smb2_request_error(req, status);
113 if (!NT_STATUS_IS_OK(error)) {
114 smbd_server_connection_terminate(req->xconn,
115 nt_errstr(error));
116 return;
118 return;
121 outbody = smbd_smb2_generate_outbody(req, 0x3C);
122 if (outbody.data == NULL) {
123 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
124 if (!NT_STATUS_IS_OK(error)) {
125 smbd_server_connection_terminate(req->xconn,
126 nt_errstr(error));
127 return;
129 return;
132 SSVAL(outbody.data, 0x00, 0x3C); /* struct size */
133 SSVAL(outbody.data, 0x02, out_flags);
134 SIVAL(outbody.data, 0x04, 0); /* reserved */
135 put_long_date_full_timespec(conn->ts_res,
136 (char *)outbody.data + 0x08, &out_creation_ts);
137 put_long_date_full_timespec(conn->ts_res,
138 (char *)outbody.data + 0x10, &out_last_access_ts);
139 put_long_date_full_timespec(conn->ts_res,
140 (char *)outbody.data + 0x18, &out_last_write_ts);
141 put_long_date_full_timespec(conn->ts_res,
142 (char *)outbody.data + 0x20, &out_change_ts);
143 SBVAL(outbody.data, 0x28, out_allocation_size);
144 SBVAL(outbody.data, 0x30, out_end_of_file);
145 SIVAL(outbody.data, 0x38, out_file_attributes);
147 error = smbd_smb2_request_done(req, outbody, NULL);
148 if (!NT_STATUS_IS_OK(error)) {
149 smbd_server_connection_terminate(req->xconn,
150 nt_errstr(error));
151 return;
155 static void setup_close_full_information(connection_struct *conn,
156 struct smb_filename *smb_fname,
157 bool posix_open,
158 struct timespec *out_creation_ts,
159 struct timespec *out_last_access_ts,
160 struct timespec *out_last_write_ts,
161 struct timespec *out_change_ts,
162 uint16_t *out_flags,
163 uint64_t *out_allocation_size,
164 uint64_t *out_end_of_file,
165 uint32_t *out_file_attributes)
167 int ret;
168 if (posix_open) {
169 ret = SMB_VFS_LSTAT(conn, smb_fname);
170 } else {
171 ret = SMB_VFS_STAT(conn, smb_fname);
173 if (ret != 0) {
174 return;
177 *out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
178 *out_file_attributes = dos_mode(conn, smb_fname);
179 *out_last_write_ts = smb_fname->st.st_ex_mtime;
180 *out_last_access_ts = smb_fname->st.st_ex_atime;
181 *out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
182 *out_change_ts = get_change_timespec(conn, NULL, smb_fname);
184 if (lp_dos_filetime_resolution(SNUM(conn))) {
185 dos_filetime_timespec(out_creation_ts);
186 dos_filetime_timespec(out_last_write_ts);
187 dos_filetime_timespec(out_last_access_ts);
188 dos_filetime_timespec(out_change_ts);
190 if (!(*out_file_attributes & FILE_ATTRIBUTE_DIRECTORY)) {
191 *out_end_of_file = get_file_size_stat(&smb_fname->st);
194 *out_allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
197 static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
198 struct files_struct *fsp,
199 uint16_t in_flags,
200 uint16_t *out_flags,
201 struct timespec *out_creation_ts,
202 struct timespec *out_last_access_ts,
203 struct timespec *out_last_write_ts,
204 struct timespec *out_change_ts,
205 uint64_t *out_allocation_size,
206 uint64_t *out_end_of_file,
207 uint32_t *out_file_attributes)
209 NTSTATUS status;
210 struct smb_request *smbreq;
211 connection_struct *conn = req->tcon->compat;
212 struct smb_filename *smb_fname = NULL;
213 uint64_t allocation_size = 0;
214 uint64_t file_size = 0;
215 uint32_t dos_attrs = 0;
216 uint16_t flags = 0;
217 bool posix_open = false;
219 ZERO_STRUCTP(out_creation_ts);
220 ZERO_STRUCTP(out_last_access_ts);
221 ZERO_STRUCTP(out_last_write_ts);
222 ZERO_STRUCTP(out_change_ts);
224 *out_flags = 0;
225 *out_allocation_size = 0;
226 *out_end_of_file = 0;
227 *out_file_attributes = 0;
229 DEBUG(10,("smbd_smb2_close: %s - %s\n",
230 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
232 smbreq = smbd_smb2_fake_smb_request(req);
233 if (smbreq == NULL) {
234 return NT_STATUS_NO_MEMORY;
237 posix_open = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN);
238 smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
239 if (smb_fname == NULL) {
240 return NT_STATUS_NO_MEMORY;
243 if ((in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) &&
244 (fsp->initial_delete_on_close || fsp->delete_on_close)) {
246 * We might be deleting the file. Ensure we
247 * return valid data from before the file got
248 * removed.
250 setup_close_full_information(conn,
251 smb_fname,
252 posix_open,
253 out_creation_ts,
254 out_last_access_ts,
255 out_last_write_ts,
256 out_change_ts,
257 &flags,
258 &allocation_size,
259 &file_size,
260 &dos_attrs);
263 status = close_file(smbreq, fsp, NORMAL_CLOSE);
264 if (!NT_STATUS_IS_OK(status)) {
265 DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
266 smb_fname_str_dbg(smb_fname), nt_errstr(status)));
267 return status;
270 if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
271 setup_close_full_information(conn,
272 smb_fname,
273 posix_open,
274 out_creation_ts,
275 out_last_access_ts,
276 out_last_write_ts,
277 out_change_ts,
278 &flags,
279 &allocation_size,
280 &file_size,
281 &dos_attrs);
284 *out_flags = flags;
285 *out_allocation_size = allocation_size;
286 *out_end_of_file = file_size;
287 *out_file_attributes = dos_attrs;
289 return NT_STATUS_OK;
292 struct smbd_smb2_close_state {
293 struct smbd_smb2_request *smb2req;
294 struct files_struct *in_fsp;
295 uint16_t in_flags;
296 uint16_t out_flags;
297 struct timespec out_creation_ts;
298 struct timespec out_last_access_ts;
299 struct timespec out_last_write_ts;
300 struct timespec out_change_ts;
301 uint64_t out_allocation_size;
302 uint64_t out_end_of_file;
303 uint32_t out_file_attributes;
306 static void smbd_smb2_close_do(struct tevent_req *subreq);
308 static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
309 struct tevent_context *ev,
310 struct smbd_smb2_request *smb2req,
311 struct files_struct *in_fsp,
312 uint16_t in_flags)
314 struct tevent_req *req;
315 struct smbd_smb2_close_state *state;
316 unsigned i;
317 NTSTATUS status;
319 req = tevent_req_create(mem_ctx, &state,
320 struct smbd_smb2_close_state);
321 if (req == NULL) {
322 return NULL;
324 state->smb2req = smb2req;
325 state->in_fsp = in_fsp;
326 state->in_flags = in_flags;
328 in_fsp->closing = true;
330 i = 0;
331 while (i < in_fsp->num_aio_requests) {
332 bool ok = tevent_req_cancel(in_fsp->aio_requests[i]);
333 if (ok) {
334 continue;
336 i += 1;
339 if (in_fsp->num_aio_requests != 0) {
340 in_fsp->deferred_close = tevent_wait_send(in_fsp, ev);
341 if (tevent_req_nomem(in_fsp->deferred_close, req)) {
342 return tevent_req_post(req, ev);
344 tevent_req_set_callback(in_fsp->deferred_close,
345 smbd_smb2_close_do, req);
346 return req;
349 status = smbd_smb2_close(smb2req,
350 state->in_fsp,
351 state->in_flags,
352 &state->out_flags,
353 &state->out_creation_ts,
354 &state->out_last_access_ts,
355 &state->out_last_write_ts,
356 &state->out_change_ts,
357 &state->out_allocation_size,
358 &state->out_end_of_file,
359 &state->out_file_attributes);
360 if (tevent_req_nterror(req, status)) {
361 return tevent_req_post(req, ev);
364 tevent_req_done(req);
365 return tevent_req_post(req, ev);
368 static void smbd_smb2_close_do(struct tevent_req *subreq)
370 struct tevent_req *req = tevent_req_callback_data(
371 subreq, struct tevent_req);
372 struct smbd_smb2_close_state *state = tevent_req_data(
373 req, struct smbd_smb2_close_state);
374 NTSTATUS status;
375 int ret;
377 ret = tevent_wait_recv(subreq);
378 TALLOC_FREE(subreq);
379 if (ret != 0) {
380 DEBUG(10, ("tevent_wait_recv returned %s\n",
381 strerror(ret)));
383 * Continue anyway, this should never happen
387 status = smbd_smb2_close(state->smb2req,
388 state->in_fsp,
389 state->in_flags,
390 &state->out_flags,
391 &state->out_creation_ts,
392 &state->out_last_access_ts,
393 &state->out_last_write_ts,
394 &state->out_change_ts,
395 &state->out_allocation_size,
396 &state->out_end_of_file,
397 &state->out_file_attributes);
398 if (tevent_req_nterror(req, status)) {
399 return;
401 tevent_req_done(req);
404 static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
405 uint16_t *out_flags,
406 struct timespec *out_creation_ts,
407 struct timespec *out_last_access_ts,
408 struct timespec *out_last_write_ts,
409 struct timespec *out_change_ts,
410 uint64_t *out_allocation_size,
411 uint64_t *out_end_of_file,
412 uint32_t *out_file_attributes)
414 struct smbd_smb2_close_state *state =
415 tevent_req_data(req,
416 struct smbd_smb2_close_state);
417 NTSTATUS status;
419 if (tevent_req_is_nterror(req, &status)) {
420 tevent_req_received(req);
421 return status;
424 *out_flags = state->out_flags;
425 *out_creation_ts = state->out_creation_ts;
426 *out_last_access_ts = state->out_last_access_ts;
427 *out_last_write_ts = state->out_last_write_ts;
428 *out_change_ts = state->out_change_ts;
429 *out_allocation_size = state->out_allocation_size;
430 *out_end_of_file = state->out_end_of_file;
431 *out_file_attributes = state->out_file_attributes;
433 tevent_req_received(req);
434 return NT_STATUS_OK;