+
+struct fetch_dos_mode_state {
+ struct files_struct *dir_fsp;
+ struct smb_filename *smb_fname;
+ uint32_t info_level;
+ uint8_t *entry_marshall_buf;
+};
+
+static void fetch_dos_mode_done(struct tevent_req *subreq);
+
+static struct tevent_req *fetch_dos_mode_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *dir_fsp,
+ struct smb_filename **smb_fname,
+ uint32_t info_level,
+ uint8_t *entry_marshall_buf)
+{
+ struct tevent_req *req = NULL;
+ struct fetch_dos_mode_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct fetch_dos_mode_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ *state = (struct fetch_dos_mode_state) {
+ .dir_fsp = dir_fsp,
+ .info_level = info_level,
+ .entry_marshall_buf = entry_marshall_buf,
+ };
+
+ state->smb_fname = talloc_move(state, smb_fname);
+
+ subreq = dos_mode_at_send(state, ev, dir_fsp, state->smb_fname);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, fetch_dos_mode_done, req);
+
+ return req;
+}
+
+static void fetch_dos_mode_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct fetch_dos_mode_state *state =
+ tevent_req_data(req,
+ struct fetch_dos_mode_state);
+ uint32_t dfs_dosmode;
+ uint32_t dosmode;
+ struct timespec btime_ts = {0};
+ off_t dosmode_off;
+ off_t btime_off;
+ NTSTATUS status;
+
+ status = dos_mode_at_recv(subreq, &dosmode);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ tevent_req_done(req);
+ return;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ switch (state->info_level) {
+ case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+ case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+ btime_off = 8;
+ dosmode_off = 56;
+ break;
+
+ default:
+ DBG_ERR("Unsupported info_level [%u]\n", state->info_level);
+ tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
+ return;
+ }
+
+
+ dfs_dosmode = IVAL(state->entry_marshall_buf, dosmode_off);
+ if (dfs_dosmode == 0) {
+ /*
+ * DOS mode for a DFS link, only overwrite if still set to 0 and
+ * not already populated by the lower layer for a DFS link in
+ * smbd_dirptr_lanman2_mode_fn().
+ */
+ SIVAL(state->entry_marshall_buf, dosmode_off, dosmode);
+ }
+
+ btime_ts = get_create_timespec(state->dir_fsp->conn,
+ NULL,
+ state->smb_fname);
+ if (lp_dos_filetime_resolution(SNUM(state->dir_fsp->conn))) {
+ dos_filetime_timespec(&btime_ts);
+ }
+
+ put_long_date_timespec(state->dir_fsp->conn->ts_res,
+ (char *)state->entry_marshall_buf + btime_off,
+ btime_ts);
+
+ tevent_req_done(req);
+ return;
+}
+
+static NTSTATUS fetch_dos_mode_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}