blob: fdda79ec7d2bf92ac075574af880b139d7e3214d [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <ndb.h>
#include "ndbhf.h"
static Ndb* doopen(char*, char*);
static void hffree(Ndb*);
static char *deffile = "#9/ndb/local";
/*
* the database entry in 'file' indicates the list of files
* that makeup the database. Open each one and search in
* the same order.
*/
Ndb*
ndbopen(char *file)
{
Ndb *db, *first, *last;
Ndbs s;
Ndbtuple *t, *nt;
if(file == 0)
file = unsharp(deffile);
db = doopen(file, nil);
if(db == 0)
return 0;
first = last = db;
t = ndbsearch(db, &s, "database", "");
Bseek(&db->b, 0, 0);
if(t == 0)
return db;
for(nt = t; nt; nt = nt->entry){
if(strcmp(nt->attr, "file") != 0)
continue;
if(strcmp(nt->val, file) == 0){
/* default file can be reordered in the list */
if(first->next == 0)
continue;
if(strcmp(first->file, file) == 0){
db = first;
first = first->next;
last->next = db;
db->next = 0;
last = db;
}
continue;
}
db = doopen(nt->val, file);
if(db == 0)
continue;
last->next = db;
last = db;
}
ndbfree(t);
return first;
}
/*
* open a single file
*/
static Ndb*
doopen(char *file, char *rel)
{
char *p;
Ndb *db;
db = (Ndb*)malloc(sizeof(Ndb));
if(db == 0)
return 0;
memset(db, 0, sizeof(Ndb));
/*
* Rooted paths are taken as is.
* Unrooted paths are taken relative to db we opened.
*/
if(file[0]!='/' && rel && (p=strrchr(rel, '/'))!=nil)
snprint(db->file, sizeof(db->file), "%.*s/%s",
utfnlen(rel, p-rel), rel, file);
else
strncpy(db->file, file, sizeof(db->file)-1);
if(ndbreopen(db) < 0){
free(db);
return 0;
}
return db;
}
/*
* dump any cached information, forget the hash tables, and reopen a single file
*/
int
ndbreopen(Ndb *db)
{
int fd;
Dir *d;
/* forget what we know about the open files */
if(db->mtime){
_ndbcacheflush(db);
hffree(db);
close(Bfildes(&db->b));
Bterm(&db->b);
db->mtime = 0;
}
/* try the open again */
fd = open(db->file, OREAD);
if(fd < 0)
return -1;
d = dirfstat(fd);
if(d == nil){
close(fd);
return -1;
}
db->qid = d->qid;
db->mtime = d->mtime;
db->length = d->length;
Binit(&db->b, fd, OREAD);
free(d);
return 0;
}
/*
* close the database files
*/
void
ndbclose(Ndb *db)
{
Ndb *nextdb;
for(; db; db = nextdb){
nextdb = db->next;
_ndbcacheflush(db);
hffree(db);
close(Bfildes(&db->b));
Bterm(&db->b);
free(db);
}
}
/*
* free the hash files belonging to a db
*/
static void
hffree(Ndb *db)
{
Ndbhf *hf, *next;
for(hf = db->hf; hf; hf = next){
next = hf->next;
close(hf->fd);
free(hf);
}
db->hf = 0;
}
/*
* return true if any part of the database has changed
*/
int
ndbchanged(Ndb *db)
{
Ndb *ndb;
Dir *d;
for(ndb = db; ndb != nil; ndb = ndb->next){
d = dirfstat(Bfildes(&db->b));
if(d == nil)
continue;
if(ndb->qid.path != d->qid.path
|| ndb->qid.vers != d->qid.vers){
free(d);
return 1;
}
free(d);
}
return 0;
}