Blame lib/stat-w32.c

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