version 1.52, 2007/09/16 14:29:33 |
version 1.53, 2007/09/17 09:28:36 |
|
|
* possibility a caller might update the file and invalidate the cache |
* possibility a caller might update the file and invalidate the cache |
* entry, and we don't look up in this cache except as a last resort. |
* entry, and we don't look up in this cache except as a last resort. |
*/ |
*/ |
static struct ohash mtimes; |
static struct ohash mtimes; |
|
|
|
|
/* There are three distinct hash structures: |
/* There are three distinct hash structures: |
* - to collate files's last modification times (global mtimes) |
* - to collate files's last modification times (global mtimes) |
* - to collate file names (in each PathEntry structure) |
* - to collate file names (in each PathEntry structure) |
* - to collate known directories (global knownDirectories). */ |
* - to collate known directories (global knownDirectories). */ |
static struct ohash_info stamp_info = { |
static struct ohash_info stamp_info = { |
offsetof(struct file_stamp, name), NULL, hash_alloc, hash_free, |
offsetof(struct file_stamp, name), NULL, hash_alloc, hash_free, |
element_alloc }; |
element_alloc }; |
|
|
static struct ohash_info file_info = { |
static struct ohash_info file_info = { |
0, NULL, hash_alloc, hash_free, element_alloc }; |
0, NULL, hash_alloc, hash_free, element_alloc }; |
|
|
static struct ohash_info dir_info = { |
static struct ohash_info dir_info = { |
offsetof(struct PathEntry, name), NULL, |
offsetof(struct PathEntry, name), NULL, |
hash_alloc, hash_free, element_alloc }; |
hash_alloc, hash_free, element_alloc }; |
|
|
/* add_file(path, name): add a file name to a path hash structure. */ |
/* add_file(path, name): add a file name to a path hash structure. */ |
static void add_file(struct PathEntry *, const char *); |
static void add_file(struct PathEntry *, const char *); |
/* n = find_file_hashi(p, name, end, hv): retrieve name in a path hash |
/* n = find_file_hashi(p, name, end, hv): retrieve name in a path hash |
* structure. */ |
* structure. */ |
static char *find_file_hashi(struct PathEntry *, const char *, const char *, |
static char *find_file_hashi(struct PathEntry *, const char *, const char *, |
uint32_t); |
uint32_t); |
|
|
/* stamp = find_stampi(name, end): look for (name, end) in the global |
/* stamp = find_stampi(name, end): look for (name, end) in the global |
|
|
} |
} |
|
|
static char * |
static char * |
find_file_hashi(struct PathEntry *p, const char *file, const char *efile, |
find_file_hashi(struct PathEntry *p, const char *file, const char *efile, |
uint32_t hv) |
uint32_t hv) |
{ |
{ |
struct ohash *h = &p->files; |
struct ohash *h = &p->files; |
|
|
if (!dot) |
if (!dot) |
Fatal("Can't access current directory"); |
Fatal("Can't access current directory"); |
|
|
/* We always need to have dot around, so we increment its reference |
/* We always need to have dot around, so we increment its reference |
* count to make sure it won't be destroyed. */ |
* count to make sure it won't be destroyed. */ |
dot->refCount++; |
dot->refCount++; |
} |
} |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Dir_MatchFilesi(const char *word, const char *eword, struct PathEntry *p, |
Dir_MatchFilesi(const char *word, const char *eword, struct PathEntry *p, |
Lst expansions) |
Lst expansions) |
{ |
{ |
unsigned int search; /* Index into the directory's table */ |
unsigned int search; /* Index into the directory's table */ |
|
|
if (*word != '.' && *entry == '.') |
if (*word != '.' && *entry == '.') |
continue; |
continue; |
if (Str_Matchi(entry, strchr(entry, '\0'), word, eword)) |
if (Str_Matchi(entry, strchr(entry, '\0'), word, eword)) |
Lst_AtEnd(expansions, |
Lst_AtEnd(expansions, |
isDot ? estrdup(entry) : |
isDot ? estrdup(entry) : |
Str_concat(p->name, entry, '/')); |
Str_concat(p->name, entry, '/')); |
} |
} |
} |
} |
|
|
* [ dir1/.../dirn/file ] which exists below one of the directories |
* [ dir1/.../dirn/file ] which exists below one of the directories |
* already on the search path), its directory is added to the end |
* already on the search path), its directory is added to the end |
* of the path on the assumption that there will be more files in |
* of the path on the assumption that there will be more files in |
* that directory later on. |
* that directory later on. |
*/ |
*/ |
char * |
char * |
Dir_FindFileComplexi(const char *name, const char *ename, Lst path, |
Dir_FindFileComplexi(const char *name, const char *ename, Lst path, |
bool checkCurdirFirst) |
bool checkCurdirFirst) |
{ |
{ |
struct PathEntry *p; /* current path member */ |
struct PathEntry *p; /* current path member */ |
|
|
const char *cp; /* index of first slash, if any */ |
const char *cp; /* index of first slash, if any */ |
bool hasSlash; |
bool hasSlash; |
struct stat stb;/* Buffer for stat, if necessary */ |
struct stat stb;/* Buffer for stat, if necessary */ |
struct file_stamp *entry; |
struct file_stamp *entry; |
/* Entry for mtimes table */ |
/* Entry for mtimes table */ |
uint32_t hv; /* hash value for last component in file name */ |
uint32_t hv; /* hash value for last component in file name */ |
char *q; /* Str_dupi(name, ename) */ |
char *q; /* Str_dupi(name, ename) */ |
|
|
|
|
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("Searching for %s...", name); |
printf("Searching for %s...", name); |
/* Unless checkCurDirFirst is false, we always look for |
/* Unless checkCurDirFirst is false, we always look for |
* the file in the current directory before anywhere else |
* the file in the current directory before anywhere else |
* and we always return exactly what the caller specified. */ |
* and we always return exactly what the caller specified. */ |
if (checkCurdirFirst && |
if (checkCurdirFirst && |
(!hasSlash || (cp - name == 2 && *name == '.')) && |
(!hasSlash || (cp - name == 2 && *name == '.')) && |
find_file_hashi(dot, cp, ename, hv) != NULL) { |
find_file_hashi(dot, cp, ename, hv) != NULL) { |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
|
|
return Str_dupi(name, ename); |
return Str_dupi(name, ename); |
} |
} |
|
|
/* Then, we look through all the directories on path, seeking one |
/* Then, we look through all the directories on path, seeking one |
* containing the final component of name and whose final |
* containing the final component of name and whose final |
* component(s) match name's initial component(s). |
* component(s) match name's initial component(s). |
* If found, we concatenate the directory name and the |
* If found, we concatenate the directory name and the |
* final component and return the resulting string. */ |
* final component and return the resulting string. */ |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
p = (struct PathEntry *)Lst_Datum(ln); |
p = (struct PathEntry *)Lst_Datum(ln); |
|
|
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("here..."); |
printf("here..."); |
if (hasSlash) { |
if (hasSlash) { |
/* If the name had a slash, its initial |
/* If the name had a slash, its initial |
* components and p's final components must |
* components and p's final components must |
* match. This is false if a mismatch is |
* match. This is false if a mismatch is |
* encountered before all of the initial |
* encountered before all of the initial |
* components have been checked (p2 > name at |
* components have been checked (p2 > name at |
* the end of the loop), or we matched only |
* the end of the loop), or we matched only |
* part of one of the components of p along |
* part of one of the components of p along |
* with all the rest of them (*p1 != '/'). */ |
* with all the rest of them (*p1 != '/'). */ |
p1 = p->name + strlen(p->name) - 1; |
p1 = p->name + strlen(p->name) - 1; |
p2 = cp - 2; |
p2 = cp - 2; |
while (p2 >= name && p1 >= p->name && |
while (p2 >= name && p1 >= p->name && |
*p1 == *p2) { |
*p1 == *p2) { |
p1--; |
p1--; |
p2--; |
p2--; |
} |
} |
if (p2 >= name || |
if (p2 >= name || |
(p1 >= p->name && *p1 != '/')) { |
(p1 >= p->name && *p1 != '/')) { |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("component mismatch -- continuing..."); |
printf("component mismatch -- continuing..."); |
continue; |
continue; |
} |
} |
} |
} |
file = Str_concati(p->name, strchr(p->name, '\0'), cp, |
file = Str_concati(p->name, strchr(p->name, '\0'), cp, |
ename, '/'); |
ename, '/'); |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("returning %s\n", file); |
printf("returning %s\n", file); |
return file; |
return file; |
} else if (hasSlash) { |
} else if (hasSlash) { |
/* If the file has a leading path component and that |
/* If the file has a leading path component and that |
* component exactly matches the entire name of the |
* component exactly matches the entire name of the |
* current search directory, we assume the file |
* current search directory, we assume the file |
* doesn't exist and return NULL. */ |
* doesn't exist and return NULL. */ |
for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; |
for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; |
p1++, p2++) |
p1++, p2++) |
continue; |
continue; |
if (*p1 == '\0' && p2 == cp - 1) { |
if (*p1 == '\0' && p2 == cp - 1) { |
|
|
|
|
/* We didn't find the file on any existing member of the path. |
/* We didn't find the file on any existing member of the path. |
* If the name doesn't contain a slash, end of story. |
* If the name doesn't contain a slash, end of story. |
* If it does contain a slash, however, it could be in a subdirectory |
* If it does contain a slash, however, it could be in a subdirectory |
* of one of the members of the search path. (eg., for path=/usr/include |
* of one of the members of the search path. (eg., for path=/usr/include |
* and name=sys/types.h, the above search fails to turn up types.h |
* and name=sys/types.h, the above search fails to turn up types.h |
* in /usr/include, even though /usr/include/sys/types.h exists). |
* in /usr/include, even though /usr/include/sys/types.h exists). |
* |
* |
* We only perform this look-up for non-absolute file names. |
* We only perform this look-up for non-absolute file names. |
* |
* |
* Whenever we score a hit, we assume there will be more matches from |
* Whenever we score a hit, we assume there will be more matches from |
* that directory, and append all but the last component of the |
* that directory, and append all but the last component of the |
* resulting name onto the search path. */ |
* resulting name onto the search path. */ |
if (!hasSlash) { |
if (!hasSlash) { |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
|
|
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) { |
p = (struct PathEntry *)Lst_Datum(ln); |
p = (struct PathEntry *)Lst_Datum(ln); |
if (p != dot) |
if (p != dot) |
file = Str_concati(p->name, |
file = Str_concati(p->name, |
strchr(p->name, '\0'), name, ename, '/'); |
strchr(p->name, '\0'), name, ename, '/'); |
else { |
else { |
/* Checking in dot -- DON'T put a leading |
/* Checking in dot -- DON'T put a leading |
* ./ on the thing. */ |
* ./ on the thing. */ |
file = Str_dupi(name, ename); |
file = Str_dupi(name, ename); |
checkedDot = true; |
checkedDot = true; |
|
|
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("got it.\n"); |
printf("got it.\n"); |
|
|
/* We've found another directory to search. |
/* We've found another directory to search. |
* We know there is a slash in 'file'. We |
* We know there is a slash in 'file'. We |
* call Dir_AddDiri to add the new directory |
* call Dir_AddDiri to add the new directory |
* onto the existing search path. Once that's |
* onto the existing search path. Once that's |
* done, we return the file name, knowing that |
* done, we return the file name, knowing that |
* should a file in this directory ever be |
* should a file in this directory ever be |
* referenced again in such a manner, we will |
* referenced again in such a manner, we will |
* find it without having to do numerous |
* find it without having to do numerous |
* access calls. */ |
* access calls. */ |
temp = strrchr(file, '/'); |
temp = strrchr(file, '/'); |
Dir_AddDiri(path, file, temp); |
Dir_AddDiri(path, file, temp); |
|
|
/* Save the modification time so if it's |
/* Save the modification time so if it's |
* needed, we don't have to fetch it again. */ |
* needed, we don't have to fetch it again. */ |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("Caching %s for %s\n", |
printf("Caching %s for %s\n", |
time_to_string(mtime), file); |
time_to_string(mtime), file); |
record_stamp(file, mtime); |
record_stamp(file, mtime); |
return file; |
return file; |
|
|
printf("failed. "); |
printf("failed. "); |
|
|
if (checkedDot) { |
if (checkedDot) { |
/* Already checked by the given name, since . was in |
/* Already checked by the given name, since . was in |
* the path, so no point in proceeding... */ |
* the path, so no point in proceeding... */ |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("Checked . already, returning NULL\n"); |
printf("Checked . already, returning NULL\n"); |
|
|
return NULL; |
return NULL; |
|
|
while ((dp = readdir(d)) != NULL) { |
while ((dp = readdir(d)) != NULL) { |
if (dp->d_name[0] == '.' && |
if (dp->d_name[0] == '.' && |
(dp->d_name[1] == '\0' || |
(dp->d_name[1] == '\0' || |
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) |
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) |
continue; |
continue; |
add_file(p, dp->d_name); |
add_file(p, dp->d_name); |
|
|
struct PathEntry *p = (struct PathEntry *)pp; |
struct PathEntry *p = (struct PathEntry *)pp; |
|
|
if (--p->refCount == 0) { |
if (--p->refCount == 0) { |
ohash_remove(&knownDirectories, |
ohash_remove(&knownDirectories, |
ohash_qlookup(&knownDirectories, p->name)); |
ohash_qlookup(&knownDirectories, p->name)); |
free_hash(&p->files); |
free_hash(&p->files); |
free(p); |
free(p); |
|
|
entry = ohash_find(&mtimes, slot); |
entry = ohash_find(&mtimes, slot); |
if (entry != NULL) { |
if (entry != NULL) { |
/* Only do this once -- the second time folks are checking to |
/* Only do this once -- the second time folks are checking to |
* see if the file was actually updated, so we need to |
* see if the file was actually updated, so we need to |
* actually go to the file system. */ |
* actually go to the file system. */ |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("Using cached time %s for %s\n", |
printf("Using cached time %s for %s\n", |