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