Fix bug 6529 - Offline files conflict with Vista and Office 2003
authorJeremy Allison <jra@samba.org>
Sat, 22 Aug 2009 04:44:21 +0000 (21:44 -0700)
committerJeremy Allison <jra@samba.org>
Sat, 22 Aug 2009 04:44:21 +0000 (21:44 -0700)
On filesystems that can't store less than one second timestamps,
round the incoming timestamp set requests so the client can't discover
that a time set request has been truncated by the filesystem.
Needs backporting to 3.4, 3.3, 3.2 and (even) 3.0.
Jeremy

source3/include/proto.h
source3/include/smb.h
source3/lib/time.c
source3/smbd/open.c
source3/smbd/service.c
source3/smbd/trans2.c

index 963e6df0c80f8bc3cb388a7e63c2ba3d51c4d985..1b097326797e3c3670fd5ad0f602b1a7c1c5d870 100644 (file)
@@ -1044,6 +1044,7 @@ struct timespec timespec_current(void);
 struct timespec timespec_min(const struct timespec *ts1,
                           const struct timespec *ts2);
 int timespec_compare(const struct timespec *ts1, const struct timespec *ts2);
+void round_timespec(struct timespec *ts);
 struct timespec interpret_long_date(const char *p);
 void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate);
 void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate);
index 9d1e22b064d41a624915873a8ad9b8963f04f931..1347ab228b6e89bb22df1b0d1d961f5cd6301d00 100644 (file)
@@ -557,6 +557,9 @@ typedef struct connection_struct {
        bool ipc;
        bool read_only; /* Attributes for the current user of the share. */
        bool admin_user; /* Attributes for the current user of the share. */
+       bool hires_timestamps_avail; /* Does this filesystem honor
+                                       sub second timestamps on files
+                                       and directories ? */
        char *connectpath;
        char *origpath;
 
index a2e615acc52fa2a2fef622cacc38317c041738b8..06605cd30a79b16940e0423354d9e993d01dd4aa 100644 (file)
@@ -467,6 +467,17 @@ int timespec_compare(const struct timespec *ts1, const struct timespec *ts2)
        return 0;
 }
 
+/****************************************************************************
+ Round up a timespec if nsec > 500000000, round down if lower,
+ then zero nsec.
+****************************************************************************/
+
+void round_timespec(struct timespec *ts)
+{
+       ts->tv_sec += ts->tv_nsec >= 500000000 ? 1 : 0;
+       ts->tv_nsec = 0;
+}
+
 /****************************************************************************
  Interprets an nt time into a unix struct timespec.
  Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
index 045635535f6da6b2aced9f22b2782b57ef07ef22..9b4eedf4326e9437a840b3a8c24887bacdca31bc 100644 (file)
@@ -3284,8 +3284,12 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
        /* Try and make a create timestamp, if required. */
        if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
                if (lp_store_create_time(SNUM(conn))) {
+                       struct timespec ts = smb_fname->st.st_ex_btime;
+                       if (!conn->hires_timestamps_avail) {
+                               round_timespec(&ts);
+                       }
                        set_create_timespec_ea(conn, fsp,
-                               smb_fname, smb_fname->st.st_ex_btime);
+                               smb_fname, ts);
                }
        }
 
index fc56105adf8a92b71f60e5fb4462cbd35ff26228..6254d752a15feb4fe1aa1b1968c5325e8f64fb40 100644 (file)
@@ -1015,6 +1015,19 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
                goto err_root_exit;
        }
 
+       if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
+                       smb_fname_cpath->st.st_ex_atime.tv_nsec ||
+                       smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
+               /* If any of the normal UNIX directory timestamps
+                * have a non-zero tv_nsec component assume
+                * we can fully store hires timestamps. We need
+                * to make a runtime/share level distinction
+                * as on Linux ext3 doesn't have hires timestamps, but
+                * ext4 does, so a compile time test won't work. JRA.
+                */
+               conn->hires_timestamps_avail = true;
+       }
+
        string_set(&conn->origpath,conn->connectpath);
 
 #if SOFTLINK_OPTIMISATION
index 56651b44ec5687057d837cfd10aabc2a267ab2aa..2900e764e8ad484e0df714550f067941525e1dcc 100644 (file)
@@ -5402,6 +5402,15 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
                action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
        }
 
+       if (!conn->hires_timestamps_avail) {
+               /* We can't store sub second timestamps
+                * on this share. Round to seconds. */
+               round_timespec(&ft->create_time);
+               round_timespec(&ft->ctime);
+               round_timespec(&ft->atime);
+               round_timespec(&ft->mtime);
+       }
+
        DEBUG(5,("smb_set_filetime: actime: %s\n ",
                time_to_asc(convert_timespec_to_time_t(ft->atime))));
        DEBUG(5,("smb_set_filetime: modtime: %s\n ",