VirtualBox

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

Last change on this file since 1980 was 1980, checked in by bird, 17 years ago

kmk: Some cleanup.

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