dvitomp fix from Akira
[mplib] / src / texk / kpathsea / readable.c
1 /* readable.c: check if a filename is a readable non-directory file.
2
3    Copyright 1993, 1995, 1996, 2008 Karl Berry.
4    Copyright 1998, 1999, 2000, 2001, 2005 Olaf Weber.
5
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.
10
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.
15
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/>.  */
18
19 #include <kpathsea/config.h>
20 #include <kpathsea/c-stat.h>
21 #include <kpathsea/pathsearch.h>
22 #include <kpathsea/readable.h>
23 #include <kpathsea/tex-hush.h>
24 #include <kpathsea/truncate.h>
25
26
27 /* If access can read FN, run stat (assigning to stat buffer ST) and
28    check that fn is not a directory.  Don't check for just being a
29    regular file, as it is potentially useful to read fifo's or some
30    kinds of devices.  */
31
32 #ifdef __DJGPP__
33 /* `stat' is way too expensive for such a simple job.  */
34 #define READABLE(fn, st) \
35   (access (fn, R_OK) == 0 && access (fn, D_OK) == -1)
36 #elif WIN32
37 /* Warning: st must be an unsigned int under Win32 */
38 static boolean
39 READABLE(const_string fn, unsigned int st)
40 {
41   if ((st = GetFileAttributes(fn)) != 0xFFFFFFFF) {
42       /* succeeded */
43       errno = 0;
44   } else {
45       switch(GetLastError()) {
46       case ERROR_BUFFER_OVERFLOW:
47           errno = ENAMETOOLONG;
48           break;
49       case ERROR_ACCESS_DENIED:
50           errno = EACCES;
51           break;
52       default :
53           errno = EIO;          /* meaningless, will make ret=NULL later */
54           break;
55       }
56   }
57   return ((st != 0xFFFFFFFF) &&
58                   !(st & FILE_ATTRIBUTE_DIRECTORY));
59 }
60 #else
61 #define READABLE(fn, st) \
62   (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && !S_ISDIR (st.st_mode))
63 #endif
64
65 /* POSIX invented the brain-damage of not necessarily truncating
66    filename components; the system's behavior is defined by the value of
67    the symbol _POSIX_NO_TRUNC, but you can't change it dynamically!
68    
69    Generic const return warning.  See extend-fname.c.  */
70
71 string
72 kpse_readable_file P1C(const_string, name)
73 {
74   string ret;
75
76 #ifdef WIN32
77   unsigned int st = 0;
78 #else /* ! WIN32 */
79   struct stat st;
80 #endif
81
82   kpse_normalize_path((string)name);
83   if (READABLE (name, st)) {
84       ret = (string) name;
85 #ifdef ENAMETOOLONG
86   } else if (errno == ENAMETOOLONG) {
87       ret = kpse_truncate_filename (name);
88
89       /* Perhaps some other error will occur with the truncated name, so
90          let's call access again.  */
91       if (!READABLE (ret, st)) { /* Failed.  */
92           if (ret != name) free (ret);
93           ret = NULL;
94       }
95 #endif /* ENAMETOOLONG */
96   } else { /* Some other error.  */
97       if (errno == EACCES) { /* Maybe warn them if permissions are bad.  */
98           if (!kpse_tex_hush ("readable")) {
99               perror (name);
100           }
101       }
102       ret = NULL;
103   }
104   return ret;
105 }