curlx: add curlx_winapi_ functions

Split them out from lib/strerror. Used by test code.

Closes #17299
This commit is contained in:
Daniel Stenberg 2025-05-09 10:21:53 +02:00
parent 9468503330
commit c74d3e10d2
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
9 changed files with 193 additions and 110 deletions

View File

@ -31,7 +31,8 @@ LIB_CURLX_CFILES = \
curlx/timediff.c \
curlx/timeval.c \
curlx/version_win32.c \
curlx/warnless.c
curlx/warnless.c \
curlx/winapi.c
LIB_CURLX_HFILES = \
curlx/base64.h \
@ -43,7 +44,8 @@ LIB_CURLX_HFILES = \
curlx/timediff.h \
curlx/timeval.h \
curlx/version_win32.h \
curlx/warnless.h
curlx/warnless.h \
curlx/winapi.h
LIB_VAUTH_CFILES = \
vauth/cleartext.c \

View File

@ -65,4 +65,7 @@
#include "timeval.h"
#include "timediff.h"
#include "winapi.h"
/* for curlx_winapi_strerror */
#endif /* HEADER_CURL_CURLX_H */

135
lib/curlx/winapi.c Normal file
View File

@ -0,0 +1,135 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "../curl_setup.h"
/*
* curlx_winapi_strerror:
* Variant of Curl_strerror if the error code is definitely Windows API.
*/
#ifdef _WIN32
#include "winapi.h"
#ifdef BUILDING_LIBCURL
#include <curl/mprintf.h>
#define SNPRINTF curl_msnprintf
#else
/* when built for the test servers */
/* adjust for old MSVC */
#if defined(_MSC_VER) && (_MSC_VER < 1900)
# define SNPRINTF _snprintf
#else
#define SNPRINTF snprintf
#endif
#endif /* !BUILDING_LIBCURL */
#ifdef _WIN32
/* This is a helper function for Curl_strerror that converts Windows API error
* codes (GetLastError) to error messages.
* Returns NULL if no error message was found for error code.
*/
const char *curlx_get_winapi_error(int err, char *buf, size_t buflen)
{
char *p;
wchar_t wbuf[256];
if(!buflen)
return NULL;
*buf = '\0';
*wbuf = L'\0';
/* We return the local codepage version of the error string because if it is
output to the user's terminal it will likely be with functions which
expect the local codepage (eg fprintf, failf, infof).
FormatMessageW -> wcstombs is used for Windows CE compatibility. */
if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
LANG_NEUTRAL, wbuf, CURL_ARRAYSIZE(wbuf), NULL)) {
size_t written = wcstombs(buf, wbuf, buflen - 1);
if(written != (size_t)-1)
buf[written] = '\0';
else
*buf = '\0';
}
/* Truncate multiple lines */
p = strchr(buf, '\n');
if(p) {
if(p > buf && *(p-1) == '\r')
*(p-1) = '\0';
else
*p = '\0';
}
return *buf ? buf : NULL;
}
#endif /* _WIN32 */
const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen)
{
#ifdef PRESERVE_WINDOWS_ERROR_CODE
DWORD old_win_err = GetLastError();
#endif
int old_errno = errno;
if(!buflen)
return NULL;
*buf = '\0';
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(!curlx_get_winapi_error((int)err, buf, buflen)) {
#if defined(__GNUC__) && __GNUC__ >= 7
#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-Wformat-truncation=1"
#endif
/* some GCC compilers cause false positive warnings if we allow this
warning */
SNPRINTF(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
#if defined(__GNUC__) && __GNUC__ >= 7
#pragma GCC diagnostic pop
#endif
}
#else
{
const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
if(strlen(txt) < buflen)
strcpy(buf, txt);
}
#endif
if(errno != old_errno)
CURL_SETERRNO(old_errno);
#ifdef PRESERVE_WINDOWS_ERROR_CODE
if(old_win_err != GetLastError())
SetLastError(old_win_err);
#endif
return buf;
}
#endif /* _WIN32 */

33
lib/curlx/winapi.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef HEADER_CURLX_WINAPI_H
#define HEADER_CURLX_WINAPI_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#ifdef _WIN32
#define WINAPI_ERROR_LEN 100
const char *curlx_get_winapi_error(int err, char *buf, size_t buflen);
const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen);
#endif
#endif /* HEADER_CURLX_WINAPI_H */

View File

@ -42,6 +42,7 @@
#include "curl_sspi.h"
#endif
#include "curlx/winapi.h"
#include "strerror.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -782,50 +783,6 @@ get_winsock_error(int err, char *buf, size_t len)
}
#endif /* USE_WINSOCK */
#ifdef _WIN32
/* This is a helper function for Curl_strerror that converts Windows API error
* codes (GetLastError) to error messages.
* Returns NULL if no error message was found for error code.
*/
static const char *
get_winapi_error(int err, char *buf, size_t buflen)
{
char *p;
wchar_t wbuf[256];
if(!buflen)
return NULL;
*buf = '\0';
*wbuf = L'\0';
/* We return the local codepage version of the error string because if it is
output to the user's terminal it will likely be with functions which
expect the local codepage (eg fprintf, failf, infof).
FormatMessageW -> wcstombs is used for Windows CE compatibility. */
if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
LANG_NEUTRAL, wbuf, CURL_ARRAYSIZE(wbuf), NULL)) {
size_t written = wcstombs(buf, wbuf, buflen - 1);
if(written != (size_t)-1)
buf[written] = '\0';
else
*buf = '\0';
}
/* Truncate multiple lines */
p = strchr(buf, '\n');
if(p) {
if(p > buf && *(p-1) == '\r')
*(p-1) = '\0';
else
*p = '\0';
}
return *buf ? buf : NULL;
}
#endif /* _WIN32 */
/*
* Our thread-safe and smart strerror() replacement.
*
@ -872,9 +829,9 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
{
if(
#ifdef USE_WINSOCK
!get_winsock_error(err, buf, buflen) &&
!get_winsock_error(err, buf, buflen) &&
#endif
!get_winapi_error(err, buf, buflen))
!curlx_get_winapi_error(err, buf, buflen))
curl_msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
}
#else /* not Windows coming up */
@ -935,47 +892,6 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
return buf;
}
/*
* curlx_winapi_strerror:
* Variant of Curl_strerror if the error code is definitely Windows API.
*/
#ifdef _WIN32
const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen)
{
#ifdef PRESERVE_WINDOWS_ERROR_CODE
DWORD old_win_err = GetLastError();
#endif
int old_errno = errno;
if(!buflen)
return NULL;
*buf = '\0';
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(!get_winapi_error((int)err, buf, buflen)) {
curl_msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
}
#else
{
const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
if(strlen(txt) < buflen)
strcpy(buf, txt);
}
#endif
if(errno != old_errno)
CURL_SETERRNO(old_errno);
#ifdef PRESERVE_WINDOWS_ERROR_CODE
if(old_win_err != GetLastError())
SetLastError(old_win_err);
#endif
return buf;
}
#endif /* _WIN32 */
#ifdef USE_WINDOWS_SSPI
/*
* Curl_sspi_strerror:
@ -1098,7 +1014,7 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
}
else {
char msgbuf[256];
if(get_winapi_error(err, msgbuf, sizeof(msgbuf)))
if(curlx_get_winapi_error(err, msgbuf, sizeof(msgbuf)))
curl_msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf);
else
curl_msnprintf(buf, buflen, "%s (0x%08X)", txt, err);

View File

@ -29,9 +29,6 @@
#define STRERROR_LEN 256 /* a suitable length */
const char *Curl_strerror(int err, char *buf, size_t buflen);
#ifdef _WIN32
const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen);
#endif
#ifdef USE_WINDOWS_SSPI
const char *Curl_sspi_strerror(int err, char *buf, size_t buflen);
#endif

View File

@ -44,6 +44,7 @@
#include "vtls_int.h"
#include "../sendf.h"
#include "../strerror.h"
#include "../curlx/winapi.h"
#include "../curlx/multibyte.h"
#include "../curl_printf.h"
#include "hostcheck.h"
@ -174,7 +175,7 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
NULL,
NULL,
(const void **)&cert_context)) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to extract certificate from CA file "
"'%s': %s",
@ -203,7 +204,7 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
NULL);
CertFreeCertificateContext(cert_context);
if(!add_cert_result) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to add certificate from CA file '%s' "
"to certificate store: %s",
@ -251,7 +252,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
ca_file_tstr = curlx_convert_UTF8_to_tchar(ca_file);
if(!ca_file_tstr) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: invalid path name for CA file '%s': %s",
ca_file,
@ -273,7 +274,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(ca_file_handle == INVALID_HANDLE_VALUE) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to open CA file '%s': %s",
ca_file,
@ -283,7 +284,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
}
if(!GetFileSizeEx(ca_file_handle, &file_size)) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to determine size of CA file '%s': %s",
ca_file,
@ -313,7 +314,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
bytes_to_read, &bytes_read, NULL)) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to read from CA file '%s': %s",
ca_file,
@ -614,7 +615,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
&pCertContextServer);
if((sspi_status != SEC_E_OK) || !pCertContextServer) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
goto cleanup;
@ -770,7 +771,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
&pCertContextServer);
if((sspi_status != SEC_E_OK) || !pCertContextServer) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
result = CURLE_PEER_FAILED_VERIFICATION;
@ -806,7 +807,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CERT_STORE_CREATE_NEW_FLAG,
NULL);
if(!trust_store) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: failed to create certificate store: %s",
curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
@ -853,7 +854,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CertCreateCertificateChainEngine(
(CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
if(!create_engine_result) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data,
"schannel: failed to create certificate chain engine: %s",
curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
@ -878,7 +879,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
char buffer[STRERROR_LEN];
char buffer[WINAPI_ERROR_LEN];
failf(data, "schannel: CertGetCertificateChain failed: %s",
curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
pChainContext = NULL;

View File

@ -62,8 +62,8 @@ UTIL = \
server_setup.h \
../../lib/curlx/base64.c \
../../lib/curlx/base64.h \
../../lib/strerror.c \
../../lib/strerror.h
../../lib/curlx/winapi.c \
../../lib/curlx/winapi.h
FIRSTFILES = \
first.c \

View File

@ -41,10 +41,6 @@
#include <dos.h> /* delay() */
#endif
#ifdef _WIN32
#include "strerror.h"
#endif
#include <curlx.h> /* from the private lib dir */
#include "util.h"