Blame lib/fstatat.c

Packit 709fb3
/* Work around an fstatat bug on Solaris 9.
Packit 709fb3
Packit 709fb3
   Copyright (C) 2006, 2009-2017 Free Software Foundation, Inc.
Packit 709fb3
Packit 709fb3
   This program is free software: you can redistribute it and/or modify
Packit 709fb3
   it under the terms of the GNU General Public License as published by
Packit 709fb3
   the Free Software Foundation; either version 3 of the License, or
Packit 709fb3
   (at your option) any later version.
Packit 709fb3
Packit 709fb3
   This program is distributed in the hope that it will be useful,
Packit 709fb3
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 709fb3
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 709fb3
   GNU General Public License for more details.
Packit 709fb3
Packit 709fb3
   You should have received a copy of the GNU General Public License
Packit 709fb3
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 709fb3
Packit 709fb3
/* Written by Paul Eggert and Jim Meyering.  */
Packit 709fb3
Packit 709fb3
/* If the user's config.h happens to include <sys/stat.h>, let it include only
Packit 709fb3
   the system's <sys/stat.h> here, so that orig_fstatat doesn't recurse to
Packit 709fb3
   rpl_fstatat.  */
Packit 709fb3
#define __need_system_sys_stat_h
Packit 709fb3
#include <config.h>
Packit 709fb3
Packit 709fb3
/* Get the original definition of fstatat.  It might be defined as a macro.  */
Packit 709fb3
#include <sys/types.h>
Packit 709fb3
#include <sys/stat.h>
Packit 709fb3
#undef __need_system_sys_stat_h
Packit 709fb3
Packit 709fb3
#if HAVE_FSTATAT
Packit 709fb3
static int
Packit 709fb3
orig_fstatat (int fd, char const *filename, struct stat *buf, int flags)
Packit 709fb3
{
Packit 709fb3
  return fstatat (fd, filename, buf, flags);
Packit 709fb3
}
Packit 709fb3
#endif
Packit 709fb3
Packit 709fb3
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
Packit 709fb3
   eliminates this include because of the preliminary #include <sys/stat.h>
Packit 709fb3
   above.  */
Packit 709fb3
#include "sys/stat.h"
Packit 709fb3
Packit 709fb3
#include <errno.h>
Packit 709fb3
#include <fcntl.h>
Packit 709fb3
#include <string.h>
Packit 709fb3
Packit 709fb3
#if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG
Packit 709fb3
Packit 709fb3
# ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK
Packit 709fb3
#  define LSTAT_FOLLOWS_SLASHED_SYMLINK 0
Packit 709fb3
# endif
Packit 709fb3
Packit 709fb3
/* fstatat should always follow symbolic links that end in /, but on
Packit 709fb3
   Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified.
Packit 709fb3
   Likewise, trailing slash on a non-directory should be an error.
Packit 709fb3
   These are the same problems that lstat.c and stat.c address, so
Packit 709fb3
   solve it in a similar way.
Packit 709fb3
Packit 709fb3
   AIX 7.1 fstatat (AT_FDCWD, ..., 0) always fails, which is a bug.
Packit 709fb3
   Work around this bug if FSTATAT_AT_FDCWD_0_BROKEN is nonzero.  */
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
rpl_fstatat (int fd, char const *file, struct stat *st, int flag)
Packit 709fb3
{
Packit 709fb3
  int result = orig_fstatat (fd, file, st, flag);
Packit 709fb3
  size_t len;
Packit 709fb3
Packit 709fb3
  if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0)
Packit 709fb3
    return result;
Packit 709fb3
  len = strlen (file);
Packit 709fb3
  if (flag & AT_SYMLINK_NOFOLLOW)
Packit 709fb3
    {
Packit 709fb3
      /* Fix lstat behavior.  */
Packit 709fb3
      if (file[len - 1] != '/' || S_ISDIR (st->st_mode))
Packit 709fb3
        return 0;
Packit 709fb3
      if (!S_ISLNK (st->st_mode))
Packit 709fb3
        {
Packit 709fb3
          errno = ENOTDIR;
Packit 709fb3
          return -1;
Packit 709fb3
        }
Packit 709fb3
      result = orig_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW);
Packit 709fb3
    }
Packit 709fb3
  /* Fix stat behavior.  */
Packit 709fb3
  if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/')
Packit 709fb3
    {
Packit 709fb3
      errno = ENOTDIR;
Packit 709fb3
      return -1;
Packit 709fb3
    }
Packit 709fb3
  return result;
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
#else /* ! (HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG) */
Packit 709fb3
Packit 709fb3
/* On mingw, the gnulib <sys/stat.h> defines 'stat' as a function-like
Packit 709fb3
   macro; but using it in AT_FUNC_F2 causes compilation failure
Packit 709fb3
   because the preprocessor sees a use of a macro that requires two
Packit 709fb3
   arguments but is only given one.  Hence, we need an inline
Packit 709fb3
   forwarder to get past the preprocessor.  */
Packit 709fb3
static int
Packit 709fb3
stat_func (char const *name, struct stat *st)
Packit 709fb3
{
Packit 709fb3
  return stat (name, st);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
/* Likewise, if there is no native 'lstat', then the gnulib
Packit 709fb3
   <sys/stat.h> defined it as stat, which also needs adjustment.  */
Packit 709fb3
# if !HAVE_LSTAT
Packit 709fb3
#  undef lstat
Packit 709fb3
#  define lstat stat_func
Packit 709fb3
# endif
Packit 709fb3
Packit 709fb3
/* Replacement for Solaris' function by the same name.
Packit 709fb3
   <http://www.google.com/search?q=fstatat+site:docs.sun.com>
Packit 709fb3
   First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE").
Packit 709fb3
   Failing that, simulate it via save_cwd/fchdir/(stat|lstat)/restore_cwd.
Packit 709fb3
   If either the save_cwd or the restore_cwd fails (relatively unlikely),
Packit 709fb3
   then give a diagnostic and exit nonzero.
Packit 709fb3
   Otherwise, this function works just like Solaris' fstatat.  */
Packit 709fb3
Packit 709fb3
# define AT_FUNC_NAME fstatat
Packit 709fb3
# define AT_FUNC_F1 lstat
Packit 709fb3
# define AT_FUNC_F2 stat_func
Packit 709fb3
# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW
Packit 709fb3
# define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat *st, int flag
Packit 709fb3
# define AT_FUNC_POST_FILE_ARGS        , st
Packit 709fb3
# include "at-func.c"
Packit 709fb3
# undef AT_FUNC_NAME
Packit 709fb3
# undef AT_FUNC_F1
Packit 709fb3
# undef AT_FUNC_F2
Packit 709fb3
# undef AT_FUNC_USE_F1_COND
Packit 709fb3
# undef AT_FUNC_POST_FILE_PARAM_DECLS
Packit 709fb3
# undef AT_FUNC_POST_FILE_ARGS
Packit 709fb3
Packit 709fb3
#endif /* !HAVE_FSTATAT */