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