blob: a3524e4064a0ba1ae3c79e3c4bb829df9566cda2 [file]
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
*/
#include <sys/stat.h>
#include <stdint.h>
#include <errno.h>
#ifndef _WIN64
#include <fcntl.h>
#include <windows.h>
int __cdecl fstat32(int fd, struct _stat32 *stat);
#endif
/* When the file time does not fit into the st_Xtime field:
* crtdll-msvcr71 msvcr80+
* st_Xtime -1 -1
* errno no change EINVAL
* returns 0 0
*
* When the file size does not fit into the st_size field:
* crtdll-msvcr90 msvcr100 msvcr110+
* st_size truncate 0 0
* errno no change no change EOVERFLOW
* returns 0 -1 -1
*
* The stat function on 32-bit system os msvcrt.dll behaves
* like the msvcr80/msvcr90, so use this behavior.
*/
int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat)
{
#ifdef _WIN64
struct _stat64 st;
int ret=_wstat64(_Name,&st);
if (ret != 0)
return ret;
_Stat->st_dev=st.st_dev;
_Stat->st_ino=st.st_ino;
_Stat->st_mode=st.st_mode;
_Stat->st_nlink=st.st_nlink;
_Stat->st_uid=st.st_uid;
_Stat->st_gid=st.st_gid;
_Stat->st_rdev=st.st_rdev;
_Stat->st_size=(_off_t) st.st_size; /* truncate 64-bit st_size to 32-bit */
_Stat->st_atime=((st.st_atime < 0 || st.st_atime > INT32_MAX) ? -1 : st.st_atime);
_Stat->st_mtime=((st.st_mtime < 0 || st.st_mtime > INT32_MAX) ? -1 : st.st_mtime);
_Stat->st_ctime=((st.st_ctime < 0 || st.st_ctime > INT32_MAX) ? -1 : st.st_ctime);
if (_Stat->st_atime == -1 || _Stat->st_mtime == -1 || _Stat->st_ctime == -1)
errno = EINVAL;
return 0;
#else
/* mingw-w64 _wstat64() on 32-bit systems is implemented as wrapper around the _wstat32().
* Therefore mingw-w64 _wstat32() implementation cannot call _wstat64().
* This _wstat32() implementation uses mingw-w64 fstat32() with handle obtained from CreateFileW().
* mingw-w64 fstat32() is a wrapper around the CRT _fstat32() and which fixes the S_IFMT to
* S_IFDIR for directories. The CRT _fstat32() returns S_IFREG for directories.
* _fstat32() requires only FILE_READ_ATTRIBUTES access and FILE_FLAG_BACKUP_SEMANTICS is
* required for opening directory via CreateFileW().
* Using just FILE_READ_ATTRIBUTES access allows to open also path which is was denied for
* reading by another process. msvcrt.dll _wstat32() also allows to be called on such path.
*/
int fd;
int ret;
int err;
HANDLE handle;
handle = CreateFileW(_Name, FILE_READ_ATTRIBUTES, FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (handle == NULL || handle == INVALID_HANDLE_VALUE) {
switch (GetLastError()) {
case ERROR_PATH_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
errno = ENOENT;
break;
case ERROR_ACCESS_DENIED:
case ERROR_WRITE_PROTECT...ERROR_SHARING_BUFFER_EXCEEDED: /* gcc extension for case ranges: https://gcc.gnu.org/onlinedocs/gcc-3.0.4/gcc/Case-Ranges.html */
errno = EACCES;
break;
case ERROR_NOT_ENOUGH_MEMORY:
errno = ENOMEM;
break;
default:
errno = EINVAL;
break;
}
return -1;
}
fd = _open_osfhandle((intptr_t)handle, O_RDONLY);
if (fd < 0) {
CloseHandle(handle);
return -1;
}
ret = fstat32(fd, _Stat);
err = errno;
close(fd);
errno = err;
return ret;
#endif
}
int (__cdecl *__MINGW_IMP_SYMBOL(_wstat32))(const wchar_t *, struct _stat32 *) = _wstat32;
/* On 32-bit systems is _wstat ABI using 32-bit time_t and 32-bit off_t */
#ifndef _WIN64
#undef _wstat
int __attribute__((alias("_wstat32"))) __cdecl _wstat(const wchar_t *_Name,struct _stat32 *_Stat);
extern int __attribute__((alias(__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_wstat32))))) (__cdecl *__MINGW_IMP_SYMBOL(_wstat))(const wchar_t *, struct _stat32 *);
#endif