From 3e8da9bb1ae70b554374888ec2e9ba3aab390102 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Fri, 12 Jan 2018 22:40:15 -0800 Subject: [PATCH] Return back checking file for sparseness. Use lseek(SEEK_HOLE) if supported by the system, otherwise fallback to block check. This allows to workaround bugs with SMB client and not introduce new bugs for filesystems with compression and deduplication. This has theoretical bug if our collection spans different filesystems and some filesystems support holes, and some not. If this ever encountered we should use pathconf(2) and cache its result for directories. --- configure.ac | 1 + monitor.c | 34 +++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 8eb55c9..1410a94 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,7 @@ AC_C_BIGENDIAN AC_FUNC_FORK AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_CHECK_FUNCS([gethostname getifaddrs gettimeofday inet_ntoa memmove memset mkdir realpath select sendfile setlocale socket strcasecmp strchr strdup strerror strncasecmp strpbrk strrchr strstr strtol strtoul]) +AC_CHECK_DECLS([SEEK_HOLE]) # # Check for struct ip_mreqn diff --git a/monitor.c b/monitor.c index d93b871..dcda631 100644 --- a/monitor.c +++ b/monitor.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -471,6 +472,30 @@ monitor_insert_file(const char *name, const char *path) return depth; } +static bool +check_notsparse(const char *path) +#if HAVE_DECL_SEEK_HOLE +{ + int fd; + bool rv; + + if ((fd = open(path, O_RDONLY)) == -1) + return (false); + if (lseek(fd, 0, SEEK_HOLE) == lseek(fd, 0, SEEK_END)) + rv = true; + else + rv = false; + close(fd); + return (rv); +} +#else +{ + struct stat st; + + return (stat(path, &st) == 0 && (st.st_blocks << 9 >= st.st_size)); +} +#endif + int monitor_insert_directory(int fd, char *name, const char * path) { @@ -480,7 +505,6 @@ monitor_insert_directory(int fd, char *name, const char * path) char path_buf[PATH_MAX]; enum file_types type = TYPE_UNKNOWN; media_types dir_types; - struct stat st; if( access(path, R_OK|X_OK) != 0 ) { @@ -538,12 +562,8 @@ monitor_insert_directory(int fd, char *name, const char * path) { monitor_insert_directory(fd, esc_name, path_buf); } - else if( type == TYPE_FILE ) - { - if( (stat(path_buf, &st) == 0) ) - { - monitor_insert_file(esc_name, path_buf); - } + else if( type == TYPE_FILE && check_notsparse(path_buf)) { + monitor_insert_file(esc_name, path_buf); } free(esc_name); }