From: Stefan Metzmacher Date: Wed, 12 Mar 2008 14:39:38 +0000 (+0100) Subject: smbd: implement the strange write time update logic X-Git-Tag: release-3-2-0pre3~1481 X-Git-Url: http://git.samba.org/samba.git/?p=tprouty%2Fsamba.git;a=commitdiff_plain;h=55b6fc1f75ead24258f38d0c8c2088a1899c154b 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 (cherry picked from commit 2eab212ea2e1bfd8fa716c2c89b2c042f7ba12ea) --- diff --git a/source/include/smb.h b/source/include/smb.h index d4bbe2d0ff..70e980a12c 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -485,9 +485,13 @@ typedef struct files_struct { struct timeval open_time; 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 pending_modtime_owner; - struct timespec pending_modtime; - struct timespec last_write_time; + + bool update_write_time_triggered; + struct timed_event *update_write_time_event; + bool update_write_time_on_close; + struct timespec close_write_time; + bool write_time_forced; + int oplock_type; int sent_oplock_break; struct timed_event *oplock_timeout; diff --git a/source/smbd/close.c b/source/smbd/close.c index 8a5c82cc93..3afc037f69 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -255,6 +255,10 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, return NT_STATUS_INVALID_PARAMETER; } + if (fsp->write_time_forced) { + set_close_write_time(fsp, lck->changed_write_time); + } + if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_remove_share_mode: Could not delete share " "entry for file %s\n", fsp->fsp_name)); @@ -317,6 +321,11 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set " "- deleting file.\n", fsp->fsp_name)); + /* + * Don't try to update the write time when we delete the file + */ + fsp->update_write_time_on_close = false; + if (!unix_token_equal(lck->delete_token, ¤t_user.ut)) { /* Become the user who requested the delete. */ @@ -428,6 +437,66 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, return status; } +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)))); + + if (null_timespec(ts)) { + return; + } + /* + * if the write time on close is explict set, then don't + * need to fix it up to the value in the locking db + */ + fsp->write_time_forced = false; + + fsp->update_write_time_on_close = true; + fsp->close_write_time = ts; +} + +static NTSTATUS update_write_time_on_close(struct files_struct *fsp) +{ + SMB_STRUCT_STAT sbuf; + struct timespec ts[2]; + NTSTATUS status; + + ZERO_STRUCT(sbuf); + ZERO_STRUCT(ts); + + if (!fsp->update_write_time_on_close) { + return NT_STATUS_OK; + } + + if (null_timespec(fsp->close_write_time)) { + fsp->close_write_time = timespec_current(); + } + + /* Ensure we have a valid stat struct for the source. */ + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } else { + if (SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } + + if (!VALID_STAT(sbuf)) { + /* if it doesn't seem to be a real file */ + return NT_STATUS_OK; + } + + ts[1] = fsp->close_write_time; + status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, + &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + /**************************************************************************** Close a file. @@ -442,6 +511,7 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ NTSTATUS saved_status1 = NT_STATUS_OK; NTSTATUS saved_status2 = NT_STATUS_OK; NTSTATUS saved_status3 = NT_STATUS_OK; + NTSTATUS saved_status4 = NT_STATUS_OK; connection_struct *conn = fsp->conn; if (fsp->aio_write_behind) { @@ -496,11 +566,7 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ * Ensure pending modtime is set after close. */ - if (fsp->pending_modtime_owner && !null_timespec(fsp->pending_modtime)) { - set_filetime(conn, fsp->fsp_name, fsp->pending_modtime); - } else if (!null_timespec(fsp->last_write_time)) { - set_filetime(conn, fsp->fsp_name, fsp->last_write_time); - } + saved_status4 = update_write_time_on_close(fsp); if (NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(saved_status1)) { @@ -509,6 +575,8 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ status = saved_status2; } else if (!NT_STATUS_IS_OK(saved_status3)) { status = saved_status3; + } else if (!NT_STATUS_IS_OK(saved_status4)) { + status = saved_status4; } } diff --git a/source/smbd/dir.c b/source/smbd/dir.c index ca6f8bfd8d..8531d6250d 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -841,6 +841,8 @@ bool get_dir_entry(TALLOC_CTX *ctx, mask_match_search(filename,mask,False) || mangle_mask_match(conn,filename,mask)) { char mname[13]; + struct timespec write_time_ts; + struct file_id fileid; if (!mangle_is_8_3(filename, False, conn->params)) { if (!name_to_8_3(filename,mname,False, @@ -883,6 +885,12 @@ bool get_dir_entry(TALLOC_CTX *ctx, *size = sbuf.st_size; *date = sbuf.st_mtime; + fileid = vfs_file_id_from_sbuf(conn, &sbuf); + write_time_ts = get_write_time(fileid); + if (!null_timespec(write_time_ts)) { + *date = convert_timespec_to_time_t(write_time_ts); + } + DEBUG(3,("get_dir_entry mask=[%s] found %s " "fname=%s (%s)\n", mask, diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index a2e617c117..0ac3873275 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -571,6 +571,11 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe errno = 0; ZERO_STRUCT(sbuf); + DEBUG(6, ("file_ntime: actime: %s", + time_to_asc(convert_timespec_to_time_t(ts[0])))); + DEBUG(6, ("file_ntime: modtime: %s", + time_to_asc(convert_timespec_to_time_t(ts[1])))); + /* Don't update the time on read-only shares */ /* We need this as set_filetime (which can be called on close and other paths) can end up calling this function @@ -615,26 +620,35 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe Change a filetime - possibly allowing DOS semantics. *******************************************************************/ -bool set_filetime(connection_struct *conn, const char *fname, - const struct timespec mtime) +bool set_write_time_path(connection_struct *conn, const char *fname, + struct file_id fileid, const struct timespec mtime, + bool overwrite) { - struct timespec ts[2]; - if (null_timespec(mtime)) { - return(True); + return true; } - ts[1] = mtime; /* mtime. */ - ts[0] = ts[1]; /* atime. */ - - if (file_ntimes(conn, fname, ts)) { - DEBUG(4,("set_filetime(%s) failed: %s\n", - fname,strerror(errno))); - return False; + if (!set_write_time(fileid, mtime, overwrite)) { + return false; } - notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, fname); + /* 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) +{ + if (overwrite) { + fsp->write_time_forced = true; + TALLOC_FREE(fsp->update_write_time_event); + } + + return set_write_time_path(fsp->conn, fsp->fsp_name, fsp->file_id, + mtime, overwrite); +} diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index 8cea4989f5..93a303f6c8 100644 --- a/source/smbd/fileio.c +++ b/source/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)) { diff --git a/source/smbd/files.c b/source/smbd/files.c index 95f01b88ce..d6e91c67be 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -374,29 +374,6 @@ files_struct *file_find_print(void) return NULL; } -/**************************************************************************** - Set a pending modtime across all files with a given dev/ino pair. - Record the owner of that modtime. -****************************************************************************/ - -void fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod) -{ - files_struct *fsp; - - if (null_timespec(mod)) { - return; - } - - for (fsp = Files;fsp;fsp=fsp->next) { - if ( fsp->fh->fd != -1 && file_id_equal(&fsp->file_id, &tfsp->file_id)) { - fsp->pending_modtime = mod; - fsp->pending_modtime_owner = False; - } - } - - tfsp->pending_modtime_owner = True; -} - /**************************************************************************** Sync open files on a connection. ****************************************************************************/ @@ -441,6 +418,9 @@ void file_free(files_struct *fsp) /* Ensure this event will never fire. */ TALLOC_FREE(fsp->oplock_timeout); + /* Ensure this event will never fire. */ + TALLOC_FREE(fsp->update_write_time_event); + bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); files_used--; @@ -548,9 +528,6 @@ NTSTATUS dup_file_fsp(files_struct *fsp, dup_fsp->open_time = fsp->open_time; dup_fsp->access_mask = access_mask; dup_fsp->share_access = share_access; - dup_fsp->pending_modtime_owner = fsp->pending_modtime_owner; - dup_fsp->pending_modtime = fsp->pending_modtime; - dup_fsp->last_write_time = fsp->last_write_time; dup_fsp->oplock_type = fsp->oplock_type; dup_fsp->can_lock = fsp->can_lock; dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 6bcf499516..e8dae705b0 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -1233,7 +1233,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1)); + set_close_write_time(fsp2, get_mtimespec(&sbuf1)); status = close_file(fsp2,NORMAL_CLOSE); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index b300c09f4f..411eb98ac5 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1042,6 +1042,7 @@ void reply_getatr(struct smb_request *req) void reply_setatr(struct smb_request *req) { + struct timespec ts[2]; connection_struct *conn = req->conn; char *fname = NULL; int mode; @@ -1053,6 +1054,8 @@ void reply_setatr(struct smb_request *req) START_PROFILE(SMBsetatr); + ZERO_STRUCT(ts); + if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); return; @@ -1110,7 +1113,10 @@ void reply_setatr(struct smb_request *req) mode = SVAL(req->inbuf,smb_vwv0); mtime = srv_make_unix_date3(req->inbuf+smb_vwv1); - if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) { + ts[1] = convert_time_t_to_timespec(mtime); + status = smb_set_file_time(conn, NULL, fname, + &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { reply_unixerror(req, ERRDOS, ERRnoaccess); END_PROFILE(SMBsetatr); return; @@ -1985,7 +1991,12 @@ void reply_mknew(struct smb_request *req) } ts[0] = get_atimespec(&sbuf); /* atime. */ - file_ntimes(conn, fsp->fsp_name, ts); + status = smb_set_file_time(conn, fsp, fname, &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcreate); + reply_openerror(req, status); + return; + } reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,fsp->fnum); @@ -4239,6 +4250,7 @@ void reply_close(struct smb_request *req) DEBUG(3,("close directory fnum=%d\n", fsp->fnum)); status = close_file(fsp,NORMAL_CLOSE); } else { + time_t t; /* * Close ordinary file. */ @@ -4251,9 +4263,8 @@ void reply_close(struct smb_request *req) * Take care of any time sent in the close. */ - fsp_set_pending_modtime(fsp, convert_time_t_to_timespec( - srv_make_unix_date3( - req->inbuf+smb_vwv1))); + t = srv_make_unix_date3(req->inbuf+smb_vwv1); + set_close_write_time(fsp, convert_time_t_to_timespec(t)); /* * close_file() returns the unix errno if an error @@ -4326,8 +4337,8 @@ void reply_writeclose(struct smb_request *req) nwritten = write_file(req,fsp,data,startpos,numtowrite); - set_filetime(conn, fsp->fsp_name, mtime); - + set_close_write_time(fsp, mtime); + /* * More insanity. W2K only closes the file if writelen > 0. * JRA. @@ -6078,7 +6089,7 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime( fsp2, get_mtimespec(&src_sbuf)); + set_close_write_time(fsp2, get_mtimespec(&src_sbuf)); /* * As we are opening fsp1 read-only we only expect @@ -6961,6 +6972,8 @@ void reply_setattrE(struct smb_request *req) connection_struct *conn = req->conn; struct timespec ts[2]; files_struct *fsp; + SMB_STRUCT_STAT sbuf; + NTSTATUS status; START_PROFILE(SMBsetattrE); @@ -6996,23 +7009,27 @@ void reply_setattrE(struct smb_request *req) * Sometimes times are sent as zero - ignore them. */ - if (null_timespec(ts[0]) && null_timespec(ts[1])) { - /* Ignore request */ - if( DEBUGLVL( 3 ) ) { - dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); - dbgtext( "ignoring zero request - not setting timestamps of 0\n" ); + /* Ensure we have a valid stat struct for the source. */ + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + status = map_nt_error_from_unix(errno); + reply_nterror(req, status); + END_PROFILE(SMBsetattrE); + return; + } + } else { + if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) { + status = map_nt_error_from_unix(errno); + reply_nterror(req, status) + END_PROFILE(SMBsetattrE); + return; } - END_PROFILE(SMBsetattrE); - return; - } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) { - /* set modify time = to access time if modify time was unset */ - ts[1] = ts[0]; } - /* Set the date on this file */ - /* Should we set pending modtime here ? JRA */ - if(file_ntimes(conn, fsp->fsp_name, ts)) { - reply_doserror(req, ERRDOS, ERRnoaccess); + status = smb_set_file_time(conn, fsp, fsp->fsp_name, + &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { + reply_doserror(req, ERRDOS, ERRnoaccess) END_PROFILE(SMBsetattrE); return; } diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 897ed33431..a9e7f5e34c 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -1238,6 +1238,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, bool needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); bool check_mangled_names = lp_manglednames(conn->params); char mangled_name[13]; /* mangled 8.3 name. */ + struct timespec write_time_ts; *out_of_space = False; *got_exact_match = False; @@ -1397,6 +1398,12 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, adate_ts = get_atimespec(&sbuf); create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + write_time_ts = get_write_time( + vfs_file_id_from_sbuf(conn, &sbuf)); + if (!null_timespec(write_time_ts)) { + mdate_ts = write_time_ts; + } + if (lp_dos_filetime_resolution(SNUM(conn))) { dos_filetime_timespec(&create_date_ts); dos_filetime_timespec(&mdate_ts); @@ -3784,6 +3791,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, int len; time_t create_time, mtime, atime; struct timespec create_time_ts, mtime_ts, atime_ts; + struct timespec write_time_ts; files_struct *fsp = NULL; struct file_id fileid; struct ea_list *ea_list = NULL; @@ -3797,6 +3805,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } ZERO_STRUCT(sbuf); + ZERO_STRUCT(write_time_ts); if (tran_call == TRANSACT2_QFILEINFO) { if (total_params < 4) { @@ -3862,6 +3871,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, fileid = vfs_file_id_from_sbuf(conn, &sbuf); delete_pending = get_delete_on_close_flag(fileid); + write_time_ts = get_write_time(fileid); } else { /* * Original code - this is an open file. @@ -3878,6 +3888,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, pos = fsp->fh->position_information; fileid = vfs_file_id_from_sbuf(conn, &sbuf); delete_pending = get_delete_on_close_flag(fileid); + write_time_ts = get_write_time(fileid); access_mask = fsp->access_mask; } @@ -3953,6 +3964,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, reply_nterror(req, NT_STATUS_DELETE_PENDING); return; } + write_time_ts = get_write_time(fileid); } if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { @@ -4073,25 +4085,20 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd allocation_size = get_allocation_size(conn,fsp,&sbuf); - if (fsp) { - if (!null_timespec(fsp->pending_modtime)) { - /* the pending modtime overrides the current modtime */ - mtime_ts = fsp->pending_modtime; - } - } else { - files_struct *fsp1; + if (!fsp) { /* Do we have this path open ? */ + files_struct *fsp1; fileid = vfs_file_id_from_sbuf(conn, &sbuf); fsp1 = file_find_di_first(fileid); - if (fsp1 && !null_timespec(fsp1->pending_modtime)) { - /* the pending modtime overrides the current modtime */ - mtime_ts = fsp1->pending_modtime; - } if (fsp1 && fsp1->initial_allocation_size) { allocation_size = get_allocation_size(conn, fsp1, &sbuf); } } + if (!null_timespec(write_time_ts)) { + mtime_ts = write_time_ts; + } + if (lp_dos_filetime_resolution(SNUM(conn))) { dos_filetime_timespec(&create_time_ts); dos_filetime_timespec(&mtime_ts); @@ -4781,12 +4788,12 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, Deal with setting the time from any of the setfilepathinfo functions. ****************************************************************************/ -static NTSTATUS smb_set_file_time(connection_struct *conn, - files_struct *fsp, - const char *fname, - const SMB_STRUCT_STAT *psbuf, - struct timespec ts[2], - bool setting_write_time) +NTSTATUS smb_set_file_time(connection_struct *conn, + files_struct *fsp, + const char *fname, + const SMB_STRUCT_STAT *psbuf, + struct timespec ts[2], + bool setting_write_time) { uint32 action = FILE_NOTIFY_CHANGE_LAST_ACCESS @@ -4828,7 +4835,7 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, } } - if(fsp != NULL) { + if (setting_write_time) { /* * This was a setfileinfo on an open file. * NT does this a lot. We also need to @@ -4839,13 +4846,18 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, * away and will set it on file close and after a write. JRA. */ - if (!null_timespec(ts[1])) { - DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", - time_to_asc(convert_timespec_to_time_t(ts[1])) )); - fsp_set_pending_modtime(fsp, ts[1]); - } + DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", + time_to_asc(convert_timespec_to_time_t(ts[1])) )); + if (fsp != NULL) { + set_write_time_fsp(fsp, ts[1], true); + } else { + set_write_time_path(conn, fname, + vfs_file_id_from_sbuf(conn, psbuf), + ts[1], true); + } } + DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); if(file_ntimes(conn, fname, ts)!=0) { @@ -5670,14 +5682,11 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } } /* But always update the time. */ - if (null_timespec(fsp->pending_modtime)) { - /* - * This is equivalent to a write. Ensure it's seen immediately - * if there are no pending writes. - */ - set_filetime(fsp->conn, fsp->fsp_name, - timespec_current()); - } + /* + * This is equivalent to a write. Ensure it's seen immediately + * if there are no pending writes. + */ + trigger_write_time_update(fsp); return NT_STATUS_OK; } @@ -5707,10 +5716,11 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } /* Changing the allocation size should set the last mod time. */ - /* Don't need to call set_filetime as this will be flushed on - * close. */ - - fsp_set_pending_modtime(new_fsp, timespec_current()); + /* + * This is equivalent to a write. Ensure it's seen immediately + * if there are no pending writes. + */ + trigger_write_time_update(new_fsp); close_file(new_fsp,NORMAL_CLOSE); return NT_STATUS_OK; @@ -6658,11 +6668,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn, SSVAL(params,0,0); - if (fsp && !null_timespec(fsp->pending_modtime)) { - /* the pending modtime overrides the current modtime */ - set_mtimespec(&sbuf, fsp->pending_modtime); - } - switch (info_level) { case SMB_INFO_STANDARD: