VirtualBox

source: kBuild/trunk/src/kmk/dir.c@ 3068

Last change on this file since 3068 was 3065, checked in by bird, 7 years ago

misc gcc warning fixes

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette