VirtualBox

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

Last change on this file since 1959 was 1941, checked in by bird, 16 years ago

dir.c: overlooked one hash_insert.

  • Property svn:eol-style set to native
File size: 36.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 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#ifndef CONFIG_WITH_STRCACHE2
1043 hash_insert (&dir->contents->dirfiles, new);
1044#else /* CONFIG_WITH_STRCACHE2 */
1045 hash_insert_strcached (&dir->contents->dirfiles, new);
1046#endif /* CONFIG_WITH_STRCACHE2 */
1047}
1048
1049
1050/* Return nonzero if FILENAME has been marked impossible. */
1051
1052int
1053file_impossible_p (const char *filename)
1054{
1055 const char *dirend;
1056 const char *p = filename;
1057 struct directory_contents *dir;
1058 struct dirfile *dirfile;
1059 struct dirfile dirfile_key;
1060
1061#ifdef VMS
1062 dirend = strrchr (filename, ']');
1063 if (dirend == 0)
1064 dir = find_directory ("[]")->contents;
1065#else
1066 dirend = strrchr (filename, '/');
1067#ifdef HAVE_DOS_PATHS
1068 /* Forward and backslashes might be mixed. We need the rightmost one. */
1069 {
1070 const char *bslash = strrchr(filename, '\\');
1071 if (!dirend || bslash > dirend)
1072 dirend = bslash;
1073 /* The case of "d:file". */
1074 if (!dirend && filename[0] && filename[1] == ':')
1075 dirend = filename + 1;
1076 }
1077#endif /* HAVE_DOS_PATHS */
1078 if (dirend == 0)
1079#ifdef _AMIGA
1080 dir = find_directory ("")->contents;
1081#else /* !VMS && !AMIGA */
1082 dir = find_directory (".")->contents;
1083#endif /* AMIGA */
1084#endif /* VMS */
1085 else
1086 {
1087 const char *dirname;
1088 const char *slash = dirend;
1089 if (dirend == filename)
1090 dirname = "/";
1091 else
1092 {
1093 char *cp;
1094#ifdef HAVE_DOS_PATHS
1095 /* d:/ and d: are *very* different... */
1096 if (dirend < filename + 3 && filename[1] == ':' &&
1097 (*dirend == '/' || *dirend == '\\' || *dirend == ':'))
1098 dirend++;
1099#endif
1100 cp = alloca (dirend - filename + 1);
1101 memcpy (cp, p, dirend - p);
1102 cp[dirend - p] = '\0';
1103 dirname = cp;
1104 }
1105 dir = find_directory (dirname)->contents;
1106 p = filename = slash + 1;
1107 }
1108
1109 if (dir == 0 || dir->dirfiles.ht_vec == 0)
1110 /* There are no files entered for this directory. */
1111 return 0;
1112
1113#ifdef __MSDOS__
1114 filename = dosify (p);
1115#endif
1116#ifdef HAVE_CASE_INSENSITIVE_FS
1117 filename = downcase (p);
1118#endif
1119#ifdef VMS
1120 filename = vmsify (p, 1);
1121#endif
1122
1123#ifndef CONFIG_WITH_STRCACHE2
1124 dirfile_key.name = filename;
1125 dirfile_key.length = strlen (filename);
1126 dirfile = hash_find_item (&dir->dirfiles, &dirfile_key);
1127#else
1128 dirfile_key.length = strlen (filename);
1129 dirfile_key.name = strcache_add_len (filename, dirfile_key.length);
1130 dirfile = hash_find_item_strcached (&dir->dirfiles, &dirfile_key);
1131#endif
1132 if (dirfile)
1133 return dirfile->impossible;
1134
1135 return 0;
1136}
1137
1138
1139/* Return the already allocated name in the
1140 directory hash table that matches DIR. */
1141
1142const char *
1143dir_name (const char *dir)
1144{
1145 return find_directory (dir)->name;
1146}
1147
1148
1149/* Print the data base of directories. */
1150
1151void
1152print_dir_data_base (void)
1153{
1154 unsigned int files;
1155 unsigned int impossible;
1156 struct directory **dir_slot;
1157 struct directory **dir_end;
1158
1159 puts (_("\n# Directories\n"));
1160
1161 files = impossible = 0;
1162
1163 dir_slot = (struct directory **) directories.ht_vec;
1164 dir_end = dir_slot + directories.ht_size;
1165 for ( ; dir_slot < dir_end; dir_slot++)
1166 {
1167 struct directory *dir = *dir_slot;
1168 if (! HASH_VACANT (dir))
1169 {
1170 if (dir->contents == 0)
1171 printf (_("# %s: could not be stat'd.\n"), dir->name);
1172 else if (dir->contents->dirfiles.ht_vec == 0)
1173 {
1174#ifdef WINDOWS32
1175 printf (_("# %s (key %s, mtime %d): could not be opened.\n"),
1176 dir->name, dir->contents->path_key,dir->contents->mtime);
1177#else /* WINDOWS32 */
1178#ifdef VMS
1179 printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"),
1180 dir->name, dir->contents->dev,
1181 dir->contents->ino[0], dir->contents->ino[1],
1182 dir->contents->ino[2]);
1183#else
1184 printf (_("# %s (device %ld, inode %ld): could not be opened.\n"),
1185 dir->name, (long int) dir->contents->dev,
1186 (long int) dir->contents->ino);
1187#endif
1188#endif /* WINDOWS32 */
1189 }
1190 else
1191 {
1192 unsigned int f = 0;
1193 unsigned int im = 0;
1194 struct dirfile **files_slot;
1195 struct dirfile **files_end;
1196
1197 files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec;
1198 files_end = files_slot + dir->contents->dirfiles.ht_size;
1199 for ( ; files_slot < files_end; files_slot++)
1200 {
1201 struct dirfile *df = *files_slot;
1202 if (! HASH_VACANT (df))
1203 {
1204 if (df->impossible)
1205 ++im;
1206 else
1207 ++f;
1208 }
1209 }
1210#ifdef WINDOWS32
1211 printf (_("# %s (key %s, mtime %d): "),
1212 dir->name, dir->contents->path_key, dir->contents->mtime);
1213#else /* WINDOWS32 */
1214#ifdef VMS
1215 printf (_("# %s (device %d, inode [%d,%d,%d]): "),
1216 dir->name, dir->contents->dev,
1217 dir->contents->ino[0], dir->contents->ino[1],
1218 dir->contents->ino[2]);
1219#else
1220 printf (_("# %s (device %ld, inode %ld): "),
1221 dir->name,
1222 (long)dir->contents->dev, (long)dir->contents->ino);
1223#endif
1224#endif /* WINDOWS32 */
1225 if (f == 0)
1226 fputs (_("No"), stdout);
1227 else
1228 printf ("%u", f);
1229 fputs (_(" files, "), stdout);
1230 if (im == 0)
1231 fputs (_("no"), stdout);
1232 else
1233 printf ("%u", im);
1234 fputs (_(" impossibilities"), stdout);
1235 if (dir->contents->dirstream == 0)
1236 puts (".");
1237 else
1238 puts (_(" so far."));
1239 files += f;
1240 impossible += im;
1241
1242#ifdef KMK
1243 fputs ("# ", stdout);
1244 hash_print_stats (&dir->contents->dirfiles, stdout);
1245 fputs ("\n", stdout);
1246#endif
1247 }
1248 }
1249 }
1250
1251 fputs ("\n# ", stdout);
1252 if (files == 0)
1253 fputs (_("No"), stdout);
1254 else
1255 printf ("%u", files);
1256 fputs (_(" files, "), stdout);
1257 if (impossible == 0)
1258 fputs (_("no"), stdout);
1259 else
1260 printf ("%u", impossible);
1261 printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill);
1262#ifdef KMK
1263 fputs ("# directories: ", stdout);
1264 hash_print_stats (&directories, stdout);
1265 fputs ("\n# directory_contents: ", stdout);
1266 hash_print_stats (&directory_contents, stdout);
1267 fputs ("\n", stdout);
1268#endif
1269}
1270
1271
1272/* Hooks for globbing. */
1273
1274#include <glob.h>
1275
1276/* Structure describing state of iterating through a directory hash table. */
1277
1278struct dirstream
1279 {
1280 struct directory_contents *contents; /* The directory being read. */
1281 struct dirfile **dirfile_slot; /* Current slot in table. */
1282 };
1283
1284/* Forward declarations. */
1285static __ptr_t open_dirstream (const char *);
1286static struct dirent *read_dirstream (__ptr_t);
1287
1288static __ptr_t
1289open_dirstream (const char *directory)
1290{
1291 struct dirstream *new;
1292 struct directory *dir = find_directory (directory);
1293
1294 if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0)
1295 /* DIR->contents is nil if the directory could not be stat'd.
1296 DIR->contents->dirfiles is nil if it could not be opened. */
1297 return 0;
1298
1299 /* Read all the contents of the directory now. There is no benefit
1300 in being lazy, since glob will want to see every file anyway. */
1301
1302 dir_contents_file_exists_p (dir->contents, 0);
1303
1304 new = xmalloc (sizeof (struct dirstream));
1305 new->contents = dir->contents;
1306 new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec;
1307
1308 return (__ptr_t) new;
1309}
1310
1311static struct dirent *
1312read_dirstream (__ptr_t stream)
1313{
1314 static char *buf;
1315 static unsigned int bufsz;
1316
1317 struct dirstream *const ds = (struct dirstream *) stream;
1318 struct directory_contents *dc = ds->contents;
1319 struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
1320
1321 while (ds->dirfile_slot < dirfile_end)
1322 {
1323 struct dirfile *df = *ds->dirfile_slot++;
1324 if (! HASH_VACANT (df) && !df->impossible)
1325 {
1326 /* The glob interface wants a `struct dirent', so mock one up. */
1327 struct dirent *d;
1328 unsigned int len = df->length + 1;
1329 unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len;
1330 if (sz > bufsz)
1331 {
1332 bufsz *= 2;
1333 if (sz > bufsz)
1334 bufsz = sz;
1335 buf = xrealloc (buf, bufsz);
1336 }
1337 d = (struct dirent *) buf;
1338#ifdef __MINGW32__
1339# if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \
1340 __MINGW32_MINOR_VERSION == 0)
1341 d->d_name = xmalloc(len);
1342# endif
1343#endif
1344 FAKE_DIR_ENTRY (d);
1345#ifdef _DIRENT_HAVE_D_NAMLEN
1346 d->d_namlen = len - 1;
1347#endif
1348#ifdef _DIRENT_HAVE_D_TYPE
1349 d->d_type = DT_UNKNOWN;
1350#endif
1351 memcpy (d->d_name, df->name, len);
1352 return d;
1353 }
1354 }
1355
1356 return 0;
1357}
1358
1359static void
1360ansi_free (void *p)
1361{
1362 if (p)
1363 free(p);
1364}
1365
1366/* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
1367 * macro for stat64(). If stat is a macro, make a local wrapper function to
1368 * invoke it.
1369 */
1370#ifndef stat
1371# ifndef VMS
1372int stat (const char *path, struct stat *sbuf);
1373# endif
1374# define local_stat stat
1375#else
1376static int
1377local_stat (const char *path, struct stat *buf)
1378{
1379 int e;
1380
1381 EINTRLOOP (e, stat (path, buf));
1382 return e;
1383}
1384#endif
1385
1386void
1387dir_setup_glob (glob_t *gl)
1388{
1389 gl->gl_opendir = open_dirstream;
1390 gl->gl_readdir = read_dirstream;
1391 gl->gl_closedir = ansi_free;
1392 gl->gl_stat = local_stat;
1393#ifdef __EMX__ /* The FreeBSD implemenation actually uses gl_lstat!! */
1394 gl->gl_lstat = local_stat;
1395#endif
1396 /* We don't bother setting gl_lstat, since glob never calls it.
1397 The slot is only there for compatibility with 4.4 BSD. */
1398}
1399
1400void
1401hash_init_directories (void)
1402{
1403#ifndef CONFIG_WITH_STRCACHE2
1404 hash_init (&directories, DIRECTORY_BUCKETS,
1405 directory_hash_1, directory_hash_2, directory_hash_cmp);
1406#else /* */
1407 hash_init_strcached (&directories, DIRECTORY_BUCKETS, &file_strcache,
1408 offsetof (struct directory, name));
1409#endif /* */
1410 hash_init (&directory_contents, DIRECTORY_BUCKETS,
1411 directory_contents_hash_1, directory_contents_hash_2,
1412 directory_contents_hash_cmp);
1413#ifdef CONFIG_WITH_ALLOC_CACHES
1414 alloccache_init (&directories_cache, sizeof (struct directory),
1415 "directories", NULL, NULL);
1416 alloccache_init (&directory_contents_cache, sizeof (struct directory_contents),
1417 "directory_contents", NULL, NULL);
1418 alloccache_init (&dirfile_cache, sizeof (struct dirfile),
1419 "dirfile", NULL, NULL);
1420#endif
1421}
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