/* WARNING: This file was generated by dkct. 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 */ /* Copyright (C) 2011-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @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