diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a835c5..daa1b57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ option(DEBUG_EXTRA "Expensive debug options" OFF) option(SET_WARNING_FLAGS "Adjust compiler warning flags" ON) option(SET_OPTIMIZATION_FLAGS "Adjust compiler optimization flags" ON) option(USE_CXX11 "Try to use C++11 if available" ON) +option(USE_DYNAMIC_UTIMENSAT "Dynamically load utimensat if not available at compile time" OFF) if(NOT DEFINED DEBUG AND CMAKE_BUILD_TYPE STREQUAL "Debug") set(DEBUG 1) endif() @@ -210,11 +211,25 @@ if(NOT WIN32) check_symbol_exists(ioctl "sys/ioctl.h" INNOEXTRACT_HAVE_IOCTL) check_symbol_exists(timegm "time.h" INNOEXTRACT_HAVE_TIMEGM) check_symbol_exists(gmtime_r "time.h" INNOEXTRACT_HAVE_GMTIME_R) - check_symbol_exists(utimensat "sys/stat.h" INNOEXTRACT_HAVE_UTIMENSAT) check_symbol_exists(AT_FDCWD "fcntl.h" INNOEXTRACT_HAVE_AT_FDCWD) + if(INNOEXTRACT_HAVE_AT_FDCWD) + check_symbol_exists(utimensat "sys/stat.h" INNOEXTRACT_HAVE_UTIMENSAT) + endif() if(INNOEXTRACT_HAVE_UTIMENSAT AND INNOEXTRACT_HAVE_AT_FDCWD) set(INNOEXTRACT_HAVE_UTIMENSAT_d 1) else() + if(USE_DYNAMIC_UTIMENSAT AND INNOEXTRACT_HAVE_AT_FDCWD) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS}) + check_symbol_exists(dlsym "dlfcn.h" INNOEXTRACT_HAVE_DLSYM) + check_symbol_exists(RTLD_DEFAULT "dlfcn.h" INNOEXTRACT_HAVE_RTLD_DEFAULT) + unset(CMAKE_REQUIRED_LIBRARIES) + if(INNOEXTRACT_HAVE_DLSYM AND INNOEXTRACT_HAVE_RTLD_DEFAULT) + set(INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT 1) + if(CMAKE_DL_LIBS) + list(APPEND LIBRARIES ${CMAKE_DL_LIBS}) + endif() + endif() + endif() check_symbol_exists(utimes "sys/time.h" INNOEXTRACT_HAVE_UTIMES) endif() @@ -407,11 +422,15 @@ print_configuration("LZMA decompression" FIRST INNOEXTRACT_HAVE_LZMA "enabled" 1 "disabled" ) +if(INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT) + set(time_prefix "nanoseconds if supported, ") + set(time_suffix " otherwise") +endif() print_configuration("File time precision" FIRST INNOEXTRACT_HAVE_UTIMENSAT_d "nanoseconds" WIN32 "100-nanoseconds" - INNOEXTRACT_HAVE_UTIMES "microseconds" - 1 "seconds" + INNOEXTRACT_HAVE_UTIMES "${time_prefix}microseconds${time_suffix}" + 1 "${time_prefix}seconds${time_suffix}" ) print_configuration("Charset conversion" INNOEXTRACT_HAVE_ICONV "iconv" diff --git a/README.md b/README.md index 0569d1d..c7a9cc0 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Build options: | `SET_WARNING_FLAGS` | `ON` | Adjust compiler warning flags. This should not affect the produced binaries but is useful to catch potential problems. | `SET_OPTIMIZATION_FLAGS` | `ON` | Adjust compiler optimization flags. For non-debug builds the only thing this does is instruct the linker to only link against libraries that are actually needed. | `USE_CXX11` | `ON` | Try to compile in C++11 mode if available. +| `USE_DYNAMIC_UTIMENSAT` | `OFF` | Dynamically load utimensat(2) if not available at compile time | `USE_STATIC_LIBS` | `OFF`^3 | Turns on static linking for all libraries, including `-static-libgcc` and `-static-libstdc++`. You can also use the individual options below: | `LZMA_USE_STATIC_LIBS` | `OFF`^4 | Statically link `liblzma`. | `Boost_USE_STATIC_LIBS` | `OFF`^4 | Statically link Boost. See also `FindBoost.cmake` diff --git a/src/configure.hpp.in b/src/configure.hpp.in index 8aa60d3..f7952aa 100644 --- a/src/configure.hpp.in +++ b/src/configure.hpp.in @@ -12,9 +12,13 @@ // File functions #cmakedefine01 INNOEXTRACT_HAVE_UTIMENSAT +#cmakedefine01 INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT #cmakedefine01 INNOEXTRACT_HAVE_AT_FDCWD #cmakedefine01 INNOEXTRACT_HAVE_UTIMES +// Shared functions +#cmakedefine01 INNOEXTRACT_HAVE_DLSYM + // Endianness #cmakedefine01 INNOEXTRACT_HAVE_BUILTIN_BSWAP16 #cmakedefine01 INNOEXTRACT_HAVE_BUILTIN_BSWAP32 diff --git a/src/util/time.cpp b/src/util/time.cpp index 16432fc..9cc14ef 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -32,9 +32,16 @@ #include #endif +#if INNOEXTRACT_HAVE_DLSYM +#include +#endif + +#if INNOEXTRACT_HAVE_AT_FDCWD +#include +#endif + #if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD #include -#include #elif !defined(_WIN32) && INNOEXTRACT_HAVE_UTIMES #include #elif !defined(_WIN32) @@ -246,18 +253,37 @@ static HANDLE open_file(LPCWSTR name) { #endif +#if INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT +extern "C" typedef int (*utimensat_proc) + (int fd, const char *path, const struct timespec times[2], int flag); +#endif + bool set_file_time(const boost::filesystem::path & path, time t, boost::uint32_t nsec) { -#if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD +#if (INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT || INNOEXTRACT_HAVE_UTIMENSAT) \ + && INNOEXTRACT_HAVE_AT_FDCWD // nanosecond precision, for Linux and POSIX.1-2008+ systems - struct timespec times[2]; - times[0].tv_sec = to_time_t(t, path.string().c_str()); - times[0].tv_nsec = boost::int32_t(nsec); - times[1] = times[0]; + struct timespec timens[2]; + timens[0].tv_sec = to_time_t(t, path.string().c_str()); + timens[0].tv_nsec = boost::int32_t(nsec); + timens[1] = timens[0]; + +#endif + +#if INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD + + static utimensat_proc utimensat_func = (utimensat_proc)dlsym(RTLD_DEFAULT, "utimensat"); + if(utimensat_func) { + return (utimensat_func(AT_FDCWD, path.string().c_str(), timens, 0) == 0); + } + +#endif + +#if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD - return (utimensat(AT_FDCWD, path.string().c_str(), times, 0) == 0); + return (utimensat(AT_FDCWD, path.string().c_str(), timens, 0) == 0); #elif defined(_WIN32)