Blame lib/stat-w32.c

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