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