VirtualBox

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

Last change on this file since 3154 was 3140, checked in by bird, 7 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

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

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