LCOV - code coverage report
Current view: top level - source3/smbd - smb2_query_directory.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 321 502 63.9 %
Date: 2023-11-21 12:31:41 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Core SMB2 server
       4             : 
       5             :    Copyright (C) Stefan Metzmacher 2009
       6             : 
       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.
      11             : 
      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.
      16             : 
      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/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "locking/share_mode_lock.h"
      23             : #include "smbd/smbd.h"
      24             : #include "smbd/globals.h"
      25             : #include "../libcli/smb/smb_common.h"
      26             : #include "trans2.h"
      27             : #include "../lib/util/tevent_ntstatus.h"
      28             : #include "system/filesys.h"
      29             : #include "lib/pthreadpool/pthreadpool_tevent.h"
      30             : 
      31             : #undef DBGC_CLASS
      32             : #define DBGC_CLASS DBGC_SMB2
      33             : 
      34             : static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
      35             :                                               struct tevent_context *ev,
      36             :                                               struct smbd_smb2_request *smb2req,
      37             :                                               struct files_struct *in_fsp,
      38             :                                               uint8_t in_file_info_class,
      39             :                                               uint8_t in_flags,
      40             :                                               uint32_t in_file_index,
      41             :                                               uint32_t in_output_buffer_length,
      42             :                                               const char *in_file_name);
      43             : static NTSTATUS smbd_smb2_query_directory_recv(struct tevent_req *req,
      44             :                                     TALLOC_CTX *mem_ctx,
      45             :                                     DATA_BLOB *out_output_buffer);
      46             : 
      47             : static void smbd_smb2_request_find_done(struct tevent_req *subreq);
      48       20212 : NTSTATUS smbd_smb2_request_process_query_directory(struct smbd_smb2_request *req)
      49             : {
      50           2 :         NTSTATUS status;
      51           2 :         const uint8_t *inbody;
      52           2 :         uint8_t in_file_info_class;
      53           2 :         uint8_t in_flags;
      54           2 :         uint32_t in_file_index;
      55           2 :         uint64_t in_file_id_persistent;
      56           2 :         uint64_t in_file_id_volatile;
      57           2 :         struct files_struct *in_fsp;
      58           2 :         uint16_t in_file_name_offset;
      59           2 :         uint16_t in_file_name_length;
      60           2 :         DATA_BLOB in_file_name_buffer;
      61           2 :         char *in_file_name_string;
      62           2 :         size_t in_file_name_string_size;
      63           2 :         uint32_t in_output_buffer_length;
      64           2 :         struct tevent_req *subreq;
      65           2 :         bool ok;
      66             : 
      67       20212 :         status = smbd_smb2_request_verify_sizes(req, 0x21);
      68       20212 :         if (!NT_STATUS_IS_OK(status)) {
      69           0 :                 return smbd_smb2_request_error(req, status);
      70             :         }
      71       20212 :         inbody = SMBD_SMB2_IN_BODY_PTR(req);
      72             : 
      73       20212 :         in_file_info_class              = CVAL(inbody, 0x02);
      74       20212 :         in_flags                        = CVAL(inbody, 0x03);
      75       20212 :         in_file_index                   = IVAL(inbody, 0x04);
      76       20212 :         in_file_id_persistent           = BVAL(inbody, 0x08);
      77       20212 :         in_file_id_volatile             = BVAL(inbody, 0x10);
      78       20212 :         in_file_name_offset             = SVAL(inbody, 0x18);
      79       20212 :         in_file_name_length             = SVAL(inbody, 0x1A);
      80       20212 :         in_output_buffer_length         = IVAL(inbody, 0x1C);
      81             : 
      82       20212 :         if (in_file_name_offset == 0 && in_file_name_length == 0) {
      83             :                 /* This is ok */
      84       20212 :         } else if (in_file_name_offset !=
      85       20212 :                    (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
      86           0 :                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
      87             :         }
      88             : 
      89       20212 :         if (in_file_name_length > SMBD_SMB2_IN_DYN_LEN(req)) {
      90           0 :                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
      91             :         }
      92             : 
      93             :         /* The output header is 8 bytes. */
      94       20212 :         if (in_output_buffer_length <= 8) {
      95           0 :                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
      96             :         }
      97             : 
      98       20212 :         DEBUG(10,("smbd_smb2_request_find_done: in_output_buffer_length = %u\n",
      99             :                 (unsigned int)in_output_buffer_length ));
     100             : 
     101             :         /* Take into account the output header. */
     102       20212 :         in_output_buffer_length -= 8;
     103             : 
     104       20212 :         in_file_name_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
     105       20212 :         in_file_name_buffer.length = in_file_name_length;
     106             : 
     107       20212 :         ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
     108       20210 :                                    in_file_name_buffer.data,
     109             :                                    in_file_name_buffer.length,
     110             :                                    &in_file_name_string,
     111             :                                    &in_file_name_string_size);
     112       20212 :         if (!ok) {
     113           0 :                 return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
     114             :         }
     115             : 
     116       20212 :         if (in_file_name_buffer.length == 0) {
     117           0 :                 in_file_name_string_size = 0;
     118             :         }
     119             : 
     120       20212 :         if (strlen(in_file_name_string) != in_file_name_string_size) {
     121           0 :                 return smbd_smb2_request_error(req, NT_STATUS_OBJECT_NAME_INVALID);
     122             :         }
     123             : 
     124       20212 :         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
     125       20212 :         if (in_fsp == NULL) {
     126           0 :                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
     127             :         }
     128             : 
     129       20212 :         subreq = smbd_smb2_query_directory_send(req, req->sconn->ev_ctx,
     130             :                                      req, in_fsp,
     131             :                                      in_file_info_class,
     132             :                                      in_flags,
     133             :                                      in_file_index,
     134             :                                      in_output_buffer_length,
     135             :                                      in_file_name_string);
     136       20212 :         if (subreq == NULL) {
     137           0 :                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     138             :         }
     139       20212 :         tevent_req_set_callback(subreq, smbd_smb2_request_find_done, req);
     140             : 
     141       20212 :         return smbd_smb2_request_pending_queue(req, subreq, 500);
     142             : }
     143             : 
     144       20212 : static void smbd_smb2_request_find_done(struct tevent_req *subreq)
     145             : {
     146       20212 :         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
     147             :                                         struct smbd_smb2_request);
     148           2 :         DATA_BLOB outbody;
     149           2 :         DATA_BLOB outdyn;
     150           2 :         uint16_t out_output_buffer_offset;
     151       20212 :         DATA_BLOB out_output_buffer = data_blob_null;
     152           2 :         NTSTATUS status;
     153           2 :         NTSTATUS error; /* transport error */
     154             : 
     155       20212 :         status = smbd_smb2_query_directory_recv(subreq,
     156             :                                      req,
     157             :                                      &out_output_buffer);
     158       20212 :         TALLOC_FREE(subreq);
     159       20212 :         if (!NT_STATUS_IS_OK(status)) {
     160        9186 :                 error = smbd_smb2_request_error(req, status);
     161        9186 :                 if (!NT_STATUS_IS_OK(error)) {
     162           0 :                         smbd_server_connection_terminate(req->xconn,
     163             :                                                          nt_errstr(error));
     164        9186 :                         return;
     165             :                 }
     166        9186 :                 return;
     167             :         }
     168             : 
     169       11026 :         out_output_buffer_offset = SMB2_HDR_BODY + 0x08;
     170             : 
     171       11026 :         outbody = smbd_smb2_generate_outbody(req, 0x08);
     172       11026 :         if (outbody.data == NULL) {
     173           0 :                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
     174           0 :                 if (!NT_STATUS_IS_OK(error)) {
     175           0 :                         smbd_server_connection_terminate(req->xconn,
     176             :                                                          nt_errstr(error));
     177           0 :                         return;
     178             :                 }
     179           0 :                 return;
     180             :         }
     181             : 
     182       11026 :         SSVAL(outbody.data, 0x00, 0x08 + 1);    /* struct size */
     183       11026 :         SSVAL(outbody.data, 0x02,
     184             :               out_output_buffer_offset);        /* output buffer offset */
     185       11026 :         SIVAL(outbody.data, 0x04,
     186             :               out_output_buffer.length);        /* output buffer length */
     187             : 
     188       11026 :         DEBUG(10,("smbd_smb2_request_find_done: out_output_buffer.length = %u\n",
     189             :                 (unsigned int)out_output_buffer.length ));
     190             : 
     191       11026 :         outdyn = out_output_buffer;
     192             : 
     193       11026 :         error = smbd_smb2_request_done(req, outbody, &outdyn);
     194       11026 :         if (!NT_STATUS_IS_OK(error)) {
     195           0 :                 smbd_server_connection_terminate(req->xconn,
     196             :                                                  nt_errstr(error));
     197           0 :                 return;
     198             :         }
     199             : }
     200             : 
     201             : static struct tevent_req *fetch_write_time_send(TALLOC_CTX *mem_ctx,
     202             :                                                 struct tevent_context *ev,
     203             :                                                 connection_struct *conn,
     204             :                                                 struct file_id id,
     205             :                                                 int info_level,
     206             :                                                 char *entry_marshall_buf,
     207             :                                                 bool *stop);
     208             : static NTSTATUS fetch_write_time_recv(struct tevent_req *req);
     209             : 
     210             : static struct tevent_req *fetch_dos_mode_send(
     211             :         TALLOC_CTX *mem_ctx,
     212             :         struct tevent_context *ev,
     213             :         struct files_struct *dir_fsp,
     214             :         struct smb_filename **smb_fname,
     215             :         uint32_t info_level,
     216             :         uint8_t *entry_marshall_buf);
     217             : 
     218             : static NTSTATUS fetch_dos_mode_recv(struct tevent_req *req);
     219             : 
     220             : struct smbd_smb2_query_directory_state {
     221             :         struct tevent_context *ev;
     222             :         struct smbd_smb2_request *smb2req;
     223             :         uint64_t async_sharemode_count;
     224             :         uint32_t find_async_delay_usec;
     225             :         DATA_BLOB out_output_buffer;
     226             :         struct smb_request *smbreq;
     227             :         int in_output_buffer_length;
     228             :         struct files_struct *dirfsp;
     229             :         const char *in_file_name;
     230             :         NTSTATUS empty_status;
     231             :         uint32_t info_level;
     232             :         uint32_t max_count;
     233             :         char *pdata;
     234             :         char *base_data;
     235             :         char *end_data;
     236             :         uint32_t num;
     237             :         uint32_t dirtype;
     238             :         bool dont_descend;
     239             :         bool ask_sharemode;
     240             :         bool async_dosmode;
     241             :         bool async_ask_sharemode;
     242             :         int last_entry_off;
     243             :         size_t max_async_dosmode_active;
     244             :         uint32_t async_dosmode_active;
     245             :         bool done;
     246             : };
     247             : 
     248             : static bool smb2_query_directory_next_entry(struct tevent_req *req);
     249             : static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq);
     250             : static void smb2_query_directory_dos_mode_done(struct tevent_req *subreq);
     251             : static void smb2_query_directory_waited(struct tevent_req *subreq);
     252             : 
     253       20212 : static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
     254             :                                               struct tevent_context *ev,
     255             :                                               struct smbd_smb2_request *smb2req,
     256             :                                               struct files_struct *fsp,
     257             :                                               uint8_t in_file_info_class,
     258             :                                               uint8_t in_flags,
     259             :                                               uint32_t in_file_index,
     260             :                                               uint32_t in_output_buffer_length,
     261             :                                               const char *in_file_name)
     262             : {
     263       20212 :         struct smbXsrv_connection *xconn = smb2req->xconn;
     264           2 :         struct tevent_req *req;
     265           2 :         struct smbd_smb2_query_directory_state *state;
     266       20212 :         connection_struct *conn = smb2req->tcon->compat;
     267           2 :         const struct loadparm_substitution *lp_sub =
     268       20212 :                 loadparm_s3_global_substitution();
     269           2 :         NTSTATUS status;
     270       20212 :         bool wcard_has_wild = false;
     271       20212 :         struct tm tm = {};
     272           2 :         char *p;
     273       20212 :         bool stop = false;
     274           2 :         bool ok;
     275       20212 :         bool posix_dir_handle = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN);
     276             : 
     277       20212 :         req = tevent_req_create(mem_ctx, &state,
     278             :                                 struct smbd_smb2_query_directory_state);
     279       20212 :         if (req == NULL) {
     280           0 :                 return NULL;
     281             :         }
     282       20212 :         state->ev = ev;
     283       20212 :         state->dirfsp = fsp;
     284       20212 :         state->smb2req = smb2req;
     285       20212 :         state->in_output_buffer_length = in_output_buffer_length;
     286       20212 :         state->in_file_name = in_file_name;
     287       20212 :         state->out_output_buffer = data_blob_null;
     288       20212 :         state->dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY;
     289             : 
     290       20212 :         DEBUG(10,("smbd_smb2_query_directory_send: %s - %s\n",
     291             :                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
     292             : 
     293       20212 :         state->smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
     294       20212 :         if (tevent_req_nomem(state->smbreq, req)) {
     295           0 :                 return tevent_req_post(req, ev);
     296             :         }
     297             : 
     298       20212 :         if (!fsp->fsp_flags.is_directory) {
     299           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
     300           0 :                 return tevent_req_post(req, ev);
     301             :         }
     302             : 
     303       20212 :         if (strcmp(state->in_file_name, "") == 0) {
     304           0 :                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
     305           0 :                 return tevent_req_post(req, ev);
     306             :         }
     307       20212 :         if (strchr_m(state->in_file_name, '\\') != NULL) {
     308           0 :                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
     309           0 :                 return tevent_req_post(req, ev);
     310             :         }
     311       20212 :         if (strchr_m(state->in_file_name, '/') != NULL) {
     312           0 :                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
     313           0 :                 return tevent_req_post(req, ev);
     314             :         }
     315             : 
     316       20212 :         p = strptime(state->in_file_name, GMT_FORMAT, &tm);
     317       20212 :         if ((p != NULL) && (*p =='\0')) {
     318             :                 /*
     319             :                  * Bogus find that asks for a shadow copy timestamp as a
     320             :                  * directory. The correct response is that it does not exist as
     321             :                  * a directory.
     322             :                  */
     323           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_FILE);
     324           0 :                 return tevent_req_post(req, ev);
     325             :         }
     326             : 
     327       20212 :         if (in_output_buffer_length > xconn->smb2.server.max_trans) {
     328           0 :                 DEBUG(2,("smbd_smb2_query_directory_send: "
     329             :                          "client ignored max trans:%s: 0x%08X: 0x%08X\n",
     330             :                          __location__, in_output_buffer_length,
     331             :                          xconn->smb2.server.max_trans));
     332           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     333           0 :                 return tevent_req_post(req, ev);
     334             :         }
     335             : 
     336       20212 :         status = smbd_smb2_request_verify_creditcharge(smb2req,
     337             :                                         in_output_buffer_length);
     338             : 
     339       20212 :         if (!NT_STATUS_IS_OK(status)) {
     340           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     341           0 :                 return tevent_req_post(req, ev);
     342             :         }
     343             : 
     344       20212 :         switch (in_file_info_class) {
     345         104 :         case SMB2_FIND_DIRECTORY_INFO:
     346         104 :                 state->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
     347         104 :                 break;
     348             : 
     349         880 :         case SMB2_FIND_FULL_DIRECTORY_INFO:
     350         880 :                 state->info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
     351         880 :                 break;
     352             : 
     353         784 :         case SMB2_FIND_BOTH_DIRECTORY_INFO:
     354         784 :                 state->info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
     355         784 :                 break;
     356             : 
     357        2409 :         case SMB2_FIND_NAME_INFO:
     358        2409 :                 state->info_level = SMB_FIND_FILE_NAMES_INFO;
     359        2409 :                 break;
     360             : 
     361       15991 :         case SMB2_FIND_ID_BOTH_DIRECTORY_INFO:
     362       15991 :                 state->info_level = SMB_FIND_ID_BOTH_DIRECTORY_INFO;
     363       15991 :                 break;
     364             : 
     365          32 :         case SMB2_FIND_ID_FULL_DIRECTORY_INFO:
     366          32 :                 state->info_level = SMB_FIND_ID_FULL_DIRECTORY_INFO;
     367          32 :                 break;
     368             : 
     369          12 :         case SMB2_FIND_POSIX_INFORMATION:
     370          12 :                 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_OPEN)) {
     371           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
     372           0 :                         return tevent_req_post(req, ev);
     373             :                 }
     374          12 :                 state->info_level = SMB2_FILE_POSIX_INFORMATION;
     375          12 :                 break;
     376           0 :         default:
     377           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_INFO_CLASS);
     378           0 :                 return tevent_req_post(req, ev);
     379             :         }
     380             : 
     381       20212 :         if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) {
     382          36 :                 struct vfs_open_how how = { .flags = O_RDONLY, };
     383             : 
     384          36 :                 status = fd_close(fsp);
     385          36 :                 if (tevent_req_nterror(req, status)) {
     386           0 :                         return tevent_req_post(req, ev);
     387             :                 }
     388             : 
     389             :                 /*
     390             :                  * fd_close() will close and invalidate the fsp's file
     391             :                  * descriptor. So we have to reopen it.
     392             :                  */
     393             : 
     394             : #ifdef O_DIRECTORY
     395          36 :                 how.flags |= O_DIRECTORY;
     396             : #endif
     397          36 :                 status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
     398          36 :                 if (tevent_req_nterror(req, status)) {
     399           0 :                         return tevent_req_post(req, ev);
     400             :                 }
     401             :         }
     402             : 
     403       20212 :         if (!state->smbreq->posix_pathnames) {
     404       20174 :                 wcard_has_wild = ms_has_wild(state->in_file_name);
     405             :         }
     406             : 
     407             :         /* Ensure we've canonicalized any search path if not a wildcard. */
     408       20212 :         if (!wcard_has_wild) {
     409             :                 /*
     410             :                  * We still need to do the case processing
     411             :                  * to save off the client-supplied last component.
     412             :                  * At least we know there's no @GMT normalization
     413             :                  * or MS-DFS paths to do in a directory mask.
     414             :                  */
     415        3694 :                 state->in_file_name = get_original_lcomp(state,
     416             :                                                 conn,
     417        1847 :                                                 state->in_file_name,
     418             :                                                 0);
     419        1847 :                 if (tevent_req_nomem(state->in_file_name, req)) {
     420           0 :                         return tevent_req_post(req, ev);
     421             :                 }
     422             :         }
     423             : 
     424       20212 :         if (fsp->dptr == NULL) {
     425       10031 :                 status = dptr_create(conn,
     426             :                                      NULL, /* req */
     427             :                                      fsp,
     428             :                                      false, /* old_handle */
     429       10027 :                                      state->in_file_name, /* wcard */
     430       10029 :                                      state->dirtype,
     431             :                                      &fsp->dptr);
     432       10029 :                 if (!NT_STATUS_IS_OK(status)) {
     433           0 :                         tevent_req_nterror(req, status);
     434           0 :                         return tevent_req_post(req, ev);
     435             :                 }
     436             : 
     437       10029 :                 state->empty_status = NT_STATUS_NO_SUCH_FILE;
     438             :         } else {
     439       10183 :                 state->empty_status = STATUS_NO_MORE_FILES;
     440             :         }
     441             : 
     442       20212 :         if (in_flags & SMB2_CONTINUE_FLAG_RESTART) {
     443         514 :                 dptr_RewindDir(fsp->dptr);
     444             :         }
     445             : 
     446       20212 :         if (in_flags & SMB2_CONTINUE_FLAG_SINGLE) {
     447         126 :                 state->max_count = 1;
     448             :         } else {
     449       20086 :                 state->max_count = UINT16_MAX;
     450             :         }
     451             : 
     452             : #define DIR_ENTRY_SAFETY_MARGIN 4096
     453             : 
     454       20212 :         state->out_output_buffer = data_blob_talloc(state, NULL,
     455             :                         in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN);
     456       20212 :         if (tevent_req_nomem(state->out_output_buffer.data, req)) {
     457           0 :                 return tevent_req_post(req, ev);
     458             :         }
     459             : 
     460       20212 :         state->out_output_buffer.length = 0;
     461       20212 :         state->pdata = (char *)state->out_output_buffer.data;
     462       20212 :         state->base_data = state->pdata;
     463             :         /*
     464             :          * end_data must include the safety margin as it's what is
     465             :          * used to determine if pushed strings have been truncated.
     466             :          */
     467       20212 :         state->end_data = state->pdata + in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN - 1;
     468             : 
     469       20212 :         DEBUG(8,("smbd_smb2_query_directory_send: dirpath=<%s> dontdescend=<%s>, "
     470             :                 "in_output_buffer_length = %u\n",
     471             :                  fsp->fsp_name->base_name, lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
     472             :                 (unsigned int)in_output_buffer_length ));
     473       40386 :         if (in_list(fsp->fsp_name->base_name,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
     474       20174 :                         posix_dir_handle ? true : conn->case_sensitive)) {
     475           0 :                 state->dont_descend = true;
     476             :         }
     477             : 
     478             :         /*
     479             :          * SMB_FIND_FILE_NAMES_INFO doesn't need stat information
     480             :          *
     481             :          * This may change when we try to improve the delete on close
     482             :          * handling in future.
     483             :          */
     484       20212 :         if (state->info_level != SMB_FIND_FILE_NAMES_INFO) {
     485       17803 :                 state->ask_sharemode = fsp_search_ask_sharemode(fsp);
     486             : 
     487       17803 :                 state->async_dosmode = lp_smbd_async_dosmode(SNUM(conn));
     488             :         }
     489             : 
     490       20212 :         if (state->ask_sharemode && lp_clustering()) {
     491           0 :                 state->ask_sharemode = false;
     492           0 :                 state->async_ask_sharemode = true;
     493             :         }
     494             : 
     495       20212 :         if (state->async_dosmode) {
     496           0 :                 size_t max_threads;
     497             : 
     498          38 :                 max_threads = pthreadpool_tevent_max_threads(conn->sconn->pool);
     499          38 :                 if (max_threads == 0 || !per_thread_cwd_supported()) {
     500           0 :                         state->async_dosmode = false;
     501             :                 }
     502             : 
     503          76 :                 state->max_async_dosmode_active = lp_smbd_max_async_dosmode(
     504          38 :                                                         SNUM(conn));
     505          38 :                 if (state->max_async_dosmode_active == 0) {
     506          38 :                         state->max_async_dosmode_active = max_threads * 2;
     507             :                 }
     508             :         }
     509             : 
     510       20212 :         if (state->async_dosmode || state->async_ask_sharemode) {
     511             :                 /*
     512             :                  * Should we only set async_internal
     513             :                  * if we're not the last request in
     514             :                  * a compound chain?
     515             :                  */
     516          38 :                 smb2_request_set_async_internal(smb2req, true);
     517             :         }
     518             : 
     519             :         /*
     520             :          * This gets set in autobuild for some tests
     521             :          */
     522       20212 :         state->find_async_delay_usec = lp_parm_ulong(SNUM(conn), "smbd",
     523             :                                                      "find async delay usec",
     524             :                                                      0);
     525             : 
     526      735296 :         while (!stop) {
     527      715084 :                 stop = smb2_query_directory_next_entry(req);
     528             :         }
     529             : 
     530       20212 :         if (!tevent_req_is_in_progress(req)) {
     531       20170 :                 return tevent_req_post(req, ev);
     532             :         }
     533             : 
     534          42 :         ok = aio_add_req_to_fsp(fsp, req);
     535          42 :         if (!ok) {
     536           0 :                 DBG_ERR("Could not add req to fsp\n");
     537           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     538           0 :                 return tevent_req_post(req, ev);
     539             :         }
     540             : 
     541          42 :         return req;
     542             : }
     543             : 
     544      715084 : static bool smb2_query_directory_next_entry(struct tevent_req *req)
     545             : {
     546      715084 :         struct smbd_smb2_query_directory_state *state = tevent_req_data(
     547             :                 req, struct smbd_smb2_query_directory_state);
     548      715084 :         struct smb_filename *smb_fname = NULL; /* relative to fsp !! */
     549      715084 :         int off = state->out_output_buffer.length;
     550      715084 :         int space_remaining = state->in_output_buffer_length - off;
     551           8 :         struct file_id file_id;
     552           8 :         NTSTATUS status;
     553      715084 :         bool get_dosmode = !state->async_dosmode;
     554      715084 :         bool stop = false;
     555             : 
     556      715084 :         SMB_ASSERT(space_remaining >= 0);
     557             : 
     558      715092 :         status = smbd_dirptr_lanman2_entry(state,
     559      715084 :                                            state->dirfsp->conn,
     560      715084 :                                            state->dirfsp->dptr,
     561      715084 :                                            state->smbreq->flags2,
     562             :                                            state->in_file_name,
     563             :                                            state->dirtype,
     564      715084 :                                            state->info_level,
     565             :                                            false, /* requires_resume_key */
     566      715084 :                                            state->dont_descend,
     567      715084 :                                            state->ask_sharemode,
     568             :                                            get_dosmode,
     569             :                                            8, /* align to 8 bytes */
     570             :                                            false, /* no padding */
     571             :                                            &state->pdata,
     572             :                                            state->base_data,
     573             :                                            state->end_data,
     574             :                                            space_remaining,
     575             :                                            &smb_fname,
     576             :                                            &state->last_entry_off,
     577             :                                            NULL,
     578             :                                            &file_id);
     579             : 
     580      715084 :         off = (int)PTR_DIFF(state->pdata, state->base_data);
     581             : 
     582      715084 :         if (!NT_STATUS_IS_OK(status)) {
     583       20134 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
     584             :                         /*
     585             :                          * Bad character conversion on name. Ignore this
     586             :                          * entry.
     587             :                          */
     588          28 :                         return false;
     589             :                 }
     590             : 
     591       20106 :                 if (state->num > 0) {
     592       10920 :                         goto last_entry_done;
     593             :                 }
     594             : 
     595        9186 :                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
     596           0 :                         tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
     597           0 :                         return true;
     598             :                 }
     599             : 
     600        9186 :                 tevent_req_nterror(req, state->empty_status);
     601        9186 :                 return true;
     602             :         }
     603             : 
     604      694950 :         if (state->async_ask_sharemode &&
     605           0 :             !S_ISDIR(smb_fname->st.st_ex_mode))
     606             :         {
     607           0 :                 struct tevent_req *subreq = NULL;
     608           0 :                 char *buf = state->base_data + state->last_entry_off;
     609             : 
     610           0 :                 subreq = fetch_write_time_send(state,
     611             :                                                state->ev,
     612           0 :                                                state->dirfsp->conn,
     613             :                                                file_id,
     614           0 :                                                state->info_level,
     615             :                                                buf,
     616             :                                                &stop);
     617           0 :                 if (tevent_req_nomem(subreq, req)) {
     618           0 :                         return true;
     619             :                 }
     620           0 :                 tevent_req_set_callback(
     621             :                         subreq,
     622             :                         smb2_query_directory_fetch_write_time_done,
     623             :                         req);
     624           0 :                 state->async_sharemode_count++;
     625             :         }
     626             : 
     627      694950 :         if (state->async_dosmode) {
     628       20138 :                 struct tevent_req *subreq = NULL;
     629       20138 :                 uint8_t *buf = NULL;
     630           0 :                 size_t outstanding_aio;
     631             : 
     632       20138 :                 buf = (uint8_t *)state->base_data + state->last_entry_off;
     633             : 
     634       20138 :                 subreq = fetch_dos_mode_send(state,
     635             :                                              state->ev,
     636             :                                              state->dirfsp,
     637             :                                              &smb_fname,
     638             :                                              state->info_level,
     639             :                                              buf);
     640       20138 :                 if (tevent_req_nomem(subreq, req)) {
     641           0 :                         return true;
     642             :                 }
     643       20138 :                 tevent_req_set_callback(subreq,
     644             :                                         smb2_query_directory_dos_mode_done,
     645             :                                         req);
     646             : 
     647       20138 :                 state->async_dosmode_active++;
     648             : 
     649       20138 :                 outstanding_aio = pthreadpool_tevent_queued_jobs(
     650       20138 :                         state->dirfsp->conn->sconn->pool);
     651             : 
     652       20138 :                 if (outstanding_aio > state->max_async_dosmode_active) {
     653           0 :                         stop = true;
     654             :                 }
     655             :         }
     656             : 
     657      694950 :         TALLOC_FREE(smb_fname);
     658             : 
     659      694950 :         state->num++;
     660      694950 :         state->out_output_buffer.length = off;
     661             : 
     662      694950 :         if (!state->done && state->num < state->max_count) {
     663      694844 :                 return stop;
     664             :         }
     665             : 
     666         106 : last_entry_done:
     667       11026 :         SIVAL(state->out_output_buffer.data, state->last_entry_off, 0);
     668             : 
     669       11026 :         state->done = true;
     670             : 
     671       11026 :         if (state->async_sharemode_count > 0) {
     672           0 :                 DBG_DEBUG("Stopping after %"PRIu64" async mtime "
     673             :                           "updates\n", state->async_sharemode_count);
     674           0 :                 return true;
     675             :         }
     676             : 
     677       11026 :         if (state->async_dosmode_active > 0) {
     678          26 :                 return true;
     679             :         }
     680             : 
     681       11000 :         if (state->find_async_delay_usec > 0) {
     682           0 :                 struct timeval tv;
     683          16 :                 struct tevent_req *subreq = NULL;
     684             : 
     685             :                 /*
     686             :                  * Should we only set async_internal
     687             :                  * if we're not the last request in
     688             :                  * a compound chain?
     689             :                  */
     690          16 :                 smb2_request_set_async_internal(state->smb2req, true);
     691             : 
     692          16 :                 tv = timeval_current_ofs(0, state->find_async_delay_usec);
     693             : 
     694          16 :                 subreq = tevent_wakeup_send(state, state->ev, tv);
     695          16 :                 if (tevent_req_nomem(subreq, req)) {
     696           0 :                         return true;
     697             :                 }
     698          16 :                 tevent_req_set_callback(subreq,
     699             :                                         smb2_query_directory_waited,
     700             :                                         req);
     701          16 :                 return true;
     702             :         }
     703             : 
     704       10984 :         tevent_req_done(req);
     705       10984 :         return true;
     706             : }
     707             : 
     708             : static void smb2_query_directory_check_next_entry(struct tevent_req *req);
     709             : 
     710           0 : static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq)
     711             : {
     712           0 :         struct tevent_req *req = tevent_req_callback_data(
     713             :                 subreq, struct tevent_req);
     714           0 :         struct smbd_smb2_query_directory_state *state = tevent_req_data(
     715             :                 req, struct smbd_smb2_query_directory_state);
     716           0 :         NTSTATUS status;
     717           0 :         bool ok;
     718             : 
     719             :         /*
     720             :          * Make sure we run as the user again
     721             :          */
     722           0 :         ok = change_to_user_and_service_by_fsp(state->dirfsp);
     723           0 :         SMB_ASSERT(ok);
     724             : 
     725           0 :         state->async_sharemode_count--;
     726             : 
     727           0 :         status = fetch_write_time_recv(subreq);
     728           0 :         TALLOC_FREE(subreq);
     729           0 :         if (tevent_req_nterror(req, status)) {
     730           0 :                 return;
     731             :         }
     732             : 
     733           0 :         smb2_query_directory_check_next_entry(req);
     734           0 :         return;
     735             : }
     736             : 
     737       20138 : static void smb2_query_directory_dos_mode_done(struct tevent_req *subreq)
     738             : {
     739           0 :         struct tevent_req *req =
     740       20138 :                 tevent_req_callback_data(subreq,
     741             :                 struct tevent_req);
     742           0 :         struct smbd_smb2_query_directory_state *state =
     743       20138 :                 tevent_req_data(req,
     744             :                 struct smbd_smb2_query_directory_state);
     745           0 :         NTSTATUS status;
     746           0 :         bool ok;
     747             : 
     748             :         /*
     749             :          * Make sure we run as the user again
     750             :          */
     751       20138 :         ok = change_to_user_and_service_by_fsp(state->dirfsp);
     752       20138 :         SMB_ASSERT(ok);
     753             : 
     754       20138 :         status = fetch_dos_mode_recv(subreq);
     755       20138 :         TALLOC_FREE(subreq);
     756       20138 :         if (tevent_req_nterror(req, status)) {
     757           0 :                 return;
     758             :         }
     759             : 
     760       20138 :         state->async_dosmode_active--;
     761             : 
     762       20138 :         smb2_query_directory_check_next_entry(req);
     763       20138 :         return;
     764             : }
     765             : 
     766       20138 : static void smb2_query_directory_check_next_entry(struct tevent_req *req)
     767             : {
     768       20138 :         struct smbd_smb2_query_directory_state *state = tevent_req_data(
     769             :                 req, struct smbd_smb2_query_directory_state);
     770       20138 :         bool stop = false;
     771             : 
     772       20138 :         if (!state->done) {
     773           0 :                 while (!stop) {
     774           0 :                         stop = smb2_query_directory_next_entry(req);
     775             :                 }
     776           0 :                 return;
     777             :         }
     778             : 
     779       20138 :         if (state->async_sharemode_count > 0 ||
     780       20138 :             state->async_dosmode_active > 0)
     781             :         {
     782       20112 :                 return;
     783             :         }
     784             : 
     785          26 :         if (state->find_async_delay_usec > 0) {
     786           0 :                 struct timeval tv;
     787           0 :                 struct tevent_req *subreq = NULL;
     788             : 
     789           0 :                 tv = timeval_current_ofs(0, state->find_async_delay_usec);
     790             : 
     791           0 :                 subreq = tevent_wakeup_send(state, state->ev, tv);
     792           0 :                 if (tevent_req_nomem(subreq, req)) {
     793           0 :                         tevent_req_post(req, state->ev);
     794           0 :                         return;
     795             :                 }
     796           0 :                 tevent_req_set_callback(subreq,
     797             :                                         smb2_query_directory_waited,
     798             :                                         req);
     799           0 :                 return;
     800             :         }
     801             : 
     802          26 :         tevent_req_done(req);
     803          26 :         return;
     804             : }
     805             : 
     806          16 : static void smb2_query_directory_waited(struct tevent_req *subreq)
     807             : {
     808          16 :         struct tevent_req *req = tevent_req_callback_data(
     809             :                 subreq, struct tevent_req);
     810           0 :         bool ok;
     811             : 
     812          16 :         ok = tevent_wakeup_recv(subreq);
     813          16 :         TALLOC_FREE(subreq);
     814          16 :         if (!ok) {
     815           0 :                 tevent_req_oom(req);
     816           0 :                 return;
     817             :         }
     818          16 :         tevent_req_done(req);
     819             : }
     820             : 
     821       20212 : static NTSTATUS smbd_smb2_query_directory_recv(struct tevent_req *req,
     822             :                                     TALLOC_CTX *mem_ctx,
     823             :                                     DATA_BLOB *out_output_buffer)
     824             : {
     825           2 :         NTSTATUS status;
     826       20212 :         struct smbd_smb2_query_directory_state *state = tevent_req_data(req,
     827             :                                              struct smbd_smb2_query_directory_state);
     828             : 
     829       20212 :         if (tevent_req_is_nterror(req, &status)) {
     830        9186 :                 tevent_req_received(req);
     831        9186 :                 return status;
     832             :         }
     833             : 
     834       11026 :         *out_output_buffer = state->out_output_buffer;
     835       11026 :         talloc_steal(mem_ctx, out_output_buffer->data);
     836             : 
     837       11026 :         tevent_req_received(req);
     838       11026 :         return NT_STATUS_OK;
     839             : }
     840             : 
     841             : struct fetch_write_time_state {
     842             :         connection_struct *conn;
     843             :         struct file_id id;
     844             :         int info_level;
     845             :         char *entry_marshall_buf;
     846             : };
     847             : 
     848             : static void fetch_write_time_done(struct tevent_req *subreq);
     849             : 
     850           0 : static struct tevent_req *fetch_write_time_send(TALLOC_CTX *mem_ctx,
     851             :                                                 struct tevent_context *ev,
     852             :                                                 connection_struct *conn,
     853             :                                                 struct file_id id,
     854             :                                                 int info_level,
     855             :                                                 char *entry_marshall_buf,
     856             :                                                 bool *stop)
     857             : {
     858           0 :         struct tevent_req *req = NULL;
     859           0 :         struct fetch_write_time_state *state = NULL;
     860           0 :         struct tevent_req *subreq = NULL;
     861           0 :         bool req_queued;
     862             : 
     863           0 :         *stop = false;
     864             : 
     865           0 :         req = tevent_req_create(mem_ctx, &state, struct fetch_write_time_state);
     866           0 :         if (req == NULL) {
     867           0 :                 return NULL;
     868             :         }
     869             : 
     870           0 :         *state = (struct fetch_write_time_state) {
     871             :                 .conn = conn,
     872             :                 .id = id,
     873             :                 .info_level = info_level,
     874             :                 .entry_marshall_buf = entry_marshall_buf,
     875             :         };
     876             : 
     877           0 :         subreq = fetch_share_mode_send(state, ev, id, &req_queued);
     878           0 :         if (tevent_req_nomem(subreq, req)) {
     879           0 :                 return tevent_req_post(req, ev);
     880             :         }
     881           0 :         tevent_req_set_callback(subreq, fetch_write_time_done, req);
     882             : 
     883           0 :         if (req_queued) {
     884           0 :                 *stop = true;
     885             :         }
     886           0 :         return req;
     887             : }
     888             : 
     889           0 : static void fetch_write_time_done(struct tevent_req *subreq)
     890             : {
     891           0 :         struct tevent_req *req = tevent_req_callback_data(
     892             :                 subreq, struct tevent_req);
     893           0 :         struct fetch_write_time_state *state = tevent_req_data(
     894             :                 req, struct fetch_write_time_state);
     895           0 :         struct timespec write_time;
     896           0 :         struct share_mode_lock *lck = NULL;
     897           0 :         NTSTATUS status;
     898           0 :         size_t off;
     899             : 
     900           0 :         status = fetch_share_mode_recv(subreq, state, &lck);
     901           0 :         TALLOC_FREE(subreq);
     902           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     903           0 :                 tevent_req_done(req);
     904           0 :                 return;
     905             :         }
     906           0 :         if (tevent_req_nterror(req, status)) {
     907           0 :                 return;
     908             :         }
     909             : 
     910           0 :         write_time = get_share_mode_write_time(lck);
     911           0 :         TALLOC_FREE(lck);
     912             : 
     913           0 :         if (is_omit_timespec(&write_time)) {
     914           0 :                 tevent_req_done(req);
     915           0 :                 return;
     916             :         }
     917             : 
     918           0 :         switch (state->info_level) {
     919           0 :         case SMB_FIND_FILE_DIRECTORY_INFO:
     920             :         case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
     921             :         case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
     922             :         case SMB_FIND_ID_FULL_DIRECTORY_INFO:
     923             :         case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
     924           0 :                 off = 24;
     925           0 :                 break;
     926             : 
     927           0 :         default:
     928           0 :                 DBG_ERR("Unsupported info_level [%d]\n", state->info_level);
     929           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
     930           0 :                 return;
     931             :         }
     932             : 
     933           0 :         put_long_date_full_timespec(state->conn->ts_res,
     934           0 :                                state->entry_marshall_buf + off,
     935             :                                &write_time);
     936             : 
     937           0 :         tevent_req_done(req);
     938           0 :         return;
     939             : }
     940             : 
     941           0 : static NTSTATUS fetch_write_time_recv(struct tevent_req *req)
     942             : {
     943           0 :         NTSTATUS status;
     944             : 
     945           0 :         if (tevent_req_is_nterror(req, &status)) {
     946           0 :                 tevent_req_received(req);
     947           0 :                 return status;
     948             :         }
     949             : 
     950           0 :         tevent_req_received(req);
     951           0 :         return NT_STATUS_OK;
     952             : }
     953             : 
     954             : struct fetch_dos_mode_state {
     955             :         struct files_struct *dir_fsp;
     956             :         struct smb_filename *smb_fname;
     957             :         uint32_t info_level;
     958             :         uint8_t *entry_marshall_buf;
     959             : };
     960             : 
     961             : static void fetch_dos_mode_done(struct tevent_req *subreq);
     962             : 
     963       20138 : static struct tevent_req *fetch_dos_mode_send(
     964             :                         TALLOC_CTX *mem_ctx,
     965             :                         struct tevent_context *ev,
     966             :                         struct files_struct *dir_fsp,
     967             :                         struct smb_filename **smb_fname,
     968             :                         uint32_t info_level,
     969             :                         uint8_t *entry_marshall_buf)
     970             : {
     971       20138 :         struct tevent_req *req = NULL;
     972       20138 :         struct fetch_dos_mode_state *state = NULL;
     973       20138 :         struct tevent_req *subreq = NULL;
     974             : 
     975       20138 :         req = tevent_req_create(mem_ctx, &state, struct fetch_dos_mode_state);
     976       20138 :         if (req == NULL) {
     977           0 :                 return NULL;
     978             :         }
     979       20138 :         *state = (struct fetch_dos_mode_state) {
     980             :                 .dir_fsp = dir_fsp,
     981             :                 .info_level = info_level,
     982             :                 .entry_marshall_buf = entry_marshall_buf,
     983             :         };
     984             : 
     985       20138 :         state->smb_fname = talloc_move(state, smb_fname);
     986             : 
     987       20138 :         subreq = dos_mode_at_send(state, ev, dir_fsp, state->smb_fname);
     988       20138 :         if (tevent_req_nomem(subreq, req)) {
     989           0 :                 return tevent_req_post(req, ev);
     990             :         }
     991       20138 :         tevent_req_set_callback(subreq, fetch_dos_mode_done, req);
     992             : 
     993       20138 :         return req;
     994             : }
     995             : 
     996       20138 : static void fetch_dos_mode_done(struct tevent_req *subreq)
     997             : {
     998           0 :         struct tevent_req *req =
     999       20138 :                 tevent_req_callback_data(subreq,
    1000             :                 struct tevent_req);
    1001           0 :         struct fetch_dos_mode_state *state =
    1002       20138 :                 tevent_req_data(req,
    1003             :                 struct fetch_dos_mode_state);
    1004           0 :         uint32_t dfs_dosmode;
    1005           0 :         uint32_t dosmode;
    1006       20138 :         struct timespec btime_ts = {0};
    1007           0 :         off_t dosmode_off;
    1008           0 :         off_t btime_off;
    1009           0 :         NTSTATUS status;
    1010             : 
    1011       20138 :         status = dos_mode_at_recv(subreq, &dosmode);
    1012       20138 :         TALLOC_FREE(subreq);
    1013       20138 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
    1014           0 :                 tevent_req_done(req);
    1015           0 :                 return;
    1016             :         }
    1017       20138 :         if (tevent_req_nterror(req, status)) {
    1018           0 :                 return;
    1019             :         }
    1020             : 
    1021       20138 :         switch (state->info_level) {
    1022       20138 :         case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
    1023             :         case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
    1024             :         case SMB_FIND_FILE_DIRECTORY_INFO:
    1025             :         case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
    1026             :         case SMB_FIND_ID_FULL_DIRECTORY_INFO:
    1027       20138 :                 btime_off = 8;
    1028       20138 :                 dosmode_off = 56;
    1029       20138 :                 break;
    1030             : 
    1031           0 :         default:
    1032           0 :                 DBG_ERR("Unsupported info_level [%u]\n", state->info_level);
    1033           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
    1034           0 :                 return;
    1035             :         }
    1036             : 
    1037             : 
    1038       20138 :         dfs_dosmode = IVAL(state->entry_marshall_buf, dosmode_off);
    1039       20138 :         if (dfs_dosmode == 0) {
    1040             :                 /*
    1041             :                  * DOS mode for a DFS link, only overwrite if still set to 0 and
    1042             :                  * not already populated by the lower layer for a DFS link in
    1043             :                  * smbd_dirptr_lanman2_mode_fn().
    1044             :                  */
    1045       20138 :                 SIVAL(state->entry_marshall_buf, dosmode_off, dosmode);
    1046             :         }
    1047             : 
    1048       20138 :         btime_ts = get_create_timespec(state->dir_fsp->conn,
    1049             :                                        NULL,
    1050       20138 :                                        state->smb_fname);
    1051       20138 :         if (lp_dos_filetime_resolution(SNUM(state->dir_fsp->conn))) {
    1052           0 :                 dos_filetime_timespec(&btime_ts);
    1053             :         }
    1054             : 
    1055       20138 :         put_long_date_full_timespec(state->dir_fsp->conn->ts_res,
    1056       20138 :                                (char *)state->entry_marshall_buf + btime_off,
    1057             :                                &btime_ts);
    1058             : 
    1059       20138 :         tevent_req_done(req);
    1060       20138 :         return;
    1061             : }
    1062             : 
    1063       20138 : static NTSTATUS fetch_dos_mode_recv(struct tevent_req *req)
    1064             : {
    1065           0 :         NTSTATUS status;
    1066             : 
    1067       20138 :         if (tevent_req_is_nterror(req, &status)) {
    1068           0 :                 tevent_req_received(req);
    1069           0 :                 return status;
    1070             :         }
    1071             : 
    1072       20138 :         tevent_req_received(req);
    1073       20138 :         return NT_STATUS_OK;
    1074             : }

Generated by: LCOV version 1.14