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