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