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

Generated by: LCOV version 1.13