version 1.26, 2000/09/14 13:46:44 |
version 1.27, 2000/09/14 13:52:41 |
|
|
#include <dirent.h> |
#include <dirent.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include "make.h" |
#include "make.h" |
#include "hash.h" |
|
#include "ohash.h" |
#include "ohash.h" |
#include "dir.h" |
#include "dir.h" |
|
|
|
|
bigmisses; /* Sought by itself */ |
bigmisses; /* Sought by itself */ |
|
|
static Path *dot; /* contents of current directory */ |
static Path *dot; /* contents of current directory */ |
static Hash_Table mtimes; /* Results of doing a last-resort stat in |
|
|
struct file_stamp { |
|
TIMESTAMP mtime; /* time stamp... */ |
|
char name[1]; /* ...for that file. */ |
|
}; |
|
|
|
static struct hash mtimes; /* Results of doing a last-resort stat in |
* Dir_FindFile -- if we have to go to the |
* Dir_FindFile -- if we have to go to the |
* system to find the file, we might as well |
* system to find the file, we might as well |
* have its mtime on record. XXX: If this is done |
* have its mtime on record. XXX: If this is done |
|
|
* 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... */ |
|
|
|
/* There are three distinct hash structures: |
|
* - to collate files's last modification times (global mtimes) |
|
* - to collate file names (in each Path structure) |
|
* - to collate known directories (global openDirectories). */ |
|
static struct hash_info stamp_info = { offsetof(struct file_stamp, name), |
|
NULL, hash_alloc, hash_free, element_alloc }; |
|
|
static struct hash_info file_info = { 0, |
static struct hash_info file_info = { 0, |
NULL, hash_alloc, hash_free, element_alloc }; |
NULL, hash_alloc, hash_free, element_alloc }; |
|
|
static struct hash_info dir_info = { offsetof(Path, name), |
static struct hash_info dir_info = { offsetof(Path, name), |
NULL, hash_alloc, hash_free, element_alloc }; |
NULL, hash_alloc, hash_free, element_alloc }; |
|
|
|
static void record_stamp __P((const char *, TIMESTAMP)); |
static void add_file __P((Path *, const char *)); |
static void add_file __P((Path *, const char *)); |
static char *find_file_hash __P((Path *, const char *, const char *, u_int32_t)); |
static char *find_file_hash __P((Path *, const char *, const char *, u_int32_t)); |
|
static struct file_stamp *find_stamp __P((const char *)); |
static void free_hash __P((struct hash *)); |
static void free_hash __P((struct hash *)); |
|
|
static Path *DirReaddir __P((const char *, const char *)); |
static Path *DirReaddir __P((const char *, const char *)); |
|
|
static void DirPrintDir __P((void *)); |
static void DirPrintDir __P((void *)); |
|
|
static void |
static void |
|
record_stamp(file, t) |
|
const char *file; |
|
TIMESTAMP t; |
|
{ |
|
unsigned slot; |
|
const char *end = NULL; |
|
struct file_stamp *n; |
|
|
|
slot = hash_qlookupi(&mtimes, file, &end); |
|
n = hash_find(&mtimes, slot); |
|
if (n) |
|
n->mtime = t; |
|
else { |
|
n = hash_create_entry(&stamp_info, file, &end); |
|
n->mtime = t; |
|
hash_insert(&mtimes, slot, n); |
|
} |
|
} |
|
|
|
static struct file_stamp * |
|
find_stamp(file) |
|
const char *file; |
|
{ |
|
return hash_find(&mtimes, hash_qlookup(&mtimes, file)); |
|
} |
|
|
|
static void |
add_file(p, file) |
add_file(p, file) |
Path *p; |
Path *p; |
const char *file; |
const char *file; |
|
|
{ |
{ |
Lst_Init(&dirSearchPath); |
Lst_Init(&dirSearchPath); |
hash_init(&openDirectories, 4, &dir_info); |
hash_init(&openDirectories, 4, &dir_info); |
Hash_InitTable(&mtimes, 0); |
hash_init(&mtimes, 4, &stamp_info); |
|
|
dot = DirReaddir(".", NULL); |
dot = DirReaddir(".", NULL); |
|
|
|
|
register char *cp; /* index of first slash, if any */ |
register char *cp; /* index of first slash, if any */ |
Boolean hasSlash; /* true if 'name' contains a / */ |
Boolean hasSlash; /* true if 'name' contains a / */ |
struct stat stb; /* Buffer for stat, if necessary */ |
struct stat stb; /* Buffer for stat, if necessary */ |
|
struct file_stamp |
|
*entry; /* Entry for mtimes table */ |
const char *e; |
const char *e; |
u_int32_t hv; |
u_int32_t hv; |
Hash_Entry *entry; |
|
|
|
/* |
/* |
* Find the final component of the name and note whether it has a |
* Find the final component of the name and note whether it has a |
|
|
printf("checking %s...", file); |
printf("checking %s...", file); |
|
|
if (stat(file, &stb) == 0) { |
if (stat(file, &stb) == 0) { |
|
TIMESTAMP mtime; |
|
|
|
grab_stat(stb, mtime); |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("got it.\n"); |
printf("got it.\n"); |
|
|
|
|
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), |
printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), |
file); |
file); |
entry = Hash_CreateEntry(&mtimes, (char *) file, |
record_stamp(file, mtime); |
(Boolean *)NULL); |
|
/* XXX */ |
|
Hash_SetValue(entry, (void *)((long)stb.st_mtime)); |
|
nearmisses += 1; |
nearmisses += 1; |
return file; |
return file; |
} else |
} else |
|
|
printf("Looking for \"%s\"...", name); |
printf("Looking for \"%s\"...", name); |
|
|
bigmisses += 1; |
bigmisses += 1; |
entry = Hash_FindEntry(&mtimes, name); |
entry = find_stamp(name); |
if (entry != (Hash_Entry *)NULL) { |
if (entry != NULL) { |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("got it (in mtime cache)\n"); |
printf("got it (in mtime cache)\n"); |
return estrdup(name); |
return estrdup(name); |
} else if (stat(name, &stb) == 0) { |
} else if (stat(name, &stb) == 0) { |
entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL); |
TIMESTAMP mtime; |
|
|
|
grab_stat(stb, mtime); |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), |
printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), |
name); |
name); |
/* XXX */ |
record_stamp(name, mtime); |
Hash_SetValue(entry, (void *)(long)stb.st_mtime); |
|
return estrdup(name); |
return estrdup(name); |
} else { |
} else { |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
|
|
* search path dirSearchPath. |
* search path dirSearchPath. |
* |
* |
* Results: |
* Results: |
* TRUE if file exists. |
* The modification time or OUT_OF_DATE if it doesn't exist |
* |
* |
* Side Effects: |
* Side Effects: |
* The modification time is placed in the node's mtime slot. |
* The modification time is placed in the node's mtime slot. |
|
|
* found one for it, the full name is placed in the path slot. |
* found one for it, the full name is placed in the path slot. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
Boolean |
TIMESTAMP |
Dir_MTime(gn) |
Dir_MTime(gn) |
GNode *gn; /* the file whose modification time is |
GNode *gn; /* the file whose modification time is |
* desired */ |
* desired */ |
{ |
{ |
char *fullName; /* the full pathname of name */ |
char *fullName; /* the full pathname of name */ |
struct stat stb; /* buffer for finding the mod time */ |
struct stat stb; /* buffer for finding the mod time */ |
Hash_Entry *entry; |
struct file_stamp |
Boolean exists; |
*entry; |
|
unsigned int slot; |
|
TIMESTAMP mtime; |
|
|
if (gn->type & OP_ARCHV) |
if (gn->type & OP_ARCHV) |
return Arch_MTime(gn); |
return Arch_MTime(gn); |
else if (gn->path == NULL) |
if (gn->path == NULL) { |
fullName = Dir_FindFile(gn->name, &dirSearchPath); |
fullName = Dir_FindFile(gn->name, &dirSearchPath); |
else |
if (fullName == NULL) |
|
fullName = estrdup(gn->name); |
|
} else |
fullName = gn->path; |
fullName = gn->path; |
|
|
if (fullName == (char *)NULL) { |
slot = hash_qlookup(&mtimes, fullName); |
fullName = estrdup(gn->name); |
entry = hash_find(&mtimes, slot); |
} |
if (entry != NULL) { |
|
/* Only do this once -- the second time folks are checking to |
entry = Hash_FindEntry(&mtimes, fullName); |
|
if (entry != (Hash_Entry *)NULL) { |
|
/* |
|
* Only do this once -- the second time folks are checking to |
|
* see if the file was actually updated, so we need to actually go |
* see if the file was actually updated, so we need to actually go |
* to the file system. |
* 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", |
Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName); |
Targ_FmtTime(entry->mtime), fullName); |
} |
mtime = entry->mtime; |
stb.st_mtime = (time_t)(long)Hash_GetValue(entry); |
free(entry); |
Hash_DeleteEntry(&mtimes, entry); |
hash_remove(&mtimes, slot); |
exists = TRUE; |
} else if (stat(fullName, &stb) == 0) |
} else if (stat (fullName, &stb) == 0) { |
grab_stat(stb, mtime); |
/* XXX forces make to differentiate between the epoch and |
else { |
* non-existent files by kludging the timestamp slightly. */ |
|
if (stb.st_mtime == OUT_OF_DATE) |
|
stb.st_mtime++; |
|
exists = TRUE; |
|
} else { |
|
if (gn->type & OP_MEMBER) { |
if (gn->type & OP_MEMBER) { |
if (fullName != gn->path) |
if (fullName != gn->path) |
free(fullName); |
free(fullName); |
return Arch_MemMTime (gn); |
return Arch_MemMTime (gn); |
} else { |
} else |
stb.st_mtime = OUT_OF_DATE; |
set_out_of_date(mtime); |
exists = FALSE; |
|
} |
|
} |
} |
if (fullName && gn->path == (char *)NULL) { |
if (fullName && gn->path == NULL) |
gn->path = fullName; |
gn->path = fullName; |
} |
|
|
|
gn->mtime = stb.st_mtime; |
gn->mtime = mtime; |
return exists; |
return gn->mtime; |
} |
} |
|
|
/* Read a directory, either from the disk, or from the cache. */ |
/* Read a directory, either from the disk, or from the cache. */ |