VirtualBox

source: kBuild/vendor/gnumake/4.2.1-git/dir.c

Last change on this file was 3138, checked in by bird, 7 years ago

Imported make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6) from https://git.savannah.gnu.org/git/make.git.

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