VirtualBox

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

Last change on this file since 2754 was 2734, checked in by bird, 10 years ago

quick build fix - should make all use our glob instead...

  • Property svn:eol-style set to native
File size: 38.1 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 /* Nope; this really is a directory we haven't seen before. */
597
598#ifndef CONFIG_WITH_ALLOC_CACHES
599 dc = (struct directory_contents *)
600 xmalloc (sizeof (struct directory_contents));
601#else
602 dc = (struct directory_contents *)
603 alloccache_alloc (&directory_contents_cache);
604#endif
605
606 /* Enter it in the contents hash table. */
607 dc->dev = st.st_dev;
608#ifdef WINDOWS32
609# ifndef CONFIG_WITH_STRCACHE2
610 dc->path_key = xstrdup (w32_path);
611# else /* CONFIG_WITH_STRCACHE2 */
612 dc->path_key = dc_key.path_key;
613# endif /* CONFIG_WITH_STRCACHE2 */
614
615 dc->ctime = st.st_ctime;
616 dc->mtime = st.st_mtime;
617# ifdef KMK
618 dc->last_updated = time(NULL);
619# endif
620
621 /*
622 * NTFS is the only WINDOWS32 filesystem that bumps mtime
623 * on a directory when files are added/deleted from
624 * a directory.
625 */
626 w32_path[3] = '\0';
627 if (GetVolumeInformation(w32_path,
628 fs_label, sizeof (fs_label),
629 &fs_serno, &fs_len,
630 &fs_flags, fs_type, sizeof (fs_type)) == FALSE)
631 dc->fs_flags = FS_UNKNOWN;
632 else if (!strcmp(fs_type, "FAT"))
633 dc->fs_flags = FS_FAT;
634 else if (!strcmp(fs_type, "NTFS"))
635 dc->fs_flags = FS_NTFS;
636 else
637 dc->fs_flags = FS_UNKNOWN;
638#else
639# ifdef VMS
640 dc->ino[0] = st.st_ino[0];
641 dc->ino[1] = st.st_ino[1];
642 dc->ino[2] = st.st_ino[2];
643# else
644 dc->ino = st.st_ino;
645# endif
646#endif /* WINDOWS32 */
647 hash_insert_at (&directory_contents, dc, dc_slot);
648 ENULLLOOP (dc->dirstream, opendir (name));
649 if (dc->dirstream == 0)
650 /* Couldn't open the directory. Mark this by setting the
651 `files' member to a nil pointer. */
652 dc->dirfiles.ht_vec = 0;
653 else
654 {
655#ifdef KMK
656 int buckets = st.st_nlink * 2;
657 if (buckets < DIRFILE_BUCKETS)
658 buckets = DIRFILE_BUCKETS;
659 hash_init_strcached (&dc->dirfiles, buckets, &file_strcache,
660 offsetof (struct dirfile, name));
661#else
662# ifndef CONFIG_WITH_STRCACHE2
663 hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
664 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
665# else /* CONFIG_WITH_STRCACHE2 */
666 hash_init_strcached (&dc->dirfiles, DIRFILE_BUCKETS,
667 &file_strcache,
668 offsetof (struct dirfile, name));
669# endif /* CONFIG_WITH_STRCACHE2 */
670#endif
671 /* Keep track of how many directories are open. */
672 ++open_directories;
673 if (open_directories == MAX_OPEN_DIRECTORIES)
674 /* We have too many directories open already.
675 Read the entire directory and then close it. */
676 dir_contents_file_exists_p (dc, 0);
677 }
678 }
679
680 /* Point the name-hashed entry for DIR at its contents data. */
681 dir->contents = dc;
682 }
683 }
684
685 return dir;
686}
687
688
689/* Return 1 if the name FILENAME is entered in DIR's hash table.
690 FILENAME must contain no slashes. */
691
692static int
693dir_contents_file_exists_p (struct directory_contents *dir,
694 const char *filename)
695{
696 unsigned int hash;
697 struct dirfile *df;
698 struct dirent *d;
699#ifdef WINDOWS32
700# ifndef KMK
701 struct stat st;
702# endif
703 int rehash = 0;
704#endif
705#ifdef KMK
706 int ret = 0;
707#endif
708
709 if (dir == 0 || dir->dirfiles.ht_vec == 0)
710 /* The directory could not be stat'd or opened. */
711 return 0;
712
713#ifdef __MSDOS__
714 filename = dosify (filename);
715#endif
716
717#ifdef HAVE_CASE_INSENSITIVE_FS
718 filename = downcase (filename);
719#endif
720
721#ifdef __EMX__
722 if (filename != 0)
723 _fnlwr (filename); /* lower case for FAT drives */
724#endif
725
726#ifdef VMS
727 filename = vmsify (filename,0);
728#endif
729
730 hash = 0;
731 if (filename != 0)
732 {
733 struct dirfile dirfile_key;
734
735 if (*filename == '\0')
736 {
737 /* Checking if the directory exists. */
738 return 1;
739 }
740#ifndef CONFIG_WITH_STRCACHE2
741 dirfile_key.name = filename;
742 dirfile_key.length = strlen (filename);
743 df = hash_find_item (&dir->dirfiles, &dirfile_key);
744#else /* CONFIG_WITH_STRCACHE2 */
745 dirfile_key.length = strlen (filename);
746 dirfile_key.name = filename
747 = strcache_add_len (filename, dirfile_key.length);
748 df = hash_find_item_strcached (&dir->dirfiles, &dirfile_key);
749#endif /* CONFIG_WITH_STRCACHE2 */
750 if (df)
751 return !df->impossible;
752 }
753
754 /* The file was not found in the hashed list.
755 Try to read the directory further. */
756
757 if (dir->dirstream == 0)
758 {
759#if defined(WINDOWS32) && !defined(KMK)
760 /*
761 * Check to see if directory has changed since last read. FAT
762 * filesystems force a rehash always as mtime does not change
763 * on directories (ugh!).
764 */
765# ifdef KMK
766 if (dir->path_key && time(NULL) > dc->last_updated + 2) /* KMK: Only recheck every 2 seconds. */
767# else
768 if (dir->path_key)
769# endif
770 {
771 if ((dir->fs_flags & FS_FAT) != 0)
772 {
773 dir->mtime = time ((time_t *) 0);
774 rehash = 1;
775 }
776# ifdef KMK
777 else if ( birdStatModTimeOnly (dir->path_key, &st.st_mtim, 1) == 0
778 && st.st_mtime > dir->mtime)
779# else
780 else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime)
781# endif
782 {
783 /* reset date stamp to show most recent re-process. */
784 dir->mtime = st.st_mtime;
785 rehash = 1;
786 }
787
788
789 /* If it has been already read in, all done. */
790 if (!rehash)
791 return 0;
792
793 /* make sure directory can still be opened; if not return. */
794 dir->dirstream = opendir (dir->path_key);
795 if (!dir->dirstream)
796 return 0;
797# ifdef KMK
798 dc->last_updated = time(NULL);
799# endif
800 }
801 else
802#endif
803 /* The directory has been all read in. */
804 return 0;
805 }
806
807 while (1)
808 {
809 /* Enter the file in the hash table. */
810 unsigned int len;
811 struct dirfile dirfile_key;
812 struct dirfile **dirfile_slot;
813
814 ENULLLOOP (d, readdir (dir->dirstream));
815 if (d == 0)
816 {
817/* bird: Workaround for smbfs mounts returning EBADF at the end of the search.
818 To exactly determin the cause here, I should probably do some smbfs
819 tracing, but for now just ignoring the EBADF on seems to work.
820 (The smb server is 64-bit vista, btw.) */
821#if defined (__FreeBSD__)
822 struct statfs stfs;
823 int saved_errno = errno;
824 errno = 0;
825 if (saved_errno == EBADF
826 && !fstatfs (dirfd (dir->dirstream), &stfs)
827 && !(stfs.f_flags & MNT_LOCAL)
828 && !strcmp(stfs.f_fstypename, "smbfs"))
829 {
830 /*fprintf (stderr, "EBADF on remote fs! dirfd=%d errno=%d\n",
831 dirfd (dir->dirstream), errno);*/
832 saved_errno = 0;
833 }
834 errno = saved_errno;
835#endif
836/* bird: end */
837 if (errno)
838 fatal (NILF, "INTERNAL: readdir(%p): %s (filename=%s)\n", (void *)dir, strerror (errno), filename);
839 break;
840 }
841
842#if defined(VMS) && defined(HAVE_DIRENT_H)
843 /* In VMS we get file versions too, which have to be stripped off */
844 {
845 char *p = strrchr (d->d_name, ';');
846 if (p)
847 *p = '\0';
848 }
849#endif
850 if (!REAL_DIR_ENTRY (d))
851 continue;
852
853 len = NAMLEN (d);
854#ifndef CONFIG_WITH_STRCACHE2
855 dirfile_key.name = d->d_name;
856 dirfile_key.length = len;
857 dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key);
858#else
859# if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
860 dirfile_key.name = strcache_add_len (downcase(d->d_name), len);
861# else
862 dirfile_key.name = strcache_add_len (d->d_name, len);
863# endif
864 dirfile_key.length = len;
865 dirfile_slot = (struct dirfile **) hash_find_slot_strcached (&dir->dirfiles, &dirfile_key);
866#endif
867#ifdef WINDOWS32
868 /*
869 * If re-reading a directory, don't cache files that have
870 * already been discovered.
871 */
872 if (! rehash || HASH_VACANT (*dirfile_slot))
873#endif
874 {
875#ifndef CONFIG_WITH_ALLOC_CACHES
876 df = xmalloc (sizeof (struct dirfile));
877#else
878 df = alloccache_alloc (&dirfile_cache);
879#endif
880#ifndef CONFIG_WITH_STRCACHE2
881#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
882 df->name = strcache_add_len (downcase(d->d_name), len);
883#else
884 df->name = strcache_add_len (d->d_name, len);
885#endif
886#else /* CONFIG_WITH_STRCACHE2 */
887 df->name = dirfile_key.name;
888#endif /* CONFIG_WITH_STRCACHE2 */
889 df->length = len;
890 df->impossible = 0;
891 hash_insert_at (&dir->dirfiles, df, dirfile_slot);
892 }
893 /* Check if the name matches the one we're searching for. */
894#ifndef CONFIG_WITH_STRCACHE2
895 if (filename != 0 && patheq (d->d_name, filename))
896#else
897 if (filename != 0 && dirfile_key.name == filename)
898#endif
899#ifdef KMK
900 ret = 1; /* Cache the whole dir. Prevents trouble on windows and os2 during 'rebuild'. */
901#else
902 return 1;
903#endif
904 }
905
906 /* If the directory has been completely read in,
907 close the stream and reset the pointer to nil. */
908 if (d == 0)
909 {
910 --open_directories;
911 closedir (dir->dirstream);
912 dir->dirstream = 0;
913 }
914#ifdef KMK
915 return ret;
916#else
917 return 0;
918#endif
919}
920
921/* Return 1 if the name FILENAME in directory DIRNAME
922 is entered in the dir hash table.
923 FILENAME must contain no slashes. */
924
925int
926dir_file_exists_p (const char *dirname, const char *filename)
927{
928 return dir_contents_file_exists_p (find_directory (dirname)->contents,
929 filename);
930}
931
932
933/* Return 1 if the file named NAME exists. */
934
935int
936file_exists_p (const char *name)
937{
938 const char *dirend;
939 const char *dirname;
940 const char *slash;
941
942#ifndef NO_ARCHIVES
943 if (ar_name (name))
944 return ar_member_date (name) != (time_t) -1;
945#endif
946
947#ifdef VMS
948 dirend = strrchr (name, ']');
949 if (dirend == 0)
950 dirend = strrchr (name, ':');
951 if (dirend == 0)
952 return dir_file_exists_p ("[]", name);
953#else /* !VMS */
954 dirend = strrchr (name, '/');
955#ifdef HAVE_DOS_PATHS
956 /* Forward and backslashes might be mixed. We need the rightmost one. */
957 {
958 const char *bslash = strrchr(name, '\\');
959 if (!dirend || bslash > dirend)
960 dirend = bslash;
961 /* The case of "d:file". */
962 if (!dirend && name[0] && name[1] == ':')
963 dirend = name + 1;
964 }
965#endif /* HAVE_DOS_PATHS */
966 if (dirend == 0)
967#ifndef _AMIGA
968 return dir_file_exists_p (".", name);
969#else /* !VMS && !AMIGA */
970 return dir_file_exists_p ("", name);
971#endif /* AMIGA */
972#endif /* VMS */
973
974 slash = dirend;
975 if (dirend == name)
976 dirname = "/";
977 else
978 {
979 char *p;
980#ifdef HAVE_DOS_PATHS
981 /* d:/ and d: are *very* different... */
982 if (dirend < name + 3 && name[1] == ':' &&
983 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
984 dirend++;
985#endif
986 p = alloca (dirend - name + 1);
987 memcpy (p, name, dirend - name);
988 p[dirend - name] = '\0';
989 dirname = p;
990 }
991 return dir_file_exists_p (dirname, slash + 1);
992}
993
994
995/* Mark FILENAME as `impossible' for `file_impossible_p'.
996 This means an attempt has been made to search for FILENAME
997 as an intermediate file, and it has failed. */
998
999void
1000file_impossible (const char *filename)
1001{
1002 const char *dirend;
1003 const char *p = filename;
1004 struct directory *dir;
1005 struct dirfile *new;
1006
1007#ifdef VMS
1008 dirend = strrchr (p, ']');
1009 if (dirend == 0)
1010 dirend = strrchr (p, ':');
1011 dirend++;
1012 if (dirend == (char *)1)
1013 dir = find_directory ("[]");
1014#else
1015 dirend = strrchr (p, '/');
1016# ifdef HAVE_DOS_PATHS
1017 /* Forward and backslashes might be mixed. We need the rightmost one. */
1018 {
1019 const char *bslash = strrchr(p, '\\');
1020 if (!dirend || bslash > dirend)
1021 dirend = bslash;
1022 /* The case of "d:file". */
1023 if (!dirend && p[0] && p[1] == ':')
1024 dirend = p + 1;
1025 }
1026# endif /* HAVE_DOS_PATHS */
1027 if (dirend == 0)
1028# ifdef _AMIGA
1029 dir = find_directory ("");
1030# else /* !VMS && !AMIGA */
1031 dir = find_directory (".");
1032# endif /* AMIGA */
1033#endif /* VMS */
1034 else
1035 {
1036 const char *dirname;
1037 const char *slash = dirend;
1038 if (dirend == p)
1039 dirname = "/";
1040 else
1041 {
1042 char *cp;
1043#ifdef HAVE_DOS_PATHS
1044 /* d:/ and d: are *very* different... */
1045 if (dirend < p + 3 && p[1] == ':' &&
1046 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
1047 dirend++;
1048#endif
1049 cp = alloca (dirend - p + 1);
1050 memcpy (cp, p, dirend - p);
1051 cp[dirend - p] = '\0';
1052 dirname = cp;
1053 }
1054 dir = find_directory (dirname);
1055 filename = p = slash + 1;
1056 }
1057
1058 if (dir->contents == 0)
1059 /* The directory could not be stat'd. We allocate a contents
1060 structure for it, but leave it out of the contents hash table. */
1061#ifndef CONFIG_WITH_ALLOC_CACHES
1062 dir->contents = xcalloc (sizeof (struct directory_contents));
1063#else
1064 dir->contents = alloccache_calloc (&directory_contents_cache);
1065#endif
1066
1067 if (dir->contents->dirfiles.ht_vec == 0)
1068 {
1069#ifndef CONFIG_WITH_STRCACHE2
1070 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS,
1071 dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
1072#else /* CONFIG_WITH_STRCACHE2 */
1073 hash_init_strcached (&dir->contents->dirfiles, DIRFILE_BUCKETS,
1074 &file_strcache, offsetof (struct dirfile, name));
1075#endif /* CONFIG_WITH_STRCACHE2 */
1076 }
1077
1078 /* Make a new entry and put it in the table. */
1079
1080#ifndef CONFIG_WITH_ALLOC_CACHES
1081 new = xmalloc (sizeof (struct dirfile));
1082#else
1083 new = alloccache_alloc (&dirfile_cache);
1084#endif
1085 new->length = strlen (filename);
1086#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
1087 new->name = strcache_add_len (downcase(filename), new->length);
1088#else
1089 new->name = strcache_add_len (filename, new->length);
1090#endif
1091 new->impossible = 1;
1092#ifndef CONFIG_WITH_STRCACHE2
1093 hash_insert (&dir->contents->dirfiles, new);
1094#else /* CONFIG_WITH_STRCACHE2 */
1095 hash_insert_strcached (&dir->contents->dirfiles, new);
1096#endif /* CONFIG_WITH_STRCACHE2 */
1097}
1098
1099
1100/* Return nonzero if FILENAME has been marked impossible. */
1101
1102int
1103file_impossible_p (const char *filename)
1104{
1105 const char *dirend;
1106 const char *p = filename;
1107 struct directory_contents *dir;
1108 struct dirfile *dirfile;
1109 struct dirfile dirfile_key;
1110
1111#ifdef VMS
1112 dirend = strrchr (filename, ']');
1113 if (dirend == 0)
1114 dir = find_directory ("[]")->contents;
1115#else
1116 dirend = strrchr (filename, '/');
1117#ifdef HAVE_DOS_PATHS
1118 /* Forward and backslashes might be mixed. We need the rightmost one. */
1119 {
1120 const char *bslash = strrchr(filename, '\\');
1121 if (!dirend || bslash > dirend)
1122 dirend = bslash;
1123 /* The case of "d:file". */
1124 if (!dirend && filename[0] && filename[1] == ':')
1125 dirend = filename + 1;
1126 }
1127#endif /* HAVE_DOS_PATHS */
1128 if (dirend == 0)
1129#ifdef _AMIGA
1130 dir = find_directory ("")->contents;
1131#else /* !VMS && !AMIGA */
1132 dir = find_directory (".")->contents;
1133#endif /* AMIGA */
1134#endif /* VMS */
1135 else
1136 {
1137 const char *dirname;
1138 const char *slash = dirend;
1139 if (dirend == filename)
1140 dirname = "/";
1141 else
1142 {
1143 char *cp;
1144#ifdef HAVE_DOS_PATHS
1145 /* d:/ and d: are *very* different... */
1146 if (dirend < filename + 3 && filename[1] == ':' &&
1147 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
1148 dirend++;
1149#endif
1150 cp = alloca (dirend - filename + 1);
1151 memcpy (cp, p, dirend - p);
1152 cp[dirend - p] = '\0';
1153 dirname = cp;
1154 }
1155 dir = find_directory (dirname)->contents;
1156 p = filename = slash + 1;
1157 }
1158
1159 if (dir == 0 || dir->dirfiles.ht_vec == 0)
1160 /* There are no files entered for this directory. */
1161 return 0;
1162
1163#ifdef __MSDOS__
1164 filename = dosify (p);
1165#endif
1166#ifdef HAVE_CASE_INSENSITIVE_FS
1167 filename = downcase (p);
1168#endif
1169#ifdef VMS
1170 filename = vmsify (p, 1);
1171#endif
1172
1173#ifndef CONFIG_WITH_STRCACHE2
1174 dirfile_key.name = filename;
1175 dirfile_key.length = strlen (filename);
1176 dirfile = hash_find_item (&dir->dirfiles, &dirfile_key);
1177#else
1178 dirfile_key.length = strlen (filename);
1179 dirfile_key.name = strcache_add_len (filename, dirfile_key.length);
1180 dirfile = hash_find_item_strcached (&dir->dirfiles, &dirfile_key);
1181#endif
1182 if (dirfile)
1183 return dirfile->impossible;
1184
1185 return 0;
1186}
1187
1188
1189/* Return the already allocated name in the
1190 directory hash table that matches DIR. */
1191
1192const char *
1193dir_name (const char *dir)
1194{
1195 return find_directory (dir)->name;
1196}
1197
1198
1199/* Print the data base of directories. */
1200
1201void
1202print_dir_data_base (void)
1203{
1204 unsigned int files;
1205 unsigned int impossible;
1206 struct directory **dir_slot;
1207 struct directory **dir_end;
1208
1209 puts (_("\n# Directories\n"));
1210
1211 files = impossible = 0;
1212
1213 dir_slot = (struct directory **) directories.ht_vec;
1214 dir_end = dir_slot + directories.ht_size;
1215 for ( ; dir_slot < dir_end; dir_slot++)
1216 {
1217 struct directory *dir = *dir_slot;
1218 if (! HASH_VACANT (dir))
1219 {
1220 if (dir->contents == 0)
1221 printf (_("# %s: could not be stat'd.\n"), dir->name);
1222 else if (dir->contents->dirfiles.ht_vec == 0)
1223 {
1224#ifdef WINDOWS32
1225 printf (_("# %s (key %s, mtime %d): could not be opened.\n"),
1226 dir->name, dir->contents->path_key,dir->contents->mtime);
1227#else /* WINDOWS32 */
1228#ifdef VMS
1229 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
1230 dir->name, dir->contents->dev,
1231 dir->contents->ino[0], dir->contents->ino[1],
1232 dir->contents->ino[2]);
1233#else
1234 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
1235 dir->name, (long int) dir->contents->dev,
1236 (long int) dir->contents->ino);
1237#endif
1238#endif /* WINDOWS32 */
1239 }
1240 else
1241 {
1242 unsigned int f = 0;
1243 unsigned int im = 0;
1244 struct dirfile **files_slot;
1245 struct dirfile **files_end;
1246
1247 files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
1248 files_end = files_slot + dir->contents->dirfiles.ht_size;
1249 for ( ; files_slot < files_end; files_slot++)
1250 {
1251 struct dirfile *df = *files_slot;
1252 if (! HASH_VACANT (df))
1253 {
1254 if (df->impossible)
1255 ++im;
1256 else
1257 ++f;
1258 }
1259 }
1260#ifdef WINDOWS32
1261 printf (_("# %s (key %s, mtime %d): "),
1262 dir->name, dir->contents->path_key, dir->contents->mtime);
1263#else /* WINDOWS32 */
1264#ifdef VMS
1265 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1266 dir->name, dir->contents->dev,
1267 dir->contents->ino[0], dir->contents->ino[1],
1268 dir->contents->ino[2]);
1269#else
1270 printf (_("# %s (device %ld, inode %ld): "),
1271 dir->name,
1272 (long)dir->contents->dev, (long)dir->contents->ino);
1273#endif
1274#endif /* WINDOWS32 */
1275 if (f == 0)
1276 fputs (_("No"), stdout);
1277 else
1278 printf ("%u", f);
1279 fputs (_(" files, "), stdout);
1280 if (im == 0)
1281 fputs (_("no"), stdout);
1282 else
1283 printf ("%u", im);
1284 fputs (_(" impossibilities"), stdout);
1285 if (dir->contents->dirstream == 0)
1286 puts (".");
1287 else
1288 puts (_(" so far."));
1289 files += f;
1290 impossible += im;
1291#ifdef KMK
1292 fputs ("# ", stdout);
1293 hash_print_stats (&dir->contents->dirfiles, stdout);
1294 fputs ("\n", stdout);
1295#endif
1296 }
1297 }
1298 }
1299
1300 fputs ("\n# ", stdout);
1301 if (files == 0)
1302 fputs (_("No"), stdout);
1303 else
1304 printf ("%u", files);
1305 fputs (_(" files, "), stdout);
1306 if (impossible == 0)
1307 fputs (_("no"), stdout);
1308 else
1309 printf ("%u", impossible);
1310 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1311#ifdef KMK
1312 fputs ("# directories: ", stdout);
1313 hash_print_stats (&directories, stdout);
1314 fputs ("\n# directory_contents: ", stdout);
1315 hash_print_stats (&directory_contents, stdout);
1316 fputs ("\n", stdout);
1317#endif
1318}
1319
1320
1321/* Hooks for globbing. */
1322
1323#include <glob.h>
1324
1325/* Structure describing state of iterating through a directory hash table. */
1326
1327struct dirstream
1328 {
1329 struct directory_contents *contents; /* The directory being read. */
1330 struct dirfile **dirfile_slot; /* Current slot in table. */
1331 };
1332
1333/* Forward declarations. */
1334static __ptr_t open_dirstream (const char *);
1335static struct dirent *read_dirstream (__ptr_t);
1336
1337static __ptr_t
1338open_dirstream (const char *directory)
1339{
1340 struct dirstream *new;
1341 struct directory *dir = find_directory (directory);
1342
1343 if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1344 /* DIR->contents is nil if the directory could not be stat'd.
1345 DIR->contents->dirfiles is nil if it could not be opened. */
1346 return 0;
1347
1348 /* Read all the contents of the directory now. There is no benefit
1349 in being lazy, since glob will want to see every file anyway. */
1350
1351 dir_contents_file_exists_p (dir->contents, 0);
1352
1353 new = xmalloc (sizeof (struct dirstream));
1354 new->contents = dir->contents;
1355 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1356
1357 return (__ptr_t) new;
1358}
1359
1360static struct dirent *
1361read_dirstream (__ptr_t stream)
1362{
1363 static char *buf;
1364 static unsigned int bufsz;
1365
1366 struct dirstream *const ds = (struct dirstream *) stream;
1367 struct directory_contents *dc = ds->contents;
1368 struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1369
1370 while (ds->dirfile_slot < dirfile_end)
1371 {
1372 struct dirfile *df = *ds->dirfile_slot++;
1373 if (! HASH_VACANT (df) && !df->impossible)
1374 {
1375 /* The glob interface wants a `struct dirent', so mock one up. */
1376 struct dirent *d;
1377 unsigned int len = df->length + 1;
1378 unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len;
1379 if (sz > bufsz)
1380 {
1381 bufsz *= 2;
1382 if (sz > bufsz)
1383 bufsz = sz;
1384 buf = xrealloc (buf, bufsz);
1385 }
1386 d = (struct dirent *) buf;
1387#ifdef __MINGW32__
1388# if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \
1389 __MINGW32_MINOR_VERSION == 0)
1390 d->d_name = xmalloc(len);
1391# endif
1392#endif
1393 FAKE_DIR_ENTRY (d);
1394#ifdef _DIRENT_HAVE_D_NAMLEN
1395 d->d_namlen = len - 1;
1396#endif
1397#ifdef _DIRENT_HAVE_D_TYPE
1398 d->d_type = DT_UNKNOWN;
1399#endif
1400 memcpy (d->d_name, df->name, len);
1401 return d;
1402 }
1403 }
1404
1405 return 0;
1406}
1407
1408static void
1409ansi_free (void *p)
1410{
1411 if (p)
1412 free(p);
1413}
1414
1415/* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1416 * macro for stat64(). If stat is a macro, make a local wrapper function to
1417 * invoke it.
1418 */
1419#ifndef stat
1420# ifndef VMS
1421int stat (const char *path, struct stat *sbuf);
1422# endif
1423# define local_stat stat
1424#else
1425static int
1426local_stat (const char *path, struct stat *buf)
1427{
1428 int e;
1429
1430 EINTRLOOP (e, stat (path, buf));
1431 return e;
1432}
1433#endif
1434
1435#ifdef KMK
1436static int dir_exists_p (const char *dirname)
1437{
1438 if (file_exists_p (dirname))
1439 {
1440 struct directory *dir = find_directory (dirname);
1441 if (dir != NULL && dir->contents && dir->contents->dirfiles.ht_vec != NULL)
1442 return 1;
1443 }
1444 return 0;
1445}
1446#endif
1447
1448void
1449dir_setup_glob (glob_t *gl)
1450{
1451 gl->gl_opendir = open_dirstream;
1452 gl->gl_readdir = read_dirstream;
1453 gl->gl_closedir = ansi_free;
1454 gl->gl_stat = local_stat;
1455#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */
1456 gl->gl_lstat = local_stat;
1457#endif
1458#if defined(KMK) && !defined(__OS2__)
1459 gl->gl_exists = file_exists_p;
1460 gl->gl_isdir = dir_exists_p;
1461#endif
1462 /* We don't bother setting gl_lstat, since glob never calls it.
1463 The slot is only there for compatibility with 4.4 BSD. */
1464}
1465
1466void
1467hash_init_directories (void)
1468{
1469#ifndef CONFIG_WITH_STRCACHE2
1470 hash_init (&directories, DIRECTORY_BUCKETS,
1471 directory_hash_1, directory_hash_2, directory_hash_cmp);
1472#else /* CONFIG_WITH_STRCACHE2 */
1473 hash_init_strcached (&directories, DIRECTORY_BUCKETS, &file_strcache,
1474 offsetof (struct directory, name));
1475#endif /* CONFIG_WITH_STRCACHE2 */
1476 hash_init (&directory_contents, DIRECTORY_BUCKETS,
1477 directory_contents_hash_1, directory_contents_hash_2,
1478 directory_contents_hash_cmp);
1479#ifdef CONFIG_WITH_ALLOC_CACHES
1480 alloccache_init (&directories_cache, sizeof (struct directory),
1481 "directories", NULL, NULL);
1482 alloccache_init (&directory_contents_cache, sizeof (struct directory_contents),
1483 "directory_contents", NULL, NULL);
1484 alloccache_init (&dirfile_cache, sizeof (struct dirfile),
1485 "dirfile", NULL, NULL);
1486#endif /* CONFIG_WITH_ALLOC_CACHES */
1487}
1488
Note: See TracBrowser for help on using the repository browser.

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