Blame lib/lstat.c

Packit Service fdd496
/* Work around a bug of lstat on some systems
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 1997-2006, 2008-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 Jim Meyering */
Packit Service fdd496
Packit Service fdd496
/* If the user's config.h happens to include <sys/stat.h>, let it include only
Packit Service fdd496
   the system's <sys/stat.h> here, so that orig_lstat doesn't recurse to
Packit Service fdd496
   rpl_lstat.  */
Packit Service fdd496
#define __need_system_sys_stat_h
Packit Service fdd496
#include <config.h>
Packit Service fdd496
Packit Service fdd496
#if !HAVE_LSTAT
Packit Service fdd496
/* On systems that lack symlinks, our replacement <sys/stat.h> already
Packit Service fdd496
   defined lstat as stat, so there is nothing further to do other than
Packit Service fdd496
   avoid an empty file.  */
Packit Service fdd496
typedef int dummy;
Packit Service fdd496
#else /* HAVE_LSTAT */
Packit Service fdd496
Packit Service fdd496
/* Get the original definition of lstat.  It might be defined as a macro.  */
Packit Service fdd496
# include <sys/types.h>
Packit Service fdd496
# include <sys/stat.h>
Packit Service fdd496
# undef __need_system_sys_stat_h
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
orig_lstat (const char *filename, struct stat *buf)
Packit Service fdd496
{
Packit Service fdd496
  return lstat (filename, buf);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Specification.  */
Packit Service fdd496
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
Packit Service fdd496
   eliminates this include because of the preliminary #include <sys/stat.h>
Packit Service fdd496
   above.  */
Packit Service fdd496
# include "sys/stat.h"
Packit Service fdd496
Packit Service fdd496
# include <string.h>
Packit Service fdd496
# include <errno.h>
Packit Service fdd496
Packit Service fdd496
/* lstat works differently on Linux and Solaris systems.  POSIX (see
Packit Service fdd496
   "pathname resolution" in the glossary) requires that programs like
Packit Service fdd496
   'ls' take into consideration the fact that FILE has a trailing slash
Packit Service fdd496
   when FILE is a symbolic link.  On Linux and Solaris 10 systems, the
Packit Service fdd496
   lstat function already has the desired semantics (in treating
Packit Service fdd496
   'lstat ("symlink/", sbuf)' just like 'lstat ("symlink/.", sbuf)',
Packit Service fdd496
   but on Solaris 9 and earlier it does not.
Packit Service fdd496
Packit Service fdd496
   If FILE has a trailing slash and specifies a symbolic link,
Packit Service fdd496
   then use stat() to get more info on the referent of FILE.
Packit Service fdd496
   If the referent is a non-directory, then set errno to ENOTDIR
Packit Service fdd496
   and return -1.  Otherwise, return stat's result.  */
Packit Service fdd496
Packit Service fdd496
int
Packit Service fdd496
rpl_lstat (const char *file, struct stat *sbuf)
Packit Service fdd496
{
Packit Service fdd496
  size_t len;
Packit Service fdd496
  int lstat_result = orig_lstat (file, sbuf);
Packit Service fdd496
Packit Service fdd496
  if (lstat_result != 0)
Packit Service fdd496
    return lstat_result;
Packit Service fdd496
Packit Service fdd496
  /* This replacement file can blindly check against '/' rather than
Packit Service fdd496
     using the ISSLASH macro, because all platforms with '\\' either
Packit Service fdd496
     lack symlinks (mingw) or have working lstat (cygwin) and thus do
Packit Service fdd496
     not compile this file.  0 len should have already been filtered
Packit Service fdd496
     out above, with a failure return of ENOENT.  */
Packit Service fdd496
  len = strlen (file);
Packit Service fdd496
  if (file[len - 1] != '/' || S_ISDIR (sbuf->st_mode))
Packit Service fdd496
    return 0;
Packit Service fdd496
Packit Service fdd496
  /* At this point, a trailing slash is only permitted on
Packit Service fdd496
     symlink-to-dir; but it should have found information on the
Packit Service fdd496
     directory, not the symlink.  Call stat() to get info about the
Packit Service fdd496
     link's referent.  Our replacement stat guarantees valid results,
Packit Service fdd496
     even if the symlink is not pointing to a directory.  */
Packit Service fdd496
  if (!S_ISLNK (sbuf->st_mode))
Packit Service fdd496
    {
Packit Service fdd496
      errno = ENOTDIR;
Packit Service fdd496
      return -1;
Packit Service fdd496
    }
Packit Service fdd496
  return stat (file, sbuf);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
#endif /* HAVE_LSTAT */