Remove cdb support

This commit is contained in:
RElesgoe 2018-04-28 20:58:14 -07:00
parent 5699020a6b
commit 0923f6a52e
25 changed files with 6 additions and 1975 deletions

View file

@ -21,9 +21,6 @@ if(WITH_BNETD)
bnxpcalc.conf bnxplevel.conf channel.conf command_groups.conf
realm.conf sql_DB_layout.conf supportfile.conf topics.conf
tournament.conf versioncheck.json icons.conf)
# special treatment for non .in files
install(FILES bnetd_default_user.cdb DESTINATION ${SYSCONFDIR})
endif(WITH_BNETD)
if(WITH_D2CS)

View file

@ -34,8 +34,6 @@
# Syntax: #
# * for plain file driver: #
# storage_path = file:mode=plain;dir=<path_to_user_files>;clan=<path_to_clan_files>;default=/path/to/default/account #
# * for cdb file driver: #
# storage_path = file:mode=cdb;dir=<path_to_cdb_files>;clan=<path_to_clan_files>;default=/path/to/default/account #
# * for sql driver: #
# storage_path = sql:variable=value;...;default=0 (0 is the default uid) #
# #
@ -52,7 +50,6 @@
# #
# Examples: #
# storage_path = "file:mode=plain;dir=${LOCALSTATEDIR}/users;clan=${LOCALSTATEDIR}/clans;team=${LOCALSTATEDIR}/teams;default=${SYSCONFDIR}/bnetd_default_user.plain"
# storage_path = "file:mode=cdb;dir=${LOCALSTATEDIR}/userscdb;clan=${LOCALSTATEDIR}/clans;team=${LOCALSTATEDIR}/teams;default=${SYSCONFDIR}/bnetd_default_user.cdb"
# storage_path = "sql:mode=mysql;host=127.0.0.1;name=PVPGN;user=pvpgn;pass=pvpgnrocks;default=0;prefix=pvpgn_"
# storage_path = "sql:mode=pgsql;host=127.0.0.1;name=pvpgn;user=pvpgn;pass=pvpgnrocks;default=0;prefix=pvpgn_"
# storage_path = "sql:mode=sqlite3;name=${LOCALSTATEDIR}/users.db;default=0;prefix=pvpgn_"

Binary file not shown.

View file

@ -5,8 +5,7 @@ include_directories(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src)
# when referenced by short names
link_directories(${CMAKE_BINARY_DIR}/src/common
${CMAKE_BINARY_DIR}/src/compat
${CMAKE_BINARY_DIR}/src/win32
${CMAKE_BINARY_DIR}/src/tinycdb)
${CMAKE_BINARY_DIR}/src/win32)
#this is needed to be compatible with existent code
add_definitions("-DHAVE_CONFIG_H")
@ -32,15 +31,12 @@ endif(SQLITE3_FOUND)
if(PGSQL_FOUND)
add_definitions("-DWITH_SQL_PGSQL")
endif(PGSQL_FOUND)
if(ODBC_FOUND)
add_definitions("-DWITH_SQL_ODBC")
endif(ODBC_FOUND)
if (WITH_WIN32_GUI)
add_definitions("-DWIN32_GUI")
endif (WITH_WIN32_GUI)
subdirs(compat common win32 tinycdb bntrackd client bniutils bnpass)
subdirs(compat common win32 bntrackd client bniutils bnpass)
if(WITH_BNETD)
add_subdirectory(bnetd)

View file

@ -12,8 +12,8 @@ set(BNETD_SOURCES
attrlayer.h autoupdate.cpp autoupdate.h channel_conv.cpp channel_conv.h
channel.cpp channel.h character.cpp character.h clan.cpp clan.h
cmdline.cpp cmdline.h command.cpp command_groups.cpp command_groups.h
command.h connection.cpp connection.h file_cdb.cpp file_cdb.h file.cpp
file.h file_plain.cpp file_plain.h friends.cpp friends.h game_conv.cpp
command.h connection.cpp connection.h file.cpp file.h file_plain.cpp
file_plain.h friends.cpp friends.h game_conv.cpp
game_conv.h game.cpp game.h handle_anongame.cpp handle_anongame.h
handle_apireg.cpp handle_apireg.h handle_bnet.cpp handle_bnet.h
handle_bot.cpp handle_bot.h handle_d2cs.cpp handle_d2cs.h
@ -53,6 +53,6 @@ else(WITH_WIN32_GUI)
add_executable(bnetd ${BNETD_SOURCES} ${BNETD_CONSOLE_RESOURCES})
endif(WITH_WIN32_GUI)
target_link_libraries(bnetd common compat win32 tinycdb ${NETWORK_LIBRARIES}
target_link_libraries(bnetd common compat win32 ${NETWORK_LIBRARIES}
${ZLIB_LIBRARIES} ${MYSQL_LIBRARIES} ${SQLITE3_LIBRARIES} ${PGSQL_LIBRARIES} ${ODBC_LIBRARIES} ${LUA_LIBRARIES})
install(TARGETS bnetd DESTINATION ${SBINDIR})

View file

@ -1,256 +0,0 @@
/*
* Copyright (C) 2003,2004 Dizzy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common/setup_before.h"
#include "file_cdb.h"
#include <cstdio>
#include <cstring>
#include "common/eventlog.h"
#include "tinycdb/cdb.h"
#include "common/setup_after.h"
namespace pvpgn
{
namespace bnetd
{
/* cdb file storage API functions */
static int cdb_read_attrs(const char *filename, t_read_attr_func cb, void *data);
static t_attr * cdb_read_attr(const char *filename, const char *key);
static int cdb_write_attrs(const char *filename, const t_hlist *attributes);
/* file_engine struct populated with the functions above */
t_file_engine file_cdb = {
cdb_read_attr,
cdb_read_attrs,
cdb_write_attrs
};
/* start of actual cdb file storage code */
//#define CDB_ON_DEMAND 1
static int cdb_write_attrs(const char *filename, const t_hlist *attributes)
{
std::FILE *cdbfile;
t_hlist *curr;
t_attr *attr;
struct cdb_make cdbm;
if ((cdbfile = std::fopen(filename, "w+b")) == NULL) {
eventlog(eventlog_level_error, __FUNCTION__, "unable to open file \"{}\" for writing ", filename);
return -1;
}
cdb_make_start(&cdbm, cdbfile);
hlist_for_each(curr, attributes) {
attr = hlist_entry(curr, t_attr, link);
if (attr_get_key(attr) && attr_get_val(attr)) {
if (std::strncmp("BNET\\CharacterDefault\\", attr_get_key(attr), 20) == 0) {
eventlog(eventlog_level_debug, __FUNCTION__, "skipping attribute key=\"{}\"", attr_get_key(attr));
}
else {
eventlog(eventlog_level_debug, __FUNCTION__, "saving attribute key=\"{}\" val=\"{}\"", attr_get_key(attr), attr_get_val(attr));
if (cdb_make_add(&cdbm, attr_get_key(attr), std::strlen(attr_get_key(attr)), attr_get_val(attr), std::strlen(attr_get_val(attr))) < 0)
{
eventlog(eventlog_level_error, __FUNCTION__, "got error on cdb_make_add ('{}' = '{}')", attr_get_key(attr), attr_get_val(attr));
cdb_make_finish(&cdbm); /* try to bail out nicely */
std::fclose(cdbfile);
return -1;
}
}
}
else eventlog(eventlog_level_error, __FUNCTION__, "could not save attribute key=\"{}\"", attr_get_key(attr));
attr_clear_dirty(attr);
}
if (cdb_make_finish(&cdbm) < 0) {
eventlog(eventlog_level_error, __FUNCTION__, "got error on cdb_make_finish");
std::fclose(cdbfile);
return -1;
}
if (std::fclose(cdbfile) < 0) {
eventlog(eventlog_level_error, __FUNCTION__, "got error on std::fclose()");
return -1;
}
return 0;
}
#ifndef CDB_ON_DEMAND
/* code adapted from tinycdb-0.73/cdb.c */
static int fget(std::FILE * fd, unsigned char *b, cdbi_t len, cdbi_t *posp, cdbi_t limit)
{
if (posp && limit - *posp < len) {
eventlog(eventlog_level_error, __FUNCTION__, "invalid cdb database format");
return -1;
}
if (std::fread(b, 1, len, fd) != len) {
if (std::ferror(fd)) {
eventlog(eventlog_level_error, __FUNCTION__, "got error reading from db file");
return -1;
}
eventlog(eventlog_level_error, __FUNCTION__, "unable to read from cdb file, incomplete file");
return -1;
}
if (posp) *posp += len;
return 0;
}
static const char * fcpy(std::FILE *fd, cdbi_t len, cdbi_t *posp, cdbi_t limit, unsigned char * buf)
{
static char *str;
static unsigned strl;
unsigned int res = 0, no = 0;
if (strl < len + 1) {
char *tmp;
tmp = (char*)xmalloc(len + 1);
if (str) xfree((void*)str);
str = tmp;
strl = len + 1;
}
while (len - res > 0) {
if (len > 2048) no = 2048;
else no = len;
if (fget(fd, buf, no, posp, limit)) return NULL;
std::memmove(str + res, buf, no);
res += no;
}
if (res > strl - 1) {
eventlog(eventlog_level_error, __FUNCTION__, "BUG, this should not happen");
return NULL;
}
str[res] = '\0';
return str;
}
static int cdb_read_attrs(const char *filename, t_read_attr_func cb, void *data)
{
cdbi_t eod, klen, vlen;
cdbi_t pos = 0;
const char *key;
const char *val;
unsigned char buf[2048];
std::FILE *f;
if ((f = std::fopen(filename, "rb")) == NULL) {
eventlog(eventlog_level_error, __FUNCTION__, "got error opening file '{}'", filename);
return -1;
}
if (fget(f, buf, 2048, &pos, 2048)) goto err_fd;
eod = cdb_unpack(buf);
while (pos < eod) {
if (fget(f, buf, 8, &pos, eod)) goto err_fd;
klen = cdb_unpack(buf);
vlen = cdb_unpack(buf + 4);
if ((key = fcpy(f, klen, &pos, eod, buf)) == NULL) {
eventlog(eventlog_level_error, __FUNCTION__, "error reading attribute key");
goto err_fd;
}
key = xstrdup(key);
if ((val = fcpy(f, vlen, &pos, eod, buf)) == NULL) {
eventlog(eventlog_level_error, __FUNCTION__, "error reading attribute val");
goto err_key;
}
// eventlog(eventlog_level_trace, __FUNCTION__, "read atribute : '%s' -> '%s'", key, val);
if (cb(key, val, data))
eventlog(eventlog_level_error, __FUNCTION__, "got error from callback on account file '{}'", filename);
xfree((void *)key);
}
std::fclose(f);
return 0;
err_key:
xfree((void *)key);
err_fd:
std::fclose(f);
return -1;
}
#else /* CDB_ON_DEMAND */
static int cdb_read_attrs(const char *filename, t_read_attr_func cb, void *data)
{
return 0;
}
#endif
static t_attr * cdb_read_attr(const char *filename, const char *key)
{
#ifdef CDB_ON_DEMAND
std::FILE *cdbfile;
t_attr *attr;
char *val;
unsigned vlen = 1;
// eventlog(eventlog_level_trace, __FUNCTION__, "reading key '{}'", key);
if ((cdbfile = std::fopen(filename, "rb")) == NULL) {
// eventlog(eventlog_level_debug, __FUNCTION__, "unable to open file \"{}\" for reading ",filename);
return NULL;
}
if (cdb_seek(cdbfile, key, std::strlen(key), &vlen) <= 0) {
// eventlog(eventlog_level_debug, __FUNCTION__, "could not find key '{}'", key);
std:; std::fclose(cdbfile);
return NULL;
}
/* FIXME: use attr_* API */
attr = xmalloc(sizeof(t_attr));
attr->key = xstrdup(key);
val = xmalloc(vlen + 1);
cdb_bread(cdbfile, val, vlen);
std::fclose(cdbfile);
val[vlen] = '\0';
attr->val = val;
attr->dirty = 0;
// eventlog(eventlog_level_trace, __FUNCTION__, "read key '{}' value '{}'", attr->key, attr->val);
return attr;
#else
return NULL;
#endif
}
}
}

View file

@ -1,20 +0,0 @@
#ifndef JUST_NEED_TYPES
#ifndef INClUDED_FILE_CDB_PROTOS
#define INClUDED_FILE_CDB_PROTOS
#include "storage_file.h"
namespace pvpgn
{
namespace bnetd
{
extern t_file_engine file_cdb;
}
}
#endif /* INClUDED_FILE_CDB_PROTOS */
#endif /* JUST_NEED_TYPES */

View file

@ -44,7 +44,6 @@
#include "team.h"
#include "account.h"
#include "file_plain.h"
#include "file_cdb.h"
#include "prefs.h"
#include "clan.h"
#undef CLAN_INTERNAL_ACCESS
@ -168,11 +167,9 @@ namespace pvpgn
if (!strcasecmp(driver, "plain"))
file = &file_plain;
else if (!strcasecmp(driver, "cdb"))
file = &file_cdb;
else
{
eventlog(eventlog_level_error, __FUNCTION__, "unknown mode '{}' must be either plain or cdb", driver);
eventlog(eventlog_level_error, __FUNCTION__, "unknown mode '{}', mode must be plain", driver);
xfree((void *)copy);
return -1;
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (C) 2005 Dizzy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __CDBHASH_H_INCLUDED__
#define __CDBHASH_H_INCLUDED__
namespace pvpgn
{
typedef unsigned int t_cdbhash;
static inline t_cdbhash cdb_hash(const void* data, std::size_t len)
{
t_cdbhash h;
const char* p = (const char*)data;
for (h = 5381; len > 0; --len, ++p) {
h += h << 5;
h ^= *p;
}
return h;
}
}
#endif /* __CDBHASH_H_INCLUDED__ */

View file

@ -1,8 +0,0 @@
add_library(tinycdb
cdb_find.cpp cdb_findnext.cpp cdb.h cdb_hash.cpp cdb_init.cpp cdb_int.h
cdb_make_add.cpp cdb_make.cpp cdb_make_find.cpp cdb_make_put.cpp
cdb_seek.cpp cdb_seq.cpp cdb_unpack.cpp)
add_executable(bncdb cdb.cpp)
target_link_libraries(bncdb tinycdb common compat )
install(TARGETS bncdb DESTINATION ${BINDIR})

View file

@ -1,144 +0,0 @@
2003-11-04 Michael Tokarev <mjt@corpit.ru>
* added cdb_get() routine: tinycdb officially uses mmap.
* added cdb_{get,read}{data,key}() macros to read and get
current data and key.
* fixed bug in cdb_seek() - incorrect wrap, sometimes
cdb_seek()+cdb_bread() may return EIO instead of finding
correct record.
* added some tweaks to Makefile to build position-independent
libcdb_pic.a and shared libcdb.so libraries. Note that
using libcdb as shared library is probably not a good idea,
due to tiny size of the library.
* added initial nss_cdb module. Still not well-tested.
Probably will not build on non-GNU system.
* adjusted tests.{ok,sh} for latest cdb utility modifications
(-a mode in query by default)
* Victor Porton (porton at ex-code.com) provided a patch
to allow tinycdb to be built on win32 platform (cdb_init.c).
Completely untested.
2003-08-13 Michael Tokarev <mjt@corpit.ru>
* s/cdbi_t/unsigned/g. No need to keep this type.
* changed usage of cdb_findnext(): one need to pass
pointer to cdb structure to cdb_findnext() now,
and should use cdb_datapos(struct cdb_find *)
instead of cdb_datapos(struct cdb *)
* added cdb_seqinit() and cdb_seqnext() routines for sequential
record enumeration
* addded cdb_dend to the cdb structure: end of data
position. Use that in cdb_seq*().
* more strict checking: ensure data is within data section,
and hash tables are within hash section of a file.
* cdb_make.c (cdb_make_start): zerofill cdb_make structure
to shut valgrind up (writing uninitialized data to file)
* cdb.c (cmode): always open file in RDWR mode to allow
duplicate key detection
2002-12-08 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.73
* de-Debianization. Oh well... ;)
* no code changes, just like in 0.72
2002-10-13 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.72
* cleaned up debian packaging and made it actually work
* no code changes
2002-07-22 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.71
* rearranged object files to not depend on ranlib on
systems that requires it (i.e. OpenBSD)
* use ranlib but mark it's possible error as non-fatal
2001-12-10 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.7a
* converted to CVS, added two missing #include <stdlib.h> for
malloc declaration and spec target to the Makefile
2001-10-14 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.7
* added cdb_seek() and cdb_bread() routines as found
in freecdb/cdb-0.64
2001-07-26 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.6
* added another option, CDB_PUT_WARN, to cdb_make_put's flags
(to allow adding unconditionally but still warn about dups),
now cdb_make_put seems to be logically complete.
* added and documented -r and -u options for cdb(1) command,
and made them consistent with -w and -e also.
* reorganized cdb(1) manpage and added changes made to cdb
command.
* added version references to manpages (and make them autogenerated
to simplify maintenance).
* added cdb(5) manpage describing CDB file format.
2001-07-25 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.5
* added missing #include <sys/types.h> in cdb_init.c, thanks to
ppetru@ppetru.net (Petru Paler)
* removed usage of pread() in cdb_make_find() and friends,
suggested by Liviu Daia <Liviu.Daia@imar.ro>
* autogenerate tinycdb.spec file from template and debian/changelog
* autogenerate cdb.h from cdb.h.in (substituting version)
2001-06-29 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.4
* added cdb_make_put() routine to conditionnaly add a record
* split cdb library to more files (finer granularity)
* added cdb_findinit() and cdb_findnext() routines
* renamed cdbtool to cdb
* simplified cdb utility (dropped various format spec, changed
options parsing) and a manpage
* added small note and copyright to every file in package
* added some testsuite (make test)
2001-05-27 Michael Tokarev <mjt+cdb@corpit.ru>
* version 0.3
* Initial Release.

View file

@ -1,479 +0,0 @@
/*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include "compat/pgetopt.h"
#include "common/xalloc.h"
#include "cdb.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "common/setup_after.h"
using namespace pvpgn;
#ifndef EPROTO
# define EPROTO EINVAL
#endif
static char *progname;
#define F_DUPMASK 0x000f
#define F_WARNDUP 0x0100
#define F_ERRDUP 0x0200
#define F_MAP 0x1000 /* map format (or else CDB native format) */
static char *buf;
static unsigned blen;
static void
#ifdef __GNUC__
__attribute__((noreturn,format(printf,2,3)))
#endif
error(int errnum, const char *fmt, ...)
{
if (fmt) {
std::va_list ap;
std::fprintf(stderr, "%s: ", progname);
va_start(ap, fmt);
std::vfprintf(stderr, fmt, ap);
va_end(ap);
}
if (errnum)
std::fprintf(stderr, ": %s\n", std::strerror(errnum));
else {
if (fmt) std::putc('\n', stderr);
std::fprintf(stderr, "%s: try `%s -h' for help\n", progname, progname);
}
std::fflush(stderr);
std::exit(errnum ? 111 : 2);
}
static void allocbuf(unsigned len) {
if (blen < len) {
if (buf) buf = (char*)xrealloc(buf, len);
else buf = (char*)xmalloc(len);
if (!buf) error(ENOMEM, "unable to allocate %u bytes", len);
blen = len;
}
}
static int qmode(char *dbname, char *key, int num, int flags)
{
struct cdb c;
struct cdb_find cf;
std::FILE *fd;
int r;
int n, found;
fd = std::fopen(dbname, "rb");
if (fd == NULL || cdb_init(&c, fd) != 0)
error(errno, "unable to open database `%s'", dbname);
r = cdb_findinit(&cf, &c, key, std::strlen(key));
if (!r)
return 100;
else if (r < 0)
error(errno, "%s", key);
n = 0; found = 0;
while((r = cdb_findnext(&cf)) > 0) {
++n;
if (num && num != n) continue;
++found;
allocbuf(cdb_datalen(&c));
if (cdb_read(&c, buf, cdb_datalen(&c), cdb_datapos(&c)) != 0)
error(errno, "unable to read value");
std::fwrite(buf, 1, cdb_datalen(&c), stdout);
if (flags & F_MAP) std::putchar('\n');
if (num)
break;
}
if (r < 0)
error(0, "%s", key);
return found ? 0 : 100;
}
static void
fget(std::FILE *f, unsigned char *b, unsigned len, unsigned *posp, unsigned limit)
{
if (posp && limit - *posp < len)
error(EPROTO, "invalid database format");
if (std::fread(b, 1, len, f) != len) {
if (std::ferror(f)) error(errno, "unable to read");
std::fprintf(stderr, "%s: unable to read: short file\n", progname);
std::exit(2);
}
if (posp) *posp += len;
}
static int
fcpy(std::FILE *fi, std::FILE *fo, unsigned len, unsigned *posp, unsigned limit)
{
while(len > blen) {
fget(fi, (unsigned char*)buf, blen, posp, limit);
if (fo && std::fwrite(buf, 1, blen, fo) != blen) return -1;
len -= blen;
}
if (len) {
fget(fi, (unsigned char*)buf, len, posp, limit);
if (fo && std::fwrite(buf, 1, len, fo) != len) return -1;
}
return 0;
}
static int
dmode(const char *dbname, char mode, int flags)
{
unsigned eod, klen, vlen;
unsigned pos = 0;
std::FILE *f;
if (std::strcmp(dbname, "-") == 0)
f = stdin;
else if ((f = std::fopen(dbname, "rb")) == NULL)
error(errno, "open %s", dbname);
allocbuf(2048);
fget(f, (unsigned char*)buf, 2048, &pos, 2048);
eod = cdb_unpack((unsigned char*)buf);
while(pos < eod) {
fget(f, (unsigned char*)buf, 8, &pos, eod);
klen = cdb_unpack((unsigned char*)buf);
vlen = cdb_unpack((unsigned char*)(buf + 4));
if (!(flags & F_MAP))
if (std::printf(mode == 'd' ? "+%u,%u:" : "+%u:", klen, vlen) < 0) return -1;
if (fcpy(f, stdout, klen, &pos, eod) != 0) return -1;
if (mode == 'd')
if (std::fputs(flags & F_MAP ? " " : "->", stdout) < 0)
return -1;
if (fcpy(f, mode == 'd' ? stdout : NULL, vlen, &pos, eod) != 0)
return -1;
if (std::putc('\n', stdout) < 0)
return -1;
}
if (pos != eod)
error(EPROTO, "invalid cdb file format");
if (!(flags & F_MAP))
if (std::putc('\n', stdout) < 0)
return -1;
return 0;
}
static int smode(const char *dbname) {
std::FILE *f;
unsigned pos, eod;
unsigned cnt = 0;
unsigned kmin = 0, kmax = 0, ktot = 0;
unsigned vmin = 0, vmax = 0, vtot = 0;
unsigned hmin = 0, hmax = 0, htot = 0, hcnt = 0;
#define NDIST 11
unsigned dist[NDIST];
unsigned char toc[2048];
unsigned k;
if (std::strcmp(dbname, "-") == 0)
f = stdin;
else if ((f = std::fopen(dbname, "rb")) == NULL)
error(errno, "open %s", dbname);
pos = 0;
fget(f, toc, 2048, &pos, 2048);
allocbuf(2048);
eod = cdb_unpack(toc);
while(pos < eod) {
unsigned klen, vlen;
fget(f, (unsigned char*)buf, 8, &pos, eod);
klen = cdb_unpack((unsigned char*)buf);
vlen = cdb_unpack((unsigned char*)(buf + 4));
fcpy(f, NULL, klen, &pos, eod);
fcpy(f, NULL, vlen, &pos, eod);
++cnt;
ktot += klen;
if (!kmin || kmin > klen) kmin = klen;
if (kmax < klen) kmax = klen;
vtot += vlen;
if (!vmin || vmin > vlen) vmin = vlen;
if (vmax < vlen) vmax = vlen;
vlen += klen;
}
if (pos != eod) error(EPROTO, "invalid cdb file format");
for (k = 0; k < NDIST; ++k)
dist[k] = 0;
for (k = 0; k < 256; ++k) {
unsigned i = cdb_unpack(toc + (k << 3));
unsigned hlen = cdb_unpack(toc + (k << 3) + 4);
if (i != pos) error(EPROTO, "invalid cdb hash table");
if (!hlen) continue;
for (i = 0; i < hlen; ++i) {
unsigned h;
fget(f, (unsigned char*)buf, 8, &pos, 0xffffffff);
if (!cdb_unpack((unsigned char*)(buf + 4))) continue;
h = (cdb_unpack((unsigned char*)buf) >> 8) % hlen;
if (h == i) h = 0;
else {
if (h < i) h = i - h;
else h = hlen - h + i;
if (h >= NDIST) h = NDIST - 1;
}
++dist[h];
}
if (!hmin || hmin > hlen) hmin = hlen;
if (hmax < hlen) hmax = hlen;
htot += hlen;
++hcnt;
}
std::printf("number of records: %u\n", cnt);
std::printf("key min/avg/max length: %u/%u/%u\n",
kmin, cnt ? (ktot + cnt / 2) / cnt : 0, kmax);
std::printf("val min/avg/max length: %u/%u/%u\n",
vmin, cnt ? (vtot + cnt / 2) / cnt : 0, vmax);
std::printf("hash tables/entries/collisions: %u/%u/%u\n",
hcnt, htot, cnt - dist[0]);
std::printf("hash table min/avg/max length: %u/%u/%u\n",
hmin, hcnt ? (htot + hcnt / 2) / hcnt : 0, hmax);
std::printf("hash table distances:\n");
for(k = 0; k < NDIST; ++k)
std::printf(" %c%u: %6u %2u%%\n",
k == NDIST - 1 ? '>' : 'd', k == NDIST - 1 ? k - 1 : k,
dist[k], cnt ? dist[k] * 100 / cnt : 0);
return 0;
}
static void badinput(const char *fn) {
std::fprintf(stderr, "%s: %s: bad format\n", progname, fn);
std::exit(2);
}
static int getnum(std::FILE *f, unsigned *np, const char *fn) {
unsigned n;
int c = std::getc(f);
if (c < '0' || c > '9') badinput(fn);
n = c - '0';
while((c = std::getc(f)) >= '0' && c <= '9') {
c -= '0';
if (0xffffffff / 10 - c < n) badinput(fn);
n = n * 10 + c;
}
*np = n;
return c;
}
static void
addrec(struct cdb_make *cdbmp,
char *key, unsigned klen,
char *val, unsigned vlen,
int flags)
{
int r = cdb_make_put(cdbmp, key, klen, val, vlen, flags & F_DUPMASK);
if (r < 0)
error(errno, "cdb_make_put");
else if (r && (flags & F_WARNDUP)) {
std::fprintf(stderr, "%s: key `", progname);
std::fwrite(key, 1, klen, stderr);
std::fputs("' duplicated\n", stderr);
if (flags & F_ERRDUP)
std::exit(1);
}
}
static void
dofile_cdb(struct cdb_make *cdbmp, std::FILE *f, const char *fn, int flags)
{
unsigned klen, vlen;
int c;
while((c = std::getc(f)) == '+') {
if ((c = getnum(f, &klen, fn)) != ',' ||
(c = getnum(f, &vlen, fn)) != ':' ||
0xffffffff - klen < vlen)
badinput(fn);
allocbuf(klen + vlen);
fget(f, (unsigned char*)buf, klen, NULL, 0);
if (std::getc(f) != '-' || std::getc(f) != '>') badinput(fn);
fget(f, (unsigned char*)(buf + klen), vlen, NULL, 0);
switch (std::getc(f))
{
case '\n': break;
case '\r': if (std::getc(f)=='\n') break;
default: badinput(fn);
}
addrec(cdbmp, buf, klen, buf + klen, vlen, flags);
}
switch (c)
{
case '\n': break;
case '\r': if (std::getc(f)=='\n') break;
default: badinput(fn);
}
}
static void
dofile_ln(struct cdb_make *cdbmp, std::FILE *f, const char *fn, int flags)
{
char *k, *v;
while(std::fgets(buf, blen, f) != NULL) {
unsigned l = 0;
for (;;) {
l += std::strlen(buf + l);
v = buf + l;
if (v > buf && v[-1] == '\n') {
v[-1] = '\0';
break;
}
if (l < blen)
allocbuf(l + 512);
if (!std::fgets(buf + l, blen - l, f))
break;
}
k = buf;
while(*k == ' ' || *k == '\t') ++k;
if (!*k || *k == '#')
continue;
v = k;
while(*v && *v != ' ' && *v != '\t') ++v;
if (*v) *v++ = '\0';
while(*v == ' ' || *v == '\t') ++v;
addrec(cdbmp, k, std::strlen(k), v, std::strlen(v), flags);
}
}
static void
dofile(struct cdb_make *cdbmp, std::FILE *f, const char *fn, int flags)
{
if (flags & F_MAP)
dofile_ln(cdbmp, f, fn, flags);
else
dofile_cdb(cdbmp, f, fn, flags);
if (std::ferror(f))
error(errno, "read error");
}
static int
cmode(char *dbname, char *tmpname, int argc, char **argv, int flags)
{
struct cdb_make cdb;
std::FILE *fd;
if (!tmpname) {
tmpname = (char*)xmalloc(std::strlen(dbname) + 5);
if (!tmpname)
error(ENOMEM, "unable to allocate memory");
std::strcat(std::strcpy(tmpname, dbname), ".tmp");
}
fd = std::fopen(tmpname, "w+b");
if (fd == 0)
error(errno, "unable to create %s", tmpname);
cdb_make_start(&cdb, fd);
allocbuf(4096);
if (argc) {
int i;
for (i = 0; i < argc; ++i) {
if (std::strcmp(argv[i], "-") == 0)
dofile(&cdb, stdin, "(stdin)", flags);
else {
std::FILE *f = std::fopen(argv[i], "rb");
if (!f)
error(errno, "%s", argv[i]);
dofile(&cdb, f, argv[i], flags);
std::fclose(f);
}
}
}
else
dofile(&cdb, stdin, "(stdin)", flags);
if (cdb_make_finish(&cdb) != 0)
error(errno, "cdb_make_finish");
std::fclose(fd);
if (std::rename(tmpname, dbname) != 0)
error(errno, "std::rename %s->%s", tmpname, dbname);
return 0;
}
int main(int argc, char **argv)
{
int c;
char mode = 0;
char *tmpname = NULL;
int flags = 0;
int num = 0;
int r;
extern char *optarg;
extern int optind;
if ((progname = std::strrchr(argv[0], '/')) != NULL)
argv[0] = ++progname;
else
progname = argv[0];
if (argc == 1)
error(0, "no arguments given");
while((c = getopt(argc, argv, "qdlcsht:n:mwrue")) != EOF)
switch(c) {
case 'q': case 'd': case 'l': case 'c': case 's':
if (mode && mode != c)
error(0, "different modes of operation requested");
mode = c;
break;
case 't': tmpname = optarg; break;
case 'w': flags |= F_WARNDUP; break;
case 'e': flags |= F_WARNDUP | F_ERRDUP; break;
case 'r': flags = (flags & ~F_DUPMASK) | CDB_PUT_REPLACE; break;
case 'u': flags = (flags & ~F_DUPMASK) | CDB_PUT_INSERT; break;
case 'm': flags |= F_MAP; break;
case 'n':
if ((num = std::atoi(optarg)) <= 0)
error(0, "invalid record number `%s'", optarg);
break;
case 'h':
std::printf("\
%s: Constant DataBase (CDB) tool. Usage is:\n\
query: %s -q [-m] [-n recno|-a] cdbfile key\n\
dump: %s -d [-m] [cdbfile|-]\n\
list: %s -l [-m] [cdbfile|-]\n\
create: %s -c [-m] [-wrue] [-t tempfile] cdbfile [infile...]\n\
stats: %s -s [cdbfile|-]\n\
help: %s -h\n\
", progname, progname, progname, progname, progname, progname, progname);
return 0;
default:
error(0, NULL);
}
argv += optind;
argc -= optind;
switch(mode) {
case 'q':
if (argc < 2) error(0, "no database or key to query specified");
if (argc > 2) error(0, "extra arguments in command line");
r = qmode(argv[0], argv[1], num, flags);
break;
case 'c':
if (!argc) error(0, "no database name specified");
if ((flags & F_WARNDUP) && !(flags & F_DUPMASK))
flags |= CDB_PUT_WARN;
r = cmode(argv[0], tmpname, argc - 1, argv + 1, flags);
break;
case 'd':
case 'l':
if (argc > 1) error(0, "extra arguments for dump/list");
r = dmode(argc ? argv[0] : "-", mode, flags);
break;
case 's':
if (argc > 1) error(0, "extra argument(s) for stats");
r = smode(argc ? argv[0] : "-");
break;
default:
error(0, "no -q, -c, -d, -l or -s option specified");
}
if (r < 0 || std::fflush(stdout) < 0)
error(errno, "unable to write: %d", c);
return r;
}

View file

@ -1,108 +0,0 @@
/* public cdb include file
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include <cstdio>
#ifndef TINYCDB_VERSION
#define TINYCDB_VERSION 0.74
namespace pvpgn
{
typedef unsigned int cdbi_t; /* compatibility */
/* common routines */
unsigned cdb_hash(const void *buf, unsigned len);
unsigned cdb_unpack(const unsigned char buf[4]);
void cdb_pack(unsigned num, unsigned char buf[4]);
struct cdb {
std::FILE *cdb_fd; /* file descriptor */
/* private members */
unsigned cdb_fsize; /* datafile size */
unsigned cdb_dend; /* end of data ptr */
const unsigned char *cdb_mem; /* mmap'ed file memory */
unsigned cdb_vpos, cdb_vlen; /* found data */
unsigned cdb_kpos, cdb_klen; /* found key */
};
#define CDB_STATIC_INIT {0,0,0,0,0,0,0,0}
#define cdb_datapos(c) ((c)->cdb_vpos)
#define cdb_datalen(c) ((c)->cdb_vlen)
#define cdb_keypos(c) ((c)->cdb_kpos)
#define cdb_keylen(c) ((c)->cdb_klen)
#define cdb_fileno(c) ((c)->cdb_fd)
int cdb_init(struct cdb *cdbp, std::FILE *fd);
void cdb_free(struct cdb *cdbp);
int cdb_read(const struct cdb *cdbp,
void *buf, unsigned len, unsigned pos);
#define cdb_readdata(cdbp, buf) \
cdb_read((cdbp), (buf), cdb_datalen(cdbp), cdb_datapos(cdbp))
#define cdb_readkey(cdbp, buf) \
cdb_read((cdbp), (buf), cdb_keylen(cdbp), cdb_keypos(cdbp))
const void *cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos);
#define cdb_getdata(cdbp) \
cdb_get((cdbp), cdb_datalen(cdbp), cdb_datapos(cdbp))
#define cdb_getkey(cdbp) \
cdb_get((cdbp), cdb_keylen(cdbp), cdb_keypos(cdbp))
int cdb_find(struct cdb *cdbp, const void *key, unsigned klen);
struct cdb_find {
struct cdb *cdb_cdbp;
unsigned cdb_hval;
const unsigned char *cdb_htp, *cdb_htab, *cdb_htend;
unsigned cdb_httodo;
const void *cdb_key;
unsigned cdb_klen;
};
int cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp,
const void *key, unsigned klen);
int cdb_findnext(struct cdb_find *cdbfp);
#define cdb_seqinit(cptr, cdbp) ((*(cptr))=2048)
int cdb_seqnext(unsigned *cptr, struct cdb *cdbp);
/* old simple interface */
/* open file using standard routine, then: */
int cdb_seek(std::FILE *fd, const void *key, unsigned klen, unsigned *dlenp);
int cdb_bread(std::FILE *fd, void *buf, int len);
/* cdb_make */
struct cdb_make {
std::FILE *cdb_fd; /* file descriptor */
/* private */
unsigned cdb_dpos; /* data position so far */
unsigned cdb_rcnt; /* record count so far */
char cdb_buf[4096]; /* write buffer */
char *cdb_bpos; /* current buf position */
struct cdb_rl *cdb_rec[256]; /* list of arrays of record infos */
};
int cdb_make_start(struct cdb_make *cdbmp, std::FILE *fd);
int cdb_make_add(struct cdb_make *cdbmp,
const void *key, unsigned klen,
const void *val, unsigned vlen);
int cdb_make_exists(struct cdb_make *cdbmp,
const void *key, unsigned klen);
int cdb_make_put(struct cdb_make *cdbmp,
const void *key, unsigned klen,
const void *val, unsigned vlen,
int flag);
#define CDB_PUT_ADD 0 /* add unconditionnaly, like cdb_make_add() */
#define CDB_PUT_REPLACE 1 /* replace: do not place to index OLD record */
#define CDB_PUT_INSERT 2 /* add only if not already exists */
#define CDB_PUT_WARN 3 /* add unconditionally but ret. 1 if exists */
int cdb_make_finish(struct cdb_make *cdbmp);
}
#endif /* include guard */

View file

@ -1,85 +0,0 @@
/* cdb_find routine
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cstring>
#include <cerrno>
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
int
cdb_find(struct cdb *cdbp, const void *key, unsigned klen)
{
const unsigned char *htp; /* hash table pointer */
const unsigned char *htab; /* hash table */
const unsigned char *htend; /* end of hash table */
unsigned httodo; /* ht bytes left to look */
unsigned pos, n;
unsigned hval;
if (klen >= cdbp->cdb_dend) /* if key size is too large */
return 0;
hval = cdb_hash(key, klen);
/* find (pos,n) hash table to use */
/* first 2048 bytes (toc) are always available */
/* (hval % 256) * 8 */
htp = cdbp->cdb_mem + ((hval << 3) & 2047); /* index in toc (256x8) */
n = cdb_unpack(htp + 4); /* table size */
if (!n) /* empty table */
return 0; /* not found */
httodo = n << 3; /* bytes of htab to lookup */
pos = cdb_unpack(htp); /* htab position */
if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */
|| pos < cdbp->cdb_dend /* is htab inside data section ? */
|| pos > cdbp->cdb_fsize /* htab start within file ? */
|| httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */
return errno = EPROTO, -1;
htab = cdbp->cdb_mem + pos; /* htab pointer */
htend = htab + httodo; /* after end of htab */
/* htab starting position: rest of hval modulo htsize, 8bytes per elt */
htp = htab + (((hval >> 8) % n) << 3);
for(;;) {
pos = cdb_unpack(htp + 4); /* record position */
if (!pos)
return 0;
if (cdb_unpack(htp) == hval) {
if (pos > cdbp->cdb_dend - 8) /* key+val lengths */
return errno = EPROTO, -1;
if (cdb_unpack(cdbp->cdb_mem + pos) == klen) {
if (cdbp->cdb_dend - klen < pos + 8)
return errno = EPROTO, -1;
if (std::memcmp(key, cdbp->cdb_mem + pos + 8, klen) == 0) {
n = cdb_unpack(cdbp->cdb_mem + pos + 4);
pos += 8;
if (cdbp->cdb_dend < n || cdbp->cdb_dend - n < pos + klen)
return errno = EPROTO, -1;
cdbp->cdb_kpos = pos;
cdbp->cdb_klen = klen;
cdbp->cdb_vpos = pos + klen;
cdbp->cdb_vlen = n;
return 1;
}
}
}
httodo -= 8;
if (!httodo)
return 0;
if ((htp += 8) >= htend)
htp = htab;
}
}
}

View file

@ -1,90 +0,0 @@
/* sequential cdb_find routines
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
/* see cdb_find.c for comments */
#include "common/setup_before.h"
#include <cstring>
#include <cerrno>
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
int
cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp,
const void *key, unsigned klen)
{
unsigned n, pos;
cdbfp->cdb_cdbp = cdbp;
cdbfp->cdb_key = key;
cdbfp->cdb_klen = klen;
cdbfp->cdb_hval = cdb_hash(key, klen);
cdbfp->cdb_htp = cdbp->cdb_mem + ((cdbfp->cdb_hval << 3) & 2047);
n = cdb_unpack(cdbfp->cdb_htp + 4);
cdbfp->cdb_httodo = n << 3;
if (!n)
return 0;
pos = cdb_unpack(cdbfp->cdb_htp);
if (n > (cdbp->cdb_fsize >> 3)
|| pos < cdbp->cdb_dend
|| pos > cdbp->cdb_fsize
|| cdbfp->cdb_httodo > cdbp->cdb_fsize - pos)
return errno = EPROTO, -1;
cdbfp->cdb_htab = cdbp->cdb_mem + pos;
cdbfp->cdb_htend = cdbfp->cdb_htab + cdbfp->cdb_httodo;
cdbfp->cdb_htp = cdbfp->cdb_htab + (((cdbfp->cdb_hval >> 8) % n) << 3);
return 1;
}
int
cdb_findnext(struct cdb_find *cdbfp) {
struct cdb *cdbp = cdbfp->cdb_cdbp;
unsigned pos, n;
unsigned klen = cdbfp->cdb_klen;
while(cdbfp->cdb_httodo) {
pos = cdb_unpack(cdbfp->cdb_htp + 4);
if (!pos)
return 0;
n = cdb_unpack(cdbfp->cdb_htp) == cdbfp->cdb_hval;
if ((cdbfp->cdb_htp += 8) >= cdbfp->cdb_htend)
cdbfp->cdb_htp = cdbfp->cdb_htab;
cdbfp->cdb_httodo -= 8;
if (n) {
if (pos > cdbp->cdb_fsize - 8)
return errno = EPROTO, -1;
if (cdb_unpack(cdbp->cdb_mem + pos) == klen) {
if (cdbp->cdb_fsize - klen < pos + 8)
return errno = EPROTO, -1;
if (std::memcmp(cdbfp->cdb_key,
cdbp->cdb_mem + pos + 8, klen) == 0) {
n = cdb_unpack(cdbp->cdb_mem + pos + 4);
pos += 8;
if (cdbp->cdb_fsize < n ||
cdbp->cdb_fsize - n < pos + klen)
return errno = EPROTO, -1;
cdbp->cdb_kpos = pos;
cdbp->cdb_klen = klen;
cdbp->cdb_vpos = pos + klen;
cdbp->cdb_vlen = n;
return 1;
}
}
}
}
return 0;
}
}

View file

@ -1,25 +0,0 @@
/* cdb hashing routine
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include "cdb.h"
#include "common/setup_after.h"
namespace pvpgn
{
unsigned
cdb_hash(const void *buf, unsigned len)
{
register const unsigned char *p = (const unsigned char *)buf;
register const unsigned char *end = p + len;
register unsigned hash = 5381; /* start value */
while (p < end)
hash = (hash + (hash << 5)) ^ *p++;
return hash;
}
}

View file

@ -1,95 +0,0 @@
/* cdb_init, cdb_free and cdb_read routines
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cstdio>
#include <cerrno>
#include <cstring>
#include "compat/mmap.h"
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
int
cdb_init(struct cdb *cdbp, std::FILE *fd)
{
unsigned char *mem;
unsigned fsize, dend;
/* get file size */
if (std::fseek(fd, 0, SEEK_END))
return -1;
fsize = (unsigned)(std::ftell(fd));
std::rewind(fd);
/* trivial sanity check: at least toc should be here */
if (fsize < 2048)
return errno = EPROTO, -1;
/* memory-map file */
if ((mem = (unsigned char*)pmmap(NULL, fsize, PROT_READ, MAP_SHARED, fileno(fd), 0)) ==
(unsigned char *)-1)
return -1;
cdbp->cdb_fd = fd;
cdbp->cdb_fsize = fsize;
cdbp->cdb_mem = mem;
#if 0
/* XXX don't know well about madvise syscall -- is it legal
to set different options for parts of one mmap() region?
There is also posix_madvise() exist, with POSIX_MADV_RANDOM etc...
*/
#ifdef MADV_RANDOM
/* set madvise() parameters. Ignore errors for now if system
doesn't support it */
madvise(mem, 2048, MADV_WILLNEED);
madvise(mem + 2048, cdbp->cdb_fsize - 2048, MADV_RANDOM);
#endif
#endif
cdbp->cdb_vpos = cdbp->cdb_vlen = 0;
cdbp->cdb_kpos = cdbp->cdb_klen = 0;
dend = cdb_unpack(mem);
if (dend < 2048) dend = 2048;
else if (dend >= fsize) dend = fsize;
cdbp->cdb_dend = dend;
return 0;
}
void
cdb_free(struct cdb *cdbp)
{
if (cdbp->cdb_mem) {
pmunmap((void*)cdbp->cdb_mem, cdbp->cdb_fsize);
cdbp->cdb_mem = NULL;
}
cdbp->cdb_fsize = 0;
}
const void *
cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos)
{
if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) {
errno = EPROTO;
return NULL;
}
return cdbp->cdb_mem + pos;
}
int
cdb_read(const struct cdb *cdbp, void *buf, unsigned len, unsigned pos)
{
const void *data = cdb_get(cdbp, len, pos);
if (!data) return -1;
std::memcpy(buf, data, len);
return 0;
}
}

View file

@ -1,33 +0,0 @@
/* internal cdb library declarations
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "cdb.h"
#ifndef EPROTO
# define EPROTO EINVAL
#endif
namespace pvpgn
{
struct cdb_rec {
cdbi_t hval;
cdbi_t rpos;
};
struct cdb_rl {
struct cdb_rl *next;
cdbi_t cnt;
struct cdb_rec rec[254];
};
int _cdb_make_find(struct cdb_make *cdbmp,
const void *key, cdbi_t klen, cdbi_t hval,
struct cdb_rl **rlp);
int _cdb_make_write(struct cdb_make *cdbmp,
const char *ptr, cdbi_t len);
}

View file

@ -1,180 +0,0 @@
/* basic cdb creation routines
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cstdio>
#include <cstring>
#include <cerrno>
#include "common/xalloc.h"
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
void
cdb_pack(unsigned num, unsigned char buf[4])
{
buf[0] = num & 255; num >>= 8;
buf[1] = num & 255; num >>= 8;
buf[2] = num & 255;
buf[3] = num >> 8;
}
int
cdb_make_start(struct cdb_make *cdbmp, std::FILE *fd)
{
std::memset(cdbmp, 0, sizeof(*cdbmp));
cdbmp->cdb_fd = fd;
cdbmp->cdb_dpos = 2048;
cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048;
return 0;
}
static int
ewrite(std::FILE *fd, const char *buf, int len)
{
while(len) {
int l = std::fwrite(buf, 1, len, fd);
if (l < 0 && errno != EINTR)
return -1;
len -= l;
buf += l;
}
return 0;
}
int
_cdb_make_write(struct cdb_make *cdbmp, const char *ptr, unsigned len)
{
unsigned l = sizeof(cdbmp->cdb_buf) - (cdbmp->cdb_bpos - cdbmp->cdb_buf);
cdbmp->cdb_dpos += len;
if (len > l) {
std::memcpy(cdbmp->cdb_bpos, ptr, l);
if (ewrite(cdbmp->cdb_fd, cdbmp->cdb_buf, sizeof(cdbmp->cdb_buf)) < 0)
return -1;
ptr += l; len -= l;
l = len / sizeof(cdbmp->cdb_buf);
if (l) {
l *= sizeof(cdbmp->cdb_buf);
if (ewrite(cdbmp->cdb_fd, ptr, l) < 0)
return -1;
ptr += l; len -= l;
}
cdbmp->cdb_bpos = cdbmp->cdb_buf;
}
if (len) {
std::memcpy(cdbmp->cdb_bpos, ptr, len);
cdbmp->cdb_bpos += len;
}
return 0;
}
static int
cdb_make_finish_internal(struct cdb_make *cdbmp)
{
unsigned hcnt[256]; /* hash table counts */
unsigned hpos[256]; /* hash table positions */
struct cdb_rec *htab;
unsigned char *p;
struct cdb_rl *rl;
unsigned hsize;
unsigned t, i;
if (((0xffffffff - cdbmp->cdb_dpos) >> 3) < cdbmp->cdb_rcnt)
return errno = ENOMEM, -1;
/* count htab sizes and reorder reclists */
hsize = 0;
for (t = 0; t < 256; ++t) {
struct cdb_rl *rlt = NULL;
i = 0;
rl = cdbmp->cdb_rec[t];
while(rl) {
struct cdb_rl *rln = rl->next;
rl->next = rlt;
rlt = rl;
i += rl->cnt;
rl = rln;
}
cdbmp->cdb_rec[t] = rlt;
if (hsize < (hcnt[t] = i << 1))
hsize = hcnt[t];
}
/* allocate memory to hold max htable */
htab = (struct cdb_rec*)xmalloc((hsize + 2) * sizeof(struct cdb_rec));
if (!htab)
return errno = ENOENT, -1;
p = (unsigned char *)htab;
htab += 2;
/* build hash tables */
for (t = 0; t < 256; ++t) {
unsigned len, hi;
hpos[t] = cdbmp->cdb_dpos;
if ((len = hcnt[t]) == 0)
continue;
for (i = 0; i < len; ++i)
htab[i].hval = htab[i].rpos = 0;
for (rl = cdbmp->cdb_rec[t]; rl; rl = rl->next)
for (i = 0; i < rl->cnt; ++i) {
hi = (rl->rec[i].hval >> 8) % len;
while(htab[hi].rpos)
if (++hi == len)
hi = 0;
htab[hi] = rl->rec[i];
}
for (i = 0; i < len; ++i) {
cdb_pack(htab[i].hval, p + (i << 3));
cdb_pack(htab[i].rpos, p + (i << 3) + 4);
}
if (_cdb_make_write(cdbmp, (char*)p, len << 3) < 0) {
xfree(p);
return -1;
}
}
xfree(p);
if (cdbmp->cdb_bpos != cdbmp->cdb_buf &&
ewrite(cdbmp->cdb_fd, cdbmp->cdb_buf,
cdbmp->cdb_bpos - cdbmp->cdb_buf) != 0)
return -1;
p = (unsigned char*)cdbmp->cdb_buf;
for (t = 0; t < 256; ++t) {
cdb_pack(hpos[t], p + (t << 3));
cdb_pack(hcnt[t], p + (t << 3) + 4);
}
std::rewind(cdbmp->cdb_fd);
if (ewrite(cdbmp->cdb_fd, (char*)p, 2048) != 0)
return -1;
return 0;
}
static void
cdb_make_free(struct cdb_make *cdbmp)
{
unsigned t;
for(t = 0; t < 256; ++t) {
struct cdb_rl *rl = cdbmp->cdb_rec[t];
while(rl) {
struct cdb_rl *tm = rl;
rl = rl->next;
xfree(tm);
}
}
}
int
cdb_make_finish(struct cdb_make *cdbmp)
{
int r = cdb_make_finish_internal(cdbmp);
cdb_make_free(cdbmp);
return r;
}
}

View file

@ -1,51 +0,0 @@
/* basic cdb_make_add routine
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cerrno>
#include "common/xalloc.h"
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
int
cdb_make_add(struct cdb_make *cdbmp,
const void *key, unsigned klen,
const void *val, unsigned vlen)
{
unsigned char rlen[8];
unsigned hval;
struct cdb_rl *rl;
if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) ||
vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8))
return errno = ENOMEM, -1;
hval = cdb_hash(key, klen);
rl = cdbmp->cdb_rec[hval&255];
if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) {
rl = (struct cdb_rl*)xmalloc(sizeof(struct cdb_rl));
if (!rl)
return errno = ENOMEM, -1;
rl->cnt = 0;
rl->next = cdbmp->cdb_rec[hval&255];
cdbmp->cdb_rec[hval&255] = rl;
}
rl->rec[rl->cnt].hval = hval;
rl->rec[rl->cnt].rpos = cdbmp->cdb_dpos;
++rl->cnt;
++cdbmp->cdb_rcnt;
cdb_pack(klen, rlen);
cdb_pack(vlen, rlen + 4);
if (_cdb_make_write(cdbmp, (char*)rlen, 8) < 0 ||
_cdb_make_write(cdbmp, (char*)key, klen) < 0 ||
_cdb_make_write(cdbmp, (char*)val, vlen) < 0)
return -1;
return 0;
}
}

View file

@ -1,91 +0,0 @@
/* routines to search in in-progress cdb file
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cstdio>
#include <cstring>
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
static int
match(std::FILE *fd, unsigned pos, const char *key, unsigned klen)
{
unsigned char buf[64]; /*XXX cdb_buf may be used here instead */
if (std::fseek(fd, pos, SEEK_SET) || std::fread(buf, 1, 8, fd) != 8)
return -1;
if (cdb_unpack(buf) != klen)
return 0;
while(klen > sizeof(buf)) {
if (std::fread(buf, 1, sizeof(buf), fd) != sizeof(buf))
return -1;
if (std::memcmp(buf, key, sizeof(buf)) != 0)
return 0;
key += sizeof(buf);
klen -= sizeof(buf);
}
if (klen) {
if (std::fread(buf, 1, klen, fd) != klen)
return -1;
if (std::memcmp(buf, key, klen) != 0)
return 0;
}
return 1;
}
int
_cdb_make_find(struct cdb_make *cdbmp,
const void *key, unsigned klen, unsigned hval,
struct cdb_rl **rlp)
{
struct cdb_rl *rl = cdbmp->cdb_rec[hval&255];
int r, i;
int seeked = 0;
while(rl) {
for(i = rl->cnt - 1; i >= 0; --i) { /* search backward */
if (rl->rec[i].hval != hval)
continue;
/*XXX this explicit flush may be unnecessary having
* smarter match() that looks to cdb_buf too, but
* most of a time here spent in finding hash values
* (above), not keys */
if (cdbmp->cdb_bpos != cdbmp->cdb_buf) {
if (std::fwrite(cdbmp->cdb_buf, 1,
cdbmp->cdb_bpos - cdbmp->cdb_buf, cdbmp->cdb_fd) < 0)
return -1;
cdbmp->cdb_bpos = cdbmp->cdb_buf;
}
seeked = 1;
r = match(cdbmp->cdb_fd, rl->rec[i].rpos, (char*)key, klen);
if (!r)
continue;
if (r < 0)
return -1;
if (std::fseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET))
return -1;
if (rlp)
*rlp = rl;
return i + 1;
}
rl = rl->next;
}
if (seeked && std::fseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET))
return -1;
return 0;
}
int
cdb_make_exists(struct cdb_make *cdbmp,
const void *key, unsigned klen)
{
return _cdb_make_find(cdbmp, key, klen, cdb_hash(key, klen), NULL);
}
}

View file

@ -1,83 +0,0 @@
/* "advanced" cdb_make_put routine
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cerrno>
#include "common/xalloc.h"
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
int
cdb_make_put(struct cdb_make *cdbmp,
const void *key, unsigned klen,
const void *val, unsigned vlen,
int flags)
{
unsigned char rlen[8];
unsigned hval = cdb_hash(key, klen);
struct cdb_rl *rl;
int c, r;
switch(flags) {
case CDB_PUT_REPLACE:
case CDB_PUT_INSERT:
case CDB_PUT_WARN:
c = _cdb_make_find(cdbmp, key, klen, hval, &rl);
if (c < 0)
return -1;
if (c) {
if (flags == CDB_PUT_INSERT)
return errno = EEXIST, 1;
else if (flags == CDB_PUT_REPLACE) {
--c;
r = 1;
break;
}
else
r = 1;
}
/* fall */
case CDB_PUT_ADD:
rl = cdbmp->cdb_rec[hval&255];
if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) {
rl = (struct cdb_rl*)xmalloc(sizeof(struct cdb_rl));
if (!rl)
return errno = ENOMEM, -1;
rl->cnt = 0;
rl->next = cdbmp->cdb_rec[hval&255];
cdbmp->cdb_rec[hval&255] = rl;
}
c = rl->cnt;
r = 0;
break;
default:
return errno = EINVAL, -1;
}
if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) ||
vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8))
return errno = ENOMEM, -1;
rl->rec[c].hval = hval;
rl->rec[c].rpos = cdbmp->cdb_dpos;
if ((unsigned)c == rl->cnt) {
++rl->cnt;
++cdbmp->cdb_rcnt;
}
cdb_pack(klen, rlen);
cdb_pack(vlen, rlen + 4);
if (_cdb_make_write(cdbmp, (char*)rlen, 8) < 0 ||
_cdb_make_write(cdbmp, (char*)key, klen) < 0 ||
_cdb_make_write(cdbmp, (char*)val, vlen) < 0)
return -1;
return r;
}
}

View file

@ -1,105 +0,0 @@
/* old interface for reading cdb file
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cstdio>
#include <cstring>
#include <cerrno>
#include "cdb_int.h"
#include "common/setup_after.h"
/* read a chunk from file, ignoring interrupts (EINTR) */
namespace pvpgn
{
int
cdb_bread(std::FILE *fd, void *buf, int len)
{
int l;
while(len > 0) {
do l = std::fread(buf, 1, len, fd);
while(l < 0 && errno == EINTR);
if (l <= 0) {
if (!l)
errno = EIO;
return -1;
}
buf = (char*)buf + l;
len -= l;
}
return 0;
}
/* find a given key in cdb file, seek a file pointer to it's value and
place data length to *dlenp. */
int
cdb_seek(std::FILE *fd, const void *key, unsigned klen, unsigned *dlenp)
{
unsigned htstart; /* hash table start position */
unsigned htsize; /* number of elements in a hash table */
unsigned httodo; /* hash table elements left to look */
unsigned hti; /* hash table index */
unsigned pos; /* position in a file */
unsigned hval; /* key's hash value */
unsigned char rbuf[64]; /* read buffer */
int needseek = 1; /* if we should seek to a hash slot */
hval = cdb_hash(key, klen);
pos = (hval & 0xff) << 3; /* position in TOC */
/* read the hash table parameters */
if (std::fseek(fd, pos, SEEK_SET) || cdb_bread(fd, rbuf, 8) < 0)
return -1;
if ((htsize = cdb_unpack(rbuf + 4)) == 0)
return 0;
hti = (hval >> 8) % htsize; /* start position in hash table */
httodo = htsize;
htstart = cdb_unpack(rbuf);
for(;;) {
if (needseek && std::fseek(fd, htstart + (hti << 3), SEEK_SET))
return -1;
if (cdb_bread(fd, rbuf, 8) < 0)
return -1;
if ((pos = cdb_unpack(rbuf + 4)) == 0) /* not found */
return 0;
if (cdb_unpack(rbuf) != hval) /* hash value not matched */
needseek = 0;
else { /* hash value matched */
if (std::fseek(fd, pos, SEEK_SET) || cdb_bread(fd, rbuf, 8) < 0)
return -1;
if (cdb_unpack(rbuf) == klen) { /* key length matches */
/* read the key from file and compare with wanted */
unsigned l = klen, c;
const char *k = (const char*)key;
if (*dlenp)
*dlenp = cdb_unpack(rbuf + 4); /* save value length */
for(;;) {
if (!l) /* the whole key read and matches, return */
return 1;
c = l > sizeof(rbuf) ? sizeof(rbuf) : l;
if (cdb_bread(fd, rbuf, c) < 0)
return -1;
if (std::memcmp(rbuf, k, c) != 0) /* no, it differs, stop here */
break;
k += c; l -= c;
}
}
needseek = 1; /* we're looked to other place, should seek back */
}
if (!--httodo)
return 0;
if (++hti == htsize) {
hti = 0;
needseek = 1;
}
}
}
}

View file

@ -1,37 +0,0 @@
/* sequential record retrieval routines
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include <cerrno>
#include "cdb_int.h"
#include "common/setup_after.h"
namespace pvpgn
{
int
cdb_seqnext(unsigned *cptr, struct cdb *cdbp) {
unsigned klen, vlen;
unsigned pos = *cptr;
unsigned dend = cdbp->cdb_dend;
const unsigned char *mem = cdbp->cdb_mem;
if (pos > dend - 8)
return 0;
klen = cdb_unpack(mem + pos);
vlen = cdb_unpack(mem + pos + 4);
pos += 8;
if (dend - klen < pos || dend - vlen < pos + klen)
return errno = EPROTO, -1;
cdbp->cdb_kpos = pos;
cdbp->cdb_klen = klen;
cdbp->cdb_vpos = pos + klen;
cdbp->cdb_vlen = vlen;
*cptr = pos + klen + vlen;
return 1;
}
}

View file

@ -1,24 +0,0 @@
/* unpack 32bit integer
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
#include "common/setup_before.h"
#include "cdb.h"
#include "common/setup_after.h"
namespace pvpgn
{
unsigned
cdb_unpack(const unsigned char buf[4])
{
unsigned n = buf[3];
n <<= 8; n |= buf[2];
n <<= 8; n |= buf[1];
n <<= 8; n |= buf[0];
return n;
}
}