diff --git a/source/include/proto.h b/source/include/proto.h index 291afac44d6..e94a2178c0a 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -5306,8 +5306,8 @@ void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok void set_delete_on_close_lck(struct share_mode_lock *lck, bool delete_on_close, UNIX_USER_TOKEN *tok); bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKEN *tok); bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, bool delete_on_close); -bool set_write_time(struct file_id fileid, struct timespec write_time, - bool overwrite); +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); int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *, const char *, void *), void *private_data); @@ -9616,11 +9616,10 @@ int file_set_dosmode(connection_struct *conn, const char *fname, const char *parent_dir, bool newfile); int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2]); -bool set_write_time_path(connection_struct *conn, const char *fname, - struct file_id fileid, const struct timespec mtime, - bool overwrite); -bool set_write_time_fsp(struct files_struct *fsp, const struct timespec mtime, - bool overwrite); +bool set_sticky_write_time_path(connection_struct *conn, const char *fname, + struct file_id fileid, const struct timespec mtime); +bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime); +bool update_write_time(struct files_struct *fsp); /* The following definitions come from smbd/error.c */ @@ -9665,6 +9664,7 @@ bool directory_has_default_acl(connection_struct *conn, const char *fname); ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n); void trigger_write_time_update(struct files_struct *fsp); +void trigger_write_time_update_immediate(struct files_struct *fsp); ssize_t write_file(struct smb_request *req, files_struct *fsp, const char *data, diff --git a/source/include/smb.h b/source/include/smb.h index c8c4f8c3cc9..d450eb51fad 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -456,7 +456,6 @@ typedef struct files_struct { uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */ uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */ - bool update_write_time_triggered; struct timed_event *update_write_time_event; bool update_write_time_on_close; struct timespec close_write_time; diff --git a/source/locking/locking.c b/source/locking/locking.c index ca61a886a60..f1f92786682 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -1405,22 +1405,21 @@ bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct return True; } -bool set_write_time(struct file_id fileid, struct timespec write_time, - bool overwrite) +bool set_sticky_write_time(struct file_id fileid, struct timespec write_time) { struct share_mode_lock *lck; - DEBUG(5,("set_write_time: %s overwrite=%d id=%s\n", + DEBUG(5,("set_sticky_write_time: %s id=%s\n", timestring(debug_ctx(), convert_timespec_to_time_t(write_time)), - overwrite, file_id_string_tos(&fileid))); + file_id_string_tos(&fileid))); lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL); if (lck == NULL) { return False; } - if (overwrite || null_timespec(lck->changed_write_time)) { + if (timespec_compare(&lck->changed_write_time, &write_time) != 0) { lck->modified = True; lck->changed_write_time = write_time; } @@ -1429,6 +1428,30 @@ bool set_write_time(struct file_id fileid, struct timespec write_time, return True; } +bool set_write_time(struct file_id fileid, struct timespec write_time) +{ + struct share_mode_lock *lck; + + DEBUG(5,("set_sticky_write_time: %s id=%s\n", + timestring(debug_ctx(), + convert_timespec_to_time_t(write_time)), + file_id_string_tos(&fileid))); + + lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL); + if (lck == NULL) { + return False; + } + + if (timespec_compare(&lck->old_write_time, &write_time) != 0) { + lck->modified = True; + lck->old_write_time = write_time; + } + + TALLOC_FREE(lck); + return True; +} + + struct forall_state { void (*fn)(const struct share_mode_entry *entry, const char *sharepath, diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index 0ac3873275b..88c6a51770e 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -616,39 +616,51 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe return ret; } -/******************************************************************* - Change a filetime - possibly allowing DOS semantics. -*******************************************************************/ +/****************************************************************** + Force a "sticky" write time on a pathname. This will always be + returned on all future write time queries and set on close. +******************************************************************/ -bool set_write_time_path(connection_struct *conn, const char *fname, - struct file_id fileid, const struct timespec mtime, - bool overwrite) +bool set_sticky_write_time_path(connection_struct *conn, const char *fname, + struct file_id fileid, const struct timespec mtime) { if (null_timespec(mtime)) { return true; } - if (!set_write_time(fileid, mtime, overwrite)) { + if (!set_sticky_write_time(fileid, mtime)) { return false; } - /* in the overwrite case the caller should trigger the notify */ - if (!overwrite) { - notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, fname); - } - return true; } -bool set_write_time_fsp(struct files_struct *fsp, const struct timespec mtime, - bool overwrite) +/****************************************************************** + Force a "sticky" write time on an fsp. This will always be + returned on all future write time queries and set on close. +******************************************************************/ + +bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime) { - if (overwrite) { - fsp->write_time_forced = true; - TALLOC_FREE(fsp->update_write_time_event); + fsp->write_time_forced = true; + TALLOC_FREE(fsp->update_write_time_event); + + return set_sticky_write_time_path(fsp->conn, fsp->fsp_name, + fsp->file_id, mtime); +} + +/****************************************************************** + Update a write time immediately, without the 2 second delay. +******************************************************************/ + +bool update_write_time(struct files_struct *fsp) +{ + if (!set_write_time(fsp->file_id, timespec_current())) { + return false; } - return set_write_time_path(fsp->conn, fsp->fsp_name, fsp->file_id, - mtime, overwrite); + notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name); + + return true; } diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index 64cea7f7ced..63850f24eba 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -176,28 +176,38 @@ static void update_write_time_handler(struct event_context *ctx, const struct timeval *now, void *private_data) { - files_struct *fsp = (files_struct *)private_data; + files_struct *fsp = (files_struct *)private_data; - /* Remove the timed event handler. */ - TALLOC_FREE(fsp->update_write_time_event); - DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); + /* Remove the timed event handler. */ + TALLOC_FREE(fsp->update_write_time_event); + DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); - /* change the write time if not already changed by someoneelse */ - set_write_time_fsp(fsp, timespec_current(), false); + /* change the write time if not already changed by someone else */ + update_write_time(fsp); } +/********************************************************* + Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY + in the future. +*********************************************************/ + void trigger_write_time_update(struct files_struct *fsp) { int delay; if (fsp->write_time_forced) { + /* No point - "sticky" write times + * in effect. + */ return; } - if (fsp->update_write_time_triggered) { + if (fsp->update_write_time_event) { + /* + * No point - an event is already scheduled. + */ return; } - fsp->update_write_time_triggered = true; delay = lp_parm_int(SNUM(fsp->conn), "smbd", "writetimeupdatedelay", @@ -212,6 +222,27 @@ void trigger_write_time_update(struct files_struct *fsp) update_write_time_handler, fsp); } +void trigger_write_time_update_immediate(struct files_struct *fsp) +{ + if (fsp->write_time_forced) { + /* + * No point - "sticky" write times + * in effect. + */ + return; + } + + if (fsp->update_write_time_event) { + /* + * No point - an event is already scheduled. + */ + return; + } + + fsp->update_write_time_on_close = true; + update_write_time(fsp); +} + /**************************************************************************** Write to a file. ****************************************************************************/ diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 16f8a5b1776..6933533672e 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -3810,9 +3810,11 @@ void reply_write(struct smb_request *req) END_PROFILE(SMBwrite); return; } - } else + trigger_write_time_update_immediate(fsp); + } else { nwritten = write_file(req,fsp,data,startpos,numtowrite); - + } + status = sync_file(conn, fsp, False); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("reply_write: sync_file for %s returned %s\n", diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 881b29c6f0a..8d839b66b38 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -4900,11 +4900,11 @@ NTSTATUS smb_set_file_time(connection_struct *conn, time_to_asc(convert_timespec_to_time_t(ts[1])) )); if (fsp != NULL) { - set_write_time_fsp(fsp, ts[1], true); + set_sticky_write_time_fsp(fsp, ts[1]); } else { - set_write_time_path(conn, fname, + set_sticky_write_time_path(conn, fname, vfs_file_id_from_sbuf(conn, psbuf), - ts[1], true); + ts[1]); } } @@ -4988,6 +4988,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, if (vfs_set_filelen(fsp, size) == -1) { return map_nt_error_from_unix(errno); } + trigger_write_time_update_immediate(fsp); return NT_STATUS_OK; } @@ -5011,6 +5012,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, return status; } + trigger_write_time_update_immediate(new_fsp); close_file(new_fsp,NORMAL_CLOSE); return NT_STATUS_OK; } @@ -5737,7 +5739,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, * This is equivalent to a write. Ensure it's seen immediately * if there are no pending writes. */ - trigger_write_time_update(fsp); + trigger_write_time_update_immediate(fsp); return NT_STATUS_OK; } @@ -5771,7 +5773,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, * This is equivalent to a write. Ensure it's seen immediately * if there are no pending writes. */ - trigger_write_time_update(new_fsp); + trigger_write_time_update_immediate(new_fsp); close_file(new_fsp,NORMAL_CLOSE); return NT_STATUS_OK;