aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsath <sath@yandex-team.com>2024-05-13 12:52:23 +0300
committersath <sath@yandex-team.com>2024-05-13 13:02:13 +0300
commit7b31bb09a816431b42dc0a7d01398445ca700477 (patch)
treec48cacc78775095b641a028c29036104cb250fd4
parent5b22fadb0f035a3b82c328e0ae710ad2b92f6eac (diff)
downloadydb-7b31bb09a816431b42dc0a7d01398445ca700477.tar.gz
Add mtime/atime/ctime with nanoseconds to TFileStat.
3523ab3f5aade2bdf4c0efd5dd2defbe19f124ff
-rw-r--r--util/datetime/systime.cpp40
-rw-r--r--util/datetime/systime.h4
-rw-r--r--util/system/fstat.cpp78
-rw-r--r--util/system/fstat.h15
4 files changed, 94 insertions, 43 deletions
diff --git a/util/datetime/systime.cpp b/util/datetime/systime.cpp
index aa935b7cf5..cb12cfdcf2 100644
--- a/util/datetime/systime.cpp
+++ b/util/datetime/systime.cpp
@@ -5,15 +5,39 @@
#ifdef _win_
+namespace {
+ // Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
+ constexpr ui64 NUMBER_OF_100_NANO_BETWEEN_1601_1970 =
+ ULL(116444736000000000);
+ constexpr ui64 NUMBER_OF_100_NANO_IN_SECOND = ULL(10000000);
+
+ union TFTUnion {
+ ui64 FTScalar;
+ FILETIME FTStruct;
+ };
+} // namespace
+
void FileTimeToTimeval(const FILETIME* ft, timeval* tv) {
- const i64 NANOINTERVAL = LL(116444736000000000); // Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
- union {
- ui64 ft_scalar;
- FILETIME ft_struct;
- } nt_time;
- nt_time.ft_struct = *ft;
- tv->tv_sec = (long)((nt_time.ft_scalar - NANOINTERVAL) / LL(10000000));
- tv->tv_usec = (i32)((nt_time.ft_scalar / LL(10)) % LL(1000000));
+ Y_ASSERT(ft);
+ Y_ASSERT(tv);
+ TFTUnion ntTime;
+ ntTime.FTStruct = *ft;
+ ntTime.FTScalar -= NUMBER_OF_100_NANO_BETWEEN_1601_1970;
+ tv->tv_sec =
+ static_cast<long>(ntTime.FTScalar / NUMBER_OF_100_NANO_IN_SECOND);
+ tv->tv_usec = static_cast<long>(
+ (ntTime.FTScalar % NUMBER_OF_100_NANO_IN_SECOND) / LL(10));
+}
+
+void FileTimeToTimespec(const FILETIME& ft, struct timespec* ts) {
+ Y_ASSERT(ts);
+ TFTUnion ntTime;
+ ntTime.FTStruct = ft;
+ ntTime.FTScalar -= NUMBER_OF_100_NANO_BETWEEN_1601_1970;
+ ts->tv_sec =
+ static_cast<time_t>(ntTime.FTScalar / NUMBER_OF_100_NANO_IN_SECOND);
+ ts->tv_nsec = static_cast<long>(
+ (ntTime.FTScalar % NUMBER_OF_100_NANO_IN_SECOND) * LL(100));
}
int gettimeofday(timeval* tp, void*) {
diff --git a/util/datetime/systime.h b/util/datetime/systime.h
index 491d36e802..760c28d6e6 100644
--- a/util/datetime/systime.h
+++ b/util/datetime/systime.h
@@ -15,8 +15,12 @@ TString CTimeR(const time_t* timer);
#include <util/system/winint.h>
#include <winsock2.h>
+// Convert FILETIME to timeval - seconds and microseconds.
void FileTimeToTimeval(const FILETIME* ft, struct timeval* tv);
+// Convert FILETIME to timespec - seconds and nanoseconds.
+void FileTimeToTimespec(const FILETIME& ft, struct timespec* ts);
+
// obtains the current time, expressed as seconds and microseconds since 00:00 UTC, January 1, 1970
int gettimeofday(struct timeval* tp, void*);
diff --git a/util/system/fstat.cpp b/util/system/fstat.cpp
index 121d34f23a..cfc5bed323 100644
--- a/util/system/fstat.cpp
+++ b/util/system/fstat.cpp
@@ -69,34 +69,61 @@ using TSystemFStat = struct stat;
#error unsupported platform
#endif
+#if defined(_unix_)
static void MakeStatFromStructStat(TFileStat& st, const struct stat& fs) {
st.Mode = fs.st_mode;
st.NLinks = fs.st_nlink;
st.Uid = fs.st_uid;
st.Gid = fs.st_gid;
st.Size = fs.st_size;
-#ifdef _unix_
st.AllocationSize = fs.st_blocks * 512;
-#else
- st.AllocationSize = st.Size; // FIXME
-#endif
+
+ #if defined(_linux_)
+ st.ATime = fs.st_atim.tv_sec;
+ st.ATimeNSec = fs.st_atim.tv_nsec;
+
+ st.MTime = fs.st_mtim.tv_sec;
+ st.MTimeNSec = fs.st_mtim.tv_nsec;
+
+ st.CTime = fs.st_ctim.tv_sec;
+ st.CTimeNSec = fs.st_ctim.tv_nsec;
+ #elif defined(_darwin_)
+ st.ATime = fs.st_atimespec.tv_sec;
+ st.ATimeNSec = fs.st_atimespec.tv_nsec;
+
+ st.MTime = fs.st_mtimespec.tv_sec;
+ st.MTimeNSec = fs.st_mtimespec.tv_nsec;
+
+ st.CTime = fs.st_birthtimespec.tv_sec;
+ st.CTimeNSec = fs.st_birthtimespec.tv_nsec;
+ #else
+ // Fallback.
st.ATime = fs.st_atime;
st.MTime = fs.st_mtime;
st.CTime = fs.st_ctime;
+ #endif
+
st.INode = fs.st_ino;
}
+#endif
static void MakeStat(TFileStat& st, const TSystemFStat& fs) {
#ifdef _unix_
MakeStatFromStructStat(st, fs);
#else
- timeval tv;
- FileTimeToTimeval(&fs.ftCreationTime, &tv);
- st.CTime = tv.tv_sec;
- FileTimeToTimeval(&fs.ftLastAccessTime, &tv);
- st.ATime = tv.tv_sec;
- FileTimeToTimeval(&fs.ftLastWriteTime, &tv);
- st.MTime = tv.tv_sec;
+ timespec timeSpec;
+ FileTimeToTimespec(fs.ftCreationTime, &timeSpec);
+ st.CTime = timeSpec.tv_sec;
+ st.CTimeNSec = timeSpec.tv_nsec;
+
+ FileTimeToTimespec(fs.ftLastAccessTime, &timeSpec);
+ st.ATime = timeSpec.tv_sec;
+ st.ATimeNSec = timeSpec.tv_nsec;
+
+ FileTimeToTimespec(fs.ftLastWriteTime, &timeSpec);
+ st.MTime = timeSpec.tv_sec;
+ st.MTimeNSec = timeSpec.tv_nsec;
+
st.NLinks = fs.nNumberOfLinks;
st.Mode = GetFileMode(fs.dwFileAttributes, fs.ReparseTag);
st.Uid = 0;
@@ -123,9 +150,13 @@ static bool GetStatByHandle(TSystemFStat& fs, FHANDLE f) {
static bool GetStatByName(TSystemFStat& fs, const char* fileName, bool nofollow) {
#ifdef _win_
- TFileHandle h = NFsPrivate::CreateFileWithUtf8Name(fileName, FILE_READ_ATTRIBUTES | FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE,
- OPEN_EXISTING,
- (nofollow ? FILE_FLAG_OPEN_REPARSE_POINT : 0) | FILE_FLAG_BACKUP_SEMANTICS, true);
+ TFileHandle h = NFsPrivate::CreateFileWithUtf8Name(
+ fileName,
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ OPEN_EXISTING,
+ (nofollow ? FILE_FLAG_OPEN_REPARSE_POINT : 0) | FILE_FLAG_BACKUP_SEMANTICS,
+ true);
if (!h.IsOpen()) {
return false;
}
@@ -150,9 +181,13 @@ TFileStat::TFileStat(FHANDLE f) {
}
}
+#if defined(_unix_)
TFileStat::TFileStat(const struct stat& st) {
MakeStatFromStructStat(*this, st);
}
+#endif
+
+bool TFileStat::operator==(const TFileStat& other) const noexcept = default;
void TFileStat::MakeFromFileName(const char* fileName, bool nofollow) {
TSystemFStat st;
@@ -191,21 +226,6 @@ bool TFileStat::IsSymlink() const noexcept {
return S_ISLNK(Mode);
}
-bool operator==(const TFileStat& l, const TFileStat& r) noexcept {
- return l.Mode == r.Mode &&
- l.Uid == r.Uid &&
- l.Gid == r.Gid &&
- l.NLinks == r.NLinks &&
- l.Size == r.Size &&
- l.ATime == r.ATime &&
- l.MTime == r.MTime &&
- l.CTime == r.CTime;
-}
-
-bool operator!=(const TFileStat& l, const TFileStat& r) noexcept {
- return !(l == r);
-}
-
i64 GetFileLength(FHANDLE fd) {
#if defined(_win_)
LARGE_INTEGER pos;
diff --git a/util/system/fstat.h b/util/system/fstat.h
index b487146e36..5d0c0e75f2 100644
--- a/util/system/fstat.h
+++ b/util/system/fstat.h
@@ -17,11 +17,13 @@ struct TFileStat {
ui64 INode = 0; /* inode number */
ui64 AllocationSize = 0; /* number of bytes allocated on the disk */
- time_t ATime = 0; /* time of last access */
- time_t MTime = 0; /* time of last modification */
- time_t CTime = 0; /* time of last status change */
+ time_t ATime = 0; /* time of last access */
+ long ATimeNSec = 0; /* nsec of last access */
+ time_t MTime = 0; /* time of last modification */
+ long MTimeNSec = 0; /* nsec of last modification */
+ time_t CTime = 0; /* time of last status change */
+ long CTimeNSec = 0; /* nsec of last status change */
-public:
TFileStat();
bool IsNull() const noexcept;
@@ -30,15 +32,16 @@ public:
bool IsDir() const noexcept;
bool IsSymlink() const noexcept;
+#if defined(_unix_)
explicit TFileStat(const struct stat& fs);
+#endif
explicit TFileStat(const TFile& f);
explicit TFileStat(FHANDLE f);
TFileStat(const TFsPath& fileName, bool nofollow = false);
TFileStat(const TString& fileName, bool nofollow = false);
TFileStat(const char* fileName, bool nofollow = false);
- friend bool operator==(const TFileStat& l, const TFileStat& r) noexcept;
- friend bool operator!=(const TFileStat& l, const TFileStat& r) noexcept;
+ bool operator==(const TFileStat& other) const noexcept;
private:
void MakeFromFileName(const char* fileName, bool nofollow);