From 3e9d824bed73e55a6a5bf8c374b249e94dee877c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 12 Mar 2008 00:16:41 +0100 Subject: [PATCH] Make the sticky writetime patch compile in 3.2 Signed-off-by: Stefan Metzmacher --- source/include/smb.h | 14 ++++++-- source/locking/locking.c | 91 +++++++++++++++++++++++++++++++++++++++------- source/smbd/close.c | 75 ++++++++++++++++++++++++++++++++++---- source/smbd/dosmode.c | 42 ++++++++++++++------- source/smbd/fileio.c | 56 ++++++++++++++++++----------- source/smbd/files.c | 29 ++------------- source/smbd/nttrans.c | 2 +- source/smbd/open.c | 15 +++++--- source/smbd/oplock.c | 9 +++-- source/smbd/reply.c | 57 ++++++++++++++++++----------- source/smbd/trans2.c | 88 ++++++++++++++++++++++++--------------------- 11 files changed, 321 insertions(+), 157 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index bf9ca6b..70e980a 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; @@ -811,6 +815,8 @@ struct share_mode_lock { struct share_mode_entry *share_modes; UNIX_USER_TOKEN *delete_token; bool delete_on_close; + struct timespec old_write_time; + struct timespec changed_write_time; bool fresh; bool modified; struct db_record *record; @@ -826,6 +832,8 @@ struct locking_data { struct { int num_share_mode_entries; bool delete_on_close; + struct timespec old_write_time; + struct timespec changed_write_time; uint32 delete_token_size; /* Only valid if either of the two previous fields are True. */ diff --git a/source/locking/locking.c b/source/locking/locking.c index 513bb31..1220245 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -504,12 +504,20 @@ static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) data = (struct locking_data *)dbuf.dptr; lck->delete_on_close = data->u.s.delete_on_close; + lck->old_write_time = data->u.s.old_write_time; + lck->changed_write_time = data->u.s.changed_write_time; lck->num_share_modes = data->u.s.num_share_mode_entries; - DEBUG(10, ("parse_share_modes: delete_on_close: %d, " - "num_share_modes: %d\n", - lck->delete_on_close, - lck->num_share_modes)); + DEBUG(10, ("parse_share_modes: delete_on_close: %d, owrt: %s, " + "cwrt: %s, tok: %u, num_share_modes: %d\n", + lck->delete_on_close, + timestring(debug_ctx(), + convert_timespec_to_time_t(lck->old_write_time)), + timestring(debug_ctx(), + convert_timespec_to_time_t( + lck->changed_write_time)), + (unsigned int)data->u.s.delete_token_size, + lck->num_share_modes)); if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { DEBUG(0, ("invalid number of share modes: %d\n", @@ -660,11 +668,20 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) ZERO_STRUCTP(data); data->u.s.num_share_mode_entries = lck->num_share_modes; data->u.s.delete_on_close = lck->delete_on_close; + data->u.s.old_write_time = lck->old_write_time; + data->u.s.changed_write_time = lck->changed_write_time; data->u.s.delete_token_size = delete_token_size; - DEBUG(10, ("unparse_share_modes: del: %d, tok = %u, num: %d\n", - data->u.s.delete_on_close, - (unsigned int)data->u.s.delete_token_size, - data->u.s.num_share_mode_entries)); + + DEBUG(10,("unparse_share_modes: del: %d, owrt: %s cwrt: %s, tok: %u, " + "num: %d\n", data->u.s.delete_on_close, + timestring(debug_ctx(), + convert_timespec_to_time_t(lck->old_write_time)), + timestring(debug_ctx(), + convert_timespec_to_time_t( + lck->changed_write_time)), + (unsigned int)data->u.s.delete_token_size, + data->u.s.num_share_mode_entries)); + memcpy(result.dptr + sizeof(*data), lck->share_modes, sizeof(struct share_mode_entry)*lck->num_share_modes); offset = sizeof(*data) + @@ -740,7 +757,8 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, struct file_id id, const char *servicepath, const char *fname, - TDB_DATA share_mode_data) + TDB_DATA share_mode_data, + const struct timespec *old_write_time) { /* Ensure we set every field here as the destructor must be valid even if parse_share_modes fails. */ @@ -752,13 +770,16 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, lck->share_modes = NULL; lck->delete_token = NULL; lck->delete_on_close = False; + ZERO_STRUCT(lck->old_write_time); + ZERO_STRUCT(lck->changed_write_time); lck->fresh = False; lck->modified = False; lck->fresh = (share_mode_data.dptr == NULL); if (lck->fresh) { - if (fname == NULL || servicepath == NULL) { + if (fname == NULL || servicepath == NULL + || old_write_time == NULL) { return False; } lck->filename = talloc_strdup(lck, fname); @@ -767,6 +788,7 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, DEBUG(0, ("talloc failed\n")); return False; } + lck->old_write_time = *old_write_time; } else { if (!parse_share_modes(share_mode_data, lck)) { DEBUG(0, ("Could not parse share modes\n")); @@ -780,7 +802,8 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, const struct file_id id, const char *servicepath, - const char *fname) + const char *fname, + const struct timespec *old_write_time) { struct share_mode_lock *lck; struct file_id tmp; @@ -798,7 +821,7 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, } if (!fill_share_mode_lock(lck, id, servicepath, fname, - lck->record->value)) { + lck->record->value, old_write_time)) { DEBUG(3, ("fill_share_mode_lock failed\n")); TALLOC_FREE(lck); return NULL; @@ -830,7 +853,7 @@ struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, return NULL; } - if (!fill_share_mode_lock(lck, id, servicepath, fname, data)) { + if (!fill_share_mode_lock(lck, id, servicepath, fname, data, NULL)) { DEBUG(3, ("fill_share_mode_lock failed\n")); TALLOC_FREE(lck); return NULL; @@ -918,6 +941,21 @@ bool rename_share_filename(struct messaging_context *msg_ctx, return True; } +struct timespec get_write_time(struct file_id id) +{ + struct timespec result; + struct share_mode_lock *lck; + + ZERO_STRUCT(result); + + if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id, NULL, NULL))) { + return result; + } + result = lck->changed_write_time; + TALLOC_FREE(lck); + return result; +} + bool get_delete_on_close_flag(struct file_id id) { bool result; @@ -1322,7 +1360,8 @@ bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKE return True; } - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { return False; } @@ -1362,6 +1401,30 @@ 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) +{ + struct share_mode_lock *lck; + + DEBUG(5,("set_write_time: %s overwrite=%d id=%s\n", + timestring(debug_ctx(), + convert_timespec_to_time_t(write_time)), + overwrite, 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)) { + lck->modified = True; + lck->changed_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/close.c b/source/smbd/close.c index 4bd23a3..5242956 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -246,7 +246,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, * This prevents race conditions with the file being created. JRA. */ - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0, ("close_remove_share_mode: Could not get share mode " @@ -316,6 +317,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. */ @@ -427,6 +433,61 @@ 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); + } + } + + 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. @@ -441,6 +502,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) { @@ -495,11 +557,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)) { @@ -508,6 +566,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; } } @@ -535,7 +595,8 @@ static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_ty * reference to a directory also. */ - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name)); diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index a2e617c..0ac3873 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 8cea498..21bfe00 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. ****************************************************************************/ diff --git a/source/smbd/files.c b/source/smbd/files.c index 95f01b8..d6e91c6 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -375,29 +375,6 @@ files_struct *file_find_print(void) } /**************************************************************************** - 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 bc93d19..c167375 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/open.c b/source/smbd/open.c index 0cc48c4..f3ed234 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1221,7 +1221,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, request_time = pml->request_time; /* Remove the deferred open entry under lock. */ - lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0, ("could not get share mode lock\n")); } else { @@ -1450,11 +1451,12 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } if (file_existed) { + struct timespec old_write_time = get_mtimespec(psbuf); id = vfs_file_id_from_sbuf(conn, psbuf); lck = get_share_mode_lock(talloc_tos(), id, conn->connectpath, - fname); + fname, &old_write_time); if (lck == NULL) { file_free(fsp); @@ -1661,7 +1663,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } if (!file_existed) { - + struct timespec old_write_time = get_mtimespec(psbuf); /* * Deal with the race condition where two smbd's detect the * file doesn't exist and do the create at the same time. One @@ -1681,7 +1683,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, lck = get_share_mode_lock(talloc_tos(), id, conn->connectpath, - fname); + fname, &old_write_time); if (lck == NULL) { DEBUG(0, ("open_file_ntcreate: Could not get share " @@ -2095,6 +2097,7 @@ NTSTATUS open_directory(connection_struct *conn, bool dir_existed = VALID_STAT(*psbuf) ? True : False; struct share_mode_lock *lck = NULL; NTSTATUS status; + struct timespec mtimespec; int info = 0; DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, " @@ -2217,9 +2220,11 @@ NTSTATUS open_directory(connection_struct *conn, string_set(&fsp->fsp_name,fname); + mtimespec = get_mtimespec(psbuf); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, conn->connectpath, - fname); + fname, &mtimespec); if (lck == NULL) { DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname)); diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 420aa94..c340954 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -181,7 +181,8 @@ bool remove_oplock(files_struct *fsp) struct share_mode_lock *lck; /* Remove the oplock flag from the sharemode. */ - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0,("remove_oplock: failed to lock share entry for " "file %s\n", fsp->fsp_name )); @@ -206,7 +207,8 @@ bool downgrade_oplock(files_struct *fsp) bool ret; struct share_mode_lock *lck; - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0,("downgrade_oplock: failed to lock share entry for " "file %s\n", fsp->fsp_name )); @@ -757,7 +759,8 @@ void release_level_2_oplocks_on_change(files_struct *fsp) if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) return; - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0,("release_level_2_oplocks_on_change: failed to lock " "share mode entry for file %s.\n", fsp->fsp_name )); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 91d5f25..911ee47 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; @@ -4239,6 +4245,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 +4258,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 +4332,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. @@ -5515,7 +5521,8 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); /* * We have the file open ourselves, so not being able to get the @@ -6077,7 +6084,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 @@ -6960,6 +6967,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); @@ -6995,23 +7004,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 d7a0f6e..03402f2 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; @@ -6431,7 +6441,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, * non-POSIX opens return SHARING_VIOLATION. */ - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL); + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0, ("smb_posix_unlink: Could not get share mode " "lock for file %s\n", fsp->fsp_name)); @@ -6657,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: -- 1.5.4 From ec5ebdd0bfa23aa6efd351347975f9e618bd9814 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 12 Mar 2008 08:14:31 +0100 Subject: [PATCH] get_write_time: fallback to the old_write_time metze Signed-off-by: Stefan Metzmacher --- source/locking/locking.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/source/locking/locking.c b/source/locking/locking.c index 1220245..93e8016 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -952,6 +952,11 @@ struct timespec get_write_time(struct file_id id) return result; } result = lck->changed_write_time; + + if (null_timespec(result)) { + result = lck->old_write_time; + } + TALLOC_FREE(lck); return result; } -- 1.5.4 From 625b16e9efc768b61fcb9e6ed0104edcc163919c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 12 Mar 2008 08:49:26 +0100 Subject: [PATCH] smbd: trigger a write time update on a write metze Signed-off-by: Stefan Metzmacher --- source/smbd/fileio.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index 21bfe00..93a303f 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -244,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)) { -- 1.5.4 From 208afc1ed1585868db557f76dca944de0aa6421f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 12 Mar 2008 09:14:56 +0100 Subject: [PATCH] smbd: if the write time was set, we need to reset it on close metze Signed-off-by: Stefan Metzmacher --- source/smbd/close.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/source/smbd/close.c b/source/smbd/close.c index 5242956..904e5d7 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)); -- 1.5.4 From c0f25ff5ba66a6ce4b35f57c40892d975fafd0b4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 12 Mar 2008 09:49:32 +0100 Subject: [PATCH] smbd: smb_set_file_time() should used instead of file_ntimes() metze Signed-off-by: Stefan Metzmacher --- source/smbd/reply.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 911ee47..a5f3a18 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1991,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); -- 1.5.4 From 2c8a4b75fcf237e29c61a7aafb91b31bb7123b5d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 5 Nov 2007 16:58:17 +0100 Subject: [PATCH] hack to fix make test together --with-fhs metze Signed-off-by: Stefan Metzmacher --- source/dynconfig.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/dynconfig.c b/source/dynconfig.c index 57008ec..f73148e 100644 --- a/source/dynconfig.c +++ b/source/dynconfig.c @@ -302,7 +302,7 @@ const char *set_dyn_PRIVATE_DIR(const char *newpath) const char *get_dyn_STATEDIR(void) { -#ifdef FHS_COMPATIBLE +#if 0//def FHS_COMPATIBLE return STATEDIR; #else return lp_lockdir(); @@ -311,7 +311,7 @@ const char *get_dyn_STATEDIR(void) const char *get_dyn_CACHEDIR(void) { -#ifdef FHS_COMPATIBLE +#if 0 //def FHS_COMPATIBLE return CACHEDIR; #else return lp_lockdir(); -- 1.5.4