diff options
author | Jeremy Allison <jra@samba.org> | 2009-08-21 21:44:21 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2009-08-21 21:44:21 -0700 |
commit | 1af0aa92b3f3467715f6ffbfedf66df1acc0a83c (patch) | |
tree | a151ed8cc04a4bea659b8d11484a197ca3b74b2c /source3 | |
parent | 47c7063dc62dc06d0cdd50e1946c088f8bf1ee1d (diff) | |
download | samba-1af0aa92b3f3467715f6ffbfedf66df1acc0a83c.tar.gz samba-1af0aa92b3f3467715f6ffbfedf66df1acc0a83c.tar.bz2 samba-1af0aa92b3f3467715f6ffbfedf66df1acc0a83c.zip |
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.
Needs backporting to 3.4, 3.3, 3.2 and (even) 3.0.
Jeremy
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/proto.h | 1 | ||||
-rw-r--r-- | source3/include/smb.h | 3 | ||||
-rw-r--r-- | source3/lib/time.c | 11 | ||||
-rw-r--r-- | source3/smbd/open.c | 6 | ||||
-rw-r--r-- | source3/smbd/service.c | 13 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 9 |
6 files changed, 42 insertions, 1 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 963e6df0c8..1b09732679 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -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); diff --git a/source3/include/smb.h b/source3/include/smb.h index 9d1e22b064..1347ab228b 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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; diff --git a/source3/lib/time.c b/source3/lib/time.c index a2e615acc5..06605cd30a 100644 --- a/source3/lib/time.c +++ b/source3/lib/time.c @@ -468,6 +468,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/source3/smbd/open.c b/source3/smbd/open.c index 045635535f..9b4eedf432 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -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); } } diff --git a/source3/smbd/service.c b/source3/smbd/service.c index fc56105adf..6254d752a1 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -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 diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 56651b44ec..2900e764e8 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -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 ", |