+++ /dev/null
-^samba3.base.delaywrite.finfo update on close\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time\(fileserver_smb1\)
-^samba3.base.delaywrite.update of write time and SMBwrite truncate\(fileserver_smb1\)
-^samba3.base.delaywrite.update of write time and SMBwrite truncate expand\(fileserver_smb1\)
-^samba3.base.delaywrite.update of write time using SET_END_OF_FILE\(fileserver_smb1\)
-^samba3.base.delaywrite.update of write time using SET_ALLOCATION_SIZE\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time using 2 connections\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 3\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 3a\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 3b\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 3c\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 4\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 5\(fileserver_smb1\)
-^samba3.base.delaywrite.delayed update of write time 6\(fileserver_smb1\)
-^samba3.smb2.timestamps.delayed-write-vs-seteof\(.*\)
-^samba3.smb2.timestamps.delayed-write-vs-flush\(.*\)
-^samba3.smb2.timestamps.delayed-write-vs-setbasic\(.*\)
-^samba3.smb2.timestamps.delayed-2write\(.*\)
-^samba3.base.delaywrite.modern_write_time_update-1\(fileserver_smb1\)
-^samba3.smb2.timestamps.modern_write_time_update-1\(.*\)
-^samba3.smb2.timestamps.modern_write_time_update-2\(.*\)
bool is_fsa : 1; /* See below */
bool have_proc_fds : 1;
bool kernel_share_modes_taken : 1;
- bool update_write_time_triggered : 1;
- bool update_write_time_on_close : 1;
bool write_time_forced : 1;
bool can_lock : 1;
bool can_read : 1;
bool posix_append : 1;
} fsp_flags;
- struct tevent_timer *update_write_time_event;
+ /* Only used for SMB1 close with explicit time */
struct timespec close_write_time;
int oplock_type;
[string,charset(UTF8)] char *stream_name;
uint32 num_delete_tokens;
[size_is(num_delete_tokens)] delete_token delete_tokens[];
- NTTIME old_write_time;
- NTTIME changed_write_time;
[skip] boolean8 not_stored;
[skip] boolean8 modified;
[ignore] file_id id; /* In memory key used to lookup cache. */
[string,charset(UTF8)] char *base_name;
hyper initial_allocation_size;
hyper position_information;
- boolean8 update_write_time_triggered;
- boolean8 update_write_time_on_close;
boolean8 write_time_forced;
- NTTIME close_write_time;
vfs_default_durable_stat stat_info;
} vfs_default_durable_cookie;
void get_file_infos(struct file_id id,
uint32_t name_hash,
- bool *delete_on_close,
- struct timespec *write_time)
+ bool *delete_on_close)
{
struct share_mode_lock *lck;
*delete_on_close = false;
}
- if (write_time) {
- *write_time = make_omit_timespec();
- }
-
if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id))) {
return;
}
*delete_on_close = is_delete_on_close_set(lck, name_hash);
}
- if (write_time) {
- *write_time = get_share_mode_write_time(lck);
- }
-
TALLOC_FREE(lck);
}
return find_delete_on_close_token(d, name_hash) != NULL;
}
-struct set_sticky_write_time_state {
- struct file_id fileid;
- struct timespec write_time;
- bool ok;
-};
-
-static void set_sticky_write_time_fn(struct share_mode_lock *lck,
- void *private_data)
-{
- struct set_sticky_write_time_state *state = private_data;
- struct share_mode_data *d = NULL;
- struct file_id_buf ftmp;
- struct timeval_buf tbuf;
- NTSTATUS status;
-
- status = share_mode_lock_access_private_data(lck, &d);
- if (!NT_STATUS_IS_OK(status)) {
- /* Any error recovery possible here ? */
- DBG_ERR("share_mode_lock_access_private_data() failed for "
- "%s id=%s - %s\n",
- timespec_string_buf(&state->write_time, true, &tbuf),
- file_id_str_buf(state->fileid, &ftmp),
- nt_errstr(status));
- return;
- }
-
- share_mode_set_changed_write_time(lck, state->write_time);
-
- state->ok = true;
-}
-
-bool set_sticky_write_time(struct file_id fileid, struct timespec write_time)
-{
- struct set_sticky_write_time_state state = {
- .fileid = fileid,
- .write_time = write_time,
- };
- struct file_id_buf ftmp;
- struct timeval_buf tbuf;
- NTSTATUS status;
-
- status = share_mode_do_locked_vfs_denied(fileid,
- set_sticky_write_time_fn,
- &state);
- if (!NT_STATUS_IS_OK(status)) {
- /* Any error recovery possible here ? */
- DBG_ERR("share_mode_do_locked_vfs_denied() failed for "
- "%s id=%s - %s\n",
- timespec_string_buf(&write_time, true, &tbuf),
- file_id_str_buf(fileid, &ftmp),
- nt_errstr(status));
- return false;
- }
-
- return state.ok;
-}
-
-struct set_write_time_state {
- struct file_id fileid;
- struct timespec write_time;
- bool ok;
-};
-
-static void set_write_time_fn(struct share_mode_lock *lck,
- void *private_data)
-{
- struct set_write_time_state *state = private_data;
- struct share_mode_data *d = NULL;
- struct file_id_buf idbuf;
- struct timeval_buf tbuf;
- NTSTATUS status;
-
- status = share_mode_lock_access_private_data(lck, &d);
- if (!NT_STATUS_IS_OK(status)) {
- /* Any error recovery possible here ? */
- DBG_ERR("share_mode_lock_access_private_data() failed for "
- "%s id=%s - %s\n",
- timespec_string_buf(&state->write_time, true, &tbuf),
- file_id_str_buf(state->fileid, &idbuf),
- nt_errstr(status));
- return;
- }
-
- share_mode_set_old_write_time(lck, state->write_time);
-
- state->ok = true;
-}
-
-bool set_write_time(struct file_id fileid, struct timespec write_time)
-{
- struct set_write_time_state state = {
- .fileid = fileid,
- .write_time = write_time,
- };
- struct file_id_buf idbuf;
- struct timeval_buf tbuf;
- NTSTATUS status;
-
- status = share_mode_do_locked_vfs_denied(fileid,
- set_write_time_fn,
- &state);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("share_mode_do_locked_vfs_denied() failed for "
- "%s id=%s - %s\n",
- timespec_string_buf(&write_time, true, &tbuf),
- file_id_str_buf(fileid, &idbuf),
- nt_errstr(status));
- return false;
- }
-
- return state.ok;
-}
-
-struct timespec get_share_mode_write_time(struct share_mode_lock *lck)
-{
- struct share_mode_data *d = NULL;
- NTSTATUS status;
-
- status = share_mode_lock_access_private_data(lck, &d);
- if (!NT_STATUS_IS_OK(status)) {
- struct file_id id = share_mode_lock_file_id(lck);
- struct file_id_buf id_buf;
- struct timespec ts_zero = {};
- /* Any error recovery possible here ? */
- DBG_ERR("share_mode_lock_access_private_data() failed for "
- "%s - %s\n",
- file_id_str_buf(id, &id_buf),
- nt_errstr(status));
- smb_panic(__location__);
- return ts_zero;
- }
-
- if (!null_nttime(d->changed_write_time)) {
- return nt_time_to_full_timespec(d->changed_write_time);
- }
- return nt_time_to_full_timespec(d->old_write_time);
-}
-
struct file_has_open_streams_state {
bool found_one;
bool ok;
const struct smb_filename *smb_fname);
void get_file_infos(struct file_id id,
uint32_t name_hash,
- bool *delete_on_close,
- struct timespec *write_time);
+ bool *delete_on_close);
bool is_valid_share_mode_entry(const struct share_mode_entry *e);
bool share_entry_stale_pid(struct share_mode_entry *e);
NTSTATUS remove_lease_if_stale(struct share_mode_lock *lck,
const struct security_token *nt_tok,
const struct security_unix_token *tok);
bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash);
-bool set_sticky_write_time(struct file_id fileid, struct timespec write_time);
-bool set_write_time(struct file_id fileid, struct timespec write_time);
-struct timespec get_share_mode_write_time(struct share_mode_lock *lck);
bool file_has_open_streams(files_struct *fsp);
bool share_mode_forall_leases(
struct share_mode_lock *lck,
static struct share_mode_data *fresh_share_mode_lock(
TALLOC_CTX *mem_ctx, const char *servicepath,
- const struct smb_filename *smb_fname,
- const struct timespec *old_write_time)
+ const struct smb_filename *smb_fname)
{
struct share_mode_data *d;
- if ((servicepath == NULL) || (smb_fname == NULL) ||
- (old_write_time == NULL)) {
+ if ((servicepath == NULL) || (smb_fname == NULL)) {
return NULL;
}
if (d->servicepath == NULL) {
goto fail;
}
- d->old_write_time = full_timespec_to_nt_time(old_write_time);
d->flags = SHARE_MODE_SHARE_DELETE |
SHARE_MODE_SHARE_WRITE |
SHARE_MODE_SHARE_READ;
struct file_id id;
const char *servicepath;
const struct smb_filename *smb_fname;
- const struct timespec *old_write_time;
NTSTATUS status;
};
d = fresh_share_mode_lock(
state->mem_ctx,
state->servicepath,
- state->smb_fname,
- state->old_write_time);
+ state->smb_fname);
if (d == NULL) {
state->status = NT_STATUS_NO_MEMORY;
return;
static NTSTATUS get_static_share_mode_data(
struct file_id id,
const char *servicepath,
- const struct smb_filename *smb_fname,
- const struct timespec *old_write_time)
+ const struct smb_filename *smb_fname)
{
struct get_static_share_mode_data_state state = {
.mem_ctx = lock_ctx,
.id = id,
.servicepath = servicepath,
.smb_fname = smb_fname,
- .old_write_time = old_write_time,
};
NTSTATUS status;
struct file_id id,
const char *servicepath,
const struct smb_filename *smb_fname,
- const struct timespec *old_write_time,
struct share_mode_lock *lck)
{
NTSTATUS status;
status = get_static_share_mode_data(
id,
servicepath,
- smb_fname,
- old_write_time);
+ smb_fname);
if (!NT_STATUS_IS_OK(status)) {
DBG_DEBUG("get_static_share_mode_data failed: %s\n",
nt_errstr(status));
status = get_share_mode_lock_internal(id,
NULL, /* servicepath */
NULL, /* smb_fname */
- NULL, /* old_write_time */
lck);
if (!NT_STATUS_IS_OK(status)) {
DBG_GET_SHARE_MODE_LOCK(status,
return d;
}
-NTTIME share_mode_changed_write_time(struct share_mode_lock *lck)
-{
- struct share_mode_data *d = share_mode_lock_assert_private_data(lck);
- return d->changed_write_time;
-}
-
-void share_mode_set_changed_write_time(struct share_mode_lock *lck, struct timespec write_time)
-{
- struct file_id fileid = share_mode_lock_file_id(lck);
- struct share_mode_data *d = share_mode_lock_assert_private_data(lck);
- struct file_id_buf ftmp;
- struct timeval_buf tbuf;
- NTTIME nt = full_timespec_to_nt_time(&write_time);
-
- DBG_INFO("%s id=%s\n",
- timespec_string_buf(&write_time, true, &tbuf),
- file_id_str_buf(fileid, &ftmp));
-
- if (d->changed_write_time != nt) {
- d->modified = true;
- d->changed_write_time = nt;
- }
-}
-
-void share_mode_set_old_write_time(struct share_mode_lock *lck, struct timespec write_time)
-{
- struct file_id fileid = share_mode_lock_file_id(lck);
- struct share_mode_data *d = share_mode_lock_assert_private_data(lck);
- struct file_id_buf ftmp;
- struct timeval_buf tbuf;
- NTTIME nt = full_timespec_to_nt_time(&write_time);
-
- DBG_INFO("%s id=%s\n",
- timespec_string_buf(&write_time, true, &tbuf),
- file_id_str_buf(fileid, &ftmp));
-
- if (d->changed_write_time != nt) {
- d->modified = true;
- d->old_write_time = nt;
- }
-}
-
const char *share_mode_servicepath(struct share_mode_lock *lck)
{
struct share_mode_data *d = share_mode_lock_assert_private_data(lck);
state->status = get_share_mode_lock_internal(state->id,
NULL, /* servicepath */
NULL, /* smb_fname */
- NULL, /* old_write_time */
&lck);
if (!NT_STATUS_IS_OK(state->status)) {
DBG_GET_SHARE_MODE_LOCK(state->status,
status = get_share_mode_lock_internal(id,
NULL, /* servicepath */
NULL, /* smb_fname */
- NULL, /* old_write_time */
&lck);
if (!NT_STATUS_IS_OK(status)) {
DBG_GET_SHARE_MODE_LOCK(status,
struct file_id id;
const char *servicepath;
const struct smb_filename *smb_fname;
- const struct timespec *old_write_time;
share_mode_entry_prepare_lock_fn_t fn;
void *private_data;
const char *location;
state->status = get_share_mode_lock_internal(state->id,
state->servicepath,
state->smb_fname,
- state->old_write_time,
state->lck);
if (!NT_STATUS_IS_OK(state->status)) {
/* no DBG_GET_SHARE_MODE_LOCK here! */
struct file_id id,
const char *servicepath,
const struct smb_filename *smb_fname,
- const struct timespec *old_write_time,
share_mode_entry_prepare_lock_fn_t fn,
void *private_data,
const char *location)
.id = id,
.servicepath = servicepath,
.smb_fname = smb_fname,
- .old_write_time = old_write_time,
.fn = fn,
.private_data = private_data,
.location = location,
state->status = get_share_mode_lock_internal(state->id,
NULL, /* servicepath */
NULL, /* smb_fname */
- NULL, /* old_write_time */
state->lck);
if (!NT_STATUS_IS_OK(state->status)) {
/* no DBG_GET_SHARE_MODE_LOCK here! */
void *private_data),
void *private_data);
-NTTIME share_mode_changed_write_time(struct share_mode_lock *lck);
-void share_mode_set_changed_write_time(struct share_mode_lock *lck, struct timespec write_time);
-void share_mode_set_old_write_time(struct share_mode_lock *lck, struct timespec write_time);
const char *share_mode_servicepath(struct share_mode_lock *lck);
char *share_mode_filename(TALLOC_CTX *mem_ctx, struct share_mode_lock *lck);
char *share_mode_data_dump(
struct file_id id,
const char *servicepath,
const struct smb_filename *smb_fname,
- const struct timespec *old_write_time,
share_mode_entry_prepare_lock_fn_t fn,
void *private_data,
const char *location);
#define share_mode_entry_prepare_lock_add(__prepare_state, __id, \
- __servicepath, __smb_fname, __old_write_time, \
+ __servicepath, __smb_fname, \
__fn, __private_data) \
_share_mode_entry_prepare_lock(__prepare_state, __id, \
- __servicepath, __smb_fname, __old_write_time, \
+ __servicepath, __smb_fname, \
__fn, __private_data, __location__);
#define share_mode_entry_prepare_lock_del(__prepare_state, __id, \
__fn, __private_data) \
_share_mode_entry_prepare_lock(__prepare_state, __id, \
- NULL, NULL, NULL, \
+ NULL, NULL, \
__fn, __private_data, __location__);
typedef void (*share_mode_entry_prepare_unlock_fn_t)(
}
}
- if (fsp->fsp_flags.write_time_forced) {
- NTTIME mtime = share_mode_changed_write_time(lck);
- struct timespec ts = nt_time_to_full_timespec(mtime);
-
- DBG_DEBUG("write time forced for %s %s\n",
- state->object_type, fsp_str_dbg(fsp));
- set_close_write_time(fsp, ts);
- } else if (fsp->fsp_flags.update_write_time_on_close) {
- /* Someone had a pending write. */
- if (is_omit_timespec(&fsp->close_write_time)) {
- DBG_DEBUG("update to current time for %s %s\n",
- state->object_type, fsp_str_dbg(fsp));
- /* Update to current time due to "normal" write. */
- set_close_write_time(fsp, timespec_current());
- } else {
- DBG_DEBUG("write time pending for %s %s\n",
- state->object_type, fsp_str_dbg(fsp));
- /* Update to time set on close call. */
- set_close_write_time(fsp, fsp->close_write_time);
- }
- }
-
if (fsp->fsp_flags.initial_delete_on_close &&
!is_delete_on_close_set(lck, fsp->name_hash)) {
/* Initial delete on close was set and no one else
struct smb_filename *base_fname = NULL;
int ret;
- /* Ensure any pending write time updates are done. */
- if (fsp->update_write_time_event) {
- fsp_flush_write_time_update(fsp);
- }
-
/*
* Lock the share entries, and determine if we should delete
* on close. If so delete whilst the lock is still in effect.
DBG_INFO("%s. Delete on close was set - deleting file.\n",
fsp_str_dbg(fsp));
- /*
- * Don't try to update the write time when we delete the file
- */
- fsp->fsp_flags.update_write_time_on_close = false;
-
if (lck_state.got_tokens &&
!unix_token_equal(lck_state.del_token, get_current_utok(conn)))
{
return status;
}
+/*
+ * This is now only used for SMB1 closes that send an
+ * explicit write time.
+ */
void set_close_write_time(struct files_struct *fsp, struct timespec ts)
{
DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
return;
}
fsp->fsp_flags.write_time_forced = false;
- fsp->fsp_flags.update_write_time_on_close = true;
fsp->close_write_time = ts;
}
-static void update_write_time_on_close_share_mode_fn(struct share_mode_lock *lck,
- void *private_data)
-{
- struct files_struct *fsp =
- talloc_get_type_abort(private_data,
- struct files_struct);
- NTTIME share_mtime = share_mode_changed_write_time(lck);
-
- /*
- * On close if we're changing the real file time we
- * must update it in the open file db too.
- */
- share_mode_set_old_write_time(lck, fsp->close_write_time);
-
- /*
- * Close write times overwrite sticky write times
- * so we must replace any sticky write time here.
- */
- if (!null_nttime(share_mtime)) {
- share_mode_set_changed_write_time(lck, fsp->close_write_time);
- }
-}
-
+/*
+ * This is now only used for SMB1 closes that send an
+ * explicit write time.
+ */
static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
{
struct smb_file_time ft;
init_smb_file_time(&ft);
- if (!(fsp->fsp_flags.update_write_time_on_close)) {
- return NT_STATUS_OK;
- }
-
if (is_omit_timespec(&fsp->close_write_time)) {
- fsp->close_write_time = timespec_current();
+ return NT_STATUS_OK;
}
/* Ensure we have a valid stat struct for the source. */
return NT_STATUS_OK;
}
- /*
- * We're being called after close_remove_share_mode() inside
- * close_normal_file() so it's quite normal to not have an
- * existing share. So just ignore the result of
- * share_mode_do_locked_vfs_denied()...
- */
- share_mode_do_locked_vfs_denied(fsp->file_id,
- update_write_time_on_close_share_mode_fn,
- fsp);
-
ft.mtime = fsp->close_write_time;
- /* As this is a close based update, we are not directly changing the
- file attributes from a client call, but indirectly from a write. */
+
status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("update_write_time_on_close: smb_set_file_time "
const char *mask,
uint32_t dirtype,
bool dont_descend,
- bool ask_sharemode,
bool get_dosmode_in,
bool (*match_fn)(TALLOC_CTX *ctx,
void *private_data,
mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
get_dosmode = false;
- ask_sharemode = false;
goto done;
}
/*
* Posix always wants to see symlinks.
*/
- ask_sharemode = false;
goto done;
}
continue;
}
- if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
- struct timespec write_time_ts;
- struct file_id fileid;
-
- fileid = vfs_file_id_from_sbuf(conn,
- &smb_fname->st);
- get_file_infos(fileid, 0, NULL, &write_time_ts);
- if (!is_omit_timespec(&write_time_ts)) {
- update_stat_ex_mtime(&smb_fname->st,
- write_time_ts);
- }
- }
-
if (toplevel_dotdot) {
/*
* Ensure posix fileid and sids are hidden
const char *mask,
uint32_t dirtype,
bool dont_descend,
- bool ask_sharemode,
bool get_dosmode,
bool (*match_fn)(TALLOC_CTX *ctx,
void *private_data,
returned on all future write time queries and set on close.
******************************************************************/
-bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
+void set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
{
- bool ok;
-
if (is_omit_timespec(&mtime)) {
- return true;
+ return;
}
fsp->fsp_flags.write_time_forced = true;
- TALLOC_FREE(fsp->update_write_time_event);
-
- ok = set_sticky_write_time(fsp->file_id, mtime);
- return ok;
}
/******************************************************************
cookie.base_name = fsp->fsp_name->base_name;
cookie.initial_allocation_size = fsp->initial_allocation_size;
cookie.position_information = fh_get_position_information(fsp->fh);
- cookie.update_write_time_triggered =
- fsp->fsp_flags.update_write_time_triggered;
- cookie.update_write_time_on_close =
- fsp->fsp_flags.update_write_time_on_close;
cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
- cookie.close_write_time = full_timespec_to_nt_time(
- &fsp->close_write_time);
cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
return NT_STATUS_NOT_SUPPORTED;
}
- /* Ensure any pending write time updates are done. */
- if (fsp->update_write_time_event) {
- fsp_flush_write_time_update(fsp);
- }
-
/*
* The above checks are done in mark_share_mode_disconnected() too
* but we want to avoid getting the lock if possible
*/
lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
if (lck != NULL) {
- struct smb_file_time ft;
-
- init_smb_file_time(&ft);
-
- if (fsp->fsp_flags.write_time_forced) {
- NTTIME mtime = share_mode_changed_write_time(lck);
- ft.mtime = nt_time_to_full_timespec(mtime);
- } else if (fsp->fsp_flags.update_write_time_on_close) {
- if (is_omit_timespec(&fsp->close_write_time)) {
- ft.mtime = timespec_current();
- } else {
- ft.mtime = fsp->close_write_time;
- }
- }
-
- if (!is_omit_timespec(&ft.mtime)) {
- round_timespec(conn->ts_res, &ft.mtime);
- file_ntimes(conn, fsp, &ft);
- }
-
ok = mark_share_mode_disconnected(lck, fsp);
if (!ok) {
TALLOC_FREE(lck);
cookie.base_name = fsp_str_dbg(fsp);
cookie.initial_allocation_size = fsp->initial_allocation_size;
cookie.position_information = fh_get_position_information(fsp->fh);
- cookie.update_write_time_triggered =
- fsp->fsp_flags.update_write_time_triggered;
- cookie.update_write_time_on_close =
- fsp->fsp_flags.update_write_time_on_close;
cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
- cookie.close_write_time = full_timespec_to_nt_time(
- &fsp->close_write_time);
cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
fsp->initial_allocation_size = cookie.initial_allocation_size;
fh_set_position_information(fsp->fh, cookie.position_information);
- fsp->fsp_flags.update_write_time_triggered =
- cookie.update_write_time_triggered;
- fsp->fsp_flags.update_write_time_on_close =
- cookie.update_write_time_on_close;
fsp->fsp_flags.write_time_forced = cookie.write_time_forced;
- fsp->close_write_time = nt_time_to_full_timespec(
- cookie.close_write_time);
status = fsp_set_smb_fname(fsp, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
return ret;
}
-void fsp_flush_write_time_update(struct files_struct *fsp)
-{
- /*
- * Note this won't expect any impersonation!
- * So don't call any SMB_VFS operations here!
- */
-
- DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
-
- trigger_write_time_update_immediate(fsp);
-}
-
-static void update_write_time_handler(struct tevent_context *ctx,
- struct tevent_timer *te,
- struct timeval now,
- void *private_data)
-{
- files_struct *fsp = (files_struct *)private_data;
- fsp_flush_write_time_update(fsp);
-}
-
/*********************************************************
- Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
- in the future.
+ Immediately update write time
*********************************************************/
-void trigger_write_time_update(struct files_struct *fsp)
-{
- int delay;
-
- if (fsp->fsp_flags.posix_open) {
- /* Don't use delayed writes on POSIX files. */
- return;
- }
-
- if (fsp->fsp_flags.write_time_forced) {
- /* No point - "sticky" write times
- * in effect.
- */
- return;
- }
-
- /* We need to remember someone did a write
- * and update to current time on close. */
-
- fsp->fsp_flags.update_write_time_on_close = true;
-
- if (fsp->fsp_flags.update_write_time_triggered) {
- /*
- * We only update the write time after 2 seconds
- * on the first normal write. After that
- * no other writes affect this until close.
- */
- return;
- }
- fsp->fsp_flags.update_write_time_triggered = true;
-
- delay = lp_parm_int(SNUM(fsp->conn),
- "smbd", "writetimeupdatedelay",
- WRITE_TIME_UPDATE_USEC_DELAY);
-
- DEBUG(5, ("Update write time %d usec later on %s\n",
- delay, fsp_str_dbg(fsp)));
-
- /* trigger the update 2 seconds later */
- fsp->update_write_time_event =
- tevent_add_timer(fsp->conn->sconn->ev_ctx, NULL,
- timeval_current_ofs_usec(delay),
- update_write_time_handler, fsp);
-}
-
-void trigger_write_time_update_immediate(struct files_struct *fsp)
+void trigger_write_time_update_immediate(struct files_struct *fsp,
+ bool update_mtime,
+ bool update_ctime)
{
struct smb_file_time ft;
init_smb_file_time(&ft);
if (fsp->fsp_flags.posix_open) {
- /* Don't use delayed writes on POSIX files. */
return;
}
return;
}
- TALLOC_FREE(fsp->update_write_time_event);
DEBUG(5, ("Update write time immediate on %s\n",
fsp_str_dbg(fsp)));
- /* After an immediate update, reset the trigger. */
- fsp->fsp_flags.update_write_time_triggered = true;
- fsp->fsp_flags.update_write_time_on_close = false;
-
- ft.mtime = timespec_current();
-
- /* Update the time in the open file db. */
- (void)set_write_time(fsp->file_id, ft.mtime);
+ if (update_mtime) {
+ /*
+ * Changing mtime would also update ctime and so implicitly
+ * handle the update_ctime=true case.
+ */
+ ft.mtime = timespec_current();
+ } else if (update_ctime && !update_mtime) {
+ /*
+ * The only way to update ctime is by changing *something* in
+ * the inode, atime being the only file metadata I could come up
+ * with we can fiddle with to achieve this.
+ */
+ ft.atime.tv_nsec = UTIME_NOW;
+ }
/* Now set on disk - takes care of notify. */
(void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
}
-void mark_file_modified(files_struct *fsp)
+/*
+ * If this is a sticky-write time handle, refresh the current mtime
+ * so we can restore it after a modification.
+ */
+void prepare_file_modified(files_struct *fsp,
+ struct file_modified_state *state)
+{
+ int ret;
+
+ if (!fsp->fsp_flags.write_time_forced) {
+ return;
+ }
+
+ ZERO_STRUCTP(state);
+
+ ret = SMB_VFS_FSTAT(fsp, &state->st);
+ if (ret != 0) {
+ DBG_ERR("Prepare [%s] failed: %s\n",
+ fsp_str_dbg(fsp), strerror(errno));
+ return;
+ }
+
+ state->valid = true;
+ return;
+}
+
+void mark_file_modified(files_struct *fsp,
+ bool modified,
+ struct file_modified_state *modified_state)
{
int dosmode;
+ NTSTATUS status;
+
+ if (fsp->fsp_flags.write_time_forced &&
+ modified_state->valid)
+ {
+ struct smb_file_time ft;
+
+ init_smb_file_time(&ft);
+ ft.mtime = modified_state->st.st_ex_mtime;
- trigger_write_time_update(fsp);
+ /*
+ * Pave over the "cached" stat info mtime in the fsp,
+ * vfs_default checks this and if the existing time matches what
+ * we're trying to set, it skips setting the time. file_ntimes()
+ * will fill the value with what we've set.
+ */
+ fsp->fsp_name->st.st_ex_mtime = (struct timespec){};
+
+ status = smb_set_file_time(fsp->conn,
+ fsp,
+ fsp->fsp_name,
+ &ft,
+ false);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("smb_set_file_time [%s] failed: %s\n",
+ fsp_str_dbg(fsp), nt_errstr(status));
+ }
+ }
if (fsp->fsp_flags.modified) {
return;
}
- fsp->fsp_flags.modified = true;
+ /*
+ * The modified fsp_flag triggers a directory lease breaks when closing
+ * the handle and this must only happen after writing to a
+ * file. Modifying a file by other means that affect the file state
+ * causing directory lease breaks is handled in the corresponding
+ * functions explicitly by calling notify_fname() with
+ * NOTIFY_ACTION_DIRLEASE_BREAK.
+ */
+ fsp->fsp_flags.modified = modified;
if (!(lp_store_dos_attributes(SNUM(fsp->conn)) ||
MAP_ARCHIVE(fsp->conn))) {
off_t pos,
size_t n)
{
+ struct file_modified_state state;
ssize_t total_written = 0;
if (fsp->print_file) {
return -1;
}
- mark_file_modified(fsp);
-
- /*
- * If this file is level II oplocked then we need
- * to grab the shared memory lock and inform all
- * other files with a level II lock that they need
- * to flush their read caches. We keep the lock over
- * the shared memory area whilst doing this.
- */
-
/* This should actually be improved to span the write. */
contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
+ prepare_file_modified(fsp, &state);
+
total_written = real_write_file(req, fsp, data, pos, n);
+ if (total_written != -1) {
+ mark_file_modified(fsp, true, &state);
+ }
return total_written;
}
TALLOC_FREE(fsp->notify);
}
- /* Ensure this event will never fire. */
- TALLOC_FREE(fsp->update_write_time_event);
-
if (fsp->op != NULL) {
fsp->op->compat = NULL;
}
files_struct *fsp,
struct smb_filename *smb_fname,
bool delete_pending,
- struct timespec write_time_ts,
struct ea_list *ea_list,
uint16_t flags2,
unsigned int max_data_bytes,
int info_level,
int requires_resume_key,
bool dont_descend,
- bool ask_sharemode,
bool get_dosmode,
uint8_t align,
bool do_pad,
The buffer we keep around whilst an aio request is in process.
*****************************************************************************/
+struct file_modified_state {
+ bool valid;
+ struct stat_ex st;
+};
+
struct aio_extra {
files_struct *fsp;
struct smb_request *smbreq;
size_t nbyte;
off_t offset;
bool write_through;
+ struct file_modified_state modified_state;
};
#define SMBD_TMPNAME_PREFIX ".::TMPNAME:"
goto out;
}
- get_file_infos(fsp->file_id, name_hash, &delete_on_close_set, NULL);
+ get_file_infos(fsp->file_id, name_hash, &delete_on_close_set);
if (delete_on_close_set) {
status = NT_STATUS_DELETE_PENDING;
goto out;
bool first_open_attempt;
bool keep_locked;
NTSTATUS status;
- struct timespec write_time;
share_mode_entry_prepare_unlock_fn_t cleanup_fn;
};
return;
}
- state->write_time = get_share_mode_write_time(lck);
-
/*
* keep the g_lock while existing the tdb chainlock,
* we we're asked to, which mean we'll keep
uint32_t open_access_mask = access_mask;
NTSTATUS status;
SMB_STRUCT_STAT saved_stat = smb_fname->st;
- struct timespec old_write_time;
bool setup_poll = false;
NTSTATUS ulstatus;
return NT_STATUS_ACCESS_DENIED;
}
- old_write_time = smb_fname->st.st_ex_mtime;
-
/*
* Deal with the race condition where two smbd's detect the
* file doesn't exist and do the create at the same time. One
fsp->file_id,
conn->connectpath,
smb_fname,
- &old_write_time,
open_ntcreate_lock_add_entry,
&lck_state);
if (!NT_STATUS_IS_OK(status)) {
}
}
- /*
- * Deal with other opens having a modified write time.
- */
- if (fsp_getinfo_ask_sharemode(fsp) &&
- !is_omit_timespec(&lck_state.write_time))
- {
- update_stat_ex_mtime(&fsp->fsp_name->st, lck_state.write_time);
- }
-
status = NT_STATUS_OK;
unlock:
struct open_ntcreate_lock_state lck_state = {};
bool keep_locked = false;
NTSTATUS status;
- struct timespec mtimespec;
int info = 0;
uint32_t need_fd_access;
NTSTATUS ulstatus;
fsp->fsp_flags.posix_open = true;
}
- /* Don't store old timestamps for directory
- handles in the internal database. We don't
- update them in there if new objects
- are created in the directory. Currently
- we only update timestamps on file writes.
- See bug #9870.
- */
- mtimespec = make_omit_timespec();
-
/*
* Obviously for FILE_LIST_DIRECTORY we need to reopen to get an fd
* usable for reading a directory. SMB2_FLUSH may be called on
fsp->file_id,
conn->connectpath,
smb_dname,
- &mtimespec,
open_ntcreate_lock_add_entry,
&lck_state);
if (!NT_STATUS_IS_OK(status)) {
}
}
- /*
- * Deal with other opens having a modified write time.
- */
- if (!is_omit_timespec(&lck_state.write_time)) {
- update_stat_ex_mtime(&fsp->fsp_name->st, lck_state.write_time);
- }
-
if (pinfo) {
*pinfo = info;
}
int file_ntimes(connection_struct *conn,
files_struct *fsp,
struct smb_file_time *ft);
-bool set_sticky_write_time_fsp(struct files_struct *fsp,
+void set_sticky_write_time_fsp(struct files_struct *fsp,
struct timespec mtime);
NTSTATUS fget_ea_dos_attribute(struct files_struct *fsp,
/* The following definitions come from smbd/fileio.c */
ssize_t read_file(files_struct *fsp,char *data,off_t pos,size_t n);
-void fsp_flush_write_time_update(struct files_struct *fsp);
-void trigger_write_time_update(struct files_struct *fsp);
-void trigger_write_time_update_immediate(struct files_struct *fsp);
-void mark_file_modified(files_struct *fsp);
+void trigger_write_time_update_immediate(struct files_struct *fsp,
+ bool update_mtime,
+ bool update_ctime);
+struct file_modified_state;
+void prepare_file_modified(files_struct *fsp,
+ struct file_modified_state *state);
+void mark_file_modified(files_struct *fsp,
+ bool modified,
+ struct file_modified_state *state);
ssize_t write_file(struct smb_request *req,
files_struct *fsp,
const char *data,
aio_ex->nbyte = numtowrite;
aio_ex->offset = startpos;
+ prepare_file_modified(fsp, &aio_ex->modified_state);
req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
data, numtowrite, startpos,
return;
}
- mark_file_modified(fsp);
+ mark_file_modified(fsp, true, &aio_ex->modified_state);
if (fsp->fsp_flags.aio_write_behind) {
struct files_struct *dirfsp = NULL;
uint32_t ucf_flags = ucf_flags_from_smb_request(req);
NTTIME twrp = 0;
- bool ask_sharemode;
if (ucf_flags & UCF_GMT_PATHNAME) {
extract_snapshot_token(fname, &twrp);
mode = fdos_mode(smb_fname->fsp);
size = smb_fname->st.st_ex_size;
- ask_sharemode = fsp_search_ask_sharemode(smb_fname->fsp);
- if (ask_sharemode) {
- struct timespec write_time_ts;
- struct file_id fileid;
-
- ZERO_STRUCT(write_time_ts);
- fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
- get_file_infos(fileid, 0, NULL, &write_time_ts);
- if (!is_omit_timespec(&write_time_ts)) {
- update_stat_ex_mtime(&smb_fname->st, write_time_ts);
- }
- }
-
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
if (mode & FILE_ATTRIBUTE_DIRECTORY) {
size = 0;
off_t *_size,
uint32_t *_mode,
struct timespec *_date,
- bool check_descend,
- bool ask_sharemode)
+ bool check_descend)
{
char *fname = NULL;
struct smb_filename *smb_fname = NULL;
mask,
dirtype,
check_descend,
- ask_sharemode,
true,
smbd_dirptr_8_3_match_fn,
conn,
&size,
&mode,
&date,
- check_descend,
- false);
+ check_descend);
TALLOC_FREE(fname);
if (!ok) {
goto SearchEmpty;
unsigned int i;
size_t hdr_size = ((uint8_t *)smb_buf(req->outbuf) + 3 - req->outbuf);
size_t available_space = xconn->smb1.sessions.max_send - hdr_size;
- bool ask_sharemode;
maxentries = MIN(maxentries, available_space/DIR_STRUCT_SIZE);
check_descend = True;
}
- ask_sharemode = fsp_search_ask_sharemode(fsp);
-
for (i=numentries;(i<maxentries) && !finished;i++) {
finished = !get_dir_entry(ctx,
conn,
&size,
&mode,
&date,
- check_descend,
- ask_sharemode);
+ check_descend);
if (!finished) {
char buf[DIR_STRUCT_SIZE];
memcpy(buf,status,21);
*/
if(numtowrite == 0) {
+ struct file_modified_state state;
+
/*
* This is actually an allocate call, and set EOF. JRA.
*/
+ prepare_file_modified(fsp, &state);
nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
if (nwritten < 0) {
reply_nterror(req, NT_STATUS_DISK_FULL);
reply_nterror(req, NT_STATUS_DISK_FULL);
goto out;
}
- trigger_write_time_update_immediate(fsp);
+ mark_file_modified(fsp, true, &state);
} else {
nwritten = write_file(req,fsp,data,startpos,numtowrite);
}
}
sync_file(conn, fsp, True /* write through */);
- if (fsp->fsp_flags.modified) {
- trigger_write_time_update_immediate(fsp);
- }
-
return NULL;
}
END_PROFILE(SMBflush);
return;
}
- if (fsp->fsp_flags.modified) {
- trigger_write_time_update_immediate(fsp);
- }
}
reply_smb1_outbuf(req, 0, 0);
goto out;
}
- if (fsp->fsp_flags.modified) {
- trigger_write_time_update_immediate(fsp);
- }
-
DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
" createtime=%u\n",
fsp_fnum_dbg(fsp),
int info_level,
bool requires_resume_key,
bool dont_descend,
- bool ask_sharemode,
char **ppdata,
char *base_data,
char *end_data,
return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
path_mask, dirtype, info_level,
- requires_resume_key, dont_descend, ask_sharemode,
+ requires_resume_key, dont_descend,
true, align, do_pad,
ppdata, base_data, end_data,
space_remaining,
int space_remaining;
struct ea_list *ea_list = NULL;
NTSTATUS ntstatus = NT_STATUS_OK;
- bool ask_sharemode;
struct smbXsrv_connection *xconn = req->xconn;
struct smbd_server_connection *sconn = req->sconn;
uint32_t ucf_flags = ucf_flags_from_smb_request(req);
space_remaining = max_data_bytes;
out_of_space = False;
- ask_sharemode = fsp_search_ask_sharemode(fsp);
-
for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
ntstatus = get_lanman2_dir_entry(talloc_tos(),
info_level,
requires_resume_key,
dont_descend,
- ask_sharemode,
&p,
pdata,
data_end,
int space_remaining;
struct ea_list *ea_list = NULL;
NTSTATUS ntstatus = NT_STATUS_OK;
- bool ask_sharemode;
TALLOC_CTX *ctx = talloc_tos();
struct smbd_server_connection *sconn = req->sconn;
bool backup_priv = false;
}
} /* end if resume_name && !continue_bit */
- ask_sharemode = fsp_search_ask_sharemode(fsp);
-
for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
ntstatus = get_lanman2_dir_entry(ctx,
info_level,
requires_resume_key,
dont_descend,
- ask_sharemode,
&p,
pdata,
data_end,
struct smb_filename *smb_fname,
struct files_struct *fsp,
bool delete_pending,
- struct timespec write_time_ts,
char **pparams, int total_params,
char **ppdata, int total_data,
unsigned int max_data_bytes)
status = smbd_do_qfilepathinfo(conn, req, req, info_level,
fsp, smb_fname,
- delete_pending, write_time_ts,
+ delete_pending,
ea_list,
req->flags2, max_data_bytes,
&fixed_portion,
struct smb_filename *smb_fname = NULL;
struct smb_filename *smb_fname_rel = NULL;
bool delete_pending = False;
- struct timespec write_time_ts = { .tv_sec = 0, };
struct files_struct *dirfsp = NULL;
files_struct *fsp = NULL;
char *fname = NULL;
get_file_infos(base_fsp->file_id,
base_fsp->name_hash,
- &delete_pending,
- NULL);
+ &delete_pending);
if (delete_pending) {
reply_nterror(req, NT_STATUS_DELETE_PENDING);
return;
if (fsp_getinfo_ask_sharemode(fsp)) {
get_file_infos(fsp->file_id,
fsp->name_hash,
- &delete_pending,
- &write_time_ts);
+ &delete_pending);
}
if (delete_pending) {
smb_fname,
fsp,
false,
- write_time_ts,
pparams,
total_params,
ppdata,
uint16_t info_level;
struct smb_filename *smb_fname = NULL;
bool delete_pending = False;
- struct timespec write_time_ts = { .tv_sec = 0, };
files_struct *fsp = NULL;
struct file_id fileid;
bool info_level_handled;
fileid = vfs_file_id_from_sbuf(
conn, &smb_fname->st);
get_file_infos(fileid, fsp->name_hash,
- &delete_pending,
- &write_time_ts);
+ &delete_pending);
}
} else {
/*
fileid = vfs_file_id_from_sbuf(
conn, &smb_fname->st);
get_file_infos(fileid, fsp->name_hash,
- &delete_pending,
- &write_time_ts);
+ &delete_pending);
}
}
smb_fname,
fsp,
delete_pending,
- write_time_ts,
pparams,
total_params,
ppdata,
uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
NTSTATUS status = NT_STATUS_OK;
- files_struct *all_fsps = NULL;
bool modify_mtime = true;
- struct file_id id;
SMB_STRUCT_STAT sbuf;
if (!CAN_WRITE(conn)) {
return status;
}
- id = vfs_file_id_from_sbuf(conn, &sbuf);
- for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
- all_fsps = file_find_di_next(all_fsps, true)) {
- /*
- * We're setting the time explicitly for UNIX.
- * Cancel any pending changes over all handles.
- */
- all_fsps->fsp_flags.update_write_time_on_close = false;
- TALLOC_FREE(all_fsps->update_write_time_event);
- }
-
/*
* Override the "setting_write_time"
* parameter here as it almost does what
aio_ex->nbyte = in_data.length;
aio_ex->offset = in_offset;
+ prepare_file_modified(fsp, &aio_ex->modified_state);
req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
in_data.data, in_data.length, in_offset,
DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
(nwritten == -1) ? strerror(err) : "no error"));
- mark_file_modified(fsp);
+ mark_file_modified(fsp, true, &aio_ex->modified_state);
status = smb2_write_complete_nosync(subreq, nwritten, err);
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
- struct smbd_smb2_flush_state *state = tevent_req_data(
- req, struct smbd_smb2_flush_state);
int ret;
struct vfs_aio_state vfs_aio_state;
tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
return;
}
- if (state->fsp->fsp_flags.modified) {
- trigger_write_time_update_immediate(state->fsp);
- }
tevent_req_done(req);
}
char *data = NULL;
unsigned int data_size = 0;
bool delete_pending = false;
- struct timespec write_time_ts;
struct file_id fileid;
size_t fixed_portion;
- ZERO_STRUCT(write_time_ts);
/*
* MS-SMB2 3.3.5.20.1 "Handling SMB2_0_INFO_FILE"
fileid = vfs_file_id_from_sbuf(
conn, &fsp->fsp_name->st);
get_file_infos(fileid, fsp->name_hash,
- &delete_pending,
- &write_time_ts);
+ &delete_pending);
}
} else {
/*
fileid = vfs_file_id_from_sbuf(
conn, &fsp->fsp_name->st);
get_file_infos(fileid, fsp->name_hash,
- &delete_pending,
- &write_time_ts);
+ &delete_pending);
}
}
fsp,
fsp->fsp_name,
delete_pending,
- write_time_ts,
NULL,
STR_UNICODE,
in_output_buffer_length,
}
}
-static struct tevent_req *fetch_write_time_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- connection_struct *conn,
- struct file_id id,
- int info_level,
- char *entry_marshall_buf,
- 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 smbd_smb2_query_directory_state {
struct tevent_context *ev;
struct smbd_smb2_request *smb2req;
- uint64_t async_sharemode_count;
uint32_t find_async_delay_usec;
DATA_BLOB out_output_buffer;
struct smb_request *smbreq;
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;
};
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);
* handling in future.
*/
if (state->info_level != SMB_FIND_FILE_NAMES_INFO) {
- state->ask_sharemode = fsp_search_ask_sharemode(fsp);
-
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 (state->async_dosmode) {
size_t max_threads;
}
}
- if (state->async_dosmode || state->async_ask_sharemode) {
+ if (state->async_dosmode) {
/*
* Should we only set async_internal
* if we're not the last request in
state->info_level,
false, /* requires_resume_key */
state->dont_descend,
- state->ask_sharemode,
get_dosmode,
8, /* align to 8 bytes */
false, /* no padding */
return true;
}
- if (state->async_ask_sharemode &&
- !S_ISDIR(smb_fname->st.st_ex_mode))
- {
- struct tevent_req *subreq = NULL;
- char *buf = state->base_data + state->last_entry_off;
-
- subreq = fetch_write_time_send(state,
- state->ev,
- state->dirfsp->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++;
- }
-
if (state->async_dosmode) {
struct tevent_req *subreq = NULL;
uint8_t *buf = NULL;
state->done = true;
- if (state->async_sharemode_count > 0) {
- DBG_DEBUG("Stopping after %"PRIu64" async mtime "
- "updates\n", state->async_sharemode_count);
- return true;
- }
-
if (state->async_dosmode_active > 0) {
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(
- subreq, struct tevent_req);
- struct smbd_smb2_query_directory_state *state = tevent_req_data(
- req, struct smbd_smb2_query_directory_state);
- NTSTATUS status;
- bool ok;
-
- /*
- * Make sure we run as the user again
- */
- ok = change_to_user_and_service_by_fsp(state->dirfsp);
- SMB_ASSERT(ok);
-
- state->async_sharemode_count--;
-
- status = fetch_write_time_recv(subreq);
- TALLOC_FREE(subreq);
- if (tevent_req_nterror(req, status)) {
- return;
- }
-
- smb2_query_directory_check_next_entry(req);
- return;
-}
-
static void smb2_query_directory_dos_mode_done(struct tevent_req *subreq)
{
struct tevent_req *req =
return;
}
- if (state->async_sharemode_count > 0 ||
- state->async_dosmode_active > 0)
- {
+ if (state->async_dosmode_active > 0) {
return;
}
return NT_STATUS_OK;
}
-struct fetch_write_time_state {
- connection_struct *conn;
- struct file_id id;
- int info_level;
- char *entry_marshall_buf;
-};
-
-static void fetch_write_time_done(struct tevent_req *subreq);
-
-static struct tevent_req *fetch_write_time_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- connection_struct *conn,
- struct file_id id,
- int info_level,
- char *entry_marshall_buf,
- bool *stop)
-{
- struct tevent_req *req = NULL;
- struct fetch_write_time_state *state = NULL;
- struct tevent_req *subreq = NULL;
- bool req_queued;
-
- *stop = false;
-
- req = tevent_req_create(mem_ctx, &state, struct fetch_write_time_state);
- if (req == NULL) {
- return NULL;
- }
-
- *state = (struct fetch_write_time_state) {
- .conn = conn,
- .id = id,
- .info_level = info_level,
- .entry_marshall_buf = entry_marshall_buf,
- };
-
- subreq = fetch_share_mode_send(state, ev, id, &req_queued);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, fetch_write_time_done, req);
-
- if (req_queued) {
- *stop = true;
- }
- return req;
-}
-
-static void fetch_write_time_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct fetch_write_time_state *state = tevent_req_data(
- req, struct fetch_write_time_state);
- struct timespec write_time;
- struct share_mode_lock *lck = NULL;
- NTSTATUS status;
- size_t off;
-
- status = fetch_share_mode_recv(subreq, state, &lck);
- TALLOC_FREE(subreq);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- tevent_req_done(req);
- return;
- }
- if (tevent_req_nterror(req, status)) {
- return;
- }
-
- write_time = get_share_mode_write_time(lck);
- TALLOC_FREE(lck);
-
- if (is_omit_timespec(&write_time)) {
- tevent_req_done(req);
- return;
- }
-
- switch (state->info_level) {
- case SMB_FIND_FILE_DIRECTORY_INFO:
- case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
- case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- case SMB_FIND_ID_FULL_DIRECTORY_INFO:
- case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
- off = 24;
- break;
-
- default:
- DBG_ERR("Unsupported info_level [%d]\n", state->info_level);
- tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
- return;
- }
-
- put_long_date_full_timespec(state->conn->ts_res,
- state->entry_marshall_buf + off,
- &write_time);
-
- tevent_req_done(req);
- return;
-}
-
-static NTSTATUS fetch_write_time_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;
-}
-
struct fetch_dos_mode_state {
struct files_struct *dir_fsp;
struct smb_filename *smb_fname;
int info_level,
int requires_resume_key,
bool dont_descend,
- bool ask_sharemode,
bool get_dosmode,
uint8_t align,
bool do_pad,
mask,
dirtype,
dont_descend,
- ask_sharemode,
get_dosmode,
smbd_dirptr_lanman2_match_fn,
&state,
files_struct *fsp,
struct smb_filename *smb_fname,
bool delete_pending,
- struct timespec write_time_ts,
struct ea_list *ea_list,
uint16_t flags2,
unsigned int max_data_bytes,
dstart = pdata;
dend = dstart + data_size - 1;
- if (!is_omit_timespec(&write_time_ts) &&
- !INFO_LEVEL_IS_UNIX(info_level))
- {
- update_stat_ex_mtime(psbuf, write_time_ts);
- }
-
create_time_ts = get_create_timespec(conn, fsp, smb_fname);
mtime_ts = psbuf->st_ex_mtime;
atime_ts = psbuf->st_ex_atime;
bool fail_after_createfile)
{
NTSTATUS status = NT_STATUS_OK;
+ struct file_modified_state state;
files_struct *new_fsp = NULL;
if (!VALID_STAT(*psbuf)) {
get_file_size_stat(psbuf));
if (size == get_file_size_stat(psbuf)) {
- if (fsp == NULL) {
- return NT_STATUS_OK;
- }
- if (!fsp->fsp_flags.modified) {
- return NT_STATUS_OK;
- }
- trigger_write_time_update_immediate(fsp);
+ /*
+ * MS-FSA 2.1.5.15.4 FileEndOfFileInformation tells us not to
+ * update the timestamps, but Windows Server 2022 does it.
+ */
+ trigger_write_time_update_immediate(fsp, true, false);
return NT_STATUS_OK;
}
return status;
}
+ prepare_file_modified(fsp, &state);
if (vfs_set_filelen(fsp, size) == -1) {
return map_nt_error_from_unix(errno);
}
- trigger_write_time_update_immediate(fsp);
+ mark_file_modified(fsp, false, &state);
return NT_STATUS_OK;
}
return NT_STATUS_INVALID_LEVEL;
}
+ prepare_file_modified(fsp, &state);
if (vfs_set_filelen(new_fsp, size) == -1) {
status = map_nt_error_from_unix(errno);
close_file_free(req, &new_fsp, NORMAL_CLOSE);
return status;
}
+ mark_file_modified(fsp, false, &state);
- trigger_write_time_update_immediate(new_fsp);
close_file_free(req, &new_fsp, NORMAL_CLOSE);
return NT_STATUS_OK;
}
return status;
}
- if (fsp->fsp_flags.modified) {
- trigger_write_time_update_immediate(fsp);
- }
return NT_STATUS_OK;
}
return status;
}
- if (fsp->fsp_flags.modified) {
- trigger_write_time_update_immediate(fsp);
- }
return NT_STATUS_OK;
}
/* Only change if needed. */
if (allocation_size !=
- SMB_VFS_GET_ALLOC_SIZE(conn, new_fsp, &new_fsp->fsp_name->st))
+ SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &fsp->fsp_name->st))
{
if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
return map_nt_error_from_unix(errno);
}
}
- /* But always update the time. */
- /*
- * This is equivalent to a write. Ensure it's seen immediately
- * if there are no pending writes.
- */
- trigger_write_time_update_immediate(fsp);
+ trigger_write_time_update_immediate(fsp, false, true);
return NT_STATUS_OK;
}
}
}
- /* Changing the allocation size should set the last mod time. */
- /*
- * This is equivalent to a write. Ensure it's seen immediately
- * if there are no pending writes.
- */
- trigger_write_time_update_immediate(new_fsp);
+ trigger_write_time_update_immediate(new_fsp, false, true);
close_file_free(req, &new_fsp, NORMAL_CLOSE);
return NT_STATUS_OK;
}