libnet: Fix Coverity ID 1634803 Dereference after null check
[Samba.git] / source3 / torture / test_readdir_timestamp.c
blob0eba415c8b45ce93634df6e7e0ed329a8883a28d
1 /*
2 * Unix SMB/CIFS implementation.
3 * Copyright (C) Volker Lendecke 2020
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "includes.h"
20 #include "torture/proto.h"
21 #include "libsmb/libsmb.h"
22 #include "libsmb/clirap.h"
23 #include "lib/util/tevent_ntstatus.h"
24 #include "lib/util/smb_strtox.h"
26 extern int torture_nprocs;
27 extern int torture_numops;
29 struct create_ts_state {
30 struct tevent_context *ev;
31 struct cli_state *cli;
32 unsigned timestamp_idx;
33 uint16_t fnum;
36 static void create_ts_opened(struct tevent_req *subreq);
37 static void create_ts_setinfo_done(struct tevent_req *subreq);
38 static void create_ts_waited(struct tevent_req *subreq);
39 static void create_ts_written(struct tevent_req *subreq);
40 static void create_ts_doc_done(struct tevent_req *subreq);
42 static struct tevent_req *create_ts_send(
43 TALLOC_CTX *mem_ctx,
44 struct tevent_context *ev,
45 struct cli_state *cli,
46 const char *fname,
47 unsigned timestamp_idx)
49 struct tevent_req *req = NULL, *subreq = NULL;
50 struct create_ts_state *state = NULL;
52 req = tevent_req_create(mem_ctx, &state, struct create_ts_state);
53 if (req == NULL) {
54 return NULL;
56 state->ev = ev;
57 state->cli = cli;
58 state->timestamp_idx = timestamp_idx;
60 subreq = cli_ntcreate_send(
61 state,
62 ev,
63 cli,
64 fname,
65 0, /* CreatFlags */
66 SEC_FILE_WRITE_ATTRIBUTE|
67 SEC_FILE_WRITE_DATA|
68 SEC_STD_DELETE, /* DesiredAccess */
69 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
70 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
71 FILE_OPEN_IF, /* CreateDisposition */
72 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
73 0, /* Impersonation */
74 0); /* SecurityFlags */
75 if (tevent_req_nomem(subreq, req)) {
76 return tevent_req_post(req, ev);
78 tevent_req_set_callback(subreq, create_ts_opened, req);
79 return req;
82 static void create_ts_opened(struct tevent_req *subreq)
84 struct tevent_req *req = tevent_req_callback_data(
85 subreq, struct tevent_req);
86 struct create_ts_state *state = tevent_req_data(
87 req, struct create_ts_state);
88 struct smb_create_returns cr;
89 struct timespec mtime;
90 NTSTATUS status;
92 status = cli_ntcreate_recv(subreq, &state->fnum, &cr);
93 TALLOC_FREE(subreq);
94 if (tevent_req_nterror(req, status)) {
95 return;
98 mtime = nt_time_to_unix_timespec(cr.last_write_time);
100 mtime.tv_sec &= ~(0xFFFFULL);
101 mtime.tv_sec |= (state->timestamp_idx & 0xFFFF);
103 subreq = cli_setfileinfo_ext_send(
104 state,
105 state->ev,
106 state->cli,
107 state->fnum,
108 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* create */
109 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* access */
110 mtime,
111 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* change */
112 UINT32_MAX); /* attr */
113 if (tevent_req_nomem(subreq, req)) {
114 return;
116 tevent_req_set_callback(subreq, create_ts_setinfo_done, req);
119 static void create_ts_setinfo_done(struct tevent_req *subreq)
121 struct tevent_req *req = tevent_req_callback_data(
122 subreq, struct tevent_req);
123 struct create_ts_state *state = tevent_req_data(
124 req, struct create_ts_state);
125 NTSTATUS status;
127 status = cli_setfileinfo_ext_recv(subreq);
128 TALLOC_FREE(subreq);
129 if (tevent_req_nterror(req, status)) {
130 return;
133 subreq = tevent_wakeup_send(
134 state, state->ev, timeval_current_ofs_msec(100));
135 if (tevent_req_nomem(subreq, req)) {
136 return;
138 tevent_req_set_callback(subreq, create_ts_waited, req);
141 static void create_ts_waited(struct tevent_req *subreq)
143 struct tevent_req *req = tevent_req_callback_data(
144 subreq, struct tevent_req);
145 struct create_ts_state *state = tevent_req_data(
146 req, struct create_ts_state);
147 bool ok;
149 ok = tevent_wakeup_recv(subreq);
150 TALLOC_FREE(subreq);
151 if (!ok) {
152 tevent_req_oom(subreq);
153 return;
156 subreq = cli_write_send(
157 state,
158 state->ev,
159 state->cli,
160 state->fnum,
162 (uint8_t *)&state->fnum,
164 sizeof(state->fnum));
165 if (tevent_req_nomem(subreq, req)) {
166 return;
168 tevent_req_set_callback(subreq, create_ts_written, req);
171 static void create_ts_written(struct tevent_req *subreq)
173 struct tevent_req *req = tevent_req_callback_data(
174 subreq, struct tevent_req);
175 struct create_ts_state *state = tevent_req_data(
176 req, struct create_ts_state);
177 size_t written;
178 NTSTATUS status;
180 status = cli_write_recv(subreq, &written);
181 TALLOC_FREE(subreq);
182 if (tevent_req_nterror(subreq, status)) {
183 return;
186 subreq = cli_nt_delete_on_close_send(
187 state, state->ev, state->cli, state->fnum, true);
188 if (tevent_req_nomem(subreq, req)) {
189 return;
191 tevent_req_set_callback(subreq, create_ts_doc_done, req);
194 static void create_ts_doc_done(struct tevent_req *subreq)
196 NTSTATUS status = cli_nt_delete_on_close_recv(subreq);
197 tevent_req_simple_finish_ntstatus(subreq, status);
200 static NTSTATUS create_ts_recv(struct tevent_req *req, uint16_t *fnum)
202 struct create_ts_state *state = tevent_req_data(
203 req, struct create_ts_state);
204 NTSTATUS status;
206 if (tevent_req_is_nterror(req, &status)) {
207 return status;
209 *fnum = state->fnum;
210 tevent_req_received(req);
211 return NT_STATUS_OK;
214 struct create_ts_files_state {
215 size_t num_files;
216 size_t num_received;
217 uint16_t *fnums;
220 static void create_ts_files_done(struct tevent_req *subreq);
222 static struct tevent_req *create_ts_files_send(
223 TALLOC_CTX *mem_ctx,
224 struct tevent_context *ev,
225 struct cli_state *cli,
226 const char *prefix,
227 size_t idx,
228 size_t num_files)
230 struct tevent_req *req = NULL;
231 struct create_ts_files_state *state = NULL;
232 size_t i;
234 req = tevent_req_create(mem_ctx, &state, struct create_ts_files_state);
235 if (req == NULL) {
236 return NULL;
238 state->num_files = num_files;
240 state->fnums = talloc_array(state, uint16_t, num_files);
241 if (tevent_req_nomem(state->fnums, req)) {
242 return tevent_req_post(req, ev);
245 for (i=0; i<num_files; i++) {
246 struct tevent_req *subreq = NULL;
247 const char *fname = NULL;
249 fname = talloc_asprintf(state, "%s%zu_%zu", prefix, idx, i);
250 if (tevent_req_nomem(fname, req)) {
251 return tevent_req_post(req, ev);
254 subreq = create_ts_send(state, ev, cli, fname, i);
255 if (tevent_req_nomem(subreq, req)) {
256 return tevent_req_post(req, ev);
258 talloc_steal(subreq, fname);
260 tevent_req_set_callback(subreq, create_ts_files_done, req);
262 return req;
265 static void create_ts_files_done(struct tevent_req *subreq)
267 struct tevent_req *req = tevent_req_callback_data(
268 subreq, struct tevent_req);
269 struct create_ts_files_state *state = tevent_req_data(
270 req, struct create_ts_files_state);
271 NTSTATUS status;
273 status = create_ts_recv(subreq, &state->fnums[state->num_received]);
274 TALLOC_FREE(subreq);
275 if (tevent_req_nterror(req, status)) {
276 return;
279 state->num_received += 1;
280 if (state->num_received == state->num_files) {
281 tevent_req_done(req);
285 static NTSTATUS create_ts_files_recv(
286 struct tevent_req *req, TALLOC_CTX *mem_ctx, uint16_t **fnums)
288 struct create_ts_files_state *state = tevent_req_data(
289 req, struct create_ts_files_state);
290 NTSTATUS status;
292 if (tevent_req_is_nterror(req, &status)) {
293 return status;
295 *fnums = talloc_move(mem_ctx, &state->fnums);
296 tevent_req_received(req);
297 return NT_STATUS_OK;
300 struct create_files_state {
301 size_t num_reqs;
302 size_t num_received;
303 struct tevent_req **reqs;
304 uint16_t **fnums;
307 static void create_files_done(struct tevent_req *subreq);
309 static struct tevent_req *create_files_send(
310 TALLOC_CTX *mem_ctx,
311 struct tevent_context *ev,
312 struct cli_state **cli,
313 size_t num_cli,
314 const char *prefix,
315 size_t num_files)
317 struct tevent_req *req = NULL;
318 struct create_files_state *state = NULL;
319 size_t i;
321 req = tevent_req_create(mem_ctx, &state, struct create_files_state);
322 if (req == NULL) {
323 return NULL;
325 state->num_reqs = num_cli;
327 state->reqs = talloc_array(state, struct tevent_req *, num_cli);
328 if (tevent_req_nomem(state->reqs, req)) {
329 return tevent_req_post(req, ev);
331 state->fnums = talloc_array(state, uint16_t *, num_cli);
332 if (tevent_req_nomem(state->fnums, req)) {
333 return tevent_req_post(req, ev);
336 for (i=0; i<num_cli; i++) {
337 state->reqs[i] = create_ts_files_send(
338 state, ev, cli[i], prefix, i, num_files);
339 if (tevent_req_nomem(state->reqs[i], req)) {
340 return tevent_req_post(req, ev);
342 tevent_req_set_callback(
343 state->reqs[i], create_files_done, req);
345 return req;
348 static void create_files_done(struct tevent_req *subreq)
350 struct tevent_req *req = tevent_req_callback_data(
351 subreq, struct tevent_req);
352 struct create_files_state *state = tevent_req_data(
353 req, struct create_files_state);
354 uint16_t *fnums = NULL;
355 NTSTATUS status;
356 size_t i;
358 status = create_ts_files_recv(subreq, state->fnums, &fnums);
359 if (tevent_req_nterror(req, status)) {
360 return;
363 for (i=0; i<state->num_reqs; i++) {
364 if (state->reqs[i] == subreq) {
365 break;
368 if (i == state->num_reqs) {
369 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
370 return;
373 TALLOC_FREE(subreq);
374 state->reqs[i] = NULL;
375 state->fnums[i] = fnums;
377 state->num_received += 1;
379 if (state->num_reqs == state->num_received) {
380 tevent_req_done(req);
384 static NTSTATUS create_files_recv(
385 struct tevent_req *req, TALLOC_CTX *mem_ctx, uint16_t ***fnums)
387 struct create_files_state *state = tevent_req_data(
388 req, struct create_files_state);
389 NTSTATUS status;
391 if (tevent_req_is_nterror(req, &status)) {
392 return status;
395 *fnums = talloc_move(mem_ctx, &state->fnums);
396 tevent_req_received(req);
397 return NT_STATUS_OK;
400 struct list_cb_state {
401 size_t found;
402 bool ok;
405 static NTSTATUS list_cb(
406 struct file_info *f,
407 const char *mask,
408 void *private_data)
410 struct list_cb_state *state = private_data;
411 char *underbar = NULL;
412 unsigned long long int name_idx;
413 int err;
415 underbar = strchr(f->name, '_');
416 if (underbar == NULL) {
417 /* alien filename, . or ..? */
418 return NT_STATUS_OK;
421 name_idx = smb_strtoull(underbar+1, NULL, 10, &err, SMB_STR_STANDARD);
422 if (err != 0) {
423 /* non-numeric? */
424 return NT_STATUS_OK;
427 if ((name_idx & 0xFFFF) != (f->mtime_ts.tv_sec & 0xFFFF)) {
428 d_printf("idx=%llu, nsec=%ld\n",
429 name_idx,
430 f->mtime_ts.tv_nsec);
431 state->ok = false;
433 state->found += 1;
435 return NT_STATUS_OK;
438 bool run_readdir_timestamp(int dummy)
440 struct cli_state **cli = NULL;
441 int i;
442 bool ret = false;
443 bool ok;
444 const char prefix[] = "readdir_ts/";
445 struct list_cb_state state = { .ok = true };
446 struct tevent_context *ev = NULL;
447 struct tevent_req *req = NULL;
448 uint16_t **fnums = NULL;
449 NTSTATUS status;
450 size_t expected;
452 cli = talloc_array(talloc_tos(), struct cli_state *, torture_nprocs);
453 if (cli == NULL) {
454 d_printf("talloc_array failed\n");
455 goto fail;
458 for (i=0; i<torture_nprocs; i++) {
459 ok = torture_open_connection_flags(&cli[i], i, 0);
460 if (!ok) {
461 d_printf("torture_open_connection_flags(%d) failed\n",
463 goto fail;
467 status = cli_mkdir(cli[0], "readdir_ts");
468 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
469 status = NT_STATUS_OK;
471 if (!NT_STATUS_IS_OK(status)) {
472 d_printf("cli_mkdir failed: %s\n", nt_errstr(status));
473 goto fail;
476 ev = samba_tevent_context_init(cli);
477 if (ev == NULL) {
478 d_printf("samba_tevent_context_init() failed\n");
479 goto fail;
482 req = create_files_send(
483 cli, ev, cli, torture_nprocs, prefix, torture_numops);
484 if (req == NULL) {
485 d_printf("create_files_send() failed\n");
486 goto fail;
489 ok = tevent_req_poll_ntstatus(req, ev, &status);
490 if (!ok) {
491 d_printf("tevent_req_poll_ntstatus failed: %s\n",
492 nt_errstr(status));
493 goto fail;
496 status = create_files_recv(req, talloc_tos(), &fnums);
497 TALLOC_FREE(req);
498 if (!NT_STATUS_IS_OK(status)) {
499 d_printf("create_files_recv failed: %s\n",
500 nt_errstr(status));
501 goto fail;
504 status = cli_list(cli[0],
505 "readdir_ts\\*",
506 FILE_ATTRIBUTE_DIRECTORY |
507 FILE_ATTRIBUTE_SYSTEM |
508 FILE_ATTRIBUTE_HIDDEN,
509 list_cb,
510 &state);
511 if (!NT_STATUS_IS_OK(status)) {
512 d_printf("cli_list failed: %s\n",
513 nt_errstr(status));
514 goto fail;
517 expected = torture_nprocs * torture_numops;
518 if (state.found != expected) {
519 d_printf("Expected %zu, got %zu files\n",
520 expected,
521 state.found);
522 goto fail;
524 if (!state.ok) {
525 d_printf("timestamp mismatch\n");
526 goto fail;
529 ret = true;
530 fail:
531 TALLOC_FREE(cli);
532 return ret;