source: trunk/src/kmk/dir.c@ 3679

Last change on this file since 3679 was 3679, checked in by bird, 5 weeks ago

kmk/dir.c: Marked bogus use of PATH_VAR.

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