X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Ftimestamp.c;h=1e0eef3e113651d22fc30f62730ccf8fd737deee;hb=55564216b05d61a397d0fa7642d43cf5c799e934;hp=33c617469ac56d55d7fee7165f8f51303bcf6e63;hpb=e8c3ca2d1d0cac3d64985b45a9f654d2029a7518;p=wimlib diff --git a/src/timestamp.c b/src/timestamp.c index 33c61746..1e0eef3e 100644 --- a/src/timestamp.c +++ b/src/timestamp.c @@ -1,50 +1,141 @@ /* * timestamp.c + * + * Conversion between Windows NT timestamps and UNIX timestamps. */ /* - * Copyright (C) 2012, 2013 Eric Biggers - * - * This file is part of wimlib, a library for working with WIM files. + * Copyright (C) 2012-2017 Eric Biggers * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. + * 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 + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * - * You should have received a copy of the GNU General Public License - * along with wimlib; if not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "wimlib/types.h" +#include "wimlib.h" /* for struct wimlib_timespec */ #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. + * + * 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_SECOND (1000000000 / NANOSECONDS_PER_TICK) +#define TICKS_PER_MICROSECOND (TICKS_PER_SECOND / 1000000) + +/* + * 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 11644473600 + +/* Windows NT timestamps to UNIX timestamps */ + +time_t +wim_timestamp_to_time_t(u64 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; + + 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) +{ + return (struct timeval) { + .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) +{ + return (struct timespec) { + .tv_sec = wim_timestamp_to_time_t(timestamp), + .tv_nsec = (timestamp % TICKS_PER_SECOND) * NANOSECONDS_PER_TICK, + }; +} + +/* UNIX timestamps to Windows NT timestamps */ u64 -get_wim_timestamp(void) +time_t_to_wim_timestamp(time_t t) +{ + return ((u64)t + EPOCH_DISTANCE) * TICKS_PER_SECOND; +} + +u64 +timeval_to_wim_timestamp(const struct timeval *tv) +{ + 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) +{ + return time_t_to_wim_timestamp(ts->tv_sec) + + (u32)ts->tv_nsec / NANOSECONDS_PER_TICK; +} + +/* Retrieve the current time as a WIM timestamp. */ +u64 +now_as_wim_timestamp(void) { struct timeval tv; + gettimeofday(&tv, NULL); - return timeval_to_wim_timestamp(tv); + return timeval_to_wim_timestamp(&tv); } +#endif /* !_WIN32 */ +/* 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); } -