Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <ndb.h>
6 #include "ndbhf.h"
8 static Ndb* doopen(char*, char*);
9 static void hffree(Ndb*);
11 static char *deffile = "#9/ndb/local";
13 /*
14 * the database entry in 'file' indicates the list of files
15 * that makeup the database. Open each one and search in
16 * the same order.
17 */
18 Ndb*
19 ndbopen(char *file)
20 {
21 Ndb *db, *first, *last;
22 Ndbs s;
23 Ndbtuple *t, *nt;
25 if(file == 0)
26 file = unsharp(deffile);
27 db = doopen(file, nil);
28 if(db == 0)
29 return 0;
30 first = last = db;
31 t = ndbsearch(db, &s, "database", "");
32 Bseek(&db->b, 0, 0);
33 if(t == 0)
34 return db;
35 for(nt = t; nt; nt = nt->entry){
36 if(strcmp(nt->attr, "file") != 0)
37 continue;
38 if(strcmp(nt->val, file) == 0){
39 /* default file can be reordered in the list */
40 if(first->next == 0)
41 continue;
42 if(strcmp(first->file, file) == 0){
43 db = first;
44 first = first->next;
45 last->next = db;
46 db->next = 0;
47 last = db;
48 }
49 continue;
50 }
51 db = doopen(nt->val, file);
52 if(db == 0)
53 continue;
54 last->next = db;
55 last = db;
56 }
57 ndbfree(t);
58 return first;
59 }
61 /*
62 * open a single file
63 */
64 static Ndb*
65 doopen(char *file, char *rel)
66 {
67 char *p;
68 Ndb *db;
70 db = (Ndb*)malloc(sizeof(Ndb));
71 if(db == 0)
72 return 0;
74 memset(db, 0, sizeof(Ndb));
75 /*
76 * Rooted paths are taken as is.
77 * Unrooted paths are taken relative to db we opened.
78 */
79 if(file[0]!='/' && rel && (p=strrchr(rel, '/'))!=nil)
80 snprint(db->file, sizeof(db->file), "%.*s/%s",
81 utfnlen(rel, p-rel), rel, file);
82 else
83 strncpy(db->file, file, sizeof(db->file)-1);
85 if(ndbreopen(db) < 0){
86 free(db);
87 return 0;
88 }
90 return db;
91 }
93 /*
94 * dump any cached information, forget the hash tables, and reopen a single file
95 */
96 int
97 ndbreopen(Ndb *db)
98 {
99 int fd;
100 Dir *d;
102 /* forget what we know about the open files */
103 if(db->mtime){
104 _ndbcacheflush(db);
105 hffree(db);
106 close(Bfildes(&db->b));
107 Bterm(&db->b);
108 db->mtime = 0;
111 /* try the open again */
112 fd = open(db->file, OREAD);
113 if(fd < 0)
114 return -1;
115 d = dirfstat(fd);
116 if(d == nil){
117 close(fd);
118 return -1;
121 db->qid = d->qid;
122 db->mtime = d->mtime;
123 db->length = d->length;
124 Binit(&db->b, fd, OREAD);
125 free(d);
126 return 0;
129 /*
130 * close the database files
131 */
132 void
133 ndbclose(Ndb *db)
135 Ndb *nextdb;
137 for(; db; db = nextdb){
138 nextdb = db->next;
139 _ndbcacheflush(db);
140 hffree(db);
141 close(Bfildes(&db->b));
142 Bterm(&db->b);
143 free(db);
147 /*
148 * free the hash files belonging to a db
149 */
150 static void
151 hffree(Ndb *db)
153 Ndbhf *hf, *next;
155 for(hf = db->hf; hf; hf = next){
156 next = hf->next;
157 close(hf->fd);
158 free(hf);
160 db->hf = 0;
163 /*
164 * return true if any part of the database has changed
165 */
166 int
167 ndbchanged(Ndb *db)
169 Ndb *ndb;
170 Dir *d;
172 for(ndb = db; ndb != nil; ndb = ndb->next){
173 d = dirfstat(Bfildes(&db->b));
174 if(d == nil)
175 continue;
176 if(ndb->qid.path != d->qid.path
177 || ndb->qid.vers != d->qid.vers){
178 free(d);
179 return 1;
181 free(d);
183 return 0;