OSDN Git Service

branch: yandytex with kpathsea.
[putex/putex.git] / src / texsourc / kpathsea / kpathsea / readable.c
1 /* readable.c: check if a filename is a readable non-directory file.
2
3    Copyright 1993, 1995, 1996, 2008, 2011, 2012 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-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>
27
28
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
32    kinds of devices.  */
33
34 #ifdef __DJGPP__
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)
38 #elif defined (WIN32)
39 /* st must be an unsigned int under Windows */
40 static boolean
41 READABLE(const_string fn, unsigned int st)
42 {
43   wchar_t *fnw;
44   fnw = get_wstring_from_fsyscp(fn, fnw=NULL);
45   if ((st = GetFileAttributesW(fnw)) != 0xFFFFFFFF) {
46       /* succeeded */
47       errno = 0;
48   } else {
49       switch(GetLastError()) {
50       case ERROR_BUFFER_OVERFLOW:
51           errno = ENAMETOOLONG;
52           break;
53       case ERROR_ACCESS_DENIED:
54           errno = EACCES;
55           break;
56       default :
57           errno = EIO;          /* meaningless, will make ret=NULL later */
58           break;
59       }
60   }
61   if(fnw) free(fnw);
62   return ((st != 0xFFFFFFFF) &&
63                   !(st & FILE_ATTRIBUTE_DIRECTORY));
64 }
65 #else
66 #define READABLE(fn, st) \
67   (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && !S_ISDIR (st.st_mode))
68 #endif
69
70
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!  */
74
75 string
76 kpathsea_readable_file (kpathsea kpse, string name)
77 {
78 #ifdef WIN32
79   unsigned int st = 0;
80 #else /* ! WIN32 */
81   struct stat st;
82 #endif
83
84   kpathsea_normalize_path (kpse, name);
85   if (READABLE (name, st)) {
86       return name;
87 #ifdef ENAMETOOLONG
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.  */
93       
94       for (; *s; s++) {
95           if (c_len <= NAME_MAX)
96               t = s;
97 #if defined(WIN32)
98           if (IS_KANJI (s)) {
99               s++;
100               c_len += 2;
101               continue;
102           }
103 #endif
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);
108                   s = t;
109               }
110               /* At a directory delimiter, reset component length.  */
111               c_len = 0;
112           } else
113               c_len++;
114       }
115       if (c_len > NAME_MAX)
116           /* Truncate if past the max for last component.  */
117           *t = 0;
118
119       /* Perhaps some other error will occur with the truncated name, so
120          let's call access again.  */
121       if (READABLE (name, st)) /* Success.  */
122           return name;
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")) {
127               perror (name);
128           }
129       }
130   }
131   return NULL;
132 }
133
134 #if defined (KPSE_COMPAT_API)
135 string
136 kpse_readable_file (string name)
137 {
138     return kpathsea_readable_file (kpse_def, name);
139 }
140 #endif