1 /* Directory hashing for GNU Make.
2 Copyright (C) 1988-2013 Free Software Foundation, Inc.
3 This file is part of GNU Make.
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
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.
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/>. */
24 # define NAMLEN(dirent) strlen((dirent)->d_name)
26 /* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */
27 const char *vmsify (const char *name, int type);
30 # define dirent direct
31 # define NAMLEN(dirent) (dirent)->d_namlen
32 # ifdef HAVE_SYS_NDIR_H
33 # include <sys/ndir.h>
35 # ifdef HAVE_SYS_DIR_H
43 # endif /* HAVE_VMSDIR_H */
46 /* In GNU systems, <dirent.h> defines this macro for us. */
49 # define NAMLEN(d) _D_NAMLEN(d)
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)
58 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
59 # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1)
66 /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */
72 dosify (const char *filename)
74 static char dos_filename[14];
78 if (filename == 0 || _USE_LFN)
81 /* FIXME: what about filenames which violate
82 8+3 constraints, like "config.h.in", or ".emacs"? */
83 if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0)
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++);
92 /* Now skip to the next dot. */
93 while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
95 if (*filename != '\0')
98 for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
99 *df++ = tolower ((unsigned char)*filename++);
102 /* Look for more dots. */
103 while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
105 if (*filename == '.')
110 #endif /* __MSDOS__ */
113 #include "pathstuff.h"
120 #ifdef HAVE_CASE_INSENSITIVE_FS
122 downcase (const char *filename)
124 static PATH_VAR (new_filename);
131 while (*filename != '\0')
133 *df++ = tolower ((unsigned char)*filename);
141 #endif /* HAVE_CASE_INSENSITIVE_FS */
146 vms_hash (const char *name)
152 unsigned char uc = *name;
154 #ifdef HAVE_CASE_INSENSITIVE_FS
155 h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
170 /* fake stat entry for a directory */
172 vmsstat_dir (const char *name, struct stat *st)
178 dir = opendir (name);
182 s = strchr (name, ':'); /* find device */
185 /* to keep the compiler happy we said "const char *name", now we cheat */
187 st->st_dev = (char *)vms_hash (name);
197 st->st_ino[0] = h & 0xff;
198 st->st_ino[1] = h & 0xff00;
199 st->st_ino[2] = h >> 16;
205 /* Hash table of directories. */
207 #ifndef DIRECTORY_BUCKETS
208 #define DIRECTORY_BUCKETS 199
211 struct directory_contents
213 dev_t dev; /* Device and inode numbers of this dir. */
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. */
222 int mtime; /* controls check for stale directory cache */
223 int fs_flags; /* FS_FAT, FS_NTFS, ... */
226 # define FS_UNKNOWN 0x4
233 #endif /* WINDOWS32 */
234 struct hash_table dirfiles; /* Files in this directory. */
235 DIR *dirstream; /* Stream reading this directory. */
239 directory_contents_hash_1 (const void *key_0)
241 const struct directory_contents *key = key_0;
246 ISTRING_HASH_1 (key->path_key, hash);
247 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime;
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]));
255 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino;
257 #endif /* WINDOWS32 */
262 directory_contents_hash_2 (const void *key_0)
264 const struct directory_contents *key = key_0;
269 ISTRING_HASH_2 (key->path_key, hash);
270 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime;
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]));
278 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino;
280 #endif /* WINDOWS32 */
285 /* Sometimes it's OK to use subtraction to get this value:
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.
291 NOTE! This macro has side-effects!
294 #define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1))
297 directory_contents_hash_cmp (const void *xv, const void *yv)
299 const struct directory_contents *x = xv;
300 const struct directory_contents *y = yv;
304 ISTRING_COMPARE (x->path_key, y->path_key, result);
307 result = MAKECMP(x->ctime, y->ctime);
312 result = MAKECMP(x->ino[0], y->ino[0]);
315 result = MAKECMP(x->ino[1], y->ino[1]);
318 result = MAKECMP(x->ino[2], y->ino[2]);
322 result = MAKECMP(x->ino, y->ino);
326 #endif /* WINDOWS32 */
328 return MAKECMP(x->dev, y->dev);
331 /* Table of directory contents hashed by device and inode number. */
332 static struct hash_table directory_contents;
336 const char *name; /* Name of the directory. */
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;
345 directory_hash_1 (const void *key)
347 return_ISTRING_HASH_1 (((const struct directory *) key)->name);
351 directory_hash_2 (const void *key)
353 return_ISTRING_HASH_2 (((const struct directory *) key)->name);
357 directory_hash_cmp (const void *x, const void *y)
359 return_ISTRING_COMPARE (((const struct directory *) x)->name,
360 ((const struct directory *) y)->name);
363 /* Table of directories hashed by name. */
364 static struct hash_table directories;
366 /* Never have more than this many directories open at once. */
368 #define MAX_OPEN_DIRECTORIES 10
370 static unsigned int open_directories = 0;
373 /* Hash table of files in each directory. */
377 const char *name; /* Name of the file. */
379 short impossible; /* This file is impossible. */
383 dirfile_hash_1 (const void *key)
385 return_ISTRING_HASH_1 (((struct dirfile const *) key)->name);
389 dirfile_hash_2 (const void *key)
391 return_ISTRING_HASH_2 (((struct dirfile const *) key)->name);
395 dirfile_hash_cmp (const void *xv, const void *yv)
397 const struct dirfile *x = xv;
398 const struct dirfile *y = yv;
399 int result = x->length - y->length;
402 return_ISTRING_COMPARE (x->name, y->name);
405 #ifndef DIRFILE_BUCKETS
406 #define DIRFILE_BUCKETS 107
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);
413 /* Find the directory named NAME and return its 'struct directory'. */
415 static struct directory *
416 find_directory (const char *name)
418 struct directory *dir;
419 struct directory **dir_slot;
420 struct directory dir_key;
423 if ((*name == '.') && (*(name+1) == 0))
426 name = vmsify (name,1);
430 dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key);
433 if (HASH_VACANT (dir))
435 /* The directory was not found. Create a new entry for it. */
436 const char *p = name + strlen (name);
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);
444 dir->name = strcache_add_len (name, p - name);
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. */
451 r = vmsstat_dir (name, &st);
452 #elif defined(WINDOWS32)
454 char tem[MAXPATHLEN], *tstart, *tend;
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);
460 if (tstart[1] == ':')
462 for (tend = tem + (p - name - 1);
463 tend > tstart && (*tend == '/' || *tend == '\\');
470 EINTRLOOP (r, stat (name, &st));
475 /* Couldn't stat the directory. Mark this by
476 setting the 'contents' member to a nil pointer. */
481 /* Search the contents hash table; device and inode are the key. */
486 struct directory_contents *dc;
487 struct directory_contents **dc_slot;
488 struct directory_contents dc_key;
490 dc_key.dev = st.st_dev;
492 dc_key.path_key = w32_path = w32ify (name, 1);
493 dc_key.ctime = st.st_ctime;
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];
500 dc_key.ino = st.st_ino;
503 dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
506 if (HASH_VACANT (dc))
508 /* Nope; this really is a directory we haven't seen before. */
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;
516 dc = (struct directory_contents *)
517 xmalloc (sizeof (struct directory_contents));
519 /* Enter it in the contents hash table. */
522 dc->path_key = xstrdup (w32_path);
523 dc->ctime = st.st_ctime;
524 dc->mtime = st.st_mtime;
526 /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
527 directory when files are added/deleted from a directory. */
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;
538 dc->fs_flags = FS_UNKNOWN;
541 dc->ino[0] = st.st_ino[0];
542 dc->ino[1] = st.st_ino[1];
543 dc->ino[2] = st.st_ino[2];
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;
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. */
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);
567 /* Point the name-hashed entry for DIR at its contents data. */
575 /* Return 1 if the name FILENAME is entered in DIR's hash table.
576 FILENAME must contain no slashes. */
579 dir_contents_file_exists_p (struct directory_contents *dir,
580 const char *filename)
589 if (dir == 0 || dir->dirfiles.ht_vec == 0)
590 /* The directory could not be stat'd or opened. */
594 filename = dosify (filename);
597 #ifdef HAVE_CASE_INSENSITIVE_FS
598 filename = downcase (filename);
603 _fnlwr (filename); /* lower case for FAT drives */
607 filename = vmsify (filename,0);
612 struct dirfile dirfile_key;
614 if (*filename == '\0')
616 /* Checking if the directory exists. */
619 dirfile_key.name = filename;
620 dirfile_key.length = strlen (filename);
621 df = hash_find_item (&dir->dirfiles, &dirfile_key);
623 return !df->impossible;
626 /* The file was not found in the hashed list.
627 Try to read the directory further. */
629 if (dir->dirstream == 0)
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!).
639 if ((dir->fs_flags & FS_FAT) != 0)
641 dir->mtime = time ((time_t *) 0);
644 else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime)
646 /* reset date stamp to show most recent re-process. */
647 dir->mtime = st.st_mtime;
651 /* If it has been already read in, all done. */
655 /* make sure directory can still be opened; if not return. */
656 dir->dirstream = opendir (dir->path_key);
662 /* The directory has been all read in. */
668 /* Enter the file in the hash table. */
670 struct dirfile dirfile_key;
671 struct dirfile **dirfile_slot;
673 ENULLLOOP (d, readdir (dir->dirstream));
677 fatal (NILF, "INTERNAL: readdir: %s\n", strerror (errno));
681 #if defined(VMS) && defined(HAVE_DIRENT_H)
682 /* In VMS we get file versions too, which have to be stripped off */
684 char *p = strrchr (d->d_name, ';');
689 if (!REAL_DIR_ENTRY (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);
698 * If re-reading a directory, don't cache files that have
699 * already been discovered.
701 if (! rehash || HASH_VACANT (*dirfile_slot))
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);
708 df->name = strcache_add_len (d->d_name, len);
712 hash_insert_at (&dir->dirfiles, df, dirfile_slot);
714 /* Check if the name matches the one we're searching for. */
715 if (filename != 0 && patheq (d->d_name, filename))
719 /* If the directory has been completely read in,
720 close the stream and reset the pointer to nil. */
724 closedir (dir->dirstream);
730 /* Return 1 if the name FILENAME in directory DIRNAME
731 is entered in the dir hash table.
732 FILENAME must contain no slashes. */
735 dir_file_exists_p (const char *dirname, const char *filename)
737 return dir_contents_file_exists_p (find_directory (dirname)->contents,
741 /* Return 1 if the file named NAME exists. */
744 file_exists_p (const char *name)
752 return ar_member_date (name) != (time_t) -1;
756 dirend = strrchr (name, ']');
758 dirend = strrchr (name, ':');
760 return dir_file_exists_p ("[]", name);
762 dirend = strrchr (name, '/');
763 #ifdef HAVE_DOS_PATHS
764 /* Forward and backslashes might be mixed. We need the rightmost one. */
766 const char *bslash = strrchr (name, '\\');
767 if (!dirend || bslash > dirend)
769 /* The case of "d:file". */
770 if (!dirend && name[0] && name[1] == ':')
773 #endif /* HAVE_DOS_PATHS */
776 return dir_file_exists_p (".", name);
777 #else /* !VMS && !AMIGA */
778 return dir_file_exists_p ("", name);
788 #ifdef HAVE_DOS_PATHS
789 /* d:/ and d: are *very* different... */
790 if (dirend < name + 3 && name[1] == ':' &&
791 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
794 p = alloca (dirend - name + 1);
795 memcpy (p, name, dirend - name);
796 p[dirend - name] = '\0';
799 return dir_file_exists_p (dirname, slash + 1);
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. */
807 file_impossible (const char *filename)
810 const char *p = filename;
811 struct directory *dir;
815 dirend = strrchr (p, ']');
817 dirend = strrchr (p, ':');
819 if (dirend == (char *)1)
820 dir = find_directory ("[]");
822 dirend = strrchr (p, '/');
823 # ifdef HAVE_DOS_PATHS
824 /* Forward and backslashes might be mixed. We need the rightmost one. */
826 const char *bslash = strrchr (p, '\\');
827 if (!dirend || bslash > dirend)
829 /* The case of "d:file". */
830 if (!dirend && p[0] && p[1] == ':')
833 # endif /* HAVE_DOS_PATHS */
836 dir = find_directory ("");
837 # else /* !VMS && !AMIGA */
838 dir = find_directory (".");
844 const char *slash = dirend;
850 #ifdef HAVE_DOS_PATHS
851 /* d:/ and d: are *very* different... */
852 if (dirend < p + 3 && p[1] == ':' &&
853 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
856 cp = alloca (dirend - p + 1);
857 memcpy (cp, p, dirend - p);
858 cp[dirend - p] = '\0';
861 dir = find_directory (dirname);
862 filename = p = slash + 1;
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));
870 if (dir->contents->dirfiles.ht_vec == 0)
872 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
873 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
876 /* Make a new entry and put it in the table. */
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);
883 new->name = strcache_add_len (filename, new->length);
886 hash_insert (&dir->contents->dirfiles, new);
889 /* Return nonzero if FILENAME has been marked impossible. */
892 file_impossible_p (const char *filename)
895 struct directory_contents *dir;
896 struct dirfile *dirfile;
897 struct dirfile dirfile_key;
900 dirend = strrchr (filename, ']');
902 dir = find_directory ("[]")->contents;
904 dirend = strrchr (filename, '/');
905 #ifdef HAVE_DOS_PATHS
906 /* Forward and backslashes might be mixed. We need the rightmost one. */
908 const char *bslash = strrchr (filename, '\\');
909 if (!dirend || bslash > dirend)
911 /* The case of "d:file". */
912 if (!dirend && filename[0] && filename[1] == ':')
913 dirend = filename + 1;
915 #endif /* HAVE_DOS_PATHS */
918 dir = find_directory ("")->contents;
919 #else /* !VMS && !AMIGA */
920 dir = find_directory (".")->contents;
926 const char *slash = dirend;
927 if (dirend == filename)
932 #ifdef HAVE_DOS_PATHS
933 /* d:/ and d: are *very* different... */
934 if (dirend < filename + 3 && filename[1] == ':' &&
935 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
938 cp = alloca (dirend - filename + 1);
939 memcpy (cp, filename, dirend - filename);
940 cp[dirend - filename] = '\0';
943 dir = find_directory (dirname)->contents;
944 filename = slash + 1;
947 if (dir == 0 || dir->dirfiles.ht_vec == 0)
948 /* There are no files entered for this directory. */
952 filename = dosify (filename);
954 #ifdef HAVE_CASE_INSENSITIVE_FS
955 filename = downcase (filename);
958 filename = vmsify (filename, 1);
961 dirfile_key.name = filename;
962 dirfile_key.length = strlen (filename);
963 dirfile = hash_find_item (&dir->dirfiles, &dirfile_key);
965 return dirfile->impossible;
970 /* Return the already allocated name in the
971 directory hash table that matches DIR. */
974 dir_name (const char *dir)
976 return find_directory (dir)->name;
979 /* Print the data base of directories. */
982 print_dir_data_base (void)
985 unsigned int impossible;
986 struct directory **dir_slot;
987 struct directory **dir_end;
989 puts (_("\n# Directories\n"));
991 files = impossible = 0;
993 dir_slot = (struct directory **) directories.ht_vec;
994 dir_end = dir_slot + directories.ht_size;
995 for ( ; dir_slot < dir_end; dir_slot++)
997 struct directory *dir = *dir_slot;
998 if (! HASH_VACANT (dir))
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)
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 */
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]);
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);
1018 #endif /* WINDOWS32 */
1023 unsigned int im = 0;
1024 struct dirfile **files_slot;
1025 struct dirfile **files_end;
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++)
1031 struct dirfile *df = *files_slot;
1032 if (! HASH_VACANT (df))
1041 printf (_("# %s (key %s, mtime %d): "),
1042 dir->name, dir->contents->path_key, dir->contents->mtime);
1043 #else /* WINDOWS32 */
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]);
1050 printf (_("# %s (device %ld, inode %ld): "),
1052 (long)dir->contents->dev, (long)dir->contents->ino);
1054 #endif /* WINDOWS32 */
1056 fputs (_("No"), stdout);
1059 fputs (_(" files, "), stdout);
1061 fputs (_("no"), stdout);
1064 fputs (_(" impossibilities"), stdout);
1065 if (dir->contents->dirstream == 0)
1068 puts (_(" so far."));
1075 fputs ("\n# ", stdout);
1077 fputs (_("No"), stdout);
1079 printf ("%u", files);
1080 fputs (_(" files, "), stdout);
1081 if (impossible == 0)
1082 fputs (_("no"), stdout);
1084 printf ("%u", impossible);
1085 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1088 /* Hooks for globbing. */
1092 /* Structure describing state of iterating through a directory hash table. */
1096 struct directory_contents *contents; /* The directory being read. */
1097 struct dirfile **dirfile_slot; /* Current slot in table. */
1100 /* Forward declarations. */
1101 static __ptr_t open_dirstream (const char *);
1102 static struct dirent *read_dirstream (__ptr_t);
1105 open_dirstream (const char *directory)
1107 struct dirstream *new;
1108 struct directory *dir = find_directory (directory);
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. */
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. */
1118 dir_contents_file_exists_p (dir->contents, 0);
1120 new = xmalloc (sizeof (struct dirstream));
1121 new->contents = dir->contents;
1122 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1124 return (__ptr_t) new;
1127 static struct dirent *
1128 read_dirstream (__ptr_t stream)
1131 static unsigned int bufsz;
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;
1137 while (ds->dirfile_slot < dirfile_end)
1139 struct dirfile *df = *ds->dirfile_slot++;
1140 if (! HASH_VACANT (df) && !df->impossible)
1142 /* The glob interface wants a 'struct dirent', so mock one up. */
1144 unsigned int len = df->length + 1;
1145 unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len;
1151 buf = xrealloc (buf, bufsz);
1153 d = (struct dirent *) buf;
1155 # if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \
1156 __MINGW32_MINOR_VERSION == 0)
1157 d->d_name = xmalloc (len);
1161 #ifdef _DIRENT_HAVE_D_NAMLEN
1162 d->d_namlen = len - 1;
1164 #ifdef _DIRENT_HAVE_D_TYPE
1165 d->d_type = DT_UNKNOWN;
1167 memcpy (d->d_name, df->name, len);
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
1186 * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a
1187 * regular file; fix that here.
1189 #if !defined(stat) && !defined(WINDOWS32)
1191 int stat (const char *path, struct stat *sbuf);
1193 # define local_stat stat
1196 local_stat (const char *path, struct stat *buf)
1200 size_t plen = strlen (path);
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] == '\\'))
1208 char parent[MAXPATHLEN];
1210 strncpy (parent, path, plen - 2);
1211 parent[plen - 2] = '\0';
1212 if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
1217 EINTRLOOP (e, stat (path, buf));
1223 dir_setup_glob (glob_t *gl)
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. */
1234 hash_init_directories (void)
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);