all: properly handle time_t on 32-bit platforms

Do not force 64-bit `time_t` on 32-bit platforms, since libfuse
does not do so.  Linking shared objects with incompatible types
breaks ABI, resulting in undefined behavior.

Instead, add run-time checks to make sure that timestamps do not
overflow.  If they do, set to `INT32_MAX`.

Also tidy up build scripts, tests, and the installation guide.
This commit is contained in:
CismonX 2025-06-14 11:43:03 +08:00
parent f1451d206e
commit 6fc165ff65
No known key found for this signature in database
GPG key ID: 3094873E29A482FB
5 changed files with 36 additions and 47 deletions

View file

@ -166,19 +166,6 @@ Notes
In this case, the utility library will not be built from source,
and other components will link to the specified library instead.
### Targeting 32-bit Platforms
BookmarkFS requires 64-bit `off_t` and `time_t`, which may not be supported
on 32-bit platforms (e.g., i386 FreeBSD does not support 64-bit `time_t`).
If using Autoconf 2.72 or later, the configuration script automatically
performs checks and defines necessary macros, and fails if unsupported.
With legacy Autoconf, only `off_t` is checked.
To manually configure 64-bit `time_t`, add preprocessor flags
`-D_TIME_BITS=64` (or something equivalent, depending on the toolchain).
If unsupported, `make` will fail.
### FreeBSD and GNU libiconv
NOTE: You may skip this section if _not_ building the Chromium backend.

View file

@ -196,18 +196,7 @@ AS_VAR_IF([ac_have_largefile], [no], [
]))
])
m4_version_prereq([2.72], [
AC_SYS_YEAR2038
AS_VAR_IF([ac_have_year2038], [no], [
AC_MSG_ERROR(m4_normalize([
64-bit time_t is unsupported on this platform.
]))
])
], [
dnl fallback to compile-time check...
AX_COMPILE_CHECK_SIZEOF([time_t])
])
AX_COMPILE_CHECK_SIZEOF([time_t])
AX_COMPILE_CHECK_SIZEOF([uintptr_t], [#include <stdint.h>])
# -- Output --

View file

@ -58,17 +58,14 @@
#include "watcher.h"
#include "xstd.h"
#if defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T != 8)
# error "64-bit time_t is required"
#endif
#define BACKEND_FILENAME_GUID ( 1u << 16 )
// Chromium uses Windows FILETIME epoch instead of Unix epoch.
// Chromium uses Windows FILETIME epoch, which is
// `((1970 - 1601) * 365 + 89) * 24 * 3600` seconds before the Unix epoch.
//
// See Chromium source code: /base/time/time.h
// (`base::Time::kTimeTToMicrosecondsOffset`)
#define EPOCH_DIFF ( (time_t)((1970 - 1601) * 365 + 89) * 24 * 3600 )
#define EPOCH_DIFF INT64_C(11644473600)
#define BOOKMARKS_ROOT_ID 0
@ -387,7 +384,7 @@ build_tsnode (
ts = &now;
}
time_t secs = ts->tv_sec + EPOCH_DIFF;
int64_t secs = ts->tv_sec + EPOCH_DIFF;
int64_t microsecs = secs * 1000000 + ts->tv_nsec / 1000;
char buf[32];
@ -1461,12 +1458,17 @@ parse_ts (
}
if (buf != NULL) {
time_t secs = microsecs / 1000000;
if (unlikely(secs < EPOCH_DIFF)) {
int64_t secs = microsecs / 1000000 - EPOCH_DIFF;
if (unlikely(secs < 0)) {
// Stay away from negative tv_sec
secs = EPOCH_DIFF;
secs = 0;
}
buf->tv_sec = secs - EPOCH_DIFF;
#if defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T < 8)
else if (secs > INT32_MAX) {
secs = INT32_MAX;
}
#endif
buf->tv_sec = secs;
buf->tv_nsec = (microsecs % 1000000) * 1000;
}
return 0;

View file

@ -2135,7 +2135,7 @@ static int64_t
timespec_to_usecs (
struct timespec const *ts
) {
return ts->tv_sec * 1000000 + ts->tv_nsec / 1000;
return (int64_t)ts->tv_sec * 1000000 + ts->tv_nsec / 1000;
}
static int
@ -2778,11 +2778,16 @@ usecs_to_timespec (
struct timespec *ts_buf,
int64_t microsecs
) {
if (unlikely(microsecs < 0)) {
microsecs = 0;
int64_t secs = microsecs / 1000000;
if (unlikely(secs < 0)) {
secs = 0;
}
ts_buf->tv_sec = microsecs / 1000000;
#if defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T < 8)
else if (secs > INT32_MAX) {
secs = INT32_MAX;
}
#endif
ts_buf->tv_sec = secs;
ts_buf->tv_nsec = (microsecs % 1000000) * 1000;
}

View file

@ -31,13 +31,14 @@
#include <unistd.h>
#include "check_util.h"
#include "backend_util.h"
#include "frontend_util.h"
#include "prng.h"
// Forward declaration start
static int compare_timespec (struct timespec, struct timespec);
static int do_check_fs_times (int, int);
static void usecs_to_timespec (struct timespec *, uint32_t);
static void usecs_to_timespec (struct timespec *, uint64_t);
// Forward declaration end
static int
@ -113,9 +114,8 @@ do_check_fs_times (
ASSERT_NE(-1, compare_timespec(stat_buf.st_atim, now));
for (int i = 0; i < rounds; ++i) {
uint64_t bits = prng_rand();
usecs_to_timespec(&times[0], bits & 0xffffffff);
usecs_to_timespec(&times[1], bits >> 32);
usecs_to_timespec(&times[0], prng_rand());
usecs_to_timespec(&times[1], prng_rand());
ASSERT_EQ(0, futimens(fd, times));
ASSERT_EQ(0, fstat(fd, &stat_buf));
@ -142,9 +142,15 @@ do_check_fs_times (
static void
usecs_to_timespec (
struct timespec *ts_buf,
uint32_t usecs
uint64_t usecs
) {
ts_buf->tv_sec = usecs / 1000000;
int64_t secs = usecs / 1000000;
#if defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T < 8)
secs %= (int64_t)INT32_MAX + 1;
#else
secs %= TIMESPEC_SEC_MAX + 1;
#endif
ts_buf->tv_sec = secs;
ts_buf->tv_nsec = (usecs % 1000000) * 1000;
}