diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/configure.in | 51 | ||||
-rw-r--r-- | source3/smbd/notify_hash.c | 38 |
2 files changed, 85 insertions, 4 deletions
diff --git a/source3/configure.in b/source3/configure.in index d11acd0267..e343a9f54f 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -1196,6 +1196,57 @@ if test x$ac_cv_func_fstat64 = xno ; then fi fi +################################################# +# Check whether struct stat has timestamps with sub-second resolution. +# At least IRIX and Solaris have these. +# +# We check that +# all of st_mtim, st_atim and st_ctim exist +# all of the members are in fact of type struct timespec +# +# There is some conflicting standards weirdness about whether we should use +# "struct timespec" or "timespec_t". Linux doesn't have timespec_t, so we +# prefer struct timespec. + +AC_CACHE_CHECK([whether struct stat has sub-second timestamps], samba_stat_hires, + [ + AC_TRY_COMPILE( + [ +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + ], + [ + struct timespec t; + struct stat s = {0}; + t.tv_sec = s.st_mtim.tv_sec; + t.tv_nsec = s.st_mtim.tv_nsec; + t.tv_sec = s.st_ctim.tv_sec; + t.tv_nsec = s.st_ctim.tv_nsec; + t.tv_sec = s.st_atim.tv_sec; + t.tv_nsec = s.st_atim.tv_nsec; + ], + samba_stat_hires=yes, samba_stat_hires=no) + ]) + +if test x"$samba_stat_hires" = x"yes" ; then + AC_DEFINE(HAVE_STAT_ST_MTIM, 1, [whether struct stat contains st_mtim]) + AC_DEFINE(HAVE_STAT_ST_ATIM, 1, [whether struct stat contains st_atim]) + AC_DEFINE(HAVE_STAT_ST_CTIM, 1, [whether struct stat contains st_ctim]) + AC_DEFINE(HAVE_STAT_HIRES_TIMESTAMPS, 1, + [whether struct stat has sub-second timestamps]) +fi + ##################################### # we might need the resolv library on some systems AC_CHECK_LIB(resolv, dn_expand) diff --git a/source3/smbd/notify_hash.c b/source3/smbd/notify_hash.c index 08eefab652..ee7d4314ee 100644 --- a/source3/smbd/notify_hash.c +++ b/source3/smbd/notify_hash.c @@ -23,14 +23,28 @@ struct change_data { time_t last_check_time; /* time we last checked this entry */ +#ifdef HAVE_STAT_HIRES_TIMESTAMPS + struct timespec modify_time; + struct timespec status_time; +#else time_t modify_time; /* Info from the directory we're monitoring. */ time_t status_time; /* Info from the directory we're monitoring. */ +#endif time_t total_time; /* Total time of all directory entries - don't care if it wraps. */ unsigned int num_entries; /* Zero or the number of files in the directory. */ unsigned int mode_sum; unsigned char name_hash[16]; }; + +#ifdef HAVE_STAT_HIRES_TIMESTAMPS +/* Compare struct timespec. */ +#define TIMESTAMP_NEQ(x, y) (((x).tv_sec != (y).tv_sec) || ((x).tv_nsec != (y).tv_nsec)) +#else +/* Compare time_t . */ +#define TIMESTAMP_NEQ(x, y) ((x) != (y)) +#endif + /**************************************************************************** Create the hash we will use to determine if the contents changed. *****************************************************************************/ @@ -52,20 +66,36 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, if(SMB_VFS_STAT(conn,path, &st) == -1) return False; +#ifdef HAVE_STAT_HIRES_TIMESTAMPS + data->modify_time = st.st_mtim; + data->status_time = st.st_ctim; +#else data->modify_time = st.st_mtime; data->status_time = st.st_ctime; +#endif if (old_data) { /* * Shortcut to avoid directory scan if the time * has changed - we always must return true then. */ - if (old_data->modify_time != data->modify_time || - old_data->status_time != data->status_time ) { + if (TIMESTAMP_NEQ(old_data->modify_time, data->modify_time) || + TIMESTAMP_NEQ(old_data->status_time, data->status_time) ) { return True; } } + if (S_ISDIR(st.st_mode) && + (flags & ~(FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) == 0) + { + /* This is the case of a client wanting to know only when + * the contents of a directory changes. Since any file + * creation, rename or deletion will update the directory + * timestamps, we don't need to create a hash. + */ + return True; + } + /* * If we are to watch for changes that are only stored * in inodes of files, not in the directory inode, we must @@ -176,8 +206,8 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, } if (!notify_hash(conn, path, flags, &data2, data) || - data2.modify_time != data->modify_time || - data2.status_time != data->status_time || + TIMESTAMP_NEQ(data2.modify_time, data->modify_time) || + TIMESTAMP_NEQ(data2.status_time, data->status_time) || data2.total_time != data->total_time || data2.num_entries != data->num_entries || data2.mode_sum != data->mode_sum || |