1
/* $NetBSD: dir.c,v 1.20 1997/09/28 03:31:02 lukem Exp $ */
1
/* $NetBSD: dir.c,v 1.40 2004/02/03 19:25:29 chuck Exp $ */
4
4
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
7
* This code is derived from software contributed to Berkeley by
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
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.
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
5
36
* Copyright (c) 1988, 1989 by Adam de Boor
6
37
* Copyright (c) 1989 by Berkeley Softworks
7
38
* All rights reserved.
198
244
* should be ok, but... */
201
static int DirFindName __P((ClientData, ClientData));
202
static int DirMatchFiles __P((char *, Path *, Lst));
203
static void DirExpandCurly __P((char *, char *, Lst, Lst));
204
static void DirExpandInt __P((char *, Lst, Lst));
205
static int DirPrintWord __P((ClientData, ClientData));
206
static int DirPrintDir __P((ClientData, ClientData));
207
static char *DirLookup __P((Path *, char *, char *, Boolean));
208
static char *DirLookupSubdir __P((Path *, char *));
247
static int DirFindName(ClientData, ClientData);
248
static int DirMatchFiles(const char *, Path *, Lst);
249
static void DirExpandCurly(const char *, const char *, Lst, Lst);
250
static void DirExpandInt(const char *, Lst, Lst);
251
static int DirPrintWord(ClientData, ClientData);
252
static int DirPrintDir(ClientData, ClientData);
253
static char *DirLookup(Path *, const char *, const char *, Boolean);
254
static char *DirLookupSubdir(Path *, const char *);
255
static char *DirFindDot(Boolean, const char *, const char *);
256
static char *DirLookupAbs(Path *, const char *, const char *);
211
259
*-----------------------------------------------------------------------
220
268
*-----------------------------------------------------------------------
271
Dir_Init (const char *cdname)
226
273
dirSearchPath = Lst_Init (FALSE);
227
274
openDirectories = Lst_Init (FALSE);
228
275
Hash_InitTable(&mtimes, 0);
231
* Since the Path structure is placed on both openDirectories and
232
* the path we give Dir_AddDir (which in this case is openDirectories),
233
* we need to remove "." from openDirectories and what better time to
234
* do it than when we have to fetch the thing anyway?
279
dotLast = (Path *) emalloc (sizeof (Path));
280
dotLast->refCount = 1;
282
dotLast->name = estrdup(".DOTLAST");
283
Hash_InitTable (&dotLast->files, -1);
287
* Called by Dir_Init() and whenever .CURDIR is assigned to.
290
Dir_InitCur (const char *cdname)
294
if (cdname != NULL) {
296
* Our build directory is not the same as our source directory.
297
* Keep this one around too.
299
if ((p = Dir_AddDir(NULL, cdname))) {
301
if (cur && cur != p) {
303
* We've been here before, cleanup.
306
Dir_Destroy((ClientData) cur);
314
*-----------------------------------------------------------------------
316
* (re)initialize "dot" (current/object directory) path hash
322
* some directories may be opened.
323
*-----------------------------------------------------------------------
331
/* Remove old entry from openDirectories, but do not destroy. */
332
ln = Lst_Member (openDirectories, (ClientData)dot);
333
(void) Lst_Remove (openDirectories, ln);
236
336
dot = Dir_AddDir (NULL, ".");
339
Error("Cannot open `.' (%s)", strerror(errno));
239
344
* We always need to have dot around, so we increment its reference count
240
345
* to make sure it's not destroyed.
242
347
dot->refCount += 1;
244
if (cdname != NULL) {
246
* Our build directory is not the same as our source directory.
247
* Keep this one around too.
249
cur = Dir_AddDir (NULL, cdname);
348
Dir_SetPATH(); /* initialize */
264
361
*-----------------------------------------------------------------------
270
368
cur->refCount -= 1;
271
369
Dir_Destroy((ClientData) cur);
273
371
dot->refCount -= 1;
372
dotLast->refCount -= 1;
373
Dir_Destroy((ClientData) dotLast);
274
374
Dir_Destroy((ClientData) dot);
275
375
Dir_ClearPath(dirSearchPath);
276
376
Lst_Destroy(dirSearchPath, NOFREE);
277
377
Dir_ClearPath(openDirectories);
278
378
Lst_Destroy(openDirectories, NOFREE);
279
379
Hash_DeleteTable(&mtimes);
384
* We want ${.PATH} to indicate the order in which we will actually
385
* search, so we rebuild it after any .PATH: target.
386
* This is the simplest way to deal with the effect of .DOTLAST.
391
LstNode ln; /* a list element */
393
Boolean hasLastDot = FALSE; /* true we should search dot last */
395
Var_Delete(".PATH", VAR_GLOBAL);
397
if (Lst_Open (dirSearchPath) == SUCCESS) {
398
if ((ln = Lst_First (dirSearchPath)) != NILLNODE) {
399
p = (Path *) Lst_Datum (ln);
402
Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
408
Var_Append(".PATH", dot->name, VAR_GLOBAL);
410
Var_Append(".PATH", cur->name, VAR_GLOBAL);
413
while ((ln = Lst_Next (dirSearchPath)) != NILLNODE) {
414
p = (Path *) Lst_Datum (ln);
417
if (p == dot && hasLastDot)
419
Var_Append(".PATH", p->name, VAR_GLOBAL);
424
Var_Append(".PATH", dot->name, VAR_GLOBAL);
426
Var_Append(".PATH", cur->name, VAR_GLOBAL);
428
Lst_Close(dirSearchPath);
421
583
*-----------------------------------------------------------------------
424
DirExpandCurly(word, brace, path, expansions)
425
char *word; /* Entire word to expand */
426
char *brace; /* First curly brace in it */
427
Lst path; /* Search path to use */
428
Lst expansions; /* Place to store the expansions */
586
DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions)
430
char *end; /* Character after the closing brace */
431
char *cp; /* Current position in brace clause */
432
char *start; /* Start of current piece of brace clause */
588
const char *end; /* Character after the closing brace */
589
const char *cp; /* Current position in brace clause */
590
const char *start; /* Start of current piece of brace clause */
433
591
int bracelevel; /* Number of braces we've seen. If we see a
434
592
* right brace when this is 0, we've hit the
435
593
* end of the clause. */
436
char *file; /* Current expansion */
594
char *file; /* Current expansion */
437
595
int otherLen; /* The length of the other pieces of the
438
596
* expansion (chars before and after the
439
597
* clause in 'word') */
440
char *cp2; /* Pointer for checking for wildcards in
598
char *cp2; /* Pointer for checking for wildcards in
441
599
* expansion before calling Dir_Expand */
702
860
*-----------------------------------------------------------------------
705
DirLookup(p, name, cp, hasSlash)
863
DirLookup(Path *p, const char *name, const char *cp, Boolean hasSlash)
711
char *p1; /* pointer into p->name */
712
char *p2; /* pointer into name */
713
865
char *file; /* the current filename to check */
715
867
if (DEBUG(DIR)) {
716
printf("%s...", p->name);
718
if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {
724
* If the name had a slash, its initial components and p's
725
* final components must match. This is false if a mismatch
726
* is encountered before all of the initial components
727
* have been checked (p2 > name at the end of the loop), or
728
* we matched only part of one of the components of p
729
* along with all the rest of them (*p1 != '/').
731
p1 = p->name + strlen (p->name) - 1;
733
while (p2 >= name && p1 >= p->name && *p1 == *p2) {
736
if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
738
printf("component mismatch -- continuing...");
743
file = str_concat (p->name, cp, STR_ADDSLASH);
745
printf("returning %s\n", file);
750
} else if (hasSlash) {
752
* If the file has a leading path component and that component
753
* exactly matches the entire name of the current search
754
* directory, we assume the file doesn't exist and return NULL.
756
for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
759
if (*p1 == '\0' && p2 == cp - 1) {
761
printf("must be here but isn't -- returing\n");
868
printf(" %s ...\n", p->name);
871
if (Hash_FindEntry (&p->files, cp) == (Hash_Entry *)NULL)
874
file = str_concat (p->name, cp, STR_ADDSLASH);
876
printf(" returning %s\n", file);
830
938
*-----------------------------------------------------------------------
940
* Find if the file with the given name exists in the given path.
943
* The path to the file, the empty string or NULL. If the file is
944
* the empty string, the search should be terminated.
945
* This path is guaranteed to be in a different part of memory
946
* than name and so may be safely free'd.
950
*-----------------------------------------------------------------------
953
DirLookupAbs(Path *p, const char *name, const char *cp)
955
char *p1; /* pointer into p->name */
956
const char *p2; /* pointer into name */
959
printf(" %s ...\n", p->name);
963
* If the file has a leading path component and that component
964
* exactly matches the entire name of the current search
965
* directory, we can attempt another cache lookup. And if we don't
966
* have a hit, we can safely assume the file does not exist at all.
968
for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
971
if (*p1 != '\0' || p2 != cp - 1) {
975
if (Hash_FindEntry (&p->files, cp) == (Hash_Entry *)NULL) {
977
printf(" must be here but isn't -- returning\n");
979
/* Return empty string: terminates search */
986
printf(" returning %s\n", name);
988
return (estrdup (name));
992
*-----------------------------------------------------------------------
994
* Find the file given on "." or curdir
997
* The path to the file or NULL. This path is guaranteed to be in a
998
* different part of memory than name and so may be safely free'd.
1002
*-----------------------------------------------------------------------
1005
DirFindDot(Boolean hasSlash, const char *name, const char *cp)
1008
if (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL) {
1010
printf(" in '.'\n");
1014
return (estrdup (name));
1017
Hash_FindEntry (&cur->files, cp) != (Hash_Entry *)NULL) {
1019
printf(" in ${.CURDIR} = %s\n", cur->name);
1023
return str_concat (cur->name, cp, STR_ADDSLASH);
1030
*-----------------------------------------------------------------------
831
1031
* Dir_FindFile --
832
1032
* Find the file with the given name along the given search path.
1035
* name the file to find
1036
* path the Lst of directories to search
835
1039
* The path to the file or NULL. This path is guaranteed to be in a
836
1040
* different part of memory than name and so may be safely free'd.
845
1049
*-----------------------------------------------------------------------
848
Dir_FindFile (name, path)
849
char *name; /* the file to find */
850
Lst path; /* the Lst of directories to search */
1052
Dir_FindFile(const char *name, Lst path)
852
LstNode ln; /* a list element */
853
register char *file; /* the current filename to check */
854
register Path *p; /* current path member */
855
register char *cp; /* index of first slash, if any */
856
Boolean hasSlash; /* true if 'name' contains a / */
857
struct stat stb; /* Buffer for stat, if necessary */
858
Hash_Entry *entry; /* Entry for mtimes table */
1054
LstNode ln; /* a list element */
1055
char *file; /* the current filename to check */
1056
Path *p; /* current path member */
1057
const char *cp; /* index of first slash, if any */
1058
Boolean hasLastDot = FALSE; /* true we should search dot last */
1059
Boolean hasSlash; /* true if 'name' contains a / */
1060
struct stat stb; /* Buffer for stat, if necessary */
1061
Hash_Entry *entry; /* Entry for mtimes table */
861
1064
* Find the final component of the name and note whether it has a
907
1085
return ((char *) NULL);
910
if (cur && (file = DirLookup(cur, name, cp, hasSlash)) != NULL) {
1088
if ((ln = Lst_First (path)) != NILLNODE) {
1089
p = (Path *) Lst_Datum (ln);
1093
printf("[dot last]...");
918
* We look through all the directories on the path seeking one which
919
* contains the final component of the given name and whose final
920
* component(s) match the name's initial component(s). If such a beast
921
* is found, we concatenate the directory name and the final component
922
* and return the resulting string. If we don't find any such thing,
923
* we go on to phase two...
1101
* If there's no leading directory components or if the leading
1102
* directory component is exactly `./', consult the cached contents
1103
* of each of the directories on the search path.
925
while ((ln = Lst_Next (path)) != NILLNODE) {
926
p = (Path *) Lst_Datum (ln);
927
if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
1105
if ((!hasSlash || (cp - name == 2 && *name == '.'))) {
1107
* We look through all the directories on the path seeking one which
1108
* contains the final component of the given name. If such a beast
1109
* is found, we concatenate the directory name and the final
1110
* component and return the resulting string. If we don't find any
1111
* such thing, we go on to phase two...
1113
* No matter what, we always look for the file in the current
1114
* directory before anywhere else (unless we found the magic
1115
* DOTLAST path, in which case we search it last) and we *do not*
1116
* add the ./ to it if it exists.
1117
* This is so there are no conflicts between what the user
1118
* specifies (fish.c) and what pmake finds (./fish.c).
1121
(file = DirFindDot(hasSlash, name, cp)) != NULL) {
1126
while ((ln = Lst_Next (path)) != NILLNODE) {
1127
p = (Path *) Lst_Datum (ln);
1130
if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) {
1137
(file = DirFindDot(hasSlash, name, cp)) != NULL) {
937
* We didn't find the file on any existing members of the directory.
1145
* We didn't find the file on any directory in the search path.
938
1146
* If the name doesn't contain a slash, that means it doesn't exist.
939
1147
* If it *does* contain a slash, however, there is still hope: it
940
1148
* could be in a subdirectory of one of the members of the search
941
1149
* path. (eg. /usr/include and sys/types.h. The above search would
942
1150
* fail to turn up types.h in /usr/include, but it *is* in
943
* /usr/include/sys/types.h) If we find such a beast, we assume there
1151
* /usr/include/sys/types.h).
1152
* [ This no longer applies: If we find such a beast, we assume there
944
1153
* will be more (what else can we assume?) and add all but the last
945
1154
* component of the resulting name onto the search path (at the
946
* end). This phase is only performed if the file is *not* absolute.
1156
* This phase is only performed if the file is *not* absolute.
948
1158
if (!hasSlash) {
949
1159
if (DEBUG(DIR)) {
1160
printf(" failed.\n");
953
1163
return ((char *) NULL);
1166
if (name[0] != '/') {
957
1167
Boolean checkedDot = FALSE;
959
1169
if (DEBUG(DIR)) {
960
printf("failed. Trying subdirectories...");
1170
printf(" Trying subdirectories...\n");
963
if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1176
if ((file = DirLookupSubdir(dot, name)) != NULL)
1179
if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
966
1183
(void) Lst_Open (path);
967
1184
while ((ln = Lst_Next (path)) != NILLNODE) {
968
1185
p = (Path *) Lst_Datum (ln);
970
1191
checkedDot = TRUE;
971
1193
if ((file = DirLookupSubdir(p, name)) != NULL) {
972
1194
Lst_Close (path);
980
1198
Lst_Close (path);
1201
if (dot && !checkedDot) {
1203
if ((file = DirLookupSubdir(dot, name)) != NULL)
1206
if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
982
1210
if (checkedDot) {
984
1212
* Already checked by the given name, since . was in the path,
985
1213
* so no point in proceeding...
987
1215
if (DEBUG(DIR)) {
988
printf("Checked . already, returning NULL\n");
1216
printf(" Checked . already, returning NULL\n");
1221
} else { /* name[0] == '/' */
1224
* For absolute names, compare directory path prefix against the
1225
* the directory path of each member on the search path for an exact
1226
* match. If we have an exact match on any member of the search path,
1227
* use the cached contents of that member to lookup the final file
1228
* component. If that lookup fails we can safely assume that the
1229
* file does not exist at all. This is signified by DirLookupAbs()
1230
* returning an empty string.
1233
printf(" Trying exact path matches...\n");
1236
if (!hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL)
1237
return *file?file:NULL;
1239
(void) Lst_Open (path);
1240
while ((ln = Lst_Next (path)) != NILLNODE) {
1241
p = (Path *) Lst_Datum (ln);
1244
if ((file = DirLookupAbs(p, name, cp)) != NULL) {
1246
return *file?file:NULL;
1251
if (hasLastDot && cur && (file = DirLookupAbs(cur, name, cp)) != NULL)
1252
return *file?file:NULL;
1029
1290
#else /* !notdef */
1030
1291
if (DEBUG(DIR)) {
1031
printf("Looking for \"%s\"...", name);
1292
printf(" Looking for \"%s\" ...\n", name);
1034
1295
bigmisses += 1;
1035
1296
entry = Hash_FindEntry(&mtimes, name);
1036
1297
if (entry != (Hash_Entry *)NULL) {
1037
1298
if (DEBUG(DIR)) {
1038
printf("got it (in mtime cache)\n");
1299
printf(" got it (in mtime cache)\n");
1040
1301
return(estrdup(name));
1041
1302
} else if (stat (name, &stb) == 0) {
1042
1303
entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);
1043
1304
if (DEBUG(DIR)) {
1044
printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
1305
printf(" Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
1047
1308
Hash_SetValue(entry, (long)stb.st_mtime);
1048
1309
return (estrdup (name));
1050
1311
if (DEBUG(DIR)) {
1051
printf("failed. Returning NULL\n");
1312
printf(" failed. Returning NULL\n");
1053
1314
return ((char *)NULL);
1055
1316
#endif /* notdef */
1321
*-----------------------------------------------------------------------
1322
* Dir_FindHereOrAbove --
1323
* search for a path starting at a given directory and then working
1324
* our way up towards the root.
1327
* here starting directory
1328
* search_path the path we are looking for
1329
* result the result of a successful search is placed here
1330
* rlen the length of the result buffer
1331
* (typically MAXPATHLEN + 1)
1334
* 0 on failure, 1 on success [in which case the found path is put
1335
* in the result buffer].
1338
*-----------------------------------------------------------------------
1341
Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) {
1344
char dirbase[MAXPATHLEN + 1], *db_end;
1345
char try[MAXPATHLEN + 1], *try_end;
1347
/* copy out our starting point */
1348
snprintf(dirbase, sizeof(dirbase), "%s", here);
1349
db_end = dirbase + strlen(dirbase);
1351
/* loop until we determine a result */
1354
/* try and stat(2) it ... */
1355
snprintf(try, sizeof(try), "%s/%s", dirbase, search_path);
1356
if (stat(try, &st) != -1) {
1358
* success! if we found a file, chop off
1359
* the filename so we return a directory.
1361
if ((st.st_mode & S_IFMT) != S_IFDIR) {
1362
try_end = try + strlen(try);
1363
while (try_end > try && *try_end != '/')
1366
*try_end = 0; /* chop! */
1372
snprintf(result, rlen, "%s", try);
1377
* nope, we didn't find it. if we used up dirbase we've
1378
* reached the root and failed.
1380
if (db_end == dirbase)
1381
break; /* failed! */
1384
* truncate dirbase from the end to move up a dir
1386
while (db_end > dirbase && *db_end != '/')
1388
*db_end = 0; /* chop! */
1059
1399
*-----------------------------------------------------------------------
1061
1401
* Find the modification time of the file described by gn along the
1062
1402
* search path dirSearchPath.
1405
* gn the file whose modification time is desired
1065
1408
* The modification time or 0 if it doesn't exist
1140
1489
*-----------------------------------------------------------------------
1143
Dir_AddDir (path, name)
1144
Lst path; /* the path to which the directory should be
1146
const char *name; /* the name of the directory to add */
1492
Dir_AddDir(Lst path, const char *name)
1148
LstNode ln; /* node in case Path structure is found */
1149
register Path *p = NULL; /* pointer to new Path structure */
1494
LstNode ln = NILLNODE; /* node in case Path structure is found */
1495
Path *p = NULL; /* pointer to new Path structure */
1150
1496
DIR *d; /* for reading directory */
1151
register struct dirent *dp; /* entry in directory */
1153
ln = Lst_Find (openDirectories, (ClientData)name, DirFindName);
1497
struct dirent *dp; /* entry in directory */
1499
if (strcmp(name, ".DOTLAST") == 0) {
1500
ln = Lst_Find (path, (ClientData)UNCONST(name), DirFindName);
1502
return (Path *) Lst_Datum(ln);
1504
dotLast->refCount += 1;
1505
(void)Lst_AtFront(path, (ClientData)dotLast);
1510
ln = Lst_Find (openDirectories, (ClientData)UNCONST(name), DirFindName);
1154
1511
if (ln != NILLNODE) {
1155
1512
p = (Path *)Lst_Datum (ln);
1156
1513
if (Lst_Member(path, (ClientData)p) == NILLNODE) {