1 /* $OpenBSD: dir.c,v 1.59 2010/07/19 19:46:44 espie Exp $ */ 2 /* $NetBSD: dir.c,v 1.14 1997/03/29 16:51:26 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1999 Marc Espie. 6 * 7 * Extensive code changes for the OpenBSD project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 22 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 /* 31 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 32 * Copyright (c) 1988, 1989 by Adam de Boor 33 * Copyright (c) 1989 by Berkeley Softworks 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Adam de Boor. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 #include <sys/param.h> 65 #include <sys/stat.h> 66 #include <dirent.h> 67 #include <limits.h> 68 #include <stddef.h> 69 #include <stdio.h> 70 #include <stdint.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include "config.h" 74 #include "defines.h" 75 #include "ohash.h" 76 #include "dir.h" 77 #include "lst.h" 78 #include "memory.h" 79 #include "buf.h" 80 #include "gnode.h" 81 #include "arch.h" 82 #include "targ.h" 83 #include "error.h" 84 #include "str.h" 85 #include "timestamp.h" 86 87 88 /* A search path consists of a Lst of PathEntry structures. A Path 89 * structure has in it the name of the directory and a hash table of all 90 * the files in the directory. This is used to cut down on the number of 91 * system calls necessary to find implicit dependents and their like. 92 * Since these searches are made before any actions are taken, we need not 93 * worry about the directory changing due to creation commands. If this 94 * hampers the style of some makefiles, they must be changed. 95 * 96 * A list of all previously-read directories is kept in the 97 * knownDirectories cache. 98 * 99 * The need for the caching of whole directories is brought about by 100 * the multi-level transformation code in suff.c, which tends to search 101 * for far more files than regular make does. In the initial 102 * implementation, the amount of time spent performing "stat" calls was 103 * truly astronomical. The problem with hashing at the start is, 104 * of course, that pmake doesn't then detect changes to these directories 105 * during the course of the make. Three possibilities suggest themselves: 106 * 107 * 1) just use stat to test for a file's existence. As mentioned 108 * above, this is very inefficient due to the number of checks 109 * engendered by the multi-level transformation code. 110 * 2) use readdir() and company to search the directories, keeping 111 * them open between checks. I have tried this and while it 112 * didn't slow down the process too much, it could severely 113 * affect the amount of parallelism available as each directory 114 * open would take another file descriptor out of play for 115 * handling I/O for another job. Given that it is only recently 116 * that UNIX OS's have taken to allowing more than 20 or 32 117 * file descriptors for a process, this doesn't seem acceptable 118 * to me. 119 * 3) record the mtime of the directory in the PathEntry structure and 120 * verify the directory hasn't changed since the contents were 121 * hashed. This will catch the creation or deletion of files, 122 * but not the updating of files. However, since it is the 123 * creation and deletion that is the problem, this could be 124 * a good thing to do. Unfortunately, if the directory (say ".") 125 * were fairly large and changed fairly frequently, the constant 126 * rehashing could seriously degrade performance. It might be 127 * good in such cases to keep track of the number of rehashes 128 * and if the number goes over a (small) limit, resort to using 129 * stat in its place. 130 * 131 * An additional thing to consider is that pmake is used primarily 132 * to create C programs and until recently pcc-based compilers refused 133 * to allow you to specify where the resulting object file should be 134 * placed. This forced all objects to be created in the current 135 * directory. This isn't meant as a full excuse, just an explanation of 136 * some of the reasons for the caching used here. 137 * 138 * One more note: the location of a target's file is only performed 139 * on the downward traversal of the graph and then only for terminal 140 * nodes in the graph. This could be construed as wrong in some cases, 141 * but prevents inadvertent modification of files when the "installed" 142 * directory for a file is provided in the search path. 143 * 144 * Another data structure maintained by this module is an mtime 145 * cache used when the searching of cached directories fails to find 146 * a file. In the past, Dir_FindFile would simply perform an access() 147 * call in such a case to determine if the file could be found using 148 * just the name given. When this hit, however, all that was gained 149 * was the knowledge that the file existed. Given that an access() is 150 * essentially a stat() without the copyout() call, and that the same 151 * filesystem overhead would have to be incurred in Dir_MTime, it made 152 * sense to replace the access() with a stat() and record the mtime 153 * in a cache for when Dir_MTime was actually called. */ 154 155 156 /* several data structures exist to handle caching of directory stuff. 157 * 158 * There is a global hash of directory names (knownDirectories), and each 159 * read directory is kept there as one PathEntry instance. Such a structure 160 * only contains the file names. 161 * 162 * There is a global hash of timestamps (modification times), so care must 163 * be taken of giving the right file names to that structure. 164 * 165 * XXX A set of similar structure should exist at the Target level to properly 166 * take care of VPATH issues. 167 */ 168 169 170 /* each directory is cached into a PathEntry structure. */ 171 struct PathEntry { 172 int refCount; /* ref-counted, can participate to 173 * several paths */ 174 struct ohash files; /* hash of name of files in the directory */ 175 char name[1]; /* directory name */ 176 }; 177 178 /* PathEntry kept on knownDirectories */ 179 static struct ohash_info dir_info = { 180 offsetof(struct PathEntry, name), NULL, hash_alloc, hash_free, 181 element_alloc 182 }; 183 184 static struct ohash knownDirectories; /* cache all open directories */ 185 186 187 /* file names kept in a path entry */ 188 static struct ohash_info file_info = { 189 0, NULL, hash_alloc, hash_free, element_alloc 190 }; 191 192 193 /* Global structure used to cache mtimes. XXX We don't cache an mtime 194 * before a caller actually looks up for the given time, because of the 195 * possibility a caller might update the file and invalidate the cache 196 * entry, and we don't look up in this cache except as a last resort. 197 */ 198 struct file_stamp { 199 TIMESTAMP mtime; /* time stamp... */ 200 char name[1]; /* ...for that file. */ 201 }; 202 203 static struct ohash mtimes; 204 205 206 static struct ohash_info stamp_info = { 207 offsetof(struct file_stamp, name), NULL, hash_alloc, hash_free, 208 element_alloc 209 }; 210 211 212 213 static LIST theDefaultPath; /* main search path */ 214 Lst defaultPath= &theDefaultPath; 215 struct PathEntry *dot; /* contents of current directory */ 216 217 218 219 /* add_file(path, name): add a file name to a path hash structure. */ 220 static void add_file(struct PathEntry *, const char *); 221 /* n = find_file_hashi(p, name, end, hv): retrieve name in a path hash 222 * structure. */ 223 static char *find_file_hashi(struct PathEntry *, const char *, const char *, 224 uint32_t); 225 226 /* stamp = find_stampi(name, end): look for (name, end) in the global 227 * cache. */ 228 static struct file_stamp *find_stampi(const char *, const char *); 229 /* record_stamp(name, timestamp): record timestamp for name in the global 230 * cache. */ 231 static void record_stamp(const char *, TIMESTAMP); 232 233 static bool read_directory(struct PathEntry *); 234 /* p = DirReaddiri(name, end): read an actual directory, caching results 235 * as we go. */ 236 static struct PathEntry *create_PathEntry(const char *, const char *); 237 /* Debugging: show a dir name in a path. */ 238 static void DirPrintDir(void *); 239 240 /*** 241 *** timestamp handling 242 ***/ 243 244 static void 245 record_stamp(const char *file, TIMESTAMP t) 246 { 247 unsigned int slot; 248 const char *end = NULL; 249 struct file_stamp *n; 250 251 slot = ohash_qlookupi(&mtimes, file, &end); 252 n = ohash_find(&mtimes, slot); 253 if (n) 254 n->mtime = t; 255 else { 256 n = ohash_create_entry(&stamp_info, file, &end); 257 n->mtime = t; 258 ohash_insert(&mtimes, slot, n); 259 } 260 } 261 262 static struct file_stamp * 263 find_stampi(const char *file, const char *efile) 264 { 265 return ohash_find(&mtimes, ohash_qlookupi(&mtimes, file, &efile)); 266 } 267 268 /*** 269 *** PathEntry handling 270 ***/ 271 272 static void 273 add_file(struct PathEntry *p, const char *file) 274 { 275 unsigned int slot; 276 const char *end = NULL; 277 char *n; 278 struct ohash *h = &p->files; 279 280 slot = ohash_qlookupi(h, file, &end); 281 n = ohash_find(h, slot); 282 if (n == NULL) { 283 n = ohash_create_entry(&file_info, file, &end); 284 ohash_insert(h, slot, n); 285 } 286 } 287 288 static char * 289 find_file_hashi(struct PathEntry *p, const char *file, const char *efile, 290 uint32_t hv) 291 { 292 struct ohash *h = &p->files; 293 294 return ohash_find(h, ohash_lookup_interval(h, file, efile, hv)); 295 } 296 297 static bool 298 read_directory(struct PathEntry *p) 299 { 300 DIR *d; 301 struct dirent *dp; 302 303 if (DEBUG(DIR)) { 304 printf("Caching %s...", p->name); 305 fflush(stdout); 306 } 307 308 if ((d = opendir(p->name)) == NULL) 309 return false; 310 311 ohash_init(&p->files, 4, &file_info); 312 313 while ((dp = readdir(d)) != NULL) { 314 if (dp->d_name[0] == '.' && 315 (dp->d_name[1] == '\0' || 316 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) 317 continue; 318 add_file(p, dp->d_name); 319 } 320 (void)closedir(d); 321 if (DEBUG(DIR)) 322 printf("done\n"); 323 return true; 324 } 325 326 /* Read a directory, either from the disk, or from the cache. */ 327 static struct PathEntry * 328 create_PathEntry(const char *name, const char *ename) 329 { 330 struct PathEntry *p; 331 unsigned int slot; 332 333 slot = ohash_qlookupi(&knownDirectories, name, &ename); 334 p = ohash_find(&knownDirectories, slot); 335 336 if (p == NULL) { 337 p = ohash_create_entry(&dir_info, name, &ename); 338 p->refCount = 0; 339 if (!read_directory(p)) { 340 free(p); 341 return NULL; 342 } 343 ohash_insert(&knownDirectories, slot, p); 344 } 345 p->refCount++; 346 return p; 347 } 348 349 char * 350 PathEntry_name(struct PathEntry *p) 351 { 352 return p->name; 353 } 354 355 /* Side Effects: cache the current directory */ 356 void 357 Dir_Init(void) 358 { 359 char *dotname = "."; 360 361 Static_Lst_Init(defaultPath); 362 ohash_init(&knownDirectories, 4, &dir_info); 363 ohash_init(&mtimes, 4, &stamp_info); 364 365 366 dot = create_PathEntry(dotname, dotname+1); 367 368 if (!dot) 369 Fatal("Can't access current directory"); 370 } 371 372 #ifdef CLEANUP 373 void 374 Dir_End(void) 375 { 376 struct PathEntry *p; 377 unsigned int i; 378 379 dot->refCount--; 380 Dir_Destroy(dot); 381 Lst_Destroy(defaultPath, Dir_Destroy); 382 for (p = ohash_first(&knownDirectories, &i); p != NULL; 383 p = ohash_next(&knownDirectories, &i)) 384 Dir_Destroy(p); 385 ohash_delete(&knownDirectories); 386 free_hash(&mtimes); 387 } 388 #endif 389 390 391 /*- 392 *----------------------------------------------------------------------- 393 * Dir_MatchFilesi -- 394 * Given a pattern and a PathEntry structure, see if any files 395 * match the pattern and add their names to the 'expansions' list if 396 * any do. This is incomplete -- it doesn't take care of patterns like 397 * src / *src / *.c properly (just *.c on any of the directories), but it 398 * will do for now. 399 *----------------------------------------------------------------------- 400 */ 401 void 402 Dir_MatchFilesi(const char *word, const char *eword, struct PathEntry *p, 403 Lst expansions) 404 { 405 unsigned int search; /* Index into the directory's table */ 406 const char *entry; /* Current entry in the table */ 407 408 for (entry = ohash_first(&p->files, &search); entry != NULL; 409 entry = ohash_next(&p->files, &search)) { 410 /* See if the file matches the given pattern. We follow the UNIX 411 * convention that dot files will only be found if the pattern 412 * begins with a dot (the hashing scheme doesn't hash . or .., 413 * so they won't match `.*'. */ 414 if (*word != '.' && *entry == '.') 415 continue; 416 if (Str_Matchi(entry, strchr(entry, '\0'), word, eword)) 417 Lst_AtEnd(expansions, 418 p == dot ? estrdup(entry) : 419 Str_concat(p->name, entry, '/')); 420 } 421 } 422 423 /*- 424 * Side Effects: 425 * If the file is found in a directory which is not on the path 426 * already (either 'name' is absolute or it is a relative path 427 * [ dir1/.../dirn/file ] which exists below one of the directories 428 * already on the search path), its directory is added to the end 429 * of the path on the assumption that there will be more files in 430 * that directory later on. 431 */ 432 char * 433 Dir_FindFileComplexi(const char *name, const char *ename, Lst path, 434 bool checkCurdirFirst) 435 { 436 struct PathEntry *p; /* current path member */ 437 char *p1; /* pointer into p->name */ 438 const char *p2; /* pointer into name */ 439 LstNode ln; /* a list element */ 440 char *file; /* the current filename to check */ 441 char *temp; /* index into file */ 442 const char *basename; 443 bool hasSlash; 444 struct stat stb;/* Buffer for stat, if necessary */ 445 struct file_stamp *entry; 446 /* Entry for mtimes table */ 447 uint32_t hv; /* hash value for last component in file name */ 448 char *q; /* Str_dupi(name, ename) */ 449 450 /* Find the final component of the name and note whether name has a 451 * slash in it */ 452 basename = Str_rchri(name, ename, '/'); 453 if (basename) { 454 hasSlash = true; 455 basename++; 456 } else { 457 hasSlash = false; 458 basename = name; 459 } 460 461 hv = ohash_interval(basename, &ename); 462 463 if (DEBUG(DIR)) 464 printf("Searching for %s...", name); 465 /* Unless checkCurDirFirst is false, we always look for 466 * the file in the current directory before anywhere else 467 * and we always return exactly what the caller specified. */ 468 if (checkCurdirFirst && 469 (!hasSlash || (basename - name == 2 && *name == '.')) && 470 find_file_hashi(dot, basename, ename, hv) != NULL) { 471 if (DEBUG(DIR)) 472 printf("in '.'\n"); 473 return Str_dupi(name, ename); 474 } 475 476 /* Then, we look through all the directories on path, seeking one 477 * containing the final component of name and whose final 478 * component(s) match name's initial component(s). 479 * If found, we concatenate the directory name and the 480 * final component and return the resulting string. */ 481 for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { 482 p = (struct PathEntry *)Lst_Datum(ln); 483 if (DEBUG(DIR)) 484 printf("%s...", p->name); 485 if (find_file_hashi(p, basename, ename, hv) != NULL) { 486 if (DEBUG(DIR)) 487 printf("here..."); 488 if (hasSlash) { 489 /* If the name had a slash, its initial 490 * components and p's final components must 491 * match. This is false if a mismatch is 492 * encountered before all of the initial 493 * components have been checked (p2 > name at 494 * the end of the loop), or we matched only 495 * part of one of the components of p along 496 * with all the rest of them (*p1 != '/'). */ 497 p1 = p->name + strlen(p->name) - 1; 498 p2 = basename - 2; 499 while (p2 >= name && p1 >= p->name && 500 *p1 == *p2) { 501 p1--; 502 p2--; 503 } 504 if (p2 >= name || 505 (p1 >= p->name && *p1 != '/')) { 506 if (DEBUG(DIR)) 507 printf("component mismatch -- continuing..."); 508 continue; 509 } 510 } 511 file = Str_concati(p->name, strchr(p->name, '\0'), basename, 512 ename, '/'); 513 if (DEBUG(DIR)) 514 printf("returning %s\n", file); 515 return file; 516 } else if (hasSlash) { 517 /* If the file has a leading path component and that 518 * component exactly matches the entire name of the 519 * current search directory, we assume the file 520 * doesn't exist and return NULL. */ 521 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; 522 p1++, p2++) 523 continue; 524 if (*p1 == '\0' && p2 == basename - 1) { 525 if (DEBUG(DIR)) 526 printf("has to be here but isn't -- returning NULL\n"); 527 return NULL; 528 } 529 } 530 } 531 532 /* We didn't find the file on any existing member of the path. 533 * If the name doesn't contain a slash, end of story. 534 * If it does contain a slash, however, it could be in a subdirectory 535 * of one of the members of the search path. (eg., for path=/usr/include 536 * and name=sys/types.h, the above search fails to turn up types.h 537 * in /usr/include, even though /usr/include/sys/types.h exists). 538 * 539 * We only perform this look-up for non-absolute file names. 540 * 541 * Whenever we score a hit, we assume there will be more matches from 542 * that directory, and append all but the last component of the 543 * resulting name onto the search path. */ 544 if (!hasSlash) { 545 if (DEBUG(DIR)) 546 printf("failed.\n"); 547 return NULL; 548 } 549 550 if (*name != '/') { 551 bool checkedDot = false; 552 553 if (DEBUG(DIR)) 554 printf("failed. Trying subdirectories..."); 555 for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { 556 p = (struct PathEntry *)Lst_Datum(ln); 557 if (p != dot) 558 file = Str_concati(p->name, 559 strchr(p->name, '\0'), name, ename, '/'); 560 else { 561 /* Checking in dot -- DON'T put a leading 562 * ./ on the thing. */ 563 file = Str_dupi(name, ename); 564 checkedDot = true; 565 } 566 if (DEBUG(DIR)) 567 printf("checking %s...", file); 568 569 if (stat(file, &stb) == 0) { 570 TIMESTAMP mtime; 571 572 ts_set_from_stat(stb, mtime); 573 if (DEBUG(DIR)) 574 printf("got it.\n"); 575 576 /* We've found another directory to search. 577 * We know there is a slash in 'file'. We 578 * call Dir_AddDiri to add the new directory 579 * onto the existing search path. Once that's 580 * done, we return the file name, knowing that 581 * should a file in this directory ever be 582 * referenced again in such a manner, we will 583 * find it without having to do numerous 584 * access calls. */ 585 temp = strrchr(file, '/'); 586 Dir_AddDiri(path, file, temp); 587 588 /* Save the modification time so if it's 589 * needed, we don't have to fetch it again. */ 590 if (DEBUG(DIR)) 591 printf("Caching %s for %s\n", 592 time_to_string(mtime), file); 593 record_stamp(file, mtime); 594 return file; 595 } else 596 free(file); 597 } 598 599 if (DEBUG(DIR)) 600 printf("failed. "); 601 602 if (checkedDot) { 603 /* Already checked by the given name, since . was in 604 * the path, so no point in proceeding... */ 605 if (DEBUG(DIR)) 606 printf("Checked . already, returning NULL\n"); 607 return NULL; 608 } 609 } 610 611 /* Didn't find it that way, either. Last resort: look for the file 612 * in the global mtime cache, then on the disk. 613 * If this doesn't succeed, we finally return a NULL pointer. 614 * 615 * We cannot add this directory onto the search path because 616 * of this amusing case: 617 * $(INSTALLDIR)/$(FILE): $(FILE) 618 * 619 * $(FILE) exists in $(INSTALLDIR) but not in the current one. 620 * When searching for $(FILE), we will find it in $(INSTALLDIR) 621 * b/c we added it here. This is not good... */ 622 q = Str_dupi(name, ename); 623 if (DEBUG(DIR)) 624 printf("Looking for \"%s\"...", q); 625 626 entry = find_stampi(name, ename); 627 if (entry != NULL) { 628 if (DEBUG(DIR)) 629 printf("got it (in mtime cache)\n"); 630 return q; 631 } else if (stat(q, &stb) == 0) { 632 TIMESTAMP mtime; 633 634 ts_set_from_stat(stb, mtime); 635 if (DEBUG(DIR)) 636 printf("Caching %s for %s\n", time_to_string(mtime), q); 637 record_stamp(q, mtime); 638 return q; 639 } else { 640 if (DEBUG(DIR)) 641 printf("failed. Returning NULL\n"); 642 free(q); 643 return NULL; 644 } 645 } 646 647 void 648 Dir_AddDiri(Lst path, const char *name, const char *ename) 649 { 650 struct PathEntry *p; 651 652 p = create_PathEntry(name, ename); 653 if (p == NULL) 654 return; 655 if (p->refCount == 1) 656 Lst_AtEnd(path, p); 657 else if (!Lst_AddNew(path, p)) 658 return; 659 } 660 661 void * 662 Dir_CopyDir(void *p) 663 { 664 ((struct PathEntry *)p)->refCount++; 665 return p; 666 } 667 668 /*- 669 *----------------------------------------------------------------------- 670 * Dir_MakeFlags -- 671 * Make a string by taking all the directories in the given search 672 * path and preceding them by the given flag. Used by the suffix 673 * module to create variables for compilers based on suffix search 674 * paths. 675 * 676 * Results: 677 * The string mentioned above. Note that there is no space between 678 * the given flag and each directory. The empty string is returned if 679 * Things don't go well. 680 *----------------------------------------------------------------------- 681 */ 682 char * 683 Dir_MakeFlags(const char *flag, Lst path) 684 { 685 LstNode ln; 686 BUFFER buf; 687 688 Buf_Init(&buf, 0); 689 690 for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { 691 Buf_AddString(&buf, flag); 692 Buf_AddString(&buf, ((struct PathEntry *)Lst_Datum(ln))->name); 693 Buf_AddSpace(&buf); 694 } 695 696 return Buf_Retrieve(&buf); 697 } 698 699 void 700 Dir_Destroy(void *pp) 701 { 702 struct PathEntry *p = (struct PathEntry *)pp; 703 704 if (--p->refCount == 0) { 705 ohash_remove(&knownDirectories, 706 ohash_qlookup(&knownDirectories, p->name)); 707 free_hash(&p->files); 708 free(p); 709 } 710 } 711 712 /*- 713 *----------------------------------------------------------------------- 714 * Dir_Concat -- 715 * Concatenate two paths, adding the second to the end of the first. 716 * Makes sure to avoid duplicates. 717 * 718 * Side Effects: 719 * Reference counts for added dirs are upped. 720 *----------------------------------------------------------------------- 721 */ 722 void 723 Dir_Concat(Lst path1, Lst path2) 724 { 725 LstNode ln; 726 struct PathEntry *p; 727 728 for (ln = Lst_First(path2); ln != NULL; ln = Lst_Adv(ln)) { 729 p = (struct PathEntry *)Lst_Datum(ln); 730 if (Lst_AddNew(path1, p)) 731 p->refCount++; 732 } 733 } 734 735 static void 736 DirPrintDir(void *p) 737 { 738 printf("%s ", ((struct PathEntry *)p)->name); 739 } 740 741 void 742 Dir_PrintPath(Lst path) 743 { 744 Lst_Every(path, DirPrintDir); 745 } 746 747 TIMESTAMP 748 Dir_MTime(GNode *gn) 749 { 750 char *fullName; 751 struct stat stb; 752 struct file_stamp *entry; 753 unsigned int slot; 754 TIMESTAMP mtime; 755 756 if (gn->type & OP_PHONY) 757 return gn->mtime; 758 759 if (gn->type & OP_ARCHV) 760 return Arch_MTime(gn); 761 762 if (gn->path == NULL) { 763 fullName = Dir_FindFile(gn->name, defaultPath); 764 if (fullName == NULL) 765 fullName = estrdup(gn->name); 766 } else 767 fullName = gn->path; 768 769 slot = ohash_qlookup(&mtimes, fullName); 770 entry = ohash_find(&mtimes, slot); 771 if (entry != NULL) { 772 /* Only do this once -- the second time folks are checking to 773 * see if the file was actually updated, so we need to 774 * actually go to the file system. */ 775 if (DEBUG(DIR)) 776 printf("Using cached time %s for %s\n", 777 time_to_string(entry->mtime), fullName); 778 mtime = entry->mtime; 779 free(entry); 780 ohash_remove(&mtimes, slot); 781 } else if (stat(fullName, &stb) == 0) 782 ts_set_from_stat(stb, mtime); 783 else { 784 if (gn->type & OP_MEMBER) { 785 if (fullName != gn->path) 786 free(fullName); 787 return Arch_MemMTime(gn); 788 } else 789 ts_set_out_of_date(mtime); 790 } 791 if (fullName && gn->path == NULL) 792 gn->path = fullName; 793 794 gn->mtime = mtime; 795 return gn->mtime; 796 } 797 798