xref: /plan9/sys/src/libndb/ndbopen.c (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <ndb.h>
6 #include "ndbhf.h"
7 
8 static Ndb*	doopen(char*);
9 static void	hffree(Ndb*);
10 
11 static char *deffile = "/lib/ndb/local";
12 
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*
ndbopen(char * file)19 ndbopen(char *file)
20 {
21 	Ndb *db, *first, *last;
22 	Ndbs s;
23 	Ndbtuple *t, *nt;
24 
25 	if(file == nil && (file = getenv("NDBFILE")) == nil)
26 		file = deffile;
27 	db = doopen(file);
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);
52 		if(db == 0)
53 			continue;
54 		last->next = db;
55 		last = db;
56 	}
57 	ndbfree(t);
58 	return first;
59 }
60 
61 /*
62  *  open a single file
63  */
64 static Ndb*
doopen(char * file)65 doopen(char *file)
66 {
67 	Ndb *db;
68 
69 	db = (Ndb*)malloc(sizeof(Ndb));
70 	if(db == 0)
71 		return 0;
72 	memset(db, 0, sizeof(Ndb));
73 	strncpy(db->file, file, sizeof(db->file)-1);
74 
75 	if(ndbreopen(db) < 0){
76 		free(db);
77 		return 0;
78 	}
79 
80 	return db;
81 }
82 
83 /*
84  *  dump any cached information, forget the hash tables, and reopen a single file
85  */
86 int
ndbreopen(Ndb * db)87 ndbreopen(Ndb *db)
88 {
89 	int fd;
90 	Dir *d;
91 
92 	/* forget what we know about the open files */
93 	if(db->mtime){
94 		_ndbcacheflush(db);
95 		hffree(db);
96 		close(Bfildes(&db->b));
97 		Bterm(&db->b);
98 		db->mtime = 0;
99 	}
100 
101 	/* try the open again */
102 	fd = open(db->file, OREAD);
103 	if(fd < 0)
104 		return -1;
105 	d = dirfstat(fd);
106 	if(d == nil){
107 		close(fd);
108 		return -1;
109 	}
110 
111 	db->qid = d->qid;
112 	db->mtime = d->mtime;
113 	db->length = d->length;
114 	Binits(&db->b, fd, OREAD, db->buf, sizeof(db->buf));
115 	free(d);
116 	return 0;
117 }
118 
119 /*
120  *  close the database files
121  */
122 void
ndbclose(Ndb * db)123 ndbclose(Ndb *db)
124 {
125 	Ndb *nextdb;
126 
127 	for(; db; db = nextdb){
128 		nextdb = db->next;
129 		_ndbcacheflush(db);
130 		hffree(db);
131 		close(Bfildes(&db->b));
132 		Bterm(&db->b);
133 		free(db);
134 	}
135 }
136 
137 /*
138  *  free the hash files belonging to a db
139  */
140 static void
hffree(Ndb * db)141 hffree(Ndb *db)
142 {
143 	Ndbhf *hf, *next;
144 
145 	for(hf = db->hf; hf; hf = next){
146 		next = hf->next;
147 		close(hf->fd);
148 		free(hf);
149 	}
150 	db->hf = 0;
151 }
152 
153 /*
154  *  return true if any part of the database has changed
155  */
156 int
ndbchanged(Ndb * db)157 ndbchanged(Ndb *db)
158 {
159 	Ndb *ndb;
160 	Dir *d;
161 
162 	for(ndb = db; ndb != nil; ndb = ndb->next){
163 		d = dirfstat(Bfildes(&ndb->b));
164 		if(d == nil)
165 			continue;
166 		if(ndb->qid.path != d->qid.path
167 		|| ndb->qid.vers != d->qid.vers){
168 			free(d);
169 			return 1;
170 		}
171 		free(d);
172 	}
173 	return 0;
174 }
175