/* readable.c: check if a filename is a readable non-directory file. Copyright 1993, 1995, 1996, 2008 Karl Berry. Copyright 1998, 1999, 2000, 2001, 2005 Olaf Weber. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include #include #include #include #include #include /* If access can read FN, run stat (assigning to stat buffer ST) and check that fn is not a directory. Don't check for just being a regular file, as it is potentially useful to read fifo's or some kinds of devices. */ #ifdef __DJGPP__ /* `stat' is way too expensive for such a simple job. */ #define READABLE(fn, st) \ (access (fn, R_OK) == 0 && access (fn, D_OK) == -1) #elif WIN32 /* Warning: st must be an unsigned int under Win32 */ static boolean READABLE(const_string fn, unsigned int st) { if ((st = GetFileAttributes(fn)) != 0xFFFFFFFF) { /* succeeded */ errno = 0; } else { switch(GetLastError()) { case ERROR_BUFFER_OVERFLOW: errno = ENAMETOOLONG; break; case ERROR_ACCESS_DENIED: errno = EACCES; break; default : errno = EIO; /* meaningless, will make ret=NULL later */ break; } } return ((st != 0xFFFFFFFF) && !(st & FILE_ATTRIBUTE_DIRECTORY)); } #else #define READABLE(fn, st) \ (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && !S_ISDIR (st.st_mode)) #endif /* POSIX invented the brain-damage of not necessarily truncating filename components; the system's behavior is defined by the value of the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! Generic const return warning. See extend-fname.c. */ string kpathsea_readable_file (kpathsea kpse, const_string name) { string ret; #ifdef WIN32 unsigned int st = 0; #else /* ! WIN32 */ struct stat st; #endif kpathsea_normalize_path(kpse, (string)name); if (READABLE (name, st)) { ret = (string) name; #ifdef ENAMETOOLONG } else if (errno == ENAMETOOLONG) { ret = kpathsea_truncate_filename (kpse, name); /* Perhaps some other error will occur with the truncated name, so let's call access again. */ if (!READABLE (ret, st)) { /* Failed. */ if (ret != name) free (ret); ret = NULL; } #endif /* ENAMETOOLONG */ } else { /* Some other error. */ if (errno == EACCES) { /* Maybe warn them if permissions are bad. */ if (!kpathsea_tex_hush (kpse, "readable")) { perror (name); } } ret = NULL; } return ret; } #if defined (KPSE_COMPAT_API) string kpse_readable_file (const_string name) { return kpathsea_readable_file (kpse_def, name); } #endif