X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Ftimestamp.c;h=16e412b36a4b789bc9ccf474c73a1f63f15931eb;hp=33c617469ac56d55d7fee7165f8f51303bcf6e63;hb=088dff37aa334c218e1cac96cc847f5dd14f7124;hpb=e8c3ca2d1d0cac3d64985b45a9f654d2029a7518 diff --git a/src/timestamp.c b/src/timestamp.c index 33c61746..16e412b3 100644 --- a/src/timestamp.c +++ b/src/timestamp.c @@ -1,50 +1,121 @@ /* * 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/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; +} + +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; + + /* 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); } -