From bed0b68b0c386e303df572baf2fd51a23608f03a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Aug 2009 22:32:42 -0700 Subject: [PATCH] Fix bug 6529 - Offline files conflict with Vista and Office 2003 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. Jeremy --- source/include/smb.h | 3 +++ source/lib/time.c | 11 +++++++++++ source/smbd/service.c | 23 +++++++++++++++++++++++ source/smbd/trans2.c | 7 +++++++ 4 files changed, 44 insertions(+), 0 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index dc346d8..08f9139 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -629,6 +629,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 *dirpath; char *connectpath; char *origpath; diff --git a/source/lib/time.c b/source/lib/time.c index 5c4d951..fa5b75b 100644 --- a/source/lib/time.c +++ b/source/lib/time.c @@ -1230,6 +1230,17 @@ int timespec_compare(const struct timespec *ts1, const struct timespec *ts2) } /**************************************************************************** + 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 will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case. diff --git a/source/smbd/service.c b/source/smbd/service.c index 1c8ffbd..cc7e9ec 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -1159,6 +1159,29 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, goto err_root_exit; } + { + struct timespec atime_ts = get_atimespec(&st); + struct timespec ctime_ts = get_ctimespec(&st); + struct timespec mtime_ts = get_mtimespec(&st); + + if (mtime_ts.tv_nsec || + atime_ts.tv_nsec || + ctime_ts.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. + */ + DEBUG(10,("make_connection_snum: hires timestamps " + "available on share %s, directory %s\n", + lp_servicename(snum), + conn->connectpath )); + conn->hires_timestamps_avail = true; + } + } + string_set(&conn->origpath,conn->connectpath); #if SOFTLINK_OPTIMISATION diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 9e675fc..59669bf 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -4906,6 +4906,13 @@ NTSTATUS smb_set_file_time(connection_struct *conn, } } + if (!conn->hires_timestamps_avail) { + /* We can't store sub second timestamps + * on this share. Round to seconds. */ + round_timespec(&ts[0]); + round_timespec(&ts[1]); + } + if (setting_write_time) { /* * This was a Windows setfileinfo on an open file. -- 1.6.0.4