1 /*************************************************************************************************
2 * Implementation of Curia
3 * Copyright (C) 2000-2006 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 "curia.h"
20 #include "myconf.h"
21
22 #define CR_NAMEMAX 512 /* max size of a database name */
23 #define CR_DPMAX 512 /* max number of division of a database */
24 #define CR_DIRMODE 00755 /* permission of a creating directory */
25 #define CR_FILEMODE 00644 /* permission of a creating file */
26 #define CR_PATHBUFSIZ 1024 /* size of a path buffer */
27 #define CR_DEFDNUM 5 /* default number of division of a database */
28 #define CR_ATTRBNUM 16 /* bucket number of attrubute database */
29 #define CR_DPNAME "depot" /* name of each sub database */
30 #define CR_KEYDNUM "dnum" /* key of division number */
31 #define CR_KEYLRNUM "lrnum" /* key of the number of large objects */
32 #define CR_TMPFSUF MYEXTSTR "crtmp" /* suffix of a temporary directory */
33 #define CR_LOBDIR "lob" /* name of the directory of large objects */
34 #define CR_LOBDDEPTH 2 /* depth of the directories of large objects */
35 #define CR_NUMBUFSIZ 32 /* size of a buffer for a number */
36 #define CR_IOBUFSIZ 8192 /* size of an I/O buffer */
37
38
39 /* private function prototypes */
40 static char *crstrdup(const char *str);
41 static int crdpgetnum(DEPOT *depot, const char *kbuf, int ksiz);
42 static char *crgetlobpath(CURIA *curia, const char *kbuf, int ksiz);
43 static int crmklobdir(const char *path);
44 static int crrmlobdir(const char *path);
45 static int crcplobdir(CURIA *curia, const char *path);
46 static int crwrite(int fd, const void *buf, int size);
47 static int crread(int fd, void *buf, int size);
48
49
50
51 /*************************************************************************************************
52 * public objects
53 *************************************************************************************************/
54
55
56 /* Get a database handle. */
cropen(const char * name,int omode,int bnum,int dnum)57 CURIA *cropen(const char *name, int omode, int bnum, int dnum){
58 DEPOT *attr, **depots;
59 char path[CR_PATHBUFSIZ], *tname;
60 int i, j, dpomode, inode, lrnum;
61 struct stat sbuf;
62 CURIA *curia;
63 assert(name);
64 if(dnum < 1) dnum = CR_DEFDNUM;
65 if(dnum > CR_DPMAX) dnum = CR_DPMAX;
66 if(strlen(name) > CR_NAMEMAX){
67 dpecodeset(DP_EMISC, __FILE__, __LINE__);
68 return NULL;
69 }
70 dpomode = DP_OREADER;
71 if(omode & CR_OWRITER){
72 dpomode = DP_OWRITER;
73 if(omode & CR_OCREAT) dpomode |= DP_OCREAT;
74 if(omode & CR_OTRUNC) dpomode |= DP_OTRUNC;
75 if(omode & CR_OSPARSE) dpomode |= DP_OSPARSE;
76 }
77 if(omode & CR_ONOLCK) dpomode |= DP_ONOLCK;
78 if(omode & CR_OLCKNB) dpomode |= DP_OLCKNB;
79 attr = NULL;
80 lrnum = 0;
81 if((omode & CR_OWRITER) && (omode & CR_OCREAT)){
82 if(mkdir(name, CR_DIRMODE) == -1 && errno != EEXIST){
83 dpecodeset(DP_EMKDIR, __FILE__, __LINE__);
84 return NULL;
85 }
86 for(i = 0; i < dnum; i++){
87 sprintf(path, "%s%c%04d", name, MYPATHCHR, i + 1);
88 if(mkdir(path, CR_DIRMODE) == -1 && errno != EEXIST){
89 dpecodeset(DP_EMKDIR, __FILE__, __LINE__);
90 return NULL;
91 }
92 }
93 sprintf(path, "%s%c%s", name, MYPATHCHR, CR_DPNAME);
94 if(!(attr = dpopen(path, dpomode, CR_ATTRBNUM))) return NULL;
95 if(dprnum(attr) > 0){
96 if((dnum = crdpgetnum(attr, CR_KEYDNUM, -1)) < 1 ||
97 (lrnum = crdpgetnum(attr, CR_KEYLRNUM, -1)) < 0){
98 dpclose(attr);
99 dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
100 return NULL;
101 }
102 } else {
103 if(!dpput(attr, CR_KEYDNUM, -1, (char *)&dnum, sizeof(int), DP_DOVER)){
104 dpclose(attr);
105 return NULL;
106 }
107 }
108 }
109 if(!attr){
110 sprintf(path, "%s%c%s", name, MYPATHCHR, CR_DPNAME);
111 if(!(attr = dpopen(path, dpomode, 1))) return NULL;
112 if(!(omode & CR_OTRUNC)){
113 if((dnum = crdpgetnum(attr, CR_KEYDNUM, -1)) < 1 ||
114 (lrnum = crdpgetnum(attr, CR_KEYLRNUM, -1)) < 0){
115 dpclose(attr);
116 dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
117 return NULL;
118 }
119 }
120 }
121 if(omode & CR_OTRUNC){
122 for(i = 0; i < CR_DPMAX; i++){
123 sprintf(path, "%s%c%04d%c%s", name, MYPATHCHR, i + 1, MYPATHCHR, CR_DPNAME);
124 if(unlink(path) == -1 && errno != ENOENT){
125 dpclose(attr);
126 dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
127 return NULL;
128 }
129 sprintf(path, "%s%c%04d%c%s", name, MYPATHCHR, i + 1, MYPATHCHR, CR_LOBDIR);
130 if(!crrmlobdir(path)){
131 dpclose(attr);
132 return NULL;
133 }
134 if(i >= dnum){
135 sprintf(path, "%s%c%04d", name, MYPATHCHR, i + 1);
136 if(rmdir(path) == -1 && errno != ENOENT){
137 dpclose(attr);
138 dpecodeset(DP_ERMDIR, __FILE__, __LINE__);
139 return NULL;
140 }
141 }
142 }
143 errno = 0;
144 }
145 if(lstat(name, &sbuf) == -1){
146 dpclose(attr);
147 dpecodeset(DP_ESTAT, __FILE__, __LINE__);
148 return NULL;
149 }
150 inode = sbuf.st_ino;
151 if(!(depots = malloc(dnum * sizeof(DEPOT *)))){
152 dpclose(attr);
153 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
154 return NULL;
155 }
156 for(i = 0; i < dnum; i++){
157 sprintf(path, "%s%c%04d%c%s", name, MYPATHCHR, i + 1, MYPATHCHR, CR_DPNAME);
158 if(!(depots[i] = dpopen(path, dpomode, bnum))){
159 for(j = 0; j < i; j++){
160 dpclose(depots[j]);
161 }
162 free(depots);
163 dpclose(attr);
164 return NULL;
165 }
166 }
167 curia = malloc(sizeof(CURIA));
168 tname = crstrdup(name);
169 if(!curia || !tname){
170 free(curia);
171 free(tname);
172 for(i = 0; i < dnum; i++){
173 dpclose(depots[i]);
174 }
175 free(depots);
176 dpclose(attr);
177 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
178 return NULL;
179 }
180 curia->name = tname;
181 curia->wmode = (omode & CR_OWRITER);
182 curia->inode = inode;
183 curia->attr = attr;
184 curia->depots = depots;
185 curia->dnum = dnum;
186 curia->inum = 0;
187 curia->lrnum = lrnum;
188 return curia;
189 }
190
191
192 /* Close a database handle. */
crclose(CURIA * curia)193 int crclose(CURIA *curia){
194 int i, err;
195 assert(curia);
196 err = FALSE;
197 for(i = 0; i < curia->dnum; i++){
198 if(!dpclose(curia->depots[i])) err = TRUE;
199 }
200 free(curia->depots);
201 if(curia->wmode){
202 if(!dpput(curia->attr, CR_KEYLRNUM, -1, (char *)&(curia->lrnum), sizeof(int), DP_DOVER))
203 err = TRUE;
204 }
205 if(!dpclose(curia->attr)) err = TRUE;
206 free(curia->name);
207 free(curia);
208 return err ? FALSE : TRUE;
209 }
210
211
212 /* Store a record. */
crput(CURIA * curia,const char * kbuf,int ksiz,const char * vbuf,int vsiz,int dmode)213 int crput(CURIA *curia, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode){
214 int dpdmode;
215 int tnum;
216 assert(curia && kbuf && vbuf);
217 if(!curia->wmode){
218 dpecodeset(DP_EMODE, __FILE__, __LINE__);
219 return FALSE;
220 }
221 switch(dmode){
222 case CR_DKEEP: dpdmode = DP_DKEEP; break;
223 case CR_DCAT: dpdmode = DP_DCAT; break;
224 default: dpdmode = DP_DOVER; break;
225 }
226 tnum = dpouterhash(kbuf, ksiz) % curia->dnum;
227 return dpput(curia->depots[tnum], kbuf, ksiz, vbuf, vsiz, dpdmode);
228 }
229
230
231 /* Delete a record. */
crout(CURIA * curia,const char * kbuf,int ksiz)232 int crout(CURIA *curia, const char *kbuf, int ksiz){
233 int tnum;
234 assert(curia && kbuf);
235 if(!curia->wmode){
236 dpecodeset(DP_EMODE, __FILE__, __LINE__);
237 return FALSE;
238 }
239 tnum = dpouterhash(kbuf, ksiz) % curia->dnum;
240 return dpout(curia->depots[tnum], kbuf, ksiz);
241 }
242
243
244 /* Retrieve a record. */
crget(CURIA * curia,const char * kbuf,int ksiz,int start,int max,int * sp)245 char *crget(CURIA *curia, const char *kbuf, int ksiz, int start, int max, int *sp){
246 int tnum;
247 assert(curia && kbuf && start >= 0);
248 tnum = dpouterhash(kbuf, ksiz) % curia->dnum;
249 return dpget(curia->depots[tnum], kbuf, ksiz, start, max, sp);
250 }
251
252
253 /* Retrieve a record and write the value into a buffer. */
crgetwb(CURIA * curia,const char * kbuf,int ksiz,int start,int max,char * vbuf)254 int crgetwb(CURIA *curia, const char *kbuf, int ksiz, int start, int max, char *vbuf){
255 int tnum;
256 assert(curia && kbuf && start >= 0 && max >= 0 && vbuf);
257 tnum = dpouterhash(kbuf, ksiz) % curia->dnum;
258 return dpgetwb(curia->depots[tnum], kbuf, ksiz, start, max, vbuf);
259 }
260
261
262 /* Get the size of the value of a record. */
crvsiz(CURIA * curia,const char * kbuf,int ksiz)263 int crvsiz(CURIA *curia, const char *kbuf, int ksiz){
264 int tnum;
265 assert(curia && kbuf);
266 tnum = dpouterhash(kbuf, ksiz) % curia->dnum;
267 return dpvsiz(curia->depots[tnum], kbuf, ksiz);
268 }
269
270
271 /* Initialize the iterator of a database handle. */
criterinit(CURIA * curia)272 int criterinit(CURIA *curia){
273 int i, err;
274 assert(curia);
275 err = FALSE;
276 for(i = 0; i < curia->dnum; i++){
277 if(!dpiterinit(curia->depots[i])){
278 err = TRUE;
279 break;
280 }
281 }
282 curia->inum = 0;
283 return err ? FALSE : TRUE;
284 }
285
286
287 /* Get the next key of the iterator. */
criternext(CURIA * curia,int * sp)288 char *criternext(CURIA *curia, int *sp){
289 char *kbuf;
290 assert(curia);
291 kbuf = NULL;
292 while(curia->inum < curia->dnum && !(kbuf = dpiternext(curia->depots[curia->inum], sp))){
293 if(dpecode != DP_ENOITEM) return NULL;
294 (curia->inum)++;
295 }
296 return kbuf;
297 }
298
299
300 /* Set alignment of a database handle. */
crsetalign(CURIA * curia,int align)301 int crsetalign(CURIA *curia, int align){
302 int i, err;
303 assert(curia);
304 if(!curia->wmode){
305 dpecodeset(DP_EMODE, __FILE__, __LINE__);
306 return FALSE;
307 }
308 err = FALSE;
309 for(i = 0; i < curia->dnum; i++){
310 if(!dpsetalign(curia->depots[i], align)){
311 err = TRUE;
312 break;
313 }
314 }
315 return err ? FALSE : TRUE;
316 }
317
318
319 /* Set the size of the free block pool of a database handle. */
crsetfbpsiz(CURIA * curia,int size)320 int crsetfbpsiz(CURIA *curia, int size){
321 int i, err;
322 assert(curia && size >= 0);
323 if(!curia->wmode){
324 dpecodeset(DP_EMODE, __FILE__, __LINE__);
325 return FALSE;
326 }
327 err = FALSE;
328 for(i = 0; i < curia->dnum; i++){
329 if(!dpsetfbpsiz(curia->depots[i], size)){
330 err = TRUE;
331 break;
332 }
333 }
334 return err ? FALSE : TRUE;
335 }
336
337
338 /* Synchronize contents of updating a database with the files and the devices. */
crsync(CURIA * curia)339 int crsync(CURIA *curia){
340 int i, err;
341 assert(curia);
342 if(!curia->wmode){
343 dpecodeset(DP_EMODE, __FILE__, __LINE__);
344 return FALSE;
345 }
346 err = FALSE;
347 if(!dpput(curia->attr, CR_KEYLRNUM, -1, (char *)&(curia->lrnum), sizeof(int), DP_DOVER) ||
348 !dpsync(curia->attr)) err = TRUE;
349 for(i = 0; i < curia->dnum; i++){
350 if(!dpsync(curia->depots[i])){
351 err = TRUE;
352 break;
353 }
354 }
355 return err ? FALSE : TRUE;
356 }
357
358
359 /* Optimize a database. */
croptimize(CURIA * curia,int bnum)360 int croptimize(CURIA *curia, int bnum){
361 int i, err;
362 assert(curia);
363 if(!curia->wmode){
364 dpecodeset(DP_EMODE, __FILE__, __LINE__);
365 return FALSE;
366 }
367 err = FALSE;
368 for(i = 0; i < curia->dnum; i++){
369 if(!dpoptimize(curia->depots[i], bnum)){
370 err = TRUE;
371 break;
372 }
373 }
374 curia->inum = 0;
375 return err ? FALSE : TRUE;
376 }
377
378
379 /* Get the name of a database. */
crname(CURIA * curia)380 char *crname(CURIA *curia){
381 char *name;
382 assert(curia);
383 if(!(name = crstrdup(curia->name))){
384 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
385 return NULL;
386 }
387 return name;
388 }
389
390
391 /* Get the total size of database files. */
crfsiz(CURIA * curia)392 int crfsiz(CURIA *curia){
393 int i, sum, rv;
394 assert(curia);
395 sum = 0;
396 for(i = 0; i < curia->dnum; i++){
397 rv = dpfsiz(curia->depots[i]);
398 if(rv == -1) return -1;
399 sum += rv;
400 }
401 return sum;
402 }
403
404
405 /* Get the total size of database files as double-precision value. */
crfsizd(CURIA * curia)406 double crfsizd(CURIA *curia){
407 double sum;
408 int i, rv;
409 assert(curia);
410 sum = 0.0;
411 for(i = 0; i < curia->dnum; i++){
412 rv = dpfsiz(curia->depots[i]);
413 if(rv == -1) return -1.0;
414 sum += rv;
415 }
416 return sum;
417 }
418
419
420 /* Get the total number of the elements of each bucket array. */
crbnum(CURIA * curia)421 int crbnum(CURIA *curia){
422 int i, sum, rv;
423 assert(curia);
424 sum = 0;
425 for(i = 0; i < curia->dnum; i++){
426 rv = dpbnum(curia->depots[i]);
427 if(rv == -1) return -1;
428 sum += rv;
429 }
430 return sum;
431 }
432
433
434 /* Get the total number of the used elements of each bucket array. */
crbusenum(CURIA * curia)435 int crbusenum(CURIA *curia){
436 int i, sum, rv;
437 assert(curia);
438 sum = 0;
439 for(i = 0; i < curia->dnum; i++){
440 rv = dpbusenum(curia->depots[i]);
441 if(rv == -1) return -1;
442 sum += rv;
443 }
444 return sum;
445 }
446
447
448 /* Get the number of the records stored in a database. */
crrnum(CURIA * curia)449 int crrnum(CURIA *curia){
450 int i, sum, rv;
451 assert(curia);
452 sum = 0;
453 for(i = 0; i < curia->dnum; i++){
454 rv = dprnum(curia->depots[i]);
455 if(rv == -1) return -1;
456 sum += rv;
457 }
458 return sum;
459 }
460
461
462 /* Check whether a database handle is a writer or not. */
crwritable(CURIA * curia)463 int crwritable(CURIA *curia){
464 assert(curia);
465 return curia->wmode;
466 }
467
468
469 /* Check whether a database has a fatal error or not. */
crfatalerror(CURIA * curia)470 int crfatalerror(CURIA *curia){
471 int i;
472 assert(curia);
473 if(dpfatalerror(curia->attr)) return TRUE;
474 for(i = 0; i < curia->dnum; i++){
475 if(dpfatalerror(curia->depots[i])) return TRUE;
476 }
477 return FALSE;
478 }
479
480
481 /* Get the inode number of a database directory. */
crinode(CURIA * curia)482 int crinode(CURIA *curia){
483 assert(curia);
484 return curia->inode;
485 }
486
487
488 /* Get the last modified time of a database. */
crmtime(CURIA * curia)489 time_t crmtime(CURIA *curia){
490 assert(curia);
491 return dpmtime(curia->attr);
492 }
493
494
495 /* Remove a database directory. */
crremove(const char * name)496 int crremove(const char *name){
497 struct stat sbuf;
498 CURIA *curia;
499 char path[CR_PATHBUFSIZ];
500 assert(name);
501 if(lstat(name, &sbuf) == -1){
502 dpecodeset(DP_ESTAT, __FILE__, __LINE__);
503 return FALSE;
504 }
505 if((curia = cropen(name, CR_OWRITER | CR_OTRUNC, 1, 1)) != NULL) crclose(curia);
506 sprintf(path, "%s%c0001%c%s", name, MYPATHCHR, MYPATHCHR, CR_DPNAME);
507 dpremove(path);
508 sprintf(path, "%s%c0001", name, MYPATHCHR);
509 if(rmdir(path) == -1){
510 dpecodeset(DP_ERMDIR, __FILE__, __LINE__);
511 return FALSE;
512 }
513 sprintf(path, "%s%c%s", name, MYPATHCHR, CR_DPNAME);
514 if(!dpremove(path)) return FALSE;
515 if(rmdir(name) == -1){
516 dpecodeset(DP_ERMDIR, __FILE__, __LINE__);
517 return FALSE;
518 }
519 return TRUE;
520 }
521
522
523 /* Repair a broken database directory. */
crrepair(const char * name)524 int crrepair(const char *name){
525 CURIA *tcuria;
526 DEPOT *tdepot;
527 char path[CR_PATHBUFSIZ], *kbuf, *vbuf;
528 struct stat sbuf;
529 int i, j, err, bnum, dnum, ksiz, vsiz;
530 assert(name);
531 err = FALSE;
532 bnum = 0;
533 dnum = 0;
534 for(i = 1; i <= CR_DPMAX; i++){
535 sprintf(path, "%s%c%04d%c%s", name, MYPATHCHR, i, MYPATHCHR, CR_DPNAME);
536 if(lstat(path, &sbuf) != -1){
537 dnum++;
538 if(!dprepair(path)) err = TRUE;
539 if((tdepot = dpopen(path, DP_OREADER, -1)) != NULL){
540 bnum += dpbnum(tdepot);
541 dpclose(tdepot);
542 }
543 }
544 }
545 if(dnum < CR_DEFDNUM) dnum = CR_DEFDNUM;
546 bnum /= dnum;
547 sprintf(path, "%s%s", name, CR_TMPFSUF);
548 if((tcuria = cropen(path, CR_OWRITER | CR_OCREAT | CR_OTRUNC, bnum, dnum)) != NULL){
549 for(i = 1; i <= CR_DPMAX; i++){
550 sprintf(path, "%s%c%04d%c%s", name, MYPATHCHR, i, MYPATHCHR, CR_DPNAME);
551 if(lstat(path, &sbuf) != -1){
552 if((tdepot = dpopen(path, DP_OREADER, -1)) != NULL){
553 if(!dpiterinit(tdepot)) err = TRUE;
554 while((kbuf = dpiternext(tdepot, &ksiz)) != NULL){
555 if((vbuf = dpget(tdepot, kbuf, ksiz, 0, -1, &vsiz)) != NULL){
556 if(!crput(tcuria, kbuf, ksiz, vbuf, vsiz, CR_DKEEP)) err = TRUE;
557 free(vbuf);
558 }
559 free(kbuf);
560 }
561 dpclose(tdepot);
562 } else {
563 err = TRUE;
564 }
565 }
566 for(j = 0; j <= CR_DPMAX; j++){
567 sprintf(path, "%s%c%04d%c%s", name, MYPATHCHR, j, MYPATHCHR, CR_LOBDIR);
568 if(lstat(path, &sbuf) != -1){
569 if(!crcplobdir(tcuria, path)) err = TRUE;
570 }
571 }
572 }
573 if(!crclose(tcuria)) err = TRUE;
574 if(!crremove(name)) err = TRUE;
575 sprintf(path, "%s%s", name, CR_TMPFSUF);
576 if(rename(path, name) == -1){
577 if(!err) dpecodeset(DP_EMISC, __FILE__, __LINE__);
578 err = TRUE;
579 }
580 } else {
581 err = TRUE;
582 }
583 return err ? FALSE : TRUE;
584 }
585
586
587 /* Dump all records as endian independent data. */
crexportdb(CURIA * curia,const char * name)588 int crexportdb(CURIA *curia, const char *name){
589 char path[CR_PATHBUFSIZ], *kbuf, *vbuf, *pbuf;
590 int i, err, *fds, ksiz, vsiz, psiz;
591 assert(curia && name);
592 if(!(criterinit(curia))) return FALSE;
593 if(mkdir(name, CR_DIRMODE) == -1 && errno != EEXIST){
594 dpecodeset(DP_EMKDIR, __FILE__, __LINE__);
595 return FALSE;
596 }
597 err = FALSE;
598 fds = malloc(sizeof(int) * curia->dnum);
599 for(i = 0; i < curia->dnum; i++){
600 sprintf(path, "%s%c%04d", name, MYPATHCHR, i + 1);
601 if((fds[i] = open(path, O_RDWR | O_CREAT | O_TRUNC, CR_FILEMODE)) == -1){
602 if(!err) dpecodeset(DP_EOPEN, __FILE__, __LINE__);
603 err = TRUE;
604 break;
605 }
606 }
607 while(!err && (kbuf = criternext(curia, &ksiz)) != NULL){
608 if((vbuf = crget(curia, kbuf, ksiz, 0, -1, &vsiz)) != NULL){
609 if((pbuf = malloc(ksiz + vsiz + CR_NUMBUFSIZ * 2)) != NULL){
610 psiz = 0;
611 psiz += sprintf(pbuf + psiz, "%X\n%X\n", ksiz, vsiz);
612 memcpy(pbuf + psiz, kbuf, ksiz);
613 psiz += ksiz;
614 pbuf[psiz++] = '\n';
615 memcpy(pbuf + psiz, vbuf, vsiz);
616 psiz += vsiz;
617 pbuf[psiz++] = '\n';
618 if(!crwrite(fds[curia->inum], pbuf, psiz)){
619 dpecodeset(DP_EWRITE, __FILE__, __LINE__);
620 err = TRUE;
621 }
622 free(pbuf);
623 } else {
624 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
625 err = TRUE;
626 }
627 free(vbuf);
628 } else {
629 err = TRUE;
630 }
631 free(kbuf);
632 }
633 for(i = 0; i < curia->dnum; i++){
634 if(fds[i] != -1 && close(fds[i]) == -1){
635 if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
636 err = TRUE;
637 }
638 }
639 free(fds);
640 return !err && !crfatalerror(curia);
641 }
642
643
644 /* Load all records from endian independent data. */
crimportdb(CURIA * curia,const char * name)645 int crimportdb(CURIA *curia, const char *name){
646 DEPOT *depot;
647 char ipath[CR_PATHBUFSIZ], opath[CR_PATHBUFSIZ], *kbuf, *vbuf;
648 int i, err, ksiz, vsiz;
649 struct stat sbuf;
650 assert(curia && name);
651 if(!curia->wmode){
652 dpecodeset(DP_EMODE, __FILE__, __LINE__);
653 return FALSE;
654 }
655 if(crrnum(curia) > 0){
656 dpecodeset(DP_EMISC, __FILE__, __LINE__);
657 return FALSE;
658 }
659 err = FALSE;
660 for(i = 0; !err && i < CR_DPMAX; i++){
661 sprintf(ipath, "%s%c%04d", name, MYPATHCHR, i + 1);
662 if(lstat(ipath, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) break;
663 sprintf(opath, "%s%c%04d%s", curia->name, MYPATHCHR, i + 1, CR_TMPFSUF);
664 if((depot = dpopen(opath, DP_OWRITER | DP_OCREAT | DP_OTRUNC, -1)) != NULL){
665 if(dpimportdb(depot, ipath)){
666 dpiterinit(depot);
667 while((kbuf = dpiternext(depot, &ksiz)) != NULL){
668 if((vbuf = dpget(depot, kbuf, ksiz, 0, -1, &vsiz)) != NULL){
669 if(!crput(curia, kbuf, ksiz, vbuf, vsiz, CR_DKEEP)) err = TRUE;
670 free(vbuf);
671 } else {
672 err = TRUE;
673 }
674 free(kbuf);
675 }
676 } else {
677 err = TRUE;
678 }
679 if(!dpclose(depot)) err = TRUE;
680 if(!dpremove(opath)) err = TRUE;
681 } else {
682 err = TRUE;
683 }
684 }
685 return !err && !crfatalerror(curia);
686 }
687
688
689 /* Store a large object. */
crputlob(CURIA * curia,const char * kbuf,int ksiz,const char * vbuf,int vsiz,int dmode)690 int crputlob(CURIA *curia, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode){
691 char *path;
692 int mode, fd, err, be;
693 struct stat sbuf;
694 assert(curia && kbuf && vbuf);
695 if(!curia->wmode){
696 dpecodeset(DP_EMODE, __FILE__, __LINE__);
697 return FALSE;
698 }
699 if(ksiz < 0) ksiz = strlen(kbuf);
700 if(vsiz < 0) vsiz = strlen(vbuf);
701 if(!(path = crgetlobpath(curia, kbuf, ksiz))) return FALSE;
702 if(!crmklobdir(path)){
703 free(path);
704 return FALSE;
705 }
706 be = lstat(path, &sbuf) != -1 && S_ISREG(sbuf.st_mode);
707 mode = O_RDWR | O_CREAT;
708 if(dmode & CR_DKEEP) mode |= O_EXCL;
709 if(dmode & CR_DCAT){
710 mode |= O_APPEND;
711 } else {
712 mode |= O_TRUNC;
713 }
714 if((fd = open(path, mode, CR_FILEMODE)) == -1){
715 free(path);
716 dpecodeset(DP_EOPEN, __FILE__, __LINE__);
717 if(dmode == CR_DKEEP) dpecodeset(DP_EKEEP, __FILE__, __LINE__);
718 return FALSE;
719 }
720 free(path);
721 err = FALSE;
722 if(crwrite(fd, vbuf, vsiz) == -1){
723 err = TRUE;
724 dpecodeset(DP_EWRITE, __FILE__, __LINE__);
725 }
726 if(close(fd) == -1){
727 err = TRUE;
728 dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
729 }
730 if(!err && !be) (curia->lrnum)++;
731 return err ? FALSE : TRUE;
732 }
733
734
735 /* Delete a large object. */
croutlob(CURIA * curia,const char * kbuf,int ksiz)736 int croutlob(CURIA *curia, const char *kbuf, int ksiz){
737 char *path;
738 int err, be;
739 struct stat sbuf;
740 assert(curia && kbuf);
741 if(!curia->wmode){
742 dpecodeset(DP_EMODE, __FILE__, __LINE__);
743 return FALSE;
744 }
745 if(ksiz < 0) ksiz = strlen(kbuf);
746 if(!(path = crgetlobpath(curia, kbuf, ksiz))) return FALSE;
747 be = lstat(path, &sbuf) != -1 && S_ISREG(sbuf.st_mode);
748 err = FALSE;
749 if(unlink(path) == -1){
750 err = TRUE;
751 dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
752 }
753 free(path);
754 if(!err && be) (curia->lrnum)--;
755 return err ? FALSE : TRUE;
756 }
757
758
759 /* Retrieve a large object. */
crgetlob(CURIA * curia,const char * kbuf,int ksiz,int start,int max,int * sp)760 char *crgetlob(CURIA *curia, const char *kbuf, int ksiz, int start, int max, int *sp){
761 char *path, *buf;
762 struct stat sbuf;
763 int fd, size;
764 assert(curia && kbuf && start >= 0);
765 if(ksiz < 0) ksiz = strlen(kbuf);
766 if(!(path = crgetlobpath(curia, kbuf, ksiz))) return NULL;
767 if((fd = open(path, O_RDONLY, CR_FILEMODE)) == -1){
768 free(path);
769 dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
770 return NULL;
771 }
772 free(path);
773 if(fstat(fd, &sbuf) == -1){
774 close(fd);
775 dpecodeset(DP_ESTAT, __FILE__, __LINE__);
776 return NULL;
777 }
778 if(start > sbuf.st_size){
779 close(fd);
780 dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
781 return NULL;
782 }
783 if(lseek(fd, start, SEEK_SET) == -1){
784 close(fd);
785 dpecodeset(DP_ESEEK, __FILE__, __LINE__);
786 return NULL;
787 }
788 if(max < 0) max = sbuf.st_size;
789 if(!(buf = malloc(max + 1))){
790 close(fd);
791 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
792 return NULL;
793 }
794 size = crread(fd, buf, max);
795 close(fd);
796 if(size == -1){
797 free(buf);
798 dpecodeset(DP_EREAD, __FILE__, __LINE__);
799 return NULL;
800 }
801 buf[size] = '\0';
802 if(sp) *sp = size;
803 return buf;
804 }
805
806
807 /* Get the file descriptor of a large object. */
crgetlobfd(CURIA * curia,const char * kbuf,int ksiz)808 int crgetlobfd(CURIA *curia, const char *kbuf, int ksiz){
809 char *path;
810 int fd;
811 assert(curia && kbuf);
812 if(ksiz < 0) ksiz = strlen(kbuf);
813 if(!(path = crgetlobpath(curia, kbuf, ksiz))) return -1;
814 if((fd = open(path, curia->wmode ? O_RDWR: O_RDONLY, CR_FILEMODE)) == -1){
815 free(path);
816 dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
817 return -1;
818 }
819 free(path);
820 return fd;
821 }
822
823
824 /* Get the size of the value of a large object. */
crvsizlob(CURIA * curia,const char * kbuf,int ksiz)825 int crvsizlob(CURIA *curia, const char *kbuf, int ksiz){
826 char *path;
827 struct stat sbuf;
828 assert(curia && kbuf);
829 if(ksiz < 0) ksiz = strlen(kbuf);
830 if(!(path = crgetlobpath(curia, kbuf, ksiz))) return -1;
831 if(lstat(path, &sbuf) == -1){
832 free(path);
833 dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
834 return -1;
835 }
836 free(path);
837 return sbuf.st_size;
838 }
839
840
841 /* Get the number of the large objects stored in a database. */
crrnumlob(CURIA * curia)842 int crrnumlob(CURIA *curia){
843 assert(curia);
844 return curia->lrnum;
845 }
846
847
848
849 /*************************************************************************************************
850 * features for experts
851 *************************************************************************************************/
852
853
854 /* Synchronize updating contents on memory. */
crmemsync(CURIA * curia)855 int crmemsync(CURIA *curia){
856 int i, err;
857 assert(curia);
858 if(!curia->wmode){
859 dpecodeset(DP_EMODE, __FILE__, __LINE__);
860 return FALSE;
861 }
862 err = FALSE;
863 if(!dpput(curia->attr, CR_KEYLRNUM, -1, (char *)&(curia->lrnum), sizeof(int), DP_DOVER) ||
864 !dpmemsync(curia->attr)) err = TRUE;
865 for(i = 0; i < curia->dnum; i++){
866 if(!dpmemsync(curia->depots[i])){
867 err = TRUE;
868 break;
869 }
870 }
871 return err ? FALSE : TRUE;
872 }
873
874
875 /* Get flags of a database. */
crgetflags(CURIA * curia)876 int crgetflags(CURIA *curia){
877 assert(curia);
878 return dpgetflags(curia->attr);
879 }
880
881
882 /* Set flags of a database. */
crsetflags(CURIA * curia,int flags)883 int crsetflags(CURIA *curia, int flags){
884 assert(curia);
885 if(!curia->wmode){
886 dpecodeset(DP_EMODE, __FILE__, __LINE__);
887 return FALSE;
888 }
889 return dpsetflags(curia->attr, flags);
890 }
891
892
893
894 /*************************************************************************************************
895 * private objects
896 *************************************************************************************************/
897
898
899 /* Get a copied string.
900 `str' specifies an original string.
901 The return value is a copied string whose region is allocated by `malloc'. */
crstrdup(const char * str)902 static char *crstrdup(const char *str){
903 int len;
904 char *buf;
905 assert(str);
906 len = strlen(str);
907 if(!(buf = malloc(len + 1))) return NULL;
908 memcpy(buf, str, len + 1);
909 return buf;
910 }
911
912
913 /* Get an integer from a database.
914 `depot' specifies an inner database handle.
915 `kbuf' specifies the pointer to the region of a key.
916 `ksiz' specifies the size of the key.
917 The return value is the integer of the corresponding record. */
crdpgetnum(DEPOT * depot,const char * kbuf,int ksiz)918 static int crdpgetnum(DEPOT *depot, const char *kbuf, int ksiz){
919 char *vbuf;
920 int vsiz, rv;
921 if(!(vbuf = dpget(depot, kbuf, ksiz, 0, -1, &vsiz)) || vsiz != sizeof(int)){
922 free(vbuf);
923 return INT_MIN;
924 }
925 rv = *(int *)vbuf;
926 free(vbuf);
927 return rv;
928 }
929
930
931 /* Get the path of a large object.
932 `curia' specifies a database handle.
933 `kbuf' specifies the pointer to the region of a key.
934 `ksiz' specifies the size of the key.
935 The return value is a path string whose region is allocated by `malloc'. */
crgetlobpath(CURIA * curia,const char * kbuf,int ksiz)936 static char *crgetlobpath(CURIA *curia, const char *kbuf, int ksiz){
937 char prefix[CR_PATHBUFSIZ], *wp, *path;
938 int i, hash;
939 assert(curia && kbuf && ksiz >= 0);
940 wp = prefix;
941 wp += sprintf(wp, "%s%c%04d%c%s%c",
942 curia->name, MYPATHCHR, dpouterhash(kbuf, ksiz) % curia->dnum + 1,
943 MYPATHCHR, CR_LOBDIR, MYPATHCHR);
944 hash = dpinnerhash(kbuf, ksiz);
945 for(i = 0; i < CR_LOBDDEPTH; i++){
946 wp += sprintf(wp, "%02X%c", hash % 0x100, MYPATHCHR);
947 hash /= 0x100;
948 }
949 if(!(path = malloc(strlen(prefix) + ksiz * 2 + 1))){
950 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
951 return NULL;
952 }
953 wp = path;
954 wp += sprintf(path, "%s", prefix);
955 for(i = 0; i < ksiz; i++){
956 wp += sprintf(wp, "%02X", ((unsigned char *)kbuf)[i]);
957 }
958 return path;
959 }
960
961
962 /* Create directories included in a path.
963 `path' specifies a path.
964 The return value is true if successful, else, it is false. */
crmklobdir(const char * path)965 static int crmklobdir(const char *path){
966 char elem[CR_PATHBUFSIZ], *wp;
967 const char *dp;
968 int err, len;
969 wp = elem;
970 err = FALSE;
971 while(*path != '\0' && (dp = strchr(path, MYPATHCHR)) != NULL){
972 len = dp - path;
973 if(wp != elem) wp += sprintf(wp, "%c", MYPATHCHR);
974 memcpy(wp, path, len);
975 wp[len] = '\0';
976 wp += len;
977 if(mkdir(elem, CR_DIRMODE) == -1 && errno != EEXIST) err = TRUE;
978 path = dp + 1;
979 }
980 if(err) dpecodeset(DP_EMKDIR, __FILE__, __LINE__);
981 return err ? FALSE : TRUE;
982 }
983
984
985 /* Remove file and directories under a directory.
986 `path' specifies a path.
987 The return value is true if successful, else, it is false. */
crrmlobdir(const char * path)988 static int crrmlobdir(const char *path){
989 char elem[CR_PATHBUFSIZ];
990 DIR *DD;
991 struct dirent *dp;
992 assert(path);
993 if(unlink(path) != -1){
994 return TRUE;
995 } else {
996 if(errno == ENOENT) return TRUE;
997 if(!(DD = opendir(path))){
998 dpecodeset(DP_EMISC, __FILE__, __LINE__);
999 return FALSE;
1000 }
1001 while((dp = readdir(DD)) != NULL){
1002 if(!strcmp(dp->d_name, MYCDIRSTR) || !strcmp(dp->d_name, MYPDIRSTR)) continue;
1003 sprintf(elem, "%s%c%s", path, MYPATHCHR, dp->d_name);
1004 if(!crrmlobdir(elem)){
1005 closedir(DD);
1006 return FALSE;
1007 }
1008 }
1009 }
1010 if(closedir(DD) == -1){
1011 dpecodeset(DP_EMISC, __FILE__, __LINE__);
1012 return FALSE;
1013 }
1014 if(rmdir(path) == -1){
1015 dpecodeset(DP_ERMDIR, __FILE__, __LINE__);
1016 return FALSE;
1017 }
1018 return TRUE;
1019 }
1020
1021
1022 /* Copy file and directories under a directory for repairing.
1023 `path' specifies a path.
1024 The return value is true if successful, else, it is false. */
crcplobdir(CURIA * curia,const char * path)1025 static int crcplobdir(CURIA *curia, const char *path){
1026 char elem[CR_PATHBUFSIZ], numbuf[3], *rp, *kbuf, *vbuf;
1027 DIR *DD;
1028 struct dirent *dp;
1029 struct stat sbuf;
1030 int i, ksiz, vsiz, fd;
1031 assert(curia && path);
1032 if(lstat(path, &sbuf) == -1){
1033 dpecodeset(DP_ESTAT, __FILE__, __LINE__);
1034 return FALSE;
1035 }
1036 if(S_ISREG(sbuf.st_mode)){
1037 rp = strrchr(path, MYPATHCHR) + 1;
1038 for(i = 0; rp[i] != '\0'; i += 2){
1039 numbuf[0] = rp[i];
1040 numbuf[1] = rp[i+1];
1041 numbuf[2] = '\0';
1042 elem[i/2] = (int)strtol(numbuf, NULL, 16);
1043 }
1044 kbuf = elem;
1045 ksiz = i / 2;
1046 vsiz = sbuf.st_size;
1047 if(!(vbuf = malloc(vsiz + 1))){
1048 dpecodeset(DP_EALLOC, __FILE__, __LINE__);
1049 return FALSE;
1050 }
1051 if((fd = open(path, O_RDONLY, CR_FILEMODE)) == -1){
1052 free(vbuf);
1053 dpecodeset(DP_EOPEN, __FILE__, __LINE__);
1054 return FALSE;
1055 }
1056 if(crread(fd, vbuf, vsiz) == -1){
1057 close(fd);
1058 free(vbuf);
1059 dpecodeset(DP_EOPEN, __FILE__, __LINE__);
1060 return FALSE;
1061 }
1062 if(!crputlob(curia, kbuf, ksiz, vbuf, vsiz, DP_DOVER)){
1063 close(fd);
1064 free(vbuf);
1065 return FALSE;
1066 }
1067 close(fd);
1068 free(vbuf);
1069 return TRUE;
1070 }
1071 if(!(DD = opendir(path))){
1072 dpecodeset(DP_EMISC, __FILE__, __LINE__);
1073 return FALSE;
1074 }
1075 while((dp = readdir(DD)) != NULL){
1076 if(!strcmp(dp->d_name, MYCDIRSTR) || !strcmp(dp->d_name, MYPDIRSTR)) continue;
1077 sprintf(elem, "%s%c%s", path, MYPATHCHR, dp->d_name);
1078 if(!crcplobdir(curia, elem)){
1079 closedir(DD);
1080 return FALSE;
1081 }
1082 }
1083 if(closedir(DD) == -1){
1084 dpecodeset(DP_EMISC, __FILE__, __LINE__);
1085 return FALSE;
1086 }
1087 return TRUE;
1088 }
1089
1090
1091 /* Write into a file.
1092 `fd' specifies a file descriptor.
1093 `buf' specifies a buffer to write.
1094 `size' specifies the size of the buffer.
1095 The return value is the size of the written buffer, or, -1 on failure. */
crwrite(int fd,const void * buf,int size)1096 static int crwrite(int fd, const void *buf, int size){
1097 char *lbuf;
1098 int rv, wb;
1099 assert(fd >= 0 && buf && size >= 0);
1100 lbuf = (char *)buf;
1101 rv = 0;
1102 do {
1103 wb = write(fd, lbuf, size);
1104 switch(wb){
1105 case -1: if(errno != EINTR) return -1;
1106 case 0: break;
1107 default:
1108 lbuf += wb;
1109 size -= wb;
1110 rv += wb;
1111 break;
1112 }
1113 } while(size > 0);
1114 return rv;
1115 }
1116
1117
1118 /* Read from a file and store the data into a buffer.
1119 `fd' specifies a file descriptor.
1120 `buffer' specifies a buffer to store into.
1121 `size' specifies the size to read with.
1122 The return value is the size read with, or, -1 on failure. */
crread(int fd,void * buf,int size)1123 static int crread(int fd, void *buf, int size){
1124 char *lbuf;
1125 int i, bs;
1126 assert(fd >= 0 && buf && size >= 0);
1127 lbuf = buf;
1128 for(i = 0; i < size && (bs = read(fd, lbuf + i, size - i)) != 0; i += bs){
1129 if(bs == -1 && errno != EINTR) return -1;
1130 }
1131 return i;
1132 }
1133
1134
1135
1136 /* END OF FILE */
1137