Просмотр исходного кода

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

Matej Kenda 2 лет назад
Родитель
Сommit
6456d03df7

+ 2 - 2
Foundation/include/Poco/Timestamp.h

@@ -135,7 +135,7 @@ public:
 		/// (100 nanosecond intervals since midnight,
 		/// October 15, 1582).
 
-	static TimeDiff resolution();
+	static constexpr TimeDiff resolution();
 		/// Returns the resolution in units per second.
 		/// Since the timestamp has microsecond resolution,
 		/// 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;
 }

+ 35 - 10
Foundation/src/File_UNIX.cpp

@@ -212,15 +212,24 @@ Timestamp FileImpl::createdImpl() const
 {
 	poco_assert (!_path.empty());
 
-#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(_DARWIN_FEATURE_64_BIT_INODE))
+	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)
-		return Timestamp::fromEpochTime(st.st_birthtime);
+	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_birthtimespec.tv_sec) * Timestamp::resolution() + st.st_birthtimespec.tv_nsec/nsk;
+		return Timestamp(tv);
+#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
-	struct stat st;
-	if (stat(_path.c_str(), &st) == 0)
 		return Timestamp::fromEpochTime(st.st_ctime);
 #endif
+	}
 	else
 		handleLastErrorImpl(_path);
 	return 0;
@@ -231,9 +240,24 @@ Timestamp FileImpl::getLastModifiedImpl() const
 {
 	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 (::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);
+#endif
+	}
 	else
 		handleLastErrorImpl(_path);
 	return 0;
@@ -244,10 +268,11 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts)
 {
 	poco_assert (!_path.empty());
 
-	struct utimbuf tb;
-	tb.actime  = ts.epochTime();
-	tb.modtime = ts.epochTime();
-	if (utime(_path.c_str(), &tb) != 0)
+	const ::time_t s = ts.epochTime();
+	const ::suseconds_t us = ts.epochMicroseconds() % 1'000'000;
+	const ::timeval times[2] = { {s, us}, {s, us} };
+
+	if (::utimes(_path.c_str(), times) != 0)
 		handleLastErrorImpl(_path);
 }
 

+ 3 - 3
Foundation/testsuite/src/GlobTest.cpp

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