Blame gl/tests/lstat.c

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