Blame src/gl/stat-w32.c

Packit aea12f
/* Core of implementation of fstat and stat for native Windows.
Packit Service 991b93
   Copyright (C) 2017-2020 Free Software Foundation, Inc.
Packit aea12f
Packit aea12f
   This program is free software: you can redistribute it and/or modify
Packit aea12f
   it under the terms of the GNU General Public License as published by
Packit aea12f
   the Free Software Foundation; either version 3 of the License, or
Packit aea12f
   (at your option) any later version.
Packit aea12f
Packit aea12f
   This program is distributed in the hope that it will be useful,
Packit aea12f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit aea12f
   GNU General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public License
Packit aea12f
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
/* Written by Bruno Haible.  */
Packit aea12f
Packit aea12f
#include <config.h>
Packit aea12f
Packit aea12f
#if defined _WIN32 && ! defined __CYGWIN__
Packit aea12f
Packit aea12f
/* Ensure that <windows.h> defines FILE_ID_INFO.  */
Packit Service 991b93
#if !defined _WIN32_WINNT || (_WIN32_WINNT < _WIN32_WINNT_WIN8)
Packit Service 991b93
# undef _WIN32_WINNT
Packit Service 991b93
# define _WIN32_WINNT _WIN32_WINNT_WIN8
Packit Service 991b93
#endif
Packit aea12f
Packit aea12f
#include <sys/types.h>
Packit aea12f
#include <sys/stat.h>
Packit aea12f
#include <errno.h>
Packit aea12f
#include <limits.h>
Packit aea12f
#include <string.h>
Packit aea12f
#include <unistd.h>
Packit aea12f
#include <windows.h>
Packit aea12f
Packit aea12f
/* Specification.  */
Packit aea12f
#include "stat-w32.h"
Packit aea12f
Packit aea12f
#include "pathmax.h"
Packit aea12f
#include "verify.h"
Packit aea12f
Packit Service 991b93
#if !(_WIN32_WINNT >= _WIN32_WINNT_VISTA)
Packit Service 991b93
Packit aea12f
/* Avoid warnings from gcc -Wcast-function-type.  */
Packit Service 991b93
# define GetProcAddress \
Packit Service 991b93
   (void *) GetProcAddress
Packit aea12f
Packit Service 991b93
# if _GL_WINDOWS_STAT_INODES == 2
Packit aea12f
/* GetFileInformationByHandleEx was introduced only in Windows Vista.  */
Packit aea12f
typedef DWORD (WINAPI * GetFileInformationByHandleExFuncType) (HANDLE hFile,
Packit aea12f
                                                               FILE_INFO_BY_HANDLE_CLASS fiClass,
Packit aea12f
                                                               LPVOID lpBuffer,
Packit aea12f
                                                               DWORD dwBufferSize);
Packit aea12f
static GetFileInformationByHandleExFuncType GetFileInformationByHandleExFunc = NULL;
Packit Service 991b93
# endif
Packit aea12f
/* GetFinalPathNameByHandle was introduced only in Windows Vista.  */
Packit aea12f
typedef DWORD (WINAPI * GetFinalPathNameByHandleFuncType) (HANDLE hFile,
Packit Service 991b93
                                                           LPSTR lpFilePath,
Packit aea12f
                                                           DWORD lenFilePath,
Packit aea12f
                                                           DWORD dwFlags);
Packit aea12f
static GetFinalPathNameByHandleFuncType GetFinalPathNameByHandleFunc = NULL;
Packit aea12f
static BOOL initialized = FALSE;
Packit aea12f
Packit aea12f
static void
Packit aea12f
initialize (void)
Packit aea12f
{
Packit aea12f
  HMODULE kernel32 = LoadLibrary ("kernel32.dll");
Packit aea12f
  if (kernel32 != NULL)
Packit aea12f
    {
Packit Service 991b93
# if _GL_WINDOWS_STAT_INODES == 2
Packit aea12f
      GetFileInformationByHandleExFunc =
Packit aea12f
        (GetFileInformationByHandleExFuncType) GetProcAddress (kernel32, "GetFileInformationByHandleEx");
Packit Service 991b93
# endif
Packit aea12f
      GetFinalPathNameByHandleFunc =
Packit aea12f
        (GetFinalPathNameByHandleFuncType) GetProcAddress (kernel32, "GetFinalPathNameByHandleA");
Packit aea12f
    }
Packit aea12f
  initialized = TRUE;
Packit aea12f
}
Packit aea12f
Packit Service 991b93
#else
Packit Service 991b93
Packit Service 991b93
# define GetFileInformationByHandleExFunc GetFileInformationByHandleEx
Packit Service 991b93
# define GetFinalPathNameByHandleFunc GetFinalPathNameByHandle
Packit Service 991b93
Packit Service 991b93
#endif
Packit Service 991b93
Packit aea12f
/* Converts a FILETIME to GMT time since 1970-01-01 00:00:00.  */
Packit aea12f
#if _GL_WINDOWS_STAT_TIMESPEC
Packit aea12f
struct timespec
Packit aea12f
_gl_convert_FILETIME_to_timespec (const FILETIME *ft)
Packit aea12f
{
Packit aea12f
  struct timespec result;
Packit aea12f
  /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */
Packit aea12f
  unsigned long long since_1601 =
Packit aea12f
    ((unsigned long long) ft->dwHighDateTime << 32)
Packit aea12f
    | (unsigned long long) ft->dwLowDateTime;
Packit aea12f
  if (since_1601 == 0)
Packit aea12f
    {
Packit aea12f
      result.tv_sec = 0;
Packit aea12f
      result.tv_nsec = 0;
Packit aea12f
    }
Packit aea12f
  else
Packit aea12f
    {
Packit aea12f
      /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89
Packit aea12f
         leap years, in total 134774 days.  */
Packit aea12f
      unsigned long long since_1970 =
Packit aea12f
        since_1601 - (unsigned long long) 134774 * (unsigned long long) 86400 * (unsigned long long) 10000000;
Packit aea12f
      result.tv_sec = since_1970 / (unsigned long long) 10000000;
Packit aea12f
      result.tv_nsec = (unsigned long) (since_1970 % (unsigned long long) 10000000) * 100;
Packit aea12f
    }
Packit aea12f
  return result;
Packit aea12f
}
Packit aea12f
#else
Packit aea12f
time_t
Packit aea12f
_gl_convert_FILETIME_to_POSIX (const FILETIME *ft)
Packit aea12f
{
Packit aea12f
  /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */
Packit aea12f
  unsigned long long since_1601 =
Packit aea12f
    ((unsigned long long) ft->dwHighDateTime << 32)
Packit aea12f
    | (unsigned long long) ft->dwLowDateTime;
Packit aea12f
  if (since_1601 == 0)
Packit aea12f
    return 0;
Packit aea12f
  else
Packit aea12f
    {
Packit aea12f
      /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89
Packit aea12f
         leap years, in total 134774 days.  */
Packit aea12f
      unsigned long long since_1970 =
Packit aea12f
        since_1601 - (unsigned long long) 134774 * (unsigned long long) 86400 * (unsigned long long) 10000000;
Packit aea12f
      return since_1970 / (unsigned long long) 10000000;
Packit aea12f
    }
Packit aea12f
}
Packit aea12f
#endif
Packit aea12f
Packit aea12f
/* Fill *BUF with information about the file designated by H.
Packit aea12f
   PATH is the file name, if known, otherwise NULL.
Packit aea12f
   Return 0 if successful, or -1 with errno set upon failure.  */
Packit aea12f
int
Packit aea12f
_gl_fstat_by_handle (HANDLE h, const char *path, struct stat *buf)
Packit aea12f
{
Packit aea12f
  /* GetFileType
Packit aea12f
     <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype> */
Packit aea12f
  DWORD type = GetFileType (h);
Packit aea12f
  if (type == FILE_TYPE_DISK)
Packit aea12f
    {
Packit Service 991b93
#if !(_WIN32_WINNT >= _WIN32_WINNT_VISTA)
Packit aea12f
      if (!initialized)
Packit aea12f
        initialize ();
Packit Service 991b93
#endif
Packit aea12f
Packit aea12f
      /* st_mode can be determined through
Packit aea12f
         GetFileAttributesEx
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesexa>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_win32_file_attribute_data>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandle
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandleEx with argument FileBasicInfo
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_basic_info>
Packit aea12f
         The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher.  */
Packit aea12f
      BY_HANDLE_FILE_INFORMATION info;
Packit aea12f
      if (! GetFileInformationByHandle (h, &info))
Packit aea12f
        goto failed;
Packit aea12f
Packit aea12f
      /* Test for error conditions before starting to fill *buf.  */
Packit aea12f
      if (sizeof (buf->st_size) <= 4 && info.nFileSizeHigh > 0)
Packit aea12f
        {
Packit aea12f
          errno = EOVERFLOW;
Packit aea12f
          return -1;
Packit aea12f
        }
Packit aea12f
Packit aea12f
#if _GL_WINDOWS_STAT_INODES
Packit aea12f
      /* st_ino can be determined through
Packit aea12f
         GetFileInformationByHandle
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information>
Packit aea12f
         as 64 bits, or through
Packit aea12f
         GetFileInformationByHandleEx with argument FileIdInfo
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_id_info>
Packit aea12f
         as 128 bits.
Packit aea12f
         The latter requires -D_WIN32_WINNT=_WIN32_WINNT_WIN8 or higher.  */
Packit aea12f
      /* Experiments show that GetFileInformationByHandleEx does not provide
Packit aea12f
         much more information than GetFileInformationByHandle:
Packit aea12f
           * The dwVolumeSerialNumber from GetFileInformationByHandle is equal
Packit aea12f
             to the low 32 bits of the 64-bit VolumeSerialNumber from
Packit aea12f
             GetFileInformationByHandleEx, and is apparently sufficient for
Packit aea12f
             identifying the device.
Packit aea12f
           * The nFileIndex from GetFileInformationByHandle is equal to the low
Packit aea12f
             64 bits of the 128-bit FileId from GetFileInformationByHandleEx,
Packit aea12f
             and the high 64 bits of this 128-bit FileId are zero.
Packit aea12f
           * On a FAT file system, GetFileInformationByHandleEx fails with error
Packit aea12f
             ERROR_INVALID_PARAMETER, whereas GetFileInformationByHandle
Packit aea12f
             succeeds.
Packit aea12f
           * On a CIFS/SMB file system, GetFileInformationByHandleEx fails with
Packit aea12f
             error ERROR_INVALID_LEVEL, whereas GetFileInformationByHandle
Packit aea12f
             succeeds.  */
Packit aea12f
# if _GL_WINDOWS_STAT_INODES == 2
Packit aea12f
      if (GetFileInformationByHandleExFunc != NULL)
Packit aea12f
        {
Packit aea12f
          FILE_ID_INFO id;
Packit aea12f
          if (GetFileInformationByHandleExFunc (h, FileIdInfo, &id, sizeof (id)))
Packit aea12f
            {
Packit aea12f
              buf->st_dev = id.VolumeSerialNumber;
Packit aea12f
              verify (sizeof (ino_t) == sizeof (id.FileId));
Packit aea12f
              memcpy (&buf->st_ino, &id.FileId, sizeof (ino_t));
Packit aea12f
              goto ino_done;
Packit aea12f
            }
Packit aea12f
          else
Packit aea12f
            {
Packit aea12f
              switch (GetLastError ())
Packit aea12f
                {
Packit aea12f
                case ERROR_INVALID_PARAMETER: /* older Windows version, or FAT */
Packit aea12f
                case ERROR_INVALID_LEVEL: /* CIFS/SMB file system */
Packit aea12f
                  goto fallback;
Packit aea12f
                default:
Packit aea12f
                  goto failed;
Packit aea12f
                }
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
     fallback: ;
Packit aea12f
      /* Fallback for older Windows versions.  */
Packit aea12f
      buf->st_dev = info.dwVolumeSerialNumber;
Packit aea12f
      buf->st_ino._gl_ino[0] = ((ULONGLONG) info.nFileIndexHigh << 32) | (ULONGLONG) info.nFileIndexLow;
Packit aea12f
      buf->st_ino._gl_ino[1] = 0;
Packit aea12f
     ino_done: ;
Packit aea12f
# else /* _GL_WINDOWS_STAT_INODES == 1 */
Packit aea12f
      buf->st_dev = info.dwVolumeSerialNumber;
Packit aea12f
      buf->st_ino = ((ULONGLONG) info.nFileIndexHigh << 32) | (ULONGLONG) info.nFileIndexLow;
Packit aea12f
# endif
Packit aea12f
#else
Packit aea12f
      /* st_ino is not wide enough for identifying a file on a device.
Packit aea12f
         Without st_ino, st_dev is pointless.  */
Packit aea12f
      buf->st_dev = 0;
Packit aea12f
      buf->st_ino = 0;
Packit aea12f
#endif
Packit aea12f
Packit aea12f
      /* st_mode.  */
Packit aea12f
      unsigned int mode =
Packit aea12f
        /* XXX How to handle FILE_ATTRIBUTE_REPARSE_POINT ?  */
Packit aea12f
        ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR | S_IEXEC_UGO : _S_IFREG)
Packit aea12f
        | S_IREAD_UGO
Packit aea12f
        | ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE_UGO);
Packit aea12f
      if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
Packit aea12f
        {
Packit aea12f
          /* Determine whether the file is executable by looking at the file
Packit aea12f
             name suffix.
Packit aea12f
             If the file name is already known, use it. Otherwise, for
Packit aea12f
             non-empty files, it can be determined through
Packit aea12f
             GetFinalPathNameByHandle
Packit aea12f
             <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea>
Packit aea12f
             or through
Packit aea12f
             GetFileInformationByHandleEx with argument FileNameInfo
Packit aea12f
             <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex>
Packit aea12f
             <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_name_info>
Packit aea12f
             Both require -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher.  */
Packit aea12f
          if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0)
Packit aea12f
            {
Packit aea12f
              char fpath[PATH_MAX];
Packit aea12f
              if (path != NULL
Packit aea12f
                  || (GetFinalPathNameByHandleFunc != NULL
Packit aea12f
                      && GetFinalPathNameByHandleFunc (h, fpath, sizeof (fpath), VOLUME_NAME_NONE)
Packit aea12f
                         < sizeof (fpath)
Packit aea12f
                      && (path = fpath, 1)))
Packit aea12f
                {
Packit aea12f
                  const char *last_dot = NULL;
Packit aea12f
                  const char *p;
Packit aea12f
                  for (p = path; *p != '\0'; p++)
Packit aea12f
                    if (*p == '.')
Packit aea12f
                      last_dot = p;
Packit aea12f
                  if (last_dot != NULL)
Packit aea12f
                    {
Packit aea12f
                      const char *suffix = last_dot + 1;
Packit aea12f
                      if (_stricmp (suffix, "exe") == 0
Packit aea12f
                          || _stricmp (suffix, "bat") == 0
Packit aea12f
                          || _stricmp (suffix, "cmd") == 0
Packit aea12f
                          || _stricmp (suffix, "com") == 0)
Packit aea12f
                        mode |= S_IEXEC_UGO;
Packit aea12f
                    }
Packit aea12f
                }
Packit aea12f
              else
Packit aea12f
                /* Cannot determine file name.  Pretend that it is executable.  */
Packit aea12f
                mode |= S_IEXEC_UGO;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
      buf->st_mode = mode;
Packit aea12f
Packit aea12f
      /* st_nlink can be determined through
Packit aea12f
         GetFileInformationByHandle
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandleEx with argument FileStandardInfo
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_standard_info>
Packit aea12f
         The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher.  */
Packit aea12f
      buf->st_nlink = (info.nNumberOfLinks > SHRT_MAX ? SHRT_MAX : info.nNumberOfLinks);
Packit aea12f
Packit aea12f
      /* There's no easy way to map the Windows SID concept to an integer.  */
Packit aea12f
      buf->st_uid = 0;
Packit aea12f
      buf->st_gid = 0;
Packit aea12f
Packit aea12f
      /* st_rdev is irrelevant for normal files and directories.  */
Packit aea12f
      buf->st_rdev = 0;
Packit aea12f
Packit aea12f
      /* st_size can be determined through
Packit aea12f
         GetFileSizeEx
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfilesizeex>
Packit aea12f
         or through
Packit aea12f
         GetFileAttributesEx
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesexa>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_win32_file_attribute_data>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandle
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandleEx with argument FileStandardInfo
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_standard_info>
Packit aea12f
         The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher.  */
Packit aea12f
      if (sizeof (buf->st_size) <= 4)
Packit aea12f
        /* Range check already done above.  */
Packit aea12f
        buf->st_size = info.nFileSizeLow;
Packit aea12f
      else
Packit aea12f
        buf->st_size = ((long long) info.nFileSizeHigh << 32) | (long long) info.nFileSizeLow;
Packit aea12f
Packit aea12f
      /* st_atime, st_mtime, st_ctime can be determined through
Packit aea12f
         GetFileTime
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletime>
Packit aea12f
         or through
Packit aea12f
         GetFileAttributesEx
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesexa>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_win32_file_attribute_data>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandle
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information>
Packit aea12f
         or through
Packit aea12f
         GetFileInformationByHandleEx with argument FileBasicInfo
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfileinformationbyhandleex>
Packit aea12f
         <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_file_basic_info>
Packit aea12f
         The latter requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher.  */
Packit aea12f
#if _GL_WINDOWS_STAT_TIMESPEC
Packit aea12f
      buf->st_atim = _gl_convert_FILETIME_to_timespec (&info.ftLastAccessTime);
Packit aea12f
      buf->st_mtim = _gl_convert_FILETIME_to_timespec (&info.ftLastWriteTime);
Packit aea12f
      buf->st_ctim = _gl_convert_FILETIME_to_timespec (&info.ftCreationTime);
Packit aea12f
#else
Packit aea12f
      buf->st_atime = _gl_convert_FILETIME_to_POSIX (&info.ftLastAccessTime);
Packit aea12f
      buf->st_mtime = _gl_convert_FILETIME_to_POSIX (&info.ftLastWriteTime);
Packit aea12f
      buf->st_ctime = _gl_convert_FILETIME_to_POSIX (&info.ftCreationTime);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
      return 0;
Packit aea12f
    }
Packit aea12f
  else if (type == FILE_TYPE_CHAR || type == FILE_TYPE_PIPE)
Packit aea12f
    {
Packit aea12f
      buf->st_dev = 0;
Packit aea12f
#if _GL_WINDOWS_STAT_INODES == 2
Packit aea12f
      buf->st_ino._gl_ino[0] = buf->st_ino._gl_ino[1] = 0;
Packit aea12f
#else
Packit aea12f
      buf->st_ino = 0;
Packit aea12f
#endif
Packit aea12f
      buf->st_mode = (type == FILE_TYPE_PIPE ? _S_IFIFO : _S_IFCHR);
Packit aea12f
      buf->st_nlink = 1;
Packit aea12f
      buf->st_uid = 0;
Packit aea12f
      buf->st_gid = 0;
Packit aea12f
      buf->st_rdev = 0;
Packit aea12f
      if (type == FILE_TYPE_PIPE)
Packit aea12f
        {
Packit aea12f
          /* PeekNamedPipe
Packit aea12f
             <https://msdn.microsoft.com/en-us/library/aa365779.aspx> */
Packit aea12f
          DWORD bytes_available;
Packit aea12f
          if (PeekNamedPipe (h, NULL, 0, NULL, &bytes_available, NULL))
Packit aea12f
            buf->st_size = bytes_available;
Packit aea12f
          else
Packit aea12f
            buf->st_size = 0;
Packit aea12f
        }
Packit aea12f
      else
Packit aea12f
        buf->st_size = 0;
Packit aea12f
#if _GL_WINDOWS_STAT_TIMESPEC
Packit aea12f
      buf->st_atim.tv_sec = 0; buf->st_atim.tv_nsec = 0;
Packit aea12f
      buf->st_mtim.tv_sec = 0; buf->st_mtim.tv_nsec = 0;
Packit aea12f
      buf->st_ctim.tv_sec = 0; buf->st_ctim.tv_nsec = 0;
Packit aea12f
#else
Packit aea12f
      buf->st_atime = 0;
Packit aea12f
      buf->st_mtime = 0;
Packit aea12f
      buf->st_ctime = 0;
Packit aea12f
#endif
Packit aea12f
      return 0;
Packit aea12f
    }
Packit aea12f
  else
Packit aea12f
    {
Packit aea12f
      errno = ENOENT;
Packit aea12f
      return -1;
Packit aea12f
    }
Packit aea12f
Packit aea12f
 failed:
Packit aea12f
  {
Packit aea12f
    DWORD error = GetLastError ();
Packit aea12f
    #if 0
Packit aea12f
    fprintf (stderr, "_gl_fstat_by_handle error 0x%x\n", (unsigned int) error);
Packit aea12f
    #endif
Packit aea12f
    switch (error)
Packit aea12f
      {
Packit aea12f
      case ERROR_ACCESS_DENIED:
Packit aea12f
      case ERROR_SHARING_VIOLATION:
Packit aea12f
        errno = EACCES;
Packit aea12f
        break;
Packit aea12f
Packit aea12f
      case ERROR_OUTOFMEMORY:
Packit aea12f
        errno = ENOMEM;
Packit aea12f
        break;
Packit aea12f
Packit aea12f
      case ERROR_WRITE_FAULT:
Packit aea12f
      case ERROR_READ_FAULT:
Packit aea12f
      case ERROR_GEN_FAILURE:
Packit aea12f
        errno = EIO;
Packit aea12f
        break;
Packit aea12f
Packit aea12f
      default:
Packit aea12f
        errno = EINVAL;
Packit aea12f
        break;
Packit aea12f
      }
Packit aea12f
    return -1;
Packit aea12f
  }
Packit aea12f
}
Packit aea12f
Packit aea12f
#else
Packit aea12f
Packit aea12f
/* This declaration is solely to ensure that after preprocessing
Packit aea12f
   this file is never empty.  */
Packit aea12f
typedef int dummy;
Packit aea12f
Packit aea12f
#endif