mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-19 21:13:35 +00:00
[linux] Fix zero file creation (birth) time
Observed in Ubuntu 24 via Orb on arm-based Mac Signed-off-by: Alexander Borsuk <me@alex.bio>
This commit is contained in:
committed by
Konstantin Pastbin
parent
fbaa59ce3b
commit
674abcf02e
@@ -1029,9 +1029,9 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames)
|
|||||||
BookmarkManager bmManager(BM_CALLBACKS);
|
BookmarkManager bmManager(BM_CALLBACKS);
|
||||||
bmManager.EnableTestMode(true);
|
bmManager.EnableTestMode(true);
|
||||||
|
|
||||||
auto const file1Name = "file1";
|
auto const fileNameFromMemory = "";
|
||||||
BookmarkManager::KMLDataCollection kmlDataCollection1;
|
BookmarkManager::KMLDataCollection kmlDataCollection1;
|
||||||
kmlDataCollection1.emplace_back(file1Name /* filePath */,
|
kmlDataCollection1.emplace_back(fileNameFromMemory /* filePath */,
|
||||||
LoadKmlData(MemReader(kmlString3, strlen(kmlString3)), KmlFileType::Text));
|
LoadKmlData(MemReader(kmlString3, strlen(kmlString3)), KmlFileType::Text));
|
||||||
bmManager.CreateCategories(std::move(kmlDataCollection1));
|
bmManager.CreateCategories(std::move(kmlDataCollection1));
|
||||||
|
|
||||||
@@ -1056,29 +1056,29 @@ UNIT_CLASS_TEST(Runner, Bookmarks_SpecialXMLNames)
|
|||||||
|
|
||||||
bmManager.GetEditSession().DeleteBmCategory(catId, true);
|
bmManager.GetEditSession().DeleteBmCategory(catId, true);
|
||||||
|
|
||||||
auto const file2Name = "file2";
|
auto const fileNameOnDisk = "file1";
|
||||||
BookmarkManager::KMLDataCollection kmlDataCollection2;
|
BookmarkManager::KMLDataCollection kmlDataCollection2;
|
||||||
kmlDataCollection2.emplace_back(file1Name /* filePath */, LoadKmlFile(fileNameTmp, GetActiveKmlFileType()));
|
kmlDataCollection2.emplace_back(fileNameOnDisk /* filePath */, LoadKmlFile(fileNameTmp, GetActiveKmlFileType()));
|
||||||
bmManager.CreateCategories(std::move(kmlDataCollection2));
|
bmManager.CreateCategories(std::move(kmlDataCollection2));
|
||||||
|
|
||||||
BookmarkManager::KMLDataCollection kmlDataCollection3;
|
BookmarkManager::KMLDataCollection kmlDataCollection3;
|
||||||
kmlDataCollection3.emplace_back(file2Name /* filePath */,
|
kmlDataCollection3.emplace_back(fileNameFromMemory /* filePath */,
|
||||||
LoadKmlData(MemReader(kmlString3, strlen(kmlString3)), KmlFileType::Text));
|
LoadKmlData(MemReader(kmlString3, strlen(kmlString3)), KmlFileType::Text));
|
||||||
|
|
||||||
bmManager.CreateCategories(std::move(kmlDataCollection3));
|
bmManager.CreateCategories(std::move(kmlDataCollection3));
|
||||||
|
|
||||||
TEST_EQUAL(bmManager.GetBmGroupsCount(), 2, ());
|
TEST_EQUAL(bmManager.GetBmGroupsCount(), 2, ());
|
||||||
auto const catId2 = bmManager.GetSortedBmGroupIdList().front();
|
auto const lastModifiedCatId = bmManager.GetSortedBmGroupIdList().front();
|
||||||
auto const catId3 = bmManager.GetSortedBmGroupIdList().back();
|
auto const olderCatId = bmManager.GetSortedBmGroupIdList().back();
|
||||||
|
|
||||||
TEST_EQUAL(bmManager.GetUserMarkIds(catId2).size(), 1, ());
|
TEST_EQUAL(bmManager.GetUserMarkIds(lastModifiedCatId).size(), 1, ());
|
||||||
TEST_EQUAL(bmManager.GetCategoryName(catId2), expectedName, ());
|
TEST_EQUAL(bmManager.GetCategoryName(olderCatId), expectedName, ());
|
||||||
TEST_EQUAL(bmManager.GetCategoryFileName(catId2), file1Name, ());
|
TEST_EQUAL(bmManager.GetCategoryFileName(lastModifiedCatId), fileNameFromMemory, ());
|
||||||
TEST_EQUAL(bmManager.GetCategoryFileName(catId3), file2Name, ());
|
TEST_EQUAL(bmManager.GetCategoryFileName(olderCatId), fileNameOnDisk, ());
|
||||||
|
|
||||||
auto const bmId1 = *bmManager.GetUserMarkIds(catId2).begin();
|
auto const bmId1 = *bmManager.GetUserMarkIds(lastModifiedCatId).begin();
|
||||||
auto const * bm1 = bmManager.GetBookmark(bmId1);
|
auto const * bm1 = bmManager.GetBookmark(bmId1);
|
||||||
auto const bmId2 = *bmManager.GetUserMarkIds(catId3).begin();
|
auto const bmId2 = *bmManager.GetUserMarkIds(olderCatId).begin();
|
||||||
auto const * bm2 = bmManager.GetBookmark(bmId2);
|
auto const * bm2 = bmManager.GetBookmark(bmId2);
|
||||||
TEST(EqualBookmarks(*bm1, *bm2), ());
|
TEST(EqualBookmarks(*bm1, *bm2), ());
|
||||||
TEST_EQUAL(kml::GetDefaultStr(bm1->GetName()), "![X1]{X2}(X3)", ());
|
TEST_EQUAL(kml::GetDefaultStr(bm1->GetName()), "![X1]{X2}(X3)", ());
|
||||||
|
|||||||
@@ -232,6 +232,9 @@ time_t Platform::GetFileCreationTime(std::string const & path)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (0 == stat(path.c_str(), &st))
|
if (0 == stat(path.c_str(), &st))
|
||||||
return st.st_atim.tv_sec;
|
return st.st_atim.tv_sec;
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileCreationTime stat failed for", path, "with error", strerror(errno)));
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,5 +244,8 @@ time_t Platform::GetFileModificationTime(std::string const & path)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (0 == stat(path.c_str(), &st))
|
if (0 == stat(path.c_str(), &st))
|
||||||
return st.st_mtim.tv_sec;
|
return st.st_mtim.tv_sec;
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileModificationTime stat failed for", path, "with error", strerror(errno)));
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,16 +260,30 @@ void Platform::GetSystemFontNames(FilesList & res) const
|
|||||||
// static
|
// static
|
||||||
time_t Platform::GetFileCreationTime(std::string const & path)
|
time_t Platform::GetFileCreationTime(std::string const & path)
|
||||||
{
|
{
|
||||||
// In older Linux versions there is no reliable way to get file creation time.
|
// In older Linux versions there is no reliable way to get file creation time with GLIBC.
|
||||||
#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 28
|
// Musl supports statx since 2018.
|
||||||
|
#if !defined(__GLIBC__) || (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 28)
|
||||||
struct statx st;
|
struct statx st;
|
||||||
if (0 == statx(AT_FDCWD, path.c_str(), 0, STATX_BTIME, &st))
|
if (0 == statx(AT_FDCWD, path.c_str(), 0, STATX_BTIME, &st))
|
||||||
return st.stx_btime.tv_sec;
|
{
|
||||||
|
// Orbstack on MacOS returns zero birth time, see https://github.com/orbstack/orbstack/issues/2064
|
||||||
|
if (st.stx_btime.tv_sec != 0)
|
||||||
|
return st.stx_btime.tv_sec;
|
||||||
|
|
||||||
|
LOG(LWARNING, ("statx returned zero birth time for", path,
|
||||||
|
", using the earliest time from access, modification or status change instead."));
|
||||||
|
return std::min(st.stx_atime.tv_sec, std::min(st.stx_mtime.tv_sec, st.stx_ctime.tv_sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileCreationTime statx failed for", path, "with error", strerror(errno)));
|
||||||
#else
|
#else
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (0 == stat(path.c_str(), &st))
|
if (0 == stat(path.c_str(), &st))
|
||||||
return std::min(st.st_atim.tv_sec, st.st_mtim.tv_sec);
|
return std::min(st.st_atim.tv_sec, st.st_mtim.tv_sec);
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileCreationTime stat failed for", path, "with error", strerror(errno)));
|
||||||
#endif
|
#endif
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,5 +293,8 @@ time_t Platform::GetFileModificationTime(std::string const & path)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (0 == stat(path.c_str(), &st))
|
if (0 == stat(path.c_str(), &st))
|
||||||
return st.st_mtim.tv_sec;
|
return st.st_mtim.tv_sec;
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileModificationTime stat failed for", path, "with error", strerror(errno)));
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,9 @@ time_t Platform::GetFileCreationTime(std::string const & path)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (0 == stat(path.c_str(), &st))
|
if (0 == stat(path.c_str(), &st))
|
||||||
return st.st_birthtimespec.tv_sec;
|
return st.st_birthtimespec.tv_sec;
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileCreationTime stat failed for", path, "with error", strerror(errno)));
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,5 +202,8 @@ time_t Platform::GetFileModificationTime(std::string const & path)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (0 == stat(path.c_str(), &st))
|
if (0 == stat(path.c_str(), &st))
|
||||||
return st.st_mtimespec.tv_sec;
|
return st.st_mtimespec.tv_sec;
|
||||||
|
|
||||||
|
LOG(LERROR, ("GetFileModificationTime stat failed for", path, "with error", strerror(errno)));
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,7 +220,10 @@ time_t GetFileTime(std::string const & path, FileTimeType fileTimeType)
|
|||||||
{
|
{
|
||||||
HANDLE hFile = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
HANDLE hFile = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
if (hFile == INVALID_HANDLE_VALUE)
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
return 0;
|
{
|
||||||
|
LOG(LERROR, ("GetFileTime CreateFileA failed for", path, "with error", strerror(errno)));
|
||||||
|
return 0; // TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
|
}
|
||||||
|
|
||||||
SCOPE_GUARD(autoClose, bind(&CloseHandle, hFile));
|
SCOPE_GUARD(autoClose, bind(&CloseHandle, hFile));
|
||||||
|
|
||||||
@@ -234,8 +237,11 @@ time_t GetFileTime(std::string const & path, FileTimeType fileTimeType)
|
|||||||
case FileTimeType::Modification: ftLastWrite = &ft; break;
|
case FileTimeType::Modification: ftLastWrite = &ft; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetFileTime(hFile, ftCreate, nullptr, ftLastWrite))
|
if (!::GetFileTime(hFile, ftCreate, nullptr, ftLastWrite))
|
||||||
return 0;
|
{
|
||||||
|
LOG(LERROR, ("GetFileTime ::GetFileTime failed for", path, "with error", strerror(errno)));
|
||||||
|
return 0; // TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
|
}
|
||||||
|
|
||||||
ULARGE_INTEGER ull;
|
ULARGE_INTEGER ull;
|
||||||
ull.LowPart = ft.dwLowDateTime;
|
ull.LowPart = ft.dwLowDateTime;
|
||||||
@@ -247,12 +253,14 @@ time_t GetFileTime(std::string const & path, FileTimeType fileTimeType)
|
|||||||
// static
|
// static
|
||||||
time_t Platform::GetFileCreationTime(std::string const & path)
|
time_t Platform::GetFileCreationTime(std::string const & path)
|
||||||
{
|
{
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return GetFileTime(path, FileTimeType::Creation);
|
return GetFileTime(path, FileTimeType::Creation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
time_t Platform::GetFileModificationTime(std::string const & path)
|
time_t Platform::GetFileModificationTime(std::string const & path)
|
||||||
{
|
{
|
||||||
|
// TODO(AB): Refactor to return std::optional<time_t>.
|
||||||
return GetFileTime(path, FileTimeType::Modification);
|
return GetFileTime(path, FileTimeType::Modification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user