VirtualBox

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

Last change on this file since 2657 was 2591, checked in by bird, 13 years ago

kmk: Merged in changes from GNU make 3.82. Previous GNU make base version was gnumake-2008-10-28-CVS.

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