VirtualBox

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

Last change on this file since 1939 was 1915, checked in by bird, 16 years ago

kmk: CONFIG_WITH_MINIMAL_STATS vs. CONFIG_WITH_MAKE_STATS - require special builds for expensive statistics.

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