build: tidy up curl-specific fstat calls and stat struct type

To avoid redefining the `fstat` system symbol, and to clarify
`struct_stat` is a curl symbol.

- introduce `curlx_fstat()` macro and use it.
- rename `struct_stat` to `curl_struct_stat`.

Also:
- tests: replace direct `curlx_win32_stat()` call with `curlx_stat()`.
- checksrc: disallow direct `_fstati64` and `fstat()` calls, except in
  examples.

Closes #20496
This commit is contained in:
Viktor Szakats 2026-02-02 13:14:30 +01:00
parent 9630593650
commit a84b041281
No known key found for this signature in database
GPG key ID: B5ABD165E2AEF201
22 changed files with 53 additions and 50 deletions

View file

@ -11,6 +11,7 @@ allowfunc fdopen
allowfunc fopen
allowfunc fprintf
allowfunc free
allowfunc fstat
allowfunc gmtime
allowfunc localtime
allowfunc malloc

View file

@ -332,6 +332,7 @@ makes us write better code.
This is the full list of functions generally banned.
_access
_fstati64
_lseeki64
_mbscat
_mbsncat
@ -365,6 +366,7 @@ This is the full list of functions generally banned.
free
freeaddrinfo
freopen
fstat
getaddrinfo
gets
gmtime

View file

@ -89,7 +89,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
unsigned char randbuf[41];
char *tempstore = NULL;
#ifndef _WIN32
struct_stat sb;
curl_struct_stat sb;
#endif
int fd = -1;
char *dir = NULL;
@ -99,7 +99,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
*fh = curlx_fopen(filename, FOPEN_WRITETEXT);
if(!*fh)
goto fail;
if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
if(curlx_fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
return CURLE_OK;
}
curlx_fclose(*fh);

View file

@ -490,9 +490,6 @@
# include <sys/types.h>
# include <sys/stat.h>
/* Large file (>2Gb) support using Win32 functions. */
# undef fstat
# define fstat(fdes, stp) _fstati64(fdes, stp)
# define struct_stat struct _stati64
# define curl_lseek _lseeki64
# define LSEEK_ERROR ((__int64)-1)
#elif defined(__DJGPP__)
@ -508,10 +505,6 @@
# define LSEEK_ERROR ((off_t)-1)
#endif
#ifndef struct_stat
#define struct_stat struct stat
#endif
#ifndef SIZEOF_TIME_T
/* assume default size of time_t to be 32 bits */
#define SIZEOF_TIME_T 4

View file

@ -405,7 +405,7 @@ FILE *curlx_win32_freopen(const char *filename, const char *mode, FILE *fp)
return result;
}
int curlx_win32_stat(const char *path, struct_stat *buffer)
int curlx_win32_stat(const char *path, curl_struct_stat *buffer)
{
int result = -1;
TCHAR *fixed = NULL;

View file

@ -34,6 +34,7 @@
int curlx_fseek(void *stream, curl_off_t offset, int whence);
#ifdef _WIN32
#include <sys/stat.h> /* for _fstati64, struct _stati64 */
#ifndef CURL_WINDOWS_UWP
HANDLE curlx_CreateFile(const char *filename,
DWORD dwDesiredAccess,
@ -43,9 +44,11 @@ HANDLE curlx_CreateFile(const char *filename,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
#endif /* !CURL_WINDOWS_UWP */
#define curlx_fstat _fstati64
#define curl_struct_stat struct _stati64
FILE *curlx_win32_fopen(const char *filename, const char *mode);
FILE *curlx_win32_freopen(const char *filename, const char *mode, FILE *fh);
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_stat(const char *path, curl_struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
int curlx_win32_rename(const char *oldpath, const char *newpath);
#define CURLX_FOPEN_LOW(fname, mode) curlx_win32_fopen(fname, mode)
@ -56,6 +59,8 @@ int curlx_win32_rename(const char *oldpath, const char *newpath);
#define curlx_close _close
#define curlx_rename curlx_win32_rename
#else
#define curlx_fstat fstat
#define curl_struct_stat struct stat
#define CURLX_FOPEN_LOW fopen
#define CURLX_FREOPEN_LOW freopen
#define CURLX_FDOPEN_LOW fdopen

View file

@ -270,7 +270,7 @@ static CURLcode file_upload(struct Curl_easy *data,
CURLcode result = CURLE_OK;
char *xfer_ulbuf;
size_t xfer_ulblen;
struct_stat file_stat;
curl_struct_stat file_stat;
const char *sendbuf;
bool eos = FALSE;
@ -311,7 +311,7 @@ static CURLcode file_upload(struct Curl_easy *data,
/* treat the negative resume offset value as the case of "-" */
if(data->state.resume_from < 0) {
if(fstat(fd, &file_stat)) {
if(curlx_fstat(fd, &file_stat)) {
curlx_close(fd);
failf(data, "cannot get the size of %s", file->path);
return CURLE_WRITE_ERROR;
@ -390,9 +390,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
*/
struct FILEPROTO *file = Curl_meta_get(data, CURL_META_FILE_EASY);
CURLcode result = CURLE_OK;
struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
Windows version to have a different struct without
having to redefine the simple word 'stat' */
curl_struct_stat statbuf;
curl_off_t expected_size = -1;
bool size_known;
bool fstated = FALSE;
@ -411,7 +409,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
fd = file->fd;
/* VMS: This only works reliable for STREAMLF files */
if(fstat(fd, &statbuf) != -1) {
if(curlx_fstat(fd, &statbuf) != -1) {
if(!S_ISDIR(statbuf.st_mode))
expected_size = statbuf.st_size;
/* and store the modification time */

View file

@ -107,7 +107,7 @@ static const char aschex[] =
* and CD/DVD images should be either a STREAM_LF format or a fixed format.
*
*/
curl_off_t VmsRealFileSize(const char *name, const struct_stat *stat_buf)
curl_off_t VmsRealFileSize(const char *name, const curl_struct_stat *stat_buf)
{
char buffer[8192];
curl_off_t count;
@ -136,7 +136,8 @@ curl_off_t VmsRealFileSize(const char *name, const struct_stat *stat_buf)
* if not to call a routine to get the correct size.
*
*/
static curl_off_t VmsSpecialSize(const char *name, const struct_stat *stat_buf)
static curl_off_t VmsSpecialSize(const char *name,
const curl_struct_stat *stat_buf)
{
switch(stat_buf->st_fab_rfm) {
case FAB$C_VAR:
@ -160,7 +161,7 @@ static curl_off_t VmsSpecialSize(const char *name, const struct_stat *stat_buf)
*/
static FILE *vmsfopenread(const char *file, const char *mode)
{
struct_stat statbuf;
curl_struct_stat statbuf;
int result;
result = curlx_stat(file, &statbuf);
@ -1307,7 +1308,7 @@ CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
if(filename) {
char *base;
struct_stat sbuf;
curl_struct_stat sbuf;
if(curlx_stat(filename, &sbuf))
result = CURLE_READ_ERROR;

View file

@ -1089,7 +1089,7 @@ static CURLcode ssh_state_pkey_init(struct Curl_easy *data,
/* To ponder about: should really the lib be messing about with the
HOME environment variable etc? */
char *home = curl_getenv("HOME");
struct_stat sbuf;
curl_struct_stat sbuf;
/* If no private key file is specified, try some common paths. */
if(home) {

View file

@ -49,6 +49,7 @@ my @ignore_line;
my %banfunc = (
"_access" => 1,
"_fstati64" => 1,
"_lseeki64" => 1,
"_mbscat" => 1,
"_mbsncat" => 1,
@ -82,6 +83,7 @@ my %banfunc = (
"free" => 1,
"freeaddrinfo" => 1,
"freopen" => 1,
"fstat" => 1,
"getaddrinfo" => 1,
"gets" => 1,
"gmtime" => 1,

View file

@ -291,7 +291,7 @@ static SANITIZEcode rename_if_reserved_dos(char ** const sanitized,
* to rename such files. */
char *p, *base, *buffer;
#ifdef MSDOS
struct_stat st_buf;
curl_struct_stat st_buf;
#endif
size_t len, bufsize;

View file

@ -68,7 +68,7 @@ int getfiletime(const char *filename, curl_off_t *stamp)
GetLastError());
}
#else
struct_stat statbuf;
curl_struct_stat statbuf;
if(curlx_stat(filename, &statbuf) != -1) {
*stamp = (curl_off_t)statbuf.st_mtime;
rc = 0;

View file

@ -122,13 +122,13 @@ static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent,
char *data = NULL;
curl_off_t size;
curl_off_t origin;
struct_stat sbuf;
curl_struct_stat sbuf;
CURLX_SET_BINMODE(stdin);
origin = ftell(stdin);
/* If stdin is a regular file, do not buffer data but read it
when needed. */
if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) &&
if(fd >= 0 && origin >= 0 && !curlx_fstat(fd, &sbuf) &&
#ifdef __VMS
sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC &&
#endif

View file

@ -2209,7 +2209,7 @@ static ParameterError existingfile(char **store,
const struct LongShort *a,
const char *filename)
{
struct_stat info;
curl_struct_stat info;
if(curlx_stat(filename, &info)) {
errorf("The file '%s' provided to --%s does not exist",
filename, a->lname);

View file

@ -146,7 +146,7 @@ static bool is_pkcs11_uri(const char *string)
*
*/
static curl_off_t vms_realfilesize(const char *name,
const struct_stat *stat_buf)
const curl_struct_stat *stat_buf)
{
char buffer[8192];
curl_off_t count;
@ -176,7 +176,8 @@ static curl_off_t vms_realfilesize(const char *name,
* if not to call a routine to get the correct size.
*
*/
static curl_off_t VmsSpecialSize(const char *name, const struct_stat *stat_buf)
static curl_off_t VmsSpecialSize(const char *name,
const curl_struct_stat *stat_buf)
{
switch(stat_buf->st_fab_rfm) {
case FAB$C_VAR:
@ -247,7 +248,7 @@ static struct per_transfer *del_per_transfer(struct per_transfer *per)
static CURLcode pre_transfer(struct per_transfer *per)
{
curl_off_t uploadfilesize = -1;
struct_stat fileinfo;
curl_struct_stat fileinfo;
CURLcode result = CURLE_OK;
if(per->uploadfile && !stdin_upload(per->uploadfile)) {
@ -284,7 +285,7 @@ static CURLcode pre_transfer(struct per_transfer *per)
if(per->infd == -1)
#else
per->infd = curlx_open(per->uploadfile, O_RDONLY | CURL_O_BINARY);
if((per->infd == -1) || fstat(per->infd, &fileinfo))
if((per->infd == -1) || curlx_fstat(per->infd, &fileinfo))
#endif
{
helpf("cannot open '%s'", per->uploadfile);
@ -547,11 +548,11 @@ static CURLcode retrycheck(struct OperationConfig *config,
}
if(truncate && outs->bytes && outs->filename && outs->stream) {
struct_stat fileinfo;
curl_struct_stat fileinfo;
/* The output can be a named pipe or a character device etc that
cannot be truncated. Only truncate regular files. */
if(!fstat(fileno(outs->stream), &fileinfo) &&
if(!curlx_fstat(fileno(outs->stream), &fileinfo) &&
S_ISREG(fileinfo.st_mode)) {
int rc;
/* We have written data to an output file, we truncate file */
@ -717,7 +718,7 @@ static CURLcode post_per_transfer(struct per_transfer *per,
errorf("curl: (%d) Failed writing body", result);
}
if(result && config->rm_partial) {
struct_stat st;
curl_struct_stat st;
if(!curlx_stat(outs->filename, &st) && S_ISREG(st.st_mode)) {
if(!unlink(outs->filename))
notef("Removed output file: %s", outs->filename);
@ -1039,7 +1040,7 @@ static CURLcode setup_outfile(struct OperationConfig *config,
}
if(config->skip_existing) {
struct_stat fileinfo;
curl_struct_stat fileinfo;
if(!curlx_stat(per->outfile, &fileinfo)) {
/* file is present */
notef("skips transfer, \"%s\" exists locally", per->outfile);
@ -1051,7 +1052,7 @@ static CURLcode setup_outfile(struct OperationConfig *config,
if(config->resume_from_current) {
/* We are told to continue from where we are now. Get the size
of the file as it is now and open it for append instead */
struct_stat fileinfo;
curl_struct_stat fileinfo;
/* VMS -- Danger, the filesize is only valid for stream files */
if(curlx_stat(per->outfile, &fileinfo) == 0)
/* set offset to current file size: */

View file

@ -37,7 +37,7 @@ static CURLcode test_lib505(const char *URL)
char errbuf[STRERROR_LEN];
FILE *hd_src;
int hd;
struct_stat file_info;
curl_struct_stat file_info;
struct curl_slist *hl;
struct curl_slist *headerlist = NULL;
@ -59,7 +59,7 @@ static CURLcode test_lib505(const char *URL)
}
/* get the file size of the local file */
hd = fstat(fileno(hd_src), &file_info);
hd = curlx_fstat(fileno(hd_src), &file_info);
if(hd == -1) {
/* cannot open file, bail out */
curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n",

View file

@ -30,7 +30,7 @@ static CURLcode test_lib525(const char *URL)
char errbuf[STRERROR_LEN];
FILE *hd_src = NULL;
int hd;
struct_stat file_info;
curl_struct_stat file_info;
CURLM *multi = NULL;
int running;
@ -50,7 +50,7 @@ static CURLcode test_lib525(const char *URL)
}
/* get the file size of the local file */
hd = fstat(fileno(hd_src), &file_info);
hd = curlx_fstat(fileno(hd_src), &file_info);
if(hd == -1) {
/* cannot open file, bail out */
curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n",

View file

@ -34,7 +34,7 @@ static CURLcode test_lib541(const char *URL)
char errbuf[STRERROR_LEN];
FILE *hd_src;
int hd;
struct_stat file_info;
curl_struct_stat file_info;
if(!libtest_arg2) {
curl_mfprintf(stderr, "Usage: <url> <file-to-upload>\n");
@ -50,7 +50,7 @@ static CURLcode test_lib541(const char *URL)
}
/* get the file size of the local file */
hd = fstat(fileno(hd_src), &file_info);
hd = curlx_fstat(fileno(hd_src), &file_info);
if(hd == -1) {
/* cannot open file, bail out */
curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n",

View file

@ -35,7 +35,7 @@ static CURLcode test_lib568(const char *URL)
char errbuf[STRERROR_LEN];
int sdp;
FILE *sdpf = NULL;
struct_stat file_info;
curl_struct_stat file_info;
char *stream_uri = NULL;
int request = 1;
struct curl_slist *custom_headers = NULL;
@ -74,7 +74,7 @@ static CURLcode test_lib568(const char *URL)
result = TEST_ERR_MAJOR_BAD;
goto test_cleanup;
}
fstat(sdp, &file_info);
curlx_fstat(sdp, &file_info);
curlx_close(sdp);
sdpf = curlx_fopen(libtest_arg2, "rb");

View file

@ -35,7 +35,7 @@ static CURLcode test_lib572(const char *URL)
char errbuf[STRERROR_LEN];
int params;
FILE *paramsf = NULL;
struct_stat file_info;
curl_struct_stat file_info;
char *stream_uri = NULL;
int request = 1;
struct curl_slist *custom_headers = NULL;
@ -92,7 +92,7 @@ static CURLcode test_lib572(const char *URL)
result = TEST_ERR_MAJOR_BAD;
goto test_cleanup;
}
fstat(params, &file_info);
curlx_fstat(params, &file_info);
curlx_close(params);
paramsf = curlx_fopen(libtest_arg2, "rb");

View file

@ -220,7 +220,7 @@ static CURLcode test_lib582(const char *URL)
char errbuf[STRERROR_LEN];
FILE *hd_src = NULL;
int hd;
struct_stat file_info;
curl_struct_stat file_info;
CURLM *multi = NULL;
struct t582_ReadWriteSockets sockets = { { NULL, 0, 0 }, { NULL, 0, 0 } };
int success = 0;
@ -245,7 +245,7 @@ static CURLcode test_lib582(const char *URL)
}
/* get the file size of the local file */
hd = fstat(fileno(hd_src), &file_info);
hd = curlx_fstat(fileno(hd_src), &file_info);
if(hd == -1) {
/* cannot open file, bail out */
curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n",

View file

@ -670,7 +670,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
curlx_strcopy(sau->sun_path, sizeof(sau->sun_path), unix_socket, len);
rc = bind(sock, (struct sockaddr *)sau, sizeof(struct sockaddr_un));
if(rc && SOCKERRNO == SOCKEADDRINUSE) {
struct_stat statbuf;
curl_struct_stat statbuf;
/* socket already exists. Perhaps it is stale? */
curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(CURL_SOCKET_BAD == unixfd) {
@ -690,7 +690,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
/* socket server is not alive, now check if it was actually a socket. */
#ifdef _WIN32
/* Windows does not have lstat function. */
rc = curlx_win32_stat(unix_socket, &statbuf);
rc = curlx_stat(unix_socket, &statbuf);
#else
rc = lstat(unix_socket, &statbuf);
#endif