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