1 /*
2 * Copyright (C) 1999-2004 Etymon Systems, Inc.
3 *
4 * Authors: Nassib Nassar
5 */
6
7 /***** old *****/
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include "open.h"
18 #include "util.h"
19 #include "lock.h"
20 #include "stem.h"
21
22 static int etymon_af_init_flag = 0;
23
24 ETYMON_AF_STATE* etymon_af_state[ETYMON_AF_MAX_OPEN];
25
etymon_af_init()26 void etymon_af_init() {
27 memset(etymon_af_state, 0, sizeof(ETYMON_AF_STATE*) * ETYMON_AF_MAX_OPEN);
28 etymon_af_init_flag = 1;
29 }
30
31
32 /* assumes that db_id is valid */
etymon_af_open_files(Uint2 db_id,int flags)33 int etymon_af_open_files(Uint2 db_id, int flags) {
34 int x_fn, x;
35
36 /* open all database files */
37 for (x_fn = 0; x_fn < ETYMON_AF_MAX_DB_FILES; x_fn++) {
38 etymon_af_state[db_id]->fd[x_fn] = open(etymon_af_state[db_id]->fn[x_fn], flags | ETYMON_AF_O_LARGEFILE, ETYMON_DB_PERM);
39 if (etymon_af_state[db_id]->fd[x_fn] == -1) {
40 /* before we leave, make an attempt to close all files */
41 for (x = 0; x < x_fn; x++) {
42 close(etymon_af_state[db_id]->fd[x]);
43 }
44 return aferr(AFEDBIO);
45 }
46 }
47 return 0;
48 }
49
50
51 /* assumes that db_id is valid */
etymon_af_close_files(Uint2 db_id)52 int etymon_af_close_files(Uint2 db_id) {
53 int x_fn;
54
55 /* close all the database files */
56 for (x_fn = 0; x_fn < ETYMON_AF_MAX_DB_FILES; x_fn++) {
57 if (close(etymon_af_state[db_id]->fd[x_fn]) == -1)
58 return aferr(AFEDBIO);
59 }
60
61 return 0;
62 }
63
64
65 /* returns a database identifier in the range 1..255 */
etymon_af_open(ETYMON_AF_OPEN * opt)66 int etymon_af_open(ETYMON_AF_OPEN* opt) {
67 int db_id;
68 Uint4 magic;
69 ssize_t nbytes;
70 int x_fn;
71 int flags;
72 int x;
73 ETYMON_AF_STAT st;
74
75 /* check for option errors */
76 if (opt->dbname == NULL)
77 return aferr(AFEINVAL);
78 if ( (opt->read_only) && (opt->create) )
79 return aferr(AFEINVAL);
80
81 /* make sure we are initialized */
82 if (etymon_af_init_flag == 0) {
83 etymon_af_init();
84 }
85
86 /* find next free id */
87 db_id = 1;
88 while ( (db_id < ETYMON_AF_MAX_OPEN) && (etymon_af_state[db_id] != NULL) ) {
89 db_id++;
90 }
91 if (db_id >= ETYMON_AF_MAX_OPEN)
92 return aferr(AFEOPENLIM);
93
94 /* create new table at the free id */
95 etymon_af_state[db_id] = (ETYMON_AF_STATE*)(malloc(sizeof(ETYMON_AF_STATE)));
96 if (etymon_af_state[db_id] == NULL)
97 return aferr(AFEMEM);
98 etymon_af_state[db_id]->dbname = opt->dbname;
99 etymon_af_state[db_id]->keep_open = opt->keep_open;
100 etymon_af_state[db_id]->read_only = opt->read_only;
101
102 /* construct file names */
103 for (x_fn = 0; x_fn < ETYMON_AF_MAX_DB_FILES; x_fn++) {
104 etymon_db_construct_path(x_fn, opt->dbname, etymon_af_state[db_id]->fn[x_fn]);
105 }
106
107 /* create database */
108 if (opt->create) {
109
110 /* open/create all database files */
111 if (etymon_af_open_files(db_id, O_WRONLY | O_CREAT | O_TRUNC) == -1) {
112 free(etymon_af_state[db_id]);
113 return -1;
114 }
115
116 /* clear any lock and then lock the database */
117 etymon_db_unlock(opt->dbname);
118 etymon_db_lock(opt->dbname, NULL);
119
120 /* initialize dbinfo */
121 magic = ETYMON_INDEX_MAGIC;
122 nbytes = write(etymon_af_state[db_id]->fd[ETYMON_DBF_INFO], &magic, sizeof(Uint4));
123 if (nbytes != sizeof(Uint4)) {
124 free(etymon_af_state[db_id]);
125 return aferr(AFEDBIO);
126 }
127 sprintf(etymon_af_state[db_id]->info.version_stamp, ETYMON_AF_BANNER_STAMP);
128 etymon_af_state[db_id]->info.udict_root = 0;
129 etymon_af_state[db_id]->info.doc_n = 0;
130 etymon_af_state[db_id]->info.optimized = 0;
131 etymon_af_state[db_id]->info.phrase = opt->phrase;
132 etymon_af_state[db_id]->info.word_proximity = 0;
133 etymon_af_state[db_id]->info.stemming = af_stem_available() ? opt->stem : 0;
134 /* write db info */
135 nbytes = write(etymon_af_state[db_id]->fd[ETYMON_DBF_INFO], &(etymon_af_state[db_id]->info), sizeof(ETYMON_DB_INFO));
136 if (nbytes != sizeof(ETYMON_DB_INFO)) {
137 free(etymon_af_state[db_id]);
138 return aferr(AFEDBIO);
139 }
140
141 /* close all the database files */
142 if (etymon_af_close_files(db_id) == -1)
143 return -1;
144
145 /* unlock the database */
146 etymon_db_unlock(opt->dbname);
147
148 } /* create */ else {
149
150 if (etymon_db_ready(opt->dbname) == 0) {
151 free(etymon_af_state[db_id]);
152 return aferr(AFEDBLOCK);
153 }
154
155 }
156
157 /* open all database files */
158 if (opt->read_only) {
159 flags = O_RDONLY;
160 } else {
161 flags = O_RDWR;
162 }
163 if (etymon_af_open_files(db_id, flags) == -1) {
164 free(etymon_af_state[db_id]);
165 return -1;
166 }
167
168 /* cache database information */
169 nbytes = read(etymon_af_state[db_id]->fd[ETYMON_DBF_INFO], &magic, sizeof(Uint4));
170 if (nbytes != sizeof(Uint4)) {
171 /* before we leave, make an attempt to close all files and free table */
172 for (x = 0; x < x_fn; x++) {
173 close(etymon_af_state[db_id]->fd[x]);
174 }
175 free(etymon_af_state[db_id]);
176 return aferr(AFEDBIO);
177 }
178 if (magic != ETYMON_INDEX_MAGIC) {
179 /* before we leave, make an attempt to close all files and free table */
180 for (x = 0; x < x_fn; x++) {
181 close(etymon_af_state[db_id]->fd[x]);
182 }
183 free(etymon_af_state[db_id]);
184 return aferr(AFEVERSION);
185 }
186 nbytes = read(etymon_af_state[db_id]->fd[ETYMON_DBF_INFO], &(etymon_af_state[db_id]->info), sizeof(ETYMON_DB_INFO));
187 if (nbytes != sizeof(ETYMON_DB_INFO)) {
188 /* before we leave, make an attempt to close all files and free table */
189 for (x = 0; x < x_fn; x++) {
190 close(etymon_af_state[db_id]->fd[x]);
191 }
192 free(etymon_af_state[db_id]);
193 return aferr(AFEDBIO);
194 }
195
196 /* cache field definitions */
197 if (etymon_af_fstat(etymon_af_state[db_id]->fd[ETYMON_DBF_FDEF], &st) == -1) {
198 perror("etymon_af_open:fstat()");
199 }
200 if (st.st_size > 0) {
201 /* read fdef table into array */
202 etymon_af_state[db_id]->fdef = (ETYMON_AF_FDEF_DISK*)(malloc(st.st_size));
203 if (etymon_af_state[db_id]->fdef == NULL)
204 return aferr(AFEMEM);
205 if (read(etymon_af_state[db_id]->fd[ETYMON_DBF_FDEF], etymon_af_state[db_id]->fdef, st.st_size) == -1) {
206 /* before we leave, make an attempt to close all files and free table */
207 for (x = 0; x < x_fn; x++) {
208 close(etymon_af_state[db_id]->fd[x]);
209 }
210 free(etymon_af_state[db_id]);
211 return aferr(AFEDBIO);
212 }
213 etymon_af_state[db_id]->fdef_count = st.st_size / sizeof(ETYMON_AF_FDEF_DISK);
214 } else {
215 etymon_af_state[db_id]->fdef = NULL;
216 etymon_af_state[db_id]->fdef_count = 0;
217 }
218
219 /* close files */
220 if (opt->keep_open == 0) {
221 /* close all the database files */
222 if (etymon_af_close_files(db_id) == -1) {
223 return -1;
224 }
225 }
226
227 return db_id;
228 }
229
etymon_af_close(ETYMON_AF_CLOSE * opt)230 int etymon_af_close(ETYMON_AF_CLOSE* opt) {
231 ssize_t nbytes;
232
233 /* make sure we have a valid pointer in the table */
234 if ( (opt->db_id < 1) || (etymon_af_state[opt->db_id] == NULL) )
235 return aferr(AFEINVAL);
236
237 /* write out cached database info */
238 if (etymon_af_state[opt->db_id]->read_only == 0) {
239 /* first we may have to open the file */
240 if (etymon_af_state[opt->db_id]->keep_open == 0) {
241 etymon_af_state[opt->db_id]->fd[ETYMON_DBF_INFO] = open(etymon_af_state[opt->db_id]->fn[ETYMON_DBF_INFO],
242 O_RDWR | ETYMON_AF_O_LARGEFILE, ETYMON_DB_PERM);
243 if (etymon_af_state[opt->db_id]->fd[ETYMON_DBF_INFO] == -1)
244 return aferr(AFEDBIO);
245 }
246 /* now write out dbinfo */
247 if (etymon_af_lseek(etymon_af_state[opt->db_id]->fd[ETYMON_DBF_INFO], (etymon_af_off_t)4, SEEK_SET) == -1)
248 return aferr(AFEDBIO);
249 nbytes = write(etymon_af_state[opt->db_id]->fd[ETYMON_DBF_INFO], &(etymon_af_state[opt->db_id]->info),
250 sizeof(ETYMON_DB_INFO));
251 if (nbytes != sizeof(ETYMON_DB_INFO))
252 return aferr(AFEDBIO);
253 /* close the file if we opened it */
254 if (etymon_af_state[opt->db_id]->keep_open == 0) {
255 if (close(etymon_af_state[opt->db_id]->fd[ETYMON_DBF_INFO]) == -1)
256 return aferr(AFEDBIO);
257 }
258 }
259
260 /* close database files if they are open */
261 if (etymon_af_state[opt->db_id]->keep_open) {
262 if (etymon_af_close_files(opt->db_id) == -1) {
263 return -1;
264 }
265 }
266
267 /* free the table */
268 if (etymon_af_state[opt->db_id]->fdef) {
269 free(etymon_af_state[opt->db_id]->fdef);
270 }
271 free(etymon_af_state[opt->db_id]);
272 etymon_af_state[opt->db_id] = NULL;
273
274 return 0;
275 }
276
277 /***** new *****/
278
setomode(const char * mode,ETYMON_AF_OPEN * op)279 static int setomode(const char *mode, ETYMON_AF_OPEN *op)
280 {
281 if (mode[0] == 'r') {
282 op->read_only = mode[1] == '+' ? 0 : 1;
283 op->create = 0;
284 return 0;
285 }
286 if (mode[0] == 'w' && mode[1] == '+') {
287 op->read_only = 0;
288 op->create = 1;
289 return 0;
290 }
291 return aferr(AFEINVAL);
292 }
293
afopen(const Afopen * r,Afopen_r * rr)294 int afopen(const Afopen *r, Afopen_r *rr)
295 {
296 ETYMON_AF_OPEN op;
297 int x;
298
299 op.dbname = r->dbpath;
300 if (setomode(r->mode, &op) < 0)
301 return -1;
302 op.keep_open = 0;
303 op.phrase = r->phrase;
304 op.stem = r->stem;
305 if ((x = etymon_af_open(&op)) == -1)
306 return -1;
307 rr->dbid = x;
308 return 0;
309 }
310
afclose(const Afclose * r,Afclose_r * rr)311 int afclose(const Afclose *r, Afclose_r *rr)
312 {
313 ETYMON_AF_CLOSE c;
314
315 c.db_id = r->dbid;
316 return etymon_af_close(&c);
317 }
318