Blame lib/lstat.c

Packit Service a2489d
/* Work around a bug of lstat on some systems
Packit Service a2489d
Packit Service a2489d
   Copyright (C) 1997-2006, 2008-2018 Free Software Foundation, Inc.
Packit Service a2489d
Packit Service a2489d
   This program is free software: you can redistribute it and/or modify
Packit Service a2489d
   it under the terms of the GNU General Public License as published by
Packit Service a2489d
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
   (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   This program is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
   GNU General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public License
Packit Service a2489d
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2489d
Packit Service a2489d
/* written by Jim Meyering */
Packit Service a2489d
Packit Service a2489d
/* If the user's config.h happens to include <sys/stat.h>, let it include only
Packit Service a2489d
   the system's <sys/stat.h> here, so that orig_lstat doesn't recurse to
Packit Service a2489d
   rpl_lstat.  */
Packit Service a2489d
#define __need_system_sys_stat_h
Packit Service a2489d
#include <config.h>
Packit Service a2489d
Packit Service a2489d
#if !HAVE_LSTAT
Packit Service a2489d
/* On systems that lack symlinks, our replacement <sys/stat.h> already
Packit Service a2489d
   defined lstat as stat, so there is nothing further to do other than
Packit Service a2489d
   avoid an empty file.  */
Packit Service a2489d
typedef int dummy;
Packit Service a2489d
#else /* HAVE_LSTAT */
Packit Service a2489d
Packit Service a2489d
/* Get the original definition of lstat.  It might be defined as a macro.  */
Packit Service a2489d
# include <sys/types.h>
Packit Service a2489d
# include <sys/stat.h>
Packit Service a2489d
# undef __need_system_sys_stat_h
Packit Service a2489d
Packit Service a2489d
static int
Packit Service a2489d
orig_lstat (const char *filename, struct stat *buf)
Packit Service a2489d
{
Packit Service a2489d
  return lstat (filename, buf);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* Specification.  */
Packit Service a2489d
/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
Packit Service a2489d
   eliminates this include because of the preliminary #include <sys/stat.h>
Packit Service a2489d
   above.  */
Packit Service a2489d
# include "sys/stat.h"
Packit Service a2489d
Packit Service a2489d
# include "stat-time.h"
Packit Service a2489d
Packit Service a2489d
# include <string.h>
Packit Service a2489d
# include <errno.h>
Packit Service a2489d
Packit Service a2489d
/* lstat works differently on Linux and Solaris systems.  POSIX (see
Packit Service a2489d
   "pathname resolution" in the glossary) requires that programs like
Packit Service a2489d
   'ls' take into consideration the fact that FILE has a trailing slash
Packit Service a2489d
   when FILE is a symbolic link.  On Linux and Solaris 10 systems, the
Packit Service a2489d
   lstat function already has the desired semantics (in treating
Packit Service a2489d
   'lstat ("symlink/", sbuf)' just like 'lstat ("symlink/.", sbuf)',
Packit Service a2489d
   but on Solaris 9 and earlier it does not.
Packit Service a2489d
Packit Service a2489d
   If FILE has a trailing slash and specifies a symbolic link,
Packit Service a2489d
   then use stat() to get more info on the referent of FILE.
Packit Service a2489d
   If the referent is a non-directory, then set errno to ENOTDIR
Packit Service a2489d
   and return -1.  Otherwise, return stat's result.  */
Packit Service a2489d
Packit Service a2489d
int
Packit Service a2489d
rpl_lstat (const char *file, struct stat *sbuf)
Packit Service a2489d
{
Packit Service a2489d
  int result = orig_lstat (file, sbuf);
Packit Service a2489d
Packit Service a2489d
  /* This replacement file can blindly check against '/' rather than
Packit Service a2489d
     using the ISSLASH macro, because all platforms with '\\' either
Packit Service a2489d
     lack symlinks (mingw) or have working lstat (cygwin) and thus do
Packit Service a2489d
     not compile this file.  0 len should have already been filtered
Packit Service a2489d
     out above, with a failure return of ENOENT.  */
Packit Service a2489d
  if (result == 0)
Packit Service a2489d
    {
Packit Service a2489d
      if (S_ISDIR (sbuf->st_mode) || file[strlen (file) - 1] != '/')
Packit Service a2489d
        result = stat_time_normalize (result, sbuf);
Packit Service a2489d
      else
Packit Service a2489d
        {
Packit Service a2489d
          /* At this point, a trailing slash is permitted only on
Packit Service a2489d
             symlink-to-dir; but it should have found information on the
Packit Service a2489d
             directory, not the symlink.  Call 'stat' to get info about the
Packit Service a2489d
             link's referent.  Our replacement stat guarantees valid results,
Packit Service a2489d
             even if the symlink is not pointing to a directory.  */
Packit Service a2489d
          if (!S_ISLNK (sbuf->st_mode))
Packit Service a2489d
            {
Packit Service a2489d
              errno = ENOTDIR;
Packit Service a2489d
              return -1;
Packit Service a2489d
            }
Packit Service a2489d
          result = stat (file, sbuf);
Packit Service a2489d
        }
Packit Service a2489d
    }
Packit Service a2489d
  return result;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#endif /* HAVE_LSTAT */