summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h4
-rw-r--r--source3/locking/locking.c96
-rw-r--r--source3/smbd/close.c6
-rw-r--r--source3/smbd/open.c15
-rw-r--r--source3/smbd/oplock.c9
-rw-r--r--source3/smbd/reply.c3
-rw-r--r--source3/smbd/trans2.c3
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));