Blame lib/stat-w32.c

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