dvitomp fix from Akira
[mplib] / src / texk / kpathsea / dir.c
1 /* dir.c: directory operations.
2
3    Copyright 1992, 1993, 1994, 1995, 2008 Karl Berry.
4    Copyright 2000, 2002, 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
21 #include <kpathsea/c-dir.h>
22 #include <kpathsea/c-stat.h>
23 #include <kpathsea/hash.h>
24 #include <kpathsea/pathsearch.h>
25
26 /* Return true if FN is a directory or a symlink to a directory,
27    false if not. */
28
29 boolean
30 dir_p P1C(const_string, fn)
31 {
32   /* FIXME : using the stat() replacement in gnuw32, 
33          we could avoid this win32 specific code. However,
34          I wonder if it would be as fast as this one is ?
35   */
36 #ifdef WIN32
37   int fa;
38
39   kpse_normalize_path((string)fn);
40   fa = GetFileAttributes(fn);
41
42   if (KPSE_DEBUG_P(KPSE_DEBUG_STAT)) {
43     if (fa == 0xFFFFFFFF) {
44       fprintf(stderr, "failed to get file attributes for %s (%d)\n",
45               fn, GetLastError());
46     } else {
47       fprintf(stderr, "path %s %s a directory\n",
48               fn , (fa & FILE_ATTRIBUTE_DIRECTORY) ? 
49               "is"  : "is not");
50     }
51   }
52   return (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
53 #else
54   struct stat stats;
55   return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode);
56 #endif
57 }
58
59 /*
60   Return -1 if FN isn't a directory, else its number of links.
61   Duplicate the call to stat; no need to incur overhead of a function
62   call for that little bit of cleanliness.
63    
64   The process is a bit different under Win32 : the first call
65   memoizes the nlinks value, the following ones retrieve it.
66 */
67 int
68 dir_links P2C(const_string, fn, long, nlinks)
69 {
70   static hash_table_type link_table;
71   string *hash_ret;
72   
73   if (link_table.size == 0)
74     link_table = hash_create (457);
75
76 #ifdef KPSE_DEBUG
77   /* This is annoying, but since we're storing integers as pointers, we
78      can't print them as strings.  */
79   if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
80     kpse_debug_hash_lookup_int = true;
81 #endif
82
83   hash_ret = hash_lookup (link_table, fn);
84   
85 #ifdef KPSE_DEBUG
86   if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
87     kpse_debug_hash_lookup_int = false;
88 #endif
89
90   /* Have to cast the int we need to/from the const_string that the hash
91      table stores for values. Let's hope an int fits in a pointer.  */
92   if (hash_ret) {
93 #ifdef WIN32
94       memcpy(&nlinks, hash_ret, sizeof(nlinks));
95 #else
96       nlinks = (long) *hash_ret;
97 #endif
98   } else { 
99 #ifdef WIN32
100       /* Insert it only if we have some informations about it. */
101       if (nlinks) {
102         char str_nlinks[sizeof(nlinks)+1];
103         memcpy(str_nlinks, (char *)&nlinks, sizeof(nlinks));
104         str_nlinks[sizeof(nlinks)] = '\0';
105         /* It's up to us to copy the value.  */
106         hash_insert(&link_table, xstrdup(fn), (const_string)str_nlinks);
107       }
108 #else
109       struct stat stats;
110       if (stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode))
111         nlinks = stats.st_nlink;
112       else
113         nlinks = -1;
114       /* It's up to us to copy the value.  */
115       hash_insert(&link_table, xstrdup(fn), (const_string)nlinks);
116 #endif
117
118 #ifdef KPSE_DEBUG
119       if (KPSE_DEBUG_P (KPSE_DEBUG_STAT))
120         DEBUGF2 ("dir_links(%s) => %ld\n", fn, nlinks);
121 #endif
122   }
123
124   /* In any case, return nlinks 
125      (either 0, the value inserted or the value retrieved. */
126   return nlinks;
127 }