Blame gl/stat.c

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