ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2);
END_EXTERN_C()
+#ifdef ZEND_WIN32
+# include "win32/ioutil.h"
+typedef php_win32_ioutil_stat_t zend_stat_t;
#ifdef _WIN64
-# define zend_fseek _fseeki64
-# define zend_ftell _ftelli64
-# define zend_lseek _lseeki64
-# define zend_fstat _fstat64
-# define zend_stat _stat64
-typedef struct __stat64 zend_stat_t;
+# define zend_fseek _fseeki64
+# define zend_ftell _ftelli64
+# define zend_lseek _lseeki64
+# else
+# define zend_fseek fseek
+# define zend_ftell ftell
+# define zend_lseek lseek
+# endif
+# define zend_fstat php_win32_ioutil_fstat
+# define zend_stat php_win32_ioutil_stat
#else
+typedef struct stat zend_stat_t;
# define zend_fseek fseek
# define zend_ftell ftell
# define zend_lseek lseek
# define zend_fstat fstat
# define zend_stat stat
-typedef struct stat zend_stat_t;
#endif
#endif
# ifndef VOLUME_NAME_DOS
# define VOLUME_NAME_DOS 0x0
# endif
+
+# include <winioctl.h>
+# include <winnt.h>
#endif
#ifndef HAVE_REALPATH
#endif
#ifdef ZEND_WIN32
-
-#ifdef CTL_CODE
-#undef CTL_CODE
-#endif
-#define CTL_CODE(DeviceType,Function,Method,Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
-#define FILE_DEVICE_FILE_SYSTEM 0x00000009
-#define METHOD_BUFFERED 0
-#define FILE_ANY_ACCESS 0
-#define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
-
-typedef struct {
- unsigned long ReparseTag;
- unsigned short ReparseDataLength;
- unsigned short Reserved;
- union {
- struct {
- unsigned short SubstituteNameOffset;
- unsigned short SubstituteNameLength;
- unsigned short PrintNameOffset;
- unsigned short PrintNameLength;
- unsigned long Flags;
- wchar_t ReparseTarget[1];
- } SymbolicLinkReparseBuffer;
- struct {
- unsigned short SubstituteNameOffset;
- unsigned short SubstituteNameLength;
- unsigned short PrintNameOffset;
- unsigned short PrintNameLength;
- wchar_t ReparseTarget[1];
- } MountPointReparseBuffer;
- struct {
- unsigned char ReparseTarget[1];
- } GenericReparseBuffer;
- };
-} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
-
-#define SECS_BETWEEN_EPOCHS (__int64)11644473600
-#define SECS_TO_100NS (__int64)10000000
-static inline time_t FileTimeToUnixTime(const FILETIME *FileTime)
-{
- __int64 UnixTime;
- SYSTEMTIME SystemTime;
- FileTimeToSystemTime(FileTime, &SystemTime);
-
- UnixTime = ((__int64)FileTime->dwHighDateTime << 32) +
- FileTime->dwLowDateTime;
-
- UnixTime -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS);
-
- UnixTime /= SECS_TO_100NS; /* now convert to seconds */
-
- if ((time_t)UnixTime != UnixTime) {
- UnixTime = 0;
- }
- return (time_t)UnixTime;
-}
-
CWD_API ssize_t php_sys_readlink(const char *link, char *target, size_t target_len){ /* {{{ */
HANDLE hFile;
wchar_t *linkw = php_win32_ioutil_any_to_w(link), targetw[MAXPATHLEN];
return (ssize_t)ret_len;
}
/* }}} */
-
-CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{{ */
-{
- WIN32_FILE_ATTRIBUTE_DATA data;
- LARGE_INTEGER t;
- size_t pathw_len = 0;
- ALLOCA_FLAG(use_heap_large)
- wchar_t *pathw = php_win32_ioutil_conv_any_to_w(path, PHP_WIN32_CP_IGNORE_LEN, &pathw_len);
-
- if (!pathw) {
- return -1;
- }
-
- if (!GetFileAttributesExW(pathw, GetFileExInfoStandard, &data)) {
- int ret;
-#if ZEND_ENABLE_ZVAL_LONG64
- ret = _wstat64(pathw, buf);
-#else
- ret = _wstat(pathw, (struct _stat32 *)buf);
-#endif
- free(pathw);
-
- return ret;
- }
-
- if (pathw_len >= 1 && pathw[1] == L':') {
- if (pathw[0] >= L'A' && pathw[0] <= L'Z') {
- buf->st_dev = buf->st_rdev = pathw[0] - L'A';
- } else {
- buf->st_dev = buf->st_rdev = pathw[0] - L'a';
- }
- } else if (PHP_WIN32_IOUTIL_IS_UNC(pathw, pathw_len)) {
- buf->st_dev = buf->st_rdev = 0;
- } else {
- wchar_t cur_path[MAXPATHLEN+1];
-
- if (NULL != _wgetcwd(cur_path, sizeof(cur_path)/sizeof(wchar_t))) {
- if (cur_path[1] == L':') {
- if (pathw[0] >= L'A' && pathw[0] <= L'Z') {
- buf->st_dev = buf->st_rdev = pathw[0] - L'A';
- } else {
- buf->st_dev = buf->st_rdev = pathw[0] - L'a';
- }
- } else {
- buf->st_dev = buf->st_rdev = -1;
- }
- } else {
- buf->st_dev = buf->st_rdev = -1;
- }
- }
-
- buf->st_uid = buf->st_gid = buf->st_ino = 0;
-
- if (lstat && data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- /* File is a reparse point. Get the target */
- HANDLE hLink = NULL;
- REPARSE_DATA_BUFFER * pbuffer;
- DWORD retlength = 0;
-
- hLink = CreateFileW(pathw,
- FILE_READ_ATTRIBUTES,
- PHP_WIN32_IOUTIL_DEFAULT_SHARE_MODE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
- if(hLink == INVALID_HANDLE_VALUE) {
- free(pathw);
- return -1;
- }
-
- pbuffer = (REPARSE_DATA_BUFFER *)do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
- if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
- free_alloca(pbuffer, use_heap_large);
- CloseHandle(hLink);
- free(pathw);
- return -1;
- }
-
- CloseHandle(hLink);
-
- if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
- buf->st_mode = S_IFLNK;
- buf->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) : (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)|S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6));
- }
-
-#if 0 /* Not used yet */
- else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
- buf->st_mode |=;
- }
-#endif
- free_alloca(pbuffer, use_heap_large);
- } else {
- buf->st_mode = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) : S_IFREG;
- buf->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) : (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)|S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6));
- }
-
- if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
- if (pathw_len >= 4 && pathw[pathw_len-4] == L'.') {
- if (_wcsnicmp(pathw+pathw_len-3, L"exe", 3) == 0 ||
- _wcsnicmp(pathw+pathw_len-3, L"com", 3) == 0 ||
- _wcsnicmp(pathw+pathw_len-3, L"bat", 3) == 0 ||
- _wcsnicmp(pathw+pathw_len-3, L"cmd", 3) == 0) {
- buf->st_mode |= (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
- }
- }
- }
-
- buf->st_nlink = 1;
- t.HighPart = data.nFileSizeHigh;
- t.LowPart = data.nFileSizeLow;
- /* It's an overflow on 32 bit, however it won't fix as long
- as zend_long is 32 bit. */
- buf->st_size = (zend_long)t.QuadPart;
- buf->st_atime = FileTimeToUnixTime(&data.ftLastAccessTime);
- buf->st_ctime = FileTimeToUnixTime(&data.ftCreationTime);
- buf->st_mtime = FileTimeToUnixTime(&data.ftLastWriteTime);
-
- free(pathw);
-
- return 0;
-}
-/* }}} */
#endif
static int php_is_dir_ok(const cwd_state *state) /* {{{ */
) {
/* File is a reparse point. Get the target */
HANDLE hLink = NULL;
- REPARSE_DATA_BUFFER * pbuffer;
+ PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER * pbuffer;
DWORD retlength = 0;
size_t bufindex = 0;
uint8_t isabsolute = 0;
return (size_t)-1;
}
- pbuffer = (REPARSE_DATA_BUFFER *)do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
+ pbuffer = (PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER *)do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
if (pbuffer == NULL) {
CloseHandle(hLink);
free_alloca(tmp, use_heap);
#endif
#ifdef ZEND_WIN32
-CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat);
-# define php_sys_stat(path, buf) php_sys_stat_ex(path, buf, 0)
-# define php_sys_lstat(path, buf) php_sys_stat_ex(path, buf, 1)
+# define php_sys_stat_ex php_win32_ioutil_stat_ex
+# define php_sys_stat php_win32_ioutil_stat
+# define php_sys_lstat php_win32_ioutil_lstat
+# define php_sys_fstat php_win32_ioutil_fstat
CWD_API ssize_t php_sys_readlink(const char *link, char *target, size_t target_len);
# define php_sys_symlink php_win32_ioutil_symlink
# define php_sys_link php_win32_ioutil_link
#else
# define php_sys_stat stat
# define php_sys_lstat lstat
+# define php_sys_fstat fstat
# ifdef HAVE_SYMLINK
# define php_sys_readlink(link, target, target_len) readlink(link, target, target_len)
# define php_sys_symlink symlink
ZVAL_LONG(&stat_uid, stat_ssb.sb.st_uid);
ZVAL_LONG(&stat_gid, stat_ssb.sb.st_gid);
#ifdef HAVE_STRUCT_STAT_ST_RDEV
-# ifdef PHP_WIN32
- /* It is unsigned, so if a negative came from userspace, it'll
- convert to UINT_MAX, but we want to keep the userspace value.
- Almost the same as in php_fstat. This is ugly, but otherwise
- we would have to maintain a fully compatible struct stat. */
- if ((int)stat_ssb.sb.st_rdev < 0) {
- ZVAL_LONG(&stat_rdev, (int)stat_ssb.sb.st_rdev);
- } else {
- ZVAL_LONG(&stat_rdev, stat_ssb.sb.st_rdev);
- }
-# else
ZVAL_LONG(&stat_rdev, stat_ssb.sb.st_rdev);
-# endif
#else
ZVAL_LONG(&stat_rdev, -1);
#endif
ZVAL_LONG(&stat_uid, stat_sb->st_uid);
ZVAL_LONG(&stat_gid, stat_sb->st_gid);
#ifdef HAVE_STRUCT_STAT_ST_RDEV
-# ifdef PHP_WIN32
- /* It is unsigned, so if a negative came from userspace, it'll
- convert to UINT_MAX, but we want to keep the userspace value.
- Almost the same as in php_if_fstat. */
- if ((int)stat_sb->st_rdev < 0) {
- ZVAL_LONG(&stat_rdev, (int)stat_sb->st_rdev);
- } else {
ZVAL_LONG(&stat_rdev, stat_sb->st_rdev);
- }
-# else
- ZVAL_LONG(&stat_rdev, stat_sb->st_rdev);
-# endif
#else
ZVAL_LONG(&stat_rdev, -1);
#endif
-- comparing difference in dir stats before and after creating file in it --
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
- int(0)
+ int(%d)
[2]=>
int(%d)
[3]=>
[12]=>
int(-1)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
- int(0)
+ int(%d)
["mode"]=>
int(%d)
["nlink"]=>
}
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
int(%d)
[2]=>
[12]=>
int(-1)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
int(%d)
["mode"]=>
-- comparing difference in dir stats before and after creating file in it --
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
- int(0)
+ int(%d)
[2]=>
int(%d)
[3]=>
[12]=>
int(-1)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
- int(0)
+ int(%d)
["mode"]=>
int(%d)
["nlink"]=>
}
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
int(%d)
[2]=>
[12]=>
int(-1)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
int(%d)
["mode"]=>
-- Testing stat() on filename stored inside an object --
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
int(%d)
[2]=>
[12]=>
int(-%d)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
int(%d)
["mode"]=>
}
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
int(%d)
[2]=>
[12]=>
int(-%d)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
int(%d)
["mode"]=>
-- Testing stat() on directory name stored inside an object --
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
int(%d)
[2]=>
[12]=>
int(-%d)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
int(%d)
["mode"]=>
}
array(26) {
[0]=>
- int(%d)
+ int(%i)
[1]=>
int(%d)
[2]=>
[12]=>
int(-%d)
["dev"]=>
- int(%d)
+ int(%i)
["ino"]=>
int(%d)
["mode"]=>
#include "main/streams/php_stream_plain_wrapper.h"
#include <pathcch.h>
+#include <winioctl.h>
+#include <winnt.h>
/*
#undef NONLS
return 0;
}/*}}}*/
+#define FILETIME_TO_UINT(filetime) \
+ (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+
+#define FILETIME_TO_TIME_T(filetime) \
+ (time_t)(FILETIME_TO_UINT(filetime) / 10000000ULL)
+
+static int php_win32_ioutil_fstat_int(HANDLE h, php_win32_ioutil_stat_t *buf, const wchar_t *pathw, size_t pathw_len, PBY_HANDLE_FILE_INFORMATION dp)
+{/*{{{*/
+ BY_HANDLE_FILE_INFORMATION d;
+ PBY_HANDLE_FILE_INFORMATION data;
+ LARGE_INTEGER t;
+ wchar_t mypath[MAXPATHLEN];
+ uint8_t is_dir;
+
+ data = !dp ? &d : dp;
+
+ if (!pathw) {
+ pathw_len = GetFinalPathNameByHandleW(h, mypath, MAXPATHLEN, VOLUME_NAME_DOS);
+ if (pathw_len >= MAXPATHLEN || pathw_len == 0) {
+ pathw_len = 0;
+ pathw = NULL;
+ } else {
+ pathw = mypath;
+ }
+ }
+
+ if(!GetFileInformationByHandle(h, data)) {
+ if (INVALID_HANDLE_VALUE != h) {
+ /* Perhaps it's a fileless stream like stdio, reuse the normal stat info. */
+ struct __stat64 _buf;
+ if (_fstat64(_open_osfhandle((intptr_t)h, 0), &_buf)) {
+ return -1;
+ }
+ buf->st_dev = _buf.st_dev;
+ buf->st_ino = _buf.st_ino;
+ buf->st_mode = _buf.st_mode;
+ buf->st_nlink = _buf.st_nlink;
+ buf->st_uid = _buf.st_uid;
+ buf->st_gid = _buf.st_gid;
+ buf->st_rdev = _buf.st_rdev;
+ buf->st_size = _buf.st_size;
+ buf->st_atime = _buf.st_atime;
+ buf->st_mtime = _buf.st_mtime;
+ buf->st_ctime = _buf.st_ctime;
+ return 0;
+ } else if(h == INVALID_HANDLE_VALUE && pathw_len > 0) {
+ /* An abnormal situation it is. For example, the user is the file
+ owner, but the file has an empty DACL. In that case, it is
+ possible CreateFile would fail, but the attributes still can
+ be read. Some info is still going to be missing. */
+ WIN32_FILE_ATTRIBUTE_DATA _data;
+ if (!GetFileAttributesExW(pathw, GetFileExInfoStandard, &_data)) {
+ DWORD err = GetLastError();
+ SET_ERRNO_FROM_WIN32_CODE(err);
+ return -1;
+ }
+ data->dwFileAttributes = _data.dwFileAttributes;
+ data->ftCreationTime = _data.ftCreationTime;
+ data->ftLastAccessTime = _data.ftLastAccessTime;
+ data->ftLastWriteTime = _data.ftLastWriteTime;
+ data->nFileSizeHigh = _data.nFileSizeHigh;
+ data->nFileSizeLow = _data.nFileSizeLow;
+ data->dwVolumeSerialNumber = 0;
+ data->nNumberOfLinks = 1;
+ data->nFileIndexHigh = 0;
+ data->nFileIndexLow = 0;
+ } else {
+ DWORD err = GetLastError();
+ SET_ERRNO_FROM_WIN32_CODE(err);
+ return -1;
+ }
+ }
+
+ is_dir = (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
+
+ buf->st_dev = data->dwVolumeSerialNumber;
+
+ buf->st_rdev = buf->st_uid = buf->st_gid = 0;
+
+ buf->st_ino = (((uint64_t)data->nFileIndexHigh) << 32) + data->nFileIndexLow;
+
+ buf->st_mode = 0;
+
+ if (!is_dir) {
+ DWORD type;
+ if (GetBinaryTypeW(pathw, &type)) {
+ buf->st_mode |= (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
+ }
+ }
+
+ if ((data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
+ buf->st_mode |= is_dir ? (S_IFDIR|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) : S_IFREG;
+ buf->st_mode |= (data->dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) : (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)|S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6));
+ }
+
+ buf->st_nlink = data->nNumberOfLinks;
+ t.HighPart = data->nFileSizeHigh;
+ t.LowPart = data->nFileSizeLow;
+ /* It's an overflow on 32 bit, however it won't fix as long
+ as zend_long is 32 bit. */
+ buf->st_size = (zend_long)t.QuadPart;
+ buf->st_atime = FILETIME_TO_TIME_T(data->ftLastAccessTime);
+ buf->st_ctime = FILETIME_TO_TIME_T(data->ftCreationTime);
+ buf->st_mtime = FILETIME_TO_TIME_T(data->ftLastWriteTime);
+
+ return 0;
+}/*}}}*/
+
+PW32IO int php_win32_ioutil_stat_ex_w(const wchar_t *path, size_t path_len, php_win32_ioutil_stat_t *buf, int lstat)
+{/*{{{*/
+ BY_HANDLE_FILE_INFORMATION data;
+ HANDLE hLink = NULL;
+ DWORD flags_and_attrs = lstat ? FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT : FILE_FLAG_BACKUP_SEMANTICS;
+ int ret;
+ ALLOCA_FLAG(use_heap_large)
+
+ hLink = CreateFileW(path,
+ FILE_READ_ATTRIBUTES,
+ PHP_WIN32_IOUTIL_DEFAULT_SHARE_MODE,
+ NULL,
+ OPEN_EXISTING,
+ flags_and_attrs,
+ NULL
+ );
+
+ ret = php_win32_ioutil_fstat_int(hLink, buf, path, path_len, &data);
+
+ if (lstat && data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ /* File is a reparse point. Get the target */
+ PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER * pbuffer;
+ DWORD retlength = 0;
+
+ pbuffer = (PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER *)do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
+ if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
+ free_alloca(pbuffer, use_heap_large);
+ CloseHandle(hLink);
+ return -1;
+ }
+
+ if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ buf->st_mode = S_IFLNK;
+ buf->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) : (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)|S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6));
+ }
+
+#if 0 /* Not used yet */
+ else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ buf->st_mode |=;
+ }
+#endif
+ free_alloca(pbuffer, use_heap_large);
+ }
+
+ CloseHandle(hLink);
+
+ return ret;
+
+}/*}}}*/
+
+PW32IO int php_win32_ioutil_fstat(int fd, php_win32_ioutil_stat_t *buf)
+{/*{{{*/
+ return php_win32_ioutil_fstat_int((HANDLE)_get_osfhandle(fd), buf, NULL, 0, NULL);
+}/*}}}*/
+
/*
* Local variables:
* tab-width: 4
return php_win32_ioutil_realpath_ex0(path, resolved, NULL);
}/*}}}*/
+#include <sys/stat.h>
+#if _WIN64
+typedef unsigned __int64 php_win32_ioutil_dev_t;
+typedef unsigned __int64 php_win32_ioutil_ino_t;
+typedef __time64_t php_win32_ioutil_time_t;
+typedef __int64 php_win32_ioutil_size_t;
+#else
+typedef unsigned __int32 php_win32_ioutil_dev_t;
+typedef unsigned __int32 php_win32_ioutil_ino_t;
+typedef __time32_t php_win32_ioutil_time_t;
+typedef __int32 php_win32_ioutil_size_t;
+#endif
+typedef struct {
+ php_win32_ioutil_dev_t st_dev;
+ php_win32_ioutil_ino_t st_ino;
+ unsigned __int32 st_mode;
+ unsigned __int32 st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ php_win32_ioutil_dev_t st_rdev;
+ php_win32_ioutil_size_t st_size;
+#if 0
+ __int32 st_blksize;
+ __int32 st_blocks;
+#endif
+ php_win32_ioutil_time_t st_atime;
+ php_win32_ioutil_time_t st_mtime;
+ php_win32_ioutil_time_t st_ctime;
+} php_win32_ioutil_stat_t;
+
+typedef struct {
+ unsigned long ReparseTag;
+ unsigned short ReparseDataLength;
+ unsigned short Reserved;
+ union {
+ struct {
+ unsigned short SubstituteNameOffset;
+ unsigned short SubstituteNameLength;
+ unsigned short PrintNameOffset;
+ unsigned short PrintNameLength;
+ unsigned long Flags;
+ wchar_t ReparseTarget[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ unsigned short SubstituteNameOffset;
+ unsigned short SubstituteNameLength;
+ unsigned short PrintNameOffset;
+ unsigned short PrintNameLength;
+ wchar_t ReparseTarget[1];
+ } MountPointReparseBuffer;
+ struct {
+ unsigned char ReparseTarget[1];
+ } GenericReparseBuffer;
+ };
+} PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER, *PHP_WIN32_IOUTIL_PREPARSE_DATA_BUFFER;
+
+PW32IO int php_win32_ioutil_stat_ex_w(const wchar_t *path, size_t path_len, php_win32_ioutil_stat_t *buf, int lstat);
+PW32IO int php_win32_ioutil_fstat(int fd, php_win32_ioutil_stat_t *buf);
+
+__forceinline static int php_win32_ioutil_stat_ex(const char *path, php_win32_ioutil_stat_t *buf, int lstat)
+{/*{{{*/
+ size_t pathw_len;
+ wchar_t *pathw = php_win32_ioutil_conv_any_to_w(path, PHP_WIN32_CP_IGNORE_LEN, &pathw_len);
+ int ret;
+
+ if (!pathw) {
+ SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
+ return -1;
+ }
+
+ ret = php_win32_ioutil_stat_ex_w(pathw, pathw_len, buf, lstat);
+
+ free(pathw);
+
+ return ret;
+}/*}}}*/
+#define php_win32_ioutil_stat(path, buf) php_win32_ioutil_stat_ex(path, buf, 0)
+#define php_win32_ioutil_lstat(path, buf) php_win32_ioutil_stat_ex(path, buf, 1)
+
#ifdef __cplusplus
}
#endif