#include "trans2.h"
#include "../lib/util/tevent_ntstatus.h"
#include "system/filesys.h"
+#include "lib/pthreadpool/pthreadpool_tevent.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SMB2
bool *stop);
static NTSTATUS fetch_write_time_recv(struct tevent_req *req);
+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);
+
+static NTSTATUS fetch_dos_mode_recv(struct tevent_req *req);
struct smbd_smb2_query_directory_state {
struct tevent_context *ev;
struct smbd_smb2_request *smb2req;
- uint64_t async_count;
+ uint64_t async_sharemode_count;
uint32_t find_async_delay_usec;
DATA_BLOB out_output_buffer;
+ struct smb_request *smbreq;
+ int in_output_buffer_length;
+ struct files_struct *fsp;
+ const char *in_file_name;
+ NTSTATUS empty_status;
+ uint32_t info_level;
+ uint32_t max_count;
+ char *pdata;
+ char *base_data;
+ char *end_data;
+ uint32_t num;
+ uint32_t dirtype;
+ bool dont_descend;
+ bool ask_sharemode;
+ bool async_dosmode;
+ bool async_ask_sharemode;
+ int last_entry_off;
+ size_t max_async_dosmode_active;
+ uint32_t async_dosmode_active;
+ bool done;
};
+static bool smb2_query_directory_next_entry(struct tevent_req *req);
static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq);
+static void smb2_query_directory_dos_mode_done(struct tevent_req *subreq);
static void smb2_query_directory_waited(struct tevent_req *subreq);
static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
struct smbXsrv_connection *xconn = smb2req->xconn;
struct tevent_req *req;
struct smbd_smb2_query_directory_state *state;
- struct smb_request *smbreq;
connection_struct *conn = smb2req->tcon->compat;
NTSTATUS status;
- NTSTATUS empty_status;
- uint32_t info_level;
- uint32_t max_count;
- char *pdata;
- char *base_data;
- char *end_data;
- int last_entry_off = 0;
- int off = 0;
- uint32_t num = 0;
- uint32_t dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY;
- bool dont_descend = false;
- bool ask_sharemode = false;
- bool async_ask_sharemode = false;
bool wcard_has_wild = false;
struct tm tm;
char *p;
+ bool stop = false;
+ bool ok;
req = tevent_req_create(mem_ctx, &state,
struct smbd_smb2_query_directory_state);
if (req == NULL) {
return NULL;
}
- state->ev = ev;
+ state->ev = fsp->conn->sconn->raw_ev_ctx;
+ state->fsp = fsp;
state->smb2req = smb2req;
+ state->in_output_buffer_length = in_output_buffer_length;
+ state->in_file_name = in_file_name;
state->out_output_buffer = data_blob_null;
+ state->dirtype = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY;
DEBUG(10,("smbd_smb2_query_directory_send: %s - %s\n",
fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
- smbreq = smbd_smb2_fake_smb_request(smb2req);
- if (tevent_req_nomem(smbreq, req)) {
+ state->smbreq = smbd_smb2_fake_smb_request(smb2req);
+ if (tevent_req_nomem(state->smbreq, req)) {
return tevent_req_post(req, ev);
}
return tevent_req_post(req, ev);
}
- if (strcmp(in_file_name, "") == 0) {
+ if (strcmp(state->in_file_name, "") == 0) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
return tevent_req_post(req, ev);
}
- if (strchr_m(in_file_name, '\\') != NULL) {
+ if (strchr_m(state->in_file_name, '\\') != NULL) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
return tevent_req_post(req, ev);
}
- if (strchr_m(in_file_name, '/') != NULL) {
+ if (strchr_m(state->in_file_name, '/') != NULL) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
return tevent_req_post(req, ev);
}
- p = strptime(in_file_name, GMT_FORMAT, &tm);
+ p = strptime(state->in_file_name, GMT_FORMAT, &tm);
if ((p != NULL) && (*p =='\0')) {
/*
* Bogus find that asks for a shadow copy timestamp as a
switch (in_file_info_class) {
case SMB2_FIND_DIRECTORY_INFO:
- info_level = SMB_FIND_FILE_DIRECTORY_INFO;
+ state->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
break;
case SMB2_FIND_FULL_DIRECTORY_INFO:
- info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
+ state->info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
break;
case SMB2_FIND_BOTH_DIRECTORY_INFO:
- info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
+ state->info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
break;
case SMB2_FIND_NAME_INFO:
- info_level = SMB_FIND_FILE_NAMES_INFO;
+ state->info_level = SMB_FIND_FILE_NAMES_INFO;
break;
case SMB2_FIND_ID_BOTH_DIRECTORY_INFO:
- info_level = SMB_FIND_ID_BOTH_DIRECTORY_INFO;
+ state->info_level = SMB_FIND_ID_BOTH_DIRECTORY_INFO;
break;
case SMB2_FIND_ID_FULL_DIRECTORY_INFO:
- info_level = SMB_FIND_ID_FULL_DIRECTORY_INFO;
+ state->info_level = SMB_FIND_ID_FULL_DIRECTORY_INFO;
break;
default:
}
}
- if (!smbreq->posix_pathnames) {
- wcard_has_wild = ms_has_wild(in_file_name);
+ if (!state->smbreq->posix_pathnames) {
+ wcard_has_wild = ms_has_wild(state->in_file_name);
}
/* Ensure we've canonicalized any search path if not a wildcard. */
char *to_free = NULL;
uint32_t ucf_flags = UCF_SAVE_LCOMP |
UCF_ALWAYS_ALLOW_WCARD_LCOMP |
- (smbreq->posix_pathnames ?
+ (state->smbreq->posix_pathnames ?
UCF_POSIX_PATHNAMES : 0);
if (ISDOT(fsp->fsp_name->base_name)) {
- fullpath = in_file_name;
+ fullpath = state->in_file_name;
} else {
size_t len;
char *tmp;
len = full_path_tos(
- fsp->fsp_name->base_name, in_file_name,
+ fsp->fsp_name->base_name, state->in_file_name,
tmpbuf, sizeof(tmpbuf), &tmp, &to_free);
if (len == -1) {
tevent_req_oom(req);
conn,
fullpath,
ucf_flags,
+ NULL,
&wcard_has_wild,
&smb_fname);
return tevent_req_post(req, ev);
}
- in_file_name = smb_fname->original_lcomp;
+ state->in_file_name = smb_fname->original_lcomp;
}
if (fsp->dptr == NULL) {
false, /* old_handle */
false, /* expect_close */
0, /* spid */
- in_file_name, /* wcard */
+ state->in_file_name, /* wcard */
wcard_has_wild,
- dirtype,
+ state->dirtype,
&fsp->dptr);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
}
- empty_status = NT_STATUS_NO_SUCH_FILE;
+ state->empty_status = NT_STATUS_NO_SUCH_FILE;
} else {
- empty_status = STATUS_NO_MORE_FILES;
+ state->empty_status = STATUS_NO_MORE_FILES;
}
if (in_flags & SMB2_CONTINUE_FLAG_RESTART) {
}
if (in_flags & SMB2_CONTINUE_FLAG_SINGLE) {
- max_count = 1;
+ state->max_count = 1;
} else {
- max_count = UINT16_MAX;
+ state->max_count = UINT16_MAX;
}
#define DIR_ENTRY_SAFETY_MARGIN 4096
}
state->out_output_buffer.length = 0;
- pdata = (char *)state->out_output_buffer.data;
- base_data = pdata;
+ state->pdata = (char *)state->out_output_buffer.data;
+ state->base_data = state->pdata;
/*
* end_data must include the safety margin as it's what is
* used to determine if pushed strings have been truncated.
*/
- end_data = pdata + in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN - 1;
- last_entry_off = 0;
- off = 0;
- num = 0;
+ state->end_data = state->pdata + in_output_buffer_length + DIR_ENTRY_SAFETY_MARGIN - 1;
DEBUG(8,("smbd_smb2_query_directory_send: dirpath=<%s> dontdescend=<%s>, "
"in_output_buffer_length = %u\n",
(unsigned int)in_output_buffer_length ));
if (in_list(fsp->fsp_name->base_name,lp_dont_descend(talloc_tos(), SNUM(conn)),
conn->case_sensitive)) {
- dont_descend = true;
+ state->dont_descend = true;
}
/*
* This may change when we try to improve the delete on close
* handling in future.
*/
- if (info_level != SMB_FIND_FILE_NAMES_INFO) {
- ask_sharemode = lp_parm_bool(SNUM(conn),
- "smbd", "search ask sharemode",
- true);
+ if (state->info_level != SMB_FIND_FILE_NAMES_INFO) {
+ state->ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
+
+ state->async_dosmode = lp_smbd_async_dosmode(SNUM(conn));
+ }
+
+ if (state->ask_sharemode && lp_clustering()) {
+ state->ask_sharemode = false;
+ state->async_ask_sharemode = true;
}
- if (ask_sharemode && lp_clustering()) {
- ask_sharemode = false;
- async_ask_sharemode = true;
+ if (state->async_dosmode) {
+ size_t max_threads;
+
+ max_threads = pthreadpool_tevent_max_threads(conn->sconn->raw_thread_pool);
+
+ state->max_async_dosmode_active = lp_smbd_max_async_dosmode(
+ SNUM(conn));
+ if (state->max_async_dosmode_active == 0) {
+ state->max_async_dosmode_active = max_threads * 2;
+ }
+ }
+ if (state->async_dosmode || state->async_ask_sharemode) {
/*
* Should we only set async_internal
* if we're not the last request in
"find async delay usec",
0);
- while (true) {
- bool got_exact_match = false;
- int space_remaining = in_output_buffer_length - off;
- struct file_id file_id;
- bool stop = false;
-
- SMB_ASSERT(space_remaining >= 0);
-
- status = smbd_dirptr_lanman2_entry(state,
- conn,
- fsp->dptr,
- smbreq->flags2,
- in_file_name,
- dirtype,
- info_level,
- false, /* requires_resume_key */
- dont_descend,
- ask_sharemode,
- true,
- 8, /* align to 8 bytes */
- false, /* no padding */
- &pdata,
- base_data,
- end_data,
- space_remaining,
- &got_exact_match,
- &last_entry_off,
- NULL,
- &file_id);
-
- off = (int)PTR_DIFF(pdata, base_data);
+ while (!stop) {
+ stop = smb2_query_directory_next_entry(req);
+ }
- if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
- /*
- * Bad character conversion on name. Ignore this
- * entry.
- */
- continue;
- } else if (num > 0) {
- goto last_entry_done;
- } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
- tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
- return tevent_req_post(req, ev);
- } else {
- tevent_req_nterror(req, empty_status);
- return tevent_req_post(req, ev);
- }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ok = aio_add_req_to_fsp(fsp, req);
+ if (!ok) {
+ DBG_ERR("Could not add req to fsp\n");
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static bool smb2_query_directory_next_entry(struct tevent_req *req)
+{
+ struct smbd_smb2_query_directory_state *state = tevent_req_data(
+ req, struct smbd_smb2_query_directory_state);
+ struct smb_filename *smb_fname = NULL; /* relative to fsp !! */
+ bool got_exact_match = false;
+ int off = state->out_output_buffer.length;
+ int space_remaining = state->in_output_buffer_length - off;
+ struct file_id file_id;
+ NTSTATUS status;
+ bool get_dosmode = !state->async_dosmode;
+ bool stop = false;
+
+ SMB_ASSERT(space_remaining >= 0);
+
+ status = smbd_dirptr_lanman2_entry(state,
+ state->fsp->conn,
+ state->fsp->dptr,
+ state->smbreq->flags2,
+ state->in_file_name,
+ state->dirtype,
+ state->info_level,
+ false, /* requires_resume_key */
+ state->dont_descend,
+ state->ask_sharemode,
+ get_dosmode,
+ 8, /* align to 8 bytes */
+ false, /* no padding */
+ &state->pdata,
+ state->base_data,
+ state->end_data,
+ space_remaining,
+ &smb_fname,
+ &got_exact_match,
+ &state->last_entry_off,
+ NULL,
+ &file_id);
+
+ off = (int)PTR_DIFF(state->pdata, state->base_data);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
+ /*
+ * Bad character conversion on name. Ignore this
+ * entry.
+ */
+ return false;
+ } else if (state->num > 0) {
+ goto last_entry_done;
+ } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ tevent_req_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
+ return true;
+ } else {
+ tevent_req_nterror(req, state->empty_status);
+ return true;
}
+ }
- if (async_ask_sharemode) {
- struct tevent_req *subreq = NULL;
-
- subreq = fetch_write_time_send(req,
- ev,
- conn,
- file_id,
- info_level,
- base_data + last_entry_off,
- &stop);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(
- subreq,
- smb2_query_directory_fetch_write_time_done,
- req);
+ if (state->async_ask_sharemode) {
+ struct tevent_req *subreq = NULL;
+ char *buf = state->base_data + state->last_entry_off;
+
+ subreq = fetch_write_time_send(state,
+ state->ev,
+ state->fsp->conn,
+ file_id,
+ state->info_level,
+ buf,
+ &stop);
+ if (tevent_req_nomem(subreq, req)) {
+ return true;
+ }
+ tevent_req_set_callback(
+ subreq,
+ smb2_query_directory_fetch_write_time_done,
+ req);
+ state->async_sharemode_count++;
+ }
- state->async_count++;
+ if (state->async_dosmode) {
+ struct tevent_req *subreq = NULL;
+ uint8_t *buf = NULL;
+ size_t outstanding_aio;
+
+ buf = (uint8_t *)state->base_data + state->last_entry_off;
+
+ subreq = fetch_dos_mode_send(state,
+ state->ev,
+ state->fsp,
+ &smb_fname,
+ state->info_level,
+ buf);
+ if (tevent_req_nomem(subreq, req)) {
+ return true;
}
+ tevent_req_set_callback(subreq,
+ smb2_query_directory_dos_mode_done,
+ req);
+
+ state->async_dosmode_active++;
- num++;
- state->out_output_buffer.length = off;
+ outstanding_aio = pthreadpool_tevent_queued_jobs(
+ state->fsp->conn->sconn->raw_thread_pool);
- if (num >= max_count) {
+ if (outstanding_aio > state->max_async_dosmode_active) {
stop = true;
}
+ }
- if (!stop) {
- continue;
- }
+ TALLOC_FREE(smb_fname);
+
+ state->num++;
+ state->out_output_buffer.length = off;
+
+ if (!state->done && state->num < state->max_count) {
+ return stop;
+ }
last_entry_done:
- SIVAL(state->out_output_buffer.data, last_entry_off, 0);
- if (state->async_count > 0) {
- DBG_DEBUG("Stopping after %"PRIu64" async mtime "
- "updates\n", state->async_count);
- return req;
- }
+ SIVAL(state->out_output_buffer.data, state->last_entry_off, 0);
- if (state->find_async_delay_usec > 0) {
- struct timeval tv;
- struct tevent_req *subreq = NULL;
+ state->done = true;
- /*
- * Should we only set async_internal
- * if we're not the last request in
- * a compound chain?
- */
- smb2_request_set_async_internal(smb2req, true);
+ if (state->async_sharemode_count > 0) {
+ DBG_DEBUG("Stopping after %"PRIu64" async mtime "
+ "updates\n", state->async_sharemode_count);
+ return true;
+ }
- tv = timeval_current_ofs(0, state->find_async_delay_usec);
+ if (state->async_dosmode_active > 0) {
+ return true;
+ }
- subreq = tevent_wakeup_send(state, ev, tv);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq,
- smb2_query_directory_waited,
- req);
- return req;
- }
+ if (state->find_async_delay_usec > 0) {
+ struct timeval tv;
+ struct tevent_req *subreq = NULL;
- tevent_req_done(req);
- return tevent_req_post(req, ev);
+ /*
+ * Should we only set async_internal
+ * if we're not the last request in
+ * a compound chain?
+ */
+ smb2_request_set_async_internal(state->smb2req, true);
+
+ tv = timeval_current_ofs(0, state->find_async_delay_usec);
+
+ subreq = tevent_wakeup_send(state, state->ev, tv);
+ if (tevent_req_nomem(subreq, req)) {
+ return true;
+ }
+ tevent_req_set_callback(subreq,
+ smb2_query_directory_waited,
+ req);
+ return true;
}
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return tevent_req_post(req, ev);
+ tevent_req_done(req);
+ return true;
}
+static void smb2_query_directory_check_next_entry(struct tevent_req *req);
+
static void smb2_query_directory_fetch_write_time_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
req, struct smbd_smb2_query_directory_state);
NTSTATUS status;
- state->async_count--;
+ state->async_sharemode_count--;
status = fetch_write_time_recv(subreq);
TALLOC_FREE(subreq);
return;
}
- if (state->async_count > 0) {
+ smb2_query_directory_check_next_entry(req);
+ return;
+}
+
+static void smb2_query_directory_dos_mode_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbd_smb2_query_directory_state *state =
+ tevent_req_data(req,
+ struct smbd_smb2_query_directory_state);
+ NTSTATUS status;
+
+ status = fetch_dos_mode_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->async_dosmode_active--;
+
+ smb2_query_directory_check_next_entry(req);
+ return;
+}
+
+static void smb2_query_directory_check_next_entry(struct tevent_req *req)
+{
+ struct smbd_smb2_query_directory_state *state = tevent_req_data(
+ req, struct smbd_smb2_query_directory_state);
+ bool stop = false;
+
+ if (!state->done) {
+ while (!stop) {
+ stop = smb2_query_directory_next_entry(req);
+ }
+ return;
+ }
+
+ if (state->async_sharemode_count > 0 ||
+ state->async_dosmode_active > 0)
+ {
return;
}
if (state->find_async_delay_usec > 0) {
struct timeval tv;
+ struct tevent_req *subreq = NULL;
tv = timeval_current_ofs(0, state->find_async_delay_usec);
tevent_req_received(req);
return NT_STATUS_OK;
}
+
+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;
+}