1 /* $NetBSD: dir.c,v 1.67 2013/03/05 22:01:43 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1988, 1989 by Adam de Boor 37 * Copyright (c) 1989 by Berkeley Softworks 38 * All rights reserved. 39 * 40 * This code is derived from software contributed to Berkeley by 41 * Adam de Boor. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 */ 71 72 #ifndef MAKE_NATIVE 73 static char rcsid[] = "$NetBSD: dir.c,v 1.67 2013/03/05 22:01:43 christos Exp $"; 74 #else 75 #include <sys/cdefs.h> 76 #ifndef lint 77 #if 0 78 static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; 79 #else 80 __RCSID("$NetBSD: dir.c,v 1.67 2013/03/05 22:01:43 christos Exp $"); 81 #endif 82 #endif /* not lint */ 83 #endif 84 85 /*- 86 * dir.c -- 87 * Directory searching using wildcards and/or normal names... 88 * Used both for source wildcarding in the Makefile and for finding 89 * implicit sources. 90 * 91 * The interface for this module is: 92 * Dir_Init Initialize the module. 93 * 94 * Dir_InitCur Set the cur Path. 95 * 96 * Dir_InitDot Set the dot Path. 97 * 98 * Dir_End Cleanup the module. 99 * 100 * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath. 101 * 102 * Dir_HasWildcards Returns TRUE if the name given it needs to 103 * be wildcard-expanded. 104 * 105 * Dir_Expand Given a pattern and a path, return a Lst of names 106 * which match the pattern on the search path. 107 * 108 * Dir_FindFile Searches for a file on a given search path. 109 * If it exists, the entire path is returned. 110 * Otherwise NULL is returned. 111 * 112 * Dir_FindHereOrAbove Search for a path in the current directory and 113 * then all the directories above it in turn until 114 * the path is found or we reach the root ("/"). 115 * 116 * Dir_MTime Return the modification time of a node. The file 117 * is searched for along the default search path. 118 * The path and mtime fields of the node are filled 119 * in. 120 * 121 * Dir_AddDir Add a directory to a search path. 122 * 123 * Dir_MakeFlags Given a search path and a command flag, create 124 * a string with each of the directories in the path 125 * preceded by the command flag and all of them 126 * separated by a space. 127 * 128 * Dir_Destroy Destroy an element of a search path. Frees up all 129 * things that can be freed for the element as long 130 * as the element is no longer referenced by any other 131 * search path. 132 * Dir_ClearPath Resets a search path to the empty list. 133 * 134 * For debugging: 135 * Dir_PrintDirectories Print stats about the directory cache. 136 */ 137 138 #include <sys/types.h> 139 #include <sys/stat.h> 140 141 #include <dirent.h> 142 #include <errno.h> 143 #include <stdio.h> 144 145 #include "make.h" 146 #include "hash.h" 147 #include "dir.h" 148 #include "job.h" 149 150 /* 151 * A search path consists of a Lst of Path structures. A Path structure 152 * has in it the name of the directory and a hash table of all the files 153 * in the directory. This is used to cut down on the number of system 154 * calls necessary to find implicit dependents and their like. Since 155 * these searches are made before any actions are taken, we need not 156 * worry about the directory changing due to creation commands. If this 157 * hampers the style of some makefiles, they must be changed. 158 * 159 * A list of all previously-read directories is kept in the 160 * openDirectories Lst. This list is checked first before a directory 161 * is opened. 162 * 163 * The need for the caching of whole directories is brought about by 164 * the multi-level transformation code in suff.c, which tends to search 165 * for far more files than regular make does. In the initial 166 * implementation, the amount of time spent performing "stat" calls was 167 * truly astronomical. The problem with hashing at the start is, 168 * of course, that pmake doesn't then detect changes to these directories 169 * during the course of the make. Three possibilities suggest themselves: 170 * 171 * 1) just use stat to test for a file's existence. As mentioned 172 * above, this is very inefficient due to the number of checks 173 * engendered by the multi-level transformation code. 174 * 2) use readdir() and company to search the directories, keeping 175 * them open between checks. I have tried this and while it 176 * didn't slow down the process too much, it could severely 177 * affect the amount of parallelism available as each directory 178 * open would take another file descriptor out of play for 179 * handling I/O for another job. Given that it is only recently 180 * that UNIX OS's have taken to allowing more than 20 or 32 181 * file descriptors for a process, this doesn't seem acceptable 182 * to me. 183 * 3) record the mtime of the directory in the Path structure and 184 * verify the directory hasn't changed since the contents were 185 * hashed. This will catch the creation or deletion of files, 186 * but not the updating of files. However, since it is the 187 * creation and deletion that is the problem, this could be 188 * a good thing to do. Unfortunately, if the directory (say ".") 189 * were fairly large and changed fairly frequently, the constant 190 * rehashing could seriously degrade performance. It might be 191 * good in such cases to keep track of the number of rehashes 192 * and if the number goes over a (small) limit, resort to using 193 * stat in its place. 194 * 195 * An additional thing to consider is that pmake is used primarily 196 * to create C programs and until recently pcc-based compilers refused 197 * to allow you to specify where the resulting object file should be 198 * placed. This forced all objects to be created in the current 199 * directory. This isn't meant as a full excuse, just an explanation of 200 * some of the reasons for the caching used here. 201 * 202 * One more note: the location of a target's file is only performed 203 * on the downward traversal of the graph and then only for terminal 204 * nodes in the graph. This could be construed as wrong in some cases, 205 * but prevents inadvertent modification of files when the "installed" 206 * directory for a file is provided in the search path. 207 * 208 * Another data structure maintained by this module is an mtime 209 * cache used when the searching of cached directories fails to find 210 * a file. In the past, Dir_FindFile would simply perform an access() 211 * call in such a case to determine if the file could be found using 212 * just the name given. When this hit, however, all that was gained 213 * was the knowledge that the file existed. Given that an access() is 214 * essentially a stat() without the copyout() call, and that the same 215 * filesystem overhead would have to be incurred in Dir_MTime, it made 216 * sense to replace the access() with a stat() and record the mtime 217 * in a cache for when Dir_MTime was actually called. 218 */ 219 220 Lst dirSearchPath; /* main search path */ 221 222 static Lst openDirectories; /* the list of all open directories */ 223 224 /* 225 * Variables for gathering statistics on the efficiency of the hashing 226 * mechanism. 227 */ 228 static int hits, /* Found in directory cache */ 229 misses, /* Sad, but not evil misses */ 230 nearmisses, /* Found under search path */ 231 bigmisses; /* Sought by itself */ 232 233 static Path *dot; /* contents of current directory */ 234 static Path *cur; /* contents of current directory, if not dot */ 235 static Path *dotLast; /* a fake path entry indicating we need to 236 * look for . last */ 237 static Hash_Table mtimes; /* Results of doing a last-resort stat in 238 * Dir_FindFile -- if we have to go to the 239 * system to find the file, we might as well 240 * have its mtime on record. XXX: If this is done 241 * way early, there's a chance other rules will 242 * have already updated the file, in which case 243 * we'll update it again. Generally, there won't 244 * be two rules to update a single file, so this 245 * should be ok, but... */ 246 247 248 static int DirFindName(const void *, const void *); 249 static int DirMatchFiles(const char *, Path *, Lst); 250 static void DirExpandCurly(const char *, const char *, Lst, Lst); 251 static void DirExpandInt(const char *, Lst, Lst); 252 static int DirPrintWord(void *, void *); 253 static int DirPrintDir(void *, void *); 254 static char *DirLookup(Path *, const char *, const char *, Boolean); 255 static char *DirLookupSubdir(Path *, const char *); 256 static char *DirFindDot(Boolean, const char *, const char *); 257 static char *DirLookupAbs(Path *, const char *, const char *); 258 259 /*- 260 *----------------------------------------------------------------------- 261 * Dir_Init -- 262 * initialize things for this module 263 * 264 * Results: 265 * none 266 * 267 * Side Effects: 268 * some directories may be opened. 269 *----------------------------------------------------------------------- 270 */ 271 void 272 Dir_Init(const char *cdname) 273 { 274 dirSearchPath = Lst_Init(FALSE); 275 openDirectories = Lst_Init(FALSE); 276 Hash_InitTable(&mtimes, 0); 277 278 Dir_InitCur(cdname); 279 280 dotLast = bmake_malloc(sizeof(Path)); 281 dotLast->refCount = 1; 282 dotLast->hits = 0; 283 dotLast->name = bmake_strdup(".DOTLAST"); 284 Hash_InitTable(&dotLast->files, -1); 285 } 286 287 /* 288 * Called by Dir_Init() and whenever .CURDIR is assigned to. 289 */ 290 void 291 Dir_InitCur(const char *cdname) 292 { 293 Path *p; 294 295 if (cdname != NULL) { 296 /* 297 * Our build directory is not the same as our source directory. 298 * Keep this one around too. 299 */ 300 if ((p = Dir_AddDir(NULL, cdname))) { 301 p->refCount += 1; 302 if (cur && cur != p) { 303 /* 304 * We've been here before, cleanup. 305 */ 306 cur->refCount -= 1; 307 Dir_Destroy(cur); 308 } 309 cur = p; 310 } 311 } 312 } 313 314 /*- 315 *----------------------------------------------------------------------- 316 * Dir_InitDot -- 317 * (re)initialize "dot" (current/object directory) path hash 318 * 319 * Results: 320 * none 321 * 322 * Side Effects: 323 * some directories may be opened. 324 *----------------------------------------------------------------------- 325 */ 326 void 327 Dir_InitDot(void) 328 { 329 if (dot != NULL) { 330 LstNode ln; 331 332 /* Remove old entry from openDirectories, but do not destroy. */ 333 ln = Lst_Member(openDirectories, dot); 334 (void)Lst_Remove(openDirectories, ln); 335 } 336 337 dot = Dir_AddDir(NULL, "."); 338 339 if (dot == NULL) { 340 Error("Cannot open `.' (%s)", strerror(errno)); 341 exit(1); 342 } 343 344 /* 345 * We always need to have dot around, so we increment its reference count 346 * to make sure it's not destroyed. 347 */ 348 dot->refCount += 1; 349 Dir_SetPATH(); /* initialize */ 350 } 351 352 /*- 353 *----------------------------------------------------------------------- 354 * Dir_End -- 355 * cleanup things for this module 356 * 357 * Results: 358 * none 359 * 360 * Side Effects: 361 * none 362 *----------------------------------------------------------------------- 363 */ 364 void 365 Dir_End(void) 366 { 367 #ifdef CLEANUP 368 if (cur) { 369 cur->refCount -= 1; 370 Dir_Destroy(cur); 371 } 372 dot->refCount -= 1; 373 dotLast->refCount -= 1; 374 Dir_Destroy(dotLast); 375 Dir_Destroy(dot); 376 Dir_ClearPath(dirSearchPath); 377 Lst_Destroy(dirSearchPath, NULL); 378 Dir_ClearPath(openDirectories); 379 Lst_Destroy(openDirectories, NULL); 380 Hash_DeleteTable(&mtimes); 381 #endif 382 } 383 384 /* 385 * We want ${.PATH} to indicate the order in which we will actually 386 * search, so we rebuild it after any .PATH: target. 387 * This is the simplest way to deal with the effect of .DOTLAST. 388 */ 389 void 390 Dir_SetPATH(void) 391 { 392 LstNode ln; /* a list element */ 393 Path *p; 394 Boolean hasLastDot = FALSE; /* true we should search dot last */ 395 396 Var_Delete(".PATH", VAR_GLOBAL); 397 398 if (Lst_Open(dirSearchPath) == SUCCESS) { 399 if ((ln = Lst_First(dirSearchPath)) != NULL) { 400 p = (Path *)Lst_Datum(ln); 401 if (p == dotLast) { 402 hasLastDot = TRUE; 403 Var_Append(".PATH", dotLast->name, VAR_GLOBAL); 404 } 405 } 406 407 if (!hasLastDot) { 408 if (dot) 409 Var_Append(".PATH", dot->name, VAR_GLOBAL); 410 if (cur) 411 Var_Append(".PATH", cur->name, VAR_GLOBAL); 412 } 413 414 while ((ln = Lst_Next(dirSearchPath)) != NULL) { 415 p = (Path *)Lst_Datum(ln); 416 if (p == dotLast) 417 continue; 418 if (p == dot && hasLastDot) 419 continue; 420 Var_Append(".PATH", p->name, VAR_GLOBAL); 421 } 422 423 if (hasLastDot) { 424 if (dot) 425 Var_Append(".PATH", dot->name, VAR_GLOBAL); 426 if (cur) 427 Var_Append(".PATH", cur->name, VAR_GLOBAL); 428 } 429 Lst_Close(dirSearchPath); 430 } 431 } 432 433 /*- 434 *----------------------------------------------------------------------- 435 * DirFindName -- 436 * See if the Path structure describes the same directory as the 437 * given one by comparing their names. Called from Dir_AddDir via 438 * Lst_Find when searching the list of open directories. 439 * 440 * Input: 441 * p Current name 442 * dname Desired name 443 * 444 * Results: 445 * 0 if it is the same. Non-zero otherwise 446 * 447 * Side Effects: 448 * None 449 *----------------------------------------------------------------------- 450 */ 451 static int 452 DirFindName(const void *p, const void *dname) 453 { 454 return (strcmp(((const Path *)p)->name, dname)); 455 } 456 457 /*- 458 *----------------------------------------------------------------------- 459 * Dir_HasWildcards -- 460 * see if the given name has any wildcard characters in it 461 * be careful not to expand unmatching brackets or braces. 462 * XXX: This code is not 100% correct. ([^]] fails etc.) 463 * I really don't think that make(1) should be expanding 464 * patterns, because then you have to set a mechanism for 465 * escaping the expansion! 466 * 467 * Input: 468 * name name to check 469 * 470 * Results: 471 * returns TRUE if the word should be expanded, FALSE otherwise 472 * 473 * Side Effects: 474 * none 475 *----------------------------------------------------------------------- 476 */ 477 Boolean 478 Dir_HasWildcards(char *name) 479 { 480 char *cp; 481 int wild = 0, brace = 0, bracket = 0; 482 483 for (cp = name; *cp; cp++) { 484 switch(*cp) { 485 case '{': 486 brace++; 487 wild = 1; 488 break; 489 case '}': 490 brace--; 491 break; 492 case '[': 493 bracket++; 494 wild = 1; 495 break; 496 case ']': 497 bracket--; 498 break; 499 case '?': 500 case '*': 501 wild = 1; 502 break; 503 default: 504 break; 505 } 506 } 507 return wild && bracket == 0 && brace == 0; 508 } 509 510 /*- 511 *----------------------------------------------------------------------- 512 * DirMatchFiles -- 513 * Given a pattern and a Path structure, see if any files 514 * match the pattern and add their names to the 'expansions' list if 515 * any do. This is incomplete -- it doesn't take care of patterns like 516 * src / *src / *.c properly (just *.c on any of the directories), but it 517 * will do for now. 518 * 519 * Input: 520 * pattern Pattern to look for 521 * p Directory to search 522 * expansion Place to store the results 523 * 524 * Results: 525 * Always returns 0 526 * 527 * Side Effects: 528 * File names are added to the expansions lst. The directory will be 529 * fully hashed when this is done. 530 *----------------------------------------------------------------------- 531 */ 532 static int 533 DirMatchFiles(const char *pattern, Path *p, Lst expansions) 534 { 535 Hash_Search search; /* Index into the directory's table */ 536 Hash_Entry *entry; /* Current entry in the table */ 537 Boolean isDot; /* TRUE if the directory being searched is . */ 538 539 isDot = (*p->name == '.' && p->name[1] == '\0'); 540 541 for (entry = Hash_EnumFirst(&p->files, &search); 542 entry != NULL; 543 entry = Hash_EnumNext(&search)) 544 { 545 /* 546 * See if the file matches the given pattern. Note we follow the UNIX 547 * convention that dot files will only be found if the pattern 548 * begins with a dot (note also that as a side effect of the hashing 549 * scheme, .* won't match . or .. since they aren't hashed). 550 */ 551 if (Str_Match(entry->name, pattern) && 552 ((entry->name[0] != '.') || 553 (pattern[0] == '.'))) 554 { 555 (void)Lst_AtEnd(expansions, 556 (isDot ? bmake_strdup(entry->name) : 557 str_concat(p->name, entry->name, 558 STR_ADDSLASH))); 559 } 560 } 561 return (0); 562 } 563 564 /*- 565 *----------------------------------------------------------------------- 566 * DirExpandCurly -- 567 * Expand curly braces like the C shell. Does this recursively. 568 * Note the special case: if after the piece of the curly brace is 569 * done there are no wildcard characters in the result, the result is 570 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. 571 * 572 * Input: 573 * word Entire word to expand 574 * brace First curly brace in it 575 * path Search path to use 576 * expansions Place to store the expansions 577 * 578 * Results: 579 * None. 580 * 581 * Side Effects: 582 * The given list is filled with the expansions... 583 * 584 *----------------------------------------------------------------------- 585 */ 586 static void 587 DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) 588 { 589 const char *end; /* Character after the closing brace */ 590 const char *cp; /* Current position in brace clause */ 591 const char *start; /* Start of current piece of brace clause */ 592 int bracelevel; /* Number of braces we've seen. If we see a 593 * right brace when this is 0, we've hit the 594 * end of the clause. */ 595 char *file; /* Current expansion */ 596 int otherLen; /* The length of the other pieces of the 597 * expansion (chars before and after the 598 * clause in 'word') */ 599 char *cp2; /* Pointer for checking for wildcards in 600 * expansion before calling Dir_Expand */ 601 602 start = brace+1; 603 604 /* 605 * Find the end of the brace clause first, being wary of nested brace 606 * clauses. 607 */ 608 for (end = start, bracelevel = 0; *end != '\0'; end++) { 609 if (*end == '{') { 610 bracelevel++; 611 } else if ((*end == '}') && (bracelevel-- == 0)) { 612 break; 613 } 614 } 615 if (*end == '\0') { 616 Error("Unterminated {} clause \"%s\"", start); 617 return; 618 } else { 619 end++; 620 } 621 otherLen = brace - word + strlen(end); 622 623 for (cp = start; cp < end; cp++) { 624 /* 625 * Find the end of this piece of the clause. 626 */ 627 bracelevel = 0; 628 while (*cp != ',') { 629 if (*cp == '{') { 630 bracelevel++; 631 } else if ((*cp == '}') && (bracelevel-- <= 0)) { 632 break; 633 } 634 cp++; 635 } 636 /* 637 * Allocate room for the combination and install the three pieces. 638 */ 639 file = bmake_malloc(otherLen + cp - start + 1); 640 if (brace != word) { 641 strncpy(file, word, brace-word); 642 } 643 if (cp != start) { 644 strncpy(&file[brace-word], start, cp-start); 645 } 646 strcpy(&file[(brace-word)+(cp-start)], end); 647 648 /* 649 * See if the result has any wildcards in it. If we find one, call 650 * Dir_Expand right away, telling it to place the result on our list 651 * of expansions. 652 */ 653 for (cp2 = file; *cp2 != '\0'; cp2++) { 654 switch(*cp2) { 655 case '*': 656 case '?': 657 case '{': 658 case '[': 659 Dir_Expand(file, path, expansions); 660 goto next; 661 } 662 } 663 if (*cp2 == '\0') { 664 /* 665 * Hit the end w/o finding any wildcards, so stick the expansion 666 * on the end of the list. 667 */ 668 (void)Lst_AtEnd(expansions, file); 669 } else { 670 next: 671 free(file); 672 } 673 start = cp+1; 674 } 675 } 676 677 678 /*- 679 *----------------------------------------------------------------------- 680 * DirExpandInt -- 681 * Internal expand routine. Passes through the directories in the 682 * path one by one, calling DirMatchFiles for each. NOTE: This still 683 * doesn't handle patterns in directories... 684 * 685 * Input: 686 * word Word to expand 687 * path Path on which to look 688 * expansions Place to store the result 689 * 690 * Results: 691 * None. 692 * 693 * Side Effects: 694 * Things are added to the expansions list. 695 * 696 *----------------------------------------------------------------------- 697 */ 698 static void 699 DirExpandInt(const char *word, Lst path, Lst expansions) 700 { 701 LstNode ln; /* Current node */ 702 Path *p; /* Directory in the node */ 703 704 if (Lst_Open(path) == SUCCESS) { 705 while ((ln = Lst_Next(path)) != NULL) { 706 p = (Path *)Lst_Datum(ln); 707 DirMatchFiles(word, p, expansions); 708 } 709 Lst_Close(path); 710 } 711 } 712 713 /*- 714 *----------------------------------------------------------------------- 715 * DirPrintWord -- 716 * Print a word in the list of expansions. Callback for Dir_Expand 717 * when DEBUG(DIR), via Lst_ForEach. 718 * 719 * Results: 720 * === 0 721 * 722 * Side Effects: 723 * The passed word is printed, followed by a space. 724 * 725 *----------------------------------------------------------------------- 726 */ 727 static int 728 DirPrintWord(void *word, void *dummy) 729 { 730 fprintf(debug_file, "%s ", (char *)word); 731 732 return(dummy ? 0 : 0); 733 } 734 735 /*- 736 *----------------------------------------------------------------------- 737 * Dir_Expand -- 738 * Expand the given word into a list of words by globbing it looking 739 * in the directories on the given search path. 740 * 741 * Input: 742 * word the word to expand 743 * path the list of directories in which to find the 744 * resulting files 745 * expansions the list on which to place the results 746 * 747 * Results: 748 * A list of words consisting of the files which exist along the search 749 * path matching the given pattern. 750 * 751 * Side Effects: 752 * Directories may be opened. Who knows? 753 *----------------------------------------------------------------------- 754 */ 755 void 756 Dir_Expand(const char *word, Lst path, Lst expansions) 757 { 758 const char *cp; 759 760 if (DEBUG(DIR)) { 761 fprintf(debug_file, "Expanding \"%s\"... ", word); 762 } 763 764 cp = strchr(word, '{'); 765 if (cp) { 766 DirExpandCurly(word, cp, path, expansions); 767 } else { 768 cp = strchr(word, '/'); 769 if (cp) { 770 /* 771 * The thing has a directory component -- find the first wildcard 772 * in the string. 773 */ 774 for (cp = word; *cp; cp++) { 775 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { 776 break; 777 } 778 } 779 if (*cp == '{') { 780 /* 781 * This one will be fun. 782 */ 783 DirExpandCurly(word, cp, path, expansions); 784 return; 785 } else if (*cp != '\0') { 786 /* 787 * Back up to the start of the component 788 */ 789 char *dirpath; 790 791 while (cp > word && *cp != '/') { 792 cp--; 793 } 794 if (cp != word) { 795 char sc; 796 /* 797 * If the glob isn't in the first component, try and find 798 * all the components up to the one with a wildcard. 799 */ 800 sc = cp[1]; 801 ((char *)UNCONST(cp))[1] = '\0'; 802 dirpath = Dir_FindFile(word, path); 803 ((char *)UNCONST(cp))[1] = sc; 804 /* 805 * dirpath is null if can't find the leading component 806 * XXX: Dir_FindFile won't find internal components. 807 * i.e. if the path contains ../Etc/Object and we're 808 * looking for Etc, it won't be found. Ah well. 809 * Probably not important. 810 */ 811 if (dirpath != NULL) { 812 char *dp = &dirpath[strlen(dirpath) - 1]; 813 if (*dp == '/') 814 *dp = '\0'; 815 path = Lst_Init(FALSE); 816 (void)Dir_AddDir(path, dirpath); 817 DirExpandInt(cp+1, path, expansions); 818 Lst_Destroy(path, NULL); 819 } 820 } else { 821 /* 822 * Start the search from the local directory 823 */ 824 DirExpandInt(word, path, expansions); 825 } 826 } else { 827 /* 828 * Return the file -- this should never happen. 829 */ 830 DirExpandInt(word, path, expansions); 831 } 832 } else { 833 /* 834 * First the files in dot 835 */ 836 DirMatchFiles(word, dot, expansions); 837 838 /* 839 * Then the files in every other directory on the path. 840 */ 841 DirExpandInt(word, path, expansions); 842 } 843 } 844 if (DEBUG(DIR)) { 845 Lst_ForEach(expansions, DirPrintWord, NULL); 846 fprintf(debug_file, "\n"); 847 } 848 } 849 850 /*- 851 *----------------------------------------------------------------------- 852 * DirLookup -- 853 * Find if the file with the given name exists in the given path. 854 * 855 * Results: 856 * The path to the file or NULL. This path is guaranteed to be in a 857 * different part of memory than name and so may be safely free'd. 858 * 859 * Side Effects: 860 * None. 861 *----------------------------------------------------------------------- 862 */ 863 static char * 864 DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, 865 Boolean hasSlash MAKE_ATTR_UNUSED) 866 { 867 char *file; /* the current filename to check */ 868 869 if (DEBUG(DIR)) { 870 fprintf(debug_file, " %s ...\n", p->name); 871 } 872 873 if (Hash_FindEntry(&p->files, cp) == NULL) 874 return NULL; 875 876 file = str_concat(p->name, cp, STR_ADDSLASH); 877 if (DEBUG(DIR)) { 878 fprintf(debug_file, " returning %s\n", file); 879 } 880 p->hits += 1; 881 hits += 1; 882 return file; 883 } 884 885 886 /*- 887 *----------------------------------------------------------------------- 888 * DirLookupSubdir -- 889 * Find if the file with the given name exists in the given path. 890 * 891 * Results: 892 * The path to the file or NULL. This path is guaranteed to be in a 893 * different part of memory than name and so may be safely free'd. 894 * 895 * Side Effects: 896 * If the file is found, it is added in the modification times hash 897 * table. 898 *----------------------------------------------------------------------- 899 */ 900 static char * 901 DirLookupSubdir(Path *p, const char *name) 902 { 903 struct stat stb; /* Buffer for stat, if necessary */ 904 Hash_Entry *entry; /* Entry for mtimes table */ 905 char *file; /* the current filename to check */ 906 907 if (p != dot) { 908 file = str_concat(p->name, name, STR_ADDSLASH); 909 } else { 910 /* 911 * Checking in dot -- DON'T put a leading ./ on the thing. 912 */ 913 file = bmake_strdup(name); 914 } 915 916 if (DEBUG(DIR)) { 917 fprintf(debug_file, "checking %s ...\n", file); 918 } 919 920 if (stat(file, &stb) == 0) { 921 if (stb.st_mtime == 0) 922 stb.st_mtime = 1; 923 /* 924 * Save the modification time so if it's needed, we don't have 925 * to fetch it again. 926 */ 927 if (DEBUG(DIR)) { 928 fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), 929 file); 930 } 931 entry = Hash_CreateEntry(&mtimes, file, NULL); 932 Hash_SetTimeValue(entry, stb.st_mtime); 933 nearmisses += 1; 934 return (file); 935 } 936 free(file); 937 return NULL; 938 } 939 940 /*- 941 *----------------------------------------------------------------------- 942 * DirLookupAbs -- 943 * Find if the file with the given name exists in the given path. 944 * 945 * Results: 946 * The path to the file, the empty string or NULL. If the file is 947 * the empty string, the search should be terminated. 948 * This path is guaranteed to be in a different part of memory 949 * than name and so may be safely free'd. 950 * 951 * Side Effects: 952 * None. 953 *----------------------------------------------------------------------- 954 */ 955 static char * 956 DirLookupAbs(Path *p, const char *name, const char *cp) 957 { 958 char *p1; /* pointer into p->name */ 959 const char *p2; /* pointer into name */ 960 961 if (DEBUG(DIR)) { 962 fprintf(debug_file, " %s ...\n", p->name); 963 } 964 965 /* 966 * If the file has a leading path component and that component 967 * exactly matches the entire name of the current search 968 * directory, we can attempt another cache lookup. And if we don't 969 * have a hit, we can safely assume the file does not exist at all. 970 */ 971 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { 972 continue; 973 } 974 if (*p1 != '\0' || p2 != cp - 1) { 975 return NULL; 976 } 977 978 if (Hash_FindEntry(&p->files, cp) == NULL) { 979 if (DEBUG(DIR)) { 980 fprintf(debug_file, " must be here but isn't -- returning\n"); 981 } 982 /* Return empty string: terminates search */ 983 return bmake_strdup(""); 984 } 985 986 p->hits += 1; 987 hits += 1; 988 if (DEBUG(DIR)) { 989 fprintf(debug_file, " returning %s\n", name); 990 } 991 return (bmake_strdup(name)); 992 } 993 994 /*- 995 *----------------------------------------------------------------------- 996 * DirFindDot -- 997 * Find the file given on "." or curdir 998 * 999 * Results: 1000 * The path to the file or NULL. This path is guaranteed to be in a 1001 * different part of memory than name and so may be safely free'd. 1002 * 1003 * Side Effects: 1004 * Hit counts change 1005 *----------------------------------------------------------------------- 1006 */ 1007 static char * 1008 DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) 1009 { 1010 1011 if (Hash_FindEntry(&dot->files, cp) != NULL) { 1012 if (DEBUG(DIR)) { 1013 fprintf(debug_file, " in '.'\n"); 1014 } 1015 hits += 1; 1016 dot->hits += 1; 1017 return (bmake_strdup(name)); 1018 } 1019 if (cur && 1020 Hash_FindEntry(&cur->files, cp) != NULL) { 1021 if (DEBUG(DIR)) { 1022 fprintf(debug_file, " in ${.CURDIR} = %s\n", cur->name); 1023 } 1024 hits += 1; 1025 cur->hits += 1; 1026 return str_concat(cur->name, cp, STR_ADDSLASH); 1027 } 1028 1029 return NULL; 1030 } 1031 1032 /*- 1033 *----------------------------------------------------------------------- 1034 * Dir_FindFile -- 1035 * Find the file with the given name along the given search path. 1036 * 1037 * Input: 1038 * name the file to find 1039 * path the Lst of directories to search 1040 * 1041 * Results: 1042 * The path to the file or NULL. This path is guaranteed to be in a 1043 * different part of memory than name and so may be safely free'd. 1044 * 1045 * Side Effects: 1046 * If the file is found in a directory which is not on the path 1047 * already (either 'name' is absolute or it is a relative path 1048 * [ dir1/.../dirn/file ] which exists below one of the directories 1049 * already on the search path), its directory is added to the end 1050 * of the path on the assumption that there will be more files in 1051 * that directory later on. Sometimes this is true. Sometimes not. 1052 *----------------------------------------------------------------------- 1053 */ 1054 char * 1055 Dir_FindFile(const char *name, Lst path) 1056 { 1057 LstNode ln; /* a list element */ 1058 char *file; /* the current filename to check */ 1059 Path *p; /* current path member */ 1060 const char *cp; /* Terminal name of file */ 1061 Boolean hasLastDot = FALSE; /* true we should search dot last */ 1062 Boolean hasSlash; /* true if 'name' contains a / */ 1063 struct stat stb; /* Buffer for stat, if necessary */ 1064 Hash_Entry *entry; /* Entry for mtimes table */ 1065 const char *trailing_dot = "."; 1066 1067 /* 1068 * Find the final component of the name and note whether it has a 1069 * slash in it (the name, I mean) 1070 */ 1071 cp = strrchr(name, '/'); 1072 if (cp) { 1073 hasSlash = TRUE; 1074 cp += 1; 1075 } else { 1076 hasSlash = FALSE; 1077 cp = name; 1078 } 1079 1080 if (DEBUG(DIR)) { 1081 fprintf(debug_file, "Searching for %s ...", name); 1082 } 1083 1084 if (Lst_Open(path) == FAILURE) { 1085 if (DEBUG(DIR)) { 1086 fprintf(debug_file, "couldn't open path, file not found\n"); 1087 } 1088 misses += 1; 1089 return NULL; 1090 } 1091 1092 if ((ln = Lst_First(path)) != NULL) { 1093 p = (Path *)Lst_Datum(ln); 1094 if (p == dotLast) { 1095 hasLastDot = TRUE; 1096 if (DEBUG(DIR)) 1097 fprintf(debug_file, "[dot last]..."); 1098 } 1099 } 1100 if (DEBUG(DIR)) { 1101 fprintf(debug_file, "\n"); 1102 } 1103 1104 /* 1105 * If there's no leading directory components or if the leading 1106 * directory component is exactly `./', consult the cached contents 1107 * of each of the directories on the search path. 1108 */ 1109 if (!hasSlash || (cp - name == 2 && *name == '.')) { 1110 /* 1111 * We look through all the directories on the path seeking one which 1112 * contains the final component of the given name. If such a beast 1113 * is found, we concatenate the directory name and the final 1114 * component and return the resulting string. If we don't find any 1115 * such thing, we go on to phase two... 1116 * 1117 * No matter what, we always look for the file in the current 1118 * directory before anywhere else (unless we found the magic 1119 * DOTLAST path, in which case we search it last) and we *do not* 1120 * add the ./ to it if it exists. 1121 * This is so there are no conflicts between what the user 1122 * specifies (fish.c) and what pmake finds (./fish.c). 1123 */ 1124 if (!hasLastDot && 1125 (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1126 Lst_Close(path); 1127 return file; 1128 } 1129 1130 while ((ln = Lst_Next(path)) != NULL) { 1131 p = (Path *)Lst_Datum(ln); 1132 if (p == dotLast) 1133 continue; 1134 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { 1135 Lst_Close(path); 1136 return file; 1137 } 1138 } 1139 1140 if (hasLastDot && 1141 (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1142 Lst_Close(path); 1143 return file; 1144 } 1145 } 1146 Lst_Close(path); 1147 1148 /* 1149 * We didn't find the file on any directory in the search path. 1150 * If the name doesn't contain a slash, that means it doesn't exist. 1151 * If it *does* contain a slash, however, there is still hope: it 1152 * could be in a subdirectory of one of the members of the search 1153 * path. (eg. /usr/include and sys/types.h. The above search would 1154 * fail to turn up types.h in /usr/include, but it *is* in 1155 * /usr/include/sys/types.h). 1156 * [ This no longer applies: If we find such a beast, we assume there 1157 * will be more (what else can we assume?) and add all but the last 1158 * component of the resulting name onto the search path (at the 1159 * end).] 1160 * This phase is only performed if the file is *not* absolute. 1161 */ 1162 if (!hasSlash) { 1163 if (DEBUG(DIR)) { 1164 fprintf(debug_file, " failed.\n"); 1165 } 1166 misses += 1; 1167 return NULL; 1168 } 1169 1170 if (*cp == '\0') { 1171 /* we were given a trailing "/" */ 1172 cp = trailing_dot; 1173 } 1174 1175 if (name[0] != '/') { 1176 Boolean checkedDot = FALSE; 1177 1178 if (DEBUG(DIR)) { 1179 fprintf(debug_file, " Trying subdirectories...\n"); 1180 } 1181 1182 if (!hasLastDot) { 1183 if (dot) { 1184 checkedDot = TRUE; 1185 if ((file = DirLookupSubdir(dot, name)) != NULL) 1186 return file; 1187 } 1188 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1189 return file; 1190 } 1191 1192 (void)Lst_Open(path); 1193 while ((ln = Lst_Next(path)) != NULL) { 1194 p = (Path *)Lst_Datum(ln); 1195 if (p == dotLast) 1196 continue; 1197 if (p == dot) { 1198 if (checkedDot) 1199 continue; 1200 checkedDot = TRUE; 1201 } 1202 if ((file = DirLookupSubdir(p, name)) != NULL) { 1203 Lst_Close(path); 1204 return file; 1205 } 1206 } 1207 Lst_Close(path); 1208 1209 if (hasLastDot) { 1210 if (dot && !checkedDot) { 1211 checkedDot = TRUE; 1212 if ((file = DirLookupSubdir(dot, name)) != NULL) 1213 return file; 1214 } 1215 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1216 return file; 1217 } 1218 1219 if (checkedDot) { 1220 /* 1221 * Already checked by the given name, since . was in the path, 1222 * so no point in proceeding... 1223 */ 1224 if (DEBUG(DIR)) { 1225 fprintf(debug_file, " Checked . already, returning NULL\n"); 1226 } 1227 return NULL; 1228 } 1229 1230 } else { /* name[0] == '/' */ 1231 1232 /* 1233 * For absolute names, compare directory path prefix against the 1234 * the directory path of each member on the search path for an exact 1235 * match. If we have an exact match on any member of the search path, 1236 * use the cached contents of that member to lookup the final file 1237 * component. If that lookup fails we can safely assume that the 1238 * file does not exist at all. This is signified by DirLookupAbs() 1239 * returning an empty string. 1240 */ 1241 if (DEBUG(DIR)) { 1242 fprintf(debug_file, " Trying exact path matches...\n"); 1243 } 1244 1245 if (!hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL) 1246 return *file?file:NULL; 1247 1248 (void)Lst_Open(path); 1249 while ((ln = Lst_Next(path)) != NULL) { 1250 p = (Path *)Lst_Datum(ln); 1251 if (p == dotLast) 1252 continue; 1253 if ((file = DirLookupAbs(p, name, cp)) != NULL) { 1254 Lst_Close(path); 1255 return *file?file:NULL; 1256 } 1257 } 1258 Lst_Close(path); 1259 1260 if (hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL) 1261 return *file?file:NULL; 1262 } 1263 1264 /* 1265 * Didn't find it that way, either. Sigh. Phase 3. Add its directory 1266 * onto the search path in any case, just in case, then look for the 1267 * thing in the hash table. If we find it, grand. We return a new 1268 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh. 1269 * Note that if the directory holding the file doesn't exist, this will 1270 * do an extra search of the final directory on the path. Unless something 1271 * weird happens, this search won't succeed and life will be groovy. 1272 * 1273 * Sigh. We cannot add the directory onto the search path because 1274 * of this amusing case: 1275 * $(INSTALLDIR)/$(FILE): $(FILE) 1276 * 1277 * $(FILE) exists in $(INSTALLDIR) but not in the current one. 1278 * When searching for $(FILE), we will find it in $(INSTALLDIR) 1279 * b/c we added it here. This is not good... 1280 */ 1281 #ifdef notdef 1282 if (cp == traling_dot) { 1283 cp = strrchr(name, '/'); 1284 cp += 1; 1285 } 1286 cp[-1] = '\0'; 1287 (void)Dir_AddDir(path, name); 1288 cp[-1] = '/'; 1289 1290 bigmisses += 1; 1291 ln = Lst_Last(path); 1292 if (ln == NULL) { 1293 return NULL; 1294 } else { 1295 p = (Path *)Lst_Datum(ln); 1296 } 1297 1298 if (Hash_FindEntry(&p->files, cp) != NULL) { 1299 return (bmake_strdup(name)); 1300 } else { 1301 return NULL; 1302 } 1303 #else /* !notdef */ 1304 if (DEBUG(DIR)) { 1305 fprintf(debug_file, " Looking for \"%s\" ...\n", name); 1306 } 1307 1308 bigmisses += 1; 1309 entry = Hash_FindEntry(&mtimes, name); 1310 if (entry != NULL) { 1311 if (DEBUG(DIR)) { 1312 fprintf(debug_file, " got it (in mtime cache)\n"); 1313 } 1314 return(bmake_strdup(name)); 1315 } else if (stat(name, &stb) == 0) { 1316 if (stb.st_mtime == 0) 1317 stb.st_mtime = 1; 1318 entry = Hash_CreateEntry(&mtimes, name, NULL); 1319 if (DEBUG(DIR)) { 1320 fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), 1321 name); 1322 } 1323 Hash_SetTimeValue(entry, stb.st_mtime); 1324 return (bmake_strdup(name)); 1325 } else { 1326 if (DEBUG(DIR)) { 1327 fprintf(debug_file, " failed. Returning NULL\n"); 1328 } 1329 return NULL; 1330 } 1331 #endif /* notdef */ 1332 } 1333 1334 1335 /*- 1336 *----------------------------------------------------------------------- 1337 * Dir_FindHereOrAbove -- 1338 * search for a path starting at a given directory and then working 1339 * our way up towards the root. 1340 * 1341 * Input: 1342 * here starting directory 1343 * search_path the path we are looking for 1344 * result the result of a successful search is placed here 1345 * rlen the length of the result buffer 1346 * (typically MAXPATHLEN + 1) 1347 * 1348 * Results: 1349 * 0 on failure, 1 on success [in which case the found path is put 1350 * in the result buffer]. 1351 * 1352 * Side Effects: 1353 *----------------------------------------------------------------------- 1354 */ 1355 int 1356 Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) { 1357 1358 struct stat st; 1359 char dirbase[MAXPATHLEN + 1], *db_end; 1360 char try[MAXPATHLEN + 1], *try_end; 1361 1362 /* copy out our starting point */ 1363 snprintf(dirbase, sizeof(dirbase), "%s", here); 1364 db_end = dirbase + strlen(dirbase); 1365 1366 /* loop until we determine a result */ 1367 while (1) { 1368 1369 /* try and stat(2) it ... */ 1370 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); 1371 if (stat(try, &st) != -1) { 1372 /* 1373 * success! if we found a file, chop off 1374 * the filename so we return a directory. 1375 */ 1376 if ((st.st_mode & S_IFMT) != S_IFDIR) { 1377 try_end = try + strlen(try); 1378 while (try_end > try && *try_end != '/') 1379 try_end--; 1380 if (try_end > try) 1381 *try_end = 0; /* chop! */ 1382 } 1383 1384 /* 1385 * done! 1386 */ 1387 snprintf(result, rlen, "%s", try); 1388 return(1); 1389 } 1390 1391 /* 1392 * nope, we didn't find it. if we used up dirbase we've 1393 * reached the root and failed. 1394 */ 1395 if (db_end == dirbase) 1396 break; /* failed! */ 1397 1398 /* 1399 * truncate dirbase from the end to move up a dir 1400 */ 1401 while (db_end > dirbase && *db_end != '/') 1402 db_end--; 1403 *db_end = 0; /* chop! */ 1404 1405 } /* while (1) */ 1406 1407 /* 1408 * we failed... 1409 */ 1410 return(0); 1411 } 1412 1413 /*- 1414 *----------------------------------------------------------------------- 1415 * Dir_MTime -- 1416 * Find the modification time of the file described by gn along the 1417 * search path dirSearchPath. 1418 * 1419 * Input: 1420 * gn the file whose modification time is desired 1421 * 1422 * Results: 1423 * The modification time or 0 if it doesn't exist 1424 * 1425 * Side Effects: 1426 * The modification time is placed in the node's mtime slot. 1427 * If the node didn't have a path entry before, and Dir_FindFile 1428 * found one for it, the full name is placed in the path slot. 1429 *----------------------------------------------------------------------- 1430 */ 1431 int 1432 Dir_MTime(GNode *gn, Boolean recheck) 1433 { 1434 char *fullName; /* the full pathname of name */ 1435 struct stat stb; /* buffer for finding the mod time */ 1436 Hash_Entry *entry; 1437 1438 if (gn->type & OP_ARCHV) { 1439 return Arch_MTime(gn); 1440 } else if (gn->type & OP_PHONY) { 1441 gn->mtime = 0; 1442 return 0; 1443 } else if (gn->path == NULL) { 1444 if (gn->type & OP_NOPATH) 1445 fullName = NULL; 1446 else { 1447 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); 1448 if (fullName == NULL && gn->flags & FROM_DEPEND && 1449 !Lst_IsEmpty(gn->iParents)) { 1450 char *cp; 1451 1452 cp = strrchr(gn->name, '/'); 1453 if (cp) { 1454 /* 1455 * This is an implied source, and it may have moved, 1456 * see if we can find it via the current .PATH 1457 */ 1458 cp++; 1459 1460 fullName = Dir_FindFile(cp, Suff_FindPath(gn)); 1461 if (fullName) { 1462 /* 1463 * Put the found file in gn->path 1464 * so that we give that to the compiler. 1465 */ 1466 gn->path = bmake_strdup(fullName); 1467 if (!Job_RunTarget(".STALE", gn->fname)) 1468 fprintf(stdout, 1469 "%s: %s, %d: ignoring stale %s for %s, " 1470 "found %s\n", progname, gn->fname, gn->lineno, 1471 makeDependfile, gn->name, fullName); 1472 } 1473 } 1474 } 1475 if (DEBUG(DIR)) 1476 fprintf(debug_file, "Found '%s' as '%s'\n", 1477 gn->name, fullName ? fullName : "(not found)" ); 1478 } 1479 } else { 1480 fullName = gn->path; 1481 } 1482 1483 if (fullName == NULL) { 1484 fullName = bmake_strdup(gn->name); 1485 } 1486 1487 if (!recheck) 1488 entry = Hash_FindEntry(&mtimes, fullName); 1489 else 1490 entry = NULL; 1491 if (entry != NULL) { 1492 if (DEBUG(DIR)) { 1493 fprintf(debug_file, "Using cached time %s for %s\n", 1494 Targ_FmtTime(Hash_GetTimeValue(entry)), fullName); 1495 } 1496 stb.st_mtime = Hash_GetTimeValue(entry); 1497 } else if (stat(fullName, &stb) < 0) { 1498 if (gn->type & OP_MEMBER) { 1499 if (fullName != gn->path) 1500 free(fullName); 1501 return Arch_MemMTime(gn); 1502 } else { 1503 stb.st_mtime = 0; 1504 } 1505 } else { 1506 if (stb.st_mtime == 0) { 1507 /* 1508 * 0 handled specially by the code, if the time is really 0, 1509 * return something else instead 1510 */ 1511 stb.st_mtime = 1; 1512 } 1513 entry = Hash_CreateEntry(&mtimes, fullName, NULL); 1514 Hash_SetTimeValue(entry, stb.st_mtime); 1515 } 1516 1517 if (fullName && gn->path == NULL) { 1518 gn->path = fullName; 1519 } 1520 1521 gn->mtime = stb.st_mtime; 1522 return (gn->mtime); 1523 } 1524 1525 /*- 1526 *----------------------------------------------------------------------- 1527 * Dir_AddDir -- 1528 * Add the given name to the end of the given path. The order of 1529 * the arguments is backwards so ParseDoDependency can do a 1530 * Lst_ForEach of its list of paths... 1531 * 1532 * Input: 1533 * path the path to which the directory should be 1534 * added 1535 * name the name of the directory to add 1536 * 1537 * Results: 1538 * none 1539 * 1540 * Side Effects: 1541 * A structure is added to the list and the directory is 1542 * read and hashed. 1543 *----------------------------------------------------------------------- 1544 */ 1545 Path * 1546 Dir_AddDir(Lst path, const char *name) 1547 { 1548 LstNode ln = NULL; /* node in case Path structure is found */ 1549 Path *p = NULL; /* pointer to new Path structure */ 1550 DIR *d; /* for reading directory */ 1551 struct dirent *dp; /* entry in directory */ 1552 1553 if (strcmp(name, ".DOTLAST") == 0) { 1554 ln = Lst_Find(path, name, DirFindName); 1555 if (ln != NULL) 1556 return (Path *)Lst_Datum(ln); 1557 else { 1558 dotLast->refCount += 1; 1559 (void)Lst_AtFront(path, dotLast); 1560 } 1561 } 1562 1563 if (path) 1564 ln = Lst_Find(openDirectories, name, DirFindName); 1565 if (ln != NULL) { 1566 p = (Path *)Lst_Datum(ln); 1567 if (path && Lst_Member(path, p) == NULL) { 1568 p->refCount += 1; 1569 (void)Lst_AtEnd(path, p); 1570 } 1571 } else { 1572 if (DEBUG(DIR)) { 1573 fprintf(debug_file, "Caching %s ...", name); 1574 } 1575 1576 if ((d = opendir(name)) != NULL) { 1577 p = bmake_malloc(sizeof(Path)); 1578 p->name = bmake_strdup(name); 1579 p->hits = 0; 1580 p->refCount = 1; 1581 Hash_InitTable(&p->files, -1); 1582 1583 while ((dp = readdir(d)) != NULL) { 1584 #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ 1585 /* 1586 * The sun directory library doesn't check for a 0 inode 1587 * (0-inode slots just take up space), so we have to do 1588 * it ourselves. 1589 */ 1590 if (dp->d_fileno == 0) { 1591 continue; 1592 } 1593 #endif /* sun && d_ino */ 1594 (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); 1595 } 1596 (void)closedir(d); 1597 (void)Lst_AtEnd(openDirectories, p); 1598 if (path != NULL) 1599 (void)Lst_AtEnd(path, p); 1600 } 1601 if (DEBUG(DIR)) { 1602 fprintf(debug_file, "done\n"); 1603 } 1604 } 1605 return p; 1606 } 1607 1608 /*- 1609 *----------------------------------------------------------------------- 1610 * Dir_CopyDir -- 1611 * Callback function for duplicating a search path via Lst_Duplicate. 1612 * Ups the reference count for the directory. 1613 * 1614 * Results: 1615 * Returns the Path it was given. 1616 * 1617 * Side Effects: 1618 * The refCount of the path is incremented. 1619 * 1620 *----------------------------------------------------------------------- 1621 */ 1622 void * 1623 Dir_CopyDir(void *p) 1624 { 1625 ((Path *)p)->refCount += 1; 1626 1627 return (p); 1628 } 1629 1630 /*- 1631 *----------------------------------------------------------------------- 1632 * Dir_MakeFlags -- 1633 * Make a string by taking all the directories in the given search 1634 * path and preceding them by the given flag. Used by the suffix 1635 * module to create variables for compilers based on suffix search 1636 * paths. 1637 * 1638 * Input: 1639 * flag flag which should precede each directory 1640 * path list of directories 1641 * 1642 * Results: 1643 * The string mentioned above. Note that there is no space between 1644 * the given flag and each directory. The empty string is returned if 1645 * Things don't go well. 1646 * 1647 * Side Effects: 1648 * None 1649 *----------------------------------------------------------------------- 1650 */ 1651 char * 1652 Dir_MakeFlags(const char *flag, Lst path) 1653 { 1654 char *str; /* the string which will be returned */ 1655 char *s1, *s2;/* the current directory preceded by 'flag' */ 1656 LstNode ln; /* the node of the current directory */ 1657 Path *p; /* the structure describing the current directory */ 1658 1659 str = bmake_strdup(""); 1660 1661 if (Lst_Open(path) == SUCCESS) { 1662 while ((ln = Lst_Next(path)) != NULL) { 1663 p = (Path *)Lst_Datum(ln); 1664 s2 = str_concat(flag, p->name, 0); 1665 str = str_concat(s1 = str, s2, STR_ADDSPACE); 1666 free(s1); 1667 free(s2); 1668 } 1669 Lst_Close(path); 1670 } 1671 1672 return (str); 1673 } 1674 1675 /*- 1676 *----------------------------------------------------------------------- 1677 * Dir_Destroy -- 1678 * Nuke a directory descriptor, if possible. Callback procedure 1679 * for the suffixes module when destroying a search path. 1680 * 1681 * Input: 1682 * pp The directory descriptor to nuke 1683 * 1684 * Results: 1685 * None. 1686 * 1687 * Side Effects: 1688 * If no other path references this directory (refCount == 0), 1689 * the Path and all its data are freed. 1690 * 1691 *----------------------------------------------------------------------- 1692 */ 1693 void 1694 Dir_Destroy(void *pp) 1695 { 1696 Path *p = (Path *)pp; 1697 p->refCount -= 1; 1698 1699 if (p->refCount == 0) { 1700 LstNode ln; 1701 1702 ln = Lst_Member(openDirectories, p); 1703 (void)Lst_Remove(openDirectories, ln); 1704 1705 Hash_DeleteTable(&p->files); 1706 free(p->name); 1707 free(p); 1708 } 1709 } 1710 1711 /*- 1712 *----------------------------------------------------------------------- 1713 * Dir_ClearPath -- 1714 * Clear out all elements of the given search path. This is different 1715 * from destroying the list, notice. 1716 * 1717 * Input: 1718 * path Path to clear 1719 * 1720 * Results: 1721 * None. 1722 * 1723 * Side Effects: 1724 * The path is set to the empty list. 1725 * 1726 *----------------------------------------------------------------------- 1727 */ 1728 void 1729 Dir_ClearPath(Lst path) 1730 { 1731 Path *p; 1732 while (!Lst_IsEmpty(path)) { 1733 p = (Path *)Lst_DeQueue(path); 1734 Dir_Destroy(p); 1735 } 1736 } 1737 1738 1739 /*- 1740 *----------------------------------------------------------------------- 1741 * Dir_Concat -- 1742 * Concatenate two paths, adding the second to the end of the first. 1743 * Makes sure to avoid duplicates. 1744 * 1745 * Input: 1746 * path1 Dest 1747 * path2 Source 1748 * 1749 * Results: 1750 * None 1751 * 1752 * Side Effects: 1753 * Reference counts for added dirs are upped. 1754 * 1755 *----------------------------------------------------------------------- 1756 */ 1757 void 1758 Dir_Concat(Lst path1, Lst path2) 1759 { 1760 LstNode ln; 1761 Path *p; 1762 1763 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) { 1764 p = (Path *)Lst_Datum(ln); 1765 if (Lst_Member(path1, p) == NULL) { 1766 p->refCount += 1; 1767 (void)Lst_AtEnd(path1, p); 1768 } 1769 } 1770 } 1771 1772 /********** DEBUG INFO **********/ 1773 void 1774 Dir_PrintDirectories(void) 1775 { 1776 LstNode ln; 1777 Path *p; 1778 1779 fprintf(debug_file, "#*** Directory Cache:\n"); 1780 fprintf(debug_file, "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", 1781 hits, misses, nearmisses, bigmisses, 1782 (hits+bigmisses+nearmisses ? 1783 hits * 100 / (hits + bigmisses + nearmisses) : 0)); 1784 fprintf(debug_file, "# %-20s referenced\thits\n", "directory"); 1785 if (Lst_Open(openDirectories) == SUCCESS) { 1786 while ((ln = Lst_Next(openDirectories)) != NULL) { 1787 p = (Path *)Lst_Datum(ln); 1788 fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); 1789 } 1790 Lst_Close(openDirectories); 1791 } 1792 } 1793 1794 static int 1795 DirPrintDir(void *p, void *dummy) 1796 { 1797 fprintf(debug_file, "%s ", ((Path *)p)->name); 1798 return (dummy ? 0 : 0); 1799 } 1800 1801 void 1802 Dir_PrintPath(Lst path) 1803 { 1804 Lst_ForEach(path, DirPrintDir, NULL); 1805 } 1806