New upstream version 1.9
[debian/gzip] / lib / lstat.c
index 27a0cb5103dc500f5ed7dabd5ef34a8a1703df28..5873bbd67c9084d87ec081af5fc5268a671cc925 100644 (file)
@@ -1,7 +1,6 @@
 /* Work around a bug of lstat on some systems
 
-   Copyright (C) 1997-1999, 2000-2006, 2008-2009 Free Software
-   Foundation, Inc.
+   Copyright (C) 1997-2006, 2008-2018 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Jim Meyering */
 
+/* If the user's config.h happens to include <sys/stat.h>, let it include only
+   the system's <sys/stat.h> here, so that orig_lstat doesn't recurse to
+   rpl_lstat.  */
+#define __need_system_sys_stat_h
 #include <config.h>
 
 #if !HAVE_LSTAT
@@ -28,29 +31,33 @@ typedef int dummy;
 #else /* HAVE_LSTAT */
 
 /* Get the original definition of lstat.  It might be defined as a macro.  */
-# define __need_system_sys_stat_h
 # include <sys/types.h>
 # include <sys/stat.h>
 # undef __need_system_sys_stat_h
 
-static inline int
+static int
 orig_lstat (const char *filename, struct stat *buf)
 {
   return lstat (filename, buf);
 }
 
 /* Specification.  */
-# include <sys/stat.h>
+/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
+   eliminates this include because of the preliminary #include <sys/stat.h>
+   above.  */
+# include "sys/stat.h"
+
+# include "stat-time.h"
 
 # include <string.h>
 # include <errno.h>
 
 /* lstat works differently on Linux and Solaris systems.  POSIX (see
-   `pathname resolution' in the glossary) requires that programs like
-   `ls' take into consideration the fact that FILE has a trailing slash
+   "pathname resolution" in the glossary) requires that programs like
+   'ls' take into consideration the fact that FILE has a trailing slash
    when FILE is a symbolic link.  On Linux and Solaris 10 systems, the
    lstat function already has the desired semantics (in treating
-   `lstat ("symlink/", sbuf)' just like `lstat ("symlink/.", sbuf)',
+   'lstat ("symlink/", sbuf)' just like 'lstat ("symlink/.", sbuf)',
    but on Solaris 9 and earlier it does not.
 
    If FILE has a trailing slash and specifies a symbolic link,
@@ -61,32 +68,33 @@ orig_lstat (const char *filename, struct stat *buf)
 int
 rpl_lstat (const char *file, struct stat *sbuf)
 {
-  size_t len;
-  int lstat_result = orig_lstat (file, sbuf);
-
-  if (lstat_result != 0)
-    return lstat_result;
+  int result = orig_lstat (file, sbuf);
 
   /* This replacement file can blindly check against '/' rather than
      using the ISSLASH macro, because all platforms with '\\' either
      lack symlinks (mingw) or have working lstat (cygwin) and thus do
      not compile this file.  0 len should have already been filtered
      out above, with a failure return of ENOENT.  */
-  len = strlen (file);
-  if (file[len - 1] != '/' || S_ISDIR (sbuf->st_mode))
-    return 0;
-
-  /* At this point, a trailing slash is only permitted on
-     symlink-to-dir; but it should have found information on the
-     directory, not the symlink.  Call stat() to get info about the
-     link's referent.  Our replacement stat guarantees valid results,
-     even if the symlink is not pointing to a directory.  */
-  if (!S_ISLNK (sbuf->st_mode))
+  if (result == 0)
     {
-      errno = ENOTDIR;
-      return -1;
+      if (S_ISDIR (sbuf->st_mode) || file[strlen (file) - 1] != '/')
+        result = stat_time_normalize (result, sbuf);
+      else
+        {
+          /* At this point, a trailing slash is permitted only on
+             symlink-to-dir; but it should have found information on the
+             directory, not the symlink.  Call 'stat' to get info about the
+             link's referent.  Our replacement stat guarantees valid results,
+             even if the symlink is not pointing to a directory.  */
+          if (!S_ISLNK (sbuf->st_mode))
+            {
+              errno = ENOTDIR;
+              return -1;
+            }
+          result = stat (file, sbuf);
+        }
     }
-  return stat (file, sbuf);
+  return result;
 }
 
 #endif /* HAVE_LSTAT */