Blame lib/stat-w32.c

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