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