VirtualBox

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

Last change on this file since 2091 was 1993, checked in by bird, 16 years ago

Merged in current GNU Make code (CVS from 2008-10-28). Ref #55.

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

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