1 /* Directory hashing for GNU Make.
2 Copyright (C) 1988-2020 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 downcase_inplace(char *filename)
150 while (*name != '\0')
152 *name = tolower ((unsigned char)*name);
158 #ifndef _USE_STD_STAT
159 /* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino
160 when _USE_STD_STAT is used on the compile line.
162 Prior to _USE_STD_STAT support, the st_dev is a pointer to thread
163 static memory containing the device of the last filename looked up.
165 Todo: find out if the ino_t still needs to be faked on a directory.
168 /* Define this if the older VMS_INO_T is needed */
172 vms_hash (const char *name)
178 unsigned char uc = *name;
180 #ifdef HAVE_CASE_INSENSITIVE_FS
181 h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
196 /* fake stat entry for a directory */
198 vmsstat_dir (const char *name, struct stat *st)
204 dir = opendir (name);
208 s = strchr (name, ':'); /* find device */
211 /* to keep the compiler happy we said "const char *name", now we cheat */
213 st->st_dev = (char *)vms_hash (name);
223 st->st_ino[0] = h & 0xff;
224 st->st_ino[1] = h & 0xff00;
225 st->st_ino[2] = h >> 16;
230 # define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf)
232 #endif /* _USE_STD_STAT */
235 /* Hash table of directories. */
237 #ifndef DIRECTORY_BUCKETS
238 #define DIRECTORY_BUCKETS 199
241 struct directory_contents
243 dev_t dev; /* Device and inode numbers of this dir. */
245 /* Inode means nothing on WINDOWS32. Even file key information is
246 * unreliable because it is random per file open and undefined for remote
247 * filesystems. The most unique attribute I can come up with is the fully
248 * qualified name of the directory. Beware though, this is also
249 * unreliable. I'm open to suggestion on a better way to emulate inode. */
252 time_t mtime; /* controls check for stale directory cache */
253 int fs_flags; /* FS_FAT, FS_NTFS, ... */
256 # define FS_UNKNOWN 0x4
263 #endif /* WINDOWS32 */
264 struct hash_table dirfiles; /* Files in this directory. */
265 DIR *dirstream; /* Stream reading this directory. */
269 directory_contents_hash_1 (const void *key_0)
271 const struct directory_contents *key = key_0;
276 ISTRING_HASH_1 (key->path_key, hash);
277 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime;
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]));
285 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino;
287 #endif /* WINDOWS32 */
292 directory_contents_hash_2 (const void *key_0)
294 const struct directory_contents *key = key_0;
299 ISTRING_HASH_2 (key->path_key, hash);
300 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime;
303 hash = (((unsigned int) key->dev << 4)
304 ^ ~((unsigned int) key->ino[0]
305 + (unsigned int) key->ino[1]
306 + (unsigned int) key->ino[2]));
308 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino;
310 #endif /* WINDOWS32 */
315 /* Sometimes it's OK to use subtraction to get this value:
317 But, if we're not sure of the type of X and Y they may be too large for an
318 int (on a 64-bit system for example). So, use ?: instead.
319 See Savannah bug #15534.
321 NOTE! This macro has side-effects!
324 #define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1))
327 directory_contents_hash_cmp (const void *xv, const void *yv)
329 const struct directory_contents *x = xv;
330 const struct directory_contents *y = yv;
334 ISTRING_COMPARE (x->path_key, y->path_key, result);
337 result = MAKECMP(x->ctime, y->ctime);
342 result = MAKECMP(x->ino[0], y->ino[0]);
345 result = MAKECMP(x->ino[1], y->ino[1]);
348 result = MAKECMP(x->ino[2], y->ino[2]);
352 result = MAKECMP(x->ino, y->ino);
356 #endif /* WINDOWS32 */
358 return MAKECMP(x->dev, y->dev);
361 /* Table of directory contents hashed by device and inode number. */
362 static struct hash_table directory_contents;
366 const char *name; /* Name of the directory. */
368 /* The directory's contents. This data may be shared by several
369 entries in the hash table, which refer to the same directory
370 (identified uniquely by 'dev' and 'ino') under different names. */
371 struct directory_contents *contents;
375 directory_hash_1 (const void *key)
377 return_ISTRING_HASH_1 (((const struct directory *) key)->name);
381 directory_hash_2 (const void *key)
383 return_ISTRING_HASH_2 (((const struct directory *) key)->name);
387 directory_hash_cmp (const void *x, const void *y)
389 return_ISTRING_COMPARE (((const struct directory *) x)->name,
390 ((const struct directory *) y)->name);
393 /* Table of directories hashed by name. */
394 static struct hash_table directories;
396 /* Never have more than this many directories open at once. */
398 #define MAX_OPEN_DIRECTORIES 10
400 static unsigned int open_directories = 0;
403 /* Hash table of files in each directory. */
407 const char *name; /* Name of the file. */
409 short impossible; /* This file is impossible. */
414 dirfile_hash_1 (const void *key)
416 return_ISTRING_HASH_1 (((struct dirfile const *) key)->name);
420 dirfile_hash_2 (const void *key)
422 return_ISTRING_HASH_2 (((struct dirfile const *) key)->name);
426 dirfile_hash_cmp (const void *xv, const void *yv)
428 const struct dirfile *x = xv;
429 const struct dirfile *y = yv;
430 int result = (int) (x->length - y->length);
433 return_ISTRING_COMPARE (x->name, y->name);
436 #ifndef DIRFILE_BUCKETS
437 #define DIRFILE_BUCKETS 107
440 static int dir_contents_file_exists_p (struct directory_contents *dir,
441 const char *filename);
442 static struct directory *find_directory (const char *name);
444 /* Find the directory named NAME and return its 'struct directory'. */
446 static struct directory *
447 find_directory (const char *name)
449 struct directory *dir;
450 struct directory **dir_slot;
451 struct directory dir_key;
454 dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key);
457 if (HASH_VACANT (dir))
459 /* The directory was not found. Create a new entry for it. */
460 const char *p = name + strlen (name);
464 dir = xmalloc (sizeof (struct directory));
465 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
466 /* Todo: Why is this only needed on VMS? */
468 char *lname = downcase_inplace (xstrdup (name));
469 dir->name = strcache_add_len (lname, p - name);
473 dir->name = strcache_add_len (name, p - name);
475 hash_insert_at (&directories, dir, dir_slot);
476 /* The directory is not in the name hash table.
477 Find its device and inode numbers, and look it up by them. */
479 #if defined(WINDOWS32)
481 char tem[MAXPATHLEN], *tstart, *tend;
483 /* Remove any trailing slashes. Windows32 stat fails even on
484 valid directories if they end in a slash. */
485 memcpy (tem, name, p - name + 1);
487 if (tstart[1] == ':')
489 for (tend = tem + (p - name - 1);
490 tend > tstart && (*tend == '/' || *tend == '\\');
497 EINTRLOOP (r, stat (name, &st));
502 /* Couldn't stat the directory. Mark this by
503 setting the 'contents' member to a nil pointer. */
508 /* Search the contents hash table; device and inode are the key. */
513 struct directory_contents *dc;
514 struct directory_contents **dc_slot;
515 struct directory_contents dc_key;
517 dc_key.dev = st.st_dev;
519 dc_key.path_key = w32_path = w32ify (name, 1);
520 dc_key.ctime = st.st_ctime;
523 dc_key.ino[0] = st.st_ino[0];
524 dc_key.ino[1] = st.st_ino[1];
525 dc_key.ino[2] = st.st_ino[2];
527 dc_key.ino = st.st_ino;
530 dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
533 if (HASH_VACANT (dc))
535 /* Nope; this really is a directory we haven't seen before. */
537 char fs_label[BUFSIZ];
538 char fs_type[BUFSIZ];
539 unsigned long fs_serno;
540 unsigned long fs_flags;
541 unsigned long fs_len;
543 dc = (struct directory_contents *)
544 xmalloc (sizeof (struct directory_contents));
546 /* Enter it in the contents hash table. */
549 dc->path_key = xstrdup (w32_path);
550 dc->ctime = st.st_ctime;
551 dc->mtime = st.st_mtime;
553 /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
554 directory when files are added/deleted from a directory. */
556 if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label),
557 &fs_serno, &fs_len, &fs_flags, fs_type,
558 sizeof (fs_type)) == FALSE)
559 dc->fs_flags = FS_UNKNOWN;
560 else if (!strcmp (fs_type, "FAT"))
561 dc->fs_flags = FS_FAT;
562 else if (!strcmp (fs_type, "NTFS"))
563 dc->fs_flags = FS_NTFS;
565 dc->fs_flags = FS_UNKNOWN;
568 dc->ino[0] = st.st_ino[0];
569 dc->ino[1] = st.st_ino[1];
570 dc->ino[2] = st.st_ino[2];
574 #endif /* WINDOWS32 */
575 hash_insert_at (&directory_contents, dc, dc_slot);
576 ENULLLOOP (dc->dirstream, opendir (name));
577 if (dc->dirstream == 0)
578 /* Couldn't open the directory. Mark this by setting the
579 'files' member to a nil pointer. */
580 dc->dirfiles.ht_vec = 0;
583 hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
584 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
585 /* Keep track of how many directories are open. */
587 if (open_directories == MAX_OPEN_DIRECTORIES)
588 /* We have too many directories open already.
589 Read the entire directory and then close it. */
590 dir_contents_file_exists_p (dc, 0);
594 /* Point the name-hashed entry for DIR at its contents data. */
602 /* Return 1 if the name FILENAME is entered in DIR's hash table.
603 FILENAME must contain no slashes. */
606 dir_contents_file_exists_p (struct directory_contents *dir,
607 const char *filename)
616 if (dir == 0 || dir->dirfiles.ht_vec == 0)
617 /* The directory could not be stat'd or opened. */
621 filename = dosify (filename);
624 #ifdef HAVE_CASE_INSENSITIVE_FS
625 filename = downcase (filename);
630 _fnlwr (filename); /* lower case for FAT drives */
634 struct dirfile dirfile_key;
636 if (*filename == '\0')
638 /* Checking if the directory exists. */
641 dirfile_key.name = filename;
642 dirfile_key.length = strlen (filename);
643 df = hash_find_item (&dir->dirfiles, &dirfile_key);
645 return !df->impossible;
648 /* The file was not found in the hashed list.
649 Try to read the directory further. */
651 if (dir->dirstream == 0)
655 * Check to see if directory has changed since last read. FAT
656 * filesystems force a rehash always as mtime does not change
657 * on directories (ugh!).
661 if ((dir->fs_flags & FS_FAT) != 0)
663 dir->mtime = time ((time_t *) 0);
666 else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime)
668 /* reset date stamp to show most recent re-process. */
669 dir->mtime = st.st_mtime;
673 /* If it has been already read in, all done. */
677 /* make sure directory can still be opened; if not return. */
678 dir->dirstream = opendir (dir->path_key);
684 /* The directory has been all read in. */
690 /* Enter the file in the hash table. */
692 struct dirfile dirfile_key;
693 struct dirfile **dirfile_slot;
695 ENULLLOOP (d, readdir (dir->dirstream));
699 pfatal_with_name ("INTERNAL: readdir");
703 #if defined(VMS) && defined(HAVE_DIRENT_H)
704 /* In VMS we get file versions too, which have to be stripped off.
705 Some versions of VMS return versions on Unix files even when
706 the feature option to strip them is set. */
708 char *p = strrchr (d->d_name, ';');
713 if (!REAL_DIR_ENTRY (d))
717 dirfile_key.name = d->d_name;
718 dirfile_key.length = len;
719 dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key);
722 * If re-reading a directory, don't cache files that have
723 * already been discovered.
725 if (! rehash || HASH_VACANT (*dirfile_slot))
728 df = xmalloc (sizeof (struct dirfile));
729 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
730 /* TODO: Why is this only needed on VMS? */
731 df->name = strcache_add_len (downcase_inplace (d->d_name), len);
733 df->name = strcache_add_len (d->d_name, len);
735 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
736 df->type = d->d_type;
740 hash_insert_at (&dir->dirfiles, df, dirfile_slot);
742 /* Check if the name matches the one we're searching for. */
743 if (filename != 0 && patheq (d->d_name, filename))
747 /* If the directory has been completely read in,
748 close the stream and reset the pointer to nil. */
752 closedir (dir->dirstream);
758 /* Return 1 if the name FILENAME in directory DIRNAME
759 is entered in the dir hash table.
760 FILENAME must contain no slashes. */
763 dir_file_exists_p (const char *dirname, const char *filename)
766 if ((filename != NULL) && (dirname != NULL))
769 want_vmsify = (strpbrk (dirname, ":<[") != NULL);
771 filename = vmsify (filename, 0);
774 return dir_contents_file_exists_p (find_directory (dirname)->contents,
778 /* Return 1 if the file named NAME exists. */
781 file_exists_p (const char *name)
789 return ar_member_date (name) != (time_t) -1;
792 dirend = strrchr (name, '/');
796 dirend = strrchr (name, ']');
797 dirend == NULL ? dirend : dirend++;
801 dirend = strrchr (name, '>');
802 dirend == NULL ? dirend : dirend++;
806 dirend = strrchr (name, ':');
807 dirend == NULL ? dirend : dirend++;
810 #ifdef HAVE_DOS_PATHS
811 /* Forward and backslashes might be mixed. We need the rightmost one. */
813 const char *bslash = strrchr (name, '\\');
814 if (!dirend || bslash > dirend)
816 /* The case of "d:file". */
817 if (!dirend && name[0] && name[1] == ':')
820 #endif /* HAVE_DOS_PATHS */
823 return dir_file_exists_p (".", name);
825 return dir_file_exists_p ("", name);
834 #ifdef HAVE_DOS_PATHS
835 /* d:/ and d: are *very* different... */
836 if (dirend < name + 3 && name[1] == ':' &&
837 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
840 p = alloca (dirend - name + 1);
841 memcpy (p, name, dirend - name);
842 p[dirend - name] = '\0';
851 return dir_file_exists_p (dirname, slash);
854 /* Mark FILENAME as 'impossible' for 'file_impossible_p'.
855 This means an attempt has been made to search for FILENAME
856 as an intermediate file, and it has failed. */
859 file_impossible (const char *filename)
862 const char *p = filename;
863 struct directory *dir;
866 dirend = strrchr (p, '/');
870 dirend = strrchr (p, ']');
871 dirend == NULL ? dirend : dirend++;
875 dirend = strrchr (p, '>');
876 dirend == NULL ? dirend : dirend++;
880 dirend = strrchr (p, ':');
881 dirend == NULL ? dirend : dirend++;
884 #ifdef HAVE_DOS_PATHS
885 /* Forward and backslashes might be mixed. We need the rightmost one. */
887 const char *bslash = strrchr (p, '\\');
888 if (!dirend || bslash > dirend)
890 /* The case of "d:file". */
891 if (!dirend && p[0] && p[1] == ':')
894 #endif /* HAVE_DOS_PATHS */
897 dir = find_directory ("");
899 dir = find_directory (".");
904 const char *slash = dirend;
910 #ifdef HAVE_DOS_PATHS
911 /* d:/ and d: are *very* different... */
912 if (dirend < p + 3 && p[1] == ':' &&
913 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
916 cp = alloca (dirend - p + 1);
917 memcpy (cp, p, dirend - p);
918 cp[dirend - p] = '\0';
921 dir = find_directory (dirname);
924 filename = p = slash + 1;
926 filename = p = slash;
928 filename = p = slash + 1;
932 if (dir->contents == 0)
933 /* The directory could not be stat'd. We allocate a contents
934 structure for it, but leave it out of the contents hash table. */
935 dir->contents = xcalloc (sizeof (struct directory_contents));
937 if (dir->contents->dirfiles.ht_vec == 0)
939 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
940 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
943 /* Make a new entry and put it in the table. */
945 new = xmalloc (sizeof (struct dirfile));
946 new->length = strlen (filename);
947 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
948 /* todo: Why is this only needed on VMS? */
949 new->name = strcache_add_len (downcase (filename), new->length);
951 new->name = strcache_add_len (filename, new->length);
954 hash_insert (&dir->contents->dirfiles, new);
957 /* Return nonzero if FILENAME has been marked impossible. */
960 file_impossible_p (const char *filename)
963 struct directory_contents *dir;
964 struct dirfile *dirfile;
965 struct dirfile dirfile_key;
970 dirend = strrchr (filename, '/');
974 want_vmsify = (strpbrk (filename, "]>:^") != NULL);
975 dirend = strrchr (filename, ']');
977 if (dirend == NULL && want_vmsify)
978 dirend = strrchr (filename, '>');
979 if (dirend == NULL && want_vmsify)
980 dirend = strrchr (filename, ':');
982 #ifdef HAVE_DOS_PATHS
983 /* Forward and backslashes might be mixed. We need the rightmost one. */
985 const char *bslash = strrchr (filename, '\\');
986 if (!dirend || bslash > dirend)
988 /* The case of "d:file". */
989 if (!dirend && filename[0] && filename[1] == ':')
990 dirend = filename + 1;
992 #endif /* HAVE_DOS_PATHS */
995 dir = find_directory ("")->contents;
997 dir = find_directory (".")->contents;
1001 const char *dirname;
1002 const char *slash = dirend;
1003 if (dirend == filename)
1008 #ifdef HAVE_DOS_PATHS
1009 /* d:/ and d: are *very* different... */
1010 if (dirend < filename + 3 && filename[1] == ':' &&
1011 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
1014 cp = alloca (dirend - filename + 1);
1015 memcpy (cp, filename, dirend - filename);
1016 cp[dirend - filename] = '\0';
1019 dir = find_directory (dirname)->contents;
1022 filename = slash + 1;
1026 filename = slash + 1;
1030 if (dir == 0 || dir->dirfiles.ht_vec == 0)
1031 /* There are no files entered for this directory. */
1035 filename = dosify (filename);
1037 #ifdef HAVE_CASE_INSENSITIVE_FS
1038 filename = downcase (filename);
1042 filename = vmsify (filename, 1);
1045 dirfile_key.name = filename;
1046 dirfile_key.length = strlen (filename);
1047 dirfile = hash_find_item (&dir->dirfiles, &dirfile_key);
1049 return dirfile->impossible;
1054 /* Return the already allocated name in the
1055 directory hash table that matches DIR. */
1058 dir_name (const char *dir)
1060 return find_directory (dir)->name;
1063 /* Print the data base of directories. */
1066 print_dir_data_base (void)
1069 unsigned int impossible;
1070 struct directory **dir_slot;
1071 struct directory **dir_end;
1073 puts (_("\n# Directories\n"));
1075 files = impossible = 0;
1077 dir_slot = (struct directory **) directories.ht_vec;
1078 dir_end = dir_slot + directories.ht_size;
1079 for ( ; dir_slot < dir_end; dir_slot++)
1081 struct directory *dir = *dir_slot;
1082 if (! HASH_VACANT (dir))
1084 if (dir->contents == 0)
1085 printf (_("# %s: could not be stat'd.\n"), dir->name);
1086 else if (dir->contents->dirfiles.ht_vec == 0)
1089 printf (_("# %s (key %s, mtime %I64u): could not be opened.\n"),
1090 dir->name, dir->contents->path_key,
1091 (unsigned long long)dir->contents->mtime);
1092 #else /* WINDOWS32 */
1094 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
1095 dir->name, dir->contents->dev,
1096 dir->contents->ino[0], dir->contents->ino[1],
1097 dir->contents->ino[2]);
1099 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
1100 dir->name, (long int) dir->contents->dev,
1101 (long int) dir->contents->ino);
1103 #endif /* WINDOWS32 */
1108 unsigned int im = 0;
1109 struct dirfile **files_slot;
1110 struct dirfile **files_end;
1112 files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
1113 files_end = files_slot + dir->contents->dirfiles.ht_size;
1114 for ( ; files_slot < files_end; files_slot++)
1116 struct dirfile *df = *files_slot;
1117 if (! HASH_VACANT (df))
1126 printf (_("# %s (key %s, mtime %I64u): "),
1127 dir->name, dir->contents->path_key,
1128 (unsigned long long)dir->contents->mtime);
1129 #else /* WINDOWS32 */
1131 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1132 dir->name, dir->contents->dev,
1133 dir->contents->ino[0], dir->contents->ino[1],
1134 dir->contents->ino[2]);
1136 printf (_("# %s (device %ld, inode %ld): "),
1138 (long)dir->contents->dev, (long)dir->contents->ino);
1140 #endif /* WINDOWS32 */
1142 fputs (_("No"), stdout);
1145 fputs (_(" files, "), stdout);
1147 fputs (_("no"), stdout);
1150 fputs (_(" impossibilities"), stdout);
1151 if (dir->contents->dirstream == 0)
1154 puts (_(" so far."));
1161 fputs ("\n# ", stdout);
1163 fputs (_("No"), stdout);
1165 printf ("%u", files);
1166 fputs (_(" files, "), stdout);
1167 if (impossible == 0)
1168 fputs (_("no"), stdout);
1170 printf ("%u", impossible);
1171 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1174 /* Hooks for globbing. */
1176 /* Structure describing state of iterating through a directory hash table. */
1180 struct directory_contents *contents; /* The directory being read. */
1181 struct dirfile **dirfile_slot; /* Current slot in table. */
1184 /* Forward declarations. */
1185 static __ptr_t open_dirstream (const char *);
1186 static struct dirent *read_dirstream (__ptr_t);
1189 open_dirstream (const char *directory)
1191 struct dirstream *new;
1192 struct directory *dir = find_directory (directory);
1194 if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1195 /* DIR->contents is nil if the directory could not be stat'd.
1196 DIR->contents->dirfiles is nil if it could not be opened. */
1199 /* Read all the contents of the directory now. There is no benefit
1200 in being lazy, since glob will want to see every file anyway. */
1202 dir_contents_file_exists_p (dir->contents, 0);
1204 new = xmalloc (sizeof (struct dirstream));
1205 new->contents = dir->contents;
1206 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1208 return (__ptr_t) new;
1211 static struct dirent *
1212 read_dirstream (__ptr_t stream)
1215 static size_t bufsz;
1217 struct dirstream *const ds = (struct dirstream *) stream;
1218 struct directory_contents *dc = ds->contents;
1219 struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1221 while (ds->dirfile_slot < dirfile_end)
1223 struct dirfile *df = *ds->dirfile_slot++;
1224 if (! HASH_VACANT (df) && !df->impossible)
1226 /* The glob interface wants a 'struct dirent', so mock one up. */
1228 size_t len = df->length + 1;
1229 size_t sz = sizeof (*d) - sizeof (d->d_name) + len;
1235 buf = xrealloc (buf, bufsz);
1237 d = (struct dirent *) buf;
1239 # if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \
1240 __MINGW32_MINOR_VERSION == 0)
1241 d->d_name = xmalloc (len);
1245 #ifdef _DIRENT_HAVE_D_NAMLEN
1246 d->d_namlen = len - 1;
1248 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
1249 d->d_type = df->type;
1251 memcpy (d->d_name, df->name, len);
1259 /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1260 * macro for stat64(). If stat is a macro, make a local wrapper function to
1263 * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a
1264 * regular file; fix that here.
1266 #if !defined(stat) && !defined(WINDOWS32) || defined(VMS)
1268 # ifndef HAVE_SYS_STAT_H
1269 int stat (const char *path, struct stat *sbuf);
1272 /* We are done with the fake stat. Go back to the real stat */
1277 # define local_stat stat
1280 local_stat (const char *path, struct stat *buf)
1284 size_t plen = strlen (path);
1286 /* Make sure the parent of "." exists and is a directory, not a
1287 file. This is because 'stat' on Windows normalizes the argument
1288 foo/. => foo without checking first that foo is a directory. */
1289 if (plen > 1 && path[plen - 1] == '.'
1290 && (path[plen - 2] == '/' || path[plen - 2] == '\\'))
1292 char parent[MAXPATHLEN];
1294 strncpy (parent, path, plen - 2);
1295 parent[plen - 2] = '\0';
1296 if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
1301 EINTRLOOP (e, stat (path, buf));
1306 /* Similarly for lstat. */
1307 #if !defined(lstat) && !defined(WINDOWS32) || defined(VMS)
1309 # ifndef HAVE_SYS_STAT_H
1310 int lstat (const char *path, struct stat *sbuf);
1313 /* We are done with the fake lstat. Go back to the real lstat */
1318 # define local_lstat lstat
1319 #elif defined(WINDOWS32)
1320 /* Windows doesn't support lstat(). */
1321 # define local_lstat local_stat
1324 local_lstat (const char *path, struct stat *buf)
1327 EINTRLOOP (e, lstat (path, buf));
1333 dir_setup_glob (glob_t *gl)
1336 gl->gl_opendir = open_dirstream;
1337 gl->gl_readdir = read_dirstream;
1338 gl->gl_closedir = free;
1339 gl->gl_lstat = local_lstat;
1340 gl->gl_stat = local_stat;
1344 hash_init_directories (void)
1346 hash_init (&directories, DIRECTORY_BUCKETS,
1347 directory_hash_1, directory_hash_2, directory_hash_cmp);
1348 hash_init (&directory_contents, DIRECTORY_BUCKETS,
1349 directory_contents_hash_1, directory_contents_hash_2,
1350 directory_contents_hash_cmp);