version 1.24, 2000/09/14 13:32:06 |
version 1.25, 2000/09/14 13:43:30 |
|
|
* Dir_PrintDirectories Print stats about the directory cache. |
* Dir_PrintDirectories Print stats about the directory cache. |
*/ |
*/ |
|
|
|
#include <stddef.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <sys/types.h> |
#include <sys/types.h> |
#include <dirent.h> |
#include <dirent.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include "make.h" |
#include "make.h" |
#include "hash.h" |
#include "hash.h" |
|
#include "ohash.h" |
#include "dir.h" |
#include "dir.h" |
|
|
#ifndef lint |
#ifndef lint |
|
|
* hampers the style of some makefiles, they must be changed. |
* hampers the style of some makefiles, they must be changed. |
* |
* |
* A list of all previously-read directories is kept in the |
* A list of all previously-read directories is kept in the |
* openDirectories Lst. This list is checked first before a directory |
* openDirectories cache. |
* is opened. |
|
* |
* |
* The need for the caching of whole directories is brought about by |
* The need for the caching of whole directories is brought about by |
* the multi-level transformation code in suff.c, which tends to search |
* the multi-level transformation code in suff.c, which tends to search |
|
|
|
|
LIST dirSearchPath; /* main search path */ |
LIST dirSearchPath; /* main search path */ |
|
|
static LIST openDirectories; /* the list of all open directories */ |
static struct hash openDirectories; /* cache all open directories */ |
|
|
/* |
/* |
* Variables for gathering statistics on the efficiency of the hashing |
* Variables for gathering statistics on the efficiency of the hashing |
|
|
* be two rules to update a single file, so this |
* be two rules to update a single file, so this |
* should be ok, but... */ |
* should be ok, but... */ |
|
|
|
static struct hash_info dir_info = { offsetof(Path, name), |
|
NULL, hash_alloc, hash_free, element_alloc }; |
|
|
static int DirFindName __P((void *, void *)); |
static Path *DirReaddir __P((const char *, const char *)); |
static int DirMatchFiles __P((char *, Path *, Lst)); |
static int DirMatchFiles __P((char *, Path *, Lst)); |
static void DirExpandCurly __P((char *, char *, Lst, Lst)); |
static void DirExpandCurly __P((char *, char *, Lst, Lst)); |
static void DirExpandInt __P((char *, Lst, Lst)); |
static void DirExpandInt __P((char *, Lst, Lst)); |
|
|
Dir_Init() |
Dir_Init() |
{ |
{ |
Lst_Init(&dirSearchPath); |
Lst_Init(&dirSearchPath); |
Lst_Init(&openDirectories); |
hash_init(&openDirectories, 4, &dir_info); |
Hash_InitTable(&mtimes, 0); |
Hash_InitTable(&mtimes, 0); |
|
|
/* |
dot = DirReaddir(".", NULL); |
* Since the Path structure is placed on both openDirectories and |
|
* the path we give Dir_AddDir (which in this case is openDirectories), |
|
* we need to remove "." from openDirectories and what better time to |
|
* do it than when we have to fetch the thing anyway? |
|
*/ |
|
Dir_AddDir(&openDirectories, "."); |
|
dot = (Path *)Lst_DeQueue(&openDirectories); |
|
|
|
/* |
/* We always need to have dot around, so we increment its reference count |
* We always need to have dot around, so we increment its reference count |
* to make sure it's not destroyed. */ |
* to make sure it's not destroyed. |
dot->refCount++; |
*/ |
|
dot->refCount += 1; |
|
} |
} |
|
|
/*- |
/*- |
|
|
Dir_End() |
Dir_End() |
{ |
{ |
#ifdef CLEANUP |
#ifdef CLEANUP |
dot->refCount -= 1; |
struct Path *p; |
|
unsigned int i; |
|
|
|
dot->refCount--; |
Dir_Destroy(dot); |
Dir_Destroy(dot); |
Dir_ClearPath(&dirSearchPath); |
Lst_Destroy(&dirSearchPath, Dir_Destroy); |
Lst_Destroy(&dirSearchPath, NOFREE); |
for (p = hash_first(&openDirectories, &i); p != NULL; |
Dir_ClearPath(&openDirectories); |
p = hash_next(&openDirectories, &i)) |
Lst_Destroy(&openDirectories, NOFREE); |
Dir_Destroy(p); |
|
hash_delete(&openDirectories); |
Hash_DeleteTable(&mtimes); |
Hash_DeleteTable(&mtimes); |
#endif |
#endif |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* DirFindName -- |
|
* See if the Path structure describes the same directory as the |
|
* given one by comparing their names. Called from Dir_AddDir via |
|
* Lst_Find when searching the list of open directories. |
|
* |
|
* Results: |
|
* 0 if it is the same. Non-zero otherwise |
|
* |
|
* Side Effects: |
|
* None |
|
*----------------------------------------------------------------------- |
|
*/ |
|
static int |
|
DirFindName (p, dname) |
|
void *p; /* Current name */ |
|
void *dname; /* Desired name */ |
|
{ |
|
return strcmp(((Path *)p)->name, (char *)dname); |
|
} |
|
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Dir_HasWildcards -- |
* Dir_HasWildcards -- |
* see if the given name has any wildcard characters in it |
* see if the given name has any wildcard characters in it |
* be careful not to expand unmatching brackets or braces. |
* be careful not to expand unmatching brackets or braces. |
|
|
if (*dp == '/') |
if (*dp == '/') |
*dp = '\0'; |
*dp = '\0'; |
Lst_Init(&temp); |
Lst_Init(&temp); |
Dir_AddDir(&temp, dirpath); |
Dir_AddDir(&temp, dirpath, NULL); |
DirExpandInt(cp+1, &temp, expansions); |
DirExpandInt(cp+1, &temp, expansions); |
Lst_Destroy(&temp, NOFREE); |
Lst_Destroy(&temp, NOFREE); |
} |
} |
|
|
* again in such a manner, we will find it without having to do |
* again in such a manner, we will find it without having to do |
* numerous numbers of access calls. Hurrah! |
* numerous numbers of access calls. Hurrah! |
*/ |
*/ |
cp = strrchr (file, '/'); |
cp = strrchr(file, '/'); |
*cp = '\0'; |
Dir_AddDir(path, file, cp); |
Dir_AddDir (path, file); |
|
*cp = '/'; |
|
|
|
/* |
/* |
* Save the modification time so if it's needed, we don't have |
* Save the modification time so if it's needed, we don't have |
|
|
* b/c we added it here. This is not good... |
* b/c we added it here. This is not good... |
*/ |
*/ |
#ifdef notdef |
#ifdef notdef |
cp[-1] = '\0'; |
Dir_AddDir(path, name, cp-1); |
Dir_AddDir (path, name); |
|
cp[-1] = '/'; |
|
|
|
bigmisses += 1; |
bigmisses += 1; |
ln = Lst_Last(path); |
ln = Lst_Last(path); |
|
|
return exists; |
return exists; |
} |
} |
|
|
|
/* Read a directory, either from the disk, or from the cache. */ |
|
static Path * |
|
DirReaddir(name, end) |
|
const char *name; |
|
const char *end; |
|
{ |
|
Path *p; /* pointer to new Path structure */ |
|
DIR *d; /* for reading directory */ |
|
struct dirent *dp; /* entry in directory */ |
|
unsigned int slot; |
|
|
|
slot = hash_qlookupi(&openDirectories, name, &end); |
|
p = hash_find(&openDirectories, slot); |
|
|
|
if (p != NULL) |
|
return p; |
|
|
|
p = hash_create_entry(&dir_info, name, &end); |
|
p->hits = 0; |
|
p->refCount = 0; |
|
Hash_InitTable(&p->files, -1); |
|
|
|
if (DEBUG(DIR)) { |
|
printf("Caching %s...", p->name); |
|
fflush(stdout); |
|
} |
|
|
|
if ((d = opendir(p->name)) == NULL) |
|
return NULL; |
|
/* Skip the first two entries -- these will *always* be . and .. */ |
|
(void)readdir(d); |
|
(void)readdir(d); |
|
|
|
while ((dp = readdir(d)) != NULL) { |
|
#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ |
|
/* The sun directory library doesn't check for a 0 inode |
|
* (0-inode slots just take up space), so we have to do |
|
* it ourselves. */ |
|
if (dp->d_fileno == 0) |
|
continue; |
|
#endif /* sun && d_ino */ |
|
(void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL); |
|
} |
|
(void)closedir(d); |
|
if (DEBUG(DIR)) |
|
printf("done\n"); |
|
|
|
hash_insert(&openDirectories, slot, p); |
|
return p; |
|
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Dir_AddDir -- |
* Dir_AddDir -- |
|
|
* the arguments is backwards so ParseDoDependency can do a |
* the arguments is backwards so ParseDoDependency can do a |
* Lst_ForEach of its list of paths... |
* Lst_ForEach of its list of paths... |
* |
* |
* Results: |
|
* none |
|
* |
|
* Side Effects: |
* Side Effects: |
* A structure is added to the list and the directory is |
* A structure is added to the list and the directory is |
* read and hashed. |
* read and hashed. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Dir_AddDir (path, name) |
Dir_AddDir(path, name, end) |
Lst path; /* the path to which the directory should be |
Lst path; /* the path to which the directory should be |
* added */ |
* added */ |
char *name; /* the name of the directory to add */ |
const char *name; /* the name of the directory to add */ |
|
const char *end; |
{ |
{ |
LstNode ln; /* node in case Path structure is found */ |
Path *p; /* pointer to new Path structure */ |
register Path *p; /* pointer to new Path structure */ |
|
DIR *d; /* for reading directory */ |
|
register struct dirent *dp; /* entry in directory */ |
|
|
|
ln = Lst_Find(&openDirectories, DirFindName, name); |
p = DirReaddir(name, end); |
if (ln != NULL) { |
if (p == NULL) |
p = (Path *)Lst_Datum(ln); |
return; |
if (Lst_Member(path, p) == NULL) { |
if (p->refCount == 0) |
p->refCount += 1; |
Lst_AtEnd(path, p); |
Lst_AtEnd(path, p); |
else if (Lst_Member(path, p) != NULL) |
} |
return; |
} else { |
else |
if (DEBUG(DIR)) { |
Lst_AtEnd(path, p); |
printf("Caching %s...", name); |
p->refCount++; |
fflush(stdout); |
|
} |
|
|
|
if ((d = opendir (name)) != (DIR *) NULL) { |
|
p = (Path *) emalloc (sizeof (Path)); |
|
p->name = estrdup (name); |
|
p->hits = 0; |
|
p->refCount = 1; |
|
Hash_InitTable (&p->files, -1); |
|
|
|
/* |
|
* Skip the first two entries -- these will *always* be . and .. |
|
*/ |
|
(void)readdir(d); |
|
(void)readdir(d); |
|
|
|
while ((dp = readdir (d)) != (struct dirent *) NULL) { |
|
#if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ |
|
/* |
|
* The sun directory library doesn't check for a 0 inode |
|
* (0-inode slots just take up space), so we have to do |
|
* it ourselves. |
|
*/ |
|
if (dp->d_fileno == 0) { |
|
continue; |
|
} |
|
#endif /* sun && d_ino */ |
|
(void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL); |
|
} |
|
(void) closedir (d); |
|
Lst_AtEnd(&openDirectories, p); |
|
Lst_AtEnd(path, p); |
|
} |
|
if (DEBUG(DIR)) { |
|
printf("done\n"); |
|
} |
|
} |
|
} |
} |
|
|
/*- |
/*- |
|
|
void *pp; /* The directory descriptor to nuke */ |
void *pp; /* The directory descriptor to nuke */ |
{ |
{ |
Path *p = (Path *) pp; |
Path *p = (Path *) pp; |
p->refCount -= 1; |
|
|
|
if (p->refCount == 0) { |
if (--p->refCount == 0) { |
LstNode ln; |
hash_remove(&openDirectories, hash_qlookup(&openDirectories, p->name)); |
|
|
ln = Lst_Member(&openDirectories, p); |
|
Lst_Remove(&openDirectories, ln); |
|
|
|
Hash_DeleteTable (&p->files); |
Hash_DeleteTable (&p->files); |
free(p->name); |
|
free(p); |
free(p); |
} |
} |
} |
} |
|
|
void |
void |
Dir_PrintDirectories() |
Dir_PrintDirectories() |
{ |
{ |
LstNode ln; |
|
Path *p; |
Path *p; |
|
unsigned int i; |
|
|
printf ("#*** Directory Cache:\n"); |
printf ("#*** Directory Cache:\n"); |
printf ("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", |
printf ("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", |
|
|
(hits+bigmisses+nearmisses ? |
(hits+bigmisses+nearmisses ? |
hits * 100 / (hits + bigmisses + nearmisses) : 0)); |
hits * 100 / (hits + bigmisses + nearmisses) : 0)); |
printf ("# %-20s referenced\thits\n", "directory"); |
printf ("# %-20s referenced\thits\n", "directory"); |
Lst_Open(&openDirectories); |
for (p = hash_first(&openDirectories, &i); p != NULL; |
while ((ln = Lst_Next(&openDirectories)) != NULL) { |
p = hash_next(&openDirectories, &i)) |
p = (Path *)Lst_Datum(ln); |
printf("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); |
printf("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); |
|
} |
|
Lst_Close(&openDirectories); |
|
} |
} |
|
|
static void |
static void |