Blame gl/stat-w32.c

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