Blame gnulib/lib/stat.c

Packit Service a2ae7a
/* Work around platform bugs in stat.
Packit Service a2ae7a
   Copyright (C) 2009-2019 Free Software Foundation, Inc.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is free software: you can redistribute it and/or modify
Packit Service a2ae7a
   it under the terms of the GNU Lesser General Public License as published by
Packit Service a2ae7a
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service a2ae7a
   (at your option) any later version.
Packit Service a2ae7a
Packit Service a2ae7a
   This program is distributed in the hope that it will be useful,
Packit Service a2ae7a
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2ae7a
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2ae7a
   GNU Lesser General Public License for more details.
Packit Service a2ae7a
Packit Service a2ae7a
   You should have received a copy of the GNU Lesser General Public License
Packit Service a2ae7a
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* Written by Eric Blake and Bruno Haible.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* If the user's config.h happens to include <sys/stat.h>, let it include only
Packit Service a2ae7a
   the system's <sys/stat.h> here, so that orig_stat doesn't recurse to
Packit Service a2ae7a
   rpl_stat.  */
Packit Service a2ae7a
#define __need_system_sys_stat_h
Packit Service a2ae7a
#include <config.h>
Packit Service a2ae7a
Packit Service a2ae7a
/* Get the original definition of stat.  It might be defined as a macro.  */
Packit Service a2ae7a
#include <sys/types.h>
Packit Service a2ae7a
#include <sys/stat.h>
Packit Service a2ae7a
#undef __need_system_sys_stat_h
Packit Service a2ae7a
Packit Service a2ae7a
#if defined _WIN32 && ! defined __CYGWIN__
Packit Service a2ae7a
# define WINDOWS_NATIVE
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
#if !defined WINDOWS_NATIVE
Packit Service a2ae7a
Packit Service a2ae7a
static int
Packit Service a2ae7a
orig_stat (const char *filename, struct stat *buf)
Packit Service a2ae7a
{
Packit Service a2ae7a
  return stat (filename, buf);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* Specification.  */
Packit Service a2ae7a
#ifdef __osf__
Packit Service a2ae7a
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
Packit Service a2ae7a
   eliminates this include because of the preliminary #include <sys/stat.h>
Packit Service a2ae7a
   above.  */
Packit Service a2ae7a
# include "sys/stat.h"
Packit Service a2ae7a
#else
Packit Service a2ae7a
# include <sys/stat.h>
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
#include "stat-time.h"
Packit Service a2ae7a
Packit Service a2ae7a
#include <errno.h>
Packit Service a2ae7a
#include <limits.h>
Packit Service a2ae7a
#include <stdbool.h>
Packit Service a2ae7a
#include <string.h>
Packit Service a2ae7a
#include "filename.h"
Packit Service a2ae7a
#include "malloca.h"
Packit Service a2ae7a
#include "verify.h"
Packit Service a2ae7a
Packit Service a2ae7a
#ifdef WINDOWS_NATIVE
Packit Service a2ae7a
# define WIN32_LEAN_AND_MEAN
Packit Service a2ae7a
# include <windows.h>
Packit Service a2ae7a
# include "stat-w32.h"
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
#ifdef WINDOWS_NATIVE
Packit Service a2ae7a
/* Return TRUE if the given file name denotes an UNC root.  */
Packit Service a2ae7a
static BOOL
Packit Service a2ae7a
is_unc_root (const char *rname)
Packit Service a2ae7a
{
Packit Service a2ae7a
  /* Test whether it has the syntax '\\server\share'.  */
Packit Service a2ae7a
  if (ISSLASH (rname[0]) && ISSLASH (rname[1]))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* It starts with two slashes.  Find the next slash.  */
Packit Service a2ae7a
      const char *p = rname + 2;
Packit Service a2ae7a
      const char *q = p;
Packit Service a2ae7a
      while (*q != '\0' && !ISSLASH (*q))
Packit Service a2ae7a
        q++;
Packit Service a2ae7a
      if (q > p && *q != '\0')
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Found the next slash at q.  */
Packit Service a2ae7a
          q++;
Packit Service a2ae7a
          const char *r = q;
Packit Service a2ae7a
          while (*r != '\0' && !ISSLASH (*r))
Packit Service a2ae7a
            r++;
Packit Service a2ae7a
          if (r > q && *r == '\0')
Packit Service a2ae7a
            return TRUE;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return FALSE;
Packit Service a2ae7a
}
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* Store information about NAME into ST.  Work around bugs with
Packit Service a2ae7a
   trailing slashes.  Mingw has other bugs (such as st_ino always
Packit Service a2ae7a
   being 0 on success) which this wrapper does not work around.  But
Packit Service a2ae7a
   at least this implementation provides the ability to emulate fchdir
Packit Service a2ae7a
   correctly.  */
Packit Service a2ae7a
Packit Service a2ae7a
int
Packit Service a2ae7a
rpl_stat (char const *name, struct stat *buf)
Packit Service a2ae7a
{
Packit Service a2ae7a
#ifdef WINDOWS_NATIVE
Packit Service a2ae7a
  /* Fill the fields ourselves, because the original stat function returns
Packit Service a2ae7a
     values for st_atime, st_mtime, st_ctime that depend on the current time
Packit Service a2ae7a
     zone.  See
Packit Service a2ae7a
     <https://lists.gnu.org/r/bug-gnulib/2017-04/msg00134.html>  */
Packit Service a2ae7a
  /* XXX Should we convert to wchar_t* and prepend '\\?\', in order to work
Packit Service a2ae7a
     around length limitations
Packit Service a2ae7a
     <https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file> ?  */
Packit Service a2ae7a
Packit Service a2ae7a
  /* POSIX <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
Packit Service a2ae7a
     specifies: "More than two leading <slash> characters shall be treated as
Packit Service a2ae7a
     a single <slash> character."  */
Packit Service a2ae7a
  if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2]))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      name += 2;
Packit Service a2ae7a
      while (ISSLASH (name[1]))
Packit Service a2ae7a
        name++;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  size_t len = strlen (name);
Packit Service a2ae7a
  size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
Packit Service a2ae7a
Packit Service a2ae7a
  /* Remove trailing slashes (except the very first one, at position
Packit Service a2ae7a
     drive_prefix_len), but remember their presence.  */
Packit Service a2ae7a
  size_t rlen;
Packit Service a2ae7a
  bool check_dir = false;
Packit Service a2ae7a
Packit Service a2ae7a
  rlen = len;
Packit Service a2ae7a
  while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
Packit Service a2ae7a
    {
Packit Service a2ae7a
      check_dir = true;
Packit Service a2ae7a
      if (rlen == drive_prefix_len + 1)
Packit Service a2ae7a
        break;
Packit Service a2ae7a
      rlen--;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  /* Handle '' and 'C:'.  */
Packit Service a2ae7a
  if (!check_dir && rlen == drive_prefix_len)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      errno = ENOENT;
Packit Service a2ae7a
      return -1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  /* Handle '\\'.  */
Packit Service a2ae7a
  if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      errno = ENOENT;
Packit Service a2ae7a
      return -1;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  const char *rname;
Packit Service a2ae7a
  char *malloca_rname;
Packit Service a2ae7a
  if (rlen == len)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      rname = name;
Packit Service a2ae7a
      malloca_rname = NULL;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  else
Packit Service a2ae7a
    {
Packit Service a2ae7a
      malloca_rname = malloca (rlen + 1);
Packit Service a2ae7a
      if (malloca_rname == NULL)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          errno = ENOMEM;
Packit Service a2ae7a
          return -1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
      memcpy (malloca_rname, name, rlen);
Packit Service a2ae7a
      malloca_rname[rlen] = '\0';
Packit Service a2ae7a
      rname = malloca_rname;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  /* There are two ways to get at the requested information:
Packit Service a2ae7a
       - by scanning the parent directory and examining the relevant
Packit Service a2ae7a
         directory entry,
Packit Service a2ae7a
       - by opening the file directly.
Packit Service a2ae7a
     The first approach fails for root directories (e.g. 'C:\') and
Packit Service a2ae7a
     UNC root directories (e.g. '\\server\share').
Packit Service a2ae7a
     The second approach fails for some system files (e.g. 'C:\pagefile.sys'
Packit Service a2ae7a
     and 'C:\hiberfil.sys'): ERROR_SHARING_VIOLATION.
Packit Service a2ae7a
     The second approach gives more information (in particular, correct
Packit Service a2ae7a
     st_dev, st_ino, st_nlink fields).
Packit Service a2ae7a
     So we use the second approach and, as a fallback except for root and
Packit Service a2ae7a
     UNC root directories, also the first approach.  */
Packit Service a2ae7a
  {
Packit Service a2ae7a
    int ret;
Packit Service a2ae7a
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Approach based on the file.  */
Packit Service a2ae7a
Packit Service a2ae7a
      /* Open a handle to the file.
Packit Service a2ae7a
         CreateFile
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea>
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files>  */
Packit Service a2ae7a
      HANDLE h =
Packit Service a2ae7a
        CreateFile (rname,
Packit Service a2ae7a
                    FILE_READ_ATTRIBUTES,
Packit Service a2ae7a
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
Packit Service a2ae7a
                    NULL,
Packit Service a2ae7a
                    OPEN_EXISTING,
Packit Service a2ae7a
                    /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
Packit Service a2ae7a
                       in case as different) makes sense only when applied to *all*
Packit Service a2ae7a
                       filesystem operations.  */
Packit Service a2ae7a
                    FILE_FLAG_BACKUP_SEMANTICS /* | FILE_FLAG_POSIX_SEMANTICS */,
Packit Service a2ae7a
                    NULL);
Packit Service a2ae7a
      if (h != INVALID_HANDLE_VALUE)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          ret = _gl_fstat_by_handle (h, rname, buf);
Packit Service a2ae7a
          CloseHandle (h);
Packit Service a2ae7a
          goto done;
Packit Service a2ae7a
        }
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
    /* Test for root and UNC root directories.  */
Packit Service a2ae7a
    if ((rlen == drive_prefix_len + 1 && ISSLASH (rname[drive_prefix_len]))
Packit Service a2ae7a
        || is_unc_root (rname))
Packit Service a2ae7a
      goto failed;
Packit Service a2ae7a
Packit Service a2ae7a
    /* Fallback.  */
Packit Service a2ae7a
    {
Packit Service a2ae7a
      /* Approach based on the directory entry.  */
Packit Service a2ae7a
Packit Service a2ae7a
      if (strchr (rname, '?') != NULL || strchr (rname, '*') != NULL)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Other Windows API functions would fail with error
Packit Service a2ae7a
             ERROR_INVALID_NAME.  */
Packit Service a2ae7a
          if (malloca_rname != NULL)
Packit Service a2ae7a
            freea (malloca_rname);
Packit Service a2ae7a
          errno = ENOENT;
Packit Service a2ae7a
          return -1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
Packit Service a2ae7a
      /* Get the details about the directory entry.  This can be done through
Packit Service a2ae7a
         FindFirstFile
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-findfirstfilea>
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-_win32_find_dataa>
Packit Service a2ae7a
         or through
Packit Service a2ae7a
         FindFirstFileEx with argument FindExInfoBasic
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-findfirstfileexa>
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ne-minwinbase-findex_info_levels>
Packit Service a2ae7a
         <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-_win32_find_dataa>  */
Packit Service a2ae7a
      WIN32_FIND_DATA info;
Packit Service a2ae7a
      HANDLE h = FindFirstFile (rname, &info;;
Packit Service a2ae7a
      if (h == INVALID_HANDLE_VALUE)
Packit Service a2ae7a
        goto failed;
Packit Service a2ae7a
Packit Service a2ae7a
      /* Test for error conditions before starting to fill *buf.  */
Packit Service a2ae7a
      if (sizeof (buf->st_size) <= 4 && info.nFileSizeHigh > 0)
Packit Service a2ae7a
        {
Packit Service a2ae7a
          FindClose (h);
Packit Service a2ae7a
          if (malloca_rname != NULL)
Packit Service a2ae7a
            freea (malloca_rname);
Packit Service a2ae7a
          errno = EOVERFLOW;
Packit Service a2ae7a
          return -1;
Packit Service a2ae7a
        }
Packit Service a2ae7a
Packit Service a2ae7a
# if _GL_WINDOWS_STAT_INODES
Packit Service a2ae7a
      buf->st_dev = 0;
Packit Service a2ae7a
#  if _GL_WINDOWS_STAT_INODES == 2
Packit Service a2ae7a
      buf->st_ino._gl_ino[0] = buf->st_ino._gl_ino[1] = 0;
Packit Service a2ae7a
#  else /* _GL_WINDOWS_STAT_INODES == 1 */
Packit Service a2ae7a
      buf->st_ino = 0;
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
# else
Packit Service a2ae7a
      /* st_ino is not wide enough for identifying a file on a device.
Packit Service a2ae7a
         Without st_ino, st_dev is pointless.  */
Packit Service a2ae7a
      buf->st_dev = 0;
Packit Service a2ae7a
      buf->st_ino = 0;
Packit Service a2ae7a
# endif
Packit Service a2ae7a
Packit Service a2ae7a
      /* st_mode.  */
Packit Service a2ae7a
      unsigned int mode =
Packit Service a2ae7a
        /* XXX How to handle FILE_ATTRIBUTE_REPARSE_POINT ?  */
Packit Service a2ae7a
        ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR | S_IEXEC_UGO : _S_IFREG)
Packit Service a2ae7a
        | S_IREAD_UGO
Packit Service a2ae7a
        | ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE_UGO);
Packit Service a2ae7a
      if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          /* Determine whether the file is executable by looking at the file
Packit Service a2ae7a
             name suffix.  */
Packit Service a2ae7a
          if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0)
Packit Service a2ae7a
            {
Packit Service a2ae7a
              const char *last_dot = NULL;
Packit Service a2ae7a
              const char *p;
Packit Service a2ae7a
              for (p = info.cFileName; *p != '\0'; p++)
Packit Service a2ae7a
                if (*p == '.')
Packit Service a2ae7a
                  last_dot = p;
Packit Service a2ae7a
              if (last_dot != NULL)
Packit Service a2ae7a
                {
Packit Service a2ae7a
                  const char *suffix = last_dot + 1;
Packit Service a2ae7a
                  if (_stricmp (suffix, "exe") == 0
Packit Service a2ae7a
                      || _stricmp (suffix, "bat") == 0
Packit Service a2ae7a
                      || _stricmp (suffix, "cmd") == 0
Packit Service a2ae7a
                      || _stricmp (suffix, "com") == 0)
Packit Service a2ae7a
                    mode |= S_IEXEC_UGO;
Packit Service a2ae7a
                }
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
      buf->st_mode = mode;
Packit Service a2ae7a
Packit Service a2ae7a
      /* st_nlink.  Ignore hard links here.  */
Packit Service a2ae7a
      buf->st_nlink = 1;
Packit Service a2ae7a
Packit Service a2ae7a
      /* There's no easy way to map the Windows SID concept to an integer.  */
Packit Service a2ae7a
      buf->st_uid = 0;
Packit Service a2ae7a
      buf->st_gid = 0;
Packit Service a2ae7a
Packit Service a2ae7a
      /* st_rdev is irrelevant for normal files and directories.  */
Packit Service a2ae7a
      buf->st_rdev = 0;
Packit Service a2ae7a
Packit Service a2ae7a
      /* st_size.  */
Packit Service a2ae7a
      if (sizeof (buf->st_size) <= 4)
Packit Service a2ae7a
        /* Range check already done above.  */
Packit Service a2ae7a
        buf->st_size = info.nFileSizeLow;
Packit Service a2ae7a
      else
Packit Service a2ae7a
        buf->st_size = ((long long) info.nFileSizeHigh << 32) | (long long) info.nFileSizeLow;
Packit Service a2ae7a
Packit Service a2ae7a
      /* st_atime, st_mtime, st_ctime.  */
Packit Service a2ae7a
# if _GL_WINDOWS_STAT_TIMESPEC
Packit Service a2ae7a
      buf->st_atim = _gl_convert_FILETIME_to_timespec (&info.ftLastAccessTime);
Packit Service a2ae7a
      buf->st_mtim = _gl_convert_FILETIME_to_timespec (&info.ftLastWriteTime);
Packit Service a2ae7a
      buf->st_ctim = _gl_convert_FILETIME_to_timespec (&info.ftCreationTime);
Packit Service a2ae7a
# else
Packit Service a2ae7a
      buf->st_atime = _gl_convert_FILETIME_to_POSIX (&info.ftLastAccessTime);
Packit Service a2ae7a
      buf->st_mtime = _gl_convert_FILETIME_to_POSIX (&info.ftLastWriteTime);
Packit Service a2ae7a
      buf->st_ctime = _gl_convert_FILETIME_to_POSIX (&info.ftCreationTime);
Packit Service a2ae7a
# endif
Packit Service a2ae7a
Packit Service a2ae7a
      FindClose (h);
Packit Service a2ae7a
Packit Service a2ae7a
      ret = 0;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
   done:
Packit Service a2ae7a
    if (ret >= 0 && check_dir && !S_ISDIR (buf->st_mode))
Packit Service a2ae7a
      {
Packit Service a2ae7a
        errno = ENOTDIR;
Packit Service a2ae7a
        ret = -1;
Packit Service a2ae7a
      }
Packit Service a2ae7a
    if (malloca_rname != NULL)
Packit Service a2ae7a
      {
Packit Service a2ae7a
        int saved_errno = errno;
Packit Service a2ae7a
        freea (malloca_rname);
Packit Service a2ae7a
        errno = saved_errno;
Packit Service a2ae7a
      }
Packit Service a2ae7a
    return ret;
Packit Service a2ae7a
  }
Packit Service a2ae7a
Packit Service a2ae7a
 failed:
Packit Service a2ae7a
  {
Packit Service a2ae7a
    DWORD error = GetLastError ();
Packit Service a2ae7a
    #if 0
Packit Service a2ae7a
    fprintf (stderr, "rpl_stat error 0x%x\n", (unsigned int) error);
Packit Service a2ae7a
    #endif
Packit Service a2ae7a
Packit Service a2ae7a
    if (malloca_rname != NULL)
Packit Service a2ae7a
      freea (malloca_rname);
Packit Service a2ae7a
Packit Service a2ae7a
    switch (error)
Packit Service a2ae7a
      {
Packit Service a2ae7a
      /* Some of these errors probably cannot happen with the specific flags
Packit Service a2ae7a
         that we pass to CreateFile.  But who knows...  */
Packit Service a2ae7a
      case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist.  */
Packit Service a2ae7a
      case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist.  */
Packit Service a2ae7a
      case ERROR_BAD_PATHNAME:   /* rname is such as '\\server'.  */
Packit Service a2ae7a
      case ERROR_BAD_NET_NAME:   /* rname is such as '\\server\nonexistentshare'.  */
Packit Service a2ae7a
      case ERROR_INVALID_NAME:   /* rname contains wildcards, misplaced colon, etc.  */
Packit Service a2ae7a
      case ERROR_DIRECTORY:
Packit Service a2ae7a
        errno = ENOENT;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      case ERROR_ACCESS_DENIED:  /* rname is such as 'C:\System Volume Information\foo'.  */
Packit Service a2ae7a
      case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys' (second approach only).  */
Packit Service a2ae7a
                                    /* XXX map to EACCESS or EPERM? */
Packit Service a2ae7a
        errno = EACCES;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      case ERROR_OUTOFMEMORY:
Packit Service a2ae7a
        errno = ENOMEM;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      case ERROR_WRITE_PROTECT:
Packit Service a2ae7a
        errno = EROFS;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      case ERROR_WRITE_FAULT:
Packit Service a2ae7a
      case ERROR_READ_FAULT:
Packit Service a2ae7a
      case ERROR_GEN_FAILURE:
Packit Service a2ae7a
        errno = EIO;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      case ERROR_BUFFER_OVERFLOW:
Packit Service a2ae7a
      case ERROR_FILENAME_EXCED_RANGE:
Packit Service a2ae7a
        errno = ENAMETOOLONG;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      case ERROR_DELETE_PENDING: /* XXX map to EACCESS or EPERM? */
Packit Service a2ae7a
        errno = EPERM;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
Packit Service a2ae7a
      default:
Packit Service a2ae7a
        errno = EINVAL;
Packit Service a2ae7a
        break;
Packit Service a2ae7a
      }
Packit Service a2ae7a
Packit Service a2ae7a
    return -1;
Packit Service a2ae7a
  }
Packit Service a2ae7a
#else
Packit Service a2ae7a
  int result = orig_stat (name, buf);
Packit Service a2ae7a
  if (result == 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
# if REPLACE_FUNC_STAT_FILE
Packit Service a2ae7a
      /* Solaris 9 mistakenly succeeds when given a non-directory with a
Packit Service a2ae7a
         trailing slash.  */
Packit Service a2ae7a
      if (!S_ISDIR (buf->st_mode))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          size_t len = strlen (name);
Packit Service a2ae7a
          if (ISSLASH (name[len - 1]))
Packit Service a2ae7a
            {
Packit Service a2ae7a
              errno = ENOTDIR;
Packit Service a2ae7a
              return -1;
Packit Service a2ae7a
            }
Packit Service a2ae7a
        }
Packit Service a2ae7a
# endif /* REPLACE_FUNC_STAT_FILE */
Packit Service a2ae7a
      result = stat_time_normalize (result, buf);
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return result;
Packit Service a2ae7a
#endif
Packit Service a2ae7a
}