| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: dir.c,v 1.210 2020/11/14 21:29:44 rillig Exp $ */ | | 1 | /* $NetBSD: dir.c,v 1.211 2020/11/23 18:24:05 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -124,27 +124,27 @@ | | | @@ -124,27 +124,27 @@ |
124 | */ | | 124 | */ |
125 | | | 125 | |
126 | #include <sys/types.h> | | 126 | #include <sys/types.h> |
127 | #include <sys/stat.h> | | 127 | #include <sys/stat.h> |
128 | | | 128 | |
129 | #include <dirent.h> | | 129 | #include <dirent.h> |
130 | #include <errno.h> | | 130 | #include <errno.h> |
131 | | | 131 | |
132 | #include "make.h" | | 132 | #include "make.h" |
133 | #include "dir.h" | | 133 | #include "dir.h" |
134 | #include "job.h" | | 134 | #include "job.h" |
135 | | | 135 | |
136 | /* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */ | | 136 | /* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */ |
137 | MAKE_RCSID("$NetBSD: dir.c,v 1.210 2020/11/14 21:29:44 rillig Exp $"); | | 137 | MAKE_RCSID("$NetBSD: dir.c,v 1.211 2020/11/23 18:24:05 rillig Exp $"); |
138 | | | 138 | |
139 | #define DIR_DEBUG0(text) DEBUG0(DIR, text) | | 139 | #define DIR_DEBUG0(text) DEBUG0(DIR, text) |
140 | #define DIR_DEBUG1(fmt, arg1) DEBUG1(DIR, fmt, arg1) | | 140 | #define DIR_DEBUG1(fmt, arg1) DEBUG1(DIR, fmt, arg1) |
141 | #define DIR_DEBUG2(fmt, arg1, arg2) DEBUG2(DIR, fmt, arg1, arg2) | | 141 | #define DIR_DEBUG2(fmt, arg1, arg2) DEBUG2(DIR, fmt, arg1, arg2) |
142 | | | 142 | |
143 | /* A search path is a list of CachedDir structures. A CachedDir has in it the | | 143 | /* A search path is a list of CachedDir structures. A CachedDir has in it the |
144 | * name of the directory and the names of all the files in the directory. | | 144 | * name of the directory and the names of all the files in the directory. |
145 | * This is used to cut down on the number of system calls necessary to find | | 145 | * This is used to cut down on the number of system calls necessary to find |
146 | * implicit dependents and their like. Since these searches are made before | | 146 | * implicit dependents and their like. Since these searches are made before |
147 | * any actions are taken, we need not worry about the directory changing due | | 147 | * any actions are taken, we need not worry about the directory changing due |
148 | * to creation commands. If this hampers the style of some makefiles, they | | 148 | * to creation commands. If this hampers the style of some makefiles, they |
149 | * must be changed. | | 149 | * must be changed. |
150 | * | | 150 | * |
| @@ -369,27 +369,27 @@ Dir_Init(void) | | | @@ -369,27 +369,27 @@ Dir_Init(void) |
369 | HashTable_Init(&mtimes); | | 369 | HashTable_Init(&mtimes); |
370 | HashTable_Init(&lmtimes); | | 370 | HashTable_Init(&lmtimes); |
371 | } | | 371 | } |
372 | | | 372 | |
373 | void | | 373 | void |
374 | Dir_InitDir(const char *cdname) | | 374 | Dir_InitDir(const char *cdname) |
375 | { | | 375 | { |
376 | Dir_InitCur(cdname); | | 376 | Dir_InitCur(cdname); |
377 | | | 377 | |
378 | dotLast = bmake_malloc(sizeof *dotLast); | | 378 | dotLast = bmake_malloc(sizeof *dotLast); |
379 | dotLast->refCount = 1; | | 379 | dotLast->refCount = 1; |
380 | dotLast->hits = 0; | | 380 | dotLast->hits = 0; |
381 | dotLast->name = bmake_strdup(".DOTLAST"); | | 381 | dotLast->name = bmake_strdup(".DOTLAST"); |
382 | HashTable_Init(&dotLast->files); | | 382 | HashSet_Init(&dotLast->files); |
383 | } | | 383 | } |
384 | | | 384 | |
385 | /* | | 385 | /* |
386 | * Called by Dir_InitDir and whenever .CURDIR is assigned to. | | 386 | * Called by Dir_InitDir and whenever .CURDIR is assigned to. |
387 | */ | | 387 | */ |
388 | void | | 388 | void |
389 | Dir_InitCur(const char *cdname) | | 389 | Dir_InitCur(const char *cdname) |
390 | { | | 390 | { |
391 | CachedDir *dir; | | 391 | CachedDir *dir; |
392 | | | 392 | |
393 | if (cdname == NULL) | | 393 | if (cdname == NULL) |
394 | return; | | 394 | return; |
395 | | | 395 | |
| @@ -563,27 +563,27 @@ Dir_HasWildcards(const char *name) | | | @@ -563,27 +563,27 @@ Dir_HasWildcards(const char *name) |
563 | * dir Directory to search | | 563 | * dir Directory to search |
564 | * expansion Place to store the results | | 564 | * expansion Place to store the results |
565 | */ | | 565 | */ |
566 | static void | | 566 | static void |
567 | DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions) | | 567 | DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions) |
568 | { | | 568 | { |
569 | const char *dirName = dir->name; | | 569 | const char *dirName = dir->name; |
570 | Boolean isDot = dirName[0] == '.' && dirName[1] == '\0'; | | 570 | Boolean isDot = dirName[0] == '.' && dirName[1] == '\0'; |
571 | HashIter hi; | | 571 | HashIter hi; |
572 | | | 572 | |
573 | /* XXX: Iterating over all hash entries is inefficient. If the pattern | | 573 | /* XXX: Iterating over all hash entries is inefficient. If the pattern |
574 | * is a plain string without any wildcards, a direct lookup is faster. */ | | 574 | * is a plain string without any wildcards, a direct lookup is faster. */ |
575 | | | 575 | |
576 | HashIter_Init(&hi, &dir->files); | | 576 | HashIter_InitSet(&hi, &dir->files); |
577 | while (HashIter_Next(&hi) != NULL) { | | 577 | while (HashIter_Next(&hi) != NULL) { |
578 | const char *base = hi.entry->key; | | 578 | const char *base = hi.entry->key; |
579 | | | 579 | |
580 | if (!Str_Match(base, pattern)) | | 580 | if (!Str_Match(base, pattern)) |
581 | continue; | | 581 | continue; |
582 | | | 582 | |
583 | /* | | 583 | /* |
584 | * Follow the UNIX convention that dot files are only found if the | | 584 | * Follow the UNIX convention that dot files are only found if the |
585 | * pattern begins with a dot. The pattern '.*' does not match '.' or | | 585 | * pattern begins with a dot. The pattern '.*' does not match '.' or |
586 | * '..' since these are not included in the directory cache. | | 586 | * '..' since these are not included in the directory cache. |
587 | * | | 587 | * |
588 | * This means that the pattern '[a-z.]*' does not find '.file', which | | 588 | * This means that the pattern '[a-z.]*' does not find '.file', which |
589 | * is consistent with bash, NetBSD sh and csh. | | 589 | * is consistent with bash, NetBSD sh and csh. |
| @@ -838,27 +838,27 @@ Dir_Expand(const char *word, SearchPath | | | @@ -838,27 +838,27 @@ Dir_Expand(const char *word, SearchPath |
838 | if (DEBUG(DIR)) | | 838 | if (DEBUG(DIR)) |
839 | PrintExpansions(expansions); | | 839 | PrintExpansions(expansions); |
840 | } | | 840 | } |
841 | | | 841 | |
842 | /* Find if the file with the given name exists in the given path. | | 842 | /* Find if the file with the given name exists in the given path. |
843 | * Return the freshly allocated path to the file, or NULL. */ | | 843 | * Return the freshly allocated path to the file, or NULL. */ |
844 | static char * | | 844 | static char * |
845 | DirLookup(CachedDir *dir, const char *base) | | 845 | DirLookup(CachedDir *dir, const char *base) |
846 | { | | 846 | { |
847 | char *file; /* the current filename to check */ | | 847 | char *file; /* the current filename to check */ |
848 | | | 848 | |
849 | DIR_DEBUG1(" %s ...\n", dir->name); | | 849 | DIR_DEBUG1(" %s ...\n", dir->name); |
850 | | | 850 | |
851 | if (HashTable_FindEntry(&dir->files, base) == NULL) | | 851 | if (!HashSet_Contains(&dir->files, base)) |
852 | return NULL; | | 852 | return NULL; |
853 | | | 853 | |
854 | file = str_concat3(dir->name, "/", base); | | 854 | file = str_concat3(dir->name, "/", base); |
855 | DIR_DEBUG1(" returning %s\n", file); | | 855 | DIR_DEBUG1(" returning %s\n", file); |
856 | dir->hits++; | | 856 | dir->hits++; |
857 | hits++; | | 857 | hits++; |
858 | return file; | | 858 | return file; |
859 | } | | 859 | } |
860 | | | 860 | |
861 | | | 861 | |
862 | /* Find if the file with the given name exists in the given directory. | | 862 | /* Find if the file with the given name exists in the given directory. |
863 | * Return the freshly allocated path to the file, or NULL. */ | | 863 | * Return the freshly allocated path to the file, or NULL. */ |
864 | static char * | | 864 | static char * |
| @@ -891,51 +891,51 @@ DirLookupAbs(CachedDir *dir, const char | | | @@ -891,51 +891,51 @@ DirLookupAbs(CachedDir *dir, const char |
891 | DIR_DEBUG1(" %s ...\n", dir->name); | | 891 | DIR_DEBUG1(" %s ...\n", dir->name); |
892 | | | 892 | |
893 | /* | | 893 | /* |
894 | * If the file has a leading path component and that component | | 894 | * If the file has a leading path component and that component |
895 | * exactly matches the entire name of the current search | | 895 | * exactly matches the entire name of the current search |
896 | * directory, we can attempt another cache lookup. And if we don't | | 896 | * directory, we can attempt another cache lookup. And if we don't |
897 | * have a hit, we can safely assume the file does not exist at all. | | 897 | * have a hit, we can safely assume the file does not exist at all. |
898 | */ | | 898 | */ |
899 | for (dnp = dir->name, np = name; *dnp != '\0' && *dnp == *np; dnp++, np++) | | 899 | for (dnp = dir->name, np = name; *dnp != '\0' && *dnp == *np; dnp++, np++) |
900 | continue; | | 900 | continue; |
901 | if (*dnp != '\0' || np != cp - 1) | | 901 | if (*dnp != '\0' || np != cp - 1) |
902 | return NULL; | | 902 | return NULL; |
903 | | | 903 | |
904 | if (HashTable_FindEntry(&dir->files, cp) == NULL) { | | 904 | if (!HashSet_Contains(&dir->files, cp)) { |
905 | DIR_DEBUG0(" must be here but isn't -- returning\n"); | | 905 | DIR_DEBUG0(" must be here but isn't -- returning\n"); |
906 | return bmake_strdup(""); /* to terminate the search */ | | 906 | return bmake_strdup(""); /* to terminate the search */ |
907 | } | | 907 | } |
908 | | | 908 | |
909 | dir->hits++; | | 909 | dir->hits++; |
910 | hits++; | | 910 | hits++; |
911 | DIR_DEBUG1(" returning %s\n", name); | | 911 | DIR_DEBUG1(" returning %s\n", name); |
912 | return bmake_strdup(name); | | 912 | return bmake_strdup(name); |
913 | } | | 913 | } |
914 | | | 914 | |
915 | /* Find the file given on "." or curdir. | | 915 | /* Find the file given on "." or curdir. |
916 | * Return the freshly allocated path to the file, or NULL. */ | | 916 | * Return the freshly allocated path to the file, or NULL. */ |
917 | static char * | | 917 | static char * |
918 | DirFindDot(const char *name, const char *base) | | 918 | DirFindDot(const char *name, const char *base) |
919 | { | | 919 | { |
920 | | | 920 | |
921 | if (HashTable_FindEntry(&dot->files, base) != NULL) { | | 921 | if (HashSet_Contains(&dot->files, base)) { |
922 | DIR_DEBUG0(" in '.'\n"); | | 922 | DIR_DEBUG0(" in '.'\n"); |
923 | hits++; | | 923 | hits++; |
924 | dot->hits++; | | 924 | dot->hits++; |
925 | return bmake_strdup(name); | | 925 | return bmake_strdup(name); |
926 | } | | 926 | } |
927 | | | 927 | |
928 | if (cur != NULL && HashTable_FindEntry(&cur->files, base) != NULL) { | | 928 | if (cur != NULL && HashSet_Contains(&cur->files, base)) { |
929 | DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); | | 929 | DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); |
930 | hits++; | | 930 | hits++; |
931 | cur->hits++; | | 931 | cur->hits++; |
932 | return str_concat3(cur->name, "/", base); | | 932 | return str_concat3(cur->name, "/", base); |
933 | } | | 933 | } |
934 | | | 934 | |
935 | return NULL; | | 935 | return NULL; |
936 | } | | 936 | } |
937 | | | 937 | |
938 | /* Find the file with the given name along the given search path. | | 938 | /* Find the file with the given name along the given search path. |
939 | * | | 939 | * |
940 | * If the file is found in a directory that is not on the path | | 940 | * If the file is found in a directory that is not on the path |
941 | * already (either 'name' is absolute or it is a relative path | | 941 | * already (either 'name' is absolute or it is a relative path |
| @@ -1380,40 +1380,40 @@ Dir_AddDir(SearchPath *path, const char | | | @@ -1380,40 +1380,40 @@ Dir_AddDir(SearchPath *path, const char |
1380 | dir->refCount++; | | 1380 | dir->refCount++; |
1381 | Lst_Append(path, dir); | | 1381 | Lst_Append(path, dir); |
1382 | } | | 1382 | } |
1383 | return dir; | | 1383 | return dir; |
1384 | } | | 1384 | } |
1385 | | | 1385 | |
1386 | DIR_DEBUG1("Caching %s ...", name); | | 1386 | DIR_DEBUG1("Caching %s ...", name); |
1387 | | | 1387 | |
1388 | if ((d = opendir(name)) != NULL) { | | 1388 | if ((d = opendir(name)) != NULL) { |
1389 | dir = bmake_malloc(sizeof *dir); | | 1389 | dir = bmake_malloc(sizeof *dir); |
1390 | dir->name = bmake_strdup(name); | | 1390 | dir->name = bmake_strdup(name); |
1391 | dir->hits = 0; | | 1391 | dir->hits = 0; |
1392 | dir->refCount = 1; | | 1392 | dir->refCount = 1; |
1393 | HashTable_Init(&dir->files); | | 1393 | HashSet_Init(&dir->files); |
1394 | | | 1394 | |
1395 | while ((dp = readdir(d)) != NULL) { | | 1395 | while ((dp = readdir(d)) != NULL) { |
1396 | #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ | | 1396 | #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ |
1397 | /* | | 1397 | /* |
1398 | * The sun directory library doesn't check for a 0 inode | | 1398 | * The sun directory library doesn't check for a 0 inode |
1399 | * (0-inode slots just take up space), so we have to do | | 1399 | * (0-inode slots just take up space), so we have to do |
1400 | * it ourselves. | | 1400 | * it ourselves. |
1401 | */ | | 1401 | */ |
1402 | if (dp->d_fileno == 0) { | | 1402 | if (dp->d_fileno == 0) { |
1403 | continue; | | 1403 | continue; |
1404 | } | | 1404 | } |
1405 | #endif /* sun && d_ino */ | | 1405 | #endif /* sun && d_ino */ |
1406 | (void)HashTable_CreateEntry(&dir->files, dp->d_name, NULL); | | 1406 | (void)HashSet_Add(&dir->files, dp->d_name); |
1407 | } | | 1407 | } |
1408 | (void)closedir(d); | | 1408 | (void)closedir(d); |
1409 | OpenDirs_Add(&openDirs, dir); | | 1409 | OpenDirs_Add(&openDirs, dir); |
1410 | if (path != NULL) | | 1410 | if (path != NULL) |
1411 | Lst_Append(path, dir); | | 1411 | Lst_Append(path, dir); |
1412 | } | | 1412 | } |
1413 | DIR_DEBUG0("done\n"); | | 1413 | DIR_DEBUG0("done\n"); |
1414 | return dir; | | 1414 | return dir; |
1415 | } | | 1415 | } |
1416 | | | 1416 | |
1417 | /* Return a copy of dirSearchPath, incrementing the reference counts for | | 1417 | /* Return a copy of dirSearchPath, incrementing the reference counts for |
1418 | * the contained directories. */ | | 1418 | * the contained directories. */ |
1419 | SearchPath * | | 1419 | SearchPath * |
| @@ -1475,27 +1475,27 @@ Dir_MakeFlags(const char *flag, SearchPa | | | @@ -1475,27 +1475,27 @@ Dir_MakeFlags(const char *flag, SearchPa |
1475 | * | | 1475 | * |
1476 | * Input: | | 1476 | * Input: |
1477 | * dirp The directory descriptor to nuke | | 1477 | * dirp The directory descriptor to nuke |
1478 | */ | | 1478 | */ |
1479 | void | | 1479 | void |
1480 | Dir_Destroy(void *dirp) | | 1480 | Dir_Destroy(void *dirp) |
1481 | { | | 1481 | { |
1482 | CachedDir *dir = dirp; | | 1482 | CachedDir *dir = dirp; |
1483 | dir->refCount--; | | 1483 | dir->refCount--; |
1484 | | | 1484 | |
1485 | if (dir->refCount == 0) { | | 1485 | if (dir->refCount == 0) { |
1486 | OpenDirs_Remove(&openDirs, dir->name); | | 1486 | OpenDirs_Remove(&openDirs, dir->name); |
1487 | | | 1487 | |
1488 | HashTable_Done(&dir->files); | | 1488 | HashSet_Done(&dir->files); |
1489 | free(dir->name); | | 1489 | free(dir->name); |
1490 | free(dir); | | 1490 | free(dir); |
1491 | } | | 1491 | } |
1492 | } | | 1492 | } |
1493 | | | 1493 | |
1494 | /* Clear out all elements from the given search path. | | 1494 | /* Clear out all elements from the given search path. |
1495 | * The path is set to the empty list but is not destroyed. */ | | 1495 | * The path is set to the empty list but is not destroyed. */ |
1496 | void | | 1496 | void |
1497 | Dir_ClearPath(SearchPath *path) | | 1497 | Dir_ClearPath(SearchPath *path) |
1498 | { | | 1498 | { |
1499 | while (!Lst_IsEmpty(path)) { | | 1499 | while (!Lst_IsEmpty(path)) { |
1500 | CachedDir *dir = Lst_Dequeue(path); | | 1500 | CachedDir *dir = Lst_Dequeue(path); |
1501 | Dir_Destroy(dir); | | 1501 | Dir_Destroy(dir); |