/* Copyright (C) 2011-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk3dbi.ctr */ /** @file dk3dbi.c The dk3dbi module. */ #line 372 "dk3dbi.ctr" #include "dk3all.h" #include "dk3dbi.h" #ifdef DK3_USE_DB #undef DK3_USE_DB #endif #ifdef DK3_USE_NDBM #undef DK3_USE_NDBM #endif #if DK3_HAVE_DB_H #include /** Use Berkeley DB. */ #define DK3_USE_DB 1 #endif #if DK3_HAVE_NDBM_H #include /** Use NDBM. */ #define DK3_USE_NDBM 1 #endif #line 399 "dk3dbi.ctr" /** Data type used in storage. */ typedef struct { /** Key data. */ void *keydata; /** value data. */ void *valdata; /** Key size (number of bytes in key data). */ size_t keysize; /** Value size (number of bytes in value data). */ size_t valsize; } dk3_dbi_node_t; /** Names of database types. Order must match the definitions in @ref databasetypes. */ static dkChar const * const dk3dbi_type_names[] = { /* 0 */ dkT("mem"), /* 1 */ dkT("bdb"), /* 2 */ dkT("ndbm"), NULL #line 440 "dk3dbi.ctr" }; /** Modes to open file. */ static dkChar const * const dk3dbi_file_open_modes[] = { /* 0 */ dkT("rb"), /* 1 */ dkT("wb") }; /** File name suffixes for NDBM files. */ static char const * const dk3dbi_ndbm_suffixes[] = { ".dir", ".pag" }; /** Delete one storage node, release memory. @param np Node to delete. */ static void dk3dbi_node_delete(dk3_dbi_node_t *np) { if(np) { dk3_release(np->keydata); dk3_release(np->valdata); np->keydata = NULL; np->valdata = NULL; np->keysize = 0; np->valsize = 0; dk3_delete(np); } } /** Create a new node with specified buffer sizes. @param ks Keys size. @param vs Value size. @param app Application structure for diagnostics. @return Pointer to new node on success, NULL on error. */ static dk3_dbi_node_t * dk3dbi_node_new(size_t ks, size_t vs, dk3_app_t *app) { dk3_dbi_node_t *back = NULL; char *cpk = NULL; /* Key buffer pointer. */ char *cpv = NULL; /* Value buffer pointer. */ int ok = 0; /* Flag: Success. */ #line 494 "dk3dbi.ctr" back = dk3_new_app(dk3_dbi_node_t,1,app); if(back) { back->keysize = 0; back->valsize = 0; back->keydata = NULL; back->valdata = NULL; cpk = dk3_new_app(char,ks,app); if(cpk) { cpv = dk3_new_app(char,vs,app); if(cpv) { ok = 1; back->keydata = (void *)cpk; back->valdata = (void *)cpv; back->keysize = ks; back->valsize = vs; } } if(!(ok)) { dk3_delete(cpk); dk3_delete(cpv); dk3dbi_node_delete(back); back = NULL; } } #line 516 "dk3dbi.ctr" return back; } /** Comparison of storage nodes. @param l Left node. @param r Right node. @param cr Comparison criteria (0=node/node, 1=node/datum). @return Comparison result. */ static int dk3dbi_node_compare(void const *l, void const *r, int cr) { int back = 0; dk3_dbi_node_t const *pl; /* Left object pointer. */ dk3_dbi_node_t const *pr; /* Right object pointer. */ dk3_datum_t const *pd; /* Right object pointer (datum). */ if(l) { if(r) { pl = (dk3_dbi_node_t const *)l; switch(cr) { case 1: { pd = (dk3_datum_t const *)r; if(pl->keydata) { if(pd->dt) { if(pl->keysize > pd->sz) { back = 1; } else { if(pl->keysize < pd->sz) { back = -1; } else { back = dk3mem_cmp(pl->keydata, pd->dt, pl->keysize); if(back < -1) back = -1; if(back > 1) back = 1; } } } else { back = 1; } } else { if(pd->dt) { back = -1; } } } break; default: { pr = (dk3_dbi_node_t const *)r; if(pl->keydata) { if(pr->keydata) { if(pl->keysize > pr->keysize) { back = 1; } else { if(pl->keysize < pr->keysize) { back = -1; } else { back = dk3mem_cmp(pl->keydata, pr->keydata, pl->keysize); if(back < -1) back = -1; if(back > 1) back = 1; } } } else { back = 1; } } else { if(pr->keydata) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Read in-memory database from file. @param dbp Database to initialize. @return 1 on success (even if there is not db file yet), 0 on error. */ static int dk3dbi_mem_read_file(dk3_dbi_t *dbp) { unsigned char uc[8]; /* Buffer for key and value size. */ FILE *fipo; /* Input file. */ dk3_dbi_node_t *np; /* Node for record just read. */ unsigned char *kd; /* Key data buffer pointer. */ unsigned char *vd; /* Value data buffer pointer. */ dkChar const *oldsourcename; /* Previous source file name. */ unsigned long oldsourceline; /* Previous source file line. */ unsigned long ul1; /* Key size as unsigned long. */ unsigned long ul2; /* Value size as unsigned long. */ size_t nread; /* Number of bytes read from file. */ size_t ks; /* Key size. */ size_t vs; /* Value size. */ int ok = 0; /* Flag: Success. */ int back = 1; int cc = 1; /* Flag: Can continue. */ #line 625 "dk3dbi.ctr" oldsourcename = dk3app_get_source_file(dbp->app); oldsourceline = dk3app_get_source_line(dbp->app); dk3app_set_source_file(dbp->app, dbp->fn); dk3app_set_source_line(dbp->app, 0UL); fipo = dk3sf_fopen_app(dbp->fn, dk3dbi_file_open_modes[0], dbp->app); if(fipo) { while((cc) && (back)) { cc = 0; kd = vd = NULL; nread = dk3sf_fread_app(uc, 1, 8, fipo, dbp->app); if(nread > 0) { if(nread == 8) { ul1 = ((((unsigned long)(uc[0])) << 24) & 0xFF000000UL) | ((((unsigned long)(uc[1])) << 16) & 0x00FF0000UL) | ((((unsigned long)(uc[2])) << 8) & 0x0000FF00UL) | (( (unsigned long)(uc[3]) ) & 0x000000FFUL); ul2 = ((((unsigned long)(uc[4])) << 24) & 0xFF000000UL) | ((((unsigned long)(uc[5])) << 16) & 0x00FF0000UL) | ((((unsigned long)(uc[6])) << 8) & 0x0000FF00UL) | (( (unsigned long)(uc[7]) ) & 0x000000FFUL); ks = (size_t)ul1; vs = (size_t)ul2; if(sizeof(size_t) < 4) { if((ul1 > 0x0000FFFFUL) || (ul2 > 0x0000FFFFUL)) { back = 0; /* ERROR: Entry size too large! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 245); } } if(back) { kd = dk3_new_app(unsigned char,ks,dbp->app); vd = dk3_new_app(unsigned char,vs,dbp->app); if((kd) && (vd)) { ok = 0; nread = dk3sf_fread_app(kd, 1, ks, fipo, dbp->app); if(nread == ks) { nread = dk3sf_fread_app(vd, 1, vs, fipo, dbp->app); if(nread == vs) { np = dk3_new_app(dk3_dbi_node_t,1,dbp->app); if(np) { np->keydata = kd; np->valdata = vd; np->keysize = ks; np->valsize = vs; if(dk3sto_add((dbp->details).mem.s_mem, np)) { cc = 1; ok = 1; } else { np->keydata = np->valdata = NULL; np->keysize = np->valsize = 0; dk3_delete(np); np = NULL; back = 0; } } } else { back = 0; /* ERROR: File probably damaged! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 246); } } else { back = 0; /* ERROR: File probably damaged! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 246); } if(!(ok)) { dk3_delete(kd); dk3_delete(vd); kd = vd = NULL; #if VERSION_BEFORE_20150821 ks = vs = 0; #endif } } else { back = 0; dk3_delete(kd); dk3_delete(vd); } } } else { back = 0; /* ERROR: File probably damaged! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 246); } } else { /* End of file reached. */ } } fclose(fipo); } dk3app_set_source_file(dbp->app, oldsourcename); dk3app_set_source_line(dbp->app, oldsourceline); #line 714 "dk3dbi.ctr" return back; } /** Synchronize memory database to file. @param dbp Database. @return 1 on success, 0 on error. */ static int dk3dbi_mem_sync(dk3_dbi_t *dbp) { unsigned char uc[8]; /* Buffer for key and value size. */ FILE *fipo; /* Output file. */ dk3_dbi_node_t *np; /* Current node to process. */ unsigned long ul1; /* Key size as unsigned long. */ unsigned long ul2; /* Value size as unsigned long. */ size_t nwrite; /* Number of bytes written. */ int back = 0; #line 735 "dk3dbi.ctr" if(dbp->fn) { #line 736 "dk3dbi.ctr" fipo = dk3sf_fopen_app(dbp->fn, dk3dbi_file_open_modes[1], dbp->app); if(fipo) { #line 738 "dk3dbi.ctr" back = 1; dk3sto_it_reset((dbp->details).mem.i_mem); do { np = (dk3_dbi_node_t *)dk3sto_it_next((dbp->details).mem.i_mem); if(np) { #line 743 "dk3dbi.ctr" ul1 = (unsigned long)(np->keysize); ul2 = (unsigned long)(np->valsize); uc[0] = (unsigned char)((ul1 >> 24) & 0x000000FFUL); uc[1] = (unsigned char)((ul1 >> 16) & 0x000000FFUL); uc[2] = (unsigned char)((ul1 >> 8) & 0x000000FFUL); uc[3] = (unsigned char)( ul1 & 0x000000FFUL); uc[4] = (unsigned char)((ul2 >> 24) & 0x000000FFUL); uc[5] = (unsigned char)((ul2 >> 16) & 0x000000FFUL); uc[6] = (unsigned char)((ul2 >> 8) & 0x000000FFUL); uc[7] = (unsigned char)( ul2 & 0x000000FFUL); nwrite = dk3sf_fwrite_app(uc, 1, 8, fipo, dbp->app); if(nwrite) { #line 755 "dk3dbi.ctr" nwrite = dk3sf_fwrite_app(np->keydata,1,np->keysize,fipo,dbp->app); if(nwrite) { #line 757 "dk3dbi.ctr" nwrite = dk3sf_fwrite_app(np->valdata,1,np->valsize,fipo,dbp->app); if(!(nwrite)) { #line 760 "dk3dbi.ctr" back = 0; dbp->ec = DK3_ERROR_DURING_WRITE; } } else { #line 764 "dk3dbi.ctr" back = 0; dbp->ec = DK3_ERROR_DURING_WRITE; } } else { #line 768 "dk3dbi.ctr" back = 0; dbp->ec = DK3_ERROR_DURING_WRITE; } } } while((np) && (back)); if(!dk3sf_fclose_fn_app(fipo, dbp->fn, dbp->app)) { back = 0; } } else { #line 777 "dk3dbi.ctr" dbp->ec = DK3_ERROR_NOT_OPENED_FOR_WRITING; } } else { /* BUG: No file name, must not happen! */ } #line 782 "dk3dbi.ctr" return back; } /** Set entry (in-memory database). @param dbp Database. @param key Key data. @param val Value data. @return 1 on success, 0 on error. */ static int dk3dbi_mem_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { int back = 0; dk3_dbi_node_t *np; /* Current node to process. */ unsigned char *nb; /* New value buffer for node. */ #line 801 "dk3dbi.ctr" np = (dk3_dbi_node_t *)dk3sto_it_find_like( (dbp->details).mem.i_mem, (void *)key, 1 ); if(np) { #line 805 "dk3dbi.ctr" nb = dk3_new_app(unsigned char,val->sz,dbp->app); if(nb) { dk3mem_cpy(nb, val->dt, val->sz); dk3_release(np->valdata); np->valdata = nb; np->valsize = val->sz; back = 1; #line 812 "dk3dbi.ctr" } else { dbp->ec = DK3_ERROR_MEMORY; } } else { #line 816 "dk3dbi.ctr" np = dk3dbi_node_new(key->sz, val->sz, dbp->app); if(np) { dk3mem_cpy(np->keydata, key->dt, key->sz); dk3mem_cpy(np->valdata, val->dt, val->sz); np->keysize = key->sz; np->valsize = val->sz; if(dk3sto_add((dbp->details).mem.s_mem, (void *)np)) { back = 1; #line 824 "dk3dbi.ctr" } else { dk3dbi_node_delete(np); dbp->ec = DK3_ERROR_MEMORY; } } else { dbp->ec = DK3_ERROR_MEMORY; } } #line 832 "dk3dbi.ctr" return back; } /** Retrieve entry (in-memory database). @param dbp Database. @param key Key data. @param val Value data (input: result buffer size, output: buffer size used). @return 1 on success, 0 on error. */ static int dk3dbi_mem_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { int back = 0; dk3_dbi_node_t *np; /* Current node to process. */ #line 851 "dk3dbi.ctr" np = (dk3_dbi_node_t *)dk3sto_it_find_like( (dbp->details).mem.i_mem, (void *)key, 1 ); if(np) { #line 855 "dk3dbi.ctr" if(val->sz >= np->valsize) { dk3mem_cpy(val->dt, np->valdata, np->valsize); val->sz = np->valsize; back = 1; #line 859 "dk3dbi.ctr" } else { #line 860 "dk3dbi.ctr" } } else { #line 862 "dk3dbi.ctr" if(dbp->rfk) { if(dbp->app) { /* ERROR: Entry not found! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 249); } } } #line 870 "dk3dbi.ctr" return back; } /** Delete entry (in-memory database). @param dbp Database. @param key Key data. @return 1 on success, 0 on error. */ static int dk3dbi_mem_delete(dk3_dbi_t *dbp, dk3_datum_t *key) { dk3_dbi_node_t *np; /* Current node to process .*/ int back = 1; #line 887 "dk3dbi.ctr" np = (dk3_dbi_node_t *)dk3sto_it_find_like( (dbp->details).mem.i_mem, (void *)key, 1 ); if(np) { dk3sto_remove((dbp->details).mem.s_mem, (void *)np); dk3dbi_node_delete(np); } #line 894 "dk3dbi.ctr" return back; } /** Traverse database (in-memory database). @param dbp Database. @param obj Object to modify during traversal. @param fct Function to invoke for each key/value pair. @return 1 on success, 0 on error. */ static int dk3dbi_mem_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct) { dk3_datum_t key; /* Key data. */ dk3_datum_t val; /* Value data. */ dk3_dbi_node_t *np; /* Current node to process. */ int back = 1; int res = 1; /* Function result for current node. */ #line 915 "dk3dbi.ctr" dk3sto_it_reset((dbp->details).mem.i_mem); do { np = (dk3_dbi_node_t *)dk3sto_it_next((dbp->details).mem.i_mem); if(np) { key.sz = np->keysize; key.dt = np->keydata; val.sz = np->valsize; val.dt = np->valdata; res = (*fct)(obj, &key, &val); if(res < 1) { #line 925 "dk3dbi.ctr" back = 0; } } } while((np) && (res >= 0)); #line 930 "dk3dbi.ctr" return back; } #if DK3_USE_DB /** Open Berkeley DB file. @param dbp Database. @param trunc Flag: Truncate database. @return 1 on success, 0 on error. */ static int dk3dbi_bdb_open_file(dk3_dbi_t *dbp, int trunc) { char fnb[DK3_MAX_PATH]; /* File name buffer, 8-bit chars. */ DB *db = NULL; /* BDB. */ u_int32_t flags = 0UL; /* Flags to open BDB. */ int back = 0; int ret; /* BDB operation result. */ #line 950 "dk3dbi.ctr" if(dk3sf_filename_to_c8(fnb, sizeof(fnb), dbp->fn, dbp->app)) { ret = db_create(&db, NULL, 0); if(ret == 0) { db->set_errfile(db, NULL); flags = DB_RDONLY; if(dbp->wr) { flags = DB_CREATE; if(trunc) { flags |= DB_TRUNCATE; } } ret = db->open(db, NULL, fnb, NULL, DB_BTREE, flags, 0600); if(ret == 0) { back = 1; (dbp->details).bdb.dbptr = (void *)db; } else { db->close(db, 0); } } else { /* ERROR: Failed to create database */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 9); } } else { /* ERROR: File name conversion failed! */ dbp->ec = DK3_ERROR_INVALID_ARGS; } #line 976 "dk3dbi.ctr" return back; } /** Set entry (Berkeley DB). @param dbp Database. @param key Key data. @param val Value data. @return 1 on success, 0 on error. */ static int dk3dbi_bdb_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { DBT k; /* Key datum. */ DBT v; /* Value datum. */ DB *db; /* BDB structure. */ int res; /* BDB operation result. */ int back = 0; #line 995 "dk3dbi.ctr" db = (DB *)((dbp->details).bdb.dbptr); dk3mem_res((void *)(&k), sizeof(DBT)); dk3mem_res((void *)(&v), sizeof(DBT)); k.data = key->dt; k.size = key->sz; v.data = val->dt; v.size = val->sz; db->del(db, NULL, &k, 0); dk3mem_res((void *)(&k), sizeof(DBT)); k.data = key->dt; k.size = key->sz; res = db->put(db, NULL, &k, &v, 0); if(res == 0) { back = 1; } #line 1007 "dk3dbi.ctr" return back; } /** Retrieve entry (Berkeley DB). @param dbp Database. @param key Key data. @param val Value data (input: result buffer size, output: buffer size used). @return 1 on success, 0 on error. */ static int dk3dbi_bdb_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { DBT k; /* Key datum. */ DBT v; /* Value datum. */ DB *db; /* BDB structure. */ int res; /* BDB operation result. */ int back = 0; #line 1027 "dk3dbi.ctr" db = (DB *)((dbp->details).bdb.dbptr); dk3mem_res((void *)(&k), sizeof(DBT)); dk3mem_res((void *)(&v), sizeof(DBT)); k.data = key->dt; k.size = key->sz; v.data = val->dt; v.ulen = val->sz; v.flags = DB_DBT_USERMEM; res = db->get(db, NULL, &k, &v, 0); if(res == 0) { back = 1; val->sz = v.size; } else { if(dbp->rfk) { if(dbp->app) { /* ERROR: Entry not found! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 249); } } } #line 1044 "dk3dbi.ctr" return back; } /** Delete entry (Berkeley DB). @param dbp Database. @param key Key data. @return 1 on success, 0 on error. */ static int dk3dbi_bdb_delete(dk3_dbi_t *dbp, dk3_datum_t *key) { DBT k; /* Key datum. */ DB *db; /* BDB structure. */ int res; /* BDB operation result. */ int back = 0; #line 1061 "dk3dbi.ctr" db = (DB *)((dbp->details).bdb.dbptr); dk3mem_res((void *)(&k), sizeof(DBT)); k.data = key->dt; k.size = key->sz; res = db->del(db, NULL, &k, 0); if(res == 0) { back = 1; } #line 1068 "dk3dbi.ctr" return back; } /** Traverse database (Berkeley DB). @param dbp Database. @param obj Object to modify during traversal. @param fct Function to invoke for each key/value pair. @return 1 on success, 0 on error. */ static int dk3dbi_bdb_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct) { DBT k; /* Key datum (BDB). */ DBT v; /* Value datum (BDB). */ dk3_datum_t key; /* Key datum (dk3dbi). */ dk3_datum_t val; /* Vaue datum (dk3dbi). */ DB *db; /* BDB structure. */ DBC *cp = NULL; /* BDB cursor. */ int res; /* BDB operation result. */ int cc; /* Flag: Can continue. */ int isfirst; /* Flag: No record received yet. */ int back = 0; #line 1092 "dk3dbi.ctr" db = (DB *)((dbp->details).bdb.dbptr); res = db->cursor(db, NULL, &cp, 0); if(res == 0) { #line 1095 "dk3dbi.ctr" if(cp) { #line 1096 "dk3dbi.ctr" #if VERSION_BEFORE_20150821 cc = 1; #endif back = 1; isfirst = 1; dk3mem_res((void *)(&k), sizeof(DBT)); dk3mem_res((void *)(&v), sizeof(DBT)); do { #line 1104 "dk3dbi.ctr" cc = 0; #if DK3_HAVE_DB_CURSOR_C_GET /* 2011-10-23: c_get() not in current documentation of BDB. */ res = cp->c_get(cp, &k, &v, ((isfirst) ? (DB_FIRST) : (DB_NEXT))); #else if(isfirst) { #line 1110 "dk3dbi.ctr" res = cp->get(cp, &k, &v, DB_FIRST); } else { #line 1112 "dk3dbi.ctr" res = cp->get(cp, &k, &v, DB_NEXT); } #endif isfirst = 0; if(res == 0) { #line 1117 "dk3dbi.ctr" cc = 1; key.dt = k.data; key.sz = k.size; val.dt = v.data; val.sz = v.size; res = (*fct)(obj, &key, &val); switch(res) { case 0: { #line 1123 "dk3dbi.ctr" back = 0; } break; case -1: { #line 1126 "dk3dbi.ctr" back = 0; cc = 0; } break; } } else { #line 1130 "dk3dbi.ctr" #if VERSION_BEFORE_20150821 cc = 0; #endif if(res != DB_NOTFOUND) { #line 1134 "dk3dbi.ctr" back = 0; } } } while(cc); cp->c_close(cp); } else { #line 1140 "dk3dbi.ctr" } } else { #line 1142 "dk3dbi.ctr" } if(cp) { cp->c_close(cp); } #line 1146 "dk3dbi.ctr" return back; } #endif #if DK3_USE_NDBM /** Open NDBM database file. @param dbp Database. @param trunc Flag: Truncate database. @return 1 on success, 0 on error. */ static int dk3dbi_ndbm_open_file(dk3_dbi_t *dbp, int trunc) { DBM *dbm = NULL; /* NDBM structure. */ int back = 0; int omode = 0; /* Output file mode. */ #line 1166 "dk3dbi.ctr" omode = O_CREAT; if(dbp->wr) { #line 1168 "dk3dbi.ctr" omode |= O_RDWR; if(trunc) { #line 1170 "dk3dbi.ctr" omode |= O_TRUNC; } } else { #line 1173 "dk3dbi.ctr" omode |= O_RDONLY; } #line 1175 "dk3dbi.ctr" dbm = dbm_open(dbp->fn, omode, 0600); if(dbm) { #line 1177 "dk3dbi.ctr" (dbp->details).ndbm.dbptr = (void *)dbm; back = 1; } else { #line 1180 "dk3dbi.ctr" } #line 1181 "dk3dbi.ctr" return back; } /** Set entry (NDBM). @param dbp Database. @param key Key data. @param val Value data. @return 1 on success, 0 on error. */ static int dk3dbi_ndbm_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { datum k; /* Key datum. */ datum v; /* Value datum. */ DBM *dbm; /* NDBM structure. */ int res; /* Operation result. */ int back = 0; #line 1200 "dk3dbi.ctr" dbm = (DBM *)((dbp->details).ndbm.dbptr); dk3mem_res((void *)(&k),sizeof(datum)); dk3mem_res((void *)(&v),sizeof(datum)); k.dptr = key->dt; k.dsize = key->sz; v.dptr = val->dt; v.dsize = val->sz; res = dbm_store(dbm, k, v, DBM_INSERT); if(res == 0) { back = 1; } else { dk3mem_res((void *)(&k),sizeof(datum)); dk3mem_res((void *)(&v),sizeof(datum)); k.dptr = key->dt; k.dsize = key->sz; v.dptr = val->dt; v.dsize = val->sz; res = dbm_store(dbm, k, v, DBM_REPLACE); if(res == 0) { back = 1; } } #line 1216 "dk3dbi.ctr" return back; } /** Retrieve entry (NDBM). @param dbp Database. @param key Key data. @param val Value data (input: result buffer size, output: buffer size used). @return 1 on success, 0 on error. */ static int dk3dbi_ndbm_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { datum k; /* Key datum. */ datum v; /* Value datum. */ DBM *dbm; /* NDBM structure. */ int back = 0; #line 1235 "dk3dbi.ctr" dbm = (DBM *)((dbp->details).ndbm.dbptr); dk3mem_res((void *)(&k), sizeof(datum)); k.dptr = key->dt; k.dsize = key->sz; v = dbm_fetch(dbm, k); if((v.dptr) && (v.dsize)) { if(v.dsize <= val->sz) { dk3mem_cpy(val->dt, v.dptr, v.dsize); val->sz = v.dsize; back = 1; } } else { if(dbp->rfk) { if(dbp->app) { /* ERROR: Entry not found! */ dk3app_log_i1(dbp->app, DK3_LL_ERROR, 249); } } } #line 1253 "dk3dbi.ctr" return back; } /** Delete entry (NDBM). @param dbp Database. @param key Key data. @return 1 on success, 0 on error. */ static int dk3dbi_ndbm_delete(dk3_dbi_t *dbp, dk3_datum_t *key) { datum k; /* Key datum. */ DBM *dbm; /* NDBM structure. */ int back = 0; #line 1269 "dk3dbi.ctr" dbm = (DBM *)((dbp->details).ndbm.dbptr); dk3mem_res((void *)(&k),sizeof(datum)); k.dptr = key->dt; k.dsize = key->sz; if(dbm_delete(dbm, k) == 0) { back = 1; } #line 1275 "dk3dbi.ctr" return back; } /** Traverse database (NDBM). @param dbp Database. @param obj Object to modify during traversal. @param fct Function to invoke for each key/value pair. @return 1 on success, 0 on error. */ static int dk3dbi_ndbm_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct) { datum k; /* Key datum (NDBM). */ datum v; /* Value datum (NDBM). */ dk3_datum_t key; /* Key datum (dk3dbi). */ dk3_datum_t val; /* Value datum (dk3dbi). */ DBM *dbm; /* NDBM structure. */ int isfirst = 1; /* Flag: No record received yet. */ int cc; /* Flag: Can continue. */ int res; /* Operation result. */ int back = 1; #line 1298 "dk3dbi.ctr" dbm = (DBM *)((dbp->details).ndbm.dbptr); cc = 1; do { cc = 0; if(isfirst) { k = dbm_firstkey(dbm); } else { k = dbm_nextkey(dbm); } isfirst = 0; if((k.dptr) && (k.dsize)) { v = dbm_fetch(dbm, k); if((v.dptr) && (v.dsize)) { cc = 1; key.dt = k.dptr; key.sz = k.dsize; val.dt = v.dptr; val.sz = v.dsize; res = (*fct)(obj, &key, &val); switch(res) { case 0: { back = 0; #line 1320 "dk3dbi.ctr" } break; case -1: { back = 0; cc = 0; #line 1323 "dk3dbi.ctr" } break; } } } } while(cc); #line 1329 "dk3dbi.ctr" return back; } #endif int dk3dbi_type_supported(int tp) { int back = 0; #line 1341 "dk3dbi.ctr" switch(tp) { case DK3_DB_TYPE_MEMORY: { back = 1; } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB back = 1; #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM back = 1; #endif } break; } #line 1357 "dk3dbi.ctr" return back; } /** If no type is specified use best available database type. @return Best available database type. */ static int dk3dbi_choose_best_available_type(void) { int back = DK3_DB_TYPE_MEMORY; #line 1371 "dk3dbi.ctr" #if DK3_USE_DB back = DK3_DB_TYPE_BDB; #else #if DK3_USE_NDBM back = DK3_DB_TYPE_NDBM; #endif #endif #line 1379 "dk3dbi.ctr" return back; } /** Internal function to close the database. @param dbp Database to close. */ static void dk3dbi_close_internal(dk3_dbi_t *dbp) { dk3_dbi_node_t *np; /* Current node to process. */ #line 1393 "dk3dbi.ctr" if(dbp) { switch(dbp->tp) { case DK3_DB_TYPE_MEMORY: { if((dbp->details).mem.s_mem) { if((dbp->details).mem.i_mem) { dk3sto_it_reset((dbp->details).mem.i_mem); do { np = (dk3_dbi_node_t *)dk3sto_it_next((dbp->details).mem.i_mem); if(np) { dk3dbi_node_delete(np); } } while(np); dk3sto_it_close((dbp->details).mem.i_mem); } dk3sto_close((dbp->details).mem.s_mem); } (dbp->details).mem.s_mem = NULL; } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB DB *db; if((dbp->details).bdb.dbptr) { db = (DB *)((dbp->details).bdb.dbptr); db->close(db, 0); (dbp->details).bdb.dbptr = NULL; } #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM DBM *dbm; if((dbp->details).ndbm.dbptr) { dbm = (DBM *)((dbp->details).ndbm.dbptr); dbm_close(dbm); (dbp->details).ndbm.dbptr = NULL; } #endif } break; } dbp->app = NULL; if(dbp->fn) { dk3_delete(dbp->fn); } dbp->fn = NULL; dk3_delete(dbp); } #line 1439 "dk3dbi.ctr" } /** Synchronize database (write all modifications to file). @param dbp Database. @return 1 on success, 0 on error. */ static int dk3dbi_sync_internal(dk3_dbi_t *dbp) { int back = 0; #line 1453 "dk3dbi.ctr" switch(dbp->tp) { case DK3_DB_TYPE_MEMORY: { back = dk3dbi_mem_sync(dbp); } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB DB *db; db = (DB *)((dbp->details).bdb.dbptr); if(db->sync(db, 0) == 0) { back = 1; } #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM /* There is no sync function! */ dbp->ec = DK3_ERROR_NOT_SUPPORTED; #endif } break; } #line 1473 "dk3dbi.ctr" return back; } /** Open a database if the type is known. This function is invoked with the real file name and a known database type. @param fn File name. @param tp Database type. @param acc Access type DK3_DB_ACCESS_xxx, see @ref databaseaccess. @param pec Pointer to variable for error codes, may be NULL. @param app Application structure for diagnostics, may be NULL. @param trunc Flag: Truncate database. @return Pointer to database structure on success, NULL on error. */ static dk3_dbi_t * dk3dbi_open_app_with_tp( dkChar const *fn, int tp, int acc, int *pec, dk3_app_t *app, int trunc ) { dk3_dbi_t *back = NULL; int ok = 0; /* Flag: Success. */ #line 1504 "dk3dbi.ctr" back = dk3_new_app(dk3_dbi_t,1,app); if(back) { back->ec = 0; back->rfk = 0; back->wr = ((acc != DK3_DB_ACCESS_READ) ? 1 : 0); back->app = app; back->fn = NULL; back->tp = tp; back->mod = 0; back->fn = dk3str_dup_app(fn, app); if(back->fn) { switch(tp) { case DK3_DB_TYPE_MEMORY: { (back->details).mem.s_mem = NULL; (back->details).mem.i_mem = NULL; (back->details).mem.s_mem = dk3sto_open_app(app); if((back->details).mem.s_mem) { dk3sto_set_comp( (back->details).mem.s_mem, dk3dbi_node_compare, 0 ); (back->details).mem.i_mem = dk3sto_it_open( (back->details).mem.s_mem ); if((back->details).mem.i_mem) { if(!(trunc)) { ok = dk3dbi_mem_read_file(back); } else { ok = 1; } } } } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB (back->details).bdb.dbptr = NULL; #line 1541 "dk3dbi.ctr" ok = dk3dbi_bdb_open_file(back, trunc); #else if(pec) { *pec = DK3_ERROR_NOT_SUPPORTED; } if(app) { /* ERROR: Database type not supported! */ dk3app_log_i3( app, DK3_LL_ERROR, 247, 248, dk3dbi_type_names[1] ); } #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM (back->details).ndbm.dbptr = NULL; #line 1555 "dk3dbi.ctr" ok = dk3dbi_ndbm_open_file(back, trunc); #else if(pec) { *pec = DK3_ERROR_NOT_SUPPORTED; } #line 1558 "dk3dbi.ctr" if(app) { /* ERROR: Database type not supported! */ dk3app_log_i3( app, DK3_LL_ERROR, 247, 248, dk3dbi_type_names[2] ); } #endif } break; } } else { if(pec) { *pec = DK3_ERROR_MEMORY; } } if(!(ok)) { dk3dbi_close_internal(back); back = NULL; } } #line 1575 "dk3dbi.ctr" return back; } int dk3dbi_find_type_and_name( dkChar const **myfn, int *mytp, dkChar const *fn, int tp, int *pec, dk3_app_t *app ) { dkChar *p1; /* Start of real file name. */ int back = 0; #line 1593 "dk3dbi.ctr" *mytp = tp; p1 = dk3str_chr(fn, dkT(':')); if(p1) { #line 1596 "dk3dbi.ctr" if(p1[1] == dkT(':')) { #line 1597 "dk3dbi.ctr" *(p1++) = dkT('\0'); p1++; *myfn = p1; *mytp = dk3str_array_index(dk3dbi_type_names, fn, 0); if(*mytp >= 0) { #line 1602 "dk3dbi.ctr" if(dk3dbi_type_supported(*mytp)) { back = 1; } else { #line 1605 "dk3dbi.ctr" if(app) { /* ERROR: Database type not supported! */ dk3app_log_i3(app, DK3_LL_ERROR, 247, 248, fn); } if(pec) { *pec = DK3_ERROR_NOT_SUPPORTED; } } } else { #line 1614 "dk3dbi.ctr" if(app) { /* ERROR: Database type not found! */ dk3app_log_i3(app, DK3_LL_ERROR, 247, 248, fn); } if(pec) { *pec = DK3_ERROR_INVALID_ARGS; } } } else { #line 1623 "dk3dbi.ctr" /* Single colon */ *myfn = fn; if(tp < 0) { *mytp = dk3dbi_choose_best_available_type(); } back = 1; } } else { #line 1631 "dk3dbi.ctr" /* No colon found */ *myfn = fn; if(tp < 0) { *mytp = dk3dbi_choose_best_available_type(); } back = 1; } if(back) { if(*mytp >= 0) { if(!dk3dbi_type_supported(*mytp)) { back = 0; if(app) { /* ERROR: Database type not supported! */ } if(pec) { *pec = DK3_ERROR_NOT_SUPPORTED; } } } else { back = 0; } } #line 1653 "dk3dbi.ctr" return back; } /** Open a database. @param fn File name. @param tp Database type. @param acc Access type. @param pec Pointer to error code variable. @param app Application structure for diagnostics, may be NULL. @param trunc Flag: Truncate database. @return Pointer to new database on success, NULL on error. */ static dk3_dbi_t * dk3dbi_open_internal( dkChar const *fn, int tp, int acc, int *pec, dk3_app_t *app, int trunc ) { dkChar fnb[DK3_MAX_PATH + 16]; /* File name buffer. */ dk3_dbi_t *back = NULL; dkChar const *myfn = NULL; /* Real file name. */ int mytp = DK3_DB_TYPE_UNKNOWN; /* Database type. */ #line 1683 "dk3dbi.ctr" if(fn) { #line 1684 "dk3dbi.ctr" if(dk3str_len(fn) < DK3_SIZEOF(fnb,dkChar)) { #line 1685 "dk3dbi.ctr" dk3str_cpy_not_overlapped(fnb, fn); if(dk3dbi_find_type_and_name(&myfn ,&mytp, fnb, tp, pec, app)) { #line 1688 "dk3dbi.ctr" if((myfn) && (mytp >= 0)) { #line 1689 "dk3dbi.ctr" back = dk3dbi_open_app_with_tp(myfn, mytp, acc, pec, app, trunc); } else { #line 1691 "dk3dbi.ctr" /* BUG: Must not happen! */ } } } else { #line 1695 "dk3dbi.ctr" if(app) { /* ERROR: File name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn); } if(pec) { *pec = DK3_ERROR_INVALID_ARGS; } } } else { #line 1704 "dk3dbi.ctr" } #line 1705 "dk3dbi.ctr" return back; } dk3_dbi_t * dk3dbi_open_app( dkChar const *fn, int tp, int acc, int *pec, dk3_app_t *app ) { dk3_dbi_t *back; back = dk3dbi_open_internal(fn, tp, acc, pec, app, 0); return back; } dk3_dbi_t * dk3dbi_open_truncate_app( dkChar const *fn, int tp, int acc, int *pec, dk3_app_t *app ) { dk3_dbi_t *back; #line 1737 "dk3dbi.ctr" back = dk3dbi_open_internal(fn, tp, acc, pec, app, 1); #line 1739 "dk3dbi.ctr" return back; } dk3_dbi_t * dk3dbi_open(dkChar const *fn, int tp, int acc, int *pec) { dk3_dbi_t *back = NULL; #line 1749 "dk3dbi.ctr" back = dk3dbi_open_app(fn, tp, acc, pec, NULL); #line 1751 "dk3dbi.ctr" return back; } dk3_dbi_t * dk3dbi_open_truncate(dkChar const *fn, int tp, int acc, int *pec) { dk3_dbi_t *back; back = dk3dbi_open_truncate_app(fn, tp, acc, pec, NULL); return back; } int dk3dbi_close(dk3_dbi_t *dbp) { int back = 0; #line 1771 "dk3dbi.ctr" if(dbp) { back = 1; if(dbp->mod) { #line 1774 "dk3dbi.ctr" back = dk3dbi_sync_internal(dbp); } dk3dbi_close_internal(dbp); } #line 1778 "dk3dbi.ctr" return back; } int dk3dbi_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { int back = 0; #line 1788 "dk3dbi.ctr" if((dbp) && (key) && (val)) { if((key->dt) && (key->sz) && (val->dt) && (val->sz)) { if(dbp->wr) { switch(dbp->tp) { case DK3_DB_TYPE_MEMORY: { back = dk3dbi_mem_set(dbp, key, val); dbp->mod = 1; } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB back = dk3dbi_bdb_set(dbp, key, val); dbp->mod = 1; #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM back = dk3dbi_ndbm_set(dbp, key, val); dbp->mod = 1; #endif } break; } } else { /* ERROR: Write operations denied! */ dbp->ec = DK3_ERROR_NOT_OPENED_FOR_WRITING; if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 251); } } } else { dbp->ec = DK3_ERROR_INVALID_ARGS; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 1824 "dk3dbi.ctr" return back; } int dk3dbi_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val) { int back = 0; #line 1834 "dk3dbi.ctr" if((dbp) && (key) && (val)) { if((key->dt) && (key->sz) && (val->dt) && (val->sz)) { switch(dbp->tp) { case DK3_DB_TYPE_MEMORY: { back = dk3dbi_mem_get(dbp, key, val); } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB back = dk3dbi_bdb_get(dbp, key, val); #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM back = dk3dbi_ndbm_get(dbp, key, val); #endif } break; } } else { dbp->ec = DK3_ERROR_INVALID_ARGS; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 1859 "dk3dbi.ctr" return back; } int dk3dbi_delete(dk3_dbi_t *dbp, dk3_datum_t *key) { int back = 0; #line 1869 "dk3dbi.ctr" if((dbp) && (key)) { if((key->dt) && (key->sz)) { switch(dbp->tp) { case DK3_DB_TYPE_MEMORY: { back = dk3dbi_mem_delete(dbp, key); dbp->mod = 1; } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB back = dk3dbi_bdb_delete(dbp, key); dbp->mod = 1; #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM back = dk3dbi_ndbm_delete(dbp, key); dbp->mod = 1; #endif } break; } } else { dbp->ec = DK3_ERROR_INVALID_ARGS; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 1897 "dk3dbi.ctr" return back; } int dk3dbi_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct) { int back = 0; #line 1907 "dk3dbi.ctr" if((dbp) && (fct)) { switch(dbp->tp) { case DK3_DB_TYPE_MEMORY: { back = dk3dbi_mem_traverse(dbp, obj, fct); } break; case DK3_DB_TYPE_BDB: { #if DK3_USE_DB back = dk3dbi_bdb_traverse(dbp, obj, fct); #endif } break; case DK3_DB_TYPE_NDBM: { #if DK3_USE_NDBM back = dk3dbi_ndbm_traverse(dbp, obj, fct); #endif } break; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 1928 "dk3dbi.ctr" return back; } int dk3dbi_sync(dk3_dbi_t *dbp) { int back = 0; #line 1938 "dk3dbi.ctr" if(dbp) { back = 1; if(dbp->mod) { back = dk3dbi_sync_internal(dbp); if(back) { dbp->mod = 0; } } } #line 1945 "dk3dbi.ctr" return back; } int dk3dbi_get_error(dk3_dbi_t *dbp, int res) { int back = 0; #line 1955 "dk3dbi.ctr" if(dbp) { back = dbp->ec; if(res) { dbp->ec = 0; } } #line 1959 "dk3dbi.ctr" return back; } int dk3dbi_set_c8_string( dk3_dbi_t *dbp, char const *key, char const *val ) { dk3_datum_t k; /* Key datum. */ dk3_datum_t v; /* Value datum. */ size_t ks; /* Key size (number of bytes). */ size_t vs; /* Value size (number of bytes). */ int back = 0; #line 1977 "dk3dbi.ctr" if((dbp) && (key) && (val)) { ks = dk3str_c8_len(key); vs = dk3str_c8_len(val); ks++; vs++; if((ks) && (vs)) { k.dt = (void *)key; k.sz = ks; v.dt = (void *)val; v.sz = vs; back = dk3dbi_set(dbp, &k, &v); } else { /* ERROR: At least one numeric overflow. */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 1997 "dk3dbi.ctr" return back; } int dk3dbi_get_c8_string( dk3_dbi_t *dbp, char const *key, char *vb, size_t vbsz ) { dk3_datum_t k; /* Key datum. */ dk3_datum_t v; /* Value datum. */ size_t ks; /* Key size (number of bytes). */ int back = 0; int orfk; #line 2016 "dk3dbi.ctr" if((dbp) && (key) && (vb) && (vbsz)) { ks = dk3str_c8_len(key); ks++; if(ks) { k.dt = (void *)key; k.sz = ks; v.dt = vb; v.sz = vbsz; orfk = dbp->rfk; dbp->rfk = 0; if(dk3dbi_get(dbp, &k, &v)) { back = 1; if(v.sz > 0) { if(v.sz < vbsz) { vb[v.sz] = '\0'; } else { vb[vbsz - 1] = '\0'; } } else { vb[0] = '\0'; } } dbp->rfk = orfk; } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2049 "dk3dbi.ctr" return back; } int dk3dbi_delete_c8_string( dk3_dbi_t *dbp, char const *key ) { dk3_datum_t k; /* Key datum. */ size_t ks; /* Key size in bytes. */ int back = 0; #line 2064 "dk3dbi.ctr" if((dbp) && (key)) { ks = dk3str_c8_len(key); ks++; if(ks) { k.dt = (void *)key; k.sz = ks; back = dk3dbi_delete(dbp, &k); } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2082 "dk3dbi.ctr" return back; } int dk3dbi_set_c16_string( dk3_dbi_t *dbp, dk3_c16_t const *key, dk3_c16_t const *val ) { dk3_datum_t k; /* Key datum. */ dk3_datum_t v; /* Value datum. */ size_t ks; /* Key size (number of bytes). */ size_t vs; /* Value size (number of bytes). */ int back = 0; #line 2100 "dk3dbi.ctr" if((dbp) && (key) && (val)) { ks = dk3str_c16_len(key); vs = dk3str_c16_len(val); ks = dk3mem_mul_size_t(dk3mem_add_size_t(ks, 1, NULL), 2, NULL); vs = dk3mem_mul_size_t(dk3mem_add_size_t(vs, 1, NULL), 2, NULL); if((ks) && (vs)) { k.dt = (void *)key; k.sz = ks; v.dt = (void *)val; v.sz = vs; back = dk3dbi_set(dbp, &k, &v); } else { /* ERROR: Size overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2120 "dk3dbi.ctr" return back; } int dk3dbi_get_c16_string( dk3_dbi_t *dbp, dk3_c16_t const *key, dk3_c16_t *vb, size_t vbsz ) { dk3_datum_t k; /* Key datum. */ dk3_datum_t v; /* Value datum. */ size_t ks; /* Key size (number of bytes). */ size_t vs; /* Value size (number of bytes). */ int back = 0; int orfk; #line 2140 "dk3dbi.ctr" if((dbp) && (key) && (vb) && (vbsz)) { ks = dk3str_c16_len(key); ks = dk3mem_mul_size_t(dk3mem_add_size_t(ks, 1, NULL), 2, NULL); vs = dk3mem_mul_size_t(vbsz, 2, NULL); if((ks) && (vs)) { k.dt = (void *)key; k.sz = ks; v.dt = vb, v.sz = vs; orfk = dbp->rfk; dbp->rfk = 0; if(dk3dbi_get(dbp, &k, &v)) { if(!((v.sz) % 2)) { back = 1; v.sz = v.sz / 2; if(v.sz > 0) { if(v.sz < vbsz) { vb[v.sz] = 0U; } else { vb[vbsz - 1] = 0U; } } else { vb[0] = 0U; } } else { /* ERROR: Damaged entry! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 250); } dbp->ec = DK3_ERROR_DATA_DAMAGED; } } dbp->rfk = orfk; } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2182 "dk3dbi.ctr" return back; } int dk3dbi_delete_c16_string( dk3_dbi_t *dbp, dk3_c16_t const *key ) { dk3_datum_t k; /* Key datum. */ size_t ks; /* Key size (number of bytes). */ int back = 0; #line 2197 "dk3dbi.ctr" if((dbp) && (key)) { ks = dk3str_c16_len(key); ks = dk3mem_mul_size_t(dk3mem_add_size_t(ks, 1, NULL), 2, NULL); if(ks) { k.dt = (void *)key; k.sz = ks; back = dk3dbi_delete(dbp, &k); } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2215 "dk3dbi.ctr" return back; } int dk3dbi_set_c32_string( dk3_dbi_t *dbp, dk3_c32_t const *key, dk3_c32_t const *val ) { dk3_datum_t k; /* Key datum. */ dk3_datum_t v; /* Value datum. */ size_t ks; /* Key size (number of bytes). */ size_t vs; /* Value size (number of bytes). */ int back = 0; #line 2233 "dk3dbi.ctr" if((dbp) && (key) && (val)) { ks = dk3str_c32_len(key); ks = dk3mem_mul_size_t(dk3mem_add_size_t(ks, 1, NULL), 4, NULL); vs = dk3str_c32_len(val); vs = dk3mem_mul_size_t(dk3mem_add_size_t(vs, 1, NULL), 4, NULL); if((ks) && (vs)) { k.dt = (void *)key; k.sz = ks; v.dt = (void *)val; v.sz = vs; back = dk3dbi_set(dbp, &k, &v); } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2253 "dk3dbi.ctr" return back; } int dk3dbi_get_c32_string( dk3_dbi_t *dbp, dk3_c32_t const *key, dk3_c32_t *vb, size_t vbsz ) { dk3_datum_t k; /* Key datum. */ dk3_datum_t v; /* Value datum. */ size_t ks; /* Key size (number of bytes). */ size_t vs; /* Value size (number of bytes). */ int back = 0; int orfk; #line 2273 "dk3dbi.ctr" if((dbp) && (key) && (vb) && (vbsz)) { ks = dk3str_c32_len(key); ks = dk3mem_mul_size_t(dk3mem_add_size_t(ks, 1, NULL), 4, NULL); vs = dk3mem_mul_size_t(vbsz, 4, NULL); if((ks) && (vs)) { k.dt = (void *)key; k.sz = ks; v.dt = vb; v.sz = vs; orfk = dbp->rfk; dbp->rfk = 0; if(dk3dbi_get(dbp, &k, &v)) { if(!((v.sz) % 4)) { back = 1; v.sz = v.sz / 4; if(v.sz > 0) { if(v.sz < vbsz) { vb[v.sz] = 0UL; } else { vb[vbsz - 1] = 0UL; } } else { vb[0] = 0UL; } } else { /* ERROR: Damaged entry! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 250); } dbp->ec = DK3_ERROR_DATA_DAMAGED; } } dbp->rfk = orfk; } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2315 "dk3dbi.ctr" return back; } int dk3dbi_delete_c32_string( dk3_dbi_t *dbp, dk3_c32_t const *key ) { dk3_datum_t k; /* Key datum. */ size_t ks; /* Key size (number of bytes). */ int back = 0; #line 2330 "dk3dbi.ctr" if((dbp) && (key)) { ks = dk3str_c32_len(key); ks = dk3mem_mul_size_t(dk3mem_add_size_t(ks, 1, NULL), 4, NULL); if(ks) { k.dt = (void *)key; k.sz = ks; back = dk3dbi_delete(dbp, &k); } else { /* ERROR: Numeric overflow! */ if(dbp->app) { dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15); } dbp->ec = DK3_ERROR_MATH_OVERFLOW; } } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2348 "dk3dbi.ctr" return back; } int dk3dbi_set_string( dk3_dbi_t *dbp, dkChar const *key, dkChar const *val ) { int back = 0; #line 2362 "dk3dbi.ctr" if((dbp) && (key) && (val)) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 back = dk3dbi_set_c32_string(dbp, key, val); #else back = dk3dbi_set_c16_string(dbp, key, val); #endif #else back = dk3dbi_set_c8_string(dbp, key, val); #endif } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2377 "dk3dbi.ctr" return back; } int dk3dbi_get_string( dk3_dbi_t *dbp, dkChar const *key, dkChar *vb, size_t vbsz ) { int back = 0; #line 2392 "dk3dbi.ctr" if((dbp) && (key) && (vb) && (vbsz)) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 back = dk3dbi_get_c32_string(dbp, key, vb, vbsz); #else back = dk3dbi_get_c16_string(dbp, key, vb, vbsz); #endif #else back = dk3dbi_get_c8_string(dbp, key, vb, vbsz); #endif } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2407 "dk3dbi.ctr" return back; } int dk3dbi_delete_string( dk3_dbi_t *dbp, dkChar const *key ) { int back = 0; #line 2419 "dk3dbi.ctr" if((dbp) && (key)) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 back = dk3dbi_delete_c32_string(dbp, key); #else back = dk3dbi_delete_c16_string(dbp, key); #endif #else back = dk3dbi_delete_c8_string(dbp, key); #endif } else { if(dbp) { dbp->ec = DK3_ERROR_INVALID_ARGS; } } #line 2434 "dk3dbi.ctr" return back; } /** Delete or truncate a database file. @param fn File name. @param tp Database type. @param del Flag: Delete (non-zero) or truncate (0). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3dbi_dbfile_del_or_trunc(dkChar const *fn, int tp, int del, dk3_app_t *app) { dkChar fnb[DK3_MAX_PATH + 16]; /* Copy of file name. */ char c8fn[DK3_MAX_PATH]; /* File name as 8-bit. */ FILE *fipo; /* File to truncate. */ dkChar const *myfn; /* File name. */ int ec = 0; /* Error code. */ int mytp; /* DB type. */ int back = 0; #line 2458 "dk3dbi.ctr" mytp = tp; if(fn) { if(dk3str_len(fn) < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, fn); if(dk3dbi_find_type_and_name(&myfn, &mytp, fnb, tp, &ec, app)) { if((myfn) && (mytp >= 0)) { switch(mytp) { case DK3_DB_TYPE_MEMORY: { #line 2466 "dk3dbi.ctr" if(del) { dk3sf_remove_file_app(myfn, app); back = 1; } else { fipo = dk3sf_fopen_app(myfn, dk3dbi_file_open_modes[1], app); if(fipo) { #line 2472 "dk3dbi.ctr" if(dk3sf_fclose_fn_app(fipo, myfn, app)) { back = 1; } } else { #line 2476 "dk3dbi.ctr" } } } break; case DK3_DB_TYPE_BDB: { #line 2480 "dk3dbi.ctr" if(dk3sf_filename_to_c8(c8fn, sizeof(c8fn), myfn, app)) { if(del) { dk3sf_remove_file_app(myfn, app); back = 1; } else { #if DK3_USE_DB DB *db = NULL; int ret; u_int32_t flags; ret = db_create(&db, NULL, 0); if(ret == 0) { #line 2491 "dk3dbi.ctr" flags = DB_CREATE | DB_TRUNCATE; ret = db->open(db, NULL, c8fn, NULL, DB_BTREE, flags, 0600); if(ret == 0) { #line 2494 "dk3dbi.ctr" back = 1; } else { #line 2496 "dk3dbi.ctr" } if(db) { db->close(db, 0); } } else { #line 2501 "dk3dbi.ctr" } #endif } } else { #line 2505 "dk3dbi.ctr" } } break; case DK3_DB_TYPE_NDBM: { #line 2508 "dk3dbi.ctr" if(dk3sf_filename_to_c8(c8fn, sizeof(c8fn), myfn, app)) { if(del) { if((dk3str_c8_len(c8fn) + dk3str_c8_len(dk3dbi_ndbm_suffixes[0]) ) < sizeof(c8fn) ) { dk3str_c8_cat(c8fn, dk3dbi_ndbm_suffixes[0]); dk3sf_c8_remove_file_app(c8fn, app); dk3sf_filename_to_c8(c8fn, sizeof(c8fn), myfn, app); if((dk3str_c8_len(c8fn) + dk3str_c8_len(dk3dbi_ndbm_suffixes[1]) ) < sizeof(c8fn) ) { dk3str_c8_cat(c8fn, dk3dbi_ndbm_suffixes[1]); dk3sf_c8_remove_file_app(c8fn, app); back = 1; } } } else { #if DK3_USE_NDBM DBM *dbm = NULL; dbm = dbm_open(c8fn, (O_RDWR | O_CREAT | O_TRUNC), 0600); if(dbm) { dbm_close(dbm); } #endif } } else { #line 2538 "dk3dbi.ctr" } } break; default: { /* BUG: Illegal database type, must not happen! */ } break; } } else { #line 2545 "dk3dbi.ctr" /* BUG: Must not happen! */ } } else { #line 2548 "dk3dbi.ctr" /* Error: Name or type not found, already reported! */ } } else { #line 2551 "dk3dbi.ctr" /* ERROR: File name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn); } } else { #line 2555 "dk3dbi.ctr" } #line 2556 "dk3dbi.ctr" return back; } int dk3dbi_dbfile_delete_app(dkChar const *fn, int tp, dk3_app_t *app) { int back; #line 2566 "dk3dbi.ctr" back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, app); #line 2568 "dk3dbi.ctr" return back; } int dk3dbi_dbfile_truncate_app(dkChar const *fn, int tp, dk3_app_t *app) { int back; #line 2578 "dk3dbi.ctr" back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, app); #line 2580 "dk3dbi.ctr" return back; } int dk3dbi_dbfile_delete(dkChar const *fn, int tp) { int back; #line 2590 "dk3dbi.ctr" back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, NULL); #line 2592 "dk3dbi.ctr" return back; } int dk3dbi_dbfile_truncate(dkChar const *fn, int tp) { int back; #line 2602 "dk3dbi.ctr" back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, NULL); #line 2604 "dk3dbi.ctr" return back; } #if !DK3_ON_WINDOWS #if DK3_CHAR_SIZE == 1 #if DK3_HAVE_CHOWN && DK3_HAVE_CHMOD static int dk3dbi_change_file_user_and_permissions( dk3_dbi_t *db, char const *fn, uid_t uid, gid_t gid, mode_t mode ) { int back = 0; if(0 == chown(fn, uid, gid)) { if(0 == chmod(fn, mode)) { back = 1; } else { /* ERROR: Failed to change file permissions! */ if(db->app) { dk3app_log_i3(db->app, DK3_LL_ERROR, 272, 273, fn); } } } else { /* ERROR: Failed to change file ownership! */ if(db->app) { dk3app_log_i3(db->app, DK3_LL_ERROR, 270, 271, fn); } } return back; } int dk3dbi_change_user_and_permissions( dk3_dbi_t *db, uid_t uid, gid_t gid, mode_t mode ) { dkChar fnb[DK3_MAX_PATH]; int back = 0; if(db) { switch(db->tp) { case DK3_DB_TYPE_MEMORY: case DK3_DB_TYPE_BDB: { if(db->fn) { back = dk3dbi_change_file_user_and_permissions( db, db->fn, uid, gid, mode ); } else { /* ERROR: No file name for database! */ if(db->app) { dk3app_log_i1(db->app, DK3_LL_ERROR, 269); } } } break; case DK3_DB_TYPE_NDBM: { if(db->fn) { if(dk3str_len(db->fn) < DK3_SIZEOF(fnb,dkChar)) { back = 1; dk3str_cpy_not_overlapped(fnb, db->fn); if((dk3str_len(fnb) + dk3str_len(dk3dbi_ndbm_suffixes[0])) < DK3_SIZEOF(fnb,dkChar) ) { dk3str_cat(fnb, dk3dbi_ndbm_suffixes[0]); if(!dk3dbi_change_file_user_and_permissions(db,fnb,uid,gid,mode)) { back = 0; } } else { /* ERROR: File name too long! */ if(db->app) { dk3app_log_i3(db->app, DK3_LL_ERROR, 66, 67, db->fn); } back = 0; } dk3str_cpy_not_overlapped(fnb, db->fn); if((dk3str_len(fnb) + dk3str_len(dk3dbi_ndbm_suffixes[1])) < DK3_SIZEOF(fnb,dkChar) ) { dk3str_cat(fnb, dk3dbi_ndbm_suffixes[1]); if(!dk3dbi_change_file_user_and_permissions(db,fnb,uid,gid,mode)) { back = 0; } } else { /* ERROR: File name too long! */ if(db->app) { dk3app_log_i3(db->app, DK3_LL_ERROR, 66, 67, db->fn); } back = 0; } } else { /* ERROR: File name too long! */ if(db->app) { dk3app_log_i3(db->app, DK3_LL_ERROR, 66, 67, db->fn); } } } else { /* ERROR: No file name for database! */ if(db->app) { dk3app_log_i1(db->app, DK3_LL_ERROR, 269); } } } break; } } return back; } #endif #endif #endif