* makeint.h (STOP_SET): [SV 40371] Cast to unsigned char.
[platform/upstream/make.git] / dir.c
1 /* Directory hashing for GNU Make.
2 Copyright (C) 1988-2013 Free Software Foundation, Inc.
3 This file is part of GNU Make.
4
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
8 version.
9
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include "makeint.h"
18 #include "hash.h"
19 #include "filedef.h"
20 #include "dep.h"
21
22 #ifdef  HAVE_DIRENT_H
23 # include <dirent.h>
24 # define NAMLEN(dirent) strlen((dirent)->d_name)
25 # ifdef VMS
26 /* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */
27 const char *vmsify (const char *name, int type);
28 # endif
29 #else
30 # define dirent direct
31 # define NAMLEN(dirent) (dirent)->d_namlen
32 # ifdef HAVE_SYS_NDIR_H
33 #  include <sys/ndir.h>
34 # endif
35 # ifdef HAVE_SYS_DIR_H
36 #  include <sys/dir.h>
37 # endif
38 # ifdef HAVE_NDIR_H
39 #  include <ndir.h>
40 # endif
41 # ifdef HAVE_VMSDIR_H
42 #  include "vmsdir.h"
43 # endif /* HAVE_VMSDIR_H */
44 #endif
45
46 /* In GNU systems, <dirent.h> defines this macro for us.  */
47 #ifdef _D_NAMLEN
48 # undef NAMLEN
49 # define NAMLEN(d) _D_NAMLEN(d)
50 #endif
51
52 #if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__)
53 /* Posix does not require that the d_ino field be present, and some
54    systems do not provide it. */
55 # define REAL_DIR_ENTRY(dp) 1
56 # define FAKE_DIR_ENTRY(dp)
57 #else
58 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
59 # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1)
60 #endif /* POSIX */
61 \f
62 #ifdef __MSDOS__
63 #include <ctype.h>
64 #include <fcntl.h>
65
66 /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support.  */
67 #ifndef _USE_LFN
68 #define _USE_LFN 0
69 #endif
70
71 static const char *
72 dosify (const char *filename)
73 {
74   static char dos_filename[14];
75   char *df;
76   int i;
77
78   if (filename == 0 || _USE_LFN)
79     return filename;
80
81   /* FIXME: what about filenames which violate
82      8+3 constraints, like "config.h.in", or ".emacs"?  */
83   if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0)
84     return filename;
85
86   df = dos_filename;
87
88   /* First, transform the name part.  */
89   for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
90     *df++ = tolower ((unsigned char)*filename++);
91
92   /* Now skip to the next dot.  */
93   while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
94     ++filename;
95   if (*filename != '\0')
96     {
97       *df++ = *filename++;
98       for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
99         *df++ = tolower ((unsigned char)*filename++);
100     }
101
102   /* Look for more dots.  */
103   while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
104     ++filename;
105   if (*filename == '.')
106     return filename;
107   *df = 0;
108   return dos_filename;
109 }
110 #endif /* __MSDOS__ */
111
112 #ifdef WINDOWS32
113 #include "pathstuff.h"
114 #endif
115
116 #ifdef _AMIGA
117 #include <ctype.h>
118 #endif
119
120 #ifdef HAVE_CASE_INSENSITIVE_FS
121 static const char *
122 downcase (const char *filename)
123 {
124   static PATH_VAR (new_filename);
125   char *df;
126
127   if (filename == 0)
128     return 0;
129
130   df = new_filename;
131   while (*filename != '\0')
132     {
133       *df++ = tolower ((unsigned char)*filename);
134       ++filename;
135     }
136
137   *df = 0;
138
139   return new_filename;
140 }
141 #endif /* HAVE_CASE_INSENSITIVE_FS */
142
143 #ifdef VMS
144
145 static int
146 vms_hash (const char *name)
147 {
148   int h = 0;
149
150   while (*name)
151     {
152       unsigned char uc = *name;
153       int g;
154 #ifdef HAVE_CASE_INSENSITIVE_FS
155       h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
156 #else
157       h = (h << 4) + uc;
158 #endif
159       name++;
160       g = h & 0xf0000000;
161       if (g)
162         {
163           h = h ^ (g >> 24);
164           h = h ^ g;
165         }
166     }
167   return h;
168 }
169
170 /* fake stat entry for a directory */
171 static int
172 vmsstat_dir (const char *name, struct stat *st)
173 {
174   char *s;
175   int h;
176   DIR *dir;
177
178   dir = opendir (name);
179   if (dir == 0)
180     return -1;
181   closedir (dir);
182   s = strchr (name, ':');       /* find device */
183   if (s)
184     {
185       /* to keep the compiler happy we said "const char *name", now we cheat */
186       *s++ = 0;
187       st->st_dev = (char *)vms_hash (name);
188       h = vms_hash (s);
189       *(s-1) = ':';
190     }
191   else
192     {
193       st->st_dev = 0;
194       h = vms_hash (name);
195     }
196
197   st->st_ino[0] = h & 0xff;
198   st->st_ino[1] = h & 0xff00;
199   st->st_ino[2] = h >> 16;
200
201   return 0;
202 }
203 #endif /* VMS */
204 \f
205 /* Hash table of directories.  */
206
207 #ifndef DIRECTORY_BUCKETS
208 #define DIRECTORY_BUCKETS 199
209 #endif
210
211 struct directory_contents
212   {
213     dev_t dev;                  /* Device and inode numbers of this dir.  */
214 #ifdef WINDOWS32
215     /* Inode means nothing on WINDOWS32. Even file key information is
216      * unreliable because it is random per file open and undefined for remote
217      * filesystems. The most unique attribute I can come up with is the fully
218      * qualified name of the directory. Beware though, this is also
219      * unreliable. I'm open to suggestion on a better way to emulate inode.  */
220     char *path_key;
221     int   ctime;
222     int   mtime;        /* controls check for stale directory cache */
223     int   fs_flags;     /* FS_FAT, FS_NTFS, ... */
224 # define FS_FAT      0x1
225 # define FS_NTFS     0x2
226 # define FS_UNKNOWN  0x4
227 #else
228 # ifdef VMS
229     ino_t ino[3];
230 # else
231     ino_t ino;
232 # endif
233 #endif /* WINDOWS32 */
234     struct hash_table dirfiles; /* Files in this directory.  */
235     DIR *dirstream;             /* Stream reading this directory.  */
236   };
237
238 static unsigned long
239 directory_contents_hash_1 (const void *key_0)
240 {
241   const struct directory_contents *key = key_0;
242   unsigned long hash;
243
244 #ifdef WINDOWS32
245   hash = 0;
246   ISTRING_HASH_1 (key->path_key, hash);
247   hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime;
248 #else
249 # ifdef VMS
250   hash = (((unsigned int) key->dev << 4)
251           ^ ((unsigned int) key->ino[0]
252              + (unsigned int) key->ino[1]
253              + (unsigned int) key->ino[2]));
254 # else
255   hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino;
256 # endif
257 #endif /* WINDOWS32 */
258   return hash;
259 }
260
261 static unsigned long
262 directory_contents_hash_2 (const void *key_0)
263 {
264   const struct directory_contents *key = key_0;
265   unsigned long hash;
266
267 #ifdef WINDOWS32
268   hash = 0;
269   ISTRING_HASH_2 (key->path_key, hash);
270   hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime;
271 #else
272 # ifdef VMS
273   hash = (((unsigned int) key->dev << 4)
274           ^ ~((unsigned int) key->ino[0]
275               + (unsigned int) key->ino[1]
276               + (unsigned int) key->ino[2]));
277 # else
278   hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino;
279 # endif
280 #endif /* WINDOWS32 */
281
282   return hash;
283 }
284
285 /* Sometimes it's OK to use subtraction to get this value:
286      result = X - Y;
287    But, if we're not sure of the type of X and Y they may be too large for an
288    int (on a 64-bit system for example).  So, use ?: instead.
289    See Savannah bug #15534.
290
291    NOTE!  This macro has side-effects!
292 */
293
294 #define MAKECMP(_x,_y)  ((_x)<(_y)?-1:((_x)==(_y)?0:1))
295
296 static int
297 directory_contents_hash_cmp (const void *xv, const void *yv)
298 {
299   const struct directory_contents *x = xv;
300   const struct directory_contents *y = yv;
301   int result;
302
303 #ifdef WINDOWS32
304   ISTRING_COMPARE (x->path_key, y->path_key, result);
305   if (result)
306     return result;
307   result = MAKECMP(x->ctime, y->ctime);
308   if (result)
309     return result;
310 #else
311 # ifdef VMS
312   result = MAKECMP(x->ino[0], y->ino[0]);
313   if (result)
314     return result;
315   result = MAKECMP(x->ino[1], y->ino[1]);
316   if (result)
317     return result;
318   result = MAKECMP(x->ino[2], y->ino[2]);
319   if (result)
320     return result;
321 # else
322   result = MAKECMP(x->ino, y->ino);
323   if (result)
324     return result;
325 # endif
326 #endif /* WINDOWS32 */
327
328   return MAKECMP(x->dev, y->dev);
329 }
330
331 /* Table of directory contents hashed by device and inode number.  */
332 static struct hash_table directory_contents;
333
334 struct directory
335   {
336     const char *name;                   /* Name of the directory.  */
337
338     /* The directory's contents.  This data may be shared by several
339        entries in the hash table, which refer to the same directory
340        (identified uniquely by 'dev' and 'ino') under different names.  */
341     struct directory_contents *contents;
342   };
343
344 static unsigned long
345 directory_hash_1 (const void *key)
346 {
347   return_ISTRING_HASH_1 (((const struct directory *) key)->name);
348 }
349
350 static unsigned long
351 directory_hash_2 (const void *key)
352 {
353   return_ISTRING_HASH_2 (((const struct directory *) key)->name);
354 }
355
356 static int
357 directory_hash_cmp (const void *x, const void *y)
358 {
359   return_ISTRING_COMPARE (((const struct directory *) x)->name,
360                           ((const struct directory *) y)->name);
361 }
362
363 /* Table of directories hashed by name.  */
364 static struct hash_table directories;
365
366 /* Never have more than this many directories open at once.  */
367
368 #define MAX_OPEN_DIRECTORIES 10
369
370 static unsigned int open_directories = 0;
371
372
373 /* Hash table of files in each directory.  */
374
375 struct dirfile
376   {
377     const char *name;           /* Name of the file.  */
378     short length;
379     short impossible;           /* This file is impossible.  */
380   };
381
382 static unsigned long
383 dirfile_hash_1 (const void *key)
384 {
385   return_ISTRING_HASH_1 (((struct dirfile const *) key)->name);
386 }
387
388 static unsigned long
389 dirfile_hash_2 (const void *key)
390 {
391   return_ISTRING_HASH_2 (((struct dirfile const *) key)->name);
392 }
393
394 static int
395 dirfile_hash_cmp (const void *xv, const void *yv)
396 {
397   const struct dirfile *x = xv;
398   const struct dirfile *y = yv;
399   int result = x->length - y->length;
400   if (result)
401     return result;
402   return_ISTRING_COMPARE (x->name, y->name);
403 }
404
405 #ifndef DIRFILE_BUCKETS
406 #define DIRFILE_BUCKETS 107
407 #endif
408 \f
409 static int dir_contents_file_exists_p (struct directory_contents *dir,
410                                        const char *filename);
411 static struct directory *find_directory (const char *name);
412
413 /* Find the directory named NAME and return its 'struct directory'.  */
414
415 static struct directory *
416 find_directory (const char *name)
417 {
418   struct directory *dir;
419   struct directory **dir_slot;
420   struct directory dir_key;
421
422 #ifdef VMS
423   if ((*name == '.') && (*(name+1) == 0))
424     name = "[]";
425   else
426     name = vmsify (name,1);
427 #endif
428
429   dir_key.name = name;
430   dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key);
431   dir = *dir_slot;
432
433   if (HASH_VACANT (dir))
434     {
435       /* The directory was not found.  Create a new entry for it.  */
436       const char *p = name + strlen (name);
437       struct stat st;
438       int r;
439
440       dir = xmalloc (sizeof (struct directory));
441 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
442       dir->name = strcache_add_len (downcase (name), p - name);
443 #else
444       dir->name = strcache_add_len (name, p - name);
445 #endif
446       hash_insert_at (&directories, dir, dir_slot);
447       /* The directory is not in the name hash table.
448          Find its device and inode numbers, and look it up by them.  */
449
450 #ifdef VMS
451       r = vmsstat_dir (name, &st);
452 #elif defined(WINDOWS32)
453       {
454         char tem[MAXPATHLEN], *tstart, *tend;
455
456         /* Remove any trailing slashes.  Windows32 stat fails even on
457            valid directories if they end in a slash. */
458         memcpy (tem, name, p - name + 1);
459         tstart = tem;
460         if (tstart[1] == ':')
461           tstart += 2;
462         for (tend = tem + (p - name - 1);
463              tend > tstart && (*tend == '/' || *tend == '\\');
464              tend--)
465           *tend = '\0';
466
467         r = stat (tem, &st);
468       }
469 #else
470       EINTRLOOP (r, stat (name, &st));
471 #endif
472
473       if (r < 0)
474         {
475         /* Couldn't stat the directory.  Mark this by
476            setting the 'contents' member to a nil pointer.  */
477           dir->contents = 0;
478         }
479       else
480         {
481           /* Search the contents hash table; device and inode are the key.  */
482
483 #ifdef WINDOWS32
484           char *w32_path;
485 #endif
486           struct directory_contents *dc;
487           struct directory_contents **dc_slot;
488           struct directory_contents dc_key;
489
490           dc_key.dev = st.st_dev;
491 #ifdef WINDOWS32
492           dc_key.path_key = w32_path = w32ify (name, 1);
493           dc_key.ctime = st.st_ctime;
494 #else
495 # ifdef VMS
496           dc_key.ino[0] = st.st_ino[0];
497           dc_key.ino[1] = st.st_ino[1];
498           dc_key.ino[2] = st.st_ino[2];
499 # else
500           dc_key.ino = st.st_ino;
501 # endif
502 #endif
503           dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
504           dc = *dc_slot;
505
506           if (HASH_VACANT (dc))
507             {
508               /* Nope; this really is a directory we haven't seen before.  */
509 #ifdef WINDOWS32
510               char  fs_label[BUFSIZ];
511               char  fs_type[BUFSIZ];
512               unsigned long  fs_serno;
513               unsigned long  fs_flags;
514               unsigned long  fs_len;
515 #endif
516               dc = (struct directory_contents *)
517                 xmalloc (sizeof (struct directory_contents));
518
519               /* Enter it in the contents hash table.  */
520               dc->dev = st.st_dev;
521 #ifdef WINDOWS32
522               dc->path_key = xstrdup (w32_path);
523               dc->ctime = st.st_ctime;
524               dc->mtime = st.st_mtime;
525
526               /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
527                  directory when files are added/deleted from a directory.  */
528               w32_path[3] = '\0';
529               if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label),
530                                         &fs_serno, &fs_len, &fs_flags, fs_type,
531                                         sizeof (fs_type)) == FALSE)
532                 dc->fs_flags = FS_UNKNOWN;
533               else if (!strcmp (fs_type, "FAT"))
534                 dc->fs_flags = FS_FAT;
535               else if (!strcmp (fs_type, "NTFS"))
536                 dc->fs_flags = FS_NTFS;
537               else
538                 dc->fs_flags = FS_UNKNOWN;
539 #else
540 # ifdef VMS
541               dc->ino[0] = st.st_ino[0];
542               dc->ino[1] = st.st_ino[1];
543               dc->ino[2] = st.st_ino[2];
544 # else
545               dc->ino = st.st_ino;
546 # endif
547 #endif /* WINDOWS32 */
548               hash_insert_at (&directory_contents, dc, dc_slot);
549               ENULLLOOP (dc->dirstream, opendir (name));
550               if (dc->dirstream == 0)
551                 /* Couldn't open the directory.  Mark this by setting the
552                    'files' member to a nil pointer.  */
553                 dc->dirfiles.ht_vec = 0;
554               else
555                 {
556                   hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
557                              dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
558                   /* Keep track of how many directories are open.  */
559                   ++open_directories;
560                   if (open_directories == MAX_OPEN_DIRECTORIES)
561                     /* We have too many directories open already.
562                        Read the entire directory and then close it.  */
563                     dir_contents_file_exists_p (dc, 0);
564                 }
565             }
566
567           /* Point the name-hashed entry for DIR at its contents data.  */
568           dir->contents = dc;
569         }
570     }
571
572   return dir;
573 }
574 \f
575 /* Return 1 if the name FILENAME is entered in DIR's hash table.
576    FILENAME must contain no slashes.  */
577
578 static int
579 dir_contents_file_exists_p (struct directory_contents *dir,
580                             const char *filename)
581 {
582   struct dirfile *df;
583   struct dirent *d;
584 #ifdef WINDOWS32
585   struct stat st;
586   int rehash = 0;
587 #endif
588
589   if (dir == 0 || dir->dirfiles.ht_vec == 0)
590     /* The directory could not be stat'd or opened.  */
591     return 0;
592
593 #ifdef __MSDOS__
594   filename = dosify (filename);
595 #endif
596
597 #ifdef HAVE_CASE_INSENSITIVE_FS
598   filename = downcase (filename);
599 #endif
600
601 #ifdef __EMX__
602   if (filename != 0)
603     _fnlwr (filename); /* lower case for FAT drives */
604 #endif
605
606 #ifdef VMS
607   filename = vmsify (filename,0);
608 #endif
609
610   if (filename != 0)
611     {
612       struct dirfile dirfile_key;
613
614       if (*filename == '\0')
615         {
616           /* Checking if the directory exists.  */
617           return 1;
618         }
619       dirfile_key.name = filename;
620       dirfile_key.length = strlen (filename);
621       df = hash_find_item (&dir->dirfiles, &dirfile_key);
622       if (df)
623         return !df->impossible;
624     }
625
626   /* The file was not found in the hashed list.
627      Try to read the directory further.  */
628
629   if (dir->dirstream == 0)
630     {
631 #ifdef WINDOWS32
632       /*
633        * Check to see if directory has changed since last read. FAT
634        * filesystems force a rehash always as mtime does not change
635        * on directories (ugh!).
636        */
637       if (dir->path_key)
638         {
639           if ((dir->fs_flags & FS_FAT) != 0)
640             {
641               dir->mtime = time ((time_t *) 0);
642               rehash = 1;
643             }
644           else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime)
645             {
646               /* reset date stamp to show most recent re-process.  */
647               dir->mtime = st.st_mtime;
648               rehash = 1;
649             }
650
651           /* If it has been already read in, all done.  */
652           if (!rehash)
653             return 0;
654
655           /* make sure directory can still be opened; if not return.  */
656           dir->dirstream = opendir (dir->path_key);
657           if (!dir->dirstream)
658             return 0;
659         }
660       else
661 #endif
662         /* The directory has been all read in.  */
663         return 0;
664     }
665
666   while (1)
667     {
668       /* Enter the file in the hash table.  */
669       unsigned int len;
670       struct dirfile dirfile_key;
671       struct dirfile **dirfile_slot;
672
673       ENULLLOOP (d, readdir (dir->dirstream));
674       if (d == 0)
675         {
676           if (errno)
677             fatal (NILF, "INTERNAL: readdir: %s\n", strerror (errno));
678           break;
679         }
680
681 #if defined(VMS) && defined(HAVE_DIRENT_H)
682       /* In VMS we get file versions too, which have to be stripped off */
683       {
684         char *p = strrchr (d->d_name, ';');
685         if (p)
686           *p = '\0';
687       }
688 #endif
689       if (!REAL_DIR_ENTRY (d))
690         continue;
691
692       len = NAMLEN (d);
693       dirfile_key.name = d->d_name;
694       dirfile_key.length = len;
695       dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key);
696 #ifdef WINDOWS32
697       /*
698        * If re-reading a directory, don't cache files that have
699        * already been discovered.
700        */
701       if (! rehash || HASH_VACANT (*dirfile_slot))
702 #endif
703         {
704           df = xmalloc (sizeof (struct dirfile));
705 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
706           df->name = strcache_add_len (downcase (d->d_name), len);
707 #else
708           df->name = strcache_add_len (d->d_name, len);
709 #endif
710           df->length = len;
711           df->impossible = 0;
712           hash_insert_at (&dir->dirfiles, df, dirfile_slot);
713         }
714       /* Check if the name matches the one we're searching for.  */
715       if (filename != 0 && patheq (d->d_name, filename))
716         return 1;
717     }
718
719   /* If the directory has been completely read in,
720      close the stream and reset the pointer to nil.  */
721   if (d == 0)
722     {
723       --open_directories;
724       closedir (dir->dirstream);
725       dir->dirstream = 0;
726     }
727   return 0;
728 }
729
730 /* Return 1 if the name FILENAME in directory DIRNAME
731    is entered in the dir hash table.
732    FILENAME must contain no slashes.  */
733
734 int
735 dir_file_exists_p (const char *dirname, const char *filename)
736 {
737   return dir_contents_file_exists_p (find_directory (dirname)->contents,
738                                      filename);
739 }
740 \f
741 /* Return 1 if the file named NAME exists.  */
742
743 int
744 file_exists_p (const char *name)
745 {
746   const char *dirend;
747   const char *dirname;
748   const char *slash;
749
750 #ifndef NO_ARCHIVES
751   if (ar_name (name))
752     return ar_member_date (name) != (time_t) -1;
753 #endif
754
755 #ifdef VMS
756   dirend = strrchr (name, ']');
757   if (dirend == 0)
758     dirend = strrchr (name, ':');
759   if (dirend == 0)
760     return dir_file_exists_p ("[]", name);
761 #else /* !VMS */
762   dirend = strrchr (name, '/');
763 #ifdef HAVE_DOS_PATHS
764   /* Forward and backslashes might be mixed.  We need the rightmost one.  */
765   {
766     const char *bslash = strrchr (name, '\\');
767     if (!dirend || bslash > dirend)
768       dirend = bslash;
769     /* The case of "d:file".  */
770     if (!dirend && name[0] && name[1] == ':')
771       dirend = name + 1;
772   }
773 #endif /* HAVE_DOS_PATHS */
774   if (dirend == 0)
775 #ifndef _AMIGA
776     return dir_file_exists_p (".", name);
777 #else /* !VMS && !AMIGA */
778     return dir_file_exists_p ("", name);
779 #endif /* AMIGA */
780 #endif /* VMS */
781
782   slash = dirend;
783   if (dirend == name)
784     dirname = "/";
785   else
786     {
787       char *p;
788 #ifdef HAVE_DOS_PATHS
789   /* d:/ and d: are *very* different...  */
790       if (dirend < name + 3 && name[1] == ':' &&
791           (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
792         dirend++;
793 #endif
794       p = alloca (dirend - name + 1);
795       memcpy (p, name, dirend - name);
796       p[dirend - name] = '\0';
797       dirname = p;
798     }
799   return dir_file_exists_p (dirname, slash + 1);
800 }
801 \f
802 /* Mark FILENAME as 'impossible' for 'file_impossible_p'.
803    This means an attempt has been made to search for FILENAME
804    as an intermediate file, and it has failed.  */
805
806 void
807 file_impossible (const char *filename)
808 {
809   const char *dirend;
810   const char *p = filename;
811   struct directory *dir;
812   struct dirfile *new;
813
814 #ifdef VMS
815   dirend = strrchr (p, ']');
816   if (dirend == 0)
817     dirend = strrchr (p, ':');
818   dirend++;
819   if (dirend == (char *)1)
820     dir = find_directory ("[]");
821 #else
822   dirend = strrchr (p, '/');
823 # ifdef HAVE_DOS_PATHS
824   /* Forward and backslashes might be mixed.  We need the rightmost one.  */
825   {
826     const char *bslash = strrchr (p, '\\');
827     if (!dirend || bslash > dirend)
828       dirend = bslash;
829     /* The case of "d:file".  */
830     if (!dirend && p[0] && p[1] == ':')
831       dirend = p + 1;
832   }
833 # endif /* HAVE_DOS_PATHS */
834   if (dirend == 0)
835 # ifdef _AMIGA
836     dir = find_directory ("");
837 # else /* !VMS && !AMIGA */
838     dir = find_directory (".");
839 # endif /* AMIGA */
840 #endif /* VMS */
841   else
842     {
843       const char *dirname;
844       const char *slash = dirend;
845       if (dirend == p)
846         dirname = "/";
847       else
848         {
849           char *cp;
850 #ifdef HAVE_DOS_PATHS
851           /* d:/ and d: are *very* different...  */
852           if (dirend < p + 3 && p[1] == ':' &&
853               (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
854             dirend++;
855 #endif
856           cp = alloca (dirend - p + 1);
857           memcpy (cp, p, dirend - p);
858           cp[dirend - p] = '\0';
859           dirname = cp;
860         }
861       dir = find_directory (dirname);
862       filename = p = slash + 1;
863     }
864
865   if (dir->contents == 0)
866     /* The directory could not be stat'd.  We allocate a contents
867        structure for it, but leave it out of the contents hash table.  */
868     dir->contents = xcalloc (sizeof (struct directory_contents));
869
870   if (dir->contents->dirfiles.ht_vec == 0)
871     {
872       hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
873                  dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
874     }
875
876   /* Make a new entry and put it in the table.  */
877
878   new = xmalloc (sizeof (struct dirfile));
879   new->length = strlen (filename);
880 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
881   new->name = strcache_add_len (downcase (filename), new->length);
882 #else
883   new->name = strcache_add_len (filename, new->length);
884 #endif
885   new->impossible = 1;
886   hash_insert (&dir->contents->dirfiles, new);
887 }
888 \f
889 /* Return nonzero if FILENAME has been marked impossible.  */
890
891 int
892 file_impossible_p (const char *filename)
893 {
894   const char *dirend;
895   struct directory_contents *dir;
896   struct dirfile *dirfile;
897   struct dirfile dirfile_key;
898
899 #ifdef VMS
900   dirend = strrchr (filename, ']');
901   if (dirend == 0)
902     dir = find_directory ("[]")->contents;
903 #else
904   dirend = strrchr (filename, '/');
905 #ifdef HAVE_DOS_PATHS
906   /* Forward and backslashes might be mixed.  We need the rightmost one.  */
907   {
908     const char *bslash = strrchr (filename, '\\');
909     if (!dirend || bslash > dirend)
910       dirend = bslash;
911     /* The case of "d:file".  */
912     if (!dirend && filename[0] && filename[1] == ':')
913       dirend = filename + 1;
914   }
915 #endif /* HAVE_DOS_PATHS */
916   if (dirend == 0)
917 #ifdef _AMIGA
918     dir = find_directory ("")->contents;
919 #else /* !VMS && !AMIGA */
920     dir = find_directory (".")->contents;
921 #endif /* AMIGA */
922 #endif /* VMS */
923   else
924     {
925       const char *dirname;
926       const char *slash = dirend;
927       if (dirend == filename)
928         dirname = "/";
929       else
930         {
931           char *cp;
932 #ifdef HAVE_DOS_PATHS
933           /* d:/ and d: are *very* different...  */
934           if (dirend < filename + 3 && filename[1] == ':' &&
935               (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
936             dirend++;
937 #endif
938           cp = alloca (dirend - filename + 1);
939           memcpy (cp, filename, dirend - filename);
940           cp[dirend - filename] = '\0';
941           dirname = cp;
942         }
943       dir = find_directory (dirname)->contents;
944       filename = slash + 1;
945     }
946
947   if (dir == 0 || dir->dirfiles.ht_vec == 0)
948     /* There are no files entered for this directory.  */
949     return 0;
950
951 #ifdef __MSDOS__
952   filename = dosify (filename);
953 #endif
954 #ifdef HAVE_CASE_INSENSITIVE_FS
955   filename = downcase (filename);
956 #endif
957 #ifdef VMS
958   filename = vmsify (filename, 1);
959 #endif
960
961   dirfile_key.name = filename;
962   dirfile_key.length = strlen (filename);
963   dirfile = hash_find_item (&dir->dirfiles, &dirfile_key);
964   if (dirfile)
965     return dirfile->impossible;
966
967   return 0;
968 }
969 \f
970 /* Return the already allocated name in the
971    directory hash table that matches DIR.  */
972
973 const char *
974 dir_name (const char *dir)
975 {
976   return find_directory (dir)->name;
977 }
978 \f
979 /* Print the data base of directories.  */
980
981 void
982 print_dir_data_base (void)
983 {
984   unsigned int files;
985   unsigned int impossible;
986   struct directory **dir_slot;
987   struct directory **dir_end;
988
989   puts (_("\n# Directories\n"));
990
991   files = impossible = 0;
992
993   dir_slot = (struct directory **) directories.ht_vec;
994   dir_end = dir_slot + directories.ht_size;
995   for ( ; dir_slot < dir_end; dir_slot++)
996     {
997       struct directory *dir = *dir_slot;
998       if (! HASH_VACANT (dir))
999         {
1000           if (dir->contents == 0)
1001             printf (_("# %s: could not be stat'd.\n"), dir->name);
1002           else if (dir->contents->dirfiles.ht_vec == 0)
1003             {
1004 #ifdef WINDOWS32
1005               printf (_("# %s (key %s, mtime %d): could not be opened.\n"),
1006                       dir->name, dir->contents->path_key,dir->contents->mtime);
1007 #else  /* WINDOWS32 */
1008 #ifdef VMS
1009               printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
1010                       dir->name, dir->contents->dev,
1011                       dir->contents->ino[0], dir->contents->ino[1],
1012                       dir->contents->ino[2]);
1013 #else
1014               printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
1015                       dir->name, (long int) dir->contents->dev,
1016                       (long int) dir->contents->ino);
1017 #endif
1018 #endif /* WINDOWS32 */
1019             }
1020           else
1021             {
1022               unsigned int f = 0;
1023               unsigned int im = 0;
1024               struct dirfile **files_slot;
1025               struct dirfile **files_end;
1026
1027               files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
1028               files_end = files_slot + dir->contents->dirfiles.ht_size;
1029               for ( ; files_slot < files_end; files_slot++)
1030                 {
1031                   struct dirfile *df = *files_slot;
1032                   if (! HASH_VACANT (df))
1033                     {
1034                       if (df->impossible)
1035                         ++im;
1036                       else
1037                         ++f;
1038                     }
1039                 }
1040 #ifdef WINDOWS32
1041               printf (_("# %s (key %s, mtime %d): "),
1042                       dir->name, dir->contents->path_key, dir->contents->mtime);
1043 #else  /* WINDOWS32 */
1044 #ifdef VMS
1045               printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1046                       dir->name, dir->contents->dev,
1047                       dir->contents->ino[0], dir->contents->ino[1],
1048                       dir->contents->ino[2]);
1049 #else
1050               printf (_("# %s (device %ld, inode %ld): "),
1051                       dir->name,
1052                       (long)dir->contents->dev, (long)dir->contents->ino);
1053 #endif
1054 #endif /* WINDOWS32 */
1055               if (f == 0)
1056                 fputs (_("No"), stdout);
1057               else
1058                 printf ("%u", f);
1059               fputs (_(" files, "), stdout);
1060               if (im == 0)
1061                 fputs (_("no"), stdout);
1062               else
1063                 printf ("%u", im);
1064               fputs (_(" impossibilities"), stdout);
1065               if (dir->contents->dirstream == 0)
1066                 puts (".");
1067               else
1068                 puts (_(" so far."));
1069               files += f;
1070               impossible += im;
1071             }
1072         }
1073     }
1074
1075   fputs ("\n# ", stdout);
1076   if (files == 0)
1077     fputs (_("No"), stdout);
1078   else
1079     printf ("%u", files);
1080   fputs (_(" files, "), stdout);
1081   if (impossible == 0)
1082     fputs (_("no"), stdout);
1083   else
1084     printf ("%u", impossible);
1085   printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1086 }
1087 \f
1088 /* Hooks for globbing.  */
1089
1090 #include <glob.h>
1091
1092 /* Structure describing state of iterating through a directory hash table.  */
1093
1094 struct dirstream
1095   {
1096     struct directory_contents *contents; /* The directory being read.  */
1097     struct dirfile **dirfile_slot; /* Current slot in table.  */
1098   };
1099
1100 /* Forward declarations.  */
1101 static __ptr_t open_dirstream (const char *);
1102 static struct dirent *read_dirstream (__ptr_t);
1103
1104 static __ptr_t
1105 open_dirstream (const char *directory)
1106 {
1107   struct dirstream *new;
1108   struct directory *dir = find_directory (directory);
1109
1110   if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1111     /* DIR->contents is nil if the directory could not be stat'd.
1112        DIR->contents->dirfiles is nil if it could not be opened.  */
1113     return 0;
1114
1115   /* Read all the contents of the directory now.  There is no benefit
1116      in being lazy, since glob will want to see every file anyway.  */
1117
1118   dir_contents_file_exists_p (dir->contents, 0);
1119
1120   new = xmalloc (sizeof (struct dirstream));
1121   new->contents = dir->contents;
1122   new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1123
1124   return (__ptr_t) new;
1125 }
1126
1127 static struct dirent *
1128 read_dirstream (__ptr_t stream)
1129 {
1130   static char *buf;
1131   static unsigned int bufsz;
1132
1133   struct dirstream *const ds = (struct dirstream *) stream;
1134   struct directory_contents *dc = ds->contents;
1135   struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1136
1137   while (ds->dirfile_slot < dirfile_end)
1138     {
1139       struct dirfile *df = *ds->dirfile_slot++;
1140       if (! HASH_VACANT (df) && !df->impossible)
1141         {
1142           /* The glob interface wants a 'struct dirent', so mock one up.  */
1143           struct dirent *d;
1144           unsigned int len = df->length + 1;
1145           unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len;
1146           if (sz > bufsz)
1147             {
1148               bufsz *= 2;
1149               if (sz > bufsz)
1150                 bufsz = sz;
1151               buf = xrealloc (buf, bufsz);
1152             }
1153           d = (struct dirent *) buf;
1154 #ifdef __MINGW32__
1155 # if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \
1156                                      __MINGW32_MINOR_VERSION == 0)
1157           d->d_name = xmalloc (len);
1158 # endif
1159 #endif
1160           FAKE_DIR_ENTRY (d);
1161 #ifdef _DIRENT_HAVE_D_NAMLEN
1162           d->d_namlen = len - 1;
1163 #endif
1164 #ifdef _DIRENT_HAVE_D_TYPE
1165           d->d_type = DT_UNKNOWN;
1166 #endif
1167           memcpy (d->d_name, df->name, len);
1168           return d;
1169         }
1170     }
1171
1172   return 0;
1173 }
1174
1175 static void
1176 ansi_free (void *p)
1177 {
1178   if (p)
1179     free (p);
1180 }
1181
1182 /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1183  * macro for stat64().  If stat is a macro, make a local wrapper function to
1184  * invoke it.
1185  *
1186  * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a
1187  * regular file; fix that here.
1188  */
1189 #if !defined(stat) && !defined(WINDOWS32)
1190 # ifndef VMS
1191 int stat (const char *path, struct stat *sbuf);
1192 # endif
1193 # define local_stat stat
1194 #else
1195 static int
1196 local_stat (const char *path, struct stat *buf)
1197 {
1198   int e;
1199 #ifdef WINDOWS32
1200   size_t plen = strlen (path);
1201
1202   /* Make sure the parent of "." exists and is a directory, not a
1203      file.  This is because 'stat' on Windows normalizes the argument
1204      foo/. => foo without checking first that foo is a directory.  */
1205   if (plen > 1 && path[plen - 1] == '.'
1206       && (path[plen - 2] == '/' || path[plen - 2] == '\\'))
1207     {
1208       char parent[MAXPATHLEN];
1209
1210       strncpy (parent, path, plen - 2);
1211       parent[plen - 2] = '\0';
1212       if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
1213         return -1;
1214     }
1215 #endif
1216
1217   EINTRLOOP (e, stat (path, buf));
1218   return e;
1219 }
1220 #endif
1221
1222 void
1223 dir_setup_glob (glob_t *gl)
1224 {
1225   gl->gl_opendir = open_dirstream;
1226   gl->gl_readdir = read_dirstream;
1227   gl->gl_closedir = ansi_free;
1228   gl->gl_stat = local_stat;
1229   /* We don't bother setting gl_lstat, since glob never calls it.
1230      The slot is only there for compatibility with 4.4 BSD.  */
1231 }
1232
1233 void
1234 hash_init_directories (void)
1235 {
1236   hash_init (&directories, DIRECTORY_BUCKETS,
1237              directory_hash_1, directory_hash_2, directory_hash_cmp);
1238   hash_init (&directory_contents, DIRECTORY_BUCKETS,
1239              directory_contents_hash_1, directory_contents_hash_2,
1240              directory_contents_hash_cmp);
1241 }