locking: store the write time in the locking.tdb
authorStefan Metzmacher <metze@samba.org>
Wed, 12 Mar 2008 14:32:47 +0000 (15:32 +0100)
committerStefan Metzmacher <metze@samba.org>
Mon, 7 Apr 2008 10:29:25 +0000 (12:29 +0200)
This is needed to implement the strange write time update
logic later. We need to store 2 time timestamps to
distinguish between the time the file system had before
the first client opened the file and a forced timestamp update.

metze
(This used to be commit 6aaa2ce0eeb46f6735ec984a2e7aadde7a7f456d)

source3/include/smb.h
source3/locking/locking.c
source3/smbd/close.c
source3/smbd/open.c
source3/smbd/oplock.c
source3/smbd/reply.c
source3/smbd/trans2.c

index 4d18dc594fcef59576c073cbad7d6386e786d03a..73695da7f033a6db76cc195d9da2b6b422cf0a1e 100644 (file)
@@ -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. */
index 782e10fb7cd9ea73f6b095a32ca493bc9bae1d45..8d8c0347a5682c6212a2f14f77bb428e210dd6d5 100644 (file)
@@ -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,
index b06c0d1e9c98795d4e7186e731bffb784ab3b5f3..8a5c82cc937261ece6070b5551d997f7219f6a1a 100644 (file)
@@ -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));
index 0cc48c4f1c36842633b87424be38a6669f25b68f..f3ed234c87eb4c923d6c3c7b52f383ea01fc38f7 100644 (file)
@@ -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));
index 420aa94fe6998eeb5ccdb1ec36d33d901954deb5..c3409547fe02c0636d725fbaf1d29008f1d8a952 100644 (file)
@@ -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 ));
index 972f30dbbd0caa4504e98991e90e923e2ba9f75f..b300c09f4f8584d1bc2c7c68c11b44271136d018 100644 (file)
@@ -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
index d7a0f6eff85b40a81e9fe07b2148c78476cb9b89..308ba271b8bd92df8eaf8f5b9087ac28fb58131c 100644 (file)
@@ -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));