VirtualBox

source: kBuild/trunk/src/gmake/dir.c@ 285

Last change on this file since 285 was 57, checked in by bird, 21 years ago

Config & adjustments for OS/2 LIBC. dllshell.

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