tinycdb-0.78build1/0000775000000000000000000000000011753222544011102 5ustar tinycdb-0.78build1/ChangeLog0000664000000000000000000001235711753175776012702 0ustar 2006-06-29 Michael Tokarev * see debian/changelog file for further changes. 2005-04-18 Michael Tokarev * move cdb_make_find.c content into cdb_make_put.c * introduce CDB_PUT_REPLACE0 - zerofill old duplicates * allow usage of cdb.h in C++ 2005-04-11 Michael Tokarev * do not autogenerate files (cdb.h.in, cdb.3.in etc), but use real files instead (only substituted VERSION and NAME) * finally fixed the `!fputs()' condition to be `fputs() < 0' as it should be in cdb.c (misbehaves on *bsd) * kill cdbi_t usage in cdb_int.h * export _cdb_make_fullwrite() (was ewrite()) and _cdb_make_flush() and use them in cdb_make.c as appropriate * almost completely rewrite _cdb_make_find() and friends: - _cdb_make_find() now accepts new parameter, remove (bool), which, if true, indicates all found records should be deleted from the database. - Call _cdb_make_find() with remove=0 from cdb_make_exists() - Call _cdb_make_find() with appropriate arguments from cdb_make_put(), and simplify the latter greatly (was too clumsy anyway) * rename `flags' parameter in cdb_make_put() to be `mode' which is more appropriate * change #if conditional in nss_cdb.c from __GLIBC__ to __GNU_LIBRARY__ 2003-11-04 Michael Tokarev * 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 * 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 * version 0.73 * de-Debianization. Oh well... ;) * no code changes, just like in 0.72 2002-10-13 Michael Tokarev * version 0.72 * cleaned up debian packaging and made it actually work * no code changes 2002-07-22 Michael Tokarev * 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 * version 0.7a * converted to CVS, added two missing #include for malloc declaration and spec target to the Makefile 2001-10-14 Michael Tokarev * version 0.7 * added cdb_seek() and cdb_bread() routines as found in freecdb/cdb-0.64 2001-07-26 Michael Tokarev * 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 * version 0.5 * added missing #include 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 * autogenerate tinycdb.spec file from template and debian/changelog * autogenerate cdb.h from cdb.h.in (substituting version) 2001-06-29 Michael Tokarev * 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 * version 0.3 * Initial Release. tinycdb-0.78build1/Makefile0000664000000000000000000001066011753222373012545 0ustar #! /usr/bin/make -rf # Makefile: make file for tinycdb package # # This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. # Public domain. VERSION = 0.78 prefix=/usr/local exec_prefix=$(prefix) bindir=$(exec_prefix)/bin libdir=$(exec_prefix)/lib syslibdir=$(libdir) sysconfdir=/etc includedir=$(prefix)/include mandir=$(prefix)/man NSSCDB_DIR = $(sysconfdir) DESTDIR= CC = cc CFLAGS = -O CDEFS = -D_FILE_OFFSET_BITS=64 LD = $(CC) LDFLAGS = AR = ar ARFLAGS = rv RANLIB = ranlib NSS_CDB = libnss_cdb.so.2 LIBBASE = libcdb LIB = $(LIBBASE).a PICLIB = $(LIBBASE)_pic.a SHAREDLIB = $(LIBBASE).so.1 SOLIB = $(LIBBASE).so CDB_USELIB = $(LIB) NSS_USELIB = $(PICLIB) LIBMAP = $(LIBBASE).map INSTALLPROG = cdb # The following assumes GNU CC/LD - # used for building shared libraries only CFLAGS_PIC = -fPIC LDFLAGS_SHARED = -shared LDFLAGS_SONAME = -Wl,--soname= LDFLAGS_VSCRIPT = -Wl,--version-script= CP = cp LIB_SRCS = cdb_init.c cdb_find.c cdb_findnext.c cdb_seq.c cdb_seek.c \ cdb_unpack.c \ cdb_make_add.c cdb_make_put.c cdb_make.c cdb_hash.c NSS_SRCS = nss_cdb.c nss_cdb-passwd.c nss_cdb-group.c nss_cdb-spwd.c NSSMAP = nss_cdb.map DISTFILES = Makefile cdb.h cdb_int.h $(LIB_SRCS) cdb.c \ $(NSS_SRCS) nss_cdb.h nss_cdb-Makefile \ cdb.3 cdb.1 cdb.5 \ tinycdb.spec tests.sh tests.ok \ $(LIBMAP) $(NSSMAP) \ ChangeLog NEWS DEBIANLIST = changelog compat control control.nss copyright libcdb.pc rules DEBIANFILES = $(addprefix debian/, $(DEBIANLIST)) all: static static: staticlib cdb staticlib: $(LIB) nss: $(NSS_CDB) piclib: $(PICLIB) sharedlib: $(SHAREDLIB) shared: sharedlib cdb-shared LIB_OBJS = $(LIB_SRCS:.c=.o) LIB_OBJS_PIC = $(LIB_SRCS:.c=.lo) NSS_OBJS = $(NSS_SRCS:.c=.lo) $(LIB): $(LIB_OBJS) -rm -f $@ $(AR) $(ARFLAGS) $@ $(LIB_OBJS) -$(RANLIB) $@ $(PICLIB): $(LIB_OBJS_PIC) -rm -f $@ $(AR) $(ARFLAGS) $@ $(LIB_OBJS_PIC) -$(RANLIB) $@ $(SHAREDLIB): $(LIB_OBJS_PIC) $(LIBMAP) -rm -f $(SOLIB) ln -s $@ $(SOLIB) $(LD) $(LDFLAGS) $(LDFLAGS_SHARED) -o $@ \ $(LDFLAGS_SONAME)$(SHAREDLIB) $(LDFLAGS_VSCRIPT)$(LIBMAP) \ $(LIB_OBJS_PIC) cdb: cdb.o $(CDB_USELIB) $(LD) $(LDFLAGS) -o $@ cdb.o $(CDB_USELIB) cdb-shared: cdb.o $(SHAREDLIB) $(LD) $(LDFLAGS) -o $@ cdb.o $(SHAREDLIB) $(NSS_CDB): $(NSS_OBJS) $(NSS_USELIB) $(NSSMAP) $(LD) $(LDFLAGS) $(LDFLAGS_SHARED) -o $@ \ $(LDFLAGS_SONAME)$@ $(LDFLAGS_VSCRIPT)$(NSSMAP) \ $(NSS_OBJS) $(NSS_USELIB) .SUFFIXES: .SUFFIXES: .c .o .lo .c.o: $(CC) $(CFLAGS) $(CDEFS) -c $< .c.lo: $(CC) $(CFLAGS) $(CDEFS) $(CFLAGS_PIC) -c -o $@ -DNSSCDB_DIR=\"$(NSSCDB_DIR)\" $< cdb.o: cdb.h $(LIB_OBJS) $(LIB_OBJS_PIC): cdb_int.h cdb.h $(NSS_OBJS): nss_cdb.h cdb.h clean: -rm -f *.o *.lo core *~ tests.out tests-shared.ok realclean distclean: -rm -f *.o *.lo core *~ $(LIBBASE)[._][aps]* $(NSS_CDB)* cdb cdb-shared test tests check: cdb sh ./tests.sh ./cdb > tests.out 2>&1 diff tests.ok tests.out @echo All tests passed test-shared tests-shared check-shared: cdb-shared sed 's/^cdb: /cdb-shared: /' tests-shared.ok LD_LIBRARY_PATH=. sh ./tests.sh ./cdb-shared > tests.out 2>&1 diff tests-shared.ok tests.out rm -f tests-shared.ok @echo All tests passed do_install = \ while [ "$$1" ] ; do \ if [ .$$4 = .- ]; then f=$$1; else f=$$4; fi; \ d=$(DESTDIR)$$3 ; echo installing $$1 to $$d/$$f; \ [ -d $$d ] || mkdir -p $$d || exit 1 ; \ $(CP) $$1 $$d/$$f || exit 1; \ chmod 0$$2 $$d/$$f || exit 1; \ shift 4; \ done install-all: all $(INSTALLPROG) set -- \ cdb.h 644 $(includedir) - \ cdb.3 644 $(mandir)/man3 - \ cdb.1 644 $(mandir)/man1 - \ cdb.5 644 $(mandir)/man5 - \ $(INSTALLPROG) 755 $(bindir) cdb \ libcdb.a 644 $(libdir) - \ ; \ $(do_install) install-nss: nss @set -- $(NSS_CDB) 644 $(syslibdir) - \ nss_cdb-Makefile 644 $(sysconfdir) cdb-Makefile ; \ $(do_install) install-sharedlib: sharedlib @set -- $(SHAREDLIB) 644 $(libdir) - ; \ $(do_install) ; \ ln -sf $(SHAREDLIB) $(DESTDIR)$(libdir)/$(LIBBASE).so install-piclib: piclib @set -- $(PICLIB) 644 $(libdir) - ; \ $(do_install) install: install-all DNAME = tinycdb-$(VERSION) dist: $(DNAME).tar.gz $(DNAME).tar.gz: $(DISTFILES) $(DEBIANFILES) mkdir $(DNAME) $(DNAME)/debian ln $(DISTFILES) $(DNAME)/ ln $(DEBIANFILES) $(DNAME)/debian/ tar cfz $@ $(DNAME) rm -fr $(DNAME) .PHONY: all clean realclean dist spec .PHONY: test tests check test-shared tests-shared check-shared .PHONY: static staticlib shared sharedlib nss piclib .PHONY: install install-all install-sharedlib install-piclib install-nss tinycdb-0.78build1/NEWS0000664000000000000000000000615611753222162011605 0ustar User-visible news. Latest at the top. tinycdb-0.78 2012-05-11 - bugfix release: o fixed >2Gb file size prob on 32bit platform o fixed handling of files >=4Gb o fixed a few compiler warnings - introduce $(LD) and $(LDFLAGS), and also $(CDEFS) in Makefile tinycdb-0.77 - bugfix release: manpage typos, portability fixes and the like - bugfix: improper logic in EINTR handling in _cdb_make_full_write routine which may lead to corruped .cdb file. tinycdb-0.76 - new cdb utility option: -p permissions, to specify permission bits for the newly created database file. - cdb utility, when creating the database, does unlink() of the (temp) db file and when opens it with O_CREAT|O_EXCL, instead of previous O_CREAT|O_TRUNC w/o unlink() behaviour, and uses O_NOFOLLOW flag if available. This avoids any possible symlink race conditions, but is somewhat incompatible with previous versions, where it was possible to create temp file beforehand with proper permissions. Together with new -p option (above), this isn't that big change. - cdb utility now allows to omit temp file usage (with final rename()) when creating the database, by specifying -t- (`-' as temp file name) (or -t the_same_name_as_the_db_file). Useful if the utility is called from a script which does its own rename afterwards. - alot of minor code changes to make modern compilers happy (mostly signed char vs unsigned char "fixes"). Including additions of `unsigned' into common structure definitions in cdb.h - the API stays compatible still. - several (spelling and other) fixes for manpages. - tinycdb is, once again, maintained as a native Debian package. Debian package has been split into 4 parts: libcdb1, libcdb-dev, tinycdb (the utility) and libnss_cdb. RPM .spec file now builds two packages as well: tinycdb (includes shared library, the utility, and nss_cdb module) and tinycdb-devel (development files). tinycdb-0.75 (2005-04-11) - make cdb_make_put(CDB_PUT_REPLACE) to actually *remove* all (was only first previously) matching records, by rewriting the file. - new mode CDB_PUT_REPLACE0, which zeroes out old duplicate records - fixed fputs() == NULL condition in cdb.c, finally (should be < 0, not == NULL) tinycdb-0.74 (2003-11-04) - reworked cdb utility, see manpage for details. cdb -q now prints all matching records by default (incompat change), use cdb -q -n XX to return only XXth record if any. -m works with -q. - there are several new routines (and macros) in library. - cdb_seqinit() and cdb_seqstart() to fetch all records - cdb_get() to get a pointer to data in internal buffer - cdb_{get,read}{data,key}() - cdbi_t gone (but still defined). Use unsigned instead. - cdb_findnext() changed - fixed a bug in cdb_seek() (EIO instead of getting valid record) - added nss_cdb (for passwd, group and shadow databases only) - Makefile targets to build PIC code (libcdb_pic.a, required for nss_cdb) and shared library (probably not a good idea) - Modifications to allow tinycdb to compile under win32, by Victor Porton (porton at ex-code.com). tinycdb-0.78build1/cdb.10000664000000000000000000001515611753222162011720 0ustar .\" cdb.1: cdb command tool manpage .\" .\" This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. .\" Public domain. .\" .TH cdb 1 "Jan 2009" .SH NAME cdb \- Constant DataBase manipulation tool .SH SYNOPSYS \fBcdb\fR \-q [\-m] [\-n \fInum\fR] \fIdbname\fR \fIkey\fR .br \fBcdb\fR \-d [\-m] [\fIdbname\fR|\-] .br \fBcdb\fR \-l [\-m] [\fIdbname\fR|\-] .br \fBcdb\fR \-s [\fIdbname\fR|\-] .br \fBcdb\fR \-c [\-m] [\-t \fItmpname\fR|\-] [\-p \fIperms\fR] [\-weru0] \fIdbname\fR [\fIinfile\fR...] .SH DESCRIPTION \fBcdb\fR used to query, dump, list, analyze or create CDB (Constant DataBase) files. Format of cdb described in \fIcdb\fR(5) manpage. This manual page corresponds to version \fB0.78\fR of \fBtinycdb\fR package. .SS Query \fBcdb \-q\fR finds given \fIkey\fR in a given \fIdbname\fR cdb file, and writes associated value to standard output if found (and exits with zero), or exits with non\-zero if not found. \fIdbname\fR must be seekable file, and stdin can not be used as input. By default, \fBcdb\fR will print \fIall\fR records found. Options recognized in query mode: .IP \fB\-n\fInum\fR causes \fBcdb\fR to find and write a record with a given number \fInum\fR starting with 1 \(em when there are many records with a given key. .IP \fB\-m\fR newline will be added after every value printed. By default, multiple values will be written without any delimiter. .SS "Dump/List" \fBcdb \-d\fR dumps contents, and \fBcdb \-l\fR lists keys of \fIcdbfile\fR (or standard input if not specified) to standard output, in format controlled by presence of \fB\-m\fR option. See subsection "Formats" below. Output from \fBcdb \-d\fR can be used as an input for \fBcdb \-c\fR. .SS Create Cdb database created in two stages: temporary database is created, and after it is complete, it gets atomically renamed to permanent place. This avoids requirements for locking between readers and writers (or creaters). \fBcdb \-c\fR will attempt to create cdb in file \fItmpname\fR (or \fIdbname\fR with ".tmp" appended if no \-t option given) and then rename it to \fIdbname\fR. It will read supplied \fIinfile\fRs (or standard input if none specified). Options recognized in create mode: .IP "\fB\-t \fItmpname\fR" use given \fItmpname\fR as temporary file. Defaults to \fIdbname\fR.tmp (i.e. with output file with .tmp added). Note \fItmpname\fR must be in the same filesystem as output file, as .B cdb uses .IR rename (2) to finalize the database creation procedure. If \fItmpname\fR is a single dash (\-), no temp file will be created, database will be built in\-place. This mode is useful when the final renaming is done by the caller. .IP "\fB\-p \fIperms\fR" permissions for the newly created file (usually an octal number, like 0644). By default the permissions are 0666 (with current process umask applied). If this option is specified, current umask value has no effect. .IP \fB\-w\fR warn about duplicate keys. .IP \fB\-e\fR abort on duplicate keys (implies \-w). .IP \fB\-r\fR replace existing key with new one in case of duplicate. This may require database file rewrite to remove old records, and can be slow. .IP \fB\-0\fR zero-fill existing records when duplicate records are added. This is faster than \fB\-r\fR, but leaves extra zeros in the database file in case of duplicates. .IP \fB\-u\fR do not add duplicate records. .IP \fB\-m\fR interpret input as a sequence of lines, one record per line, with value separated from a key by space or tab characters, instead of native cdb format (see "Input/Output Format" below). .PP Note that using any option that requires duplicate checking will slow creation process \fIsignificantly\fR, especially for large databases. .SS Statistics \fBcdb \-s\fR will analyze \fIdbfile\fR and print summary to standard output. Statistics include: total number of rows in a file, minimum, average and maximum key and value lengths, hash tables (max 256) and entries used, number of hash collisions (that is, more than one key point to the same hash table entry), minimum, average and maximum hash table size (of non-empty tables), and number of keys that sits at 10 different distances from it's calculated hash table index \(em keys in distance 0 requires only one hash table lookup, 1 \(em two and so on; more keys at greater distance means slower database search. .SS "Input/Output Format" By default, \fBcdb\fR expects (for create operation) or writes (for dump/list) native cdb format data. Cdb native format is a sequence of records in a form: .br +\fIklen\fR,\fIvlen\fR:\fIkey\fR\->\fIval\fR\\n .br where "+", ",", ":", "\-", ">" and "\\n" (newline) are literal characters, \fIklen\fR and \fIvlen\fR are length of key and value as decimal numbers, and \fIkey\fR and \fIval\fR are key and value themselves. Series of records terminated by an empty line. This is the only format where key and value may contain any character including newline, zero (\\0) and so on. When \fB\-l\fR option requested (list keys mode), \fBcdb\fR will produce slightly modified output in a form: .br +\fIklen\fR:\fIkey\fR\\n .br (note \fIvlen\fR and \fIval\fR are omitted, together with surrounding delimiters). If \fB\-m\fR option is given, \fBcdb\fR will expect or produce one line for every record (newline is a record delimiter), and every line should contain optional whitespace, key, whitespace and value up to end of line. Lines started with hash character (#) and empty lines are ignored. This is the same format as \fBmkmap\fR(1) utility expects. .SH "OPTIONS SUMMARY" Here is a short summary of all options accepted by \fBcdb\fR utility: .IP \fB\-0\fR zero-fill duplicate records in create (\fB\-c\fR) mode. .IP \fB\-c\fR create mode. .IP \fB\-d\fR dump mode. .IP \fB\-e\fR abort (error) on duplicate key in create (\fB\-c\fR) mode. .IP \fB\-h\fR print short help and exit. .IP \fB\-l\fR list mode. .IP \fB\-m\fR input or output is in "map" format, not in native cdb format. In query mode, add a newline after every value written. .IP \fB\-n\fInum\fR find and print \fInum\fRth record in query (\fB\-q\fR) mode. .IP \fB\-q\fR query mode. .IP \fB\-r\fR replace duplicate keys in create (\fB\-c\fR) mode. .IP \fB\-s\fR statistics mode. .IP "\fB\-t\fR \fItempfile\fR" specify temporary file when creating (\fB\-c\fR) cdb file (use single dash (\-) as \fItempfile\fR to stop using temp file). .IP \fB\-u\fR do not insert duplicate keys (unique) in create (\fB\-c\fR) mode. .IP \fB\-w\fR warn about duplicate keys in create (\fB\-c\fR) mode. .SH AUTHOR The \fBtinycdb\fR package written by Michael Tokarev , based on ideas and shares file format with original cdb library by Dan Bernstein. .SH "SEE ALSO" cdb(5), cdb(3). .SH LICENCE Public domain. tinycdb-0.78build1/cdb.30000664000000000000000000004745411753222162011730 0ustar .\" cdb.3: cdb library manpage .\" .\" This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. .\" Public domain. .\" .TH cdb 3 "Jun 2006" .SH NAME cdb \- Constant DataBase library .SH SYNOPSYS .nf .ft B #include cc ... \-lcdb .ft R .fi .SH DESCRIPTION .B cdb is a library to create and access Constant DataBase files. File stores (key,value) pairs and used to quickly find a value based on a given key. Cdb files are create-once files, that is, once created, file cannot be updated but recreated from scratch -- this is why database is called \fIconstant\fR. Cdb file is optimized for quick access. Format of such file described in \fIcdb\fR(5) manpage. This manual page corresponds to version \fB0.78\fR of \fBtinycdb\fR package. Library defines two non-interlaced interfaces: for querying existing cdb file data (read-only mode) and for creating such a file (almost write-only). Strictly speaking, those modes allows very limited set of opposite operation as well (i.e. in query mode, it is possible to update key's value). All routines in this library are thread-safe as no global data used, except of \fIerrno\fR variable for error indication. .B cdb datafiles may be moved between systems safely, since format does not depend on architecture. .SH "QUERY MODE" There are two query modes available. First uses a structure that represents a cdb database, just like \fBFILE\fR structure in stdio library, and another works with plain filedescriptor. First mode is more sophisticated and flexible, and usually somewhat faster. It uses \fBmmap\fR(2) internally. This mode may look more "natural" or object-oriented compared to second one. The following routines works with any mode: .nf unsigned \fBcdb_unpack\fR(\fIbuf\fR) const unsigned char \fIbuf\fR[4]; .fi .RS helper routine to convert 32-bit integer from internal representation to machine format. May be used to handle application integers in a portable way. There is no error return. .RE .SS "Query Mode 1" All query operations in first more deals with common data structure, \fBstruct cdb\fR, associated with an open file descriptor. This structure is opaque to application. The following routines exists for accessing \fBcdb\fR database: .nf int \fBcdb_init\fR(\fIcdbp\fR, \fIfd\fR) struct cdb *\fIcdbp\fR; int \fIfd\fR; .fi .RS initializes structure given by \fIcdbp\fR pointer and associates it with opened file descriptor \fIfd\fR. Memory allocation for structure itself if needed and file open operation should be done by application. File \fIfd\fR should be opened at least read-only, and should be seekable. Routine returns 0 on success or negative value on error. .RE .nf void \fBcdb_free\fR(\fIcdbp\fR) struct cdb *\fIcdbp\fR; .fi .RS frees internal resources held by structure. Note that this routine does \fInot\fR closes a file. .RE .nf int \fBcdb_fileno\fR(\fIcdbp\fR) const struct cdb *\fIcdbp\fR; .fi .RS returns filedescriptor associated with cdb (as was passed to \fBcdb_init\fR()). .RE .nf int \fBcdb_read\fR(\fIcdbp\fR, \fIbuf\fR, \fIlen\fR, \fIpos\fR) int \fBcdb_readdata\fR(\fIcdbp\fR, \fIbuf\fR, \fIlen\fR, \fIpos\fR) int \fBcdb_readkey\fR(\fIcdbp\fR, \fIbuf\fR, \fIlen\fR, \fIpos\fR) const struct cdb *\fIcdbp\fR; void *\fIbuf\fR; unsigned \fIlen\fR; unsigned \fIpos\fR; .fi .RS reads a data from cdb file, starting at position \fIpos\fR of length \fIlen\fR, placing result to \fIbuf\fR. This routine may be used to get actual value found by \fBcdb_find\fR() or other routines that returns position and length of a data. Returns 0 on success or negative value on error. Routines \fBcdb_readdata\fR() and \fBcdb_readkey\fR() are shorthands to read current (after e.g. \fBcdb_find\fR()) data and key respectively, using \fBcdb_read\fR(). .RE .nf const void *\fBcdb_get\fR(\fIcdbp\fR, \fIlen\fR, \fIpos\fR) const void *\fBcdb_getdata\fR(\fIcdbp\fR) const void *\fBcdb_getkey\fR(\fIcdbp\fR) const struct cdb *\fIcdbp\fR; unsigned \fIlen\fR; unsigned \fIpos\fR; .fi .RS Internally, cdb library uses memory-mmaped region to access the on-disk database. \fBcdb_get\fR() allows to access internal memory in a way similar to \fBcdb_read\fR() but without extra copying and buffer allocation. Returns pointer to actual data on success or NULL on error (position points to outside of the database). Routines \fBcdb_getdata\fR() and \fBcdb_getkey\fR() are shorthands to access current (after e.g. \fBcdb_find\fR()) data and key respectively, using \fBcdb_get\fR(). .RE .nf int \fBcdb_find\fR(\fIcdbp\fR, \fIkey\fR, \fIklen\fR) unsigned \fBcdb_datapos\fR(\fIcdbp\fR) unsigned \fBcdb_datalen\fR(\fIcdbp\fR) unsigned \fBcdb_keypos\fR(\fIcdbp\fR) unsigned \fBcdb_keylen\fR(\fIcdbp\fR) struct cdb *\fIcdbp\fR; const void *\fIkey\fR; unsigned \fIklen\fR; .fi .RS attempts to find a key given by (\fIkey\fR,\fIklen\fR) parameters. If key exists in database, routine returns 1 and places position and length of value associated with this key to internal fields inside \fIcdbp\fR structure, to be accessible by \fBcdb_datapos\fR(\fIcdbp\fR) and \fBcdb_datalen\fR(\fIcdbp\fR) routines. If key is not in database, \fBcdb_find\fR() returns 0. On error, negative value is returned. Data pointers (available via \fBcdb_datapos\fR() and \fBcdb_datalen\fR()) gets updated only in case of successful search. Note that using \fBcdb_find\fR() it is possible to lookup only \fIfirst\fR record with a given key. .RE .nf int \fBcdb_findinit(\fIcdbfp\fR, \fIcdbp\fR, \fIkey\fR, \fIklen\fR) int \fBcdb_findnext\fR(\fIcdbfp\fR) struct cdb_find *\fIcdbfp\fR; const struct cdb *\fIcdbp\fR; const void *\fIkey\fR; unsigned \fIklen\fR; .fi .RS sequential-find routines that used separate structure. It is possible to have more than one record with the same key in a database, and these routines allows to enumerate all them. \fBcdb_findinit\fR() initializes search structure pointed to by \fIcdbfp\fR. It will return negative value on error or non-negative value on success. \fBcdb_findnext\fR() attempts to find next (first when called right after \fBcdb_findinit\fR()) matching key, setting value position and length in \fIcdbfp\fR structure. It will return positive value if given key was found, 0 if there is no more such key(s), or negative value on error. To access value position and length after successful call to \fBcdb_findnext\fR() (when it returned positive result), use \fBcdb_datapos\fR(\fIcdbp\fR) and \fBcdb_datalen\fR(\fIcdbp\fR) routines. It is error to continue using \fBcdb_findnext\fR() after it returned 0 or error condition (\fBcdb_findinit\fR() should be called again). Current data pointers (available via \fBcdb_datapos\fR() and \fBcdb_datalen\fR()) gets updated only on successful search. .RE .nf void \fBcdb_seqinit\fR(\fIcptr\fR, \fIcdbp\fR) int \fBcdb_seqnext\fR(\fIcptr\fR, \fIcdbp\fR) unsigned *\fIcptr\fR; struct cdb *\fIcdbp\fR; .fi .RS sequential enumeration of all records stored in cdb file. \fBcdb_seqinit\fR() initializes access current data pointer \fIcptr\fR to point before first record in a cdb file. \fBcdb_seqnext\fR() updates data pointers in \fIcdbp\fR to point to the next record and updates \fIcptr\fR, returning positive value on success, 0 on end of data condition and negative value on error. Current record will be available after successful operation using \fBcdb_datapos\fR(\fIcdbp\fR) and \fBcdb_datalen\fR(\fIcdbp\fR) (for the data) and \fBcdb_keypos\fR(\fIcdbp\fR) and \fBcdb_keylen\fR(\fIcdbp\fR) (for the key of the record). Data pointers gets updated only in case of successful operation. .RE .SS "Query Mode 2" In this mode, one need to open a \fBcdb\fR file using one of standard system calls (such as \fBopen\fR(2)) to obtain a filedescriptor, and then pass that filedescriptor to cdb routines. Available methods to query a cdb database using only a filedescriptor include: .nf int \fBcdb_seek\fR(\fIfd\fR, \fIkey\fR, \fIklen\fR, \fIdlenp\fR) int \fIfd\fR; const void *\fIkey\fR; unsigned \fIklen\fR; unsigned *\fIdlenp\fR; .fi .RS searches a cdb database (as pointed to by \fIfd\fR filedescriptor) for a key given by (\fIkey\fR, \fIklen\fR), and positions file pointer to start of data associated with that key if found, so that next read operation from this filedescriptor will read that value, and places length of value, in bytes, to variable pointed to by \fIdlenp\fR. Returns positive value if operation was successful, 0 if key was not found, or negative value on error. To read the data from a cdb file, \fBcdb_bread\fR() routine below can be used. .RE .nf int \fBcdb_bread\fR(\fIfd\fR, \fIbuf\fR, \fIlen\fR) int \fIfd\fR; void *\fIbuf\fR; int \fIlen\fR; .fi .RS reads data from a file (as pointed to by \fIfd\fR filedescriptor) and places \fIlen\fR bytes from this file to a buffer pointed to by \fIbuf\fR. Returns 0 if exactly \fIlen\fR bytes was read, or a negative value in case of error or end-of-file. This routine ignores interrupt errors (EINTR). Sets errno variable to \fBEIO\fR in case of end-of-file condition (when there is less than \fIlen\fR bytes available to read). .RE .SS Notes Note that \fIvalue\fR of any given key may be updated in place by another value of the same size, by writing to file at position found by \fBcdb_find\fR() or \fBcdb_seek\fR(). However one should be very careful when doing so, since write operation may not succeed in case of e.g. power failure, thus leaving corrupted data. When database is (re)created, one can guarantee that no incorrect data will be written to database, but not with inplace update. Note also that it is not possible to update any key or to change length of value. .SS .SH "CREATING MODE" .B cdb database file should usually be created in two steps: first, temporary file created and written to disk, and second, that temporary file is renamed to permanent place. Unix rename(2) call is atomic operation, it removes destination file if any AND renaes another file in one step. This way it is guaranteed that readers will not see incomplete database. To prevent multiple simultaneous updates, locking may also be used. All routines used to create \fBcdb\fR database works with \fBstruct cdb_make\fR object that is opaque to application. Application may assume that \fBstruct cdb_make\fR has at least the same member(s) as published in \fBstruct cdb\fR above. .nf int \fBcdb_make_start\fR(\fIcdbmp\fR, \fIfd\fR) struct cdb_make *\fIcdbmp\fR; int \fIfd\fR; .fi .RS initializes structure to create a database. File \fIfd\fR should be opened read-write and should be seekable. Returns 0 on success or negative value on error. .RE .nf int \fBcdb_make_add\fR(\fIcdbmp\fR, \fIkey\fR, \fIklen\fR, \fIval\fR, \fIvlen\fR) struct cdb_make *\fIcdbmp\fR; const void *\fIkey\fR, *\fIval\fR; unsigned \fIklen\fR, \fIvlen\fR; .fi .RS adds record with key (\fIkey\fR,\fIklen\fR) and value (\fIval\fR,\fIvlen\fR) to a database. Returns 0 on success or negative value on error. Note that this routine does not checks if given key already exists, but \fBcdb_find\fR() will not see second record with the same key. It is not possible to continue building a database if \fBcdb_make_add\fR() returned error indicator. .RE .nf int \fBcdb_make_finish\fR(\fIcdbmp\fR) struct cdb_make *\fIcdbmp\fR; .fi .RS finalizes database file, constructing all needed indexes, and frees memory structures. It does \fInot\fR closes filedescriptor. Returns 0 on success or negative value on error. .RE .nf int \fBcdb_make_exists\fR(\fIcdbmp\fR, \fIkey\fR, \fIklen\fR) struct cdb_make *\fIcdbmp\fR; const void *\fIkey\fR; unsigned \fIklen\fR; .fi .RS This routine attempts to find given by (\fIkey\fR,\fIklen\fR) key in a not-yet-complete database. It may significantly slow down the whole process, and currently it flushes internal buffer to disk on every call with key those hash value already exists in db. Returns 0 if such key doesn't exists, 1 if it is, or negative value on error. Note that database file should be opened read-write (not write-only) to use this routine. If \fBcdb_make_exists\fR() returned error, it may be not possible to continue constructing database. .RE .nf int \fBcdb_make_find\fR(\fIcdbmp\fR, \fIkey\fR, \fIklen\fR, \fImode\fR) struct cdb_make *\fIcdbmp\fR; const void *\fIkey\fR; unsigned \fIklen\fR; int \fImode\fR; .fi .RS This routine attempts to find given by (\fIkey\fR,\fIklen\fR) key in the database being created. If the given key is already exists, it an action specified by \fImode\fR will be performed: .IP \fBCDB_FIND\fR checks whenever the given record is already in the database. .IP \fBCDB_FIND_REMOVE\fR removes all matching records by re-writing the database file accordingly. .IP \fBCDB_FIND_FILL0\fR fills all matching records with zeros and removes them from index so that the records in question will not be findable with \fBcdb_find\fR(). This is faster than CDB_FIND_REMOVE, but leaves zero "gaps" in the database. Lastly inserted records, if matched, are always removed. .PP If no matching keys was found, routine returns 0. In case at least one record has been found/removed, positive value will be returned. On error, negative value will be returned and \fBerrno\fR will be set appropriately. When \fBcdb_make_find\fR() returned negative value in case of error, it is not possible to continue constructing the database. .PP \fBcdb_make_exists\fR() is the same as calling \fBcdb_make_find\fR() with \fImode\fR set to CDB_FIND. .RE .nf int \fBcdb_make_put\fR(\fIcdbmp\fR, \fIkey\fR, \fIklen\fR, \fIval\fR, \fIvlen\fR, \fImode\fR) struct cdb_make *\fIcdbmp\fR; const void *\fIkey\fR, *\fIval\fR; unsigned \fIklen\fR, \fIvlen\fR; int \fImode\fR; .fi .RS This is a somewhat combined \fBcdb_make_exists\fR() and \fBcdb_make_add\fR() routines. \fImode\fR argument controls how repeated (already existing) keys will be treated: .IP \fBCDB_PUT_ADD\fR no duplicate checking will be performed. This mode is the same as \fBcdb_make_add\fR() routine does. .IP \fBCDB_PUT_REPLACE\fR If the key already exists, it will be removed from the database before adding new key,value pair. This requires moving data in the file, and can be quite slow if the file is large. All matching old records will be removed this way. This is the same as calling \fBcdb_make_find\fR() with CDB_FIND_REMOVE \fImode\fR argument followed by calling \fBcdb_make_add\fR(). .IP \fBCDB_PUT_REPLACE0\fR If the key already exists and it isn't the last record in the file, old record will be zeroed out before adding new key,value pair. This is alot faster than CDB_PUT_REPLACE, but some extra data will still be present in the file. The data -- old record -- will not be accessible by normal searches, but will appear in sequential database traversal. This is the same as calling \fBcdb_make_find\fR() with CDB_FIND_FILL0 \fImode\fR argument followed by \fBcdb_make_add\fR(). .IP \fBCDB_PUT_INSERT\fR add key,value pair only if such key does not exists in a database. Note that since query (see query mode above) will find first added record, this mode is somewhat useless (but allows to reduce database size in case of repeated keys). This is the same as calling \fBcdb_make_exists\fR(), followed by \fBcdb_make_add\fR() if the key was not found. .IP \fBCDB_PUT_WARN\fR add key,value pair unconditionally, but also check if this key already exists. This is equivalent of \fBcdb_make_exists\fR() to check existence of the given key, unconditionally followed by \fBcdb_make_add\fR(). .PP If any error occurred during operations, the routine will return negative integer and will set global variable \fBerrno\fR to indicate reason of failure. In case of successful operation and no duplicates found, routine will return 0. If any duplicates has been found or removed (which, in case of CDB_PUT_INSERT mode, indicates that the new record was not added), routine will return positive value. If an error occurred and \fBcdb_make_put\fR() returned negative error, it is not possible to continue database construction process. .PP As with \fBcdb_make_exists\fR() and \fBcdb_make_find\fR(), usage of this routine with any but CDB_PUT_ADD mode can significantly slow down database creation process, especially when \fImode\fR is equal to CDB_PUT_REPLACE0. .RE .nf void \fBcdb_pack\fR(\fInum\fR, \fIbuf\fR) unsigned \fInum\fR; unsigned char \fIbuf\fR[4]; .fi .RS helper routine that used internally to convert machine integer \fIn\fR to internal form to be stored in datafile. 32-bit integer is stored in 4 bytes in network byte order. May be used to handle application data. There is no error return. .RE .nf unsigned \fBcdb_hash\fR(\fIbuf\fR, \fIlen\fR) const void *\fIbuf\fR; unsigned \fIlen\fR; .fi .RS helper routine that calculates cdb hash value of given bytes. CDB hash function is .br hash[n] = (hash[n\-1] + (hash[n\-1] << 5)) ^ buf[n] .br starting with .br hash[\-1] = 5381 .br .RE .SH ERRORS .B cdb library may set \fBerrno\fR to following on error: .IP EPROTO database file is corrupted in some way .IP EINVAL the same as EPROTO above if system lacks EPROTO constant .IP EINVAL \fIflag\fR argument for \fBcdb_make_put\fR() is invalid .IP EEXIST \fIflag\fR argument for \fBcdb_make_put\fR() is CDB_PUT_INSERT, and key already exists .IP ENOMEM not enough memory to complete operation (\fBcdb_make_finish\fR and \fBcdb_make_add\fR) .IP EIO set by \fBcdb_bread\fR and \fBcdb_seek\fR if a cdb file is shorter than expected or corrupted in some other way. .SH EXAMPLES .PP Note: in all examples below, error checking is not shown for brewity. .SS "Query Mode" .nf int fd; struct cdb cdb; char *key, *data; unsigned keylen, datalen; /* opening the database */ fd = open(filename, O_RDONLY); cdb_init(&cdb, fd); /* initialize key and keylen here */ /* single\-record search. */ if (cdb_find(&cdb, key, keylen) > 0) { datalen = cdb_datalen(&cdb); data = malloc(datalen + 1); cdb_read(&cdb, data, datalen, cdb_datapos(&cdb)); data[datalen] = '\\0'; printf("key=%s data=%s\\n", key, data); free(data); } else printf("key=%s not found\\n", key); /* multiple record search */ struct cdb_find cdbf; int n; cdb_findinit(&cdbf, &cdb, key, keylen); n = 0; while(cdb_findnext(&cdbf) > 0) { datalen = cdb_datalen(&cdb); data = malloc(datalen + 1); cdb_read(&cdb, data, datalen, cdb_datapos(&cdb)); data[datalen] = '\\0'; printf("key=%s data=%s\\n", key, data); free(data); ++n; } printf("key=%s %d records found\\n", n); /* sequential database access */ unsigned pos; int n; cdb_seqinit(&pos, &cdb); n = 0; while(cdb_seqnext(&pos, &cdb) > 0) { keylen = cdb_keylen(&cdb); key = malloc(keylen + 1); cdb_read(&cdb, key, keylen, cdb_keypos(&cdb)); key[keylen] = '\\0'; datalen = cdb_datalen(&cdb); data = malloc(datalen + 1); cdb_read(&cdb, data, datalen, cdb_datapos(&cdb)); data[datalen] = '\\0'; ++n; printf("record %n: key=%s data=%s\\n", n, key, data); free(data); free(key); } printf("total records found: %d\\n", n); /* close the database */ cdb_free(&cdb); close(fd); /* simplistic query mode */ fd = open(filename, O_RDONLY); if (cdb_seek(fd, key, keylen, &datalen) > 0) { data = malloc(datalen + 1); cdb_bread(fd, data, datalen); data[datalen] = '\\0'; printf("key=%s data=%s\\n", key, data); } else printf("key=%s not found\\n", key); close(fd); .fi .SS "Create Mode" .nf int fd; struct cdb_make cdbm; char *key, *data; unsigned keylen, datalen; /* initialize the database */ fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644); cdb_make_start(&cdbm, fd); while(have_more_data()) { /* initialize key and data */ if (cdb_make_exists(&cdbm, key, keylen) == 0) cdb_make_add(&cdbm, key, keylen, data, datalen); /* or use cdb_make_put() with appropriate flags */ } /* finalize and close the database */ cdb_make_finish(&cdbm); close(fd); .fi .SH "SEE ALSO" cdb(5), cdb(1), dbm(3), db(3), open(2). .SH AUTHOR The \fBtinycdb\fR package written by Michael Tokarev , based on ideas and shares file format with original cdb library by Dan Bernstein. .SH LICENSE Public domain. tinycdb-0.78build1/cdb.50000664000000000000000000000562311753176634011736 0ustar .\" cdb.5: cdb file format manpage .\" .\" This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. .\" Public domain. .\" .TH cdb 5 "Apr, 2005" .SH NAME cdb \- Constant DataBase file format .SH DESCRIPTION A \fBcdb\fR database is a single file used to map `keys' to `values', having records of (key,value) pairs. File consists of 3 parts: toc (table of contents), data and index (hash tables). Toc has fixed length of 2048 bytes, containing 256 pointers to hash tables inside index sections. Every pointer consists of position of a hash table in bytes from the beginning of a file, and a size of a hash table in entries, both are 4-bytes (32 bits) unsigned integers in little-endian form. Hash table length may have zero length, meaning that corresponding hash table is empty. Right after toc section, data section follows without any alingment. It consists of series of records, each is a key length, value (data) length, key and value. Again, key and value length are 4-byte unsigned integers. Each next record follows previous without any special alignment. After data section, index (hash tables) section follows. It should be looked to in conjunction with toc section, where each of max 256 hash tables are defined. Index section consists of series of hash tables, with starting position and length defined in toc section. Every hash table is a sequence of records each holds two numbers: key's hash value and record position inside data section (bytes from the beginning of a file to first byte of key length starting data record). If record position is zero, then this is an empty hash table slot, pointed to nowhere. CDB hash function is .nf hv = ((hv << 5) + hv) ^ \fIc\fR .fi for every single \fIc\fR byte of a key, starting with hv = \fI5381\fR. Toc section indexed by (hv % 256), i.e. hash value modulo 256 (number of entries in toc section). In order to find a record, one should: first, compute the hash value (hv) of a key. Second, look to hash table number hv modulo 256. If it is empty, then there is no such key exists. If it is not empty, then third, loop by slots inside that hash table, starting from slot with number hv divided by 256 modulo length of that table, or ((hv / 256) % htlen), searching for this hv in hash table. Stop search on empty slot (if record position is zero) or when all slots was probed (note cyclic search, jumping from end to beginning of a table). When hash value in question is found in hash table, look to key of corresponding record, comparing it with key in question. If them of the same length and equals to each other, then record is found, overwise, repeat with next hash table slot. Note that there may be several records with the same key. .SH SEE ALSO cdb(1), cdb(3). .SH AUTHOR The \fBtinycdb\fR package written by Michael Tokarev , based on ideas and shares file format with original cdb library by Dan Bernstein. .SH LICENSE Public domain. tinycdb-0.78build1/cdb.c0000664000000000000000000003377211753217477012023 0ustar /* cdb.c: cdb command line tool * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #define _GNU_SOURCE /* #define this even on Windows */ #ifdef _WIN32 /* by the way, how about win64? */ # include # include /* This pragma suppresses snippy VC warnings for POSIX functions like read() */ # pragma warning(disable: 4996) #else # include #endif #include #include #include #include #include #include #include #include #include "cdb.h" #ifndef EPROTO # define EPROTO EINVAL #endif #ifdef __GLIBC__ # define HAVE_PROGRAM_INVOCATION_SHORT_NAME #endif #ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME # define progname program_invocation_short_name #else static char *progname; #endif #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 #endif #ifdef _WIN32 # define FBINMODE "b" #else # define FBINMODE #endif #define F_DUPMASK 0x000f #define F_WARNDUP 0x0100 #define F_ERRDUP 0x0200 #define F_MAP 0x1000 /* map format (or else CDB native format) */ /* Silly defines just to suppress silly compiler warnings. * The thing is, trivial routines like strlen(), fgets() etc expects * char* argument, and GCC>=4 complains about using unsigned char* here. * Silly silly silly. */ #ifdef __GNUC__ static inline size_t ustrlen(const unsigned char *s) { return strlen((const char*)s); } static inline unsigned char *ufgets(unsigned char *s, int size, FILE *f) { return (unsigned char*)fgets((char*)s, size, f); } #else # define ustrlen strlen # define ufgets fgets #endif static unsigned char *buf; static unsigned blen; static void #ifdef __GNUC__ __attribute__((noreturn,format(printf,2,3))) #endif error(int errnum, const char *fmt, ...) { if (fmt) { va_list ap; fprintf(stderr, "%s: ", progname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } if (errnum) fprintf(stderr, ": %s\n", strerror(errnum)); else { if (fmt) putc('\n', stderr); fprintf(stderr, "%s: try `%s -h' for help\n", progname, progname); } fflush(stderr); exit(errnum ? 111 : 2); } static void allocbuf(unsigned len) { if (blen < len) { buf = (unsigned char*)(buf ? realloc(buf, len) : malloc(len)); if (!buf) error(ENOMEM, "unable to allocate %u bytes", len); blen = len; } } static int qmode(char *dbname, const char *key, int num, int flags) { struct cdb c; struct cdb_find cf; int r; int n, found; r = open(dbname, O_RDONLY); if (r < 0 || cdb_init(&c, r) != 0) error(errno, "unable to open database `%s'", dbname); r = cdb_findinit(&cf, &c, key, 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"); fwrite(buf, 1, cdb_datalen(&c), stdout); if (flags & F_MAP) putchar('\n'); if (num) break; } if (r < 0) error(0, "%s", key); return found ? 0 : 100; } static void fget(FILE *f, unsigned char *b, unsigned len, unsigned *posp, unsigned limit) { if (posp && limit - *posp < len) error(EPROTO, "invalid database format"); if (fread(b, 1, len, f) != len) { if (ferror(f)) error(errno, "unable to read"); fprintf(stderr, "%s: unable to read: short file\n", progname); exit(2); } if (posp) *posp += len; } static int fcpy(FILE *fi, FILE *fo, unsigned len, unsigned *posp, unsigned limit) { while(len > blen) { fget(fi, buf, blen, posp, limit); if (fo && fwrite(buf, 1, blen, fo) != blen) return -1; len -= blen; } if (len) { fget(fi, buf, len, posp, limit); if (fo && fwrite(buf, 1, len, fo) != len) return -1; } return 0; } static int dmode(char *dbname, char mode, int flags) { unsigned eod, klen, vlen; unsigned pos = 0; FILE *f; if (strcmp(dbname, "-") == 0) f = stdin; else if ((f = fopen(dbname, "r" FBINMODE)) == NULL) error(errno, "open %s", dbname); allocbuf(2048); fget(f, buf, 2048, &pos, 2048); eod = cdb_unpack(buf); while(pos < eod) { fget(f, buf, 8, &pos, eod); klen = cdb_unpack(buf); vlen = cdb_unpack(buf + 4); if (!(flags & F_MAP)) if (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 (fputs(flags & F_MAP ? " " : "->", stdout) < 0) return -1; if (fcpy(f, mode == 'd' ? stdout : NULL, vlen, &pos, eod) != 0) return -1; if (putc('\n', stdout) < 0) return -1; } if (pos != eod) error(EPROTO, "invalid cdb file format"); if (!(flags & F_MAP)) if (putc('\n', stdout) < 0) return -1; return 0; } static int smode(char *dbname) { 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 (strcmp(dbname, "-") == 0) f = stdin; else if ((f = fopen(dbname, "r" FBINMODE)) == 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, buf, 8, &pos, eod); klen = cdb_unpack(buf); vlen = cdb_unpack(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, buf, 8, &pos, 0xffffffff); if (!cdb_unpack(buf + 4)) continue; h = (cdb_unpack(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; } printf("number of records: %u\n", cnt); printf("key min/avg/max length: %u/%u/%u\n", kmin, cnt ? (ktot + cnt / 2) / cnt : 0, kmax); printf("val min/avg/max length: %u/%u/%u\n", vmin, cnt ? (vtot + cnt / 2) / cnt : 0, vmax); printf("hash tables/entries/collisions: %u/%u/%u\n", hcnt, htot, cnt - dist[0]); printf("hash table min/avg/max length: %u/%u/%u\n", hmin, hcnt ? (htot + hcnt / 2) / hcnt : 0, hmax); printf("hash table distances:\n"); for(k = 0; k < NDIST; ++k) 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) { fprintf(stderr, "%s: %s: bad format\n", progname, fn); exit(2); } static int getnum(FILE *f, unsigned *np, const char *fn) { unsigned n; int c = getc(f); if (c < '0' || c > '9') badinput(fn); n = c - '0'; while((c = 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, const unsigned char *key, unsigned klen, const unsigned 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)) { fprintf(stderr, "%s: key `", progname); fwrite(key, 1, klen, stderr); fputs("' duplicated\n", stderr); if (flags & F_ERRDUP) exit(1); } } static void dofile_cdb(struct cdb_make *cdbmp, FILE *f, const char *fn, int flags) { unsigned klen, vlen; int c; while((c = getc(f)) == '+') { if ((c = getnum(f, &klen, fn)) != ',' || (c = getnum(f, &vlen, fn)) != ':' || 0xffffffff - klen < vlen) badinput(fn); allocbuf(klen + vlen); fget(f, buf, klen, NULL, 0); if (getc(f) != '-' || getc(f) != '>') badinput(fn); fget(f, buf + klen, vlen, NULL, 0); if (getc(f) != '\n') badinput(fn); addrec(cdbmp, buf, klen, buf + klen, vlen, flags); } if (c != '\n') badinput(fn); } static void dofile_ln(struct cdb_make *cdbmp, FILE *f, int flags) { unsigned char *k, *v; while(ufgets(buf, blen, f) != NULL) { unsigned l = 0; for (;;) { l += ustrlen(buf + l); v = buf + l; if (v > buf && v[-1] == '\n') { v[-1] = '\0'; break; } if (l < blen) allocbuf(l + 512); if (!ufgets(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, ustrlen(k), v, ustrlen(v), flags); } } static void dofile(struct cdb_make *cdbmp, FILE *f, const char *fn, int flags) { if (flags & F_MAP) dofile_ln(cdbmp, f, flags); else dofile_cdb(cdbmp, f, fn, flags); if (ferror(f)) error(errno, "read error"); } static int cmode(char *dbname, char *tmpname, int argc, char **argv, int flags, int perms) { struct cdb_make cdb; int fd; if (!tmpname) { tmpname = (char*)malloc(strlen(dbname) + 5); if (!tmpname) error(ENOMEM, "unable to allocate memory"); /* OpenBSD compiler complains about strcat() and strcpy() usage, * and suggests to replace them with (non-standard) strlcat() and * strlcpy(). This is silly, since it's obvious that usage of * original str*() routines here is correct. * This is compiler/environment bug, not tinycdb bug, so please * fix it in proper place, and don't send patches to me. Thank you. */ strcat(strcpy(tmpname, dbname), ".tmp"); } else if (strcmp(tmpname, "-") == 0 || strcmp(tmpname, dbname) == 0) tmpname = dbname; if (perms >= 0) umask(0); unlink(tmpname); fd = open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, perms >= 0 ? perms : 0666); 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 (strcmp(argv[i], "-") == 0) dofile(&cdb, stdin, "(stdin)", flags); else { FILE *f = fopen(argv[i], "r"); if (!f) error(errno, "%s", argv[i]); dofile(&cdb, f, argv[i], flags); fclose(f); } } } else dofile(&cdb, stdin, "(stdin)", flags); if (cdb_make_finish(&cdb) != 0) error(errno, "cdb_make_finish"); close(fd); if (tmpname != dbname) if (rename(tmpname, dbname) != 0) error(errno, "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; int perms = -1; extern char *optarg; extern int optind; #ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME argv[0] = progname; #else if (argv[0] && (progname = strrchr(argv[0], '/')) != NULL) argv[0] = ++progname; else progname = argv[0]; #endif if (argc <= 1) error(0, "no arguments given"); while((c = getopt(argc, argv, "qdlcsht:n:mwruep:0")) != 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 '0': flags = (flags & ~F_DUPMASK) | CDB_PUT_REPLACE0; break; case 'm': flags |= F_MAP; break; case 'p': { char *ep = NULL; perms = strtol(optarg, &ep, 0); if (perms < 0 || perms > 0777 || (ep && *ep)) error(0, "invalid permissions `%s'", optarg); break; } case 'n': { char *ep = NULL; if ((num = strtol(optarg, &ep, 0)) <= 0 || (ep && *ep)) error(0, "invalid record number `%s'", optarg); break; } case 'h': #define strify(x) _strify(x) #define _strify(x) #x printf("\ %s: Constant DataBase (CDB) tool version " strify(TINYCDB_VERSION) ". 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] [-wrue0] [-t tempfile|-] [-p perms] 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, perms); 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 || fflush(stdout) < 0) error(errno, "unable to write: %d", c); return r; } tinycdb-0.78build1/cdb.h0000664000000000000000000000770711753222162012012 0ustar /* cdb.h: public cdb include file * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #ifndef TINYCDB_VERSION #define TINYCDB_VERSION 0.78 #ifdef __cplusplus extern "C" { #endif 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 { int 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, int 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(int fd, const void *key, unsigned klen, unsigned *dlenp); int cdb_bread(int fd, void *buf, int len); /* cdb_make */ struct cdb_make { int cdb_fd; /* file descriptor */ /* private */ unsigned cdb_dpos; /* data position so far */ unsigned cdb_rcnt; /* record count so far */ unsigned char cdb_buf[4096]; /* write buffer */ unsigned char *cdb_bpos; /* current buf position */ struct cdb_rl *cdb_rec[256]; /* list of arrays of record infos */ }; enum cdb_put_mode { CDB_PUT_ADD = 0, /* add unconditionnaly, like cdb_make_add() */ #define CDB_PUT_ADD CDB_PUT_ADD CDB_FIND = CDB_PUT_ADD, CDB_PUT_REPLACE, /* replace: do not place to index OLD record */ #define CDB_PUT_REPLACE CDB_PUT_REPLACE CDB_FIND_REMOVE = CDB_PUT_REPLACE, CDB_PUT_INSERT, /* add only if not already exists */ #define CDB_PUT_INSERT CDB_PUT_INSERT CDB_PUT_WARN, /* add unconditionally but ret. 1 if exists */ #define CDB_PUT_WARN CDB_PUT_WARN CDB_PUT_REPLACE0, /* if a record exists, fill old one with zeros */ #define CDB_PUT_REPLACE0 CDB_PUT_REPLACE0 CDB_FIND_FILL0 = CDB_PUT_REPLACE0 }; int cdb_make_start(struct cdb_make *cdbmp, int 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_find(struct cdb_make *cdbmp, const void *key, unsigned klen, enum cdb_put_mode mode); int cdb_make_put(struct cdb_make *cdbmp, const void *key, unsigned klen, const void *val, unsigned vlen, enum cdb_put_mode mode); int cdb_make_finish(struct cdb_make *cdbmp); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* include guard */ tinycdb-0.78build1/cdb_find.c0000664000000000000000000000431211753176654013010 0ustar /* cdb_find.c: cdb_find routine * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "cdb_int.h" 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 (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; } } tinycdb-0.78build1/cdb_findnext.c0000664000000000000000000000374511753176665013722 0ustar /* cdb_findnext.c: 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 "cdb_int.h" 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 (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; } tinycdb-0.78build1/cdb_hash.c0000664000000000000000000000067411753176707013021 0ustar /* cdb_hash.c: cdb hashing routine * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "cdb.h" 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; } tinycdb-0.78build1/cdb_init.c0000664000000000000000000000505611753217477013040 0ustar /* cdb_init.c: 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 #ifdef _WIN32 # include #else # include # ifndef MAP_FAILED # define MAP_FAILED ((void*)-1) # endif #endif #include #include "cdb_int.h" int cdb_init(struct cdb *cdbp, int fd) { struct stat st; unsigned char *mem; unsigned fsize, dend; #ifdef _WIN32 HANDLE hFile, hMapping; #endif /* get file size */ if (fstat(fd, &st) < 0) return -1; /* trivial sanity check: at least toc should be here */ if (st.st_size < 2048) return errno = EPROTO, -1; fsize = st.st_size < 0xffffffffu ? st.st_size : 0xffffffffu; /* memory-map file */ #ifdef _WIN32 hFile = (HANDLE) _get_osfhandle(fd); if (hFile == (HANDLE) -1) return -1; hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (!hMapping) return -1; mem = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); CloseHandle(hMapping); if (!mem) return -1; #else mem = (unsigned char*)mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) return -1; #endif /* _WIN32 */ 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) { #ifdef _WIN32 UnmapViewOfFile((void*) cdbp->cdb_mem); #else munmap((void*)cdbp->cdb_mem, cdbp->cdb_fsize); #endif /* _WIN32 */ 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; memcpy(buf, data, len); return 0; } tinycdb-0.78build1/cdb_int.h0000664000000000000000000000163211753176730012664 0ustar /* cdb_int.h: internal cdb library declarations * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "cdb.h" #include #include #ifndef EPROTO # define EPROTO EINVAL #endif #ifndef internal_function # ifdef __GNUC__ # define internal_function __attribute__((visibility("hidden"))) # else # define internal_function # endif #endif struct cdb_rec { unsigned hval; unsigned rpos; }; struct cdb_rl { struct cdb_rl *next; unsigned cnt; struct cdb_rec rec[254]; }; int _cdb_make_write(struct cdb_make *cdbmp, const unsigned char *ptr, unsigned len); int _cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len); int _cdb_make_flush(struct cdb_make *cdbmp); int _cdb_make_add(struct cdb_make *cdbmp, unsigned hval, const void *key, unsigned klen, const void *val, unsigned vlen); tinycdb-0.78build1/cdb_make.c0000664000000000000000000001001411753176747013004 0ustar /* cdb_make.c: basic cdb creation routines * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include #include #include #include "cdb_int.h" 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, int fd) { memset(cdbmp, 0, sizeof(*cdbmp)); cdbmp->cdb_fd = fd; cdbmp->cdb_dpos = 2048; cdbmp->cdb_bpos = cdbmp->cdb_buf + 2048; return 0; } int internal_function _cdb_make_fullwrite(int fd, const unsigned char *buf, unsigned len) { while(len) { int l = write(fd, buf, len); if (l > 0) { len -= l; buf += l; } else if (l < 0 && errno != EINTR) return -1; } return 0; } int internal_function _cdb_make_flush(struct cdb_make *cdbmp) { unsigned len = cdbmp->cdb_bpos - cdbmp->cdb_buf; if (len) { if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, len) < 0) return -1; cdbmp->cdb_bpos = cdbmp->cdb_buf; } return 0; } int internal_function _cdb_make_write(struct cdb_make *cdbmp, const unsigned char *ptr, unsigned len) { unsigned l = sizeof(cdbmp->cdb_buf) - (cdbmp->cdb_bpos - cdbmp->cdb_buf); cdbmp->cdb_dpos += len; if (len > l) { memcpy(cdbmp->cdb_bpos, ptr, l); cdbmp->cdb_bpos += l; if (_cdb_make_flush(cdbmp) < 0) return -1; ptr += l; len -= l; l = len / sizeof(cdbmp->cdb_buf); if (l) { l *= sizeof(cdbmp->cdb_buf); if (_cdb_make_fullwrite(cdbmp->cdb_fd, ptr, l) < 0) return -1; ptr += l; len -= l; } } if (len) { 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*)malloc((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, p, len << 3) < 0) { free(p); return -1; } } free(p); if (_cdb_make_flush(cdbmp) < 0) return -1; p = cdbmp->cdb_buf; for (t = 0; t < 256; ++t) { cdb_pack(hpos[t], p + (t << 3)); cdb_pack(hcnt[t], p + (t << 3) + 4); } if (lseek(cdbmp->cdb_fd, 0, 0) != 0 || _cdb_make_fullwrite(cdbmp->cdb_fd, 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; free(tm); } } } int cdb_make_finish(struct cdb_make *cdbmp) { int r = cdb_make_finish_internal(cdbmp); cdb_make_free(cdbmp); return r; } tinycdb-0.78build1/cdb_make_add.c0000664000000000000000000000256311753176740013617 0ustar /* cdb_make_add.c: basic cdb_make_add routine * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include /* for malloc */ #include "cdb_int.h" int internal_function _cdb_make_add(struct cdb_make *cdbmp, unsigned hval, const void *key, unsigned klen, const void *val, unsigned vlen) { unsigned char rlen[8]; struct cdb_rl *rl; unsigned i; if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) || vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8)) return errno = ENOMEM, -1; i = hval & 255; rl = cdbmp->cdb_rec[i]; if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) { rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl)); if (!rl) return errno = ENOMEM, -1; rl->cnt = 0; rl->next = cdbmp->cdb_rec[i]; cdbmp->cdb_rec[i] = rl; } i = rl->cnt++; rl->rec[i].hval = hval; rl->rec[i].rpos = cdbmp->cdb_dpos; ++cdbmp->cdb_rcnt; cdb_pack(klen, rlen); cdb_pack(vlen, rlen + 4); if (_cdb_make_write(cdbmp, rlen, 8) < 0 || _cdb_make_write(cdbmp, key, klen) < 0 || _cdb_make_write(cdbmp, val, vlen) < 0) return -1; return 0; } int cdb_make_add(struct cdb_make *cdbmp, const void *key, unsigned klen, const void *val, unsigned vlen) { return _cdb_make_add(cdbmp, cdb_hash(key, klen), key, klen, val, vlen); } tinycdb-0.78build1/cdb_make_put.c0000664000000000000000000001173411753176763013704 0ustar /* cdb_make_put.c: "advanced" cdb_make_put routine * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include #include #include #include "cdb_int.h" static void fixup_rpos(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) { unsigned i; struct cdb_rl *rl; register struct cdb_rec *rp, *rs; for (i = 0; i < 256; ++i) { for (rl = cdbmp->cdb_rec[i]; rl; rl = rl->next) for (rs = rl->rec, rp = rs + rl->cnt; --rp >= rs;) if (rp->rpos <= rpos) goto nexthash; else rp->rpos -= rlen; nexthash:; } } static int remove_record(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) { unsigned pos, len; int r, fd; len = cdbmp->cdb_dpos - rpos - rlen; cdbmp->cdb_dpos -= rlen; if (!len) return 0; /* it was the last record, nothing to do */ pos = rpos; fd = cdbmp->cdb_fd; do { r = len > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : len; if (lseek(fd, pos + rlen, SEEK_SET) < 0 || (r = read(fd, cdbmp->cdb_buf, r)) <= 0) return -1; if (lseek(fd, pos, SEEK_SET) < 0 || _cdb_make_fullwrite(fd, cdbmp->cdb_buf, r) < 0) return -1; pos += r; len -= r; } while(len); assert(cdbmp->cdb_dpos == pos); fixup_rpos(cdbmp, rpos, rlen); return 0; } static int zerofill_record(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) { if (rpos + rlen == cdbmp->cdb_dpos) { cdbmp->cdb_dpos = rpos; return 0; } if (lseek(cdbmp->cdb_fd, rpos, SEEK_SET) < 0) return -1; memset(cdbmp->cdb_buf, 0, sizeof(cdbmp->cdb_buf)); cdb_pack(rlen - 8, cdbmp->cdb_buf + 4); for(;;) { rpos = rlen > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : rlen; if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, rpos) < 0) return -1; rlen -= rpos; if (!rlen) return 0; memset(cdbmp->cdb_buf + 4, 0, 4); } } /* return: 0 = not found, 1 = error, or record length */ static unsigned match(struct cdb_make *cdbmp, unsigned pos, const char *key, unsigned klen) { int len; unsigned rlen; if (lseek(cdbmp->cdb_fd, pos, SEEK_SET) < 0) return 1; if (read(cdbmp->cdb_fd, cdbmp->cdb_buf, 8) != 8) return 1; if (cdb_unpack(cdbmp->cdb_buf) != klen) return 0; /* record length; check its validity */ rlen = cdb_unpack(cdbmp->cdb_buf + 4); if (rlen > cdbmp->cdb_dpos - pos - klen - 8) return errno = EPROTO, 1; /* someone changed our file? */ rlen += klen + 8; while(klen) { len = klen > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : klen; len = read(cdbmp->cdb_fd, cdbmp->cdb_buf, len); if (len <= 0) return 1; if (memcmp(cdbmp->cdb_buf, key, len) != 0) return 0; key += len; klen -= len; } return rlen; } static int findrec(struct cdb_make *cdbmp, const void *key, unsigned klen, unsigned hval, enum cdb_put_mode mode) { struct cdb_rl *rl; struct cdb_rec *rp, *rs; unsigned r; int seeked = 0; int ret = 0; for(rl = cdbmp->cdb_rec[hval&255]; rl; rl = rl->next) for(rs = rl->rec, rp = rs + rl->cnt; --rp >= rs;) { if (rp->hval != hval) continue; /*XXX this explicit flush may be unnecessary having * smarter match() that looks into cdb_buf too, but * most of a time here spent in finding hash values * (above), not keys */ if (!seeked && _cdb_make_flush(cdbmp) < 0) return -1; seeked = 1; r = match(cdbmp, rp->rpos, key, klen); if (!r) continue; if (r == 1) return -1; ret = 1; switch(mode) { case CDB_FIND_REMOVE: if (remove_record(cdbmp, rp->rpos, r) < 0) return -1; break; case CDB_FIND_FILL0: if (zerofill_record(cdbmp, rp->rpos, r) < 0) return -1; break; default: goto finish; } memmove(rp, rp + 1, (rs + rl->cnt - 1 - rp) * sizeof(*rp)); --rl->cnt; --cdbmp->cdb_rcnt; } finish: if (seeked && lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0) return -1; return ret; } int cdb_make_find(struct cdb_make *cdbmp, const void *key, unsigned klen, enum cdb_put_mode mode) { return findrec(cdbmp, key, klen, cdb_hash(key, klen), mode); } int cdb_make_exists(struct cdb_make *cdbmp, const void *key, unsigned klen) { return cdb_make_find(cdbmp, key, klen, CDB_FIND); } int cdb_make_put(struct cdb_make *cdbmp, const void *key, unsigned klen, const void *val, unsigned vlen, enum cdb_put_mode mode) { unsigned hval = cdb_hash(key, klen); int r; switch(mode) { case CDB_PUT_REPLACE: case CDB_PUT_INSERT: case CDB_PUT_WARN: case CDB_PUT_REPLACE0: r = findrec(cdbmp, key, klen, hval, mode); if (r < 0) return -1; if (r && mode == CDB_PUT_INSERT) return errno = EEXIST, 1; break; case CDB_PUT_ADD: r = 0; break; default: return errno = EINVAL, -1; } if (_cdb_make_add(cdbmp, hval, key, klen, val, vlen) < 0) return -1; return r; } tinycdb-0.78build1/cdb_seek.c0000664000000000000000000000515611753176774013031 0ustar /* cdb_seek.c: old interface for reading cdb file * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include #include "cdb_int.h" #ifndef SEEK_SET # define SEEK_SET 0 #endif /* read a chunk from file, ignoring interrupts (EINTR) */ int cdb_bread(int fd, void *buf, int len) { int l; while(len > 0) { do l = read(fd, buf, len); 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(int 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 (lseek(fd, pos, SEEK_SET) < 0 || 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 && lseek(fd, htstart + (hti << 3), SEEK_SET) < 0) 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 (lseek(fd, pos, SEEK_SET) < 0 || 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 (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; } } } tinycdb-0.78build1/cdb_seq.c0000664000000000000000000000127511753177004012653 0ustar /* cdb_seq.c: sequential record retrieval routines * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "cdb_int.h" 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; } tinycdb-0.78build1/cdb_unpack.c0000664000000000000000000000047611753177022013346 0ustar /* cdb_unpack.c: unpack 32bit integer * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "cdb.h" 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; } tinycdb-0.78build1/debian/0000775000000000000000000000000013076471054012326 5ustar tinycdb-0.78build1/debian/changelog0000664000000000000000000002065013076471054014203 0ustar tinycdb (0.78build1) artful; urgency=medium * No-change rebuild to pick up -fPIE compiler default in static libraries -- Steve Langasek Fri, 21 Apr 2017 20:57:16 +0000 tinycdb (0.78) unstable; urgency=low * new release (0.78), a few minor fixes: - fix handling of files >4Gb - fix handling of files >2Gb on 32bit platforms (compile with _FILE_OFFSET_BITS=64) - fix file size limit test - fix compiler warnings (missing #include) * make it multiarch-aware (install libs to /usr/lib/$arch) * use dpkg-buildflags for CFLAGS/LDFLAGS * update Standards-Version to 3.9.3 * debhelper 7 * simplify debian/rules quite a bit -- Michael Tokarev Fri, 11 May 2012 16:33:34 +0400 tinycdb (0.77) unstable; urgency=low * manpage typo fixes. * in win32, close file mapping handle right after MapViewOfFile(), instead of doing it in cdb_close(). This eliminates handle leak on win32 platform. And this is how mmap() works on unix, too. Thanks to David Boyce for this. * also for win32 platform, cdb.c (the utility): - open cdb files in binary mode - add windowsisms for include files Also thanks to David Boyce for the fixes. * fixed a bug in _cdb_make_fullwrite() - wrong logic in EINTR handling. Thanks to Florian Weimer. Closes: #511629. * install /usr/lib/pkgconfig/libcdb.pc from debian/rules. Closes: #446751, #446752. * lintian warnings: o moved $DH_COMPAT to deban/compat (=4) o set Standards-Version: 3.8.0 (no changes needed) o fixed "package package" in libcdb1 description (Closes: #442571) o s/${Source-Version}/${binary:Version}/ * released 0.77 -- Michael Tokarev Sat, 31 Jan 2009 20:12:02 +0300 tinycdb (0.76) unstable; urgency=low * 0.76 release. Closes: #342849, #316253, #360129, #383417. Also closes: #299026, #344572. * manpage spelling fixes, from Claus Assmann . * little mods to allow compiling tinycdb by C++ compiler, from Olly Betts . * use program_invocation_short_name on GLIBC, (modified) patch from Dmitry V. Levin * manpage fix (cdb_findnext() prototype), from Dmitry V. Levin * (somewhat silly) GCC-4.x "signedness" warnings fix, modified patch from Dmitry V. Levin * more signed vs unsigned char* fixes in various places * Makefile: always build libnss_cdb.so with libcdb_pic.a, no nss-shared target: to avoid extra dependency from /usr/lib/. * Makefile: use map files for lib*.so, with explicit list of exported symbols. This, in particular, avoids exporting of libcdb symbols by libnss_cdb.so. * mark all internal routines as internal_function (defined as __attribute__((visibility("hidden"))) for GCC) * Makefile: add tests-shared, to use cdb-shared for testing * Makefile: allow to specify which binary (shared vs static) to install in install target, by using INSTALLPROG variable * Makefile: pass -DNSSCDB_DIR=... to compiler when building .lo files, to allow setting of system config dir (/etc by default) on command line. For nss_cdb module. * Makefile: use $(CP) instead of cp, to be able to specify `cp' options (CP="cp -p") * Makefile: ship debian/ files in `dist' target as well, if not only for debian/changelog. * Makefile: bumped version to 0.76 * Use unlink(tmpname) + open(O_CREAT|O_EXCL) instead of open(O_CREAT|O_TRUNC) when creating the new CDB file. And use O_NOFOLLOW if defined. This also works around some (probably) possible symlink attacks. * Add -p perms option for cdb utility, to specify mode (permission bits) for newly created .cdb file (default is 0666&umask(), -p forces the given mode). * allow tmpname (cdb -t) to be `-', to mean no temp file gets created. Also check if tmpname is the same as database name and don't try to rename() if it is. * rewrite nss_cdb-Makefile a bit: simplify it, and use more sane permission scheme for /etc/shadow * bumped Debian Standards-Version to 3.7.2 (no changes necessary). * fixed a typo in cdb_seek.c, -- it segfaulted if passed NULL dlenp pointer. Thanks Daiki for the patch. Closes: #383417 * use MAP_FAILED to test mmap() return value, instead of hardcoded -1. * several minor fixes for debian/* files, thanks to Bernhard R. Link. * removed libnss_cdb Debian package, for now * libcdb-dev replaces tinycdb<0.76 -- Michael Tokarev Sat, 9 Sep 2006 13:55:10 +0400 tinycdb (0.75) unstable; urgency=low * 0.75 release * debian packaging is now back to me. Thank you Christian for doing packaging work for me, it is greatly apprecated. * build 4 packages out of the source base: - shared library libcdb1 - development files libcdb-dev - utility tinycdb - nss module nss-cdb Closes: Debian #360129, #316253. * rewrote cdb_make_put(CDB_PUT_REPLACE) to a) actually replace *all* duplicates, not just the first one, and b) perform real replace, by moving tail of .cdb file. Also, always add new record to the end of the file, not to the place where a duplicate was found. * add cdb_make_put(CDB_PUT_REPLACE0) to zerofill all duplicates, which is faster than CDB_PUT_REPLACE but less accurate as it leaves gaps in the file. * ship libcdb_pic.a in the -dev package. -- Michael Tokarev Tue, 23 Aug 2005 20:06:01 +0400 tinycdb (0.74-1) unstable; urgency=low * New upstream release. -- Christian Kurz Wed, 28 Jul 2004 20:12:02 +0200 tinycdb (0.73-1) unstable; urgency=low * First Debian release, based on the debian directory that Michael Tokarev, the upstream author, had provided in the package itself. So only some minor changes were necessary. -- Christian Kurz Tue, 5 Nov 2002 10:36:59 +0100 tinycdb (0.72) unstable; urgency=low * cleaned up debian packaging and made it actually work * no code changes -- Michael Tokarev Sun, 13 Oct 2002 03:00:32 +0400 tinycdb (0.71) unstable; urgency=low * 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 -- Michael Tokarev Mon, 22 Jul 2002 13:35:14 +0400 tinycdb (0.7a) unstable; urgency=low * converted into CVS, added two missing #include for malloc declaration and spec target to the Makefile -- Michael Tokarev Mon, 10 Dec 2001 00:21:17 +0300 tinycdb (0.7) unstable; urgency=low * added cdb_seek() and cdb_bread() routines as found in freecdb/cdb-0.64 -- Michael Tokarev Sun, 14 Oct 2001 19:29:33 +0400 tinycdb (0.6) unstable; urgency=low * 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. -- Michael Tokarev Thu, 26 Jul 2001 02:38:08 +0400 tinycdb (0.5) unstable; urgency=low * added missing #include 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 * autogenerate tinycdb.spec file from template and debian/changelog * autogenerate cdb.h from cdb.h.in (substituting version) -- Michael Tokarev Wed, 25 Jul 2001 17:16:39 +0400 tinycdb (0.4) unstable; urgency=low * 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) -- Michael Tokarev Fri, 29 Jun 2001 23:39:53 +0400 tinycdb (0.3) unstable; urgency=low * Initial Release. -- Michael Tokarev Sun, 27 May 2001 16:38:58 +0400 tinycdb-0.78build1/debian/compat0000664000000000000000000000000211753222427013522 0ustar 7 tinycdb-0.78build1/debian/control0000664000000000000000000000271011753223433013725 0ustar Source: tinycdb Section: utils Priority: optional Maintainer: Michael Tokarev Build-Depends: debhelper (>= 7) Standards-Version: 3.9.3 Package: tinycdb Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: an utility to manipulate constant databases (cdb) tinycdb is a small, fast and reliable utility and subroutine library for creating and reading constant databases. The database structure is tuned for fast reading. . This package contains a command-line utility to create, analyze, dump and query cdb files. Package: libcdb1 Architecture: any Section: libs Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Multi-Arch: same Description: shared library for constant databases (cdb) tinycdb is a small, fast and reliable utility and subroutine library for creating and reading constant databases. The database structure is tuned for fast reading. . This package provides a shared library needed to run programs using it. Package: libcdb-dev Architecture: any Section: libdevel Depends: libcdb1 (= ${binary:Version}), ${misc:Depends} Recommends: tinycdb Replaces: tinycdb (<< 0.75) Description: development files for constant databases (cdb) tinycdb is a small, fast and reliable utility and subroutine library for creating and reading constant databases. The database structure is tuned for fast reading. . This package provides development files needed to build programs using cdb library. tinycdb-0.78build1/debian/control.nss0000664000000000000000000000103711753175776014550 0ustar Package: libnss-cdb Architecture: any Section: libs Depends: ${shlibs:Depends}, tinycdb Description: cdb-based nss (name service switch) module tinycdb is a small, fast and reliable utility and subroutine library for creating and reading constant databases. The database structure is tuned for fast reading. . This package provides a name service switch (nsswitch) module to use to index /etc/password files for fast access. This module works only for passwd, group and shadow databases, not for hosts, networks, services and others. tinycdb-0.78build1/debian/copyright0000664000000000000000000000030311753175776014271 0ustar This software was written by Michael Tokarev , based on ideas by Dan Bernstein. It is in the public domain. Source code and home page is at http://www.corpit.ru/mjt/tinycdb.html tinycdb-0.78build1/debian/libcdb.pc0000664000000000000000000000027511753222427014073 0ustar # Package Information for pkg-config # Not much here, all stuff is in standard places Name: libcdb Description: tinycdb - Constant Data Base library Version: @VERSION@ Libs: -lcdb Cflags: tinycdb-0.78build1/debian/rules0000775000000000000000000000322611753223606013407 0ustar #!/usr/bin/make -f # -*- makefile -*- LIBDIR = /usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH) CFLAGS = $(shell dpkg-buildflags --get CFLAGS) \ $(shell dpkg-buildflags --get CPPFLAGS) \ -Wall -W LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS) SOVER = 1 configure: # nothing dh_testdir build-arch: libcdb.pc libcdb.pc: dh_testdir $(MAKE) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \ staticlib sharedlib cdb-shared nss cp -pf nss_cdb-Makefile cdb-Makefile cp -pf cdb-shared cdb sed 's/@VERSION@/$(shell sed -n 's/^VERSION *= *//p' Makefile)/' debian/libcdb.pc > $@ clean: dh_testdir rm -f cdb-Makefile libcdb.pc $(MAKE) distclean dh_clean build-indep: build: build-arch install: build dh_testdir dh_testroot dh_clean dh_installdocs -A NEWS # libcdb$(SOVER) dh_install -plibcdb$(SOVER) libcdb.so.$(SOVER) $(LIBDIR) # libcdb-dev dh_install -plibcdb-dev libcdb.a libcdb_pic.a libcdb.so $(LIBDIR) dh_install -plibcdb-dev cdb.h usr/include dh_install -plibcdb-dev libcdb.pc $(LIBDIR)/pkgconfig dh_installman -plibcdb-dev cdb.3 # dh_installdocs -plibcdb-dev TODO # tinycdb dh_install -ptinycdb cdb usr/bin dh_installman -ptinycdb cdb.1 cdb.5 # libnss-cdb # dh_install -plibnss-cdb cdb-Makefile etc # dh_install -plibnss-cdb libnss_cdb.so.2 lib binary-indep: binary-arch: build-arch install dh_testdir dh_testroot dh_installchangelogs dh_installdocs dh_strip dh_compress dh_fixperms dh_makeshlibs dh_installdeb dh_shlibdeps -L libcdb$(SOVER) -l debian/libcdb$(SOVER)$(LIBDIR) dh_gencontrol dh_md5sums dh_builddeb binary: binary-arch .PHONY: clean configure install .PHONY: build build-indep build-arch binary binary-indep binary-arch tinycdb-0.78build1/libcdb.map0000664000000000000000000000060711753177047013032 0ustar # libcdb.map: libcdb symbol map file for GNU LD { global: cdb_hash; cdb_unpack; cdb_pack; cdb_init; cdb_free; cdb_read; cdb_get; cdb_find; cdb_findinit; cdb_findnext; cdb_seqnext; cdb_seek; cdb_bread; cdb_make_start; cdb_make_add; cdb_make_exists; cdb_make_put; cdb_make_find; cdb_make_finish; local: *; }; tinycdb-0.78build1/nss_cdb-Makefile0000775000000000000000000000237611753177167014200 0ustar # nss_cdb-Makefile: Makefile to create cdb-indexed files # for nss_cdb module from /etc/group, /etc/passwd, /etc/shadow. # # This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. # Public domain. AWK = awk SRC = . DST = . all: $(DST)/passwd.cdb $(DST)/group.cdb $(DST)/shadow.cdb $(DST)/passwd.cdb: $(SRC)/passwd umask 022; $(AWK) -F: '\ /^#/ { next } \ NF == 7 { print $$1" "$$0; print ":"$$3" "$$1 } \ ' $(SRC)/passwd > $@.in cdb -c -m $@ $@.in rm -f $@.in $(DST)/group.cdb: $(SRC)/group umask 022; $(AWK) -F: '\ /^#/ { next } \ NF == 4 { print $$1" "$$0; print ":"$$3" "$$1 } \ ' $(SRC)/group > $@.in cdb -c -m $@ $@.in rm -f $@.in # for shadow, we first create all files with mode 0600, # and only when everything's done, right before final # rename (which is done explicitly), we change permissions # and ownership to the right values. Assuming parent dirs # have proper permissions (so no symlink attacks etc are # possible) $(DST)/shadow.cdb: $(SRC)/shadow set -e; \ umask 077; \ rm -f $@.in; \ $(AWK) -F: '\ /^#/ { next } \ NF == 9 { print $$1" "$$0 } \ ' $(SRC)/shadow > $@.in cdb -c -m -t $@.tmp -p 0600 $@.tmp2 $@.in rm -f $@.in chown --reference=$(SRC)/shadow $@.tmp2 chmod --reference=$(SRC)/shadow $@.tmp2 mv -f $@.tmp2 $@ tinycdb-0.78build1/nss_cdb-group.c0000664000000000000000000000366511753177123014027 0ustar /* nss_cdb-group.c: nss_cdb group database routines. * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "nss_cdb.h" #include #include #include nss_common(group, struct group, grent); nss_getbyname(getgrnam, struct group); nss_getbyid(getgrgid, struct group, gid_t); static char *getmember(char **bp) { char *b, *m; b = *bp; while(*b == ',') ++b; if (!*b) return NULL; m = b++; for(;;) { if (*b == ',') { *b++ = '\0'; *bp = b; return m; } else if (*b == '\0') { *bp = b; return m; } else ++b; } } static int nss_group_parse(struct group *result, char *buf, size_t bufl) { char *bufend; char **mem; int n; bufend = buf + strlen(buf) + 1; n = (unsigned)bufend % sizeof(char*); if (n) bufend += sizeof(char*) - n; result->gr_mem = mem = (char**)bufend; bufend = buf + bufl - sizeof(char*); STRING_FIELD(buf, result->gr_name); if (!result->gr_name[0]) return -1; STRING_FIELD(buf, result->gr_passwd); INT_FIELD(buf, result->gr_gid, (gid_t)); for(;;) { if ((char*)mem > bufend) return 0; if (!(*mem++ = getmember(&buf))) break; } return 1; } #ifdef TEST #include void printit(struct group *g) { char **mem; printf("name=%s pass=%s gid=%d mem:", g->gr_name, g->gr_passwd, g->gr_gid); mem = g->gr_mem; if (!mem) printf(" none"); else while(*mem) printf(" %s", *mem++); putchar('\n'); } int main(int argc, char **argv) { struct group gr, *g; char buf[36]; int err, r; while(*++argv) { r = _nss_cdb_getgrgid_r(atoi(*argv), &gr, buf, sizeof(buf), &err); if (r == NSS_STATUS_SUCCESS) printit(&gr); else printf("cdb(%s): %d %s\n", *argv, r, strerror(err)); g = getgrgid(atoi(*argv)); if (g) printit(g); else printf("grgid(%s): %m\n", *argv); } return 0; } #endif tinycdb-0.78build1/nss_cdb-passwd.c0000664000000000000000000000262611753177220014166 0ustar /* nss_cdb-passwd.c: nss_cdb passwd database routines. * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "nss_cdb.h" #include #include nss_common(passwd, struct passwd, pwent); nss_getbyname(getpwnam, struct passwd); nss_getbyid(getpwuid, struct passwd, uid_t); static int nss_passwd_parse(struct passwd *result, char *buf, size_t bufl) { STRING_FIELD(buf, result->pw_name); if (!result->pw_name[0]) return -1; STRING_FIELD(buf, result->pw_passwd); INT_FIELD(buf, result->pw_uid, (uid_t)); INT_FIELD(buf, result->pw_gid, (gid_t)); STRING_FIELD(buf, result->pw_gecos); STRING_FIELD(buf, result->pw_dir); result->pw_shell = buf; bufl = bufl; return 1; } #ifdef TEST #include static void printit(const struct passwd *p) { printf("name=`%s' pass=`%s' uid=%d gid=%d gecos=`%s' dir=`%s' shell=`%s'\n", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell); } int main(int argc, char **argv) { struct passwd pw, *p; char buf[1024]; int err, r; while(*++argv) { r = _nss_cdb_getpwuid_r(atoi(*argv), &pw, buf, sizeof(buf), &err); if (r == NSS_STATUS_SUCCESS) printit(&pw); else printf("cdb(%s): %d %s\n", *argv, r, strerror(err)); p = getpwuid(atoi(*argv)); if (p) printit(p); else printf("pwuid(%s): %m\n", *argv); } return 0; } #endif tinycdb-0.78build1/nss_cdb-spwd.c0000664000000000000000000000172411753177231013642 0ustar /* nss_cdb-spwd.c: nss_cdb shadow passwd database routines. * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "nss_cdb.h" #include nss_common(shadow, struct spwd, spent); nss_getbyname(getspnam, struct spwd); static int nss_shadow_parse(struct spwd *result, char *buf, size_t bufl) { STRING_FIELD(buf, result->sp_namp); if (!result->sp_namp[0]) return -1; STRING_FIELD(buf, result->sp_pwdp); INT_FIELD_MAYBE_NULL(buf, result->sp_lstchg, (long), -1); INT_FIELD_MAYBE_NULL(buf, result->sp_min, (long), -1); INT_FIELD_MAYBE_NULL(buf, result->sp_max, (long), -1); INT_FIELD_MAYBE_NULL(buf, result->sp_warn, (long), -1); INT_FIELD_MAYBE_NULL(buf, result->sp_inact, (long), -1); INT_FIELD_MAYBE_NULL(buf, result->sp_expire, (long), -1); if (*buf) { result->sp_flag = strtoul(buf, &buf, 10); if (*buf) return -1; } else result->sp_flag = ~0ul; bufl = bufl; return 1; } tinycdb-0.78build1/nss_cdb.c0000664000000000000000000001342111753177104012663 0ustar /* nss_cdb.c: nss_cdb common routines. * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include "nss_cdb.h" #include "cdb_int.h" /* for internal_function */ #include #include #include #include #include #if __GLIBC__ /* XXX this is in fact not a right condition */ /* XXX on glibc, this stuff works due to linker/libpthreads stubs/tricks. * On other libcs, it may require linking whole -lpthread, which is * not a good thing to do for nss module... */ #include #define lock_define(class,name) \ class pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER; #define lock_lock(name) pthread_mutex_lock(&(name)) #define lock_unlock(name) pthread_mutex_unlock(&(name)) #else /* !__GNU_LIBRARY__ */ # define lock_define_initialized(class,name) # define lock_lock(name) # define lock_unlock(name) #endif /* __GNU_LIBRARY__ */ lock_define(static, lock) /* General principle: we skip invalid/unparseable entries completely, * as if there was no such entry at all (returning NOTFOUND). * In case of data read error (e.g. invalid .cdb structure), we * return UNAVAIL. */ #define isopen(dbp) ((dbp)->lastpos) static int __nss_cdb_dosetent(struct nss_cdb *dbp) { int fd; fd = open(dbp->dbname, O_RDONLY); if (fd < 0) return 0; if (cdb_init(&dbp->cdb, fd) != 0) { close(fd); return 0; } close(fd); dbp->lastpos = 2048; /* cdb_seqinit() */ return 1; } static void __nss_cdb_doendent(struct nss_cdb *dbp) { cdb_free(&dbp->cdb); dbp->lastpos = 0; dbp->keepopen = 0; } enum nss_status internal_function __nss_cdb_setent(struct nss_cdb *dbp, int stayopen) { enum nss_status r; lock_lock(lock); if (isopen(dbp) || __nss_cdb_dosetent(dbp)) r = NSS_STATUS_SUCCESS, dbp->keepopen |= stayopen; else r = NSS_STATUS_UNAVAIL; lock_unlock(lock); return r; } enum nss_status internal_function __nss_cdb_endent(struct nss_cdb *dbp) { lock_lock(lock); if (isopen(dbp)) __nss_cdb_doendent(dbp); lock_unlock(lock); return NSS_STATUS_SUCCESS; } static enum nss_status __nss_cdb_dobyname(struct nss_cdb *dbp, const char *key, unsigned len, void *result, char *buf, size_t bufl, int *errnop) { int r; if ((r = cdb_find(&dbp->cdb, key, len)) < 0) return *errnop = errno, NSS_STATUS_UNAVAIL; len = cdb_datalen(&dbp->cdb); if (!r || len < 2) return *errnop = ENOENT, NSS_STATUS_NOTFOUND; if (len >= bufl) return *errnop = ERANGE, NSS_STATUS_TRYAGAIN; if (cdb_read(&dbp->cdb, buf, len, cdb_datapos(&dbp->cdb)) != 0) return *errnop = errno, NSS_STATUS_UNAVAIL; buf[len] = '\0'; if ((r = dbp->parsefn(result, buf, bufl)) < 0) return *errnop = ENOENT, NSS_STATUS_NOTFOUND; if (!r) return *errnop = ERANGE, NSS_STATUS_TRYAGAIN; return NSS_STATUS_SUCCESS; } enum nss_status internal_function __nss_cdb_byname(struct nss_cdb *dbp, const char *name, void *result, char *buf, size_t bufl, int *errnop) { enum nss_status r; if (*name == ':') return *errnop = ENOENT, NSS_STATUS_NOTFOUND; lock_lock(lock); if (!isopen(dbp) && !__nss_cdb_dosetent(dbp)) *errnop = errno, r = NSS_STATUS_UNAVAIL; else { r = __nss_cdb_dobyname(dbp, name, strlen(name), result, buf, bufl, errnop); if (!dbp->keepopen) __nss_cdb_doendent(dbp); } lock_unlock(lock); return r; } static enum nss_status __nss_cdb_dobyid(struct nss_cdb *dbp, unsigned long id, void *result, char *buf, size_t bufl, int *errnop) { int r; unsigned len; const char *data; if ((r = cdb_find(&dbp->cdb, buf, sprintf(buf, ":%lu", id))) < 0) return *errnop = errno, NSS_STATUS_UNAVAIL; len = cdb_datalen(&dbp->cdb); if (!r || len < 2) return *errnop = ENOENT, NSS_STATUS_NOTFOUND; if (!(data = (const char*)cdb_get(&dbp->cdb, len, cdb_datapos(&dbp->cdb)))) return *errnop = errno, NSS_STATUS_UNAVAIL; return __nss_cdb_dobyname(dbp, data, len, result, buf, bufl, errnop); } enum nss_status internal_function __nss_cdb_byid(struct nss_cdb *dbp, unsigned long id, void *result, char *buf, size_t bufl, int *errnop) { enum nss_status r; if (bufl < 30) return *errnop = ERANGE, NSS_STATUS_TRYAGAIN; lock_lock(lock); if (!isopen(dbp) && !__nss_cdb_dosetent(dbp)) *errnop = errno, r = NSS_STATUS_UNAVAIL; else { r = __nss_cdb_dobyid(dbp, id, result, buf, bufl, errnop); if (!dbp->keepopen) __nss_cdb_doendent(dbp); } lock_unlock(lock); return r; } static enum nss_status __nss_cdb_dogetent(struct nss_cdb *dbp, void *result, char *buf, size_t bufl, int *errnop) { int r; unsigned lastpos; if (!isopen(dbp) && !__nss_cdb_dosetent(dbp)) return *errnop = errno, NSS_STATUS_UNAVAIL; while((lastpos = dbp->lastpos, r = cdb_seqnext(&dbp->lastpos, &dbp->cdb)) > 0) { if (cdb_keylen(&dbp->cdb) < 2) continue; if (((const char *)cdb_getkey(&dbp->cdb))[0] == ':') /* can't fail */ continue; if (cdb_datalen(&dbp->cdb) >= bufl) return dbp->lastpos = lastpos, *errnop = ERANGE, NSS_STATUS_TRYAGAIN; cdb_readdata(&dbp->cdb, buf); buf[cdb_datalen(&dbp->cdb)] = '\0'; if ((r = dbp->parsefn(result, buf, bufl)) == 0) return dbp->lastpos = lastpos, *errnop = ERANGE, NSS_STATUS_TRYAGAIN; if (r > 0) return NSS_STATUS_SUCCESS; } if (r < 0) return *errnop = errno, NSS_STATUS_UNAVAIL; else return *errnop = ENOENT, NSS_STATUS_NOTFOUND; } enum nss_status internal_function __nss_cdb_getent(struct nss_cdb *dbp, void *result, char *buf, size_t bufl, int *errnop) { enum nss_status r; if (bufl < 30) return *errnop = ERANGE, NSS_STATUS_TRYAGAIN; lock_lock(lock); dbp->keepopen |= 1; r = __nss_cdb_dogetent(dbp, result, buf, bufl, errnop); lock_unlock(lock); return r; } tinycdb-0.78build1/nss_cdb.h0000664000000000000000000000534611753177134012702 0ustar /* nss_cdb.h: nss_cdb common include file. * * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. * Public domain. */ #include #include #include #include "cdb.h" #ifndef NSSCDB_DIR # define NSSCDB_DIR "/etc" #endif #ifndef NSSCDB_DB # define NSSCDB_DB(name) NSSCDB_DIR "/" name ".cdb" #endif typedef int (nss_parse_fn)(void *result, char *buf, size_t bufl); struct nss_cdb { nss_parse_fn *parsefn; const char *dbname; int keepopen; unsigned lastpos; struct cdb cdb; }; enum nss_status __nss_cdb_setent(struct nss_cdb *dbp, int stayopen); enum nss_status __nss_cdb_endent(struct nss_cdb *dbp); enum nss_status __nss_cdb_getent(struct nss_cdb *dbp, void *result, char *buf, size_t bufl, int *errnop); enum nss_status __nss_cdb_byname(struct nss_cdb *dbp, const char *name, void *result, char *buf, size_t bufl, int *errnop); enum nss_status __nss_cdb_byid(struct nss_cdb *dbp, unsigned long id, void *result, char *buf, size_t bufl, int *errnop); #define nss_common(dbname,structname,entname) \ static int \ nss_##dbname##_parse(structname *result, char *buf, size_t bufl); \ static struct nss_cdb db = { \ (nss_parse_fn*)&nss_##dbname##_parse, \ NSSCDB_DB(#dbname),0,0,CDB_STATIC_INIT}; \ enum nss_status _nss_cdb_set##entname(int stayopen) { \ return __nss_cdb_setent(&db, stayopen); \ } \ enum nss_status _nss_cdb_end##entname(void) { \ return __nss_cdb_endent(&db); \ } \ enum nss_status \ _nss_cdb_get##entname##_r(structname *result, \ char *buf, size_t bufl, int *errnop) { \ return __nss_cdb_getent(&db, result, buf, bufl, errnop); \ } #define nss_getbyname(getbyname, structname) \ enum nss_status \ _nss_cdb_##getbyname##_r(const char *name, structname *result, \ char *buf, size_t bufl, int *errnop) { \ return __nss_cdb_byname(&db, name, result, buf, bufl, errnop); \ } #define nss_getbyid(getbyid, structname, idtype) \ enum nss_status \ _nss_cdb_##getbyid##_r(idtype id, structname *result, \ char *buf, size_t bufl, int *errnop) { \ return __nss_cdb_byid(&db, id, result, buf, bufl, errnop); \ } #define STRING_FIELD(line, variable) \ variable = line; \ while(*line != ':') \ if (!*line++) return -1; \ *line++ = '\0' #define INT_FIELD(line, variable, convert) \ { \ char *endp; \ variable = convert(strtoul(line, &endp, 10)); \ if (endp == line) return -1; \ if (*endp++ != ':') return -1; \ line = endp; \ } #define INT_FIELD_MAYBE_NULL(line, variable, convert, default) \ { \ char *endp; \ if (!*line) return -1; \ variable = convert(strtoul(line, &endp, 10)); \ if (*endp != ':') return -1; \ if (endp == line) variable = convert(default); \ line = endp; \ } tinycdb-0.78build1/nss_cdb.map0000664000000000000000000000063011753177202013213 0ustar # nss_cdb.map: libnss_cdb symbol map file for GNU LD { global: _nss_cdb_endpwent; _nss_cdb_getpwnam_r; _nss_cdb_endspent; _nss_cdb_getspent_r; _nss_cdb_getpwent_r; _nss_cdb_getgrgid_r; _nss_cdb_endgrent; _nss_cdb_getgrent_r; _nss_cdb_setspent; _nss_cdb_setpwent; _nss_cdb_getpwuid_r; _nss_cdb_getspnam_r; _nss_cdb_setgrent; _nss_cdb_getgrnam_r; local: *; }; tinycdb-0.78build1/tests.ok0000664000000000000000000000302511753175776012615 0ustar Create simple db 0 checksum may fail if no md5sum program 97549c2e76e2d446430a392d77ed1bcb Dump simple db +3,4:one->here +1,1:a->b +1,3:b->abc +3,4:one->also 0 Stats for simple db number of records: 4 key min/avg/max length: 1/2/3 val min/avg/max length: 1/3/4 hash tables/entries/collisions: 3/8/1 hash table min/avg/max length: 2/3/4 hash table distances: d0: 3 75% d1: 1 25% d2: 0 0% d3: 0 0% d4: 0 0% d5: 0 0% d6: 0 0% d7: 0 0% d8: 0 0% d9: 0 0% >9: 0 0% 0 Query simple db (two records match) herealso 0 Query for non-existed key 100 Doing 600 repeated records 0 checksum may fail if no md5sum program 412a0b7578efca528bf8398c8811caf4 cdb stats should show 601 record number of records: 601 key min/avg/max length: 1/1/1 val min/avg/max length: 3/3/5 hash tables/entries/collisions: 2/1202/599 hash table min/avg/max length: 2/601/1200 hash table distances: d0: 2 0% d1: 1 0% d2: 1 0% d3: 1 0% d4: 1 0% d5: 1 0% d6: 1 0% d7: 1 0% d8: 1 0% d9: 1 0% >9: 590 98% 0 Querying key other 0 Dumping and re-creating db 0 0 Handling large key size cdb: (stdin): bad format 2 Handling large value size cdb: (stdin): bad format 2 Handling invalid input format (short file) cdb: unable to read: short file 2 Creating db with eol in key and value 0 checksum may fail if no md5sum program 1d444fe759c26d36f500d01c41cfda40 Querying key-value with eol b 0 Handling file size limits cdb: cdb_make_put: File too large 111 tinycdb-0.78build1/tests.sh0000775000000000000000000000457511753217476012626 0ustar #! /bin/sh # tests.sh: This script will run tests for cdb. # Execute with ./tests.sh ./cdb # (first arg if present gives path to cdb tool to use, default is `cdb'). # # This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. # Public domain. case "$1" in "") cdb=cdb ;; *) cdb="$1" ;; esac do_csum() { echo checksum may fail if no md5sum program md5sum $1 | sed -e 's|[ ].*||' -e 'y|[ABCDEF]|[abcdef]|' } rm -f 1.cdb 1a.cdb echo Create simple db echo "+3,4:one->here +1,1:a->b +1,3:b->abc +3,4:one->also " | $cdb -c 1.cdb echo $? do_csum 1.cdb echo Dump simple db $cdb -d 1.cdb echo $? echo Stats for simple db $cdb -s 1.cdb echo $? echo "Query simple db (two records match)" $cdb -q 1.cdb one echo " $?" echo Query for non-existed key $cdb -q 1.cdb none echo $? echo Doing 600 repeated records ( for i in 0 1 2 3 4 5 ; do for j in 0 1 2 3 4 5 6 7 8 9 ; do for k in 0 1 2 3 4 5 6 7 8 9 ; do echo "+1,3:a->$i$j$k" done done done echo "+1,5:b->other" echo ) | $cdb -c 1.cdb echo $? do_csum 1.cdb echo cdb stats should show 601 record $cdb -s 1.cdb echo $? echo Querying key $cdb -q 1.cdb b echo " "$? echo Dumping and re-creating db $cdb -d 1.cdb | $cdb -c 1a.cdb echo $? cmp 1.cdb 1a.cdb $cdb -d -m 1.cdb | $cdb -c -m 1a.cdb echo $? cmp 1.cdb 1a.cdb echo Handling large key size echo "+123456789012,1:" | $cdb -c 1.cdb echo $? echo Handling large value size echo "+1,123456789012:" | $cdb -c 1.cdb echo $? echo "Handling invalid input format (short file)" echo "+10,10:" | $cdb -c 1.cdb echo $? echo Creating db with eol in key and value echo "+2,2:a ->b " | $cdb -c 1.cdb echo $? do_csum 1.cdb echo Querying key-value with eol $cdb -q 1.cdb "a " echo $? echo Handling file size limits ( ulimit -f 4 trap '' 25 ( for i in 0 1 2 3 4 5 6 7 8 9 ; do for j in 0 1 2 3 4 5 6 7 8 9 ; do for k in 0 1 2 3 4 5 6 7 8 9 ; do echo "+4,4:k$i$j$k->v$i$j$k" done done done echo ) | $cdb -c 1.cdb echo $? ) if false ; then # does not work for now, bugs in libc echo Handling oom condition ( for i0 in 0 1 2 3 4 5 6 7 8 9 ; do for i1 in 0 1 2 3 4 5 6 7 8 9 ; do for i2 in 0 1 2 3 4 5 6 7 8 9 ; do for i3 in 0 1 2 3 4 5 6 7 8 9 ; do for i4 in 0 1 2 3 4 5 6 7 8 9 ; do echo "+5,0:$i0$i1$i2$i3$i4->" done done done done done echo ) | (ulimit -v 1900; $cdb -c 1.cdb) echo $? fi rm -rf 1.cdb 1a.cdb 1.cdb.tmp exit 0 tinycdb-0.78build1/tinycdb.spec0000664000000000000000000000445611753222162013417 0ustar # tinycdb.spec: tinycdb RPM spec file. # # This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru. # Public domain. Summary: A package for maintenance of constant databases Name: tinycdb Version: 0.78 Release: 1 Source: ftp://ftp.corpit.ru/pub/tinycdb/tinycdb_%version.tar.gz License: Public Domain Group: System Environment/Libraries Prefix: %{_prefix} BuildRoot: %{_tmppath}/%{name}-root Summary: TinyCDB - a Constant DataBase %description tinycdb is a small, fast and reliable utility set and subroutine library for creating and reading constant databases. The database structure is tuned for fast reading: + Successful lookups take normally just two disk accesses. + Unsuccessful lookups take only one disk access. + Small disk space and memory size requirements; a database uses 2048 bytes for the header and 24 bytes plus size of (key,value) per record. + Maximum database size is 4GB; individual record size is not otherwise limited. + Portable file format. + Fast creation of new databases. + No locking, updates are atomical. This package contains both the utility and the development files, together with nss_cdb module. %package devel Summary: Development files for the tinycdb library. Group: System Environment/Libraries Requires: %name = %version-%release Summary: Development files for tinycdb %description devel tinycdb is a small, fast and reliable utility set and subroutine library for creating and reading constant databases. This package contains tinycdb development libraries and header files. %prep %setup -q %build make CFLAGS="$RPM_OPT_FLAGS" \ staticlib sharedlib cdb-shared nss \ sysconfdir=/etc %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT %makeinstall DESTDIR=$RPM_BUILD_ROOT \ libdir=%_libdir bindir=%_bindir mandir=%_mandir \ syslibdir=/%_lib sysconfdir=/etc \ includedir=%_includedir \ install-all install-nss install-piclib install-sharedlib \ INSTALLPROG=cdb-shared CP="cp -p" %files %defattr(-,root,root) %_bindir/* %_mandir/man1/* %_mandir/man5/* %_libdir/libcdb.so.* /%_lib/libnss_cdb* /etc/cdb-Makefile %doc ChangeLog NEWS debian/changelog %files devel %defattr(-,root,root) %_libdir/libcdb.a %_libdir/libcdb_pic.a %_libdir/libcdb.so %_mandir/man3/* %_includedir/* %clean rm -rf $RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %changelog