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