VirtualBox

source: kBuild/vendor/gnumake/3.82-cvs/dir.c

Last change on this file was 2580, checked in by bird, 12 years ago

Importing the make-3-82 CVS tag with --auto-props but no keywords.

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