1 /* $NetBSD: dir.c,v 1.68 2016/06/07 00:40:00 sjg 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.68 2016/06/07 00:40:00 sjg 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.68 2016/06/07 00:40:00 sjg 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 static Hash_Table lmtimes; /* same as mtimes but for lstat */ 248 249 static int DirFindName(const void *, const void *); 250 static int DirMatchFiles(const char *, Path *, Lst); 251 static void DirExpandCurly(const char *, const char *, Lst, Lst); 252 static void DirExpandInt(const char *, Lst, Lst); 253 static int DirPrintWord(void *, void *); 254 static int DirPrintDir(void *, void *); 255 static char *DirLookup(Path *, const char *, const char *, Boolean); 256 static char *DirLookupSubdir(Path *, const char *); 257 static char *DirFindDot(Boolean, const char *, const char *); 258 static char *DirLookupAbs(Path *, const char *, const char *); 259 260 261 /* 262 * We use stat(2) a lot, cache the results 263 * mtime and mode are all we care about. 264 */ 265 struct cache_st { 266 time_t mtime; 267 mode_t mode; 268 }; 269 270 /* minimize changes below */ 271 static time_t 272 Hash_GetTimeValue(Hash_Entry *entry) 273 { 274 struct cache_st *cst; 275 276 cst = entry->clientPtr; 277 return cst->mtime; 278 } 279 280 #define CST_LSTAT 1 281 #define CST_UPDATE 2 282 283 static int 284 cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, int flags) 285 { 286 Hash_Entry *entry; 287 struct cache_st *cst; 288 int rc; 289 290 if (!pathname || !pathname[0]) 291 return -1; 292 293 entry = Hash_FindEntry(htp, pathname); 294 295 if (entry && (flags & CST_UPDATE) == 0) { 296 cst = entry->clientPtr; 297 298 memset(st, 0, sizeof(*st)); 299 st->st_mtime = cst->mtime; 300 st->st_mode = cst->mode; 301 return 0; 302 } 303 304 rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st); 305 if (rc == -1) 306 return -1; 307 308 if (st->st_mtime == 0) 309 st->st_mtime = 1; /* avoid confusion with missing file */ 310 311 if (!entry) 312 entry = Hash_CreateEntry(htp, pathname, NULL); 313 if (!entry->clientPtr) 314 entry->clientPtr = bmake_malloc(sizeof(*cst)); 315 cst = entry->clientPtr; 316 cst->mtime = st->st_mtime; 317 cst->mode = st->st_mode; 318 319 return 0; 320 } 321 322 int 323 cached_stat(const char *pathname, void *st) 324 { 325 return cached_stats(&mtimes, pathname, st, 0); 326 } 327 328 int 329 cached_lstat(const char *pathname, void *st) 330 { 331 return cached_stats(&lmtimes, pathname, st, CST_LSTAT); 332 } 333 334 /*- 335 *----------------------------------------------------------------------- 336 * Dir_Init -- 337 * initialize things for this module 338 * 339 * Results: 340 * none 341 * 342 * Side Effects: 343 * some directories may be opened. 344 *----------------------------------------------------------------------- 345 */ 346 void 347 Dir_Init(const char *cdname) 348 { 349 dirSearchPath = Lst_Init(FALSE); 350 openDirectories = Lst_Init(FALSE); 351 Hash_InitTable(&mtimes, 0); 352 Hash_InitTable(&lmtimes, 0); 353 354 Dir_InitCur(cdname); 355 356 dotLast = bmake_malloc(sizeof(Path)); 357 dotLast->refCount = 1; 358 dotLast->hits = 0; 359 dotLast->name = bmake_strdup(".DOTLAST"); 360 Hash_InitTable(&dotLast->files, -1); 361 } 362 363 /* 364 * Called by Dir_Init() and whenever .CURDIR is assigned to. 365 */ 366 void 367 Dir_InitCur(const char *cdname) 368 { 369 Path *p; 370 371 if (cdname != NULL) { 372 /* 373 * Our build directory is not the same as our source directory. 374 * Keep this one around too. 375 */ 376 if ((p = Dir_AddDir(NULL, cdname))) { 377 p->refCount += 1; 378 if (cur && cur != p) { 379 /* 380 * We've been here before, cleanup. 381 */ 382 cur->refCount -= 1; 383 Dir_Destroy(cur); 384 } 385 cur = p; 386 } 387 } 388 } 389 390 /*- 391 *----------------------------------------------------------------------- 392 * Dir_InitDot -- 393 * (re)initialize "dot" (current/object directory) path hash 394 * 395 * Results: 396 * none 397 * 398 * Side Effects: 399 * some directories may be opened. 400 *----------------------------------------------------------------------- 401 */ 402 void 403 Dir_InitDot(void) 404 { 405 if (dot != NULL) { 406 LstNode ln; 407 408 /* Remove old entry from openDirectories, but do not destroy. */ 409 ln = Lst_Member(openDirectories, dot); 410 (void)Lst_Remove(openDirectories, ln); 411 } 412 413 dot = Dir_AddDir(NULL, "."); 414 415 if (dot == NULL) { 416 Error("Cannot open `.' (%s)", strerror(errno)); 417 exit(1); 418 } 419 420 /* 421 * We always need to have dot around, so we increment its reference count 422 * to make sure it's not destroyed. 423 */ 424 dot->refCount += 1; 425 Dir_SetPATH(); /* initialize */ 426 } 427 428 /*- 429 *----------------------------------------------------------------------- 430 * Dir_End -- 431 * cleanup things for this module 432 * 433 * Results: 434 * none 435 * 436 * Side Effects: 437 * none 438 *----------------------------------------------------------------------- 439 */ 440 void 441 Dir_End(void) 442 { 443 #ifdef CLEANUP 444 if (cur) { 445 cur->refCount -= 1; 446 Dir_Destroy(cur); 447 } 448 dot->refCount -= 1; 449 dotLast->refCount -= 1; 450 Dir_Destroy(dotLast); 451 Dir_Destroy(dot); 452 Dir_ClearPath(dirSearchPath); 453 Lst_Destroy(dirSearchPath, NULL); 454 Dir_ClearPath(openDirectories); 455 Lst_Destroy(openDirectories, NULL); 456 Hash_DeleteTable(&mtimes); 457 #endif 458 } 459 460 /* 461 * We want ${.PATH} to indicate the order in which we will actually 462 * search, so we rebuild it after any .PATH: target. 463 * This is the simplest way to deal with the effect of .DOTLAST. 464 */ 465 void 466 Dir_SetPATH(void) 467 { 468 LstNode ln; /* a list element */ 469 Path *p; 470 Boolean hasLastDot = FALSE; /* true we should search dot last */ 471 472 Var_Delete(".PATH", VAR_GLOBAL); 473 474 if (Lst_Open(dirSearchPath) == SUCCESS) { 475 if ((ln = Lst_First(dirSearchPath)) != NULL) { 476 p = (Path *)Lst_Datum(ln); 477 if (p == dotLast) { 478 hasLastDot = TRUE; 479 Var_Append(".PATH", dotLast->name, VAR_GLOBAL); 480 } 481 } 482 483 if (!hasLastDot) { 484 if (dot) 485 Var_Append(".PATH", dot->name, VAR_GLOBAL); 486 if (cur) 487 Var_Append(".PATH", cur->name, VAR_GLOBAL); 488 } 489 490 while ((ln = Lst_Next(dirSearchPath)) != NULL) { 491 p = (Path *)Lst_Datum(ln); 492 if (p == dotLast) 493 continue; 494 if (p == dot && hasLastDot) 495 continue; 496 Var_Append(".PATH", p->name, VAR_GLOBAL); 497 } 498 499 if (hasLastDot) { 500 if (dot) 501 Var_Append(".PATH", dot->name, VAR_GLOBAL); 502 if (cur) 503 Var_Append(".PATH", cur->name, VAR_GLOBAL); 504 } 505 Lst_Close(dirSearchPath); 506 } 507 } 508 509 /*- 510 *----------------------------------------------------------------------- 511 * DirFindName -- 512 * See if the Path structure describes the same directory as the 513 * given one by comparing their names. Called from Dir_AddDir via 514 * Lst_Find when searching the list of open directories. 515 * 516 * Input: 517 * p Current name 518 * dname Desired name 519 * 520 * Results: 521 * 0 if it is the same. Non-zero otherwise 522 * 523 * Side Effects: 524 * None 525 *----------------------------------------------------------------------- 526 */ 527 static int 528 DirFindName(const void *p, const void *dname) 529 { 530 return (strcmp(((const Path *)p)->name, dname)); 531 } 532 533 /*- 534 *----------------------------------------------------------------------- 535 * Dir_HasWildcards -- 536 * see if the given name has any wildcard characters in it 537 * be careful not to expand unmatching brackets or braces. 538 * XXX: This code is not 100% correct. ([^]] fails etc.) 539 * I really don't think that make(1) should be expanding 540 * patterns, because then you have to set a mechanism for 541 * escaping the expansion! 542 * 543 * Input: 544 * name name to check 545 * 546 * Results: 547 * returns TRUE if the word should be expanded, FALSE otherwise 548 * 549 * Side Effects: 550 * none 551 *----------------------------------------------------------------------- 552 */ 553 Boolean 554 Dir_HasWildcards(char *name) 555 { 556 char *cp; 557 int wild = 0, brace = 0, bracket = 0; 558 559 for (cp = name; *cp; cp++) { 560 switch(*cp) { 561 case '{': 562 brace++; 563 wild = 1; 564 break; 565 case '}': 566 brace--; 567 break; 568 case '[': 569 bracket++; 570 wild = 1; 571 break; 572 case ']': 573 bracket--; 574 break; 575 case '?': 576 case '*': 577 wild = 1; 578 break; 579 default: 580 break; 581 } 582 } 583 return wild && bracket == 0 && brace == 0; 584 } 585 586 /*- 587 *----------------------------------------------------------------------- 588 * DirMatchFiles -- 589 * Given a pattern and a Path structure, see if any files 590 * match the pattern and add their names to the 'expansions' list if 591 * any do. This is incomplete -- it doesn't take care of patterns like 592 * src / *src / *.c properly (just *.c on any of the directories), but it 593 * will do for now. 594 * 595 * Input: 596 * pattern Pattern to look for 597 * p Directory to search 598 * expansion Place to store the results 599 * 600 * Results: 601 * Always returns 0 602 * 603 * Side Effects: 604 * File names are added to the expansions lst. The directory will be 605 * fully hashed when this is done. 606 *----------------------------------------------------------------------- 607 */ 608 static int 609 DirMatchFiles(const char *pattern, Path *p, Lst expansions) 610 { 611 Hash_Search search; /* Index into the directory's table */ 612 Hash_Entry *entry; /* Current entry in the table */ 613 Boolean isDot; /* TRUE if the directory being searched is . */ 614 615 isDot = (*p->name == '.' && p->name[1] == '\0'); 616 617 for (entry = Hash_EnumFirst(&p->files, &search); 618 entry != NULL; 619 entry = Hash_EnumNext(&search)) 620 { 621 /* 622 * See if the file matches the given pattern. Note we follow the UNIX 623 * convention that dot files will only be found if the pattern 624 * begins with a dot (note also that as a side effect of the hashing 625 * scheme, .* won't match . or .. since they aren't hashed). 626 */ 627 if (Str_Match(entry->name, pattern) && 628 ((entry->name[0] != '.') || 629 (pattern[0] == '.'))) 630 { 631 (void)Lst_AtEnd(expansions, 632 (isDot ? bmake_strdup(entry->name) : 633 str_concat(p->name, entry->name, 634 STR_ADDSLASH))); 635 } 636 } 637 return (0); 638 } 639 640 /*- 641 *----------------------------------------------------------------------- 642 * DirExpandCurly -- 643 * Expand curly braces like the C shell. Does this recursively. 644 * Note the special case: if after the piece of the curly brace is 645 * done there are no wildcard characters in the result, the result is 646 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. 647 * 648 * Input: 649 * word Entire word to expand 650 * brace First curly brace in it 651 * path Search path to use 652 * expansions Place to store the expansions 653 * 654 * Results: 655 * None. 656 * 657 * Side Effects: 658 * The given list is filled with the expansions... 659 * 660 *----------------------------------------------------------------------- 661 */ 662 static void 663 DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) 664 { 665 const char *end; /* Character after the closing brace */ 666 const char *cp; /* Current position in brace clause */ 667 const char *start; /* Start of current piece of brace clause */ 668 int bracelevel; /* Number of braces we've seen. If we see a 669 * right brace when this is 0, we've hit the 670 * end of the clause. */ 671 char *file; /* Current expansion */ 672 int otherLen; /* The length of the other pieces of the 673 * expansion (chars before and after the 674 * clause in 'word') */ 675 char *cp2; /* Pointer for checking for wildcards in 676 * expansion before calling Dir_Expand */ 677 678 start = brace+1; 679 680 /* 681 * Find the end of the brace clause first, being wary of nested brace 682 * clauses. 683 */ 684 for (end = start, bracelevel = 0; *end != '\0'; end++) { 685 if (*end == '{') { 686 bracelevel++; 687 } else if ((*end == '}') && (bracelevel-- == 0)) { 688 break; 689 } 690 } 691 if (*end == '\0') { 692 Error("Unterminated {} clause \"%s\"", start); 693 return; 694 } else { 695 end++; 696 } 697 otherLen = brace - word + strlen(end); 698 699 for (cp = start; cp < end; cp++) { 700 /* 701 * Find the end of this piece of the clause. 702 */ 703 bracelevel = 0; 704 while (*cp != ',') { 705 if (*cp == '{') { 706 bracelevel++; 707 } else if ((*cp == '}') && (bracelevel-- <= 0)) { 708 break; 709 } 710 cp++; 711 } 712 /* 713 * Allocate room for the combination and install the three pieces. 714 */ 715 file = bmake_malloc(otherLen + cp - start + 1); 716 if (brace != word) { 717 strncpy(file, word, brace-word); 718 } 719 if (cp != start) { 720 strncpy(&file[brace-word], start, cp-start); 721 } 722 strcpy(&file[(brace-word)+(cp-start)], end); 723 724 /* 725 * See if the result has any wildcards in it. If we find one, call 726 * Dir_Expand right away, telling it to place the result on our list 727 * of expansions. 728 */ 729 for (cp2 = file; *cp2 != '\0'; cp2++) { 730 switch(*cp2) { 731 case '*': 732 case '?': 733 case '{': 734 case '[': 735 Dir_Expand(file, path, expansions); 736 goto next; 737 } 738 } 739 if (*cp2 == '\0') { 740 /* 741 * Hit the end w/o finding any wildcards, so stick the expansion 742 * on the end of the list. 743 */ 744 (void)Lst_AtEnd(expansions, file); 745 } else { 746 next: 747 free(file); 748 } 749 start = cp+1; 750 } 751 } 752 753 754 /*- 755 *----------------------------------------------------------------------- 756 * DirExpandInt -- 757 * Internal expand routine. Passes through the directories in the 758 * path one by one, calling DirMatchFiles for each. NOTE: This still 759 * doesn't handle patterns in directories... 760 * 761 * Input: 762 * word Word to expand 763 * path Path on which to look 764 * expansions Place to store the result 765 * 766 * Results: 767 * None. 768 * 769 * Side Effects: 770 * Things are added to the expansions list. 771 * 772 *----------------------------------------------------------------------- 773 */ 774 static void 775 DirExpandInt(const char *word, Lst path, Lst expansions) 776 { 777 LstNode ln; /* Current node */ 778 Path *p; /* Directory in the node */ 779 780 if (Lst_Open(path) == SUCCESS) { 781 while ((ln = Lst_Next(path)) != NULL) { 782 p = (Path *)Lst_Datum(ln); 783 DirMatchFiles(word, p, expansions); 784 } 785 Lst_Close(path); 786 } 787 } 788 789 /*- 790 *----------------------------------------------------------------------- 791 * DirPrintWord -- 792 * Print a word in the list of expansions. Callback for Dir_Expand 793 * when DEBUG(DIR), via Lst_ForEach. 794 * 795 * Results: 796 * === 0 797 * 798 * Side Effects: 799 * The passed word is printed, followed by a space. 800 * 801 *----------------------------------------------------------------------- 802 */ 803 static int 804 DirPrintWord(void *word, void *dummy) 805 { 806 fprintf(debug_file, "%s ", (char *)word); 807 808 return(dummy ? 0 : 0); 809 } 810 811 /*- 812 *----------------------------------------------------------------------- 813 * Dir_Expand -- 814 * Expand the given word into a list of words by globbing it looking 815 * in the directories on the given search path. 816 * 817 * Input: 818 * word the word to expand 819 * path the list of directories in which to find the 820 * resulting files 821 * expansions the list on which to place the results 822 * 823 * Results: 824 * A list of words consisting of the files which exist along the search 825 * path matching the given pattern. 826 * 827 * Side Effects: 828 * Directories may be opened. Who knows? 829 *----------------------------------------------------------------------- 830 */ 831 void 832 Dir_Expand(const char *word, Lst path, Lst expansions) 833 { 834 const char *cp; 835 836 if (DEBUG(DIR)) { 837 fprintf(debug_file, "Expanding \"%s\"... ", word); 838 } 839 840 cp = strchr(word, '{'); 841 if (cp) { 842 DirExpandCurly(word, cp, path, expansions); 843 } else { 844 cp = strchr(word, '/'); 845 if (cp) { 846 /* 847 * The thing has a directory component -- find the first wildcard 848 * in the string. 849 */ 850 for (cp = word; *cp; cp++) { 851 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { 852 break; 853 } 854 } 855 if (*cp == '{') { 856 /* 857 * This one will be fun. 858 */ 859 DirExpandCurly(word, cp, path, expansions); 860 return; 861 } else if (*cp != '\0') { 862 /* 863 * Back up to the start of the component 864 */ 865 char *dirpath; 866 867 while (cp > word && *cp != '/') { 868 cp--; 869 } 870 if (cp != word) { 871 char sc; 872 /* 873 * If the glob isn't in the first component, try and find 874 * all the components up to the one with a wildcard. 875 */ 876 sc = cp[1]; 877 ((char *)UNCONST(cp))[1] = '\0'; 878 dirpath = Dir_FindFile(word, path); 879 ((char *)UNCONST(cp))[1] = sc; 880 /* 881 * dirpath is null if can't find the leading component 882 * XXX: Dir_FindFile won't find internal components. 883 * i.e. if the path contains ../Etc/Object and we're 884 * looking for Etc, it won't be found. Ah well. 885 * Probably not important. 886 */ 887 if (dirpath != NULL) { 888 char *dp = &dirpath[strlen(dirpath) - 1]; 889 if (*dp == '/') 890 *dp = '\0'; 891 path = Lst_Init(FALSE); 892 (void)Dir_AddDir(path, dirpath); 893 DirExpandInt(cp+1, path, expansions); 894 Lst_Destroy(path, NULL); 895 } 896 } else { 897 /* 898 * Start the search from the local directory 899 */ 900 DirExpandInt(word, path, expansions); 901 } 902 } else { 903 /* 904 * Return the file -- this should never happen. 905 */ 906 DirExpandInt(word, path, expansions); 907 } 908 } else { 909 /* 910 * First the files in dot 911 */ 912 DirMatchFiles(word, dot, expansions); 913 914 /* 915 * Then the files in every other directory on the path. 916 */ 917 DirExpandInt(word, path, expansions); 918 } 919 } 920 if (DEBUG(DIR)) { 921 Lst_ForEach(expansions, DirPrintWord, NULL); 922 fprintf(debug_file, "\n"); 923 } 924 } 925 926 /*- 927 *----------------------------------------------------------------------- 928 * DirLookup -- 929 * Find if the file with the given name exists in the given path. 930 * 931 * Results: 932 * The path to the file or NULL. This path is guaranteed to be in a 933 * different part of memory than name and so may be safely free'd. 934 * 935 * Side Effects: 936 * None. 937 *----------------------------------------------------------------------- 938 */ 939 static char * 940 DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, 941 Boolean hasSlash MAKE_ATTR_UNUSED) 942 { 943 char *file; /* the current filename to check */ 944 945 if (DEBUG(DIR)) { 946 fprintf(debug_file, " %s ...\n", p->name); 947 } 948 949 if (Hash_FindEntry(&p->files, cp) == NULL) 950 return NULL; 951 952 file = str_concat(p->name, cp, STR_ADDSLASH); 953 if (DEBUG(DIR)) { 954 fprintf(debug_file, " returning %s\n", file); 955 } 956 p->hits += 1; 957 hits += 1; 958 return file; 959 } 960 961 962 /*- 963 *----------------------------------------------------------------------- 964 * DirLookupSubdir -- 965 * Find if the file with the given name exists in the given path. 966 * 967 * Results: 968 * The path to the file or NULL. This path is guaranteed to be in a 969 * different part of memory than name and so may be safely free'd. 970 * 971 * Side Effects: 972 * If the file is found, it is added in the modification times hash 973 * table. 974 *----------------------------------------------------------------------- 975 */ 976 static char * 977 DirLookupSubdir(Path *p, const char *name) 978 { 979 struct stat stb; /* Buffer for stat, if necessary */ 980 char *file; /* the current filename to check */ 981 982 if (p != dot) { 983 file = str_concat(p->name, name, STR_ADDSLASH); 984 } else { 985 /* 986 * Checking in dot -- DON'T put a leading ./ on the thing. 987 */ 988 file = bmake_strdup(name); 989 } 990 991 if (DEBUG(DIR)) { 992 fprintf(debug_file, "checking %s ...\n", file); 993 } 994 995 if (cached_stat(file, &stb) == 0) { 996 /* 997 * Save the modification time so if it's needed, we don't have 998 * to fetch it again. 999 */ 1000 if (DEBUG(DIR)) { 1001 fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), 1002 file); 1003 } 1004 nearmisses += 1; 1005 return (file); 1006 } 1007 free(file); 1008 return NULL; 1009 } 1010 1011 /*- 1012 *----------------------------------------------------------------------- 1013 * DirLookupAbs -- 1014 * Find if the file with the given name exists in the given path. 1015 * 1016 * Results: 1017 * The path to the file, the empty string or NULL. If the file is 1018 * the empty string, the search should be terminated. 1019 * This path is guaranteed to be in a different part of memory 1020 * than name and so may be safely free'd. 1021 * 1022 * Side Effects: 1023 * None. 1024 *----------------------------------------------------------------------- 1025 */ 1026 static char * 1027 DirLookupAbs(Path *p, const char *name, const char *cp) 1028 { 1029 char *p1; /* pointer into p->name */ 1030 const char *p2; /* pointer into name */ 1031 1032 if (DEBUG(DIR)) { 1033 fprintf(debug_file, " %s ...\n", p->name); 1034 } 1035 1036 /* 1037 * If the file has a leading path component and that component 1038 * exactly matches the entire name of the current search 1039 * directory, we can attempt another cache lookup. And if we don't 1040 * have a hit, we can safely assume the file does not exist at all. 1041 */ 1042 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { 1043 continue; 1044 } 1045 if (*p1 != '\0' || p2 != cp - 1) { 1046 return NULL; 1047 } 1048 1049 if (Hash_FindEntry(&p->files, cp) == NULL) { 1050 if (DEBUG(DIR)) { 1051 fprintf(debug_file, " must be here but isn't -- returning\n"); 1052 } 1053 /* Return empty string: terminates search */ 1054 return bmake_strdup(""); 1055 } 1056 1057 p->hits += 1; 1058 hits += 1; 1059 if (DEBUG(DIR)) { 1060 fprintf(debug_file, " returning %s\n", name); 1061 } 1062 return (bmake_strdup(name)); 1063 } 1064 1065 /*- 1066 *----------------------------------------------------------------------- 1067 * DirFindDot -- 1068 * Find the file given on "." or curdir 1069 * 1070 * Results: 1071 * The path to the file or NULL. This path is guaranteed to be in a 1072 * different part of memory than name and so may be safely free'd. 1073 * 1074 * Side Effects: 1075 * Hit counts change 1076 *----------------------------------------------------------------------- 1077 */ 1078 static char * 1079 DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) 1080 { 1081 1082 if (Hash_FindEntry(&dot->files, cp) != NULL) { 1083 if (DEBUG(DIR)) { 1084 fprintf(debug_file, " in '.'\n"); 1085 } 1086 hits += 1; 1087 dot->hits += 1; 1088 return (bmake_strdup(name)); 1089 } 1090 if (cur && 1091 Hash_FindEntry(&cur->files, cp) != NULL) { 1092 if (DEBUG(DIR)) { 1093 fprintf(debug_file, " in ${.CURDIR} = %s\n", cur->name); 1094 } 1095 hits += 1; 1096 cur->hits += 1; 1097 return str_concat(cur->name, cp, STR_ADDSLASH); 1098 } 1099 1100 return NULL; 1101 } 1102 1103 /*- 1104 *----------------------------------------------------------------------- 1105 * Dir_FindFile -- 1106 * Find the file with the given name along the given search path. 1107 * 1108 * Input: 1109 * name the file to find 1110 * path the Lst of directories to search 1111 * 1112 * Results: 1113 * The path to the file or NULL. This path is guaranteed to be in a 1114 * different part of memory than name and so may be safely free'd. 1115 * 1116 * Side Effects: 1117 * If the file is found in a directory which is not on the path 1118 * already (either 'name' is absolute or it is a relative path 1119 * [ dir1/.../dirn/file ] which exists below one of the directories 1120 * already on the search path), its directory is added to the end 1121 * of the path on the assumption that there will be more files in 1122 * that directory later on. Sometimes this is true. Sometimes not. 1123 *----------------------------------------------------------------------- 1124 */ 1125 char * 1126 Dir_FindFile(const char *name, Lst path) 1127 { 1128 LstNode ln; /* a list element */ 1129 char *file; /* the current filename to check */ 1130 Path *p; /* current path member */ 1131 const char *cp; /* Terminal name of file */ 1132 Boolean hasLastDot = FALSE; /* true we should search dot last */ 1133 Boolean hasSlash; /* true if 'name' contains a / */ 1134 struct stat stb; /* Buffer for stat, if necessary */ 1135 Hash_Entry *entry; /* Entry for mtimes table */ 1136 const char *trailing_dot = "."; 1137 1138 /* 1139 * Find the final component of the name and note whether it has a 1140 * slash in it (the name, I mean) 1141 */ 1142 cp = strrchr(name, '/'); 1143 if (cp) { 1144 hasSlash = TRUE; 1145 cp += 1; 1146 } else { 1147 hasSlash = FALSE; 1148 cp = name; 1149 } 1150 1151 if (DEBUG(DIR)) { 1152 fprintf(debug_file, "Searching for %s ...", name); 1153 } 1154 1155 if (Lst_Open(path) == FAILURE) { 1156 if (DEBUG(DIR)) { 1157 fprintf(debug_file, "couldn't open path, file not found\n"); 1158 } 1159 misses += 1; 1160 return NULL; 1161 } 1162 1163 if ((ln = Lst_First(path)) != NULL) { 1164 p = (Path *)Lst_Datum(ln); 1165 if (p == dotLast) { 1166 hasLastDot = TRUE; 1167 if (DEBUG(DIR)) 1168 fprintf(debug_file, "[dot last]..."); 1169 } 1170 } 1171 if (DEBUG(DIR)) { 1172 fprintf(debug_file, "\n"); 1173 } 1174 1175 /* 1176 * If there's no leading directory components or if the leading 1177 * directory component is exactly `./', consult the cached contents 1178 * of each of the directories on the search path. 1179 */ 1180 if (!hasSlash || (cp - name == 2 && *name == '.')) { 1181 /* 1182 * We look through all the directories on the path seeking one which 1183 * contains the final component of the given name. If such a beast 1184 * is found, we concatenate the directory name and the final 1185 * component and return the resulting string. If we don't find any 1186 * such thing, we go on to phase two... 1187 * 1188 * No matter what, we always look for the file in the current 1189 * directory before anywhere else (unless we found the magic 1190 * DOTLAST path, in which case we search it last) and we *do not* 1191 * add the ./ to it if it exists. 1192 * This is so there are no conflicts between what the user 1193 * specifies (fish.c) and what pmake finds (./fish.c). 1194 */ 1195 if (!hasLastDot && 1196 (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1197 Lst_Close(path); 1198 return file; 1199 } 1200 1201 while ((ln = Lst_Next(path)) != NULL) { 1202 p = (Path *)Lst_Datum(ln); 1203 if (p == dotLast) 1204 continue; 1205 if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { 1206 Lst_Close(path); 1207 return file; 1208 } 1209 } 1210 1211 if (hasLastDot && 1212 (file = DirFindDot(hasSlash, name, cp)) != NULL) { 1213 Lst_Close(path); 1214 return file; 1215 } 1216 } 1217 Lst_Close(path); 1218 1219 /* 1220 * We didn't find the file on any directory in the search path. 1221 * If the name doesn't contain a slash, that means it doesn't exist. 1222 * If it *does* contain a slash, however, there is still hope: it 1223 * could be in a subdirectory of one of the members of the search 1224 * path. (eg. /usr/include and sys/types.h. The above search would 1225 * fail to turn up types.h in /usr/include, but it *is* in 1226 * /usr/include/sys/types.h). 1227 * [ This no longer applies: If we find such a beast, we assume there 1228 * will be more (what else can we assume?) and add all but the last 1229 * component of the resulting name onto the search path (at the 1230 * end).] 1231 * This phase is only performed if the file is *not* absolute. 1232 */ 1233 if (!hasSlash) { 1234 if (DEBUG(DIR)) { 1235 fprintf(debug_file, " failed.\n"); 1236 } 1237 misses += 1; 1238 return NULL; 1239 } 1240 1241 if (*cp == '\0') { 1242 /* we were given a trailing "/" */ 1243 cp = trailing_dot; 1244 } 1245 1246 if (name[0] != '/') { 1247 Boolean checkedDot = FALSE; 1248 1249 if (DEBUG(DIR)) { 1250 fprintf(debug_file, " Trying subdirectories...\n"); 1251 } 1252 1253 if (!hasLastDot) { 1254 if (dot) { 1255 checkedDot = TRUE; 1256 if ((file = DirLookupSubdir(dot, name)) != NULL) 1257 return file; 1258 } 1259 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1260 return file; 1261 } 1262 1263 (void)Lst_Open(path); 1264 while ((ln = Lst_Next(path)) != NULL) { 1265 p = (Path *)Lst_Datum(ln); 1266 if (p == dotLast) 1267 continue; 1268 if (p == dot) { 1269 if (checkedDot) 1270 continue; 1271 checkedDot = TRUE; 1272 } 1273 if ((file = DirLookupSubdir(p, name)) != NULL) { 1274 Lst_Close(path); 1275 return file; 1276 } 1277 } 1278 Lst_Close(path); 1279 1280 if (hasLastDot) { 1281 if (dot && !checkedDot) { 1282 checkedDot = TRUE; 1283 if ((file = DirLookupSubdir(dot, name)) != NULL) 1284 return file; 1285 } 1286 if (cur && (file = DirLookupSubdir(cur, name)) != NULL) 1287 return file; 1288 } 1289 1290 if (checkedDot) { 1291 /* 1292 * Already checked by the given name, since . was in the path, 1293 * so no point in proceeding... 1294 */ 1295 if (DEBUG(DIR)) { 1296 fprintf(debug_file, " Checked . already, returning NULL\n"); 1297 } 1298 return NULL; 1299 } 1300 1301 } else { /* name[0] == '/' */ 1302 1303 /* 1304 * For absolute names, compare directory path prefix against the 1305 * the directory path of each member on the search path for an exact 1306 * match. If we have an exact match on any member of the search path, 1307 * use the cached contents of that member to lookup the final file 1308 * component. If that lookup fails we can safely assume that the 1309 * file does not exist at all. This is signified by DirLookupAbs() 1310 * returning an empty string. 1311 */ 1312 if (DEBUG(DIR)) { 1313 fprintf(debug_file, " Trying exact path matches...\n"); 1314 } 1315 1316 if (!hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL) 1317 return *file?file:NULL; 1318 1319 (void)Lst_Open(path); 1320 while ((ln = Lst_Next(path)) != NULL) { 1321 p = (Path *)Lst_Datum(ln); 1322 if (p == dotLast) 1323 continue; 1324 if ((file = DirLookupAbs(p, name, cp)) != NULL) { 1325 Lst_Close(path); 1326 return *file?file:NULL; 1327 } 1328 } 1329 Lst_Close(path); 1330 1331 if (hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL) 1332 return *file?file:NULL; 1333 } 1334 1335 /* 1336 * Didn't find it that way, either. Sigh. Phase 3. Add its directory 1337 * onto the search path in any case, just in case, then look for the 1338 * thing in the hash table. If we find it, grand. We return a new 1339 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh. 1340 * Note that if the directory holding the file doesn't exist, this will 1341 * do an extra search of the final directory on the path. Unless something 1342 * weird happens, this search won't succeed and life will be groovy. 1343 * 1344 * Sigh. We cannot add the directory onto the search path because 1345 * of this amusing case: 1346 * $(INSTALLDIR)/$(FILE): $(FILE) 1347 * 1348 * $(FILE) exists in $(INSTALLDIR) but not in the current one. 1349 * When searching for $(FILE), we will find it in $(INSTALLDIR) 1350 * b/c we added it here. This is not good... 1351 */ 1352 #ifdef notdef 1353 if (cp == traling_dot) { 1354 cp = strrchr(name, '/'); 1355 cp += 1; 1356 } 1357 cp[-1] = '\0'; 1358 (void)Dir_AddDir(path, name); 1359 cp[-1] = '/'; 1360 1361 bigmisses += 1; 1362 ln = Lst_Last(path); 1363 if (ln == NULL) { 1364 return NULL; 1365 } else { 1366 p = (Path *)Lst_Datum(ln); 1367 } 1368 1369 if (Hash_FindEntry(&p->files, cp) != NULL) { 1370 return (bmake_strdup(name)); 1371 } else { 1372 return NULL; 1373 } 1374 #else /* !notdef */ 1375 if (DEBUG(DIR)) { 1376 fprintf(debug_file, " Looking for \"%s\" ...\n", name); 1377 } 1378 1379 bigmisses += 1; 1380 entry = Hash_FindEntry(&mtimes, name); 1381 if (entry != NULL) { 1382 if (DEBUG(DIR)) { 1383 fprintf(debug_file, " got it (in mtime cache)\n"); 1384 } 1385 return(bmake_strdup(name)); 1386 } else if (cached_stat(name, &stb) == 0) { 1387 if (DEBUG(DIR)) { 1388 fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), 1389 name); 1390 } 1391 return (bmake_strdup(name)); 1392 } else { 1393 if (DEBUG(DIR)) { 1394 fprintf(debug_file, " failed. Returning NULL\n"); 1395 } 1396 return NULL; 1397 } 1398 #endif /* notdef */ 1399 } 1400 1401 1402 /*- 1403 *----------------------------------------------------------------------- 1404 * Dir_FindHereOrAbove -- 1405 * search for a path starting at a given directory and then working 1406 * our way up towards the root. 1407 * 1408 * Input: 1409 * here starting directory 1410 * search_path the path we are looking for 1411 * result the result of a successful search is placed here 1412 * rlen the length of the result buffer 1413 * (typically MAXPATHLEN + 1) 1414 * 1415 * Results: 1416 * 0 on failure, 1 on success [in which case the found path is put 1417 * in the result buffer]. 1418 * 1419 * Side Effects: 1420 *----------------------------------------------------------------------- 1421 */ 1422 int 1423 Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) { 1424 1425 struct stat st; 1426 char dirbase[MAXPATHLEN + 1], *db_end; 1427 char try[MAXPATHLEN + 1], *try_end; 1428 1429 /* copy out our starting point */ 1430 snprintf(dirbase, sizeof(dirbase), "%s", here); 1431 db_end = dirbase + strlen(dirbase); 1432 1433 /* loop until we determine a result */ 1434 while (1) { 1435 1436 /* try and stat(2) it ... */ 1437 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); 1438 if (cached_stat(try, &st) != -1) { 1439 /* 1440 * success! if we found a file, chop off 1441 * the filename so we return a directory. 1442 */ 1443 if ((st.st_mode & S_IFMT) != S_IFDIR) { 1444 try_end = try + strlen(try); 1445 while (try_end > try && *try_end != '/') 1446 try_end--; 1447 if (try_end > try) 1448 *try_end = 0; /* chop! */ 1449 } 1450 1451 /* 1452 * done! 1453 */ 1454 snprintf(result, rlen, "%s", try); 1455 return(1); 1456 } 1457 1458 /* 1459 * nope, we didn't find it. if we used up dirbase we've 1460 * reached the root and failed. 1461 */ 1462 if (db_end == dirbase) 1463 break; /* failed! */ 1464 1465 /* 1466 * truncate dirbase from the end to move up a dir 1467 */ 1468 while (db_end > dirbase && *db_end != '/') 1469 db_end--; 1470 *db_end = 0; /* chop! */ 1471 1472 } /* while (1) */ 1473 1474 /* 1475 * we failed... 1476 */ 1477 return(0); 1478 } 1479 1480 /*- 1481 *----------------------------------------------------------------------- 1482 * Dir_MTime -- 1483 * Find the modification time of the file described by gn along the 1484 * search path dirSearchPath. 1485 * 1486 * Input: 1487 * gn the file whose modification time is desired 1488 * 1489 * Results: 1490 * The modification time or 0 if it doesn't exist 1491 * 1492 * Side Effects: 1493 * The modification time is placed in the node's mtime slot. 1494 * If the node didn't have a path entry before, and Dir_FindFile 1495 * found one for it, the full name is placed in the path slot. 1496 *----------------------------------------------------------------------- 1497 */ 1498 int 1499 Dir_MTime(GNode *gn, Boolean recheck) 1500 { 1501 char *fullName; /* the full pathname of name */ 1502 struct stat stb; /* buffer for finding the mod time */ 1503 Hash_Entry *entry; 1504 1505 if (gn->type & OP_ARCHV) { 1506 return Arch_MTime(gn); 1507 } else if (gn->type & OP_PHONY) { 1508 gn->mtime = 0; 1509 return 0; 1510 } else if (gn->path == NULL) { 1511 if (gn->type & OP_NOPATH) 1512 fullName = NULL; 1513 else { 1514 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); 1515 if (fullName == NULL && gn->flags & FROM_DEPEND && 1516 !Lst_IsEmpty(gn->iParents)) { 1517 char *cp; 1518 1519 cp = strrchr(gn->name, '/'); 1520 if (cp) { 1521 /* 1522 * This is an implied source, and it may have moved, 1523 * see if we can find it via the current .PATH 1524 */ 1525 cp++; 1526 1527 fullName = Dir_FindFile(cp, Suff_FindPath(gn)); 1528 if (fullName) { 1529 /* 1530 * Put the found file in gn->path 1531 * so that we give that to the compiler. 1532 */ 1533 gn->path = bmake_strdup(fullName); 1534 if (!Job_RunTarget(".STALE", gn->fname)) 1535 fprintf(stdout, 1536 "%s: %s, %d: ignoring stale %s for %s, " 1537 "found %s\n", progname, gn->fname, gn->lineno, 1538 makeDependfile, gn->name, fullName); 1539 } 1540 } 1541 } 1542 if (DEBUG(DIR)) 1543 fprintf(debug_file, "Found '%s' as '%s'\n", 1544 gn->name, fullName ? fullName : "(not found)" ); 1545 } 1546 } else { 1547 fullName = gn->path; 1548 } 1549 1550 if (fullName == NULL) { 1551 fullName = bmake_strdup(gn->name); 1552 } 1553 1554 if (!recheck) 1555 entry = Hash_FindEntry(&mtimes, fullName); 1556 else 1557 entry = NULL; 1558 if (entry != NULL) { 1559 stb.st_mtime = Hash_GetTimeValue(entry); 1560 if (DEBUG(DIR)) { 1561 fprintf(debug_file, "Using cached time %s for %s\n", 1562 Targ_FmtTime(stb.st_mtime), fullName); 1563 } 1564 } else if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) { 1565 if (gn->type & OP_MEMBER) { 1566 if (fullName != gn->path) 1567 free(fullName); 1568 return Arch_MemMTime(gn); 1569 } else { 1570 stb.st_mtime = 0; 1571 } 1572 } 1573 1574 if (fullName && gn->path == NULL) { 1575 gn->path = fullName; 1576 } 1577 1578 gn->mtime = stb.st_mtime; 1579 return (gn->mtime); 1580 } 1581 1582 /*- 1583 *----------------------------------------------------------------------- 1584 * Dir_AddDir -- 1585 * Add the given name to the end of the given path. The order of 1586 * the arguments is backwards so ParseDoDependency can do a 1587 * Lst_ForEach of its list of paths... 1588 * 1589 * Input: 1590 * path the path to which the directory should be 1591 * added 1592 * name the name of the directory to add 1593 * 1594 * Results: 1595 * none 1596 * 1597 * Side Effects: 1598 * A structure is added to the list and the directory is 1599 * read and hashed. 1600 *----------------------------------------------------------------------- 1601 */ 1602 Path * 1603 Dir_AddDir(Lst path, const char *name) 1604 { 1605 LstNode ln = NULL; /* node in case Path structure is found */ 1606 Path *p = NULL; /* pointer to new Path structure */ 1607 DIR *d; /* for reading directory */ 1608 struct dirent *dp; /* entry in directory */ 1609 1610 if (strcmp(name, ".DOTLAST") == 0) { 1611 ln = Lst_Find(path, name, DirFindName); 1612 if (ln != NULL) 1613 return (Path *)Lst_Datum(ln); 1614 else { 1615 dotLast->refCount += 1; 1616 (void)Lst_AtFront(path, dotLast); 1617 } 1618 } 1619 1620 if (path) 1621 ln = Lst_Find(openDirectories, name, DirFindName); 1622 if (ln != NULL) { 1623 p = (Path *)Lst_Datum(ln); 1624 if (path && Lst_Member(path, p) == NULL) { 1625 p->refCount += 1; 1626 (void)Lst_AtEnd(path, p); 1627 } 1628 } else { 1629 if (DEBUG(DIR)) { 1630 fprintf(debug_file, "Caching %s ...", name); 1631 } 1632 1633 if ((d = opendir(name)) != NULL) { 1634 p = bmake_malloc(sizeof(Path)); 1635 p->name = bmake_strdup(name); 1636 p->hits = 0; 1637 p->refCount = 1; 1638 Hash_InitTable(&p->files, -1); 1639 1640 while ((dp = readdir(d)) != NULL) { 1641 #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ 1642 /* 1643 * The sun directory library doesn't check for a 0 inode 1644 * (0-inode slots just take up space), so we have to do 1645 * it ourselves. 1646 */ 1647 if (dp->d_fileno == 0) { 1648 continue; 1649 } 1650 #endif /* sun && d_ino */ 1651 (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); 1652 } 1653 (void)closedir(d); 1654 (void)Lst_AtEnd(openDirectories, p); 1655 if (path != NULL) 1656 (void)Lst_AtEnd(path, p); 1657 } 1658 if (DEBUG(DIR)) { 1659 fprintf(debug_file, "done\n"); 1660 } 1661 } 1662 return p; 1663 } 1664 1665 /*- 1666 *----------------------------------------------------------------------- 1667 * Dir_CopyDir -- 1668 * Callback function for duplicating a search path via Lst_Duplicate. 1669 * Ups the reference count for the directory. 1670 * 1671 * Results: 1672 * Returns the Path it was given. 1673 * 1674 * Side Effects: 1675 * The refCount of the path is incremented. 1676 * 1677 *----------------------------------------------------------------------- 1678 */ 1679 void * 1680 Dir_CopyDir(void *p) 1681 { 1682 ((Path *)p)->refCount += 1; 1683 1684 return (p); 1685 } 1686 1687 /*- 1688 *----------------------------------------------------------------------- 1689 * Dir_MakeFlags -- 1690 * Make a string by taking all the directories in the given search 1691 * path and preceding them by the given flag. Used by the suffix 1692 * module to create variables for compilers based on suffix search 1693 * paths. 1694 * 1695 * Input: 1696 * flag flag which should precede each directory 1697 * path list of directories 1698 * 1699 * Results: 1700 * The string mentioned above. Note that there is no space between 1701 * the given flag and each directory. The empty string is returned if 1702 * Things don't go well. 1703 * 1704 * Side Effects: 1705 * None 1706 *----------------------------------------------------------------------- 1707 */ 1708 char * 1709 Dir_MakeFlags(const char *flag, Lst path) 1710 { 1711 char *str; /* the string which will be returned */ 1712 char *s1, *s2;/* the current directory preceded by 'flag' */ 1713 LstNode ln; /* the node of the current directory */ 1714 Path *p; /* the structure describing the current directory */ 1715 1716 str = bmake_strdup(""); 1717 1718 if (Lst_Open(path) == SUCCESS) { 1719 while ((ln = Lst_Next(path)) != NULL) { 1720 p = (Path *)Lst_Datum(ln); 1721 s2 = str_concat(flag, p->name, 0); 1722 str = str_concat(s1 = str, s2, STR_ADDSPACE); 1723 free(s1); 1724 free(s2); 1725 } 1726 Lst_Close(path); 1727 } 1728 1729 return (str); 1730 } 1731 1732 /*- 1733 *----------------------------------------------------------------------- 1734 * Dir_Destroy -- 1735 * Nuke a directory descriptor, if possible. Callback procedure 1736 * for the suffixes module when destroying a search path. 1737 * 1738 * Input: 1739 * pp The directory descriptor to nuke 1740 * 1741 * Results: 1742 * None. 1743 * 1744 * Side Effects: 1745 * If no other path references this directory (refCount == 0), 1746 * the Path and all its data are freed. 1747 * 1748 *----------------------------------------------------------------------- 1749 */ 1750 void 1751 Dir_Destroy(void *pp) 1752 { 1753 Path *p = (Path *)pp; 1754 p->refCount -= 1; 1755 1756 if (p->refCount == 0) { 1757 LstNode ln; 1758 1759 ln = Lst_Member(openDirectories, p); 1760 (void)Lst_Remove(openDirectories, ln); 1761 1762 Hash_DeleteTable(&p->files); 1763 free(p->name); 1764 free(p); 1765 } 1766 } 1767 1768 /*- 1769 *----------------------------------------------------------------------- 1770 * Dir_ClearPath -- 1771 * Clear out all elements of the given search path. This is different 1772 * from destroying the list, notice. 1773 * 1774 * Input: 1775 * path Path to clear 1776 * 1777 * Results: 1778 * None. 1779 * 1780 * Side Effects: 1781 * The path is set to the empty list. 1782 * 1783 *----------------------------------------------------------------------- 1784 */ 1785 void 1786 Dir_ClearPath(Lst path) 1787 { 1788 Path *p; 1789 while (!Lst_IsEmpty(path)) { 1790 p = (Path *)Lst_DeQueue(path); 1791 Dir_Destroy(p); 1792 } 1793 } 1794 1795 1796 /*- 1797 *----------------------------------------------------------------------- 1798 * Dir_Concat -- 1799 * Concatenate two paths, adding the second to the end of the first. 1800 * Makes sure to avoid duplicates. 1801 * 1802 * Input: 1803 * path1 Dest 1804 * path2 Source 1805 * 1806 * Results: 1807 * None 1808 * 1809 * Side Effects: 1810 * Reference counts for added dirs are upped. 1811 * 1812 *----------------------------------------------------------------------- 1813 */ 1814 void 1815 Dir_Concat(Lst path1, Lst path2) 1816 { 1817 LstNode ln; 1818 Path *p; 1819 1820 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) { 1821 p = (Path *)Lst_Datum(ln); 1822 if (Lst_Member(path1, p) == NULL) { 1823 p->refCount += 1; 1824 (void)Lst_AtEnd(path1, p); 1825 } 1826 } 1827 } 1828 1829 /********** DEBUG INFO **********/ 1830 void 1831 Dir_PrintDirectories(void) 1832 { 1833 LstNode ln; 1834 Path *p; 1835 1836 fprintf(debug_file, "#*** Directory Cache:\n"); 1837 fprintf(debug_file, "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", 1838 hits, misses, nearmisses, bigmisses, 1839 (hits+bigmisses+nearmisses ? 1840 hits * 100 / (hits + bigmisses + nearmisses) : 0)); 1841 fprintf(debug_file, "# %-20s referenced\thits\n", "directory"); 1842 if (Lst_Open(openDirectories) == SUCCESS) { 1843 while ((ln = Lst_Next(openDirectories)) != NULL) { 1844 p = (Path *)Lst_Datum(ln); 1845 fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); 1846 } 1847 Lst_Close(openDirectories); 1848 } 1849 } 1850 1851 static int 1852 DirPrintDir(void *p, void *dummy) 1853 { 1854 fprintf(debug_file, "%s ", ((Path *)p)->name); 1855 return (dummy ? 0 : 0); 1856 } 1857 1858 void 1859 Dir_PrintPath(Lst path) 1860 { 1861 Lst_ForEach(path, DirPrintDir, NULL); 1862 } 1863