diff options
author | sath <sath@yandex-team.com> | 2024-05-13 12:52:23 +0300 |
---|---|---|
committer | sath <sath@yandex-team.com> | 2024-05-13 13:02:13 +0300 |
commit | 7b31bb09a816431b42dc0a7d01398445ca700477 (patch) | |
tree | c48cacc78775095b641a028c29036104cb250fd4 | |
parent | 5b22fadb0f035a3b82c328e0ae710ad2b92f6eac (diff) | |
download | ydb-7b31bb09a816431b42dc0a7d01398445ca700477.tar.gz |
Add mtime/atime/ctime with nanoseconds to TFileStat.
3523ab3f5aade2bdf4c0efd5dd2defbe19f124ff
-rw-r--r-- | util/datetime/systime.cpp | 40 | ||||
-rw-r--r-- | util/datetime/systime.h | 4 | ||||
-rw-r--r-- | util/system/fstat.cpp | 78 | ||||
-rw-r--r-- | util/system/fstat.h | 15 |
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); |