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