Write times code update.
authorJeremy Allison <jra@samba.org>
Sat, 6 Sep 2008 02:01:32 +0000 (19:01 -0700)
committerKarolin Seeger <kseeger@samba.org>
Tue, 9 Sep 2008 10:16:51 +0000 (12:16 +0200)
Ok, here's the fix for the write times breakage
with the new tests in S4 smbtorture.

The key is keeping in the share mode struct
the "old_file_time" as the real write time,
set by all the write and allocation calls,
and the "changed_write_time" as the "sticky"
write time - set by the SET_FILE_TIME calls.

We can set them independently (although I
kept the optimization of not setting the
"old_file_time" is a "changed_write_time"
was already set, as we'll never see it.

This allows us to update the write time
immediately on the SMBwrite truncate case,
SET_END_OF_FILE and SET_ALLOCATION_SIZE calls,
whilst still have the 2 second delay on the
"normal" SMBwrite, SMBwriteX calls.

I think in a subsequent patch I'd like to
change the name of these from "old_file_time"
to "write_time" and "changed_write_time" to
"sticky_write_time" to make this clearer.

I think I also fixed a bug in Metze's original
code in that once a write timestamp had been
set from a "normal" SMBwriteX call the fsp->update_write_time_triggered
variable was set and then never reset - thus
meaning the write timestamp would never get
updated again on subsequent SMBwriteX's.

The new code checks the update_write_time_event
event instead, and doesn't update is there's
an event already scheduled.

Metze especially, please check this over for
your understanding.

Jeremy.
(cherry picked from commit aff490ef3b32b3bb2c11cf35ed3fa0272178da3f)

source/Makefile.in
source/include/proto.h
source/include/smb.h
source/locking/locking.c
source/smbd/dosmode.c
source/smbd/fileio.c
source/smbd/process.c
source/smbd/reply.c
source/smbd/trans2.c

index 5793b5ef4d4c671c1e4710c1decbe4762941144d..03f04cc9bf58989a26cfee9ec99e46da4f82d679 100644 (file)
@@ -623,6 +623,7 @@ VFS_TSMSM_OBJ = modules/vfs_tsmsm.o
 VFS_FILEID_OBJ = modules/vfs_fileid.o
 VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o
 VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
+VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -2381,6 +2382,10 @@ bin/aio_fork.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_FORK_OBJ)
        @echo "Building plugin $@"
        @$(SHLD_MODULE) $(VFS_AIO_FORK_OBJ)
 
+bin/vfs_acl_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ACL_XATTR_OBJ)
+       @echo "Building plugin $@"
+       @$(SHLD_MODULE) $(VFS_ACL_XATTR_OBJ)
+
 bin/registry.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/registry.o
        @echo "Building plugin $@"
        @$(SHLD_MODULE) libgpo/gpext/registry.o
index d5e942a6d7143561afec442d2ec10a196b9bbb82..eeb62e1e773fe2f0b19dce0700a8f4a2fd339a2d 100644 (file)
@@ -5308,8 +5308,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,
index c8c4f8c3cc98453750b1189e914e0cf7ec433a10..d450eb51fad54fb3d9236bee93a81f56b687eea6 100644 (file)
@@ -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;
index ca61a886a60489de450d3a520b5f527f7565d0a1..f1f92786682e7c54598d0a3c7f3e3a46e56b1ba2 100644 (file)
@@ -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,
index 0ac3873275b17688b7e0a260a9d4eb47940433f2..88c6a51770e290b1f71a63191ac710e326b2d18f 100644 (file)
@@ -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;
 }
index 64cea7f7ced116b87b4f1ccac2361484429f8643..63850f24eba7234eb0b834b4a17664ea1dcb21ae 100644 (file)
@@ -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.
 ****************************************************************************/
index b2d19e11e38850cb2701b044a784d42d26a1c5f1..c7e5c4cde37b651570ee0edf9cdf57f8f83837f4 100644 (file)
@@ -152,7 +152,7 @@ static NTSTATUS read_packet_remainder(int fd, char *buffer,
                                1 /* pad byte */)
 
 static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
-                                                   const char lenbuf[4],
+                                                   const char *lenbuf,
                                                    int fd, char **buffer,
                                                    unsigned int timeout,
                                                    size_t *p_unread,
index ff38ac88cfef60d5fd37ee34431c875d974f8b9c..3ddfad04844815b36943b7528b31782577e819a9 100644 (file)
@@ -3813,9 +3813,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",
index 881b29c6f0ac76265344124282187ef0b88c342b..8d839b66b38b68d75b008e6e9c700040a469f36a 100644 (file)
@@ -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;