Common (IO): adds ffPathGetMtime and uses it

This commit is contained in:
李通洲
2026-09-14 22:21:49 +08:00
parent e3b3b5dfc6
commit 375d0c6b25
4 changed files with 47 additions and 33 deletions
+16
View File
@@ -11,6 +11,7 @@
#include <poll.h>
#else
#include <sys/select.h>
#define st_mtim st_mtimespec // `struct stat` spells it `st_mtimespec` on Apple
#endif
#if FF_HAVE_WORDEXP
@@ -331,3 +332,18 @@ FFNativeFD ffGetNullFD(void) {
bool ffRemoveFile(const char* fileName) {
return unlink(fileName) == 0;
}
uint64_t ffPathGetMtime(const char* path) {
struct stat st;
if (stat(path, &st) != 0) {
return 0;
}
// An mtime at or before the Unix epoch means the filesystem did not fill it in. Reporting it
// as-is would hand the caller a value indistinguishable from "unknown", so treat it as such.
if (st.st_mtim.tv_sec <= 0) {
return 0;
}
return (uint64_t) st.st_mtim.tv_sec * 1000ull + (uint64_t) st.st_mtim.tv_nsec / 1000000ull;
}
+17
View File
@@ -1,6 +1,7 @@
#include "fastfetch.h"
#include "common/io.h"
#include "common/strutil.h"
#include "common/time.h"
#include "common/windows/nt.h"
#include "common/windows/unicode.h"
@@ -499,3 +500,19 @@ FFNativeFD ffGetNullFD(void) {
bool ffRemoveFile(const char* fileName) {
return DeleteFileA(fileName) != FALSE;
}
uint64_t ffPathGetMtime(const char* path) {
FF_AUTO_CLOSE_FD HANDLE handle = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (handle == INVALID_HANDLE_VALUE) { // file doesn't exist or isn't accessible
return 0;
}
FILE_BASIC_INFORMATION fileInfo;
IO_STATUS_BLOCK iosb;
if (!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileBasicInformation))) {
return 0;
}
return ffFileTimeToUnixMs((uint64_t) fileInfo.LastWriteTime.QuadPart);
}
+4
View File
@@ -291,3 +291,7 @@ static inline void wrapClosedir(HANDLE* pdir) {
FFNativeFD ffGetNullFD(void);
bool ffRemoveFile(const char* fileName);
// Modification time of a file, in milliseconds since the Unix epoch, or 0 if it can not be read.
// The representation is uniform across platforms so that a value derived from it means the
// same thing everywhere, which matters for callers that store it as a cache key.
[[gnu::nonnull(1)]] uint64_t ffPathGetMtime(const char* path);
+10 -33
View File
@@ -1,14 +1,9 @@
#include "packages.h"
#include "common/io.h"
#include "common/time.h"
#include <inttypes.h>
#include <stddef.h>
#ifdef __APPLE__
#define st_mtim st_mtimespec
#endif
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options);
const char* ffDetectPackages(FFPackagesResult* result, FFPackagesOptions* options) {
@@ -22,38 +17,20 @@ const char* ffDetectPackages(FFPackagesResult* result, FFPackagesOptions* option
}
bool ffPackagesReadCache(FFstrbuf* cacheDir, FFstrbuf* cacheContent, const char* filePath, const char* packageId, uint32_t* result) {
#ifndef _WIN32
struct stat st;
if (stat(filePath, &st) < 0) // file doesn't exist or isn't accessible
{
const uint64_t mtime_current = ffPathGetMtime(filePath);
if (__builtin_expect(mtime_current == 0, false)) {
// A missing database legitimately means "no packages installed", and must not be cached.
// A database whose modification time could not be read must not be cached either, and
// reporting 0 for it would be a lie. ffPathGetMtime() reports 0 for both, so tell them
// apart before deciding which of the two applies.
if (ffPathExists(filePath, FF_PATHTYPE_FILE)) {
return false;
}
*result = 0;
return true;
}
if (__builtin_expect(st.st_mtim.tv_sec <= 0, false)) {
return false;
}
uint64_t mtime_current = (uint64_t) st.st_mtim.tv_sec * 1000ull + (uint64_t) st.st_mtim.tv_nsec / 1000000ull;
#else
FF_AUTO_CLOSE_FD HANDLE handle = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (handle == INVALID_HANDLE_VALUE) // file doesn't exist or isn't accessible
{
*result = 0;
return true;
}
uint64_t mtime_current;
FILE_BASIC_INFORMATION fileInfo;
IO_STATUS_BLOCK iosb;
if (!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileBasicInformation))) {
return false;
}
mtime_current = ffFileTimeToUnixMs((uint64_t) fileInfo.LastWriteTime.QuadPart);
#endif
ffStrbufSet(cacheDir, &instance.state.platform.cacheDir);
ffStrbufEnsureEndsWithC(cacheDir, '/');
ffStrbufAppendF(cacheDir, "fastfetch/packages/%s.txt", packageId);