Browse Source

Add support for nanosecond file times under Linux

Also, for other POSIX.1-2008+ systems.
coverity_scan
Daniel Scharrer 13 years ago
parent
commit
e3014f72d7
  1. 6
      CMakeLists.txt
  2. 2
      src/configure.hpp.in
  3. 79
      src/util/time.cpp
  4. 6
      src/util/time.hpp

6
CMakeLists.txt

@ -130,7 +130,11 @@ if(NOT INNOEXTRACT_HAVE_GMTIME_R)
check_symbol_exists(_gmtime_s "time.h" INNOEXTRACT_HAVE_GMTIME_S)
endif()
if(NOT WIN32)
check_symbol_exists(utimes "sys/time.h" INNOEXTRACT_HAVE_UTIMES)
check_symbol_exists(utimensat "sys/stat.h" INNOEXTRACT_HAVE_UTIMENSAT)
check_symbol_exists(AT_FDCWD "fcntl.h" INNOEXTRACT_HAVE_AT_FDCWD)
if(NOT (INNOEXTRACT_HAVE_UTIMENSAT AND INNOEXTRACT_HAVE_AT_FDCWD))
check_symbol_exists(utimes "sys/time.h" INNOEXTRACT_HAVE_UTIMES)
endif()
endif()
check_symbol_exists(bswap_16 "byteswap.h" INNOEXTRACT_HAVE_BSWAP_16)

2
src/configure.hpp.in

@ -8,6 +8,8 @@
#cmakedefine01 INNOEXTRACT_HAVE_MKGMTIME
#cmakedefine01 INNOEXTRACT_HAVE_GMTIME_R
#cmakedefine01 INNOEXTRACT_HAVE_GMTIME_S
#cmakedefine01 INNOEXTRACT_HAVE_UTIMENSAT
#cmakedefine01 INNOEXTRACT_HAVE_AT_FDCWD
#cmakedefine01 INNOEXTRACT_HAVE_UTIMES
#cmakedefine01 INNOEXTRACT_HAVE_LZMA
#cmakedefine01 INNOEXTRACT_IS_BIG_ENDIAN

79
src/util/time.cpp

@ -33,7 +33,10 @@
#include <windows.h>
#endif
#if INNOEXTRACT_HAVE_UTIMES
#if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD
#include <sys/stat.h>
#include <fcntl.h>
#elif INNOEXTRACT_HAVE_UTIMES
#include <sys/time.h>
#elif !defined(_WIN32)
#include <boost/filesystem/operations.hpp>
@ -46,15 +49,19 @@ static void set_timezone(const char * value) {
const char * variable = "TZ";
#if defined(WIN32)
SetEnvironmentVariable(variable, value);
_tzset();
#else
if(value) {
setenv(variable, value, 1);
} else {
unsetenv(variable);
}
tzset();
#endif
}
@ -65,14 +72,20 @@ std::time_t parse_time(std::tm tm) {
#if INNOEXTRACT_HAVE_TIMEGM
// GNU / BSD extension
return timegm(&tm);
#elif INNOEXTRACT_HAVE_MKGMTIME
// Windows
return _mkgmtime(&tm);
#else
// Standard, but not thread-safe - should be OK for our use though
char * tz = getenv("TZ");
set_timezone("UTC");
@ -93,16 +106,21 @@ std::tm format_time(time_t t) {
#if INNOEXTRACT_HAVE_GMTIME_R
// POSIX.1
gmtime_r(&t, &ret);
#elif INNOEXTRACT_HAVE_GMTIME_S
// Windows (MSVC)
_gmtime_s(&ret, &t);
#else
// Hope that this is threadsafe...
std::tm * tmp = gmtime(&t);
// Standard C++, but may not be thread-safe
std::tm * tmp = std::gmtime(&t);
if(tmp) {
ret = *tmp;
} else {
@ -116,7 +134,7 @@ std::tm format_time(time_t t) {
return ret;
}
time_t to_local_time(time_t t) {
std::time_t to_local_time(std::time_t t) {
// Format time as UTC ...
std::tm time = format_time(t);
@ -126,18 +144,52 @@ time_t to_local_time(time_t t) {
return std::mktime(&time);
}
void set_local_timezone(std::string timezone) {
/*
* The TZ variable interprets the offset as the change from local time
* to UTC while everyone else does the opposite.
* We flip the direction so that timezone strings such as GMT+1 work as expected.
*/
for(size_t i = 0; i < timezone.length(); i++) {
if(timezone[i] == '+') {
timezone[i] = '-';
} else if(timezone[i] == '-') {
timezone[i] = '+';
}
}
set_timezone(timezone.c_str());
}
#if defined(_WIN32)
static HANDLE open_file(LPCSTR name) {
return CreateFileA(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
}
static HANDLE open_file(LPCWSTR name) {
return CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
}
#endif
bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t nsec) {
#if INNOEXTRACT_HAVE_UTIMES
#if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD
// nanosecond precision, for Linux and POSIX.1-2008+ systems
struct timespec times[2];
times[0].tv_sec = t;
times[0].tv_nsec = int32_t(nsec);
times[1] = times[0];
return (utimensat(AT_FDCWD, path.string().c_str(), times, 0) == 0);
#elif INNOEXTRACT_HAVE_UTIMES
// microsecond precision, for older POSIX systems (4.3BSD, POSIX.1-2001)
struct timeval times[2];
@ -149,6 +201,8 @@ bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t
#elif defined(_WIN32)
// 100-nanosecond precision, for Windows
// Prevent unused function warnings
(void)(HANDLE(*)(LPCSTR))open_file;
(void)(HANDLE(*)(LPCWSTR))open_file;
@ -173,6 +227,8 @@ bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t
#else
// fallback with second precision or worse
try {
(void)nsec; // sub-second precision not supported by boost
boost::filesystem::last_write_time(path, t);
@ -185,17 +241,4 @@ bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t
}
void set_local_timezone(std::string timezone) {
for(size_t i = 0; i < timezone.length(); i++) {
if(timezone[i] == '+') {
timezone[i] = '-';
} else if(timezone[i] == '-') {
timezone[i] = '+';
}
}
set_timezone(timezone.c_str());
}
} // namespace util

6
src/util/time.hpp

@ -47,12 +47,12 @@ std::tm format_time(std::time_t t);
*/
std::time_t to_local_time(std::time_t t);
//! Set a file's creation/modification time
bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t nsec);
//! Set the local timezone used by to_local_time
void set_local_timezone(std::string timezone);
//! Set a file's creation/modification time
bool set_file_time(const boost::filesystem::path & path, std::time_t t, uint32_t nsec);
} // namespace util
#endif // INNOEXTRACT_UTIL_TIME_HPP

Loading…
Cancel
Save