*/
/*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012-2017 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
# include "config.h"
#endif
+#include "wimlib.h" /* for struct wimlib_timespec */
#include "wimlib/timestamp.h"
/*
* Timestamps in WIM files are Windows NT timestamps, or FILETIMEs: 64-bit
* values storing the number of 100-nanosecond ticks since January 1, 1601.
+ *
+ * Note: UNIX timestamps are signed; Windows timestamps are not. Negative UNIX
+ * timestamps represent times before 1970-01-01. When such a timestamp is
+ * converted to a Windows timestamp, we can preserve the correct date provided
+ * that it is not also before 1601-01-01.
*/
#define NANOSECONDS_PER_TICK 100
#define TICKS_PER_MICROSECOND (TICKS_PER_SECOND / 1000000)
/*
- * EPOCH_DISTANCE is the number of 100-nanosecond ticks separating the
- * Windows NT and UNIX epochs. This is equal to ((1970-1601)*365+89)*
- * 24*60*60*10000000. 89 is the number of leap years between 1970 and 1601.
+ * EPOCH_DISTANCE is the number of seconds separating the Windows NT and UNIX
+ * epochs. This is equal to ((1970-1601)*365+89)*24*60*60. 89 is the number
+ * of leap years between 1970 and 1601.
*/
-#define EPOCH_DISTANCE 116444736000000000
-
-#define TO_WINNT_EPOCH(timestamp) ((timestamp) + EPOCH_DISTANCE)
-#define TO_UNIX_EPOCH(timestamp) ((timestamp) - EPOCH_DISTANCE)
+#define EPOCH_DISTANCE 11644473600
/* Windows NT timestamps to UNIX timestamps */
time_t
wim_timestamp_to_time_t(u64 timestamp)
{
- timestamp = TO_UNIX_EPOCH(timestamp);
+ return (timestamp / TICKS_PER_SECOND) - EPOCH_DISTANCE;
+}
+
+void
+wim_timestamp_to_wimlib_timespec(u64 timestamp, struct wimlib_timespec *wts,
+ s32 *high_part_ret)
+{
+ s64 sec = (timestamp / TICKS_PER_SECOND) - EPOCH_DISTANCE;
- return timestamp / TICKS_PER_SECOND;
+ wts->tv_sec = sec;
+ wts->tv_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK;
+
+ if (sizeof(wts->tv_sec) == 4)
+ *high_part_ret = sec >> 32;
}
+#ifdef __WIN32__
+static _unused_attribute void
+check_sizeof_time_t(void)
+{
+ /* Windows builds should always be using 64-bit time_t now. */
+ STATIC_ASSERT(sizeof(time_t) == 8);
+}
+#else
struct timeval
wim_timestamp_to_timeval(u64 timestamp)
{
- timestamp = TO_UNIX_EPOCH(timestamp);
-
return (struct timeval) {
- .tv_sec = timestamp / TICKS_PER_SECOND,
+ .tv_sec = wim_timestamp_to_time_t(timestamp),
.tv_usec = (timestamp % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND,
};
}
struct timespec
wim_timestamp_to_timespec(u64 timestamp)
{
- timestamp = TO_UNIX_EPOCH(timestamp);
-
return (struct timespec) {
- .tv_sec = timestamp / TICKS_PER_SECOND,
+ .tv_sec = wim_timestamp_to_time_t(timestamp),
.tv_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK,
};
}
u64
time_t_to_wim_timestamp(time_t t)
{
- u64 timestamp = (u64)t * TICKS_PER_SECOND;
-
- return TO_WINNT_EPOCH(timestamp);
+ return ((u64)t + EPOCH_DISTANCE) * TICKS_PER_SECOND;
}
u64
timeval_to_wim_timestamp(const struct timeval *tv)
{
- u64 timestamp = (u64)tv->tv_sec * TICKS_PER_SECOND +
- (u64)tv->tv_usec * TICKS_PER_MICROSECOND;
-
- return TO_WINNT_EPOCH(timestamp);
+ return time_t_to_wim_timestamp(tv->tv_sec) +
+ (u32)tv->tv_usec * TICKS_PER_MICROSECOND;
}
u64
timespec_to_wim_timestamp(const struct timespec *ts)
{
- u64 timestamp = (u64)ts->tv_sec * TICKS_PER_SECOND +
- (u64)ts->tv_nsec / NANOSECONDS_PER_TICK;
-
- return TO_WINNT_EPOCH(timestamp);
+ return time_t_to_wim_timestamp(ts->tv_sec) +
+ (u32)ts->tv_nsec / NANOSECONDS_PER_TICK;
}
/* Retrieve the current time as a WIM timestamp. */
{
struct timeval tv;
- /* On Windows we rely on MinGW providing gettimeofday() for us. This
- * could be changed to calling GetSystemTimeAsFileTime() directly, but
- * now_as_wim_timestamp() isn't called much and it's simpler to keep the
- * code for all platforms the same. */
gettimeofday(&tv, NULL);
return timeval_to_wim_timestamp(&tv);
}
+#endif /* !__WIN32__ */
/* Translate a WIM timestamp into a human-readable string. */
void
{
struct tm tm;
time_t t = wim_timestamp_to_time_t(timestamp);
+
gmtime_r(&t, &tm);
tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm);
}