build: avoid overriding system symbols for fopen functions

By introducing wrappers for them in the curlx namespace:
`curlx_fopen()`, `curlx_fdopen()`, `curlx_fclose()`.

The undefine/redefine/`(function)()` methods broke on systems
implementing these functions as macros. E.g. AIX 32-bit's `fopen()`.

Also:
- rename `lib/fopen.*` to `lib/curl_fopen.*` (for `Curl_fopen()`)
  to make room for the newly added `curlx/fopen.h`.
- curlx: move file-related functions from `multibyte.c` to `fopen.c`.
- tests/server: stop using the curl-specific `fopen()` implementation
  on Windows. Unicode isn't used by runtests, and it isn't critical to
  run tests on longs path. It can be re-enabled if this becomes
  necessary, or if the wrapper receives a feature that's critical for
  test servers.

Reported-by: Andrew Kirillov
Bug: https://github.com/curl/curl/issues/18510#issuecomment-3274393640

Follow-up to bf7375ecc5 #18503
Follow-up to 9863599d69 #18502
Follow-up to 3bb5e58c10 #17827

Closes #18634
This commit is contained in:
Viktor Szakats 2025-09-14 15:34:18 +02:00
parent 10bac43b87
commit 20142f5d06
No known key found for this signature in database
GPG key ID: B5ABD165E2AEF201
65 changed files with 568 additions and 484 deletions

View file

@ -26,6 +26,7 @@
LIB_CURLX_CFILES = \
curlx/base64.c \
curlx/dynbuf.c \
curlx/fopen.c \
curlx/inet_ntop.c \
curlx/inet_pton.c \
curlx/multibyte.c \
@ -43,6 +44,7 @@ LIB_CURLX_HFILES = \
curlx/base64.h \
curlx/curlx.h \
curlx/dynbuf.h \
curlx/fopen.h \
curlx/inet_ntop.h \
curlx/inet_pton.h \
curlx/multibyte.h \
@ -157,6 +159,7 @@ LIB_CFILES = \
curl_des.c \
curl_endian.c \
curl_fnmatch.c \
curl_fopen.c \
curl_get_line.c \
curl_gethostname.c \
curl_gssapi.c \
@ -181,7 +184,6 @@ LIB_CFILES = \
fake_addrinfo.c \
file.c \
fileinfo.c \
fopen.c \
formdata.c \
ftp.c \
ftplistparser.c \
@ -286,6 +288,7 @@ LIB_HFILES = \
curl_des.h \
curl_endian.h \
curl_fnmatch.h \
curl_fopen.h \
curl_get_line.h \
curl_gethostname.h \
curl_gssapi.h \
@ -320,7 +323,6 @@ LIB_HFILES = \
fake_addrinfo.h \
file.h \
fileinfo.h \
fopen.h \
formdata.h \
ftp.h \
ftplistparser.h \

View file

@ -31,11 +31,11 @@
#include <curl/curl.h>
#include "urldata.h"
#include "altsvc.h"
#include "curl_fopen.h"
#include "curl_get_line.h"
#include "parsedate.h"
#include "sendf.h"
#include "curlx/warnless.h"
#include "fopen.h"
#include "rename.h"
#include "strdup.h"
#include "curlx/inet_pton.h"
@ -227,7 +227,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
if(!asi->filename)
return CURLE_OUT_OF_MEMORY;
fp = fopen(file, FOPEN_READTEXT);
fp = curlx_fopen(file, FOPEN_READTEXT);
if(fp) {
struct dynbuf buf;
curlx_dyn_init(&buf, MAX_ALTSVC_LINE);
@ -238,7 +238,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
altsvc_add(asi, lineptr);
}
curlx_dyn_free(&buf); /* free the line buffer */
fclose(fp);
curlx_fclose(fp);
}
return result;
}
@ -391,7 +391,7 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
if(result)
break;
}
fclose(out);
curlx_fclose(out);
if(!result && tempstore && Curl_rename(tempstore, file))
result = CURLE_WRITE_ERROR;

View file

@ -80,11 +80,11 @@ Example set of cookies:
#include "slist.h"
#include "share.h"
#include "strcase.h"
#include "curl_fopen.h"
#include "curl_get_line.h"
#include "curl_memrchr.h"
#include "parsedate.h"
#include "rename.h"
#include "fopen.h"
#include "strdup.h"
#include "llist.h"
#include "curlx/strparse.h"
@ -1195,7 +1195,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
if(!strcmp(file, "-"))
fp = stdin;
else {
fp = fopen(file, "rb");
fp = curlx_fopen(file, "rb");
if(!fp)
infof(data, "WARNING: failed to open cookie file \"%s\"", file);
else
@ -1228,7 +1228,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
remove_expired(ci);
if(handle)
fclose(handle);
curlx_fclose(handle);
}
data->state.cookie_engine = TRUE;
}
@ -1583,7 +1583,7 @@ static CURLcode cookie_output(struct Curl_easy *data,
}
if(!use_stdout) {
fclose(out);
curlx_fclose(out);
out = NULL;
if(tempstore && Curl_rename(tempstore, filename)) {
unlink(tempstore);
@ -1602,7 +1602,7 @@ static CURLcode cookie_output(struct Curl_easy *data,
error:
if(out && !use_stdout)
fclose(out);
curlx_fclose(out);
free(tempstore);
return error;
}

View file

@ -33,7 +33,7 @@
#include "urldata.h"
#include "rand.h"
#include "fopen.h"
#include "curl_fopen.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -102,7 +102,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
char *dir = NULL;
*tempname = NULL;
*fh = fopen(filename, FOPEN_WRITETEXT);
*fh = curlx_fopen(filename, FOPEN_WRITETEXT);
if(!*fh)
goto fail;
if(
@ -114,7 +114,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|| !S_ISREG(sb.st_mode)) {
return CURLE_OK;
}
fclose(*fh);
curlx_fclose(*fh);
*fh = NULL;
result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
@ -144,7 +144,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
if(fd == -1)
goto fail;
*fh = fdopen(fd, FOPEN_WRITETEXT);
*fh = curlx_fdopen(fd, FOPEN_WRITETEXT);
if(!*fh)
goto fail;

View file

@ -24,6 +24,8 @@
*
***************************************************************************/
#include "curlx/fopen.h"
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
FILE **fh, char **tempname);

View file

@ -33,16 +33,5 @@
#undef Curl_tcsdup
#endif
#ifdef CURLDEBUG
#undef fopen
#ifdef CURL_FOPEN
#define fopen(fname, mode) CURL_FOPEN(fname, mode)
#endif
#undef fdopen
#undef fclose
#endif /* CURLDEBUG */
#undef HEADER_CURL_MEMORY_H
#undef HEADER_CURL_MEMDEBUG_H

View file

@ -509,11 +509,8 @@
# ifndef UNDER_CE
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
# define stat(fname, stp) curlx_win32_stat(fname, stp)
# define open curlx_win32_open
# define CURL_FOPEN(fname, mode) curlx_win32_fopen(fname, mode)
# define fopen(fname, mode) CURL_FOPEN(fname, mode)
# endif
#elif defined(__DJGPP__)
/* Requires DJGPP 2.04 */

View file

@ -64,6 +64,9 @@
#include "dynbuf.h"
/* The curlx_dyn_* functions */
#include "fopen.h"
/* The curlx_f* functions */
#include "base64.h"
#include "timeval.h"
#include "timediff.h"

310
lib/curlx/fopen.c Normal file
View file

@ -0,0 +1,310 @@
/***************************************************************************
* _ _ ____ _
* 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
*
***************************************************************************/
/*
* This file is 'mem-include-scan' clean, which means its memory allocations
* are not tracked by the curl memory tracker memdebug, so they must not use
* `CURLDEBUG` macro replacements in memdebug.h for free, malloc, etc. To avoid
* these macro replacements, wrap the names in parentheses to call the original
* versions: `ptr = (malloc)(123)`, `(free)(ptr)`, etc.
*/
#include "../curl_setup.h"
#if defined(_WIN32) && !defined(UNDER_CE)
#include "fopen.h"
#include "multibyte.h"
/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
(_WIN32_WINNT < _WIN32_WINNT_WIN10)
WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
#endif
/* Fix excessive paths (paths that exceed MAX_PATH length of 260).
*
* This is a helper function to fix paths that would exceed the MAX_PATH
* limitation check done by Windows APIs. It does so by normalizing the passed
* in filename or path 'in' to its full canonical path, and if that path is
* longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path.
*
* For example 'in' filename255chars in current directory C:\foo\bar is
* fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows
* it is ok to access that filename even though the actual full path is longer
* than 260 chars.
*
* For non-Unicode builds this function may fail sometimes because only the
* Unicode versions of some Windows API functions can access paths longer than
* MAX_PATH, for example GetFullPathNameW which is used in this function. When
* the full path is then converted from Unicode to multibyte that fails if any
* directories in the path contain characters not in the current codepage.
*/
static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
{
size_t needed, count;
const wchar_t *in_w;
wchar_t *fbuf = NULL;
/* MS documented "approximate" limit for the maximum path length */
const size_t max_path_len = 32767;
#ifndef _UNICODE
wchar_t *ibuf = NULL;
char *obuf = NULL;
#endif
*out = NULL;
/* skip paths already normalized */
if(!_tcsncmp(in, _T("\\\\?\\"), 4))
goto cleanup;
#ifndef _UNICODE
/* convert multibyte input to unicode */
needed = mbstowcs(NULL, in, 0);
if(needed == (size_t)-1 || needed >= max_path_len)
goto cleanup;
++needed; /* for NUL */
ibuf = (malloc)(needed * sizeof(wchar_t));
if(!ibuf)
goto cleanup;
count = mbstowcs(ibuf, in, needed);
if(count == (size_t)-1 || count >= needed)
goto cleanup;
in_w = ibuf;
#else
in_w = in;
#endif
/* GetFullPathNameW returns the normalized full path in unicode. It converts
forward slashes to backslashes, processes .. to remove directory segments,
etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */
needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL);
if(!needed || needed > max_path_len)
goto cleanup;
/* skip paths that are not excessive and do not need modification */
if(needed <= MAX_PATH)
goto cleanup;
fbuf = (malloc)(needed * sizeof(wchar_t));
if(!fbuf)
goto cleanup;
count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
if(!count || count >= needed)
goto cleanup;
/* prepend \\?\ or \\?\UNC\ to the excessively long path.
*
* c:\longpath ---> \\?\c:\longpath
* \\.\c:\longpath ---> \\?\c:\longpath
* \\?\c:\longpath ---> \\?\c:\longpath (unchanged)
* \\server\c$\longpath ---> \\?\UNC\server\c$\longpath
*
* https://learn.microsoft.com/dotnet/standard/io/file-path-formats
*/
if(!wcsncmp(fbuf, L"\\\\?\\", 4))
; /* do nothing */
else if(!wcsncmp(fbuf, L"\\\\.\\", 4))
fbuf[2] = '?';
else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) {
/* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */
goto cleanup;
}
else {
wchar_t *temp;
if(!wcsncmp(fbuf, L"\\\\", 2)) {
/* "\\?\UNC\" + full path without "\\" + null */
needed = 8 + (count - 2) + 1;
if(needed > max_path_len)
goto cleanup;
temp = (malloc)(needed * sizeof(wchar_t));
if(!temp)
goto cleanup;
wcsncpy(temp, L"\\\\?\\UNC\\", 8);
wcscpy(temp + 8, fbuf + 2);
}
else {
/* "\\?\" + full path + null */
needed = 4 + count + 1;
if(needed > max_path_len)
goto cleanup;
temp = (malloc)(needed * sizeof(wchar_t));
if(!temp)
goto cleanup;
wcsncpy(temp, L"\\\\?\\", 4);
wcscpy(temp + 4, fbuf);
}
(free)(fbuf);
fbuf = temp;
}
#ifndef _UNICODE
/* convert unicode full path to multibyte output */
needed = wcstombs(NULL, fbuf, 0);
if(needed == (size_t)-1 || needed >= max_path_len)
goto cleanup;
++needed; /* for NUL */
obuf = (malloc)(needed);
if(!obuf)
goto cleanup;
count = wcstombs(obuf, fbuf, needed);
if(count == (size_t)-1 || count >= needed)
goto cleanup;
*out = obuf;
obuf = NULL;
#else
*out = fbuf;
fbuf = NULL;
#endif
cleanup:
(free)(fbuf);
#ifndef _UNICODE
(free)(ibuf);
(free)(obuf);
#endif
return *out ? true : false;
}
int curlx_win32_open(const char *filename, int oflag, ...)
{
int pmode = 0;
int result = -1;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
#endif
va_list param;
va_start(param, oflag);
if(oflag & O_CREAT)
pmode = va_arg(param, int);
va_end(param);
#ifdef _UNICODE
if(filename_w) {
if(fix_excessive_path(filename_w, &fixed))
target = fixed;
else
target = filename_w;
result = _wopen(target, oflag, pmode);
curlx_unicodefree(filename_w);
}
else
/* !checksrc! disable ERRNOVAR 1 */
CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
else
target = filename;
result = _open(target, oflag, pmode);
#endif
(free)(fixed);
return result;
}
FILE *curlx_win32_fopen(const char *filename, const char *mode)
{
FILE *result = NULL;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
if(filename_w && mode_w) {
if(fix_excessive_path(filename_w, &fixed))
target = fixed;
else
target = filename_w;
result = _wfopen(target, mode_w);
}
else
/* !checksrc! disable ERRNOVAR 1 */
CURL_SETERRNO(EINVAL);
curlx_unicodefree(filename_w);
curlx_unicodefree(mode_w);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
else
target = filename;
/* !checksrc! disable BANNEDFUNC 1 */
result = fopen(target, mode);
#endif
(free)(fixed);
return result;
}
int curlx_win32_stat(const char *path, struct_stat *buffer)
{
int result = -1;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
if(path_w) {
if(fix_excessive_path(path_w, &fixed))
target = fixed;
else
target = path_w;
#ifndef USE_WIN32_LARGE_FILES
result = _wstat(target, buffer);
#else
result = _wstati64(target, buffer);
#endif
curlx_unicodefree(path_w);
}
else
/* !checksrc! disable ERRNOVAR 1 */
CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(path, &fixed))
target = fixed;
else
target = path;
#ifndef USE_WIN32_LARGE_FILES
result = _stat(target, buffer);
#else
result = _stati64(target, buffer);
#endif
#endif
(free)(fixed);
return result;
}
#endif /* _WIN32 && !UNDER_CE */

48
lib/curlx/fopen.h Normal file
View file

@ -0,0 +1,48 @@
#ifndef HEADER_CURLX_FOPEN_H
#define HEADER_CURLX_FOPEN_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
*
***************************************************************************/
#include "../curl_setup.h"
#include "multibyte.h"
#if defined(_WIN32) && !defined(UNDER_CE)
FILE *curlx_win32_fopen(const char *filename, const char *mode);
#define CURLX_FOPEN_LOW(fname, mode) curlx_win32_fopen(fname, mode)
#else
#define CURLX_FOPEN_LOW fopen
#endif
#ifdef CURLDEBUG
#define curlx_fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__)
#define curlx_fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__)
#define curlx_fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__)
#else
#define curlx_fopen CURLX_FOPEN_LOW
#define curlx_fdopen fdopen
#define curlx_fclose fclose
#endif
#endif /* HEADER_CURLX_FOPEN_H */

View file

@ -84,277 +84,4 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
return str_utf8;
}
#ifndef UNDER_CE
/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
(_WIN32_WINNT < _WIN32_WINNT_WIN10)
WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
#endif
/* Fix excessive paths (paths that exceed MAX_PATH length of 260).
*
* This is a helper function to fix paths that would exceed the MAX_PATH
* limitation check done by Windows APIs. It does so by normalizing the passed
* in filename or path 'in' to its full canonical path, and if that path is
* longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path.
*
* For example 'in' filename255chars in current directory C:\foo\bar is
* fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows
* it is ok to access that filename even though the actual full path is longer
* than 260 chars.
*
* For non-Unicode builds this function may fail sometimes because only the
* Unicode versions of some Windows API functions can access paths longer than
* MAX_PATH, for example GetFullPathNameW which is used in this function. When
* the full path is then converted from Unicode to multibyte that fails if any
* directories in the path contain characters not in the current codepage.
*/
static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
{
size_t needed, count;
const wchar_t *in_w;
wchar_t *fbuf = NULL;
/* MS documented "approximate" limit for the maximum path length */
const size_t max_path_len = 32767;
#ifndef _UNICODE
wchar_t *ibuf = NULL;
char *obuf = NULL;
#endif
*out = NULL;
/* skip paths already normalized */
if(!_tcsncmp(in, _T("\\\\?\\"), 4))
goto cleanup;
#ifndef _UNICODE
/* convert multibyte input to unicode */
needed = mbstowcs(NULL, in, 0);
if(needed == (size_t)-1 || needed >= max_path_len)
goto cleanup;
++needed; /* for NUL */
ibuf = (malloc)(needed * sizeof(wchar_t));
if(!ibuf)
goto cleanup;
count = mbstowcs(ibuf, in, needed);
if(count == (size_t)-1 || count >= needed)
goto cleanup;
in_w = ibuf;
#else
in_w = in;
#endif
/* GetFullPathNameW returns the normalized full path in unicode. It converts
forward slashes to backslashes, processes .. to remove directory segments,
etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */
needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL);
if(!needed || needed > max_path_len)
goto cleanup;
/* skip paths that are not excessive and do not need modification */
if(needed <= MAX_PATH)
goto cleanup;
fbuf = (malloc)(needed * sizeof(wchar_t));
if(!fbuf)
goto cleanup;
count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
if(!count || count >= needed)
goto cleanup;
/* prepend \\?\ or \\?\UNC\ to the excessively long path.
*
* c:\longpath ---> \\?\c:\longpath
* \\.\c:\longpath ---> \\?\c:\longpath
* \\?\c:\longpath ---> \\?\c:\longpath (unchanged)
* \\server\c$\longpath ---> \\?\UNC\server\c$\longpath
*
* https://learn.microsoft.com/dotnet/standard/io/file-path-formats
*/
if(!wcsncmp(fbuf, L"\\\\?\\", 4))
; /* do nothing */
else if(!wcsncmp(fbuf, L"\\\\.\\", 4))
fbuf[2] = '?';
else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) {
/* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */
goto cleanup;
}
else {
wchar_t *temp;
if(!wcsncmp(fbuf, L"\\\\", 2)) {
/* "\\?\UNC\" + full path without "\\" + null */
needed = 8 + (count - 2) + 1;
if(needed > max_path_len)
goto cleanup;
temp = (malloc)(needed * sizeof(wchar_t));
if(!temp)
goto cleanup;
wcsncpy(temp, L"\\\\?\\UNC\\", 8);
wcscpy(temp + 8, fbuf + 2);
}
else {
/* "\\?\" + full path + null */
needed = 4 + count + 1;
if(needed > max_path_len)
goto cleanup;
temp = (malloc)(needed * sizeof(wchar_t));
if(!temp)
goto cleanup;
wcsncpy(temp, L"\\\\?\\", 4);
wcscpy(temp + 4, fbuf);
}
(free)(fbuf);
fbuf = temp;
}
#ifndef _UNICODE
/* convert unicode full path to multibyte output */
needed = wcstombs(NULL, fbuf, 0);
if(needed == (size_t)-1 || needed >= max_path_len)
goto cleanup;
++needed; /* for NUL */
obuf = (malloc)(needed);
if(!obuf)
goto cleanup;
count = wcstombs(obuf, fbuf, needed);
if(count == (size_t)-1 || count >= needed)
goto cleanup;
*out = obuf;
obuf = NULL;
#else
*out = fbuf;
fbuf = NULL;
#endif
cleanup:
(free)(fbuf);
#ifndef _UNICODE
(free)(ibuf);
(free)(obuf);
#endif
return *out ? true : false;
}
int curlx_win32_open(const char *filename, int oflag, ...)
{
int pmode = 0;
int result = -1;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
#endif
va_list param;
va_start(param, oflag);
if(oflag & O_CREAT)
pmode = va_arg(param, int);
va_end(param);
#ifdef _UNICODE
if(filename_w) {
if(fix_excessive_path(filename_w, &fixed))
target = fixed;
else
target = filename_w;
result = _wopen(target, oflag, pmode);
curlx_unicodefree(filename_w);
}
else
/* !checksrc! disable ERRNOVAR 1 */
CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
else
target = filename;
result = _open(target, oflag, pmode);
#endif
(free)(fixed);
return result;
}
FILE *curlx_win32_fopen(const char *filename, const char *mode)
{
FILE *result = NULL;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
if(filename_w && mode_w) {
if(fix_excessive_path(filename_w, &fixed))
target = fixed;
else
target = filename_w;
result = _wfopen(target, mode_w);
}
else
/* !checksrc! disable ERRNOVAR 1 */
CURL_SETERRNO(EINVAL);
curlx_unicodefree(filename_w);
curlx_unicodefree(mode_w);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
else
target = filename;
result = (fopen)(target, mode);
#endif
(free)(fixed);
return result;
}
int curlx_win32_stat(const char *path, struct_stat *buffer)
{
int result = -1;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
if(path_w) {
if(fix_excessive_path(path_w, &fixed))
target = fixed;
else
target = path_w;
#ifndef USE_WIN32_LARGE_FILES
result = _wstat(target, buffer);
#else
result = _wstati64(target, buffer);
#endif
curlx_unicodefree(path_w);
}
else
/* !checksrc! disable ERRNOVAR 1 */
CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(path, &fixed))
target = fixed;
else
target = path;
#ifndef USE_WIN32_LARGE_FILES
result = _stat(target, buffer);
#else
result = _stati64(target, buffer);
#endif
#endif
(free)(fixed);
return result;
}
#endif /* UNDER_CE */
#endif /* _WIN32 */

View file

@ -32,10 +32,10 @@
#include "urldata.h"
#include "llist.h"
#include "hsts.h"
#include "curl_fopen.h"
#include "curl_get_line.h"
#include "sendf.h"
#include "parsedate.h"
#include "fopen.h"
#include "rename.h"
#include "share.h"
#include "strdup.h"
@ -379,7 +379,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
if(result)
break;
}
fclose(out);
curlx_fclose(out);
if(!result && tempstore && Curl_rename(tempstore, file))
result = CURLE_WRITE_ERROR;
@ -524,7 +524,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
if(!h->filename)
return CURLE_OUT_OF_MEMORY;
fp = fopen(file, FOPEN_READTEXT);
fp = curlx_fopen(file, FOPEN_READTEXT);
if(fp) {
struct dynbuf buf;
curlx_dyn_init(&buf, MAX_HSTS_LINE);
@ -542,7 +542,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
hsts_add(h, lineptr);
}
curlx_dyn_free(&buf); /* free the line buffer */
fclose(fp);
curlx_fclose(fp);
}
return result;
}

View file

@ -29,6 +29,7 @@
#include <curl/curl.h>
#include "urldata.h"
#include "curlx/fopen.h" /* for CURLX_FOPEN_LOW() */
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -68,7 +69,8 @@ static void curl_dbg_cleanup(void)
if(curl_dbg_logfile &&
curl_dbg_logfile != stderr &&
curl_dbg_logfile != stdout) {
(fclose)(curl_dbg_logfile);
/* !checksrc! disable BANNEDFUNC 1 */
fclose(curl_dbg_logfile);
}
curl_dbg_logfile = NULL;
}
@ -78,11 +80,7 @@ void curl_dbg_memdebug(const char *logname)
{
if(!curl_dbg_logfile) {
if(logname && *logname)
#ifdef CURL_FOPEN
curl_dbg_logfile = CURL_FOPEN(logname, FOPEN_WRITETEXT);
#else
curl_dbg_logfile = (fopen)(logname, FOPEN_WRITETEXT);
#endif
curl_dbg_logfile = CURLX_FOPEN_LOW(logname, FOPEN_WRITETEXT);
else
curl_dbg_logfile = stderr;
#ifdef MEMDEBUG_LOG_SYNC
@ -424,13 +422,7 @@ ALLOC_FUNC
FILE *curl_dbg_fopen(const char *file, const char *mode,
int line, const char *source)
{
FILE *res;
#ifdef CURL_FOPEN
res = CURL_FOPEN(file, mode);
#else
res = (fopen)(file, mode);
#endif
FILE *res = CURLX_FOPEN_LOW(file, mode);
if(source)
curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
source, line, file, mode, (void *)res);
@ -442,7 +434,8 @@ ALLOC_FUNC
FILE *curl_dbg_fdopen(int filedes, const char *mode,
int line, const char *source)
{
FILE *res = (fdopen)(filedes, mode);
/* !checksrc! disable BANNEDFUNC 1 */
FILE *res = fdopen(filedes, mode);
if(source)
curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
source, line, filedes, mode, (void *)res);
@ -459,7 +452,8 @@ int curl_dbg_fclose(FILE *file, int line, const char *source)
curl_dbg_log("FILE %s:%d fclose(%p)\n",
source, line, (void *)file);
res = (fclose)(file);
/* !checksrc! disable BANNEDFUNC 1 */
res = fclose(file);
return res;
}

View file

@ -52,12 +52,5 @@
#endif
#endif /* _WIN32 */
#undef fopen
#define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__)
#undef fdopen
#define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__)
#undef fclose
#define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__)
#endif /* CURLDEBUG */
#endif /* HEADER_CURL_MEMDEBUG_H */

View file

@ -34,6 +34,7 @@ struct Curl_easy;
#include "sendf.h"
#include "transfer.h"
#include "strdup.h"
#include "curlx/fopen.h"
#include "curlx/base64.h"
#if !defined(CURL_DISABLE_MIME) && \
@ -131,7 +132,7 @@ static const char aschex[] =
#ifndef __VMS
#define filesize(name, stat_data) (stat_data.st_size)
#define fopen_read fopen
#define fopen_read curlx_fopen
#else
@ -154,7 +155,7 @@ curl_off_t VmsRealFileSize(const char *name,
int ret_stat;
FILE * file;
file = fopen(name, FOPEN_READTEXT); /* VMS */
file = curlx_fopen(name, FOPEN_READTEXT); /* VMS */
if(!file)
return 0;
@ -165,7 +166,7 @@ curl_off_t VmsRealFileSize(const char *name,
if(ret_stat)
count += ret_stat;
}
fclose(file);
curlx_fclose(file);
return count;
}
@ -210,10 +211,10 @@ static FILE * vmsfopenread(const char *file, const char *mode)
case FAB$C_VAR:
case FAB$C_VFC:
case FAB$C_STMCR:
return fopen(file, FOPEN_READTEXT); /* VMS */
return curlx_fopen(file, FOPEN_READTEXT); /* VMS */
break;
default:
return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
return curlx_fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
}
}
@ -745,7 +746,7 @@ static void mime_file_free(void *ptr)
curl_mimepart *part = (curl_mimepart *) ptr;
if(part->fp) {
fclose(part->fp);
curlx_fclose(part->fp);
part->fp = NULL;
}
Curl_safefree(part->data);
@ -967,7 +968,7 @@ static size_t readback_part(curl_mimepart *part,
mimesetstate(&part->state, MIMESTATE_END, NULL);
/* Try sparing open file descriptors. */
if(part->kind == MIMEKIND_FILE && part->fp) {
fclose(part->fp);
curlx_fclose(part->fp);
part->fp = NULL;
}
FALLTHROUGH();

View file

@ -39,6 +39,7 @@
#include "netrc.h"
#include "strcase.h"
#include "curl_get_line.h"
#include "curlx/fopen.h"
#include "curlx/strparse.h"
/* The last 3 #include files should be in this order */
@ -76,7 +77,7 @@ enum found_state {
static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf)
{
NETRCcode ret = NETRC_FILE_MISSING; /* if it cannot open the file */
FILE *file = fopen(filename, FOPEN_READTEXT);
FILE *file = curlx_fopen(filename, FOPEN_READTEXT);
struct dynbuf linebuf;
curlx_dyn_init(&linebuf, MAX_NETRC_LINE);
@ -99,7 +100,7 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf)
done:
curlx_dyn_free(&linebuf);
if(file)
fclose(file);
curlx_fclose(file);
return ret;
}

View file

@ -54,6 +54,7 @@
#include "../progress.h"
#include "../select.h"
#include "../strdup.h"
#include "../curlx/fopen.h"
#include "../curlx/warnless.h"
#include "x509asn1.h"
#include "../multiif.h"
@ -211,7 +212,7 @@ static gnutls_datum_t load_file(const char *file)
long filelen;
void *ptr;
f = fopen(file, "rb");
f = curlx_fopen(file, "rb");
if(!f)
return loaded_file;
if(fseek(f, 0, SEEK_END) != 0
@ -227,7 +228,7 @@ static gnutls_datum_t load_file(const char *file)
loaded_file.data = ptr;
loaded_file.size = (unsigned int)filelen;
out:
fclose(f);
curlx_fclose(f);
return loaded_file;
}

View file

@ -33,6 +33,7 @@
#include "keylog.h"
#include <curl/curl.h>
#include "../escape.h"
#include "../curlx/fopen.h"
/* The last #include files should be: */
#include "../curl_memory.h"
@ -49,7 +50,7 @@ Curl_tls_keylog_open(void)
if(!keylog_file_fp) {
keylog_file_name = curl_getenv("SSLKEYLOGFILE");
if(keylog_file_name) {
keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
keylog_file_fp = curlx_fopen(keylog_file_name, FOPEN_APPENDTEXT);
if(keylog_file_fp) {
#ifdef _WIN32
if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
@ -57,7 +58,7 @@ Curl_tls_keylog_open(void)
if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
#endif
{
fclose(keylog_file_fp);
curlx_fclose(keylog_file_fp);
keylog_file_fp = NULL;
}
}
@ -70,7 +71,7 @@ void
Curl_tls_keylog_close(void)
{
if(keylog_file_fp) {
fclose(keylog_file_fp);
curlx_fclose(keylog_file_fp);
keylog_file_fp = NULL;
}
}

View file

@ -32,6 +32,7 @@
#include <rustls.h>
#include "../curlx/fopen.h"
#include "../curlx/inet_pton.h"
#include "../urldata.h"
#include "../sendf.h"
@ -397,7 +398,7 @@ static int
read_file_into(const char *filename,
struct dynbuf *out)
{
FILE *f = fopen(filename, FOPEN_READTEXT);
FILE *f = curlx_fopen(filename, FOPEN_READTEXT);
if(!f) {
return 0;
}
@ -407,14 +408,14 @@ read_file_into(const char *filename,
const size_t rr = fread(buf, 1, sizeof(buf), f);
if(rr == 0 ||
CURLE_OK != curlx_dyn_addn(out, buf, rr)) {
fclose(f);
curlx_fclose(f);
return 0;
}
if(rr < sizeof(buf))
break;
}
return fclose(f) == 0;
return curlx_fclose(f) == 0;
}
static void

View file

@ -47,6 +47,7 @@
#include "../strdup.h"
#include "../strerror.h"
#include "../select.h" /* for the socket readiness */
#include "../curlx/fopen.h"
#include "../curlx/inet_pton.h" /* for IP addr SNI check */
#include "../curlx/multibyte.h"
#include "../curlx/warnless.h"
@ -563,7 +564,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
&cert_store_path, &cert_thumbprint_str);
if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
fInCert = curlx_fopen(data->set.ssl.primary.clientcert, "rb");
if(result && !fInCert) {
failf(data, "schannel: Failed to get certificate location"
@ -611,7 +612,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
if((!certdata) ||
((int) fread(certdata, certsize, 1, fInCert) != 1))
continue_reading = FALSE;
fclose(fInCert);
curlx_fclose(fInCert);
if(!continue_reading) {
failf(data, "schannel: Failed to read cert file %s",
data->set.ssl.primary.clientcert);

View file

@ -68,6 +68,7 @@
#include "../progress.h"
#include "../share.h"
#include "../multiif.h"
#include "../curlx/fopen.h"
#include "../curlx/timeval.h"
#include "../curl_md5.h"
#include "../curl_sha256.h"
@ -803,7 +804,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
struct dynbuf buf;
char unsigned *pem_ptr = NULL;
size_t left;
FILE *fp = fopen(pinnedpubkey, "rb");
FILE *fp = curlx_fopen(pinnedpubkey, "rb");
if(!fp)
return result;
@ -865,7 +866,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
end:
curlx_dyn_free(&buf);
Curl_safefree(pem_ptr);
fclose(fp);
curlx_fclose(fp);
}
return result;