LCOV - code coverage report
Current view: top level - source3/torture - test_readdir_timestamp.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 0 255 0.0 %
Date: 2024-02-28 12:06:22 Functions: 0 15 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * Copyright (C) Volker Lendecke 2020
       4             :  *
       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.
       9             :  *
      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.
      14             :  *
      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/>.
      17             :  */
      18             : 
      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"
      25             : 
      26             : extern int torture_nprocs;
      27             : extern int torture_numops;
      28             : 
      29             : struct create_ts_state {
      30             :         struct tevent_context *ev;
      31             :         struct cli_state *cli;
      32             :         unsigned timestamp_idx;
      33             :         uint16_t fnum;
      34             : };
      35             : 
      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);
      41             : 
      42           0 : 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)
      48             : {
      49           0 :         struct tevent_req *req = NULL, *subreq = NULL;
      50           0 :         struct create_ts_state *state = NULL;
      51             : 
      52           0 :         req = tevent_req_create(mem_ctx, &state, struct create_ts_state);
      53           0 :         if (req == NULL) {
      54           0 :                 return NULL;
      55             :         }
      56           0 :         state->ev = ev;
      57           0 :         state->cli = cli;
      58           0 :         state->timestamp_idx = timestamp_idx;
      59             : 
      60           0 :         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           0 :         if (tevent_req_nomem(subreq, req)) {
      76           0 :                 return tevent_req_post(req, ev);
      77             :         }
      78           0 :         tevent_req_set_callback(subreq, create_ts_opened, req);
      79           0 :         return req;
      80             : }
      81             : 
      82           0 : static void create_ts_opened(struct tevent_req *subreq)
      83             : {
      84           0 :         struct tevent_req *req = tevent_req_callback_data(
      85             :                 subreq, struct tevent_req);
      86           0 :         struct create_ts_state *state = tevent_req_data(
      87             :                 req, struct create_ts_state);
      88           0 :         struct smb_create_returns cr;
      89           0 :         struct timespec mtime;
      90           0 :         NTSTATUS status;
      91             : 
      92           0 :         status = cli_ntcreate_recv(subreq, &state->fnum, &cr);
      93           0 :         TALLOC_FREE(subreq);
      94           0 :         if (tevent_req_nterror(req, status)) {
      95           0 :                 return;
      96             :         }
      97             : 
      98           0 :         mtime = nt_time_to_unix_timespec(cr.last_write_time);
      99             : 
     100           0 :         mtime.tv_sec &= ~(0xFFFFULL);
     101           0 :         mtime.tv_sec |= (state->timestamp_idx & 0xFFFF);
     102             : 
     103           0 :         subreq = cli_setfileinfo_ext_send(
     104             :                 state,
     105             :                 state->ev,
     106             :                 state->cli,
     107           0 :                 state->fnum,
     108           0 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* create */
     109           0 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* access */
     110             :                 mtime,
     111           0 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT }, /* change */
     112             :                 UINT32_MAX);    /* attr */
     113           0 :         if (tevent_req_nomem(subreq, req)) {
     114           0 :                 return;
     115             :         }
     116           0 :         tevent_req_set_callback(subreq, create_ts_setinfo_done, req);
     117             : }
     118             : 
     119           0 : static void create_ts_setinfo_done(struct tevent_req *subreq)
     120             : {
     121           0 :         struct tevent_req *req = tevent_req_callback_data(
     122             :                 subreq, struct tevent_req);
     123           0 :         struct create_ts_state *state = tevent_req_data(
     124             :                 req, struct create_ts_state);
     125           0 :         NTSTATUS status;
     126             : 
     127           0 :         status = cli_setfileinfo_ext_recv(subreq);
     128           0 :         TALLOC_FREE(subreq);
     129           0 :         if (tevent_req_nterror(req, status)) {
     130           0 :                 return;
     131             :         }
     132             : 
     133           0 :         subreq = tevent_wakeup_send(
     134             :                 state, state->ev, timeval_current_ofs_msec(100));
     135           0 :         if (tevent_req_nomem(subreq, req)) {
     136           0 :                 return;
     137             :         }
     138           0 :         tevent_req_set_callback(subreq, create_ts_waited, req);
     139             : }
     140             : 
     141           0 : static void create_ts_waited(struct tevent_req *subreq)
     142             : {
     143           0 :         struct tevent_req *req = tevent_req_callback_data(
     144             :                 subreq, struct tevent_req);
     145           0 :         struct create_ts_state *state = tevent_req_data(
     146             :                 req, struct create_ts_state);
     147           0 :         bool ok;
     148             : 
     149           0 :         ok = tevent_wakeup_recv(subreq);
     150           0 :         TALLOC_FREE(subreq);
     151           0 :         if (!ok) {
     152           0 :                 tevent_req_oom(subreq);
     153           0 :                 return;
     154             :         }
     155             : 
     156           0 :         subreq = cli_write_send(
     157             :                 state,
     158             :                 state->ev,
     159             :                 state->cli,
     160           0 :                 state->fnum,
     161             :                 0,
     162           0 :                 (uint8_t *)&state->fnum,
     163             :                 0,
     164             :                 sizeof(state->fnum));
     165           0 :         if (tevent_req_nomem(subreq, req)) {
     166           0 :                 return;
     167             :         }
     168           0 :         tevent_req_set_callback(subreq, create_ts_written, req);
     169             : }
     170             : 
     171           0 : static void create_ts_written(struct tevent_req *subreq)
     172             : {
     173           0 :         struct tevent_req *req = tevent_req_callback_data(
     174             :                 subreq, struct tevent_req);
     175           0 :         struct create_ts_state *state = tevent_req_data(
     176             :                 req, struct create_ts_state);
     177           0 :         size_t written;
     178           0 :         NTSTATUS status;
     179             : 
     180           0 :         status = cli_write_recv(subreq, &written);
     181           0 :         TALLOC_FREE(subreq);
     182           0 :         if (tevent_req_nterror(subreq, status)) {
     183           0 :                 return;
     184             :         }
     185             : 
     186           0 :         subreq = cli_nt_delete_on_close_send(
     187           0 :                 state, state->ev, state->cli, state->fnum, true);
     188           0 :         if (tevent_req_nomem(subreq, req)) {
     189           0 :                 return;
     190             :         }
     191           0 :         tevent_req_set_callback(subreq, create_ts_doc_done, req);
     192             : }
     193             : 
     194           0 : static void create_ts_doc_done(struct tevent_req *subreq)
     195             : {
     196           0 :         NTSTATUS status = cli_nt_delete_on_close_recv(subreq);
     197           0 :         tevent_req_simple_finish_ntstatus(subreq, status);
     198           0 : }
     199             : 
     200           0 : static NTSTATUS create_ts_recv(struct tevent_req *req, uint16_t *fnum)
     201             : {
     202           0 :         struct create_ts_state *state = tevent_req_data(
     203             :                 req, struct create_ts_state);
     204           0 :         NTSTATUS status;
     205             : 
     206           0 :         if (tevent_req_is_nterror(req, &status)) {
     207           0 :                 return status;
     208             :         }
     209           0 :         *fnum = state->fnum;
     210           0 :         tevent_req_received(req);
     211           0 :         return NT_STATUS_OK;
     212             : }
     213             : 
     214             : struct create_ts_files_state {
     215             :         size_t num_files;
     216             :         size_t num_received;
     217             :         uint16_t *fnums;
     218             : };
     219             : 
     220             : static void create_ts_files_done(struct tevent_req *subreq);
     221             : 
     222           0 : 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)
     229             : {
     230           0 :         struct tevent_req *req = NULL;
     231           0 :         struct create_ts_files_state *state = NULL;
     232           0 :         size_t i;
     233             : 
     234           0 :         req = tevent_req_create(mem_ctx, &state, struct create_ts_files_state);
     235           0 :         if (req == NULL) {
     236           0 :                 return NULL;
     237             :         }
     238           0 :         state->num_files = num_files;
     239             : 
     240           0 :         state->fnums = talloc_array(state, uint16_t, num_files);
     241           0 :         if (tevent_req_nomem(state->fnums, req)) {
     242           0 :                 return tevent_req_post(req, ev);
     243             :         }
     244             : 
     245           0 :         for (i=0; i<num_files; i++) {
     246           0 :                 struct tevent_req *subreq = NULL;
     247           0 :                 const char *fname = NULL;
     248             : 
     249           0 :                 fname = talloc_asprintf(state, "%s%zu_%zu", prefix, idx, i);
     250           0 :                 if (tevent_req_nomem(fname, req)) {
     251           0 :                         return tevent_req_post(req, ev);
     252             :                 }
     253             : 
     254           0 :                 subreq = create_ts_send(state, ev, cli, fname, i);
     255           0 :                 if (tevent_req_nomem(subreq, req)) {
     256           0 :                         return tevent_req_post(req, ev);
     257             :                 }
     258           0 :                 talloc_steal(subreq, fname);
     259             : 
     260           0 :                 tevent_req_set_callback(subreq, create_ts_files_done, req);
     261             :         }
     262           0 :         return req;
     263             : }
     264             : 
     265           0 : static void create_ts_files_done(struct tevent_req *subreq)
     266             : {
     267           0 :         struct tevent_req *req = tevent_req_callback_data(
     268             :                 subreq, struct tevent_req);
     269           0 :         struct create_ts_files_state *state = tevent_req_data(
     270             :                 req, struct create_ts_files_state);
     271           0 :         NTSTATUS status;
     272             : 
     273           0 :         status = create_ts_recv(subreq, &state->fnums[state->num_received]);
     274           0 :         TALLOC_FREE(subreq);
     275           0 :         if (tevent_req_nterror(req, status)) {
     276           0 :                 return;
     277             :         }
     278             : 
     279           0 :         state->num_received += 1;
     280           0 :         if (state->num_received == state->num_files) {
     281           0 :                 tevent_req_done(req);
     282             :         }
     283             : }
     284             : 
     285           0 : static NTSTATUS create_ts_files_recv(
     286             :         struct tevent_req *req, TALLOC_CTX *mem_ctx, uint16_t **fnums)
     287             : {
     288           0 :         struct create_ts_files_state *state = tevent_req_data(
     289             :                 req, struct create_ts_files_state);
     290           0 :         NTSTATUS status;
     291             : 
     292           0 :         if (tevent_req_is_nterror(req, &status)) {
     293           0 :                 return status;
     294             :         }
     295           0 :         *fnums = talloc_move(mem_ctx, &state->fnums);
     296           0 :         tevent_req_received(req);
     297           0 :         return NT_STATUS_OK;
     298             : }
     299             : 
     300             : struct create_files_state {
     301             :         size_t num_reqs;
     302             :         size_t num_received;
     303             :         struct tevent_req **reqs;
     304             :         uint16_t **fnums;
     305             : };
     306             : 
     307             : static void create_files_done(struct tevent_req *subreq);
     308             : 
     309           0 : 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)
     316             : {
     317           0 :         struct tevent_req *req = NULL;
     318           0 :         struct create_files_state *state = NULL;
     319           0 :         size_t i;
     320             : 
     321           0 :         req = tevent_req_create(mem_ctx, &state, struct create_files_state);
     322           0 :         if (req == NULL) {
     323           0 :                 return NULL;
     324             :         }
     325           0 :         state->num_reqs = num_cli;
     326             : 
     327           0 :         state->reqs = talloc_array(state, struct tevent_req *, num_cli);
     328           0 :         if (tevent_req_nomem(state->reqs, req)) {
     329           0 :                 return tevent_req_post(req, ev);
     330             :         }
     331           0 :         state->fnums = talloc_array(state, uint16_t *, num_cli);
     332           0 :         if (tevent_req_nomem(state->fnums, req)) {
     333           0 :                 return tevent_req_post(req, ev);
     334             :         }
     335             : 
     336           0 :         for (i=0; i<num_cli; i++) {
     337           0 :                 state->reqs[i] = create_ts_files_send(
     338           0 :                         state, ev, cli[i], prefix, i, num_files);
     339           0 :                 if (tevent_req_nomem(state->reqs[i], req)) {
     340           0 :                         return tevent_req_post(req, ev);
     341             :                 }
     342           0 :                 tevent_req_set_callback(
     343             :                         state->reqs[i], create_files_done, req);
     344             :         }
     345           0 :         return req;
     346             : }
     347             : 
     348           0 : static void create_files_done(struct tevent_req *subreq)
     349             : {
     350           0 :         struct tevent_req *req = tevent_req_callback_data(
     351             :                 subreq, struct tevent_req);
     352           0 :         struct create_files_state *state = tevent_req_data(
     353             :                 req, struct create_files_state);
     354           0 :         uint16_t *fnums = NULL;
     355           0 :         NTSTATUS status;
     356           0 :         size_t i;
     357             : 
     358           0 :         status = create_ts_files_recv(subreq, state->fnums, &fnums);
     359           0 :         if (tevent_req_nterror(req, status)) {
     360           0 :                 return;
     361             :         }
     362             : 
     363           0 :         for (i=0; i<state->num_reqs; i++) {
     364           0 :                 if (state->reqs[i] == subreq) {
     365           0 :                         break;
     366             :                 }
     367             :         }
     368           0 :         if (i == state->num_reqs) {
     369           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     370           0 :                 return;
     371             :         }
     372             : 
     373           0 :         TALLOC_FREE(subreq);
     374           0 :         state->reqs[i] = NULL;
     375           0 :         state->fnums[i] = fnums;
     376             : 
     377           0 :         state->num_received += 1;
     378             : 
     379           0 :         if (state->num_reqs == state->num_received) {
     380           0 :                 tevent_req_done(req);
     381             :         }
     382             : }
     383             : 
     384           0 : static NTSTATUS create_files_recv(
     385             :         struct tevent_req *req, TALLOC_CTX *mem_ctx, uint16_t ***fnums)
     386             : {
     387           0 :         struct create_files_state *state = tevent_req_data(
     388             :                 req, struct create_files_state);
     389           0 :         NTSTATUS status;
     390             : 
     391           0 :         if (tevent_req_is_nterror(req, &status)) {
     392           0 :                 return status;
     393             :         }
     394             : 
     395           0 :         *fnums = talloc_move(mem_ctx, &state->fnums);
     396           0 :         tevent_req_received(req);
     397           0 :         return NT_STATUS_OK;
     398             : }
     399             : 
     400             : struct list_cb_state {
     401             :         size_t found;
     402             :         bool ok;
     403             : };
     404             : 
     405           0 : static NTSTATUS list_cb(
     406             :         struct file_info *f,
     407             :         const char *mask,
     408             :         void *private_data)
     409             : {
     410           0 :         struct list_cb_state *state = private_data;
     411           0 :         char *underbar = NULL;
     412           0 :         unsigned long long int name_idx;
     413           0 :         int err;
     414             : 
     415           0 :         underbar = strchr(f->name, '_');
     416           0 :         if (underbar == NULL) {
     417             :                 /* alien filename, . or ..? */
     418           0 :                 return NT_STATUS_OK;
     419             :         }
     420             : 
     421           0 :         name_idx = smb_strtoull(underbar+1, NULL, 10, &err, SMB_STR_STANDARD);
     422           0 :         if (err != 0) {
     423             :                 /* non-numeric? */
     424           0 :                 return NT_STATUS_OK;
     425             :         }
     426             : 
     427           0 :         if ((name_idx & 0xFFFF) != (f->mtime_ts.tv_sec & 0xFFFF)) {
     428           0 :                 d_printf("idx=%llu, nsec=%ld\n",
     429             :                          name_idx,
     430             :                          f->mtime_ts.tv_nsec);
     431           0 :                 state->ok = false;
     432             :         }
     433           0 :         state->found += 1;
     434             : 
     435           0 :         return NT_STATUS_OK;
     436             : }
     437             : 
     438           0 : bool run_readdir_timestamp(int dummy)
     439             : {
     440           0 :         struct cli_state **cli = NULL;
     441           0 :         int i;
     442           0 :         bool ret = false;
     443           0 :         bool ok;
     444           0 :         const char prefix[] = "readdir_ts/";
     445           0 :         struct list_cb_state state = { .ok = true };
     446           0 :         struct tevent_context *ev = NULL;
     447           0 :         struct tevent_req *req = NULL;
     448           0 :         uint16_t **fnums = NULL;
     449           0 :         NTSTATUS status;
     450           0 :         size_t expected;
     451             : 
     452           0 :         cli = talloc_array(talloc_tos(), struct cli_state *, torture_nprocs);
     453           0 :         if (cli == NULL) {
     454           0 :                 d_printf("talloc_array failed\n");
     455           0 :                 goto fail;
     456             :         }
     457             : 
     458           0 :         for (i=0; i<torture_nprocs; i++) {
     459           0 :                 ok = torture_open_connection_flags(&cli[i], i, 0);
     460           0 :                 if (!ok) {
     461           0 :                         d_printf("torture_open_connection_flags(%d) failed\n",
     462             :                                  i);
     463           0 :                         goto fail;
     464             :                 }
     465             :         }
     466             : 
     467           0 :         status = cli_mkdir(cli[0], "readdir_ts");
     468           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
     469           0 :                 status = NT_STATUS_OK;
     470             :         }
     471           0 :         if (!NT_STATUS_IS_OK(status)) {
     472           0 :                 d_printf("cli_mkdir failed: %s\n", nt_errstr(status));
     473           0 :                 goto fail;
     474             :         }
     475             : 
     476           0 :         ev = samba_tevent_context_init(cli);
     477           0 :         if (ev == NULL) {
     478           0 :                 d_printf("samba_tevent_context_init() failed\n");
     479           0 :                 goto fail;
     480             :         }
     481             : 
     482           0 :         req = create_files_send(
     483             :                 cli, ev, cli, torture_nprocs, prefix, torture_numops);
     484           0 :         if (req == NULL) {
     485           0 :                 d_printf("create_files_send() failed\n");
     486           0 :                 goto fail;
     487             :         }
     488             : 
     489           0 :         ok = tevent_req_poll_ntstatus(req, ev, &status);
     490           0 :         if (!ok) {
     491           0 :                 d_printf("tevent_req_poll_ntstatus failed: %s\n",
     492             :                          nt_errstr(status));
     493           0 :                 goto fail;
     494             :         }
     495             : 
     496           0 :         status = create_files_recv(req, talloc_tos(), &fnums);
     497           0 :         TALLOC_FREE(req);
     498           0 :         if (!NT_STATUS_IS_OK(status)) {
     499           0 :                 d_printf("create_files_recv failed: %s\n",
     500             :                          nt_errstr(status));
     501           0 :                 goto fail;
     502             :         }
     503             : 
     504           0 :         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           0 :         if (!NT_STATUS_IS_OK(status)) {
     512           0 :                 d_printf("cli_list failed: %s\n",
     513             :                          nt_errstr(status));
     514           0 :                 goto fail;
     515             :         }
     516             : 
     517           0 :         expected = torture_nprocs * torture_numops;
     518           0 :         if (state.found != expected) {
     519           0 :                 d_printf("Expected %zu, got %zu files\n",
     520             :                          expected,
     521             :                          state.found);
     522           0 :                 goto fail;
     523             :         }
     524           0 :         if (!state.ok) {
     525           0 :                 d_printf("timestamp mismatch\n");
     526           0 :                 goto fail;
     527             :         }
     528             : 
     529           0 :         ret = true;
     530           0 : fail:
     531           0 :         TALLOC_FREE(cli);
     532           0 :         return ret;
     533             : }

Generated by: LCOV version 1.14