enh(File): Linux, macOS: microsecond precision for file times (create and modification time).

This commit is contained in:
Matej Kenda 2024-01-29 19:06:06 +01:00
parent d5a5ebc2d7
commit 6456d03df7
3 changed files with 40 additions and 15 deletions

View File

@ -135,7 +135,7 @@ public:
/// (100 nanosecond intervals since midnight, /// (100 nanosecond intervals since midnight,
/// October 15, 1582). /// October 15, 1582).
static TimeDiff resolution(); static constexpr TimeDiff resolution();
/// Returns the resolution in units per second. /// Returns the resolution in units per second.
/// Since the timestamp has microsecond resolution, /// Since the timestamp has microsecond resolution,
/// the returned value is always 1000000. /// the returned value is always 1000000.
@ -254,7 +254,7 @@ inline bool Timestamp::isElapsed(Timestamp::TimeDiff interval) const
} }
inline Timestamp::TimeDiff Timestamp::resolution() inline constexpr Timestamp::TimeDiff Timestamp::resolution()
{ {
return 1000000; return 1000000;
} }

View File

@ -212,15 +212,24 @@ Timestamp FileImpl::createdImpl() const
{ {
poco_assert (!_path.empty()); poco_assert (!_path.empty());
using TV = Timestamp::TimeVal;
// Nanosecond to timestamp resolution factor
static constexpr TV nsk = 1'000'000'000ll / Timestamp::resolution();
struct stat st;
if (::stat(_path.c_str(), &st) == 0)
{
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(_DARWIN_FEATURE_64_BIT_INODE)) #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(_DARWIN_FEATURE_64_BIT_INODE))
struct stat st; const TV tv = static_cast<TV>(st.st_birthtimespec.tv_sec) * Timestamp::resolution() + st.st_birthtimespec.tv_nsec/nsk;
if (stat(_path.c_str(), &st) == 0) return Timestamp(tv);
return Timestamp::fromEpochTime(st.st_birthtime); #elif POCO_OS == POCO_OS_LINUX
const TV tv = static_cast<TV>(st.st_ctim.tv_sec) * Timestamp::resolution() + st.st_ctim.tv_nsec/nsk;
return Timestamp(tv);
#else #else
struct stat st;
if (stat(_path.c_str(), &st) == 0)
return Timestamp::fromEpochTime(st.st_ctime); return Timestamp::fromEpochTime(st.st_ctime);
#endif #endif
}
else else
handleLastErrorImpl(_path); handleLastErrorImpl(_path);
return 0; return 0;
@ -231,9 +240,24 @@ Timestamp FileImpl::getLastModifiedImpl() const
{ {
poco_assert (!_path.empty()); poco_assert (!_path.empty());
using TV = Timestamp::TimeVal;
// Nanosecond to timestamp resolution factor
static constexpr TV nsk = 1'000'000'000ll / Timestamp::resolution();
struct stat st; struct stat st;
if (stat(_path.c_str(), &st) == 0) if (::stat(_path.c_str(), &st) == 0)
{
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(_DARWIN_FEATURE_64_BIT_INODE))
const TV tv = static_cast<TV>(st.st_mtimespec.tv_sec) * Timestamp::resolution() + st.st_mtimespec.tv_nsec/nsk;
return Timestamp(tv);
#elif POCO_OS == POCO_OS_LINUX
const TV tv = static_cast<TV>(st.st_mtim.tv_sec) * Timestamp::resolution() + st.st_mtim.tv_nsec/nsk;
return Timestamp(tv);
#else
return Timestamp::fromEpochTime(st.st_mtime); return Timestamp::fromEpochTime(st.st_mtime);
#endif
}
else else
handleLastErrorImpl(_path); handleLastErrorImpl(_path);
return 0; return 0;
@ -244,10 +268,11 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts)
{ {
poco_assert (!_path.empty()); poco_assert (!_path.empty());
struct utimbuf tb; const ::time_t s = ts.epochTime();
tb.actime = ts.epochTime(); const ::suseconds_t us = ts.epochMicroseconds() % 1'000'000;
tb.modtime = ts.epochTime(); const ::timeval times[2] = { {s, us}, {s, us} };
if (utime(_path.c_str(), &tb) != 0)
if (::utimes(_path.c_str(), times) != 0)
handleLastErrorImpl(_path); handleLastErrorImpl(_path);
} }

View File

@ -443,7 +443,7 @@ void GlobTest::testGlob()
files.clear(); files.clear();
Glob::glob("globtest/*/", files); Glob::glob("globtest/*/", files);
translatePaths(files); translatePaths(files);
assertTrue (files.size() == 3); assertEqual (3, files.size());
assertTrue (files.find("globtest/include/") != files.end()); assertTrue (files.find("globtest/include/") != files.end());
assertTrue (files.find("globtest/src/") != files.end()); assertTrue (files.find("globtest/src/") != files.end());
assertTrue (files.find("globtest/testsuite/") != files.end()); assertTrue (files.find("globtest/testsuite/") != files.end());
@ -451,7 +451,7 @@ void GlobTest::testGlob()
files.clear(); files.clear();
Glob::glob("globtest/testsuite/src/*", "globtest/testsuite/", files); Glob::glob("globtest/testsuite/src/*", "globtest/testsuite/", files);
translatePaths(files); translatePaths(files);
assertTrue (files.size() == 3); assertEqual (3, files.size());
assertTrue (files.find("globtest/testsuite/src/test.h") != files.end()); assertTrue (files.find("globtest/testsuite/src/test.h") != files.end());
assertTrue (files.find("globtest/testsuite/src/test.c") != files.end()); assertTrue (files.find("globtest/testsuite/src/test.c") != files.end());
assertTrue (files.find("globtest/testsuite/src/main.c") != files.end()); assertTrue (files.find("globtest/testsuite/src/main.c") != files.end());
@ -460,7 +460,7 @@ void GlobTest::testGlob()
files.clear(); files.clear();
Glob::glob("globtest/../*/testsuite/*/", files); Glob::glob("globtest/../*/testsuite/*/", files);
translatePaths(files); translatePaths(files);
assertTrue (files.size() == 1); assertEqual (1, files.size());
File dir("globtest"); File dir("globtest");
dir.remove(true); dir.remove(true);