1 /* readable.c: check if a filename is a readable non-directory file.
3 Copyright 1993, 1995, 1996, 2008, 2011, 2012 Karl Berry.
4 Copyright 1998, 1999, 2000, 2001, 2005 Olaf Weber.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
20 #include <kpathsea/c-namemx.h>
21 #include <kpathsea/c-pathch.h>
22 #include <kpathsea/c-pathmx.h>
23 #include <kpathsea/c-stat.h>
24 #include <kpathsea/pathsearch.h>
25 #include <kpathsea/readable.h>
26 #include <kpathsea/tex-hush.h>
29 /* If access can read FN, run stat (assigning to stat buffer ST) and
30 check that fn is not a directory. Don't check for just being a
31 regular file, as it is potentially useful to read fifo's or some
35 /* `stat' is way too expensive for such a simple job. */
36 #define READABLE(fn, st) \
37 (access (fn, R_OK) == 0 && access (fn, D_OK) == -1)
39 /* st must be an unsigned int under Windows */
41 READABLE(const_string fn, unsigned int st)
44 fnw = get_wstring_from_fsyscp(fn, fnw=NULL);
45 if ((st = GetFileAttributesW(fnw)) != 0xFFFFFFFF) {
49 switch(GetLastError()) {
50 case ERROR_BUFFER_OVERFLOW:
53 case ERROR_ACCESS_DENIED:
57 errno = EIO; /* meaningless, will make ret=NULL later */
62 return ((st != 0xFFFFFFFF) &&
63 !(st & FILE_ATTRIBUTE_DIRECTORY));
66 #define READABLE(fn, st) \
67 (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && !S_ISDIR (st.st_mode))
71 /* POSIX invented the brain-damage of not necessarily truncating
72 filename components; the system's behavior is defined by the value of
73 the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! */
76 kpathsea_readable_file (kpathsea kpse, string name)
84 kpathsea_normalize_path (kpse, name);
85 if (READABLE (name, st)) {
88 } else if (errno == ENAMETOOLONG) {
89 /* Truncate any too-long components in NAME. */
90 unsigned c_len = 0; /* Length of current component. */
91 char *s = name; /* Position in current component. */
92 char *t = name; /* End of allowed length. */
95 if (c_len <= NAME_MAX)
104 if (IS_DIR_SEP (*s) || IS_DEVICE_SEP (*s)) {
105 if (c_len > NAME_MAX) {
106 /* Truncate if past the max for a component. */
107 memmove (t, s, strlen (s) + 1);
110 /* At a directory delimiter, reset component length. */
115 if (c_len > NAME_MAX)
116 /* Truncate if past the max for last component. */
119 /* Perhaps some other error will occur with the truncated name, so
120 let's call access again. */
121 if (READABLE (name, st)) /* Success. */
123 #endif /* ENAMETOOLONG */
124 } else { /* Some other error. */
125 if (errno == EACCES) { /* Maybe warn them if permissions are bad. */
126 if (!kpathsea_tex_hush (kpse, "readable")) {
134 #if defined (KPSE_COMPAT_API)
136 kpse_readable_file (string name)
138 return kpathsea_readable_file (kpse_def, name);