1 /* Directory hashing for GNU Make.
2 Copyright (C) 1988-2022 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 <https://www.gnu.org/licenses/>. */
25 # define NAMLEN(dirent) strlen((dirent)->d_name)
27 /* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */
28 const char *vmsify (const char *name, int type);
31 # define dirent direct
32 # define NAMLEN(dirent) (dirent)->d_namlen
33 # ifdef HAVE_SYS_NDIR_H
34 # include <sys/ndir.h>
36 # ifdef HAVE_SYS_DIR_H
44 # endif /* HAVE_VMSDIR_H */
47 /* In GNU systems, <dirent.h> defines this macro for us. */
50 # define NAMLEN(d) _D_NAMLEN(d)
53 #if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__)
54 /* Posix does not require that the d_ino field be present, and some
55 systems do not provide it. */
56 # define REAL_DIR_ENTRY(dp) 1
57 # define FAKE_DIR_ENTRY(dp)
59 # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
60 # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1)
67 /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */
73 dosify (const char *filename)
75 static char dos_filename[14];
79 if (filename == 0 || _USE_LFN)
82 /* FIXME: what about filenames which violate
83 8+3 constraints, like "config.h.in", or ".emacs"? */
84 if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0)
89 /* First, transform the name part. */
90 for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
91 *df++ = tolower ((unsigned char)*filename++);
93 /* Now skip to the next dot. */
94 while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
96 if (*filename != '\0')
99 for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
100 *df++ = tolower ((unsigned char)*filename++);
103 /* Look for more dots. */
104 while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
106 if (*filename == '.')
111 #endif /* __MSDOS__ */
114 #include "pathstuff.h"
121 #ifdef HAVE_CASE_INSENSITIVE_FS
123 downcase (const char *filename)
125 static PATH_VAR (new_filename);
132 while (*filename != '\0')
134 *df++ = tolower ((unsigned char)*filename);
142 #endif /* HAVE_CASE_INSENSITIVE_FS */
147 downcase_inplace(char *filename)
151 while (*name != '\0')
153 *name = tolower ((unsigned char)*name);
159 #ifndef _USE_STD_STAT
160 /* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino
161 when _USE_STD_STAT is used on the compile line.
163 Prior to _USE_STD_STAT support, the st_dev is a pointer to thread
164 static memory containing the device of the last filename looked up.
166 Todo: find out if the ino_t still needs to be faked on a directory.
169 /* Define this if the older VMS_INO_T is needed */
173 vms_hash (const char *name)
179 unsigned char uc = (unsigned char) *name;
181 #ifdef HAVE_CASE_INSENSITIVE_FS
182 h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
197 /* fake stat entry for a directory */
199 vmsstat_dir (const char *name, struct stat *st)
205 dir = opendir (name);
209 s = strchr (name, ':'); /* find device */
212 /* to keep the compiler happy we said "const char *name", now we cheat */
214 st->st_dev = (char *)vms_hash (name);
224 st->st_ino[0] = h & 0xff;
225 st->st_ino[1] = h & 0xff00;
226 st->st_ino[2] = h >> 16;
231 # define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf)
233 #endif /* _USE_STD_STAT */
236 /* Never have more than this many directories open at once. */
238 #define MAX_OPEN_DIRECTORIES 10
240 static unsigned int open_directories = 0;
242 /* Hash table of directories. */
244 #ifndef DIRECTORY_BUCKETS
245 #define DIRECTORY_BUCKETS 199
248 struct directory_contents
250 dev_t dev; /* Device and inode numbers of this dir. */
252 /* Inode means nothing on WINDOWS32. Even file key information is
253 * unreliable because it is random per file open and undefined for remote
254 * filesystems. The most unique attribute I can come up with is the fully
255 * qualified name of the directory. Beware though, this is also
256 * unreliable. I'm open to suggestion on a better way to emulate inode. */
259 time_t mtime; /* controls check for stale directory cache */
260 int fs_flags; /* FS_FAT, FS_NTFS, ... */
263 # define FS_UNKNOWN 0x4
270 #endif /* WINDOWS32 */
271 struct hash_table dirfiles; /* Files in this directory. */
272 unsigned long counter; /* command_count value when last read. */
273 DIR *dirstream; /* Stream reading this directory. */
276 static struct directory_contents *
277 clear_directory_contents (struct directory_contents *dc)
283 closedir (dc->dirstream);
286 hash_free (&dc->dirfiles, 1);
292 directory_contents_hash_1 (const void *key_0)
294 const struct directory_contents *key = key_0;
299 ISTRING_HASH_1 (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 directory_contents_hash_2 (const void *key_0)
317 const struct directory_contents *key = key_0;
322 ISTRING_HASH_2 (key->path_key, hash);
323 hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime;
326 hash = (((unsigned int) key->dev << 4)
327 ^ ~((unsigned int) key->ino[0]
328 + (unsigned int) key->ino[1]
329 + (unsigned int) key->ino[2]));
331 hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino;
333 #endif /* WINDOWS32 */
338 /* Sometimes it's OK to use subtraction to get this value:
340 But, if we're not sure of the type of X and Y they may be too large for an
341 int (on a 64-bit system for example). So, use ?: instead.
342 See Savannah bug #15534.
344 NOTE! This macro has side-effects!
347 #define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1))
350 directory_contents_hash_cmp (const void *xv, const void *yv)
352 const struct directory_contents *x = xv;
353 const struct directory_contents *y = yv;
357 ISTRING_COMPARE (x->path_key, y->path_key, result);
360 result = MAKECMP(x->ctime, y->ctime);
365 result = MAKECMP(x->ino[0], y->ino[0]);
368 result = MAKECMP(x->ino[1], y->ino[1]);
371 result = MAKECMP(x->ino[2], y->ino[2]);
375 result = MAKECMP(x->ino, y->ino);
379 #endif /* WINDOWS32 */
381 return MAKECMP(x->dev, y->dev);
384 /* Table of directory contents hashed by device and inode number. */
385 static struct hash_table directory_contents;
389 const char *name; /* Name of the directory. */
390 unsigned long counter; /* command_count value when last read.
391 Used for non-existent directories. */
393 /* The directory's contents. This data may be shared by several
394 entries in the hash table, which refer to the same directory
395 (identified uniquely by 'dev' and 'ino') under different names. */
396 struct directory_contents *contents;
400 directory_hash_1 (const void *key)
402 return_ISTRING_HASH_1 (((const struct directory *) key)->name);
406 directory_hash_2 (const void *key)
408 return_ISTRING_HASH_2 (((const struct directory *) key)->name);
412 directory_hash_cmp (const void *x, const void *y)
414 return_ISTRING_COMPARE (((const struct directory *) x)->name,
415 ((const struct directory *) y)->name);
418 /* Table of directories hashed by name. */
419 static struct hash_table directories;
422 /* Hash table of files in each directory. */
426 const char *name; /* Name of the file. */
428 short impossible; /* This file is impossible. */
433 dirfile_hash_1 (const void *key)
435 return_ISTRING_HASH_1 (((struct dirfile const *) key)->name);
439 dirfile_hash_2 (const void *key)
441 return_ISTRING_HASH_2 (((struct dirfile const *) key)->name);
445 dirfile_hash_cmp (const void *xv, const void *yv)
447 const struct dirfile *x = xv;
448 const struct dirfile *y = yv;
449 int result = (int) (x->length - y->length);
452 return_ISTRING_COMPARE (x->name, y->name);
455 #ifndef DIRFILE_BUCKETS
456 #define DIRFILE_BUCKETS 107
459 static int dir_contents_file_exists_p (struct directory_contents *dir,
460 const char *filename);
461 static struct directory *find_directory (const char *name);
463 /* Find the directory named NAME and return its 'struct directory'. */
465 static struct directory *
466 find_directory (const char *name)
468 struct directory *dir;
469 struct directory **dir_slot;
470 struct directory dir_key;
471 struct directory_contents *dc;
472 struct directory_contents **dc_slot;
473 struct directory_contents dc_key;
482 dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key);
485 if (!HASH_VACANT (dir))
487 unsigned long ctr = dir->contents ? dir->contents->counter : dir->counter;
489 /* No commands have run since we parsed this directory so it's good. */
490 if (ctr == command_count)
493 DB (DB_VERBOSE, ("Directory %s cache invalidated (count %lu != command %lu)\n",
494 name, ctr, command_count));
497 clear_directory_contents (dir->contents);
501 /* The directory was not found. Create a new entry for it. */
502 size_t len = strlen (name);
504 dir = xmalloc (sizeof (struct directory));
505 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
506 /* Todo: Why is this only needed on VMS? */
508 char *lname = downcase_inplace (xstrdup (name));
509 dir->name = strcache_add_len (lname, len);
513 dir->name = strcache_add_len (name, len);
515 hash_insert_at (&directories, dir, dir_slot);
518 dir->contents = NULL;
519 dir->counter = command_count;
521 /* See if the directory exists. */
522 #if defined(WINDOWS32)
524 char tem[MAX_PATH+1], *tstart, *tend;
525 size_t len = strlen (name);
527 /* Remove any trailing slashes. Windows32 stat fails even on
528 valid directories if they end in a slash. */
529 memcpy (tem, name, len + 1);
531 if (tstart[1] == ':')
533 for (tend = tem + (len - 1); tend > tstart && ISDIRSEP (*tend); tend--)
539 EINTRLOOP (r, stat (name, &st));
543 /* Couldn't stat the directory; nothing else to do. */
546 /* Search the contents hash table; device and inode are the key. */
548 memset (&dc_key, '\0', sizeof (dc_key));
549 dc_key.dev = st.st_dev;
551 dc_key.path_key = w32_path = w32ify (name, 1);
552 dc_key.ctime = st.st_ctime;
555 dc_key.ino[0] = st.st_ino[0];
556 dc_key.ino[1] = st.st_ino[1];
557 dc_key.ino[2] = st.st_ino[2];
559 dc_key.ino = st.st_ino;
562 dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
565 if (HASH_VACANT (dc))
567 /* Nope; this really is a directory we haven't seen before. */
569 char fs_label[BUFSIZ];
570 char fs_type[BUFSIZ];
571 unsigned long fs_serno;
572 unsigned long fs_flags;
573 unsigned long fs_len;
575 /* Enter it in the contents hash table. */
576 dc = xcalloc (sizeof (struct directory_contents));
580 dc->path_key = xstrdup (w32_path);
581 dc->mtime = st.st_mtime;
583 /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
584 directory when files are added/deleted from a directory. */
586 if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label),
587 &fs_serno, &fs_len, &fs_flags, fs_type,
588 sizeof (fs_type)) == FALSE)
589 dc->fs_flags = FS_UNKNOWN;
590 else if (!strcmp (fs_type, "FAT"))
591 dc->fs_flags = FS_FAT;
592 else if (!strcmp (fs_type, "NTFS"))
593 dc->fs_flags = FS_NTFS;
595 dc->fs_flags = FS_UNKNOWN;
596 #endif /* WINDOWS32 */
598 hash_insert_at (&directory_contents, dc, dc_slot);
601 /* Point the name-hashed entry for DIR at its contents data. */
604 /* If the contents have changed, we need to reseed. */
605 if (dc->counter != command_count)
608 clear_directory_contents (dc);
610 dc->counter = command_count;
612 ENULLLOOP (dc->dirstream, opendir (name));
613 if (dc->dirstream == 0)
614 /* Couldn't open the directory. Mark this by setting the
615 'files' member to a nil pointer. */
616 dc->dirfiles.ht_vec = 0;
619 hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
620 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
621 /* Keep track of how many directories are open. */
623 if (open_directories == MAX_OPEN_DIRECTORIES)
624 /* We have too many directories open already.
625 Read the entire directory and then close it. */
626 dir_contents_file_exists_p (dc, 0);
633 /* Return 1 if the name FILENAME is entered in DIR's hash table.
634 FILENAME must contain no slashes. */
637 dir_contents_file_exists_p (struct directory_contents *dir,
638 const char *filename)
647 if (dir == 0 || dir->dirfiles.ht_vec == 0)
648 /* The directory could not be stat'd or opened. */
652 filename = dosify (filename);
655 #ifdef HAVE_CASE_INSENSITIVE_FS
656 filename = downcase (filename);
661 _fnlwr (filename); /* lower case for FAT drives */
665 struct dirfile dirfile_key;
667 if (*filename == '\0')
669 /* Checking if the directory exists. */
672 dirfile_key.name = filename;
673 dirfile_key.length = strlen (filename);
674 df = hash_find_item (&dir->dirfiles, &dirfile_key);
676 return !df->impossible;
679 /* The file was not found in the hashed list.
680 Try to read the directory further. */
682 if (dir->dirstream == 0)
686 * Check to see if directory has changed since last read. FAT
687 * filesystems force a rehash always as mtime does not change
688 * on directories (ugh!).
692 if ((dir->fs_flags & FS_FAT) != 0)
694 dir->mtime = time ((time_t *) 0);
697 else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime)
699 /* reset date stamp to show most recent re-process. */
700 dir->mtime = st.st_mtime;
704 /* If it has been already read in, all done. */
708 /* make sure directory can still be opened; if not return. */
709 dir->dirstream = opendir (dir->path_key);
715 /* The directory has been all read in. */
721 /* Enter the file in the hash table. */
723 struct dirfile dirfile_key;
724 struct dirfile **dirfile_slot;
726 ENULLLOOP (d, readdir (dir->dirstream));
730 pfatal_with_name ("INTERNAL: readdir");
734 #if defined(VMS) && defined(HAVE_DIRENT_H)
735 /* In VMS we get file versions too, which have to be stripped off.
736 Some versions of VMS return versions on Unix files even when
737 the feature option to strip them is set. */
739 char *p = strrchr (d->d_name, ';');
744 if (!REAL_DIR_ENTRY (d))
748 dirfile_key.name = d->d_name;
749 dirfile_key.length = len;
750 dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key);
753 * If re-reading a directory, don't cache files that have
754 * already been discovered.
756 if (! rehash || HASH_VACANT (*dirfile_slot))
759 df = xmalloc (sizeof (struct dirfile));
760 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
761 /* TODO: Why is this only needed on VMS? */
762 df->name = strcache_add_len (downcase_inplace (d->d_name), len);
764 df->name = strcache_add_len (d->d_name, len);
766 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
767 df->type = d->d_type;
771 hash_insert_at (&dir->dirfiles, df, dirfile_slot);
773 /* Check if the name matches the one we're searching for. */
774 if (filename != 0 && patheq (d->d_name, filename))
778 /* If the directory has been completely read in,
779 close the stream and reset the pointer to nil. */
783 closedir (dir->dirstream);
789 /* Return 1 if the name FILENAME in directory DIRNAME
790 is entered in the dir hash table.
791 FILENAME must contain no slashes. */
794 dir_file_exists_p (const char *dirname, const char *filename)
797 if ((filename != NULL) && (dirname != NULL))
800 want_vmsify = (strpbrk (dirname, ":<[") != NULL);
802 filename = vmsify (filename, 0);
805 return dir_contents_file_exists_p (find_directory (dirname)->contents,
809 /* Return 1 if the file named NAME exists. */
812 file_exists_p (const char *name)
820 return ar_member_date (name) != (time_t) -1;
823 dirend = strrchr (name, '/');
827 dirend = strrchr (name, ']');
828 dirend == NULL ? dirend : dirend++;
832 dirend = strrchr (name, '>');
833 dirend == NULL ? dirend : dirend++;
837 dirend = strrchr (name, ':');
838 dirend == NULL ? dirend : dirend++;
841 #ifdef HAVE_DOS_PATHS
842 /* Forward and backslashes might be mixed. We need the rightmost one. */
844 const char *bslash = strrchr (name, '\\');
845 if (!dirend || bslash > dirend)
847 /* The case of "d:file". */
848 if (!dirend && name[0] && name[1] == ':')
851 #endif /* HAVE_DOS_PATHS */
854 return dir_file_exists_p (".", name);
856 return dir_file_exists_p ("", name);
865 #ifdef HAVE_DOS_PATHS
866 /* d:/ and d: are *very* different... */
867 if (dirend < name + 3 && name[1] == ':' &&
868 (ISDIRSEP (*dirend) || *dirend == ':'))
871 p = alloca (dirend - name + 1);
872 memcpy (p, name, dirend - name);
873 p[dirend - name] = '\0';
882 return dir_file_exists_p (dirname, slash);
885 /* Mark FILENAME as 'impossible' for 'file_impossible_p'.
886 This means an attempt has been made to search for FILENAME
887 as an intermediate file, and it has failed. */
890 file_impossible (const char *filename)
893 const char *p = filename;
894 struct directory *dir;
897 dirend = strrchr (p, '/');
901 dirend = strrchr (p, ']');
902 dirend == NULL ? dirend : dirend++;
906 dirend = strrchr (p, '>');
907 dirend == NULL ? dirend : dirend++;
911 dirend = strrchr (p, ':');
912 dirend == NULL ? dirend : dirend++;
915 #ifdef HAVE_DOS_PATHS
916 /* Forward and backslashes might be mixed. We need the rightmost one. */
918 const char *bslash = strrchr (p, '\\');
919 if (!dirend || bslash > dirend)
921 /* The case of "d:file". */
922 if (!dirend && p[0] && p[1] == ':')
925 #endif /* HAVE_DOS_PATHS */
928 dir = find_directory ("");
930 dir = find_directory (".");
935 const char *slash = dirend;
941 #ifdef HAVE_DOS_PATHS
942 /* d:/ and d: are *very* different... */
943 if (dirend < p + 3 && p[1] == ':' &&
944 (ISDIRSEP (*dirend) || *dirend == ':'))
947 cp = alloca (dirend - p + 1);
948 memcpy (cp, p, dirend - p);
949 cp[dirend - p] = '\0';
952 dir = find_directory (dirname);
955 filename = p = slash + 1;
957 filename = p = slash;
959 filename = p = slash + 1;
963 if (dir->contents == 0)
964 /* The directory could not be stat'd. We allocate a contents
965 structure for it, but leave it out of the contents hash table. */
966 dir->contents = xcalloc (sizeof (struct directory_contents));
968 if (dir->contents->dirfiles.ht_vec == 0)
970 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
971 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
974 /* Make a new entry and put it in the table. */
976 new = xmalloc (sizeof (struct dirfile));
977 new->length = strlen (filename);
978 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
979 /* todo: Why is this only needed on VMS? */
980 new->name = strcache_add_len (downcase (filename), new->length);
982 new->name = strcache_add_len (filename, new->length);
985 hash_insert (&dir->contents->dirfiles, new);
988 /* Return nonzero if FILENAME has been marked impossible. */
991 file_impossible_p (const char *filename)
994 struct directory_contents *dir;
995 struct dirfile *dirfile;
996 struct dirfile dirfile_key;
1001 dirend = strrchr (filename, '/');
1005 want_vmsify = (strpbrk (filename, "]>:^") != NULL);
1006 dirend = strrchr (filename, ']');
1008 if (dirend == NULL && want_vmsify)
1009 dirend = strrchr (filename, '>');
1010 if (dirend == NULL && want_vmsify)
1011 dirend = strrchr (filename, ':');
1013 #ifdef HAVE_DOS_PATHS
1014 /* Forward and backslashes might be mixed. We need the rightmost one. */
1016 const char *bslash = strrchr (filename, '\\');
1017 if (!dirend || bslash > dirend)
1019 /* The case of "d:file". */
1020 if (!dirend && filename[0] && filename[1] == ':')
1021 dirend = filename + 1;
1023 #endif /* HAVE_DOS_PATHS */
1026 dir = find_directory ("")->contents;
1028 dir = find_directory (".")->contents;
1032 const char *dirname;
1033 const char *slash = dirend;
1034 if (dirend == filename)
1039 #ifdef HAVE_DOS_PATHS
1040 /* d:/ and d: are *very* different... */
1041 if (dirend < filename + 3 && filename[1] == ':' &&
1042 (ISDIRSEP (*dirend) || *dirend == ':'))
1045 cp = alloca (dirend - filename + 1);
1046 memcpy (cp, filename, dirend - filename);
1047 cp[dirend - filename] = '\0';
1050 dir = find_directory (dirname)->contents;
1053 filename = slash + 1;
1057 filename = slash + 1;
1061 if (dir == 0 || dir->dirfiles.ht_vec == 0)
1062 /* There are no files entered for this directory. */
1066 filename = dosify (filename);
1068 #ifdef HAVE_CASE_INSENSITIVE_FS
1069 filename = downcase (filename);
1073 filename = vmsify (filename, 1);
1076 dirfile_key.name = filename;
1077 dirfile_key.length = strlen (filename);
1078 dirfile = hash_find_item (&dir->dirfiles, &dirfile_key);
1080 return dirfile->impossible;
1085 /* Return the already allocated name in the
1086 directory hash table that matches DIR. */
1089 dir_name (const char *dir)
1091 return find_directory (dir)->name;
1094 /* Print the data base of directories. */
1097 print_dir_data_base (void)
1100 unsigned int impossible;
1101 struct directory **dir_slot;
1102 struct directory **dir_end;
1104 char buf[INTSTR_LENGTH + 1];
1107 puts (_("\n# Directories\n"));
1109 files = impossible = 0;
1111 dir_slot = (struct directory **) directories.ht_vec;
1112 dir_end = dir_slot + directories.ht_size;
1113 for ( ; dir_slot < dir_end; dir_slot++)
1115 struct directory *dir = *dir_slot;
1116 if (! HASH_VACANT (dir))
1118 if (dir->contents == 0)
1119 printf (_("# %s: could not be stat'd.\n"), dir->name);
1120 else if (dir->contents->dirfiles.ht_vec == 0)
1122 printf (_("# %s (key %s, mtime %s): could not be opened.\n"),
1123 dir->name, dir->contents->path_key,
1124 make_ulltoa ((unsigned long long)dir->contents->mtime, buf));
1125 #elif defined(VMS_INO_T)
1126 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
1127 dir->name, dir->contents->dev,
1128 dir->contents->ino[0], dir->contents->ino[1],
1129 dir->contents->ino[2]);
1131 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
1132 dir->name, (long) dir->contents->dev, (long) dir->contents->ino);
1137 unsigned int im = 0;
1138 struct dirfile **files_slot;
1139 struct dirfile **files_end;
1141 files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
1142 files_end = files_slot + dir->contents->dirfiles.ht_size;
1143 for ( ; files_slot < files_end; files_slot++)
1145 struct dirfile *df = *files_slot;
1146 if (! HASH_VACANT (df))
1155 printf (_("# %s (key %s, mtime %s): "),
1156 dir->name, dir->contents->path_key,
1157 make_ulltoa ((unsigned long long)dir->contents->mtime, buf));
1158 #elif defined(VMS_INO_T)
1159 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1160 dir->name, dir->contents->dev,
1161 dir->contents->ino[0], dir->contents->ino[1],
1162 dir->contents->ino[2]);
1164 printf (_("# %s (device %ld, inode %ld): "), dir->name,
1165 (long)dir->contents->dev, (long)dir->contents->ino);
1168 fputs (_("No"), stdout);
1171 fputs (_(" files, "), stdout);
1173 fputs (_("no"), stdout);
1176 fputs (_(" impossibilities"), stdout);
1177 if (dir->contents->dirstream == 0)
1180 puts (_(" so far."));
1187 fputs ("\n# ", stdout);
1189 fputs (_("No"), stdout);
1191 printf ("%u", files);
1192 fputs (_(" files, "), stdout);
1193 if (impossible == 0)
1194 fputs (_("no"), stdout);
1196 printf ("%u", impossible);
1197 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1200 /* Hooks for globbing. */
1202 /* Structure describing state of iterating through a directory hash table. */
1206 struct directory_contents *contents; /* The directory being read. */
1207 struct dirfile **dirfile_slot; /* Current slot in table. */
1210 /* Forward declarations. */
1211 static __ptr_t open_dirstream (const char *);
1212 static struct dirent *read_dirstream (__ptr_t);
1215 open_dirstream (const char *directory)
1217 struct dirstream *new;
1218 struct directory *dir = find_directory (directory);
1220 if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1221 /* DIR->contents is nil if the directory could not be stat'd.
1222 DIR->contents->dirfiles is nil if it could not be opened. */
1225 /* Read all the contents of the directory now. There is no benefit
1226 in being lazy, since glob will want to see every file anyway. */
1228 dir_contents_file_exists_p (dir->contents, 0);
1230 new = xmalloc (sizeof (struct dirstream));
1231 new->contents = dir->contents;
1232 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1234 return (__ptr_t) new;
1237 static struct dirent *
1238 read_dirstream (__ptr_t stream)
1241 static size_t bufsz;
1243 struct dirstream *const ds = (struct dirstream *) stream;
1244 struct directory_contents *dc = ds->contents;
1245 struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1247 while (ds->dirfile_slot < dirfile_end)
1249 struct dirfile *df = *ds->dirfile_slot++;
1250 if (! HASH_VACANT (df) && !df->impossible)
1252 /* The glob interface wants a 'struct dirent', so mock one up. */
1254 size_t len = df->length + 1;
1255 size_t sz = sizeof (*d) - sizeof (d->d_name) + len;
1261 buf = xrealloc (buf, bufsz);
1263 d = (struct dirent *) buf;
1265 # if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \
1266 __MINGW32_MINOR_VERSION == 0)
1267 d->d_name = xmalloc (len);
1271 #ifdef _DIRENT_HAVE_D_NAMLEN
1272 d->d_namlen = len - 1;
1274 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
1275 d->d_type = df->type;
1277 memcpy (d->d_name, df->name, len);
1285 /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1286 * macro for stat64(). If stat is a macro, make a local wrapper function to
1289 * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a
1290 * regular file; fix that here.
1292 #if !defined(stat) && !defined(WINDOWS32) || defined(VMS)
1294 # ifndef HAVE_SYS_STAT_H
1295 int stat (const char *path, struct stat *sbuf);
1298 /* We are done with the fake stat. Go back to the real stat */
1303 # define local_stat stat
1306 local_stat (const char *path, struct stat *buf)
1310 size_t plen = strlen (path);
1312 /* Make sure the parent of "." exists and is a directory, not a
1313 file. This is because 'stat' on Windows normalizes the argument
1314 foo/. => foo without checking first that foo is a directory. */
1315 if (plen > 2 && path[plen - 1] == '.' && ISDIRSEP (path[plen - 2]))
1317 char parent[MAX_PATH+1];
1319 strncpy (parent, path, MAX_PATH);
1320 parent[MIN(plen - 2, MAX_PATH)] = '\0';
1321 if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
1326 EINTRLOOP (e, stat (path, buf));
1331 /* Similarly for lstat. */
1332 #if !defined(lstat) && !defined(WINDOWS32) || defined(VMS)
1334 # ifndef HAVE_SYS_STAT_H
1335 int lstat (const char *path, struct stat *sbuf);
1338 /* We are done with the fake lstat. Go back to the real lstat */
1343 # define local_lstat lstat
1344 #elif defined(WINDOWS32)
1345 /* Windows doesn't support lstat(). */
1346 # define local_lstat local_stat
1349 local_lstat (const char *path, struct stat *buf)
1352 EINTRLOOP (e, lstat (path, buf));
1358 dir_setup_glob (glob_t *gl)
1361 gl->gl_opendir = open_dirstream;
1362 gl->gl_readdir = read_dirstream;
1363 gl->gl_closedir = free;
1364 gl->gl_lstat = local_lstat;
1365 gl->gl_stat = local_stat;
1369 hash_init_directories (void)
1371 hash_init (&directories, DIRECTORY_BUCKETS,
1372 directory_hash_1, directory_hash_2, directory_hash_cmp);
1373 hash_init (&directory_contents, DIRECTORY_BUCKETS,
1374 directory_contents_hash_1, directory_contents_hash_2,
1375 directory_contents_hash_cmp);