1 /*************************************************************************************************
2 * Implementation of Hovel
3 * Copyright (C) 2000-2007 Mikio Hirabayashi
4 * This file is part of QDBM, Quick Database Manager.
5 * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * Lesser General Public License as published by the Free Software Foundation; either version
7 * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
8 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10 * details.
11 * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
12 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
13 * 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #define QDBM_INTERNAL 1
18
19 #include "hovel.h"
20 #include "myconf.h"
21
22 #define HV_INITBNUM 32749 /* initial bucket number */
23 #define HV_ALIGNSIZ 16 /* size of alignment */
24
25
26 /* private function prototypes */
27 static int gdbm_geterrno(int ecode);
28
29
30
31 /*************************************************************************************************
32 * public objects
33 *************************************************************************************************/
34
35
36 /* String containing the version information. */
37 char *gdbm_version = "Powered by QDBM";
38
39
40 /* Get a message string corresponding to an error code. */
gdbm_strerror(gdbm_error gdbmerrno)41 char *gdbm_strerror(gdbm_error gdbmerrno){
42 switch(gdbmerrno){
43 case GDBM_NO_ERROR: return "No error";
44 case GDBM_MALLOC_ERROR: return "Malloc error";
45 case GDBM_BLOCK_SIZE_ERROR: return "Block size error";
46 case GDBM_FILE_OPEN_ERROR: return "File open error";
47 case GDBM_FILE_WRITE_ERROR: return "File write error";
48 case GDBM_FILE_SEEK_ERROR: return "File seek error";
49 case GDBM_FILE_READ_ERROR: return "File read error";
50 case GDBM_BAD_MAGIC_NUMBER: return "Bad magic number";
51 case GDBM_EMPTY_DATABASE: return "Empty database";
52 case GDBM_CANT_BE_READER: return "Can't be reader";
53 case GDBM_CANT_BE_WRITER: return "Can't be writer";
54 case GDBM_READER_CANT_DELETE: return "Reader can't delete";
55 case GDBM_READER_CANT_STORE: return "Reader can't store";
56 case GDBM_READER_CANT_REORGANIZE: return "Reader can't reorganize";
57 case GDBM_UNKNOWN_UPDATE: return "Unknown update";
58 case GDBM_ITEM_NOT_FOUND: return "Item not found";
59 case GDBM_REORGANIZE_FAILED: return "Reorganize failed";
60 case GDBM_CANNOT_REPLACE: return "Cannot replace";
61 case GDBM_ILLEGAL_DATA: return "Illegal data";
62 case GDBM_OPT_ALREADY_SET: return "Option already set";
63 case GDBM_OPT_ILLEGAL: return "Illegal option";
64 }
65 return "(invalid ecode)";
66 }
67
68
69 /* Get a database handle after the fashion of GDBM. */
gdbm_open(char * name,int block_size,int read_write,int mode,void (* fatal_func)(void))70 GDBM_FILE gdbm_open(char *name, int block_size, int read_write, int mode,
71 void (*fatal_func)(void)){
72 GDBM_FILE dbf;
73 int dpomode;
74 DEPOT *depot;
75 int flags, fd;
76 assert(name);
77 dpomode = DP_OREADER;
78 flags = O_RDONLY;
79 if(read_write & GDBM_READER){
80 dpomode = GDBM_READER;
81 if(read_write & GDBM_NOLOCK) dpomode |= DP_ONOLCK;
82 if(read_write & GDBM_LOCKNB) dpomode |= DP_OLCKNB;
83 flags = O_RDONLY;
84 } else if(read_write & GDBM_WRITER){
85 dpomode = DP_OWRITER;
86 if(read_write & GDBM_NOLOCK) dpomode |= DP_ONOLCK;
87 if(read_write & GDBM_LOCKNB) dpomode |= DP_OLCKNB;
88 flags = O_RDWR;
89 } else if(read_write & GDBM_WRCREAT){
90 dpomode = DP_OWRITER | DP_OCREAT;
91 if(read_write & GDBM_NOLOCK) dpomode |= DP_ONOLCK;
92 if(read_write & GDBM_LOCKNB) dpomode |= DP_OLCKNB;
93 if(read_write & GDBM_SPARSE) dpomode |= DP_OSPARSE;
94 flags = O_RDWR | O_CREAT;
95 } else if(read_write & GDBM_NEWDB){
96 dpomode = DP_OWRITER | DP_OCREAT | DP_OTRUNC;
97 if(read_write & GDBM_NOLOCK) dpomode |= DP_ONOLCK;
98 if(read_write & GDBM_LOCKNB) dpomode |= DP_OLCKNB;
99 if(read_write & GDBM_SPARSE) dpomode |= DP_OSPARSE;
100 flags = O_RDWR | O_CREAT | O_TRUNC;
101 } else {
102 gdbm_errno = GDBM_ILLEGAL_DATA;
103 return NULL;
104 }
105 mode |= 00600;
106 if((fd = open(name, flags, mode)) == -1 || close(fd) == -1){
107 gdbm_errno = GDBM_FILE_OPEN_ERROR;
108 return NULL;
109 }
110 if(!(depot = dpopen(name, dpomode, HV_INITBNUM))){
111 gdbm_errno = gdbm_geterrno(dpecode);
112 if(dpecode == DP_ESTAT) gdbm_errno = GDBM_FILE_OPEN_ERROR;
113 return NULL;
114 }
115 if(dpomode & DP_OWRITER){
116 if(!dpsetalign(depot, HV_ALIGNSIZ)){
117 gdbm_errno = gdbm_geterrno(dpecode);
118 dpclose(depot);
119 }
120 }
121 if((dpomode & DP_OWRITER) && (read_write & GDBM_SYNC)){
122 if(!dpsync(depot)){
123 gdbm_errno = gdbm_geterrno(dpecode);
124 dpclose(depot);
125 }
126 }
127 if(!(dbf = malloc(sizeof(GDBM)))){
128 gdbm_errno = GDBM_MALLOC_ERROR;
129 dpclose(depot);
130 return NULL;
131 }
132 dbf->depot = depot;
133 dbf->curia = NULL;
134 dbf->syncmode = (dpomode & DP_OWRITER) && (read_write & GDBM_SYNC) ? TRUE : FALSE;
135 return dbf;
136 }
137
138
139 /* Get a database handle after the fashion of QDBM. */
gdbm_open2(char * name,int read_write,int mode,int bnum,int dnum,int align)140 GDBM_FILE gdbm_open2(char *name, int read_write, int mode, int bnum, int dnum, int align){
141 GDBM_FILE dbf;
142 int dpomode, cromode, flags, fd;
143 struct stat sbuf;
144 DEPOT *depot;
145 CURIA *curia;
146 assert(name);
147 dpomode = DP_OREADER;
148 cromode = CR_OREADER;
149 flags = O_RDONLY;
150 if(read_write & GDBM_READER){
151 dpomode = DP_OREADER;
152 cromode = CR_OREADER;
153 if(read_write & GDBM_NOLOCK){
154 dpomode |= DP_ONOLCK;
155 cromode |= CR_ONOLCK;
156 }
157 if(read_write & GDBM_LOCKNB){
158 dpomode |= DP_OLCKNB;
159 cromode |= CR_OLCKNB;
160 }
161 flags = O_RDONLY;
162 } else if(read_write & GDBM_WRITER){
163 dpomode = DP_OWRITER;
164 cromode = CR_OWRITER;
165 if(read_write & GDBM_NOLOCK){
166 dpomode |= DP_ONOLCK;
167 cromode |= CR_ONOLCK;
168 }
169 if(read_write & GDBM_LOCKNB){
170 dpomode |= DP_OLCKNB;
171 cromode |= CR_OLCKNB;
172 }
173 flags = O_RDWR;
174 } else if(read_write & GDBM_WRCREAT){
175 dpomode = DP_OWRITER | DP_OCREAT;
176 cromode = CR_OWRITER | CR_OCREAT;
177 if(read_write & GDBM_NOLOCK){
178 dpomode |= DP_ONOLCK;
179 cromode |= CR_ONOLCK;
180 }
181 if(read_write & GDBM_LOCKNB){
182 dpomode |= DP_OLCKNB;
183 cromode |= CR_OLCKNB;
184 }
185 if(read_write & GDBM_SPARSE){
186 dpomode |= DP_OSPARSE;
187 cromode |= CR_OSPARSE;
188 }
189 flags = O_RDWR | O_CREAT;
190 } else if(read_write & GDBM_NEWDB){
191 dpomode = DP_OWRITER | DP_OCREAT | DP_OTRUNC;
192 cromode = CR_OWRITER | CR_OCREAT | CR_OTRUNC;
193 if(read_write & GDBM_NOLOCK){
194 dpomode |= DP_ONOLCK;
195 cromode |= CR_ONOLCK;
196 }
197 if(read_write & GDBM_LOCKNB){
198 dpomode |= DP_OLCKNB;
199 cromode |= CR_OLCKNB;
200 }
201 if(read_write & GDBM_SPARSE){
202 dpomode |= DP_OSPARSE;
203 cromode |= CR_OSPARSE;
204 }
205 flags = O_RDWR | O_CREAT | O_TRUNC;
206 } else {
207 gdbm_errno = GDBM_ILLEGAL_DATA;
208 return NULL;
209 }
210 if(lstat(name, &sbuf) != -1){
211 if(S_ISDIR(sbuf.st_mode)){
212 if(dnum < 1) dnum = 1;
213 } else {
214 dnum = 0;
215 }
216 }
217 depot = NULL;
218 curia = NULL;
219 if(dnum > 0){
220 mode |= 00700;
221 if((cromode & CR_OCREAT)){
222 if(mkdir(name, mode) == -1 && errno != EEXIST){
223 gdbm_errno = GDBM_FILE_OPEN_ERROR;
224 return NULL;
225 }
226 }
227 if(!(curia = cropen(name, cromode, bnum, dnum))){
228 gdbm_errno = gdbm_geterrno(dpecode);
229 return NULL;
230 }
231 if(cromode & CR_OWRITER) crsetalign(curia, align);
232 if((cromode & CR_OWRITER) && (read_write & GDBM_SYNC)) crsync(curia);
233 } else {
234 mode |= 00600;
235 if(dpomode & DP_OWRITER){
236 if((fd = open(name, flags, mode)) == -1 || close(fd) == -1){
237 gdbm_errno = GDBM_FILE_OPEN_ERROR;
238 return NULL;
239 }
240 }
241 if(!(depot = dpopen(name, dpomode, bnum))){
242 gdbm_errno = gdbm_geterrno(dpecode);
243 return NULL;
244 }
245 if(dpomode & DP_OWRITER) dpsetalign(depot, align);
246 if((dpomode & DP_OWRITER) && (read_write & GDBM_SYNC)) dpsync(depot);
247 }
248 if(!(dbf = malloc(sizeof(GDBM)))){
249 gdbm_errno = GDBM_MALLOC_ERROR;
250 if(depot) dpclose(depot);
251 if(curia) crclose(curia);
252 return NULL;
253 }
254 dbf->depot = depot;
255 dbf->curia = curia;
256 dbf->syncmode = (dpomode & DP_OWRITER) && (read_write & GDBM_SYNC) ? TRUE : FALSE;
257 return dbf;
258 }
259
260
261 /* Close a database handle. */
gdbm_close(GDBM_FILE dbf)262 void gdbm_close(GDBM_FILE dbf){
263 assert(dbf);
264 if(dbf->depot){
265 if(dbf->syncmode) dpsync(dbf->depot);
266 dpclose(dbf->depot);
267 } else {
268 if(dbf->syncmode) crsync(dbf->curia);
269 crclose(dbf->curia);
270 }
271 free(dbf);
272 }
273
274
275 /* Store a record. */
gdbm_store(GDBM_FILE dbf,datum key,datum content,int flag)276 int gdbm_store(GDBM_FILE dbf, datum key, datum content, int flag){
277 int dmode;
278 assert(dbf);
279 if(!key.dptr || key.dsize < 0 || !content.dptr || content.dsize < 0){
280 gdbm_errno = GDBM_ILLEGAL_DATA;
281 return -1;
282 }
283 if(dbf->depot){
284 if(!dpwritable(dbf->depot)){
285 gdbm_errno = GDBM_READER_CANT_STORE;
286 return -1;
287 }
288 dmode = (flag == GDBM_INSERT) ? DP_DKEEP : DP_DOVER;
289 if(!dpput(dbf->depot, key.dptr, key.dsize, content.dptr, content.dsize, dmode)){
290 gdbm_errno = gdbm_geterrno(dpecode);
291 if(dpecode == DP_EKEEP) return 1;
292 return -1;
293 }
294 if(dbf->syncmode && !dpsync(dbf->depot)){
295 gdbm_errno = gdbm_geterrno(dpecode);
296 return -1;
297 }
298 } else {
299 if(!crwritable(dbf->curia)){
300 gdbm_errno = GDBM_READER_CANT_STORE;
301 return -1;
302 }
303 dmode = (flag == GDBM_INSERT) ? CR_DKEEP : CR_DOVER;
304 if(!crput(dbf->curia, key.dptr, key.dsize, content.dptr, content.dsize, dmode)){
305 gdbm_errno = gdbm_geterrno(dpecode);
306 if(dpecode == DP_EKEEP) return 1;
307 return -1;
308 }
309 if(dbf->syncmode && !crsync(dbf->curia)){
310 gdbm_errno = gdbm_geterrno(dpecode);
311 return -1;
312 }
313 }
314 return 0;
315 }
316
317
318 /* Delete a record. */
gdbm_delete(GDBM_FILE dbf,datum key)319 int gdbm_delete(GDBM_FILE dbf, datum key){
320 assert(dbf);
321 if(!key.dptr || key.dsize < 0){
322 gdbm_errno = GDBM_ILLEGAL_DATA;
323 return -1;
324 }
325 if(dbf->depot){
326 if(!dpwritable(dbf->depot)){
327 gdbm_errno = GDBM_READER_CANT_DELETE;
328 return -1;
329 }
330 if(!dpout(dbf->depot, key.dptr, key.dsize)){
331 gdbm_errno = gdbm_geterrno(dpecode);
332 return -1;
333 }
334 if(dbf->syncmode && !dpsync(dbf->depot)){
335 gdbm_errno = gdbm_geterrno(dpecode);
336 return -1;
337 }
338 } else {
339 if(!crwritable(dbf->curia)){
340 gdbm_errno = GDBM_READER_CANT_DELETE;
341 return -1;
342 }
343 if(!crout(dbf->curia, key.dptr, key.dsize)){
344 gdbm_errno = gdbm_geterrno(dpecode);
345 return -1;
346 }
347 if(dbf->syncmode && !crsync(dbf->curia)){
348 gdbm_errno = gdbm_geterrno(dpecode);
349 return -1;
350 }
351 }
352 return 0;
353 }
354
355
356 /* Retrieve a record. */
gdbm_fetch(GDBM_FILE dbf,datum key)357 datum gdbm_fetch(GDBM_FILE dbf, datum key){
358 datum content;
359 char *vbuf;
360 int vsiz;
361 assert(dbf);
362 if(!key.dptr || key.dsize < 0){
363 gdbm_errno = GDBM_ILLEGAL_DATA;
364 content.dptr = NULL;
365 content.dsize = 0;
366 return content;
367 }
368 if(dbf->depot){
369 if(!(vbuf = dpget(dbf->depot, key.dptr, key.dsize, 0, -1, &vsiz))){
370 gdbm_errno = gdbm_geterrno(dpecode);
371 content.dptr = NULL;
372 content.dsize = 0;
373 return content;
374 }
375 } else {
376 if(!(vbuf = crget(dbf->curia, key.dptr, key.dsize, 0, -1, &vsiz))){
377 gdbm_errno = gdbm_geterrno(dpecode);
378 content.dptr = NULL;
379 content.dsize = 0;
380 return content;
381 }
382 }
383 content.dptr = vbuf;
384 content.dsize = vsiz;
385 return content;
386 }
387
388
389 /* Check whether a record exists or not. */
gdbm_exists(GDBM_FILE dbf,datum key)390 int gdbm_exists(GDBM_FILE dbf, datum key){
391 assert(dbf);
392 if(!key.dptr || key.dsize < 0){
393 gdbm_errno = GDBM_ILLEGAL_DATA;
394 return FALSE;
395 }
396 if(dbf->depot){
397 if(dpvsiz(dbf->depot, key.dptr, key.dsize) == -1){
398 gdbm_errno = gdbm_geterrno(dpecode);
399 return FALSE;
400 }
401 } else {
402 if(crvsiz(dbf->curia, key.dptr, key.dsize) == -1){
403 gdbm_errno = gdbm_geterrno(dpecode);
404 return FALSE;
405 }
406 }
407 return TRUE;
408 }
409
410
411 /* Get the first key of a database. */
gdbm_firstkey(GDBM_FILE dbf)412 datum gdbm_firstkey(GDBM_FILE dbf){
413 datum key;
414 assert(dbf);
415 memset(&key, 0, sizeof(datum));
416 if(dbf->depot){
417 if(dprnum(dbf->depot) < 1){
418 gdbm_errno = GDBM_EMPTY_DATABASE;
419 key.dptr = NULL;
420 key.dsize = 0;
421 return key;
422 }
423 dpiterinit(dbf->depot);
424 return gdbm_nextkey(dbf, key);
425 } else {
426 if(crrnum(dbf->curia) < 1){
427 gdbm_errno = GDBM_EMPTY_DATABASE;
428 key.dptr = NULL;
429 key.dsize = 0;
430 return key;
431 }
432 criterinit(dbf->curia);
433 return gdbm_nextkey(dbf, key);
434 }
435 }
436
437
438 /* Get the next key of a database. */
gdbm_nextkey(GDBM_FILE dbf,datum key)439 datum gdbm_nextkey(GDBM_FILE dbf, datum key){
440 char *kbuf;
441 int ksiz;
442 assert(dbf);
443 if(dbf->depot){
444 if(!(kbuf = dpiternext(dbf->depot, &ksiz))){
445 gdbm_errno = gdbm_geterrno(dpecode);
446 key.dptr = NULL;
447 key.dsize = 0;
448 return key;
449 }
450 } else {
451 if(!(kbuf = criternext(dbf->curia, &ksiz))){
452 gdbm_errno = gdbm_geterrno(dpecode);
453 key.dptr = NULL;
454 key.dsize = 0;
455 return key;
456 }
457 }
458 key.dptr = kbuf;
459 key.dsize = ksiz;
460 return key;
461 }
462
463
464 /* Synchronize contents of updating with the file and the device. */
gdbm_sync(GDBM_FILE dbf)465 void gdbm_sync(GDBM_FILE dbf){
466 assert(dbf);
467 if(dbf->depot){
468 if(!dpsync(dbf->depot)) gdbm_errno = gdbm_geterrno(dpecode);
469 } else {
470 if(!crsync(dbf->curia)) gdbm_errno = gdbm_geterrno(dpecode);
471 }
472 }
473
474
475 /* Reorganize a database. */
gdbm_reorganize(GDBM_FILE dbf)476 int gdbm_reorganize(GDBM_FILE dbf){
477 assert(dbf);
478 if(dbf->depot){
479 if(!dpwritable(dbf->depot)){
480 gdbm_errno = GDBM_READER_CANT_REORGANIZE;
481 return -1;
482 }
483 if(!dpoptimize(dbf->depot, dprnum(dbf->depot) >= HV_INITBNUM ? -1 : HV_INITBNUM)){
484 gdbm_errno = gdbm_geterrno(dpecode);
485 return -1;
486 }
487 } else {
488 if(!crwritable(dbf->curia)){
489 gdbm_errno = GDBM_READER_CANT_REORGANIZE;
490 return -1;
491 }
492 if(!croptimize(dbf->curia, crrnum(dbf->curia) >= HV_INITBNUM ? -1 : HV_INITBNUM)){
493 gdbm_errno = gdbm_geterrno(dpecode);
494 return -1;
495 }
496 }
497 return 0;
498 }
499
500
501 /* Get the file descriptor of a database file. */
gdbm_fdesc(GDBM_FILE dbf)502 int gdbm_fdesc(GDBM_FILE dbf){
503 assert(dbf);
504 if(dbf->depot){
505 return dpfdesc(dbf->depot);
506 } else {
507 return -1;
508 }
509 }
510
511
512 /* No effect. */
gdbm_setopt(GDBM_FILE dbf,int option,int * value,int size)513 int gdbm_setopt(GDBM_FILE dbf, int option, int *value, int size){
514 assert(dbf);
515 return 0;
516 }
517
518
519
520 /*************************************************************************************************
521 * features for experts
522 *************************************************************************************************/
523
524
525 /* Get the pointer of the last happened error code. */
gdbm_errnoptr(void)526 int *gdbm_errnoptr(void){
527 static int deferrno = GDBM_NO_ERROR;
528 void *ptr;
529 if(_qdbm_ptsafe){
530 if(!(ptr = _qdbm_settsd(&deferrno, sizeof(int), &deferrno))){
531 deferrno = GDBM_ILLEGAL_DATA;
532 return &deferrno;
533 }
534 return (int *)ptr;
535 }
536 return &deferrno;
537 }
538
539
540
541 /*************************************************************************************************
542 * private objects
543 *************************************************************************************************/
544
545
546 /* Get the error code of GDBM corresponding to an error code of Depot.
547 `ecode' specifies an error code of Depot.
548 The return value is the error code of GDBM. */
gdbm_geterrno(int ecode)549 static int gdbm_geterrno(int ecode){
550 switch(ecode){
551 case DP_ENOERR: return GDBM_NO_ERROR;
552 case DP_EBROKEN: return GDBM_BAD_MAGIC_NUMBER;
553 case DP_EKEEP: return GDBM_CANNOT_REPLACE;
554 case DP_ENOITEM: return GDBM_ITEM_NOT_FOUND;
555 case DP_EALLOC: return GDBM_MALLOC_ERROR;
556 case DP_EOPEN: return GDBM_FILE_OPEN_ERROR;
557 case DP_ESEEK: return GDBM_FILE_SEEK_ERROR;
558 case DP_EREAD: return GDBM_FILE_READ_ERROR;
559 case DP_EWRITE: return GDBM_FILE_WRITE_ERROR;
560 case DP_EMKDIR: return GDBM_FILE_OPEN_ERROR;
561 default: break;
562 }
563 return GDBM_ILLEGAL_DATA;
564 }
565
566
567
568 /* END OF FILE */
569