Make filetime test cases work on Windows

This commit is contained in:
Sebastian Messmer 2018-09-03 09:23:11 -07:00
parent 2348396ad9
commit 873c51962f
7 changed files with 192 additions and 12 deletions

View File

@ -47,6 +47,8 @@ set(SOURCES
system/memory_windows.cpp
system/time.cpp
system/diskspace.cpp
system/filetime_nonwindows.cpp
system/filetime_windows.cpp
value_type/ValueType.cpp
)

View File

@ -0,0 +1,13 @@
#pragma once
#ifndef MESSMER_CPPUTILS_SYSTEM_FILETIME_H
#include <ctime>
namespace cpputils {
int set_filetime(const char *filepath, timespec lastAccessTime, timespec lastModificationTime);
int get_filetime(const char *filepath, timespec* lastAccessTime, timespec* lastModificationTime);
}
#endif

View File

@ -0,0 +1,36 @@
#if !defined(_MSC_VER)
#include "filetime.h"
#include <utime.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <errno.h>
namespace cpputils {
int set_filetime(const char *filepath, timespec lastAccessTime, timespec lastModificationTime) {
struct timeval casted_times[2];
TIMESPEC_TO_TIMEVAL(&casted_times[0], &lastAccessTime);
TIMESPEC_TO_TIMEVAL(&casted_times[1], &lastModificationTime);
int retval = ::utimes(filepath, casted_times);
if (0 == retval) {
return 0;
} else {
return errno;
}
}
int get_filetime(const char *filepath, timespec* lastAccessTime, timespec* lastModificationTime) {
struct ::stat attrib;
int retval = ::stat(filepath, &attrib);
if (retval != 0) {
return errno;
}
*lastAccessTime = attrib.st_atim;
*lastModificationTime = attrib.st_mtim;
return 0;
}
}
#endif

View File

@ -0,0 +1,113 @@
#if defined(_MSC_VER)
#include "filetime.h"
#include <Windows.h>
#include <stdexcept>
namespace cpputils {
namespace {
FILETIME to_filetime(timespec value) {
ULARGE_INTEGER ull;
ull.QuadPart = (value.tv_sec * 10000000ULL) + 116444736000000000ULL + (value.tv_nsec / 100);
FILETIME result;
result.dwLowDateTime = ull.LowPart;
result.dwHighDateTime = ull.HighPart;
return result;
}
timespec to_timespec(FILETIME value) {
// function taken from https://github.com/wishstudio/flinux/blob/afbb7d7509d4f1e0fdd62bf02124e7c4ce20ca6d/src/datetime.c under GPLv3
constexpr uint64_t NANOSECONDS_PER_TICK = 100ULL;
constexpr uint64_t NANOSECONDS_PER_SECOND = 1000000000ULL;
constexpr uint64_t TICKS_PER_SECOND = 10000000ULL;
constexpr uint64_t SEC_TO_UNIX_EPOCH = 11644473600ULL;
constexpr uint64_t TICKS_TO_UNIX_EPOCH = TICKS_PER_SECOND * SEC_TO_UNIX_EPOCH;
uint64_t ticks = ((uint64_t)value.dwHighDateTime << 32ULL) + value.dwLowDateTime;
uint64_t nsec = 0;
if (ticks >= TICKS_TO_UNIX_EPOCH) { // otherwise out of range
ticks -= TICKS_TO_UNIX_EPOCH;
nsec = ticks * NANOSECONDS_PER_TICK;
}
timespec result;
result.tv_sec = nsec / NANOSECONDS_PER_SECOND;
result.tv_nsec = nsec % NANOSECONDS_PER_SECOND;
return result;
}
struct OpenFileRAII final {
HANDLE handle;
OpenFileRAII(const char* filepath, DWORD access)
:handle(CreateFileA(filepath, access, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)) {
}
BOOL close() {
if (INVALID_HANDLE_VALUE == handle) {
return 1;
}
BOOL success = CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
return success;
}
~OpenFileRAII() {
close();
}
};
}
int set_filetime(const char *filepath, timespec lastAccessTime, timespec lastModificationTime) {
OpenFileRAII file(filepath, FILE_WRITE_ATTRIBUTES);
if (INVALID_HANDLE_VALUE == file.handle) {
return GetLastError();
}
FILETIME atime = to_filetime(lastAccessTime);
FILETIME mtime = to_filetime(lastModificationTime);
BOOL success = SetFileTime(file.handle, nullptr, &atime, &mtime);
if (!success) {
return GetLastError();
}
success = file.close();
if (!success) {
return GetLastError();
}
return 0;
}
int get_filetime(const char *filepath, timespec* lastAccessTime, timespec* lastModificationTime) {
OpenFileRAII file(filepath, FILE_READ_ATTRIBUTES);
if (INVALID_HANDLE_VALUE == file.handle) {
return GetLastError();
}
FILETIME atime;
FILETIME mtime;
BOOL success = GetFileTime(file.handle, nullptr, &atime, &mtime);
if (!success) {
return GetLastError();
}
success = file.close();
if (!success) {
return GetLastError();
}
*lastAccessTime = to_timespec(atime);
*lastModificationTime = to_timespec(mtime);
return 0;
}
}
#endif

View File

@ -48,6 +48,7 @@ set(SOURCES
assert/assert_debug_test.cpp
system/GetTotalMemoryTest.cpp
system/TimeTest.cpp
system/FiletimeTest.cpp
system/MemoryTest.cpp
system/HomedirTest.cpp
value_type/ValueTypeTest.cpp

View File

@ -0,0 +1,25 @@
#include <gtest/gtest.h>
#include <cpp-utils/system/filetime.h>
#include <cpp-utils/tempfile/TempFile.h>
using cpputils::TempFile;
using cpputils::set_filetime;
using cpputils::get_filetime;
TEST(FiletimeTest, SetAndGetTime_ReturnsCorrectTime) {
TempFile file;
struct timespec accessTime { 1535965242, 12345000 };
struct timespec modificationTime { 1435965242, 98765000 };
int retval = set_filetime(file.path().string().c_str(), accessTime, modificationTime);
EXPECT_EQ(0, retval);
struct timespec readAccessTime;
struct timespec readModificationTime;
retval = get_filetime(file.path().string().c_str(), &readAccessTime, &readModificationTime);
EXPECT_EQ(0, retval);
EXPECT_EQ(accessTime.tv_sec, readAccessTime.tv_sec);
EXPECT_EQ(accessTime.tv_nsec, readAccessTime.tv_nsec);
EXPECT_EQ(modificationTime.tv_sec, readModificationTime.tv_sec);
EXPECT_EQ(modificationTime.tv_nsec, readModificationTime.tv_nsec);
}

View File

@ -1,7 +1,5 @@
#include "FuseUtimensTest.h"
#include <utime.h>
#include <sys/time.h>
#include <cpp-utils/system/filetime.h>
void FuseUtimensTest::Utimens(const char *filename, timespec lastAccessTime, timespec lastModificationTime) {
int error = UtimensReturnError(filename, lastAccessTime, lastModificationTime);
@ -13,15 +11,7 @@ int FuseUtimensTest::UtimensReturnError(const char *filename, timespec lastAcces
auto realpath = fs->mountDir() / filename;
struct timeval casted_times[2];
TIMESPEC_TO_TIMEVAL(&casted_times[0], &lastAccessTime);
TIMESPEC_TO_TIMEVAL(&casted_times[1], &lastModificationTime);
int retval = ::utimes(realpath.string().c_str(), casted_times);
if (0 == retval) {
return 0;
} else {
return errno;
}
return cpputils::set_filetime(realpath.string().c_str(), lastAccessTime, lastModificationTime);
}
struct timespec FuseUtimensTest::makeTimespec(time_t tv_sec, long tv_nsec) {