2 Unix SMB/CIFS implementation.
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/>.
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../lib/util/tevent_ntstatus.h"
27 static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
29 uint64_t in_file_id_volatile,
31 NTTIME *out_creation_time,
32 NTTIME *out_last_access_time,
33 NTTIME *out_last_write_time,
34 NTTIME *out_change_time,
35 uint64_t *out_allocation_size,
36 uint64_t *out_end_of_file,
37 uint32_t *out_file_attributes);
39 static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct smbd_smb2_request *smb2req,
43 uint64_t in_file_id_volatile);
44 static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
46 NTTIME *out_creation_time,
47 NTTIME *out_last_access_time,
48 NTTIME *out_last_write_time,
49 NTTIME *out_change_time,
50 uint64_t *out_allocation_size,
51 uint64_t *out_end_of_file,
52 uint32_t *out_file_attributes);
54 NTSTATUS smbd_smb2_request_process_close(struct smbd_smb2_request *req)
56 const uint8_t *inbody;
57 int i = req->current_idx;
60 uint64_t in_file_id_persistent;
61 uint64_t in_file_id_volatile;
63 NTTIME out_creation_time;
64 NTTIME out_last_access_time;
65 NTTIME out_last_write_time;
66 NTTIME out_change_time;
67 uint64_t out_allocation_size;
68 uint64_t out_end_of_file;
69 uint32_t out_file_attributes;
72 status = smbd_smb2_request_verify_sizes(req, 0x18);
73 if (!NT_STATUS_IS_OK(status)) {
74 return smbd_smb2_request_error(req, status);
76 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
78 outbody = data_blob_talloc(req->out.vector, NULL, 0x3C);
79 if (outbody.data == NULL) {
80 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
83 in_flags = SVAL(inbody, 0x02);
84 in_file_id_persistent = BVAL(inbody, 0x08);
85 in_file_id_volatile = BVAL(inbody, 0x10);
87 if (req->compat_chain_fsp) {
89 } else if (in_file_id_persistent != in_file_id_volatile) {
90 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
93 status = smbd_smb2_close(req,
98 &out_last_access_time,
101 &out_allocation_size,
103 &out_file_attributes);
104 if (!NT_STATUS_IS_OK(status)) {
105 return smbd_smb2_request_error(req, status);
108 SSVAL(outbody.data, 0x00, 0x3C); /* struct size */
109 SSVAL(outbody.data, 0x02, out_flags);
110 SIVAL(outbody.data, 0x04, 0); /* reserved */
111 SBVAL(outbody.data, 0x08, out_creation_time);
112 SBVAL(outbody.data, 0x10, out_last_access_time);
113 SBVAL(outbody.data, 0x18, out_last_write_time);
114 SBVAL(outbody.data, 0x20, out_change_time);
115 SBVAL(outbody.data, 0x28, out_allocation_size);
116 SBVAL(outbody.data, 0x30, out_end_of_file);
117 SIVAL(outbody.data, 0x38, out_file_attributes);
119 return smbd_smb2_request_done(req, outbody, NULL);
122 static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
124 uint64_t in_file_id_volatile,
126 NTTIME *out_creation_time,
127 NTTIME *out_last_access_time,
128 NTTIME *out_last_write_time,
129 NTTIME *out_change_time,
130 uint64_t *out_allocation_size,
131 uint64_t *out_end_of_file,
132 uint32_t *out_file_attributes)
135 struct smb_request *smbreq;
136 connection_struct *conn = req->tcon->compat_conn;
138 struct smb_filename *smb_fname = NULL;
139 struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
140 uint64_t allocation_size = 0;
141 uint64_t file_size = 0;
142 uint32_t dos_attrs = 0;
144 bool posix_open = false;
146 ZERO_STRUCT(create_date_ts);
147 ZERO_STRUCT(adate_ts);
148 ZERO_STRUCT(mdate_ts);
149 ZERO_STRUCT(cdate_ts);
152 *out_creation_time = 0;
153 *out_last_access_time = 0;
154 *out_last_write_time = 0;
155 *out_change_time = 0;
156 *out_allocation_size = 0;
157 *out_end_of_file = 0;
158 *out_file_attributes = 0;
160 DEBUG(10,("smbd_smb2_close: file_id[0x%016llX]\n",
161 (unsigned long long)in_file_id_volatile));
163 smbreq = smbd_smb2_fake_smb_request(req);
164 if (smbreq == NULL) {
165 return NT_STATUS_NO_MEMORY;
168 fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile);
170 return NT_STATUS_FILE_CLOSED;
172 if (conn != fsp->conn) {
173 return NT_STATUS_FILE_CLOSED;
175 if (req->session->vuid != fsp->vuid) {
176 return NT_STATUS_FILE_CLOSED;
179 posix_open = fsp->posix_open;
180 status = copy_smb_filename(talloc_tos(),
183 if (!NT_STATUS_IS_OK(status)) {
187 status = close_file(smbreq, fsp, NORMAL_CLOSE);
188 if (!NT_STATUS_IS_OK(status)) {
189 DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
190 fsp_str_dbg(fsp), nt_errstr(status)));
194 if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
197 ret = SMB_VFS_LSTAT(conn, smb_fname);
199 ret = SMB_VFS_STAT(conn, smb_fname);
202 flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
203 dos_attrs = dos_mode(conn, smb_fname);
204 mdate_ts = smb_fname->st.st_ex_mtime;
205 adate_ts = smb_fname->st.st_ex_atime;
206 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
207 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
209 if (lp_dos_filetime_resolution(SNUM(conn))) {
210 dos_filetime_timespec(&create_date_ts);
211 dos_filetime_timespec(&mdate_ts);
212 dos_filetime_timespec(&adate_ts);
213 dos_filetime_timespec(&cdate_ts);
215 if (!(dos_attrs & FILE_ATTRIBUTE_DIRECTORY)) {
216 file_size = get_file_size_stat(&smb_fname->st);
219 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
225 round_timespec(conn->ts_res, &create_date_ts);
226 unix_timespec_to_nt_time(out_creation_time, create_date_ts);
228 round_timespec(conn->ts_res, &adate_ts);
229 unix_timespec_to_nt_time(out_last_access_time, adate_ts);
231 round_timespec(conn->ts_res, &mdate_ts);
232 unix_timespec_to_nt_time(out_last_write_time, mdate_ts);
234 round_timespec(conn->ts_res, &cdate_ts);
235 unix_timespec_to_nt_time(out_change_time, cdate_ts);
237 *out_allocation_size = allocation_size;
238 *out_end_of_file = file_size;
239 *out_file_attributes = dos_attrs;
244 struct smbd_smb2_close_state {
246 uint64_t in_file_id_volatile;
248 NTTIME out_creation_time;
249 NTTIME out_last_access_time;
250 NTTIME out_last_write_time;
251 NTTIME out_change_time;
252 uint64_t out_allocation_size;
253 uint64_t out_end_of_file;
254 uint32_t out_file_attributes;
257 static struct tevent_req *smbd_smb2_close_send(TALLOC_CTX *mem_ctx,
258 struct tevent_context *ev,
259 struct smbd_smb2_request *smb2req,
261 uint64_t in_file_id_volatile)
263 struct tevent_req *req;
264 struct smbd_smb2_close_state *state;
267 req = tevent_req_create(mem_ctx, &state,
268 struct smbd_smb2_close_state);
272 state->in_flags = in_flags;
273 state->in_file_id_volatile = in_file_id_volatile;
275 status = smbd_smb2_close(smb2req,
277 state->in_file_id_volatile,
279 &state->out_creation_time,
280 &state->out_last_access_time,
281 &state->out_last_write_time,
282 &state->out_change_time,
283 &state->out_allocation_size,
284 &state->out_end_of_file,
285 &state->out_file_attributes);
286 if (tevent_req_nterror(req, status)) {
287 return tevent_req_post(req, ev);
290 tevent_req_done(req);
291 return tevent_req_post(req, ev);
294 static NTSTATUS smbd_smb2_close_recv(struct tevent_req *req,
296 NTTIME *out_creation_time,
297 NTTIME *out_last_access_time,
298 NTTIME *out_last_write_time,
299 NTTIME *out_change_time,
300 uint64_t *out_allocation_size,
301 uint64_t *out_end_of_file,
302 uint32_t *out_file_attributes)
304 struct smbd_smb2_close_state *state =
306 struct smbd_smb2_close_state);
309 if (tevent_req_is_nterror(req, &status)) {
310 tevent_req_received(req);
314 *out_flags = state->out_flags;
315 *out_creation_time = state->out_creation_time;
316 *out_last_access_time = state->out_last_access_time;
317 *out_last_write_time = state->out_last_write_time;
318 *out_change_time = state->out_change_time;
319 *out_allocation_size = state->out_allocation_size;
320 *out_end_of_file = state->out_end_of_file;
321 *out_file_attributes = state->out_file_attributes;
323 tevent_req_received(req);