Use reentrant time functions if available.

Copied the following from rom-properties:
- time_r.h
- config.libc.h.in
- CheckSymbolExistsOrInline.cmake
This commit is contained in:
David Korth 2022-02-14 21:36:32 -05:00
parent 2a52eb5e2a
commit 4e5d89ed35
9 changed files with 219 additions and 65 deletions

View File

@ -0,0 +1,41 @@
# Check if a symbol is available either as a regular function or an inline function.
# CHECK_SYMBOL_EXISTS_OR_INLINE(_function _header _sample_code _variable)
#
# _function - function name to check
# _header - header file
# _sample_code - sample code to compile
# _variable - variable to store the result
# Based on CHECK_SYMBOL_EXISTS(). (CheckSymbolExists.cmake)
INCLUDE(CheckSymbolExists)
INCLUDE(CheckCSourceCompiles)
MACRO(CHECK_SYMBOL_EXISTS_OR_INLINE _function _header _sample_code _variable)
# MinGW defines some reentrant functions as inline functions
# that are actually wrappers around MSVC "secure" functions.
# Check for the function as a regular function first, then check
# if it's available in the specified header.
IF(NOT DEFINED ${_variable})
CHECK_SYMBOL_EXISTS(${_function} ${_header} ${_variable})
IF(NOT ${_variable})
# Function does not exist normally.
# Check if it's an inline function in the specified header.
MESSAGE(STATUS "Looking for ${_function} as an inline function")
CHECK_C_SOURCE_COMPILES(
"#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 1
#include <${_header}>
int main(void) { ${_sample_code} }"
${_variable}_INLINE)
IF(${_variable}_INLINE)
MESSAGE(STATUS "Looking for ${_variable} as an inline function - found")
SET(${_variable} 1 CACHE INTERNAL "Have function ${_variable} (inline)")
ELSE(${_variable}_INLINE)
MESSAGE(STATUS "Looking for ${_variable} as an inline function - not found")
# ${_variable} is already cached by CHECK_SYMBOL_EXISTS().
ENDIF(${_variable}_INLINE)
ENDIF(NOT ${_variable})
ENDIF(NOT DEFINED ${_variable})
ENDMACRO(CHECK_SYMBOL_EXISTS_OR_INLINE _function _header _sample_code _variable)

View File

@ -1,6 +1,35 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
PROJECT(src)
# Check for reentrant time functions.
# NOTE: May be _gmtime32_s() or _gmtime64_s() on MSVC 2005+.
# The "inline" part will detect that.
INCLUDE(CheckSymbolExistsOrInline)
CHECK_SYMBOL_EXISTS_OR_INLINE(gmtime_r "time.h" "time_t tm; gmtime_r(&tm, NULL);" HAVE_GMTIME_R)
IF(NOT HAVE_GMTIME_R)
CHECK_SYMBOL_EXISTS_OR_INLINE(gmtime_s "time.h" "time_t tm; gmtime_s(NULL, &tm);" HAVE_GMTIME_S)
ENDIF(NOT HAVE_GMTIME_R)
CHECK_SYMBOL_EXISTS_OR_INLINE(localtime_r "time.h" "time_t tm; localtime_r(&tm, NULL);" HAVE_LOCALTIME_R)
IF(NOT HAVE_LOCALTIME_R)
CHECK_SYMBOL_EXISTS_OR_INLINE(localtime_s "time.h" "time_t tm; localtime_s(NULL, &tm);" HAVE_LOCALTIME_S)
ENDIF(NOT HAVE_LOCALTIME_R)
# Other time functions.
CHECK_SYMBOL_EXISTS_OR_INLINE(timegm "time.h" "struct tm tm; time_t x = timegm(&tm);" HAVE_TIMEGM)
IF(NOT HAVE_TIMEGM)
# NOTE: MSVCRT's _mkgmtime64() has a range of [1970/01/01, 3000/12/31].
# glibc and boost both support arbitrary ranges.
CHECK_SYMBOL_EXISTS_OR_INLINE(_mkgmtime "time.h" "struct tm tm; time_t x = _mkgmtime(&tm);" HAVE__MKGMTIME)
CHECK_SYMBOL_EXISTS_OR_INLINE(_mkgmtime32 "time.h" "struct tm tm; time_t x = _mkgmtime(&tm);" HAVE__MKGMTIME32)
CHECK_SYMBOL_EXISTS_OR_INLINE(_mkgmtime64 "time.h" "struct tm tm; time_t x = _mkgmtime64(&tm);" HAVE__MKGMTIME64)
ENDIF(NOT HAVE_TIMEGM)
IF(NOT HAVE_TIMEGM AND NOT HAVE__MKGMTIME AND NOT HAVE__MKGMTIME32 AND NOT HAVE__MKGMTIME64)
MESSAGE(FATAL_ERROR "timegm() or equivalent function not found.")
ENDIF(NOT HAVE_TIMEGM AND NOT HAVE__MKGMTIME AND NOT HAVE__MKGMTIME32 AND NOT HAVE__MKGMTIME64)
# Write the libc configuration file.
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.libc.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.libc.h")
# C++11 compatibility header.
# NOTE: This must be included regardless of C++11 support in the compiler.
# gcc-4.6 supports some C++11, but is missing explicit virtual overrides.

View File

@ -1,20 +1,8 @@
/***************************************************************************
* c99-compat.msvcrt.h: C99 compatibility header. (MSVC) *
* *
* Copyright (c) 2011-2018 by David Korth. *
* *
* This program 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 2 of the License, or (at your *
* option) any later version. *
* *
* This program 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 details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* Copyright (c) 2011-2022 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
#ifndef __C99_COMPAT_MSVCRT_H__
@ -116,20 +104,6 @@
# define wcsncasecmp(s1, s2, n) _wcsnicmp(s1, s2, n)
#endif
/** timegm() **/
/**
* Linux, Mac OS X, and other Unix-like operating systems have a
* function timegm() that converts `struct tm` to `time_t`.
*
* MSVCRT's equivalent function is _mkgmtime().
*
* NOTE: timegm() is NOT part of *any* standard!
*/
#ifndef timegm
# define timegm(tm) _mkgmtime(tm)
#endif
/** strtok_r() **/
// MSVC has strtok_s(), which is basically the same as strtok_r().

38
src/config.libc.h.in Normal file
View File

@ -0,0 +1,38 @@
/***************************************************************************
* RVT-H Tool *
* config.libc.h.in: Common libc function detection. (source file) *
* *
* Copyright (c) 2016-2022 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
#ifndef __RVTHTOOL_CONFIG_LIBC_H__
#define __RVTHTOOL_CONFIG_LIBC_H__
/** Time functions **/
/* Define to 1 if you have the `gmtime_r` function. */
#cmakedefine HAVE_GMTIME_R 1
/* Define to 1 if you have the `gmtime_s` function. */
#cmakedefine HAVE_GMTIME_S 1
/* Define to 1 if you have the `localtime_r' function. */
#cmakedefine HAVE_LOCALTIME_R 1
/* Define to 1 if you have the `localtime_s' function. */
#cmakedefine HAVE_LOCALTIME_S 1
/* Define to 1 if you have the `timegm' function. */
#cmakedefine HAVE_TIMEGM 1
/* Define to 1 if you have the `_mkgmtime' function. */
#cmakedefine HAVE__MKGMTIME 1
/* Define to 1 if you have the `_mkgmtime32' function. */
#cmakedefine HAVE__MKGMTIME32 1
/* Define to 1 if you have the `_mkgmtime64' function. */
#cmakedefine HAVE__MKGMTIME64 1
#endif /* __RVTHTOOL_CONFIG_LIBC_H__ */

View File

@ -2,20 +2,8 @@
* RVT-H Tool (librvth) *
* recrypt.cpp: RVT-H "recryption" functions. *
* *
* Copyright (c) 2018-2019 by David Korth. *
* *
* This program 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 2 of the License, or (at your *
* option) any later version. *
* *
* This program 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 details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* Copyright (c) 2018-2022 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
#include "rvth.hpp"
@ -119,9 +107,8 @@ static int rvth_create_id(uint8_t *id, size_t size,
// Clear the buffer.
memset(buf, 0xFF, sizeof(buf));
// TODO: gmtime_r(), localtime_r()
tmbuf_utc = *gmtime(&now);
tmbuf_local = *localtime(&now);
gmtime_r(&now, &tmbuf_utc);
localtime_r(&now, &tmbuf_local);
// Timezone offset.
tzoffset = ((tmbuf_local.tm_hour * 60) + (tmbuf_local.tm_min)) -

View File

@ -19,6 +19,8 @@
#include "libwiicrypto/cert.h"
#include "libwiicrypto/cert_store.h"
#include "time_r.h"
// C includes.
#include <assert.h>
#include <ctype.h>
@ -134,7 +136,8 @@ int RvtH::openGcm(RefFile *f_img)
{
time_t mtime = f_img->mtime();
if (mtime != -1) {
mtime = timegm(localtime(&mtime));
struct tm tmbuf_local;
mtime = timegm(localtime_r(&mtime, &tmbuf_local));
}
entry->timestamp = mtime;
}

View File

@ -2,25 +2,16 @@
* RVT-H Tool (librvth) *
* rvth_time.c: RVT-H timestamp functions. *
* *
* Copyright (c) 2018 by David Korth. *
* *
* This program 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 2 of the License, or (at your *
* option) any later version. *
* *
* This program 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 details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* Copyright (c) 2018-2022 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
#include "rvth_time.h"
#include "libwiicrypto/common.h"
#include "time_r.h"
// C includes
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
@ -120,8 +111,7 @@ int rvth_timestamp_create(char *buf, size_t size, time_t now)
size = 14;
}
// TODO: Use localtime_r().
tm_now = *localtime(&now);
localtime_r(&now, &tm_now);
snprintf(tsbuf, sizeof(tsbuf), "%04d%02d%02d%02d%02d%02d",
tm_now.tm_year+1900, tm_now.tm_mon+1, tm_now.tm_mday,
tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec);

View File

@ -2,7 +2,7 @@
* RVT-H Tool *
* list-banks.cpp: List banks in an RVT-H disk image. *
* *
* Copyright (c) 2018-2020 by David Korth. *
* Copyright (c) 2018-2022 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
@ -16,6 +16,8 @@
#include "libwiicrypto/gcn_structs.h"
#include "libwiicrypto/sig_tools.h"
#include "time_r.h"
// C includes. (C++ namespace)
#include <cassert>
#include <cerrno>
@ -131,9 +133,9 @@ int print_bank(const RvtH *rvth, unsigned int bank)
}
// Print the timestamp.
// TODO: Reentrant gmtime() if available.
if (entry->timestamp != -1) {
struct tm timestamp = *gmtime(&entry->timestamp);
struct tm timestamp;
gmtime_r(&entry->timestamp, &timestamp);
printf("- Timestamp: %04d/%02d/%02d %02d:%02d:%02d\n",
timestamp.tm_year + 1900, timestamp.tm_mon + 1, timestamp.tm_mday,
timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec);

90
src/time_r.h Normal file
View File

@ -0,0 +1,90 @@
/***************************************************************************
* RVT-H Tool *
* time_r.h: Workaround for missing time functions. *
* *
* Copyright (c) 2017-2022 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
#ifndef __RVTHTOOL_TIME_R_H__
#define __RVTHTOOL_TIME_R_H__
#include "config.libc.h"
// _POSIX_C_SOURCE is required for *_r() on MinGW-w64.
// However, this breaks snprintf() on FreeBSD when using clang/libc++,
// so only define it on Windows.
// Reference: https://github.com/pocoproject/poco/issues/1045#issuecomment-245987081
#ifdef _WIN32
# ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 1
# endif
#endif /* _WIN32 */
#include <time.h>
#ifndef HAVE_GMTIME_R
static inline struct tm *gmtime_r(const time_t *timep, struct tm *result)
{
#ifdef HAVE_GMTIME_S
return (gmtime_s(result, timep) == 0 ? result : NULL);
#else /* !HAVE_GMTIME_S */
// cppcheck-suppress gmtimeCalled
struct tm *tm = gmtime(timep);
if (tm && result) {
*result = *tm;
return result;
}
return NULL;
#endif /* GMTIME_S */
}
#endif /* HAVE_GMTIME_R */
#ifndef HAVE_LOCALTIME_R
static inline struct tm *localtime_r(const time_t *timep, struct tm *result)
{
#ifdef HAVE_LOCALTIME_S
return (localtime_s(result, timep) == 0 ? result : NULL);
#else /* !HAVE_LOCALTIME_S */
// cppcheck-suppress localtimeCalled
struct tm *tm = localtime(timep);
if (tm && result) {
*result = *tm;
return result;
}
return NULL;
#endif /* HAVE_LOCALTIME_S */
}
#endif /* HAVE_LOCALTIME_R */
/** timegm() **/
/**
* Linux, Mac OS X, and other Unix-like operating systems have a
* function timegm() that converts `struct tm` to `time_t`.
*
* MSVCRT's equivalent function is _mkgmtime(). Note that it might
* write to the original `struct tm`, so we'll need to make a copy.
*
* NOTE: timegm() is NOT part of *any* standard!
*/
#if !defined(HAVE_TIMEGM)
static inline time_t timegm(struct tm *tm)
{
struct tm my_tm;
my_tm = *tm;
#if defined(HAVE__MKGMTIME64)
# define USING_MSVCRT_MKGMTIME 1
return _mkgmtime64(&my_tm);
#elif defined(HAVE__MKGMTIME32)
# define USING_MSVCRT_MKGMTIME 1
return _mkgmtime32(&my_tm);
#elif defined(HAVE__MKGMTIME)
# define USING_MSVCRT_MKGMTIME 1
return _mkgmtime(&my_tm);
#else
# error timegm() or equivalent function not found.
#endif
}
#endif /* !HAVE_TIMEGM */
#endif /* __ROMPROPERTIES_TIME_R_H__ */