summaryrefslogtreecommitdiff
path: root/source3/smbd/fileio.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2008-03-12 15:39:38 +0100
committerStefan Metzmacher <metze@samba.org>2008-04-07 12:29:26 +0200
commitd03453864ab1bc5fd3b4a3abaf96176a006c102b (patch)
tree13389e06bd05336a1937b98d3e821ad995eef019 /source3/smbd/fileio.c
parent2ccf50256e31bd7b9da0f7a7c223bebca5bca062 (diff)
downloadsamba-d03453864ab1bc5fd3b4a3abaf96176a006c102b.tar.gz
samba-d03453864ab1bc5fd3b4a3abaf96176a006c102b.tar.bz2
samba-d03453864ab1bc5fd3b4a3abaf96176a006c102b.zip
smbd: implement the strange write time update logic
We now never call file_ntimes() directly, every update is done via smb_set_file_time(). This let samba3 pass the BASE-DELAYWRITE test. The write time is only updated 2 seconds after the first write() on any open handle to the current time (not the time of the first write). Each handle which had write requests updates the write time to the current time on close(). If the write time is set explicit via setfileinfo or setpathinfo the write time is visible directly and a following close on the same handle doesn't update the write time. metze (This used to be commit 2eab212ea2e1bfd8fa716c2c89b2c042f7ba12ea)
Diffstat (limited to 'source3/smbd/fileio.c')
-rw-r--r--source3/smbd/fileio.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 8cea4989f5..93a303f6c8 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -142,27 +142,6 @@ static ssize_t real_write_file(struct smb_request *req,
if (ret != -1) {
fsp->fh->pos += ret;
- /*
- * It turns out that setting the last write time from a Windows
- * client stops any subsequent writes from updating the write time.
- * Doing this after the write gives a race condition here where
- * a stat may see the changed write time before we reset it here,
- * but it's cheaper than having to store the write time in shared
- * memory and look it up using dev/inode across all running smbd's.
- * The 99% solution will hopefully be good enough in this case. JRA.
- */
-
- if (!null_timespec(fsp->pending_modtime)) {
- set_filetime(fsp->conn, fsp->fsp_name,
- fsp->pending_modtime);
-
- /* If we didn't get the "set modtime" call ourselves, we must
- store the last write time to restore on close. JRA. */
- if (!fsp->pending_modtime_owner) {
- fsp->last_write_time = timespec_current();
- }
- }
-
/* Yes - this is correct - writes don't update this. JRA. */
/* Found by Samba4 tests. */
#if 0
@@ -192,6 +171,41 @@ static int wcp_file_size_change(files_struct *fsp)
return ret;
}
+static void update_write_time_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *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));
+
+ /* change the write time if not already changed by someoneelse */
+ set_write_time_fsp(fsp, timespec_current(), false);
+}
+
+void trigger_write_time_update(struct files_struct *fsp)
+{
+ if (fsp->write_time_forced) {
+ return;
+ }
+
+ if (fsp->update_write_time_triggered) {
+ return;
+ }
+ fsp->update_write_time_triggered = true;
+
+ /* 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(2, 0),
+ "update_write_time_handler",
+ update_write_time_handler, fsp);
+}
+
/****************************************************************************
Write to a file.
****************************************************************************/
@@ -230,7 +244,9 @@ ssize_t write_file(struct smb_request *req,
fsp->modified = True;
if (SMB_VFS_FSTAT(fsp, &st) == 0) {
- int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
+ int dosmode;
+ trigger_write_time_update(fsp);
+ dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
if ((lp_store_dos_attributes(SNUM(fsp->conn)) ||
MAP_ARCHIVE(fsp->conn)) &&
!IS_DOS_ARCHIVE(dosmode)) {