Home | History | Annotate | Line # | Download | only in import
      1      1.1  christos /* Work around a bug of lstat on some systems
      2      1.1  christos 
      3  1.1.1.2  christos    Copyright (C) 1997-2006, 2008-2022 Free Software Foundation, Inc.
      4      1.1  christos 
      5  1.1.1.2  christos    This file is free software: you can redistribute it and/or modify
      6  1.1.1.2  christos    it under the terms of the GNU Lesser General Public License as
      7  1.1.1.2  christos    published by the Free Software Foundation; either version 2.1 of the
      8  1.1.1.2  christos    License, or (at your option) any later version.
      9      1.1  christos 
     10  1.1.1.2  christos    This file is distributed in the hope that it will be useful,
     11      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1.1.2  christos    GNU Lesser General Public License for more details.
     14      1.1  christos 
     15  1.1.1.2  christos    You should have received a copy of the GNU Lesser General Public License
     16      1.1  christos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
     17      1.1  christos 
     18      1.1  christos /* written by Jim Meyering */
     19      1.1  christos 
     20      1.1  christos /* If the user's config.h happens to include <sys/stat.h>, let it include only
     21      1.1  christos    the system's <sys/stat.h> here, so that orig_lstat doesn't recurse to
     22      1.1  christos    rpl_lstat.  */
     23      1.1  christos #define __need_system_sys_stat_h
     24      1.1  christos #include <config.h>
     25      1.1  christos 
     26      1.1  christos #if !HAVE_LSTAT
     27      1.1  christos /* On systems that lack symlinks, our replacement <sys/stat.h> already
     28      1.1  christos    defined lstat as stat, so there is nothing further to do other than
     29      1.1  christos    avoid an empty file.  */
     30      1.1  christos typedef int dummy;
     31      1.1  christos #else /* HAVE_LSTAT */
     32      1.1  christos 
     33      1.1  christos /* Get the original definition of lstat.  It might be defined as a macro.  */
     34      1.1  christos # include <sys/types.h>
     35      1.1  christos # include <sys/stat.h>
     36      1.1  christos # undef __need_system_sys_stat_h
     37      1.1  christos 
     38      1.1  christos static int
     39      1.1  christos orig_lstat (const char *filename, struct stat *buf)
     40      1.1  christos {
     41      1.1  christos   return lstat (filename, buf);
     42      1.1  christos }
     43      1.1  christos 
     44      1.1  christos /* Specification.  */
     45      1.1  christos # ifdef __osf__
     46      1.1  christos /* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
     47      1.1  christos    eliminates this include because of the preliminary #include <sys/stat.h>
     48      1.1  christos    above.  */
     49      1.1  christos #  include "sys/stat.h"
     50      1.1  christos # else
     51      1.1  christos #  include <sys/stat.h>
     52      1.1  christos # endif
     53      1.1  christos 
     54      1.1  christos # include "stat-time.h"
     55      1.1  christos 
     56      1.1  christos # include <string.h>
     57      1.1  christos # include <errno.h>
     58      1.1  christos 
     59      1.1  christos /* lstat works differently on Linux and Solaris systems.  POSIX (see
     60      1.1  christos    "pathname resolution" in the glossary) requires that programs like
     61      1.1  christos    'ls' take into consideration the fact that FILE has a trailing slash
     62      1.1  christos    when FILE is a symbolic link.  On Linux and Solaris 10 systems, the
     63      1.1  christos    lstat function already has the desired semantics (in treating
     64      1.1  christos    'lstat ("symlink/", sbuf)' just like 'lstat ("symlink/.", sbuf)',
     65      1.1  christos    but on Solaris 9 and earlier it does not.
     66      1.1  christos 
     67      1.1  christos    If FILE has a trailing slash and specifies a symbolic link,
     68      1.1  christos    then use stat() to get more info on the referent of FILE.
     69      1.1  christos    If the referent is a non-directory, then set errno to ENOTDIR
     70      1.1  christos    and return -1.  Otherwise, return stat's result.  */
     71      1.1  christos 
     72      1.1  christos int
     73      1.1  christos rpl_lstat (const char *file, struct stat *sbuf)
     74      1.1  christos {
     75      1.1  christos   int result = orig_lstat (file, sbuf);
     76      1.1  christos 
     77      1.1  christos   /* This replacement file can blindly check against '/' rather than
     78      1.1  christos      using the ISSLASH macro, because all platforms with '\\' either
     79      1.1  christos      lack symlinks (mingw) or have working lstat (cygwin) and thus do
     80      1.1  christos      not compile this file.  0 len should have already been filtered
     81      1.1  christos      out above, with a failure return of ENOENT.  */
     82      1.1  christos   if (result == 0)
     83      1.1  christos     {
     84      1.1  christos       if (S_ISDIR (sbuf->st_mode) || file[strlen (file) - 1] != '/')
     85      1.1  christos         result = stat_time_normalize (result, sbuf);
     86      1.1  christos       else
     87      1.1  christos         {
     88      1.1  christos           /* At this point, a trailing slash is permitted only on
     89      1.1  christos              symlink-to-dir; but it should have found information on the
     90      1.1  christos              directory, not the symlink.  Call 'stat' to get info about the
     91      1.1  christos              link's referent.  Our replacement stat guarantees valid results,
     92      1.1  christos              even if the symlink is not pointing to a directory.  */
     93      1.1  christos           if (!S_ISLNK (sbuf->st_mode))
     94      1.1  christos             {
     95      1.1  christos               errno = ENOTDIR;
     96      1.1  christos               return -1;
     97      1.1  christos             }
     98      1.1  christos           result = stat (file, sbuf);
     99      1.1  christos         }
    100      1.1  christos     }
    101      1.1  christos   return result;
    102      1.1  christos }
    103      1.1  christos 
    104      1.1  christos #endif /* HAVE_LSTAT */
    105