1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 /*
7 WARNING: This file was generated by the dkct program (see
8 http://dktools.sourceforge.net/ for details).
9 Changes you make here will be lost if dkct is run again!
10 You should modify the original source and run dkct on it.
11 Original source: dk4dbi.ctr
12 */
13
14 /** @file dk4dbi.c The dk4dbi module.
15 */
16
17
18 #include "dk4conf.h"
19
20 #if DK4_HAVE_ERRNO_H
21 #ifndef ERRNO_H_INCLUDED
22 #include <errno.h>
23 #define ERRNO_H_INCLUDED 1
24 #endif
25 #endif
26
27 #if DK4_HAVE_SYS_STAT_H
28 #ifndef SYS_STAT_H_INCLUDED
29 #include <sys/stat.h>
30 #define SYS_STAT_H_INCLUDED 1
31 #endif
32 #endif
33
34 #if DK4_HAVE_ASSERT_H
35 #ifndef ASSERT_H_INCLUDED
36 #include <assert.h>
37 #define ASSERT_H_INCLUDED 1
38 #endif
39 #endif
40
41 #include <libdk4dbi/dk4dbi.h>
42 #include <libdk4base/dk4mem.h>
43 #include <libdk4base/dk4memrs.h>
44 #include <libdk4base/dk4strd.h>
45 #include <libdk4c/dk4fopd.h>
46 #include <libdk4base/dk4numco.h>
47 #include <libdk4c/dk4isadm.h>
48 #include <libdk4c/dk4fopt.h>
49 #include <libdk4base/dk4mpl.h>
50 #include <libdk4c/dk4delfile.h>
51 #include <libdk4c/dk4stat.h>
52 #include <libdk4c/dk4statd.h>
53 #include <libdk4ma/dk4maadu.h>
54 #include <libdk4base/dk4unused.h>
55
56
57
58
59
60
61
62 /** One storage entry.
63 */
64 typedef struct {
65 void *kd; /**< Key data. */
66 void *vd; /**< Value data. */
67 size_t ks; /**< Key size. */
68 size_t vs; /**< Value size. */
69 } dk4_dbi_datum_t;
70
71
72
73 /** Backend type names.
74 */
75 static const dkChar *dk4dbi_type_names[] = {
76 /* 0 */
77 dkT("mem"),
78
79 /* 1 */
80 dkT("bdb"),
81
82 /* 2 */
83 dkT("ndbm"),
84
85 NULL
86
87 };
88
89
90
91 /** File name suffixes for NDBM files.
92 */
93
94 #if (DK4_CHAR_SIZE == 1) \
95 && (\
96 (DK4_HAVE_NDBM_H) \
97 || ((!(DK4_ON_WINDOWS)) && (DK4_HAVE_CHOWN) && (DK4_HAVE_CHMOD))\
98 )
99 static const dkChar *dk4dbi_ndbm_suffixes[] = {
100 dkT(".dir"), dkT(".pag")
101 };
102 #endif
103
104
105
106 /** Delete one record from an in-memory database,
107 release resources.
108 @param ptr Record to delete
109 @param options The database options.
110 @return 1 on success, 0 on error.
111 */
112 static
113 int
dk4dbi_datum_delete(dk4_dbi_datum_t * ptr,int options)114 dk4dbi_datum_delete(dk4_dbi_datum_t *ptr, int options)
115 {
116 int back = 0;
117
118 #if DK4_USE_ASSERT
119 assert(NULL != ptr);
120 #endif
121 if (NULL != ptr) {
122 back = 1;
123 if (0 != (DK4_DB_OPT_RESET_KEY & options)) {
124 if ((NULL != ptr->kd) && ((size_t)0UL < ptr->ks)) {
125
126 if (0 == dk4mem_reset_secure(ptr->kd, ptr->ks, NULL)) {
127 back = 0;
128 }
129 }
130 }
131 if (0 != (DK4_DB_OPT_RESET_VALUE & options)) {
132 if ((NULL != ptr->vd) && ((size_t)0UL < ptr->vs)) {
133
134 if (0 == dk4mem_reset_secure(ptr->vd, ptr->vs, NULL)) {
135 back = 0;
136 }
137 }
138 }
139 dk4mem_release(ptr->kd);
140 dk4mem_release(ptr->vd);
141 ptr->ks = ptr->vs = (size_t)0UL;
142 dk4mem_free(ptr);
143 }
144
145 return back;
146 }
147
148
149
150 /** Allocate memory for a new record.
151
152 @param ks
153 @param vs
154 @param erp
155 @return Pointer to new record structure on success, NULL on error.
156
157 Error codes:
158 - DK4_E_MEMORY_ALLOCATION_FAILED<br>
159 with mem.elsize and mem.nelem
160 set if there is not enough memory available.
161 */
162 static
163 dk4_dbi_datum_t *
dk4dbi_datum_new(size_t ks,size_t vs,dk4_er_t * erp)164 dk4dbi_datum_new(
165 size_t ks,
166 size_t vs,
167 dk4_er_t *erp
168 )
169 {
170 dk4_dbi_datum_t *back = NULL;
171
172 #if DK4_USE_ASSERT
173 assert(0 < ks);
174 assert(0 < vs);
175 #endif
176 back = dk4mem_new(dk4_dbi_datum_t,1,erp);
177 if (NULL != back) {
178 back->kd = back->vd = NULL;
179 back->ks = back->vs = (size_t)0UL;
180 if (0 < ks) { back->kd = dk4mem_new(char,ks,erp); }
181 if (0 < vs) { back->vd = dk4mem_new(char,vs,erp); }
182 if ((NULL != back->kd) && (NULL != back->vd)) {
183 back->ks = ks; back->vs = vs;
184 } else {
185 dk4mem_release(back->kd);
186 dk4mem_release(back->vd);
187 dk4mem_free(back);
188 back = NULL;
189 }
190 }
191 return back;
192 }
193
194
195
196
197 /** Write in-memory database contents back to file.
198 @param db Database to save.
199 @param erp Error report, may be NULL.
200 @return 1 on success, 0 on error.
201
202 Error codes:
203 - DK4_E_SYNTAX<br>
204 if the database file name does not refer to a regular file,
205 - DK4_E_SEC_CHECK<br>
206 with failed check id in iDetails1 if access is denied by additional
207 security checks,
208 - DK4_E_OPEN_WRITE_FAILED<br>
209 with errno value in iDetails1 if fopen() or fwrite() failed,
210 - DK4_E_CLOSE_FAILED<br>
211 with errno value in iDetails1 if fclose() failed,
212 - DK4_E_WRITE_FAILD<br>
213 if fwrite() failed.
214 */
215 static
216 int
dk4dbi_mem_to_file(dk4_dbi_t * db,dk4_er_t * erp)217 dk4dbi_mem_to_file(
218 dk4_dbi_t *db,
219 dk4_er_t *erp
220 )
221 {
222 FILE *fipo = NULL; /* Write text ile */
223 dk4_dbi_datum_t *rp = NULL; /* Current record */
224 unsigned char uc[8]; /* Sizes byte array */
225 size_t nbw = 0; /* Number of bytes */
226 int tests = DK4_FOPEN_SC_USER; /* Security checks */
227 int back = 0;
228
229
230 #if DK4_USE_ASSERT
231 assert(NULL != db);
232 #endif
233 if (dk4isadmin()) { tests = DK4_FOPEN_SC_PRIVILEGED; }
234 fipo = dk4fopen(db->fn, dkT("wb"), tests, erp);
235 if (NULL != fipo) {
236 back = 1;
237 dk4sto_it_reset((db->dt).mem.i);
238 do {
239 rp = (dk4_dbi_datum_t *)dk4sto_it_next((db->dt).mem.i);
240 if (NULL != rp) {
241 uc[0] = (unsigned char)(((unsigned long)(rp->ks) >> 24) & 0x000000FFUL);
242 uc[1] = (unsigned char)(((unsigned long)(rp->ks) >> 16) & 0x000000FFUL);
243 uc[2] = (unsigned char)(((unsigned long)(rp->ks) >> 8) & 0x000000FFUL);
244 uc[3] = (unsigned char)(((unsigned long)(rp->ks) ) & 0x000000FFUL);
245 uc[4] = (unsigned char)(((unsigned long)(rp->vs) >> 24) & 0x000000FFUL);
246 uc[5] = (unsigned char)(((unsigned long)(rp->vs) >> 16) & 0x000000FFUL);
247 uc[6] = (unsigned char)(((unsigned long)(rp->vs) >> 8) & 0x000000FFUL);
248 uc[7] = (unsigned char)(((unsigned long)(rp->vs) ) & 0x000000FFUL);
249 nbw = fwrite(uc, 1, 8, fipo);
250 if (8 == nbw) {
251 nbw = fwrite(rp->kd, 1, rp->ks, fipo);
252 if (rp->ks == nbw) {
253 nbw = fwrite(rp->vd, 1, rp->vs, fipo);
254 if (rp->vs == nbw) {
255 } else {
256 back = 0;
257 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
258 }
259 } else {
260 back = 0;
261 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
262 }
263 } else {
264 back = 0;
265 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
266 }
267 }
268 } while (NULL != rp);
269 if (0 != fclose(fipo)) {
270 back = 0;
271 dk4error_set_idetails(erp, DK4_E_CLOSE_FAILED, errno);
272 }
273 } else {
274 }
275 if (0 != back) {
276 db->uc = 0;
277 }
278
279 return back;
280 }
281
282
283
284 /** Read in-memory database contents back from file.
285 @param db Database to restore.
286 @param erp Error report, may be NULL.
287 @return 1 on success, 0 on error.
288
289 Error codes:
290 - DK4_E_SYNTAX<br>
291 if
292 - the database file name does not refer to a regular file
293 - or the file contents is not an in-memory database
294 - or key/value sizes in the file are in conflict with size restrictions,
295 - DK4_E_SEC_CHECK<br>
296 with failed check id in iDetails1 if access is denied by additional
297 security checks,
298 - DK4_E_MEMORY_ALLOCATION_FAILED<br>
299 with mem.elsize and mem.nelem
300 set if there is not enough memory available,
301 - DK4_E_OPEN_READ_FAILED with errno value in iDetails1 if fopen()
302 or fread() failed.
303 */
304 static
305 int
dk4dbi_mem_from_file(dk4_dbi_t * db,dk4_er_t * erp)306 dk4dbi_mem_from_file(
307 dk4_dbi_t *db,
308 dk4_er_t *erp
309 )
310 {
311 dk4_stat_t stb; /* File stat buffer */
312 FILE *fipo = NULL; /* Input file */
313 dk4_dbi_datum_t *rp = NULL; /* Current record to process */
314 unsigned char uc[8]; /* Buffer to read sizes */
315 size_t nbr = 0; /* Number of bytes read */
316 size_t ks = 0; /* Key size */
317 size_t vs = 0; /* Value size */
318 unsigned long ul1 = 0UL; /* Key size */
319 unsigned long ul2 = 0UL; /* Value size */
320 int back = 0; /* Result */
321 int cc = 1; /* Flag: Can continue */
322
323 #if DK4_USE_ASSERT
324 assert(NULL != db);
325 #endif
326 fipo = dk4fopen(db->fn, dkT("rb"), 0, erp);
327 if (NULL != fipo) {
328 back = 1;
329 do {
330 nbr = fread(uc, 1, 8, fipo);
331 if (8 == nbr) {
332 ul1 = ((((unsigned long)(uc[0])) << 24) & 0xFF000000UL)
333 | ((((unsigned long)(uc[1])) << 16) & 0x00FF0000UL)
334 | ((((unsigned long)(uc[2])) << 8) & 0x0000FF00UL)
335 | ((((unsigned long)(uc[3])) ) & 0x000000FFUL);
336 ul2 = ((((unsigned long)(uc[4])) << 24) & 0xFF000000UL)
337 | ((((unsigned long)(uc[5])) << 16) & 0x00FF0000UL)
338 | ((((unsigned long)(uc[6])) << 8) & 0x0000FF00UL)
339 | ((((unsigned long)(uc[7])) ) & 0x000000FFUL);
340 #if 0
341 if ((dk4_um_t)(SIZE_MAX) >= (dk4_um_t)ul1)
342 #endif
343 if (0 != dk4ma_um_isgeq(SIZE_MAX, ul1)) {
344 #if 0
345 if ((dk4_um_t)(SIZE_MAX) >= (dk4_um_t)ul2)
346 #endif
347 if (0 != dk4ma_um_isgeq(SIZE_MAX, ul2)) {
348 ks = (size_t)ul1; vs = (size_t)ul2;
349 if (
350 (((size_t)0UL == db->km) || (db->km >= ks))
351 && (((size_t)0UL == db->vm) || (db->vm >= vs))
352 && ((size_t)0UL < ks) && ((size_t)0UL < vs)
353 )
354 {
355 rp = dk4dbi_datum_new(ks, vs, erp);
356 if (NULL != rp) {
357 nbr = fread(rp->kd, 1, rp->ks, fipo);
358 if (nbr == rp->ks) {
359 nbr = fread(rp->vd, 1, rp->vs, fipo);
360 if (nbr == rp->vs) {
361 if (0 == dk4sto_add((db->dt).mem.s, rp, erp)) {
362 cc = 0;
363 back = 0;
364 dk4dbi_datum_delete(rp, 0);
365 }
366 } else {
367 cc = 0;
368 back = 0;
369 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
370 dk4dbi_datum_delete(rp, 0);
371 }
372 } else {
373 cc = 0;
374 back = 0;
375 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
376 dk4dbi_datum_delete(rp, 0);
377 }
378 } else {
379 cc = 0;
380 back = 0;
381 }
382 }
383 else
384 {
385 cc = 0;
386 back = 0;
387 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
388 }
389 } else {
390 cc = 0;
391 back = 0;
392 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
393 }
394 } else {
395 cc = 0;
396 back = 0;
397 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
398 }
399 } else {
400 cc = 0;
401 if (0 != nbr) {
402 back = 0;
403 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
404 }
405 }
406 } while (0 != cc);
407 (void)fclose(fipo);
408 } else {
409 if (0 == dk4stat(&stb, db->fn, NULL)) {
410 back = 1;
411 }
412 }
413
414 return back;
415 }
416
417
418
419 /** Compare two entries.
420 @param l Left record.
421 @param r Right record.
422 @param cr Comparison criteria, ignored.
423 @return 1 if l>r, 0 if l==r, -1 if l<r.
424 */
425 static
426 int
dk4dbi_datum_compare(const void * l,const void * r,int DK4_ARG_UNUSED (cr))427 dk4dbi_datum_compare(const void *l, const void *r, int DK4_ARG_UNUSED(cr) )
428 {
429 dk4_dbi_datum_t *pl; /* Left pointer */
430 dk4_dbi_datum_t *pr; /* Right pointer */
431 int back = 0;
432
433 DK4_UNUSED_ARG(cr)
434 if (NULL != l) {
435 if (NULL != r) {
436 pl = (dk4_dbi_datum_t *)l;
437 pr = (dk4_dbi_datum_t *)r;
438 if (NULL != pl->kd) {
439 if (NULL != pr->kd) {
440 if (pl->ks > pr->ks) {
441 back = 1;
442 } else {
443 if (pl->ks < pr->ks) {
444 back = -1;
445 } else {
446 if (0 < pl->ks) {
447 back = DK4_MEMCMP(pl->kd, pr->kd, pl->ks);
448 if (-1 > back) back = -1;
449 if ( 1 < back) back = 1;
450 }
451 }
452 }
453 } else {
454 back = 1;
455 }
456 } else {
457 if (NULL != pr->kd) { back = -1; }
458 }
459 } else {
460 back = 1;
461 }
462 } else {
463 if (NULL != r) { back = -1; }
464 }
465
466 return back;
467 }
468
469
470
471 /** Delete base database structure, release resources.
472 @param ptr Database structure to release.
473 */
474 static
475 void
dk4dbi_delete_base(dk4_dbi_t * ptr)476 dk4dbi_delete_base(dk4_dbi_t *ptr)
477 {
478
479 #if DK4_USE_ASSERT
480 assert(NULL != ptr);
481 #endif
482 if (NULL != ptr) {
483 dk4mem_release(ptr->fn);
484 dk4mem_free(ptr);
485 }
486
487 }
488
489
490
491 /** Allocate memory for a database.
492 @param fn File name.
493 @param tp Backend type.
494 @param wa Flag: Write access required.
495 @param km
496 @param vm
497 @param erp Error report, may be NULL.
498 @return Pointer to memory on success, NULL on error.
499
500 Error codes:
501 - DK4_E_MATH_OVERFLOW<br>
502 on numeric overflow when calculating size,
503 - DK4_E_MEMORY_ALLOCATION_FAILED<br>
504 with mem.elsize and mem.nelem
505 set if there is not enough memory available.
506 */
507 static
508 dk4_dbi_t *
dk4dbi_new_base(const dkChar * fn,int tp,int wa,size_t km,size_t vm,dk4_er_t * erp)509 dk4dbi_new_base(
510 const dkChar *fn,
511 int tp,
512 int wa,
513 size_t km,
514 size_t vm,
515 dk4_er_t *erp
516 )
517 {
518 dk4_dbi_t *back = NULL;
519
520 #if DK4_USE_ASSERT
521 assert(NULL != fn);
522 assert((DK4_DB_BE_MEMORY == tp) || (DK4_DB_BE_BDB == tp) || (DK4_DB_BE_NDBM == tp));
523 #endif
524 back = dk4mem_new(dk4_dbi_t,1,erp);
525 if (NULL != back) {
526 back->tp = tp;
527 back->wa = wa;
528 back->op = 0;
529 back->uc = 0;
530 back->km = km;
531 back->vm = vm;
532 switch (tp) {
533 case DK4_DB_BE_MEMORY : {
534 (back->dt).mem.s = NULL;
535 (back->dt).mem.i = NULL;
536 } break;
537 case DK4_DB_BE_BDB : {
538 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
539 (back->dt).bdb.db = NULL;
540 #endif
541 } break;
542 case DK4_DB_BE_NDBM : {
543 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
544 (back->dt).ndbm.dbm = NULL;
545 #endif
546 } break;
547 }
548 back->fn = dk4str_dup(fn, erp);
549 if (NULL == back->fn) {
550 dk4mem_free(back);
551 back = NULL;
552 }
553 }
554
555 return back;
556 }
557
558
559
560 /** Close database, release resources.
561 NOTE: Only release in-memory specific things, the
562 dk4dbi_close() function calls dk4dbi_delete_base()
563 to release the base components.
564 @param db Database to close.
565 @param erp Error report, may be NULL.
566 @return 1 on success, 0 on error.
567
568 Error codes:
569 - DK4_E_SYNTAX<br>
570 if the database file name does not refer to a regular file,
571 - DK4_E_SEC_CHECK<br>
572 with failed check id in iDetails1 if access is denied by additional
573 security checks,
574 - DK4_E_OPEN_WRITE_FAILED<br>
575 with errno value in iDetails1 if fopen() or fwrite() failed,
576 - DK4_E_CLOSE_FAILED<br>
577 with errno value in iDetails1 if fclose() failed,
578 - DK4_E_WRITE_FAILD<br>
579 if fwrite() failed.
580 */
581 static
582 int
dk4dbi_close_mem(dk4_dbi_t * db,dk4_er_t * erp)583 dk4dbi_close_mem(
584 dk4_dbi_t *db,
585 dk4_er_t *erp
586 )
587 {
588 dk4_dbi_datum_t *rp; /* Current record */
589 int back = 1;
590
591 #if DK4_USE_ASSERT
592 assert(NULL != db);
593 #endif
594 if ((NULL != (db->dt).mem.s) && (NULL != (db->dt).mem.i)) {
595 /*
596 Write records to file if there are unsaved changes.
597 */
598
599 if ((0 != db->wa) && (0 != db->uc)) {
600 if (0 == dk4dbi_mem_to_file(db, erp)) {
601 back = 0;
602 }
603 }
604 /*
605 Release memory used for the records.
606 */
607 dk4sto_it_reset((db->dt).mem.i);
608 do {
609 rp = (dk4_dbi_datum_t *)dk4sto_it_next((db->dt).mem.i);
610 if (NULL != rp) {
611 if (0 == dk4dbi_datum_delete(rp, db->op)) {
612 back = 0;
613 }
614 }
615 } while (NULL != rp);
616 }
617 if (NULL != (db->dt).mem.i) {
618 dk4sto_it_close((db->dt).mem.i);
619 }
620 if (NULL != (db->dt).mem.s) {
621 dk4sto_close((db->dt).mem.s);
622 }
623 return back;
624 }
625
626
627
628 /** Open in-memory database.
629 @param fn File name.
630 @param wa Flag: Write access required.
631 @param tr Flag: Truncate existing database.
632 @param km Maximum key size.
633 @param vm Maximum value size.
634 @param erp Error report, may be NULL.
635 @return Pointer to new database structure on success, NULL on error.
636
637 Error codes:
638 - DK4_E_MATH_OVERFLOW<br>
639 on numeric overflow when calculating size,
640 - DK4_E_MEMORY_ALLOCATION_FAILED<br>
641 with mem.elsize and mem.nelem
642 set if there is not enough memory available,
643 - DK4_E_SYNTAX<br>
644 if
645 - the database file name does not refer to a regular file
646 - or the file contents is not an in-memory database
647 - or key/value sizes in the file are in conflict with size restrictions,
648 - DK4_E_SEC_CHECK<br>
649 with failed check id in iDetails1 if access is denied by additional
650 security checks,
651 - DK4_E_OPEN_READ_FAILED with errno value in iDetails1 if fopen()
652 or fread() failed,
653 - DK4_E_OPEN_WRITE_FAILED<br>
654 with errno value in iDetails1 if fopen() or fwrite() failed,
655 - DK4_E_CLOSE_FAILED<br>
656 with errno value in iDetails1 if fclose() failed.
657 */
658 static
659 dk4_dbi_t *
dk4dbi_open_mem(const dkChar * fn,int wa,int tr,size_t km,size_t vm,dk4_er_t * erp)660 dk4dbi_open_mem(
661 const dkChar *fn,
662 int wa,
663 int tr,
664 size_t km,
665 size_t vm,
666 dk4_er_t *erp
667 )
668 {
669 dk4_dbi_t *back = NULL;
670
671 #if DK4_USE_ASSERT
672 assert(NULL != fn);
673 #endif
674 if (0 != tr) {
675 (void)dk4delete_file(fn, NULL);
676 }
677 back = dk4dbi_new_base(fn, DK4_DB_BE_MEMORY, wa, km, vm, erp);
678 if (NULL != back) {
679 (back->dt).mem.s = NULL;
680 (back->dt).mem.i = NULL;
681 (back->dt).mem.s = dk4sto_open(erp);
682 if (NULL != (back->dt).mem.s) {
683 dk4sto_set_comp((back->dt).mem.s, dk4dbi_datum_compare, 0);
684 (back->dt).mem.i = dk4sto_it_open((back->dt).mem.s, erp);
685 }
686 if ((NULL != (back->dt).mem.s) && (NULL != (back->dt).mem.i)) {
687 if (0 == tr) { /* Do not truncate */
688 if (0 == dk4dbi_mem_from_file(back, erp)) {
689 (void)dk4dbi_close_mem(back, NULL);
690 back = NULL;
691 }
692 } else { /* Truncate */
693 if (0 == dk4dbi_mem_to_file(back, erp)) {
694 (void)dk4dbi_close_mem(back, NULL);
695 back = NULL;
696 }
697 }
698 } else {
699 (void)dk4dbi_close_mem(back, NULL);
700 back = NULL;
701 }
702 }
703
704 return back;
705 }
706
707
708
709 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
710
711
712 /** Close database, release resources.
713 NOTE: Only release in-memory specific things, the
714 dk4dbi_close() function calls dk4dbi_delete_base()
715 to release the base components.
716 @param db Database to close.
717 @return 1 on success, 0 on error.
718
719 Error codes:
720 - DK4_E_SYNTAX<br>
721 if the database file name does not refer to a regular file,
722 - DK4_E_SEC_CHECK<br>
723 with failed check id in iDetails1 if access is denied by additional
724 security checks,
725 - DK4_E_OPEN_WRITE_FAILED<br>
726 with errno value in iDetails1 if fopen() or fwrite() failed,
727 - DK4_E_CLOSE_FAILED<br>
728 with errno value in iDetails1 if fclose() failed,
729 - DK4_E_WRITE_FAILD<br>
730 if fwrite() failed.
731 */
732 static
733 int
dk4dbi_close_bdb(dk4_dbi_t * db)734 dk4dbi_close_bdb(
735 dk4_dbi_t *db
736 )
737 {
738 int back = 1;
739 #if DK4_USE_ASSERT
740 assert(NULL != db);
741 #endif
742 if (NULL != (db->dt).bdb.db) {
743 if ((0 != db->wa) && (0 != db->uc)) {
744 if (0 != ((db->dt).bdb.db)->sync((db->dt).bdb.db, 0)) {
745 back = 0;
746 }
747 }
748 ((db->dt).bdb.db)->close((db->dt).bdb.db, 0);
749 (db->dt).bdb.db = NULL;
750 }
751 return back;
752 }
753
754
755
756 /** Open BDB database.
757 @param fn File name.
758 @param wa Flag: Write access required.
759 @param tr Flag: Truncate existing database.
760 @param km Maximum key size.
761 @param vm Maximum value size.
762 @param erp Error report, may be NULL.
763 @return Pointer to new database structure on success, NULL on error.
764
765 Error codes:
766 - DK4_E_MATH_OVERFLOW<br>
767 on numeric overflow when calculating size,
768 - DK4_E_MEMORY_ALLOCATION_FAILED<br>
769 with mem.elsize and mem.nelem
770 set if there is not enough memory available,
771 - DK4_E_OPEN_WRITE_FAILED<br>
772 if the database can not be opened for writing,
773 - DK4_E_OPEN_READ_FAILED<br>
774 if the database can not be opened or reading,
775 - DK4_E_NOT_SUPPORTED<br>
776 when attempting to provide a wchar_t file name on
777 non-Windows systems.
778 */
779 static
780 dk4_dbi_t *
dk4dbi_open_bdb(const dkChar * fn,int wa,int tr,size_t km,size_t vm,dk4_er_t * erp)781 dk4dbi_open_bdb(
782 const dkChar *fn,
783 int wa,
784 int tr,
785 size_t km,
786 size_t vm,
787 dk4_er_t *erp
788 )
789 {
790 #if DK4_CHAR_SIZE > 1
791 #if DK4_ON_WINDOWS
792 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
793 return NULL;
794 #else
795 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
796 return NULL;
797 #endif
798 #else
799 dk4_dbi_t *back = NULL;
800 int res = 0;
801 int flags = 0;
802
803 #if DK4_USE_ASSERT
804 assert(NULL != fn);
805 #endif
806 back = dk4dbi_new_base(fn, DK4_DB_BE_BDB, wa, km, vm, erp);
807 if (NULL != back) {
808 if (0 != tr) {
809 (void)dk4delete_file(fn, NULL);
810 }
811 res = db_create(&((back->dt).bdb.db), NULL, 0);
812 if (0 == res) {
813 ((back->dt).bdb.db)->set_errfile((back->dt).bdb.db, NULL);
814 flags = ((0 != wa)
815 ? ((0 != tr) ? ((DB_CREATE) | (DB_TRUNCATE)) : (DB_CREATE))
816 : (DB_RDONLY));
817 res = ((back->dt).bdb.db)->open(
818 (back->dt).bdb.db,NULL,back->fn,NULL,DB_BTREE,(u_int32_t)flags,0600
819 );
820 if (0 != res) {
821 ((back->dt).bdb.db)->close((back->dt).bdb.db, 0);
822 (back->dt).bdb.db = NULL;
823 dk4dbi_delete_base(back);
824 back = NULL;
825 dk4error_set_simple_error_code(
826 erp,
827 ((0 != wa) ? (DK4_E_OPEN_WRITE_FAILED) : (DK4_E_OPEN_READ_FAILED))
828 );
829 }
830 } else {
831 (back->dt).bdb.db = NULL;
832 dk4dbi_delete_base(back);
833 back = NULL;
834 dk4error_set_simple_error_code(
835 erp,
836 ((0 != wa) ? (DK4_E_OPEN_WRITE_FAILED) : (DK4_E_OPEN_READ_FAILED))
837 );
838 }
839 }
840
841 return back;
842 #endif
843 }
844
845 #endif
846 /* if DK4_HAVE_DB_H */
847
848
849
850 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
851
852
853
854 /** Close database, release resources.
855 NOTE: Only release in-memory specific things, the
856 dk4dbi_close() function calls dk4dbi_delete_base()
857 to release the base components.
858 @param db Database to close.
859 @param erp Error report, may be NULL.
860 @return 1 on success, 0 on error.
861
862 Error codes:
863 - DK4_E_SYNTAX<br>
864 if the database file name does not refer to a regular file,
865 - DK4_E_SEC_CHECK<br>
866 with failed check id in iDetails1 if access is denied by additional
867 security checks,
868 - DK4_E_OPEN_WRITE_FAILED<br>
869 with errno value in iDetails1 if fopen() or fwrite() failed,
870 - DK4_E_CLOSE_FAILED<br>
871 with errno value in iDetails1 if fclose() failed,
872 - DK4_E_WRITE_FAILD<br>
873 if fwrite() failed.
874 */
875 static
876 int
dk4dbi_close_ndbm(dk4_dbi_t * db,dk4_er_t * erp)877 dk4dbi_close_ndbm(
878 dk4_dbi_t *db,
879 dk4_er_t *erp
880 )
881 {
882 int back = 1;
883 #if DK4_USE_ASSERT
884 assert(NULL != db);
885 #endif
886 if (NULL != (db->dt).ndbm.dbm) {
887 dbm_close((db->dt).ndbm.dbm);
888 (db->dt).ndbm.dbm = NULL;
889 }
890 return back;
891 }
892
893
894
895 static
896 void
dk4dbi_truncate_ndbm(const dkChar * fn)897 dk4dbi_truncate_ndbm(const dkChar *fn)
898 {
899 dkChar buf[DK4_MAX_PATH];
900 const size_t szbuf = DK4_SIZEOF(buf,dkChar);
901 #if DK4_USE_ASSERT
902 assert(NULL != fn);
903 #endif
904 if (0 != dk4str_cpy_s(buf, szbuf, fn, NULL)) {
905 if (0 != dk4str_cat_s(buf, szbuf, dk4dbi_ndbm_suffixes[0], NULL)) {
906 (void)dk4delete_file(buf, NULL);
907 }
908 }
909 if (0 != dk4str_cpy_s(buf, szbuf, fn, NULL)) {
910 if (0 != dk4str_cat_s(buf, szbuf, dk4dbi_ndbm_suffixes[1], NULL)) {
911 (void)dk4delete_file(buf, NULL);
912 }
913 }
914 }
915
916
917
918 /** Open NDBM database.
919 @param fn File name.
920 @param wa Flag: Write access required.
921 @param tr Flag: Truncate existing database.
922 @param km Maximum key size.
923 @param vm Maximum value size.
924 @param erp Error report, may be NULL.
925 @return Pointer to new database structure on success, NULL on error.
926 */
927 static
928 dk4_dbi_t *
dk4dbi_open_ndbm(const dkChar * fn,int wa,int tr,size_t km,size_t vm,dk4_er_t * erp)929 dk4dbi_open_ndbm(
930 const dkChar *fn,
931 int wa,
932 int tr,
933 size_t km,
934 size_t vm,
935 dk4_er_t *erp
936 )
937 {
938 dk4_dbi_t *back = NULL;
939 int flags = 0; /* Flags for opening the DB */
940
941
942 #if DK4_USE_ASSERT
943 assert(NULL != fn);
944 #endif
945 if (0 != tr) {
946 dk4dbi_truncate_ndbm(fn);
947 }
948 back = dk4dbi_new_base(fn, DK4_DB_BE_NDBM, wa, km, vm, erp);
949 if (NULL != back) {
950 flags = O_CREAT
951 | ((0 != wa)
952 ? ((0 != tr) ? (O_RDWR | O_TRUNC) : (O_RDWR))
953 : (O_RDONLY));
954 (back->dt).ndbm.dbm = dbm_open(fn, flags, 0600);
955 if (NULL == (back->dt).ndbm.dbm) {
956 dk4dbi_delete_base(back);
957 back = NULL;
958 dk4error_set_simple_error_code(
959 erp,
960 ((0 != wa) ? (DK4_E_OPEN_WRITE_FAILED) : (DK4_E_OPEN_READ_FAILED))
961 );
962 }
963 }
964
965 return back;
966 }
967
968 #endif
969 /* if DK4_HAVE_NDBM_H */
970
971
972
973 dk4_dbi_t *
dk4dbi_open_with_type(const dkChar * fn,int tp,int wa,int tr,size_t km,size_t vm,dk4_er_t * erp)974 dk4dbi_open_with_type(
975 const dkChar *fn,
976 int tp,
977 int wa,
978 int tr,
979 size_t km,
980 size_t vm,
981 dk4_er_t *erp
982 )
983 {
984 dk4_dbi_t *back = NULL;
985
986 #if DK4_USE_ASSERT
987 assert(NULL != fn);
988 assert((DK4_DB_BE_MEMORY == tp) || (DK4_DB_BE_BDB == tp) || (DK4_DB_BE_NDBM == tp));
989 #endif
990 if (NULL != fn) {
991 switch (tp) {
992 case DK4_DB_BE_MEMORY : {
993 back = dk4dbi_open_mem(fn, wa, tr, km, vm, erp);
994 } break;
995 case DK4_DB_BE_BDB : {
996 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
997 back = dk4dbi_open_bdb(fn, wa, tr, km, vm, erp);
998 #else
999 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1000 #endif
1001 } break;
1002 case DK4_DB_BE_NDBM : {
1003 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1004 back = dk4dbi_open_ndbm(fn, wa, tr, km, vm, erp);
1005 #else
1006 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1007 #endif
1008 } break;
1009 default : {
1010 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1011 } break;
1012 }
1013 } else {
1014 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1015 }
1016
1017 return back;
1018 }
1019
1020
1021
1022 dk4_dbi_t *
dk4dbi_open(const dkChar * fn,int wa,int tr,size_t km,size_t vm,dk4_er_t * erp)1023 dk4dbi_open(
1024 const dkChar *fn,
1025 int wa,
1026 int tr,
1027 size_t km,
1028 size_t vm,
1029 dk4_er_t *erp
1030 )
1031 {
1032 dk4_dbi_t *back = NULL;
1033 dkChar *mycopy = NULL; /* Private copy of fn */
1034 dkChar *colon = NULL; /* First colon in mycopy */
1035 const dkChar *fnp = NULL; /* File name pointer */
1036 int tp = DK4_DB_BE_MEMORY ; /* Database type */
1037
1038
1039 #if DK4_USE_ASSERT
1040 assert(NULL != fn);
1041 #endif
1042 if (NULL != fn) {
1043 mycopy = dk4str_dup(fn, erp);
1044 if (NULL != mycopy) {
1045 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1046 tp = DK4_DB_BE_NDBM;
1047 #endif
1048 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1049 tp = DK4_DB_BE_BDB;
1050 #endif
1051 fnp = fn;
1052 colon = dk4str_chr(mycopy, dkT(':'));
1053 if (NULL != colon) {
1054 if (dkT(':') == colon[1]) {
1055 fnp = &(colon[2]);
1056 *colon = dkT('\0');
1057 tp = dk4str_array_index(dk4dbi_type_names, mycopy, 0);
1058 if (DK4_DB_BE_UNKNOWN == tp) {
1059 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1060 }
1061 }
1062 }
1063 if (DK4_DB_BE_UNKNOWN != tp) {
1064 back = dk4dbi_open_with_type(fnp, tp, wa, tr, km, vm, erp);
1065 }
1066 dk4mem_free(mycopy);
1067 }
1068 } else {
1069 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1070 }
1071
1072 return back;
1073 }
1074
1075
1076
1077 const dkChar *
dk4dbi_filename_part(const dkChar * filename)1078 dk4dbi_filename_part(const dkChar *filename)
1079 {
1080 const dkChar *back = NULL;
1081 #if DK4_USE_ASSERT
1082 assert(NULL != filename);
1083 #endif
1084 if (NULL != filename) {
1085 back = dk4str_chr(filename, dkT(':'));
1086 if (NULL != back) {
1087 back++;
1088 if (dkT(':') == *back) {
1089 back++;
1090 } else {
1091 back = filename;
1092 }
1093 } else {
1094 back = filename;
1095 }
1096 }
1097 return back;
1098 }
1099
1100
1101
1102 int
dk4dbi_close(dk4_dbi_t * db,dk4_er_t * erp)1103 dk4dbi_close(
1104 dk4_dbi_t *db,
1105 dk4_er_t *erp
1106 )
1107 {
1108 int back = 0;
1109
1110 #if DK4_USE_ASSERT
1111 assert(NULL != db);
1112 #endif
1113 if (NULL != db) {
1114 switch (db->tp) {
1115 case DK4_DB_BE_MEMORY : {
1116 back = dk4dbi_close_mem(db, erp);
1117 } break;
1118 case DK4_DB_BE_BDB : {
1119 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1120 back = dk4dbi_close_bdb(db);
1121 #else
1122 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1123 #endif
1124 } break;
1125 case DK4_DB_BE_NDBM : {
1126 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1127 back = dk4dbi_close_ndbm(db, erp);
1128 #else
1129 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1130 #endif
1131 } break;
1132 }
1133 dk4dbi_delete_base(db);
1134 } else {
1135 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1136 }
1137
1138 return back;
1139 }
1140
1141
1142
1143 int
dk4dbi_set_option(dk4_dbi_t * db,int opt,int val)1144 dk4dbi_set_option(
1145 dk4_dbi_t *db,
1146 int opt,
1147 int val
1148 )
1149 {
1150 int back = 0;
1151 #if DK4_USE_ASSERT
1152 assert(NULL != db);
1153 assert((DK4_DB_OPT_RESET_KEY == opt) || (DK4_DB_OPT_RESET_VALUE == opt));
1154 #endif
1155 if (NULL != db) {
1156 switch (opt) {
1157 case DK4_DB_OPT_RESET_KEY :
1158 case DK4_DB_OPT_RESET_VALUE :
1159 {
1160 if (0 != val) {
1161 db->op |= opt;
1162 } else {
1163 db->op &= (~(opt));
1164 }
1165 back = 1;
1166 } break;
1167 }
1168 }
1169 return back;
1170 }
1171
1172
1173
1174 int
dk4dbi_delete(dk4_dbi_t * db,const void * kp,size_t ks,dk4_er_t * erp)1175 dk4dbi_delete(
1176 dk4_dbi_t *db,
1177 const void *kp,
1178 size_t ks,
1179 dk4_er_t *erp
1180 )
1181 {
1182 int back = 0;
1183 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1184 DBT k; /* Key */
1185 #endif
1186 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1187 datum datk; /* Key */
1188 #endif
1189 dk4_dbi_datum_t dat; /* Key for comparison */
1190 dk4_dbi_datum_t *rp; /* Result found in db */
1191
1192
1193 #if DK4_USE_ASSERT
1194 assert(NULL != db);
1195 assert(0 != db->wa);
1196 #endif
1197 if ((NULL != db) && (NULL != kp) && ((size_t)0UL < ks)) {
1198 if ((0 != db->wa) && (((size_t)0UL == db->km) || (db->km >= ks))) {
1199 switch (db->tp) {
1200 case DK4_DB_BE_MEMORY : {
1201 db->uc = 1;
1202 dat.kd = (void *)kp; dat.ks = ks;
1203 rp = (dk4_dbi_datum_t *)dk4sto_it_find_like(
1204 (db->dt).mem.i, &dat, 0
1205 );
1206 if (NULL != rp) {
1207 back = dk4sto_remove((db->dt).mem.s, rp, erp);
1208 if (0 != back) {
1209 if (0 == dk4dbi_datum_delete(rp, db->op)) {
1210 back = 0;
1211 }
1212 } else {
1213 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1214 }
1215 } else {
1216 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1217 }
1218 } break;
1219 case DK4_DB_BE_BDB : {
1220 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1221 if (NULL != (db->dt).bdb.db) {
1222 db->uc = 1;
1223 DK4_MEMRES(&k, sizeof(DBT));
1224 k.data = (void *)kp; k.size = (u_int32_t)ks;
1225 if (0 == ((db->dt).bdb.db)->del((db->dt).bdb.db, NULL, &k, 0)) {
1226 back = 1;
1227 } else {
1228 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
1229 }
1230 } else {
1231 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1232 }
1233 #else
1234 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1235 #endif
1236 } break;
1237 case DK4_DB_BE_NDBM : {
1238 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1239 if (NULL != (db->dt).ndbm.dbm) {
1240 db->uc = 1;
1241 DK4_MEMRES(&datk, sizeof(datum));
1242 datk.dptr = (char *)kp; datk.dsize = ks;
1243 if (0 == dbm_delete((db->dt).ndbm.dbm, datk)) {
1244 back = 1;
1245 } else {
1246 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
1247 }
1248 } else {
1249 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1250 }
1251 #else
1252 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1253 #endif
1254 } break;
1255 }
1256 } else {
1257 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1258 }
1259 } else {
1260 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1261 }
1262
1263 return back;
1264 }
1265
1266
1267
1268 int
dk4dbi_set(dk4_dbi_t * db,const void * kp,size_t ks,const void * vp,size_t vs,dk4_er_t * erp)1269 dk4dbi_set(
1270 dk4_dbi_t *db,
1271 const void *kp,
1272 size_t ks,
1273 const void *vp,
1274 size_t vs,
1275 dk4_er_t *erp
1276 )
1277 {
1278 dk4_dbi_datum_t dat; /* Key for comparison */
1279 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1280 DBT k; /* Key */
1281 DBT v; /* Value */
1282 #endif
1283 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1284 datum datk; /* Key */
1285 datum datv; /* Value */
1286 #endif
1287 dk4_dbi_datum_t *rp = NULL; /* Result record */
1288 char *nb = NULL; /* New value buffer */
1289 int back = 0;
1290
1291
1292 #if DK4_USE_ASSERT
1293 assert(NULL != db);
1294 assert(0 != db->wa);
1295 #endif
1296 if ((NULL != db) && (NULL != kp) && ((size_t)0UL < ks)) {
1297 if ((NULL != vp) && ((size_t)0UL < vs)) {
1298 if(
1299 (((size_t)0UL == db->km) || (db->km >= ks))
1300 && (((size_t)0UL == db->vm) || (db->vm >= vs))
1301 && (0 != db->wa)
1302 )
1303 {
1304 switch (db->tp) {
1305 case DK4_DB_BE_MEMORY : {
1306 db->uc = 1;
1307 dat.kd = (void *)kp; dat.ks = ks;
1308 rp = (dk4_dbi_datum_t *)dk4sto_it_find_like(
1309 (db->dt).mem.i, &dat, 0
1310 );
1311 if (NULL != rp) {
1312 nb = dk4mem_new(char,vs,erp);
1313 if (NULL != nb) {
1314 back = 1;
1315 if (NULL != rp->vd) {
1316 if (0 != (DK4_DB_OPT_RESET_VALUE & (db->op))) {
1317 if ((size_t)0UL < rp->vs) {
1318 back = dk4mem_reset_secure(rp->vd, rp->vs, NULL);
1319 }
1320 }
1321 dk4mem_free(rp->vd);
1322 }
1323 rp->vd = nb;
1324 DK4_MEMCPY(rp->vd,vp,vs);
1325 rp->vs = vs;
1326 }
1327 } else {
1328 rp = dk4dbi_datum_new(ks, vs, erp);
1329 if (NULL != rp) {
1330 DK4_MEMCPY(rp->kd,kp,ks);
1331 DK4_MEMCPY(rp->vd,vp,vs);
1332 if (0 != dk4sto_add((db->dt).mem.s, rp, erp)) {
1333 back = 1;
1334 } else {
1335 dk4dbi_datum_delete(rp, db->op);
1336 }
1337 }
1338 }
1339 } break;
1340 case DK4_DB_BE_BDB : {
1341 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1342
1343 if (NULL != (db->dt).bdb.db) {
1344 db->uc = 1;
1345 DK4_MEMRES(&k, sizeof(DBT));
1346 DK4_MEMRES(&v, sizeof(DBT));
1347 k.data = (void *)kp; v.data = (void *)vp;
1348 k.size = (u_int32_t)ks; v.size = (u_int32_t)vs;
1349
1350 ((db->dt).bdb.db)->del((db->dt).bdb.db, NULL, &k, 0);
1351 DK4_MEMRES(&k, sizeof(DBT));
1352 k.data = (void *)kp; k.size = (u_int32_t)ks;
1353
1354 if (0 == ((db->dt).bdb.db)->put((db->dt).bdb.db,NULL,&k,&v,0)) {
1355 back = 1;
1356 } else {
1357 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
1358 }
1359 } else {
1360 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1361 }
1362 #else
1363 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1364 #endif
1365 } break;
1366 case DK4_DB_BE_NDBM : {
1367 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1368 if (NULL != (db->dt).ndbm.dbm) {
1369 db->uc = 1;
1370 DK4_MEMRES(&datk, sizeof(datum));
1371 DK4_MEMRES(&datv, sizeof(datum));
1372 datk.dptr = (char *)kp; datk.dsize = ks;
1373 datv.dptr = (char *)vp; datv.dsize = vs;
1374 if (0 == dbm_store((db->dt).ndbm.dbm, datk, datv, DBM_INSERT)) {
1375 back = 1;
1376 } else {
1377 DK4_MEMRES(&datk, sizeof(datum));
1378 DK4_MEMRES(&datv, sizeof(datum));
1379 datk.dptr = (char *)kp; datk.dsize = ks;
1380 datv.dptr = (char *)vp; datv.dsize = vs;
1381 if (0 == dbm_store((db->dt).ndbm.dbm,datk,datv,DBM_REPLACE)) {
1382 back = 1;
1383 } else {
1384 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
1385 }
1386 }
1387 } else {
1388 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1389 }
1390 #else
1391 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1392 #endif
1393 } break;
1394 }
1395 }
1396 else
1397 {
1398 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1399 }
1400 } else {
1401 back = dk4dbi_delete(db, kp, ks, erp);
1402 }
1403 } else {
1404 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1405 }
1406
1407 return back;
1408 }
1409
1410
1411
1412 int
dk4dbi_sync(dk4_dbi_t * db,dk4_er_t * erp)1413 dk4dbi_sync(
1414 dk4_dbi_t *db,
1415 dk4_er_t *erp
1416 )
1417 {
1418 int back = 0;
1419
1420 #if DK4_USE_ASSERT
1421 assert(NULL != db);
1422 #endif
1423 if (NULL != db) {
1424 switch (db->tp) {
1425 case DK4_DB_BE_MEMORY : {
1426 if ((0 != db->wa) && (0 != db->uc)) {
1427 back = dk4dbi_mem_to_file(db, erp);
1428 } else {
1429 back = 1;
1430 }
1431 } break;
1432 case DK4_DB_BE_BDB : {
1433 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1434 if (NULL != (db->dt).bdb.db) {
1435 if ((0 != db->wa) && (0 != db->uc)) {
1436 if (0 == ((db->dt).bdb.db)->sync((db->dt).bdb.db, 0)) {
1437 back = 1;
1438 db->uc = 0;
1439 } else {
1440 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
1441 }
1442 } else {
1443 back = 1;
1444 }
1445 } else {
1446 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1447 }
1448 #else
1449 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1450 #endif
1451 } break;
1452 case DK4_DB_BE_NDBM : {
1453 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1454 if (NULL != (db->dt).ndbm.dbm) {
1455 back = 1;
1456 } else {
1457 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1458 }
1459 #else
1460 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1461 #endif
1462 } break;
1463 }
1464 } else {
1465 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1466 }
1467
1468 return back;
1469 }
1470
1471
1472
1473 int
dk4dbi_get(dk4_dbi_t * db,const void * kp,size_t ks,void * vp,size_t * vs,dk4_er_t * erp)1474 dk4dbi_get(
1475 dk4_dbi_t *db,
1476 const void *kp,
1477 size_t ks,
1478 void *vp,
1479 size_t *vs,
1480 dk4_er_t *erp
1481 )
1482 {
1483 dk4_dbi_datum_t dat; /* Key for comparison */
1484 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1485 DBT k; /* Key */
1486 DBT v; /* Value */
1487 #endif
1488 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1489 datum datk; /* Key */
1490 datum datv; /* Value */
1491 #endif
1492 dk4_dbi_datum_t *rp; /* Search result pointer */
1493 int back = 0;
1494
1495
1496 #if DK4_USE_ASSERT
1497 assert(NULL != db);
1498 assert(NULL != vp);
1499 assert(NULL != vs);
1500 #endif
1501 if (
1502 (NULL != db) && (NULL != kp) && ((size_t)0 < ks)
1503 && (NULL != vp) && (NULL != vs)
1504 )
1505 {
1506 if ((size_t)0UL < *vs) {
1507 if (((size_t)0UL == db->km) || (db->km >= ks)) {
1508 switch (db->tp) {
1509 case DK4_DB_BE_MEMORY : {
1510 dat.kd = (void *)kp; dat.ks = ks;
1511 rp = (dk4_dbi_datum_t *)dk4sto_it_find_like(
1512 (db->dt).mem.i, &dat, 0
1513 );
1514 if (NULL != rp) {
1515 if ((NULL != rp->vd) && ((size_t)0UL < rp->vs)) {
1516 if (*vs >= rp->vs) {
1517 DK4_MEMCPY(vp,rp->vd,rp->vs);
1518 *vs = rp->vs;
1519 back = 1;
1520 } else {
1521 dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL);
1522 }
1523 } else {
1524 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1525 }
1526 } else {
1527 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1528 }
1529 } break;
1530 case DK4_DB_BE_BDB : {
1531 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1532
1533 if (NULL != (db->dt).bdb.db) {
1534 DK4_MEMRES(&k, sizeof(DBT));
1535 DK4_MEMRES(&v, sizeof(DBT));
1536 k.data = (void *)kp; k.size = (u_int32_t)ks;
1537 v.data = (void *)vp; v.ulen = (u_int32_t)(*vs);
1538 v.flags = DB_DBT_USERMEM;
1539 if (0 == ((db->dt).bdb.db)->get((db->dt).bdb.db,NULL,&k,&v,0)) {
1540 *vs = v.size;
1541 back = 1;
1542 } else {
1543 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1544 }
1545 } else {
1546 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1547 }
1548 #else
1549
1550 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1551 #endif
1552 } break;
1553 case DK4_DB_BE_NDBM : {
1554 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1555 if (NULL != (db->dt).ndbm.dbm) {
1556 DK4_MEMRES(&datk, sizeof(datum));
1557 DK4_MEMRES(&datv, sizeof(datum));
1558 datk.dptr = (char *)kp; datk.dsize = ks;
1559 datv = dbm_fetch((db->dt).ndbm.dbm, datk);
1560 if ((NULL != datv.dptr) && (0 < datv.dsize)) {
1561 if (*vs >= datv.dsize) {
1562 DK4_MEMCPY(vp,datv.dptr,datv.dsize);
1563 *vs = datv.dsize;
1564 back = 1;
1565 } else {
1566 dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL);
1567 }
1568 } else {
1569 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1570 }
1571 } else {
1572 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1573 }
1574 #else
1575 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1576 #endif
1577 } break;
1578 }
1579 } else {
1580 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1581 }
1582 } else {
1583 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1584 }
1585 } else {
1586 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1587 }
1588
1589 return back;
1590 }
1591
1592
1593
1594 int
dk4dbi_traverse(dk4_dbi_t * db,void * obj,dk4dbi_traverse_fct_t * fct)1595 dk4dbi_traverse(
1596 dk4_dbi_t *db,
1597 void *obj,
1598 dk4dbi_traverse_fct_t *fct
1599 )
1600 {
1601 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1602 DBT dbtk; /* Key */
1603 DBT dbtv; /* Value */
1604 DBC *cp = NULL; /* Cursor for traversal */
1605 #endif
1606 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1607 datum datk; /* Key */
1608 datum datv; /* Value */
1609 #endif
1610 dk4_dbi_datum_t *dddt = NULL; /* Pointer for traversal */
1611 int res = 0; /* Operation result */
1612 #if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_NDBM_H) || (DK4_HAVE_DB_H))
1613 int first = 1; /* Flag: Retrieving first record */
1614 #endif
1615 int back = -1;
1616
1617
1618 #if DK4_USE_ASSERT
1619 assert(NULL != db);
1620 assert(NULL != fct);
1621 #endif
1622 if ((NULL != db) && (NULL != fct)) {
1623 switch (db->tp) {
1624 case DK4_DB_BE_MEMORY : {
1625 back = 1;
1626 dk4sto_it_reset((db->dt).mem.i);
1627 do {
1628 dddt = (dk4_dbi_datum_t *)dk4sto_it_next((db->dt).mem.i);
1629 if (NULL != dddt) {
1630 res = (*fct)(obj, dddt->kd, dddt->ks, dddt->vd, dddt->vs);
1631 if (res < back) { back = res; }
1632 }
1633 } while((NULL != dddt) && (-1 < back));
1634 } break;
1635 case DK4_DB_BE_BDB : {
1636 #if DK4_HAVE_DB_H && (DK4_CHAR_SIZE == 1)
1637 res = ((db->dt).bdb.db)->cursor((db->dt).bdb.db, NULL, &cp, 0);
1638 if (0 == res) {
1639 if (NULL != cp) {
1640 back = 1;
1641 DK4_MEMRES(&dbtk, sizeof(DBT));
1642 DK4_MEMRES(&dbtv, sizeof(DBT));
1643 do {
1644 #if DK4_HAVE_DB_CURSOR_C_GET
1645 res = cp->c_get(
1646 cp, &dbtk, &dbtv, ((0 != first) ? (DB_FIRST) : (DB_NEXT))
1647 );
1648 #else
1649 res = cp->get(
1650 cp, &dbtk, &dbtv, ((0 != first) ? (DB_FIRST) : (DB_NEXT))
1651 );
1652 #endif
1653 first = 0;
1654 if (0 == res) {
1655 res = (*fct)(obj, dbtk.data, dbtk.size, dbtv.data, dbtv.size);
1656 if (res < back) { back = res; }
1657 } else {
1658 res = -1; /* Failed to obtain a record, stop */
1659 }
1660 } while((-1 < res) && (-1 < back));
1661 cp->c_close(cp);
1662 } else {
1663 }
1664 } else {
1665 }
1666 #endif
1667 } break;
1668 case DK4_DB_BE_NDBM : {
1669 #if DK4_HAVE_NDBM_H && (DK4_CHAR_SIZE == 1)
1670 back = 1;
1671 do {
1672 if (0 != first) {
1673 datk = dbm_firstkey((db->dt).ndbm.dbm);
1674 first = 0;
1675 } else {
1676 datk = dbm_nextkey((db->dt).ndbm.dbm);
1677 }
1678 if ((NULL != datk.dptr) && (0 < datk.dsize)) {
1679 datv = dbm_fetch((db->dt).ndbm.dbm, datk);
1680 if ((NULL != datv.dptr) && (0 < datv.dsize)) {
1681 res = (*fct)(obj, datk.dptr, datk.dsize, datv.dptr, datv.dsize);
1682 if (res < back) { back = res; }
1683 } else {
1684 res = -1;
1685 }
1686 } else {
1687 res = -1;
1688 }
1689 } while((-1 < res) && (-1 < back));
1690 #endif
1691 } break;
1692 }
1693 }
1694 return back;
1695 }
1696
1697
1698
1699
1700 #if !DK4_ON_WINDOWS
1701 #if DK4_CHAR_SIZE == 1
1702 #if DK4_HAVE_CHOWN && DK4_HAVE_CHMOD
1703
1704 /** Change ownership and mode for a file.
1705 @param fn File name.
1706 @param user New owner.
1707 @param group New owner group.
1708 @param mode New file permissions.
1709 @param erp Error report, may be NULL.
1710 @return 1 on success, 0 on error.
1711
1712 Error codes:
1713 - DK4_E_SYSTEM<br>
1714 with errno value in iDetails1 if chown
1715 or chmod failed.
1716 */
1717 static
1718 int
dk4dbi_change_file_owner_and_mode(const dkChar * fn,uid_t user,gid_t group,mode_t mode,dk4_er_t * erp)1719 dk4dbi_change_file_owner_and_mode(
1720 const dkChar *fn,
1721 uid_t user,
1722 gid_t group,
1723 mode_t mode,
1724 dk4_er_t *erp
1725 )
1726 {
1727 int back = 0;
1728
1729
1730 errno = 0;
1731 if (0 == chown(fn, user, group)) {
1732 errno = 0;
1733 if (0 == chmod(fn, mode)) {
1734 back = 1;
1735 } else {
1736 dk4error_set_idetails(erp, DK4_E_SYSTEM, errno);
1737 }
1738 } else {
1739 dk4error_set_idetails(erp, DK4_E_SYSTEM, errno);
1740 }
1741 return back;
1742 }
1743
1744
1745 int
dk4dbi_change_owner_and_mode(dk4_dbi_t * db,uid_t user,gid_t group,mode_t mode,dk4_er_t * erp)1746 dk4dbi_change_owner_and_mode(
1747 dk4_dbi_t *db,
1748 uid_t user,
1749 gid_t group,
1750 mode_t mode,
1751 dk4_er_t *erp
1752 )
1753 {
1754 dkChar buf[DK4_MAX_PATH]; /* File names construction */
1755 const size_t szbuf = DK4_SIZEOF(buf,dkChar); /* Buffer size */
1756 int back = 0;
1757
1758
1759 #if DK4_USE_ASSERT
1760 assert(NULL != db);
1761 #endif
1762 if (NULL != db) {
1763 switch (db->tp) {
1764 case DK4_DB_BE_MEMORY :
1765 case DK4_DB_BE_BDB :
1766 {
1767 back = dk4dbi_change_file_owner_and_mode(
1768 db->fn, user, group, mode, erp
1769 );
1770 } break;
1771 case DK4_DB_BE_NDBM : {
1772 if (0 != dk4str_cpy_s(buf, szbuf, db->fn, erp)) {
1773 if (0 != dk4str_cat_s(buf, szbuf, dk4dbi_ndbm_suffixes[0], erp)) {
1774 back = dk4dbi_change_file_owner_and_mode(buf,user,group,mode,erp);
1775 (void)dk4str_cpy_s(buf, szbuf, db->fn, erp);
1776 if (0 != dk4str_cat_s(buf, szbuf, dk4dbi_ndbm_suffixes[1], erp)) {
1777 if (0 ==
1778 dk4dbi_change_file_owner_and_mode(buf,user,group,mode,erp)
1779 )
1780 {
1781 back = 0;
1782 }
1783 }
1784 }
1785 }
1786 } break;
1787 default : {
1788 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1789 } break;
1790 }
1791 } else {
1792 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1793 }
1794 return back;
1795 }
1796
1797 #endif
1798 /* if DK4_HAVE_CHOWN && DK4_HAVE_CHMOD */
1799 #endif
1800 /* if DK4_CHAR_SIZE == 1 */
1801 #endif
1802 /* if !DK4_ON_WINDOWS */
1803
1804
1805
1806 size_t
dk4dbi_get_key_max(const dk4_dbi_t * db,dk4_er_t * erp)1807 dk4dbi_get_key_max(
1808 const dk4_dbi_t *db,
1809 dk4_er_t *erp
1810 )
1811 {
1812 size_t back = 0;
1813
1814 #if DK4_USE_ASSERT
1815 assert(NULL != db);
1816 #endif
1817 if (NULL != db) {
1818 back = db->km;
1819 } else {
1820 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1821 }
1822 return back;
1823 }
1824
1825
1826
1827 size_t
dk4dbi_get_val_max(const dk4_dbi_t * db,dk4_er_t * erp)1828 dk4dbi_get_val_max(
1829 const dk4_dbi_t *db,
1830 dk4_er_t *erp
1831 )
1832 {
1833 size_t back = 0;
1834
1835 #if DK4_USE_ASSERT
1836 assert(NULL != db);
1837 #endif
1838 if (NULL != db) {
1839 back = db->vm;
1840 } else {
1841 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
1842 }
1843 return back;
1844 }
1845
1846
1847
1848 int
dk4dbi_get_type(const dk4_dbi_t * db)1849 dk4dbi_get_type(const dk4_dbi_t *db)
1850 {
1851 int back = DK4_DB_BE_UNKNOWN;
1852 #if DK4_USE_ASSERT
1853 assert(NULL != db);
1854 #endif
1855 if (NULL != db) {
1856 back = db->tp;
1857 }
1858 return back;
1859 }
1860
1861