lstat.c revision 1.1 1 1.1 christos /* Work around a bug of lstat on some systems
2 1.1 christos
3 1.1 christos Copyright (C) 1997-2006, 2008-2020 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos This program is free software: you can redistribute it and/or modify
6 1.1 christos it under the terms of the GNU General Public License as published by
7 1.1 christos the Free Software Foundation; either version 3 of the License, or
8 1.1 christos (at your option) any later version.
9 1.1 christos
10 1.1 christos This program 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 christos GNU General Public License for more details.
14 1.1 christos
15 1.1 christos You should have received a copy of the GNU 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