Get closer to an accurate model of Windows timestamp changes.
authorJeremy Allison <jra@samba.org>
Fri, 6 Nov 2009 00:20:11 +0000 (16:20 -0800)
committerJeremy Allison <jra@samba.org>
Fri, 6 Nov 2009 00:20:11 +0000 (16:20 -0800)
"Normal" non truncate writes always cause the timestamp to
be set on close. Once a close is done on a handle this can
reset the sticky write time to current time also.
Updated smbtorture4 confirms this.
Jeremy.

source3/include/proto.h
source3/smbd/close.c
source3/smbd/dosmode.c
source3/smbd/fileio.c
source3/smbd/nttrans.c
source3/smbd/reply.c

index d08ed79050d41d81b7554a60c5e4ee2e0e623481..ef811e5774b7f02158aa95baa774950946015e0e 100644 (file)
@@ -6108,7 +6108,9 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw
 
 /* The following definitions come from smbd/close.c  */
 
-void set_close_write_time(struct files_struct *fsp, struct timespec ts);
+void set_close_write_time(struct share_mode_lock *lck,
+                       struct files_struct *fsp,
+                       struct timespec ts);
 NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
                    enum file_close_type close_type);
 void msg_close_file(struct messaging_context *msg_ctx,
@@ -6249,7 +6251,6 @@ int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime);
 bool set_sticky_write_time_fsp(struct files_struct *fsp,
                               struct timespec mtime);
-bool update_write_time(struct files_struct *fsp);
 
 NTSTATUS set_create_timespec_ea(connection_struct *conn,
                                struct files_struct *fsp,
index 642864f27e81ae40546c7f99cc6ffa9446674224..c1623ce290c3ed272885f24d8817a32a8921709b 100644 (file)
@@ -291,7 +291,15 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        }
 
        if (fsp->write_time_forced) {
-               set_close_write_time(fsp, lck->changed_write_time);
+               DEBUG(10,("close_remove_share_mode: write time forced "
+                       "for file %s\n",
+                       fsp_str_dbg(fsp)));
+               set_close_write_time(lck, fsp, lck->changed_write_time);
+       } else if (fsp->update_write_time_on_close) {
+               DEBUG(10,("close_remove_share_mode: update_write_time_on_close "
+                       "set for file %s\n",
+                       fsp_str_dbg(fsp)));
+               set_close_write_time(lck, fsp, timespec_current());
        }
 
        if (!del_share_mode(lck, fsp)) {
@@ -468,7 +476,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        return status;
 }
 
-void set_close_write_time(struct files_struct *fsp, struct timespec ts)
+void set_close_write_time(struct share_mode_lock *lck,
+                       struct files_struct *fsp, struct timespec ts)
 {
        DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
 
@@ -483,6 +492,14 @@ void set_close_write_time(struct files_struct *fsp, struct timespec ts)
 
        fsp->update_write_time_on_close = true;
        fsp->close_write_time = ts;
+
+       /* On close if we're changing the real file time we
+        * must update it in the open file db too. */
+       (void)set_write_time(fsp->file_id, ts);
+       /* If someone has a sticky write time then update it as well. */
+       if (lck && !null_timespec(lck->changed_write_time)) {
+               (void)set_sticky_write_time(fsp->file_id, ts);
+       }
 }
 
 static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
index 949c438f4feddc4d23961ffffdc5bf48bb8238b2..e10f23918d1e781f7fe729423c7077caee408407 100644 (file)
@@ -848,22 +848,6 @@ bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
        return set_sticky_write_time_path(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;
-       }
-
-       notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
-                    FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name);
-
-       return true;
-}
-
 /******************************************************************
  Set a create time EA.
 ******************************************************************/
index bd609d3e867798e42163e8d0136f9756b9356cdb..62e9a98a8d3e73c460e63a0cd7ef5d105534f0c4 100644 (file)
@@ -180,10 +180,15 @@ static void update_write_time_handler(struct event_context *ctx,
 
        /* Remove the timed event handler. */
        TALLOC_FREE(fsp->update_write_time_event);
+
        DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
 
-       /* change the write time if not already changed by someone else */
-       update_write_time(fsp);
+       /* change the write time in the open file db. */
+       (void)set_write_time(fsp->file_id, timespec_current());
+
+       /* And notify. */
+        notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+                     FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name);
 }
 
 /*********************************************************
@@ -207,11 +212,16 @@ void trigger_write_time_update(struct files_struct *fsp)
                return;
        }
 
+       /* We need to remember someone did a write
+        * and update to current time on close. */
+
+       fsp->update_write_time_on_close = true;
+
        if (fsp->update_write_time_triggered) {
                /*
-                * We only update the write time
-                * on the first write. After that
-                * no other writes affect this.
+                * We only update the write time after 2 seconds
+                * on the first normal write. After that
+                * no other writes affect this until close.
                 */
                return;
        }
@@ -221,8 +231,10 @@ void trigger_write_time_update(struct files_struct *fsp)
                            "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_on_close = true;
        fsp->update_write_time_event =
                event_add_timed(smbd_event_context(), NULL,
                                timeval_current_ofs(0, delay),
@@ -231,6 +243,8 @@ void trigger_write_time_update(struct files_struct *fsp)
 
 void trigger_write_time_update_immediate(struct files_struct *fsp)
 {
+       struct smb_file_time ft;
+
        if (fsp->posix_open) {
                /* Don't use delayed writes on POSIX files. */
                return;
@@ -248,10 +262,18 @@ void trigger_write_time_update_immediate(struct files_struct *fsp)
        DEBUG(5, ("Update write time immediate on %s\n",
                  fsp_str_dbg(fsp)));
 
+       /* After an immediate update, reset the trigger. */
        fsp->update_write_time_triggered = true;
-
         fsp->update_write_time_on_close = false;
-       update_write_time(fsp);
+
+       ZERO_STRUCT(ft);
+       ft.mtime = timespec_current();
+
+       /* Update the time in the open file db. */
+       (void)set_write_time(fsp->file_id, ft.mtime);
+
+       /* Now set on disk - takes care of notify. */
+       (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
 }
 
 /****************************************************************************
index 66102fa96ccdbf90393d260dc4d6de988d5a28a1..a1e7889119ed7a9d1fee26f2aaf6696f484b888d 100644 (file)
@@ -1296,7 +1296,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
        close_file(NULL, fsp1, NORMAL_CLOSE);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
+       set_close_write_time(NULL, fsp2, smb_fname_src->st.st_ex_mtime);
 
        status = close_file(NULL, fsp2, NORMAL_CLOSE);
 
index 984cf56c11181d4777efd37905c52e04f7e3625d..37634acc2ce4b5ac35169939b796b8124dc2e87d 100644 (file)
@@ -4646,7 +4646,7 @@ void reply_close(struct smb_request *req)
                 */
 
                t = srv_make_unix_date3(req->vwv+1);
-               set_close_write_time(fsp, convert_time_t_to_timespec(t));
+               set_close_write_time(NULL, fsp, convert_time_t_to_timespec(t));
 
                /*
                 * close_file() returns the unix errno if an error
@@ -4723,7 +4723,7 @@ void reply_writeclose(struct smb_request *req)
 
        nwritten = write_file(req,fsp,data,startpos,numtowrite);
 
-       set_close_write_time(fsp, mtime);
+       set_close_write_time(NULL, fsp, mtime);
 
        /*
         * More insanity. W2K only closes the file if writelen > 0.
@@ -6691,7 +6691,7 @@ NTSTATUS copy_file(TALLOC_CTX *ctx,
        close_file(NULL, fsp1, NORMAL_CLOSE);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
+       set_close_write_time(NULL, fsp2, smb_fname_src->st.st_ex_mtime);
 
        /*
         * As we are opening fsp1 read-only we only expect