X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Ftimestamp.c;h=6bbdd8ac41ac2741683e001b4c8bab2ed5025f79;hb=7453f4a4245219a9c01a70902283f6ebb2a65123;hp=ebe57380203d1fa956cf114bcc39c216c48fdd19;hpb=3071e89c11d1be71cf45b694432e5908e0c4ded9;p=wimlib diff --git a/src/timestamp.c b/src/timestamp.c index ebe57380..6bbdd8ac 100644 --- a/src/timestamp.c +++ b/src/timestamp.c @@ -1,9 +1,11 @@ /* * timestamp.c + * + * Conversion between Windows NT timestamps and UNIX timestamps. */ /* - * Copyright (C) 2012, 2013 Eric Biggers + * Copyright (C) 2012, 2013, 2014 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 @@ -23,26 +25,107 @@ # include "config.h" #endif -#include "wimlib/types.h" #include "wimlib/timestamp.h" -#include -#include +/* + * Timestamps in WIM files are Windows NT timestamps, or FILETIMEs: 64-bit + * values storing the number of 100-nanosecond ticks since January 1, 1601. + */ + +#define NANOSECONDS_PER_TICK 100 +#define TICKS_PER_SECOND (1000000000 / NANOSECONDS_PER_TICK) +#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. + */ +#define EPOCH_DISTANCE 116444736000000000 + +#define TO_WINNT_EPOCH(timestamp) ((timestamp) + EPOCH_DISTANCE) +#define TO_UNIX_EPOCH(timestamp) ((timestamp) - EPOCH_DISTANCE) + +/* 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; +} + +struct timeval +wim_timestamp_to_timeval(u64 timestamp) +{ + timestamp = TO_UNIX_EPOCH(timestamp); + + return (struct timeval) { + .tv_sec = timestamp / TICKS_PER_SECOND, + .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_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK, + }; +} + +/* UNIX timestamps to Windows NT timestamps */ + +u64 +time_t_to_wim_timestamp(time_t t) +{ + u64 timestamp = (u64)t * TICKS_PER_SECOND; + + return TO_WINNT_EPOCH(timestamp); +} u64 -get_wim_timestamp(void) +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); +} + +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); +} + +/* Retrieve the current time as a WIM timestamp. */ +u64 +now_as_wim_timestamp(void) { 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); + return timeval_to_wim_timestamp(&tv); } +/* Translate a WIM timestamp into a human-readable string. */ void wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len) { struct tm tm; - time_t t = wim_timestamp_to_unix(timestamp); + 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); } -