diff options
-rw-r--r-- | source3/include/smb.h | 4 | ||||
-rw-r--r-- | source3/locking/locking.c | 96 | ||||
-rw-r--r-- | source3/smbd/close.c | 6 | ||||
-rw-r--r-- | source3/smbd/open.c | 15 | ||||
-rw-r--r-- | source3/smbd/oplock.c | 9 | ||||
-rw-r--r-- | source3/smbd/reply.c | 3 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 3 |
7 files changed, 110 insertions, 26 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index 4d18dc594f..73695da7f0 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -811,6 +811,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 +828,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/source3/locking/locking.c b/source3/locking/locking.c index 782e10fb7c..8d8c0347a5 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -503,12 +503,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", @@ -659,11 +667,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) + @@ -739,7 +756,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. */ @@ -751,13 +769,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); @@ -766,6 +787,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")); @@ -779,7 +801,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; @@ -797,7 +820,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; @@ -829,7 +852,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; @@ -917,6 +940,26 @@ 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; + + if (null_timespec(result)) { + result = lck->old_write_time; + } + + TALLOC_FREE(lck); + return result; +} + bool get_delete_on_close_flag(struct file_id id) { bool result; @@ -1321,7 +1364,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; } @@ -1361,6 +1405,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/source3/smbd/close.c b/source3/smbd/close.c index b06c0d1e9c..8a5c82cc93 100644 --- a/source3/smbd/close.c +++ b/source3/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 " @@ -535,7 +536,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/source3/smbd/open.c b/source3/smbd/open.c index 0cc48c4f1c..f3ed234c87 100644 --- a/source3/smbd/open.c +++ b/source3/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/source3/smbd/oplock.c b/source3/smbd/oplock.c index 420aa94fe6..c3409547fe 100644 --- a/source3/smbd/oplock.c +++ b/source3/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/source3/smbd/reply.c b/source3/smbd/reply.c index 972f30dbbd..b300c09f4f 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -5515,7 +5515,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 diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index d7a0f6eff8..308ba271b8 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -6431,7 +6431,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)); |