From d4a38725af72e2d1c1c9cff375127fb95c9ffb64 Mon Sep 17 00:00:00 2001 From: dgsga <181612+dgsga@users.noreply.github.com> Date: Sun, 15 Oct 2023 18:54:39 +0100 Subject: [PATCH] Deprecate legacy cnid backends (#528) --- .github/workflows/build.yml | 2 +- .travis.yml | 1 - configure.ac | 6 - doc/manpages/man5/afp.conf.5.xml | 13 - doc/manual/configuration.xml | 36 - etc/afpd/afp_options.c | 19 - include/atalk/Makefile.am | 1 - include/atalk/tdb.h | 181 ---- libatalk/Makefile.am | 5 - libatalk/cnid/Makefile.am | 10 +- libatalk/cnid/cdb/.gitignore | 8 - libatalk/cnid/cdb/Makefile.am | 21 - libatalk/cnid/cdb/README | 35 - libatalk/cnid/cdb/cnid_cdb.h | 51 - libatalk/cnid/cdb/cnid_cdb_add.c | 292 ----- libatalk/cnid/cdb/cnid_cdb_close.c | 36 - libatalk/cnid/cdb/cnid_cdb_delete.c | 46 - libatalk/cnid/cdb/cnid_cdb_get.c | 50 - libatalk/cnid/cdb/cnid_cdb_lookup.c | 136 --- libatalk/cnid/cdb/cnid_cdb_meta.c | 8 - libatalk/cnid/cdb/cnid_cdb_meta.h | 50 - libatalk/cnid/cdb/cnid_cdb_nextid.c | 28 - libatalk/cnid/cdb/cnid_cdb_open.c | 381 ------- libatalk/cnid/cdb/cnid_cdb_private.h | 125 --- libatalk/cnid/cdb/cnid_cdb_rebuild_add.c | 140 --- libatalk/cnid/cdb/cnid_cdb_resolve.c | 49 - libatalk/cnid/cdb/cnid_cdb_update.c | 104 -- libatalk/cnid/cnid_init.c | 40 - libatalk/cnid/tdb/.gitignore | 8 - libatalk/cnid/tdb/Makefile.am | 20 - libatalk/cnid/tdb/README | 35 - libatalk/cnid/tdb/cnid_tdb.h | 79 -- libatalk/cnid/tdb/cnid_tdb_add.c | 210 ---- libatalk/cnid/tdb/cnid_tdb_close.c | 22 - libatalk/cnid/tdb/cnid_tdb_delete.c | 50 - libatalk/cnid/tdb/cnid_tdb_get.c | 40 - libatalk/cnid/tdb/cnid_tdb_lookup.c | 152 --- libatalk/cnid/tdb/cnid_tdb_nextid.c | 17 - libatalk/cnid/tdb/cnid_tdb_open.c | 153 --- libatalk/cnid/tdb/cnid_tdb_resolve.c | 37 - libatalk/cnid/tdb/cnid_tdb_update.c | 108 -- libatalk/tdb/.gitignore | 8 - libatalk/tdb/Makefile.am | 16 - libatalk/tdb/check.c | 423 -------- libatalk/tdb/dump.c | 137 --- libatalk/tdb/error.c | 57 - libatalk/tdb/freelist.c | 386 ------- libatalk/tdb/freelistcheck.c | 109 -- libatalk/tdb/io.c | 472 --------- libatalk/tdb/lock.c | 592 ----------- libatalk/tdb/open.c | 552 ---------- libatalk/tdb/tdb.c | 1140 -------------------- libatalk/tdb/tdb_private.h | 279 ----- libatalk/tdb/transaction.c | 1236 ---------------------- libatalk/tdb/traverse.c | 366 ------- macros/cnid-backend.m4 | 53 - macros/netatalk.m4 | 25 - macros/summary.m4 | 7 - 58 files changed, 2 insertions(+), 8661 deletions(-) delete mode 100644 include/atalk/tdb.h delete mode 100644 libatalk/cnid/cdb/.gitignore delete mode 100644 libatalk/cnid/cdb/Makefile.am delete mode 100644 libatalk/cnid/cdb/README delete mode 100644 libatalk/cnid/cdb/cnid_cdb.h delete mode 100644 libatalk/cnid/cdb/cnid_cdb_add.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_close.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_delete.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_get.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_lookup.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_meta.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_meta.h delete mode 100644 libatalk/cnid/cdb/cnid_cdb_nextid.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_open.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_private.h delete mode 100644 libatalk/cnid/cdb/cnid_cdb_rebuild_add.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_resolve.c delete mode 100644 libatalk/cnid/cdb/cnid_cdb_update.c delete mode 100644 libatalk/cnid/tdb/.gitignore delete mode 100644 libatalk/cnid/tdb/Makefile.am delete mode 100644 libatalk/cnid/tdb/README delete mode 100644 libatalk/cnid/tdb/cnid_tdb.h delete mode 100644 libatalk/cnid/tdb/cnid_tdb_add.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_close.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_delete.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_get.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_lookup.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_nextid.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_open.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_resolve.c delete mode 100644 libatalk/cnid/tdb/cnid_tdb_update.c delete mode 100644 libatalk/tdb/.gitignore delete mode 100644 libatalk/tdb/Makefile.am delete mode 100644 libatalk/tdb/check.c delete mode 100644 libatalk/tdb/dump.c delete mode 100644 libatalk/tdb/error.c delete mode 100644 libatalk/tdb/freelist.c delete mode 100644 libatalk/tdb/freelistcheck.c delete mode 100644 libatalk/tdb/io.c delete mode 100644 libatalk/tdb/lock.c delete mode 100644 libatalk/tdb/open.c delete mode 100644 libatalk/tdb/tdb.c delete mode 100644 libatalk/tdb/tdb_private.h delete mode 100644 libatalk/tdb/transaction.c delete mode 100644 libatalk/tdb/traverse.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2b5104f05e..ffce0d145c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ on: - 'README.md' env: - APT_PACKAGES: libtool libtool-bin automake autoconf libevent-dev libssl-dev libgcrypt-dev libkrb5-dev libpam0g-dev libdb-dev libtdb-dev libmysqlclient-dev libavahi-client-dev libacl1-dev libcrack2-dev libdbus-1-dev libdbus-glib-1-dev libglib2.0-dev systemtap-sdt-dev tracker tcpd + APT_PACKAGES: libtool libtool-bin automake autoconf libevent-dev libssl-dev libgcrypt-dev libkrb5-dev libpam0g-dev libdb-dev libmysqlclient-dev libavahi-client-dev libacl1-dev libcrack2-dev libdbus-1-dev libdbus-glib-1-dev libglib2.0-dev systemtap-sdt-dev tracker tcpd jobs: build-ubuntu: diff --git a/.travis.yml b/.travis.yml index d89b0f5fca..490dfbf9b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ before_install: libkrb5-dev libpam0g-dev libdb-dev - libtdb-dev libmysqlclient-dev libavahi-client-dev libacl1-dev diff --git a/configure.ac b/configure.ac index 8c650b5657..beb894a374 100644 --- a/configure.ac +++ b/configure.ac @@ -185,9 +185,6 @@ AC_NETATALK_RECVFILE dnl Check whether bundled libevent shall not be used AC_NETATALK_LIBEVENT -dnl Check whether bundled tdb shall be used -AC_NETATALK_TDB - dnl Check whether bundled talloc shall be used AC_NETATALK_TALLOC @@ -280,16 +277,13 @@ AC_CONFIG_FILES([ libatalk/adouble/Makefile libatalk/bstring/Makefile libatalk/cnid/Makefile - libatalk/cnid/cdb/Makefile libatalk/cnid/last/Makefile libatalk/cnid/dbd/Makefile - libatalk/cnid/tdb/Makefile libatalk/cnid/mysql/Makefile libatalk/compat/Makefile libatalk/dsi/Makefile libatalk/iniparser/Makefile libatalk/talloc/Makefile - libatalk/tdb/Makefile libatalk/unicode/Makefile libatalk/unicode/charsets/Makefile libatalk/util/Makefile diff --git a/doc/manpages/man5/afp.conf.5.xml b/doc/manpages/man5/afp.conf.5.xml index 0f4261a38e..0e04c0d715 100644 --- a/doc/manpages/man5/afp.conf.5.xml +++ b/doc/manpages/man5/afp.conf.5.xml @@ -2214,19 +2214,6 @@ - - cdb - - - "Concurrent database", backend is based on Oracle Berkeley DB. - With this backend several afpd daemons access the - CNID database directly. Berkeley DB locking is used to synchronize - access, if more than one afpd process is active - for a volume. The drawback is, that the crash of a single - afpd process might corrupt the database. - - - dbd diff --git a/doc/manual/configuration.xml b/doc/manual/configuration.xml index d6e697e731..91c4538104 100644 --- a/doc/manual/configuration.xml +++ b/doc/manual/configuration.xml @@ -225,23 +225,6 @@ basedir regex = /usr/home - - cdb<indexterm> - <primary>CDB</primary> - - <secondary>"cdb" CNID backend</secondary> - </indexterm> - - The "concurrent database" backend is based on Berkeley DB. With - this backend, several afpd daemons access the CNID database directly. - Berkeley DB locking is used to synchronize access, if more than one - afpd process is active for a volume. The drawback is, that the crash - of a single afpd process might corrupt the database. cdb should only - be used when sharing home directories for a larger number of users - and it has been determined that a large number of - cnid_dbd processes is problematic. - - dbd<indexterm> <primary>DBD</primary> @@ -257,25 +240,6 @@ basedir regex = /usr/home</programlisting></para> <para>This is the default backend since Netatalk 2.1.</para> </sect3> - <sect3> - <title>tdb<indexterm> - <primary>tdb</primary> - - <secondary>"tdb" CNID backend</secondary> - </indexterm> - - tdb is another persistent CNID database, it's - Samba's Trivial Database. It could be used - instead of cdb for user volumes. - Only ever use it for volumes that are - not shared and accessed by multiple clients - at once ! - This backend is also used internally (as in-memory CNID - database) as a fallback in case opening the primary database can't be - opened, because tdb can work as in-memory database. - This of course means upon restart the CNIDs are gone. - - last<indexterm> <primary>Last</primary> diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index 11b1ae5596..ca9a7507d8 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -67,31 +67,12 @@ static void show_version( void ) puts( "" ); printf( " CNID backends:\t" ); -#ifdef CNID_BACKEND_CDB - printf( "cdb "); -#endif -#ifdef CNID_BACKEND_DB3 - printf( "db3 " ); -#endif #ifdef CNID_BACKEND_DBD -#ifdef CNID_BACKEND_DBD_TXN - printf( "dbd-txn " ); -#else printf( "dbd " ); #endif -#endif -#ifdef CNID_BACKEND_HASH - printf( "hash " ); -#endif #ifdef CNID_BACKEND_LAST printf( "last " ); #endif -#ifdef CNID_BACKEND_MTAB - printf( "mtab " ); -#endif -#ifdef CNID_BACKEND_TDB - printf( "tdb " ); -#endif #ifdef CNID_BACKEND_MYSQL printf( "mysql " ); #endif diff --git a/include/atalk/Makefile.am b/include/atalk/Makefile.am index 550741d6b4..d3229c2e54 100644 --- a/include/atalk/Makefile.am +++ b/include/atalk/Makefile.am @@ -34,7 +34,6 @@ noinst_HEADERS = \ queue.h \ server_child.h \ server_ipc.h \ - tdb.h \ cnid_bdb_private.h \ cnid_mysql_private.h \ cnid_private.h \ diff --git a/include/atalk/tdb.h b/include/atalk/tdb.h deleted file mode 100644 index b13ee350a2..0000000000 --- a/include/atalk/tdb.h +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef USE_BUILTIN_TDB -# include <tdb.h> -#else -# ifndef __TDB_H__ -# define __TDB_H__ - -/* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2004 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/types.h> -#include <signal.h> - -/* flags to tdb_store() */ -#define TDB_REPLACE 1 /* Unused */ -#define TDB_INSERT 2 /* Don't overwrite an existing entry */ -#define TDB_MODIFY 3 /* Don't create an existing entry */ - -/* flags for tdb_open() */ -#define TDB_DEFAULT 0 /* just a readability place holder */ -#define TDB_CLEAR_IF_FIRST 1 -#define TDB_INTERNAL 2 /* don't store on disk */ -#define TDB_NOLOCK 4 /* don't do any locking */ -#define TDB_NOMMAP 8 /* don't use mmap */ -#define TDB_CONVERT 16 /* convert endian (internal use) */ -#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */ -#define TDB_NOSYNC 64 /* don't use synchronous transactions */ -#define TDB_SEQNUM 128 /* maintain a sequence number */ -#define TDB_VOLATILE 256 /* Activate the per-hashchain freelist, default 5 */ -#define TDB_ALLOW_NESTING 512 /* Allow transactions to nest */ -#define TDB_DISALLOW_NESTING 1024 /* Disallow transactions to nest */ - -/* error codes */ -enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, - TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT, - TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY, - TDB_ERR_NESTING}; - -/* debugging uses one of the following levels */ -enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR, - TDB_DEBUG_WARNING, TDB_DEBUG_TRACE}; - -typedef struct TDB_DATA { - unsigned char *dptr; - size_t dsize; -} TDB_DATA; - -#ifndef PRINTF_ATTRIBUTE -#if (__GNUC__ >= 3) -/** Use gcc attribute to check printf fns. a1 is the 1-based index of - * the parameter containing the format, and a2 the index of the first - * argument. Note that some gcc 2.x versions don't handle this - * properly **/ -#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) -#else -#define PRINTF_ATTRIBUTE(a1, a2) -#endif -#endif - -/* this is the context structure that is returned from a db open */ -typedef struct tdb_context TDB_CONTEXT; - -typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *); -typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_ATTRIBUTE(3, 4); -typedef unsigned int (*tdb_hash_func)(TDB_DATA *key); - -struct tdb_logging_context { - tdb_log_func log_fn; - void *log_private; -}; - -struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode); -struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode, - const struct tdb_logging_context *log_ctx, - tdb_hash_func hash_fn); -void tdb_set_max_dead(struct tdb_context *tdb, int max_dead); - -int tdb_reopen(struct tdb_context *tdb); -int tdb_reopen_all(int parent_longlived); -void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx); -enum TDB_ERROR tdb_error(struct tdb_context *tdb); -const char *tdb_errorstr(struct tdb_context *tdb); -TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key); -int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data); -int tdb_delete(struct tdb_context *tdb, TDB_DATA key); -int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag); -int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf); -int tdb_close(struct tdb_context *tdb); -TDB_DATA tdb_firstkey(struct tdb_context *tdb); -TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key); -int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *); -int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *); -int tdb_exists(struct tdb_context *tdb, TDB_DATA key); -int tdb_lockall(struct tdb_context *tdb); -int tdb_lockall_nonblock(struct tdb_context *tdb); -int tdb_unlockall(struct tdb_context *tdb); -int tdb_lockall_read(struct tdb_context *tdb); -int tdb_lockall_read_nonblock(struct tdb_context *tdb); -int tdb_unlockall_read(struct tdb_context *tdb); -int tdb_lockall_mark(struct tdb_context *tdb); -int tdb_lockall_unmark(struct tdb_context *tdb); -const char *tdb_name(struct tdb_context *tdb); -int tdb_fd(struct tdb_context *tdb); -tdb_log_func tdb_log_fn(struct tdb_context *tdb); -void *tdb_get_logging_private(struct tdb_context *tdb); -int tdb_transaction_start(struct tdb_context *tdb); -int tdb_transaction_prepare_commit(struct tdb_context *tdb); -int tdb_transaction_commit(struct tdb_context *tdb); -int tdb_transaction_cancel(struct tdb_context *tdb); -int tdb_transaction_recover(struct tdb_context *tdb); -int tdb_get_seqnum(struct tdb_context *tdb); -int tdb_hash_size(struct tdb_context *tdb); -size_t tdb_map_size(struct tdb_context *tdb); -int tdb_get_flags(struct tdb_context *tdb); -void tdb_add_flags(struct tdb_context *tdb, unsigned flag); -void tdb_remove_flags(struct tdb_context *tdb, unsigned flag); -void tdb_enable_seqnum(struct tdb_context *tdb); -void tdb_increment_seqnum_nonblock(struct tdb_context *tdb); -int tdb_check(struct tdb_context *tdb, - int (*check) (TDB_DATA key, TDB_DATA data, void *private_data), - void *private_data); - -/* Low level locking functions: use with care */ -int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key); - -void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr); - -/* wipe and repack */ -int tdb_wipe_all(struct tdb_context *tdb); -int tdb_repack(struct tdb_context *tdb); - -/* Debug functions. Not used in production. */ -void tdb_dump_all(struct tdb_context *tdb); -int tdb_printfreelist(struct tdb_context *tdb); -int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); -int tdb_freelist_size(struct tdb_context *tdb); - -extern TDB_DATA tdb_null; - -#ifdef __cplusplus -} -#endif - -# endif /* tdb.h */ -#endif /* USE_BUILTIN_TDB */ diff --git a/libatalk/Makefile.am b/libatalk/Makefile.am index abe54dd56f..8ca1bebe73 100644 --- a/libatalk/Makefile.am +++ b/libatalk/Makefile.am @@ -36,8 +36,3 @@ libatalk_la_DEPENDENCIES = \ util/libutil.la \ vfs/libvfs.la -if USE_BUILTIN_TDB -SUBDIRS += tdb -libatalk_la_LIBADD += tdb/libtdb.la -libatalk_la_DEPENDENCIES += tdb/libtdb.la -endif diff --git a/libatalk/cnid/Makefile.am b/libatalk/cnid/Makefile.am index 5c9dd52c93..71a20119bd 100644 --- a/libatalk/cnid/Makefile.am +++ b/libatalk/cnid/Makefile.am @@ -1,22 +1,14 @@ # Makefile.am for libatalk/cnid/ -SUBDIRS = last cdb dbd tdb +SUBDIRS = last dbd noinst_LTLIBRARIES = libcnid.la LIBCNID_DEPS = dbd/libcnid_dbd.la -if USE_CDB_BACKEND -LIBCNID_DEPS += cdb/libcnid_cdb.la -endif - if USE_LAST_BACKEND LIBCNID_DEPS += last/libcnid_last.la endif -if USE_TDB_BACKEND -LIBCNID_DEPS += tdb/libcnid_tdb.la -endif - if USE_MYSQL_BACKEND SUBDIRS += mysql LIBCNID_DEPS += @MYSQL_LIBS@ mysql/libcnid_mysql.la diff --git a/libatalk/cnid/cdb/.gitignore b/libatalk/cnid/cdb/.gitignore deleted file mode 100644 index fbde08fa8c..0000000000 --- a/libatalk/cnid/cdb/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -Makefile -Makefile.in -*.lo -*.la -.deps -.libs -.gitignore -libcnid_cdb_la-cnid_cdb_add.o libcnid_cdb_la-cnid_cdb_close.o libcnid_cdb_la-cnid_cdb_delete.o libcnid_cdb_la-cnid_cdb_get.o libcnid_cdb_la-cnid_cdb_lookup.o libcnid_cdb_la-cnid_cdb_open.o libcnid_cdb_la-cnid_cdb_rebuild_add.o libcnid_cdb_la-cnid_cdb_resolve.o libcnid_cdb_la-cnid_cdb_update.o diff --git a/libatalk/cnid/cdb/Makefile.am b/libatalk/cnid/cdb/Makefile.am deleted file mode 100644 index cd3ca24fda..0000000000 --- a/libatalk/cnid/cdb/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -# Makefile.am for libatalk/cnid/ - -libcnid_cdb_la_SOURCES = cnid_cdb_add.c \ - cnid_cdb_close.c \ - cnid_cdb_delete.c \ - cnid_cdb_get.c \ - cnid_cdb_lookup.c \ - cnid_cdb_open.c \ - cnid_cdb_resolve.c \ - cnid_cdb_update.c \ - cnid_cdb_rebuild_add.c \ - cnid_cdb.h -libcnid_cdb_la_CFLAGS = @BDB_CFLAGS@ -libcnid_cdb_la_LIBADD = @BDB_LIBS@ @PTHREAD_LIBS@ - -if USE_CDB_BACKEND -noinst_LTLIBRARIES = libcnid_cdb.la -endif - -noinst_HEADERS = cnid_cdb_meta.h cnid_cdb_private.h -EXTRA_DIST = README cnid_cdb_meta.c cnid_cdb_nextid.c diff --git a/libatalk/cnid/cdb/README b/libatalk/cnid/cdb/README deleted file mode 100644 index b39889bfce..0000000000 --- a/libatalk/cnid/cdb/README +++ /dev/null @@ -1,35 +0,0 @@ -the catalog database keeps track of three mappings: - CNID -> dev/ino and did/name - dev/ino -> CNID - did/name -> CNID - -dev/ino is used to keep track of magically moved files. did/name is -for quick lookups of CNIDs. - -NOTE: the database will append a nul byte to the end of name. in -addition, name should be given as it appears on disk. this allows the -creation of cnid updating/cleaning programs that don't have to deal -with knowing what the particular codepage is. - -here's the ritual: - 1) open a volume. call cnid_open. - 2) every time you need a CNID, call cnid_add(). it will - automatically look for an existing cnid and add a new one - if one isn't already there. you can pass a hint if you - want. the only use this has right now is to enable - consistency between AFP and HFS. in the future, it would - allow people to write conversion utilities that - pre-instantiate a database without needing to re-assign - CNIDs. - 3) if you want to just look for a CNID without automatically - adding one in, you have two choices: - a) cnid_resolve takes a CNID, returns name, and - over-writes the CNID given with the parent DID. this - is good for FPResolveID. - b) cnid_lookup returns a CNID corresponding to the - dev/ino,did/name keys. it will auto-update the catalog - database if there's a discrepancy. - NOTE: cnid_add calls this before adding a new CNID. - 4) when you delete a file or directory, you need to call - cnid_delete with the CNID for that file/directory. - 5) call cnid_close when closing the volume. diff --git a/libatalk/cnid/cdb/cnid_cdb.h b/libatalk/cnid/cdb/cnid_cdb.h deleted file mode 100644 index d6b17278ab..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * interface for database access to cnids. i do it this way to abstract - * things a bit in case we want to change the underlying implementation. - */ - -#ifndef _ATALK_CNID_CDB__H -#define _ATALK_CNID_CDB__H 1 - -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> - -#include <atalk/cnid.h> - -/* cnid_open.c */ -extern struct _cnid_module cnid_cdb_module; -extern struct _cnid_db *cnid_cdb_open (struct cnid_open_args *args); - -/* cnid_close.c */ -extern void cnid_cdb_close (struct _cnid_db *); - -/* cnid_add.c */ -extern cnid_t cnid_cdb_add (struct _cnid_db *, const struct stat *, cnid_t, - const char *, size_t, cnid_t); -extern int cnid_cdb_getstamp (struct _cnid_db *, void *, const size_t ); - -/* cnid_get.c */ -extern cnid_t cnid_cdb_get (struct _cnid_db *, cnid_t, const char *, size_t); -extern char *cnid_cdb_resolve (struct _cnid_db *, cnid_t *, void *, size_t ); -extern cnid_t cnid_cdb_lookup (struct _cnid_db *, const struct stat *, cnid_t, - const char *, size_t); - -/* cnid_update.c */ -extern int cnid_cdb_update (struct _cnid_db *, cnid_t, const struct stat *, - cnid_t, const char *, size_t); - -/* cnid_delete.c */ -extern int cnid_cdb_delete (struct _cnid_db *, const cnid_t); - -/* cnid_nextid.c */ -extern cnid_t cnid_cdb_nextid (struct _cnid_db *); - -extern int cnid_cdb_lock (void *); -extern int cnid_cdb_unlock (void *); - -extern cnid_t cnid_cdb_rebuild_add (struct _cnid_db *, const struct stat *, - cnid_t, const char *, size_t, cnid_t); - - -#endif /* include/atalk/cnid_cdb.h */ - diff --git a/libatalk/cnid/cdb/cnid_cdb_add.c b/libatalk/cnid/cdb/cnid_cdb_add.c deleted file mode 100644 index 7b082ecb2f..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_add.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - * cnid_add (db, dev, ino, did, name, hint): - * add a name to the CNID database. we use both dev/ino and did/name - * to keep track of things. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include <arpa/inet.h> -#include "cnid_cdb_private.h" - -extern int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st, - cnid_t did, const char *name, size_t len); - -#define tid NULL - -static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino) -{ - buf[CNID_DEV_LEN - 1] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 2] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 3] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 4] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 5] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 6] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 7] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 8] = dev; - - buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino; -} - -unsigned char *make_cnid_data(u_int32_t flags, const struct stat *st, const cnid_t did, - const char *name, const size_t len) -{ - static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1]; - unsigned char *buf = start +CNID_LEN; - u_int32_t i; - - if (len > MAXPATHLEN) - return NULL; - - make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino); - buf += CNID_DEVINO_LEN; - - i = S_ISDIR(st->st_mode)?1:0; - i = htonl(i); - memcpy(buf, &i, sizeof(i)); - buf += sizeof(i); - - /* did is already in network byte order */ - memcpy(buf, &did, sizeof(did)); - buf += sizeof(did); - - memcpy(buf, name, len); - *(buf + len) = '\0'; - - return start; -} - -/* --------------- */ -static int db_stamp(void *buffer, size_t size) -{ -time_t t; - memset(buffer, 0, size); - /* return the current time. */ - if (size < sizeof(time_t)) - return -1; - t = time(NULL); - memcpy(buffer,&t, sizeof(time_t)); - return 0; - -} - - -/* ----------------------------- */ -static cnid_t get_cnid(CNID_private *db) -{ - DBT rootinfo_key, rootinfo_data; - DBC *cursor; - int rc; - int flag, setstamp=0; - cnid_t hint,id; - char buf[ROOTINFO_DATALEN]; - char stamp[CNID_DEV_LEN]; - - if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) { - LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc)); - return CNID_INVALID; - } - - memset(&rootinfo_key, 0, sizeof(rootinfo_key)); - memset(&rootinfo_data, 0, sizeof(rootinfo_data)); - rootinfo_key.data = ROOTINFO_KEY; - rootinfo_key.size = ROOTINFO_KEYLEN; - - switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) { - case 0: - memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint)); - id = ntohl(hint); - /* If we've hit the max CNID allowed, we return a fatal error. CNID - * needs to be recycled before proceding. */ - if (++id == CNID_INVALID) { - LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit."); - errno = CNID_ERR_MAX; - goto cleanup; - } - hint = htonl(id); - flag = DB_CURRENT; - break; - case DB_NOTFOUND: - hint = htonl(CNID_START); - flag = DB_KEYFIRST; - setstamp = 1; - break; - default: - LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc)); - errno = CNID_ERR_DB; - goto cleanup; - } - - memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN); - rootinfo_data.data = buf; - rootinfo_data.size = ROOTINFO_DATALEN; - memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint)); - if (setstamp) { - if (db_stamp(stamp, CNID_DEV_LEN) < 0) { - goto cleanup; - } - memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp)); - } - - - switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) { - case 0: - break; - default: - LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc)); - errno = CNID_ERR_DB; - goto cleanup; - } - if ((rc = cursor->c_close(cursor)) != 0) { - LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc)); - errno = CNID_ERR_DB; - return CNID_INVALID; - } - return hint; -cleanup: - if ((rc = cursor->c_close(cursor)) != 0) { - LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc)); - return CNID_INVALID; - } - return CNID_INVALID; -} - -/* ------------------------ */ -cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st, - cnid_t did, const char *name, size_t len, cnid_t hint) -{ - CNID_private *db; - DBT key, data; - cnid_t id; - int rc; - - if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) { - errno = CNID_ERR_PARAM; - return CNID_INVALID; - } - - /* Do a lookup. */ - id = cnid_cdb_lookup(cdb, st, did, name, len); - /* ... Return id if it is valid, or if Rootinfo is read-only. */ - if (id || (db->flags & CNIDFLAG_DB_RO)) { -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id)); -#endif - return id; - } - - /* Initialize our DBT data structures. */ - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - if ((data.data = make_cnid_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) { - LOG(log_error, logtype_default, "cnid_add: Path name is too long"); - errno = CNID_ERR_PATH; - return CNID_INVALID; - } - data.size = CNID_HEADER_LEN + len + 1; - - if ((hint = get_cnid(db)) == 0) { - errno = CNID_ERR_DB; - return CNID_INVALID; - } - memcpy(data.data, &hint, sizeof(hint)); - - key.data = &hint; - key.size = sizeof(hint); - - /* Now we need to add the CNID data to the databases. */ - if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) { - if (rc == EINVAL) { - /* if we have a duplicate - * on cnid it's a fatal error. - * on dev:inode - * - leftover should have been delete before. - * - a second process already updated the db - * - it's a new file e.g. our file is already deleted and replaced - * on did:name leftover - */ - if (cnid_cdb_update(cdb, hint, st, did, name, len)) { - errno = CNID_ERR_DB; - return CNID_INVALID; - } - } - else { - LOG(log_error, logtype_default - , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", - name, ntohl(hint), db_strerror(rc)); - errno = CNID_ERR_DB; - return CNID_INVALID; - } - } - -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint)); -#endif - - return hint; -} - -/* cnid_cbd_getstamp */ -/*-----------------------*/ -int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len) -{ - DBT key, data; - int rc; - CNID_private *db; - - if (!cdb || !(db = cdb->cnid_db_private) || !buffer || !len) { - errno = CNID_ERR_PARAM; - return -1; - } - - memset(buffer, 0, len); - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - key.data = ROOTINFO_KEY; - key.size = ROOTINFO_KEYLEN; - - if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) { - if (rc != DB_NOTFOUND) { - LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s", - db_strerror(rc)); - errno = CNID_ERR_DB; - return -1; - } - /* we waste a single ID here... */ - get_cnid(db); - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - key.data = ROOTINFO_KEY; - key.size = ROOTINFO_KEYLEN; - if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) { - LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s", - db_strerror(rc)); - errno = CNID_ERR_DB; - return -1; - } - } - - memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len); -#ifdef DEBUG - LOG(log_debug9, logtype_cnid, "cnid_getstamp: Returning stamp"); -#endif - return 0; -} - - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_close.c b/libatalk/cnid/cdb/cnid_cdb_close.c deleted file mode 100644 index c5aeceec21..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_close.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include "cnid_cdb_private.h" - -void cnid_cdb_close(struct _cnid_db *cdb) { - CNID_private *db; - - if (!cdb) { - LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !"); - return; - } - - if (!(db = cdb->cnid_db_private)) { - return; - } - db->db_didname->sync(db->db_didname, 0); - db->db_devino->sync(db->db_devino, 0); - db->db_cnid->sync(db->db_cnid, 0); - - db->db_didname->close(db->db_didname, 0); - db->db_devino->close(db->db_devino, 0); - db->db_cnid->close(db->db_cnid, 0); - - db->dbenv->close(db->dbenv, 0); - - free(db); - free(cdb); -} - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_delete.c b/libatalk/cnid/cdb/cnid_cdb_delete.c deleted file mode 100644 index deaeca44a8..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_delete.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - * cnid_delete: delete a CNID from the database - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include <arpa/inet.h> -#include "cnid_cdb_private.h" - -#define tid NULL - -int cnid_cdb_delete(struct _cnid_db *cdb, const cnid_t id) { - CNID_private *db; - DBT key; - int rc; - - if (!cdb || !(db = cdb->cnid_db_private) || !id || (db->flags & CNIDFLAG_DB_RO)) { - return -1; - } - - memset(&key, 0, sizeof(key)); - - /* Get from ain CNID database. */ - key.data = (cnid_t *)&id; - key.size = sizeof(id); - - if ((rc = db->db_cnid->del(db->db_cnid, tid, &key, 0))) { - LOG(log_error, logtype_default, "cnid_delete: Unable to delete CNID %u: %s", - ntohl(id), db_strerror(rc)); - } - else { -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_delete: Deleting CNID %u", ntohl(id)); -#endif - } - return rc; -} - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_get.c b/libatalk/cnid/cdb/cnid_cdb_get.c deleted file mode 100644 index 9c682a8c1d..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_get.c +++ /dev/null @@ -1,50 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include "cnid_cdb_private.h" - -/* Return CNID for a given did/name. */ -cnid_t cnid_cdb_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len) -{ - char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf; - CNID_private *db; - DBT key, data; - cnid_t id; - int rc; - - if (!cdb || !(db = cdb->cnid_db_private) || (len > MAXPATHLEN)) { - return 0; - } - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - buf = start; - memcpy(buf, &did, sizeof(did)); - buf += sizeof(did); - memcpy(buf, name, len); - *(buf + len) = '\0'; /* Make it a C-string. */ - key.data = start; - key.size = CNID_DID_LEN + len + 1; - - while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0))) { - - if (rc != DB_NOTFOUND) { - LOG(log_error, logtype_default, "cnid_get: Unable to get CNID %u, name %s: %s", - ntohl(did), name, db_strerror(rc)); - } - - return 0; - } - - memcpy(&id, data.data, sizeof(id)); -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_get: Returning CNID for %u, name %s as %u", - ntohl(did), name, ntohl(id)); -#endif - return id; -} - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_lookup.c b/libatalk/cnid/cdb/cnid_cdb_lookup.c deleted file mode 100644 index 950709d5d2..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_lookup.c +++ /dev/null @@ -1,136 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include "cnid_cdb_private.h" - -#define LOGFILEMAX 100 /* kbytes */ -#define CHECKTIMEMAX 30 /* minutes */ - -/* This returns the CNID corresponding to a particular file. It will - * also fix up the various databases if there's a problem. */ -cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did, - const char *name, size_t len) -{ - unsigned char *buf; - CNID_private *db; - DBT key, devdata, diddata; - char dev[CNID_DEV_LEN]; - char ino[CNID_INO_LEN]; - int devino = 1, didname = 1; - u_int32_t type_devino = (unsigned)-1; - u_int32_t type_didname = (unsigned)-1; - u_int32_t type; - int update = 0; - cnid_t id_devino, id_didname,id = 0; - int rc; - - if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) { - return 0; - } - - if ((buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) { - LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long"); - return 0; - } - - memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type)); - type = ntohl(type); - - memset(&key, 0, sizeof(key)); - memset(&diddata, 0, sizeof(diddata)); - memset(&devdata, 0, sizeof(devdata)); - - /* Look for a CNID for our did/name */ - key.data = buf +CNID_DEVINO_OFS; - key.size = CNID_DEVINO_LEN; - - memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN); - memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN); - - if (0 != (rc = db->db_didname->get(db->db_devino, NULL, &key, &devdata, 0 )) ) { - if (rc != DB_NOTFOUND) { - LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s", - did, name, db_strerror(rc)); - return 0; - } - devino = 0; - } - else { - memcpy(&id_devino, devdata.data, sizeof(cnid_t)); - memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino)); - type_devino = ntohl(type_devino); - } - - buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len); - key.data = buf +CNID_DID_OFS; - key.size = CNID_DID_LEN + len + 1; - - if (0 != (rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0 ) ) ) { - if (rc != DB_NOTFOUND) { - LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s", - did, name, db_strerror(rc)); - return 0; - } - didname = 0; - } - else { - memcpy(&id_didname, diddata.data, sizeof(cnid_t)); - memcpy(&type_didname, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname)); - type_didname = ntohl(type_didname); - } - - if (!devino && !didname) { - return 0; - } - - if (devino && didname && id_devino == id_didname && type_devino == type) { - /* the same */ - return id_didname; - } - - if (didname) { - id = id_didname; - /* we have a did:name - * if it's the same dev or not the same type - * just delete it - */ - if (!memcmp(dev, (char *)diddata.data + CNID_DEV_OFS, CNID_DEV_LEN) || - type_didname != type) { - if (cnid_cdb_delete(cdb, id) < 0) { - return 0; - } - } - else { - update = 1; - } - } - - if (devino) { - id = id_devino; - if (type_devino != type) { - /* same dev:inode but not same type one is a folder the other - * is a file,it's an inode reused, delete the record - */ - if (cnid_cdb_delete(cdb, id) < 0) { - return 0; - } - } - else { - update = 1; - } - } - if (!update) { - return 0; - } - /* Fix up the database. assume it was a file move and rename */ - cnid_cdb_update(cdb, id, st, did, name, len); - -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id)); -#endif - return id; -} - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_meta.c b/libatalk/cnid/cdb/cnid_cdb_meta.c deleted file mode 100644 index f88a9e29c0..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_meta.c +++ /dev/null @@ -1,8 +0,0 @@ -/* - * - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - * deal with metadata - * - */ diff --git a/libatalk/cnid/cdb/cnid_cdb_meta.h b/libatalk/cnid/cdb/cnid_cdb_meta.h deleted file mode 100644 index e8a4bdd050..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_meta.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - */ - -#define CNID_META_CNID_LEN 4 -#define CNID_META_MDATE_LEN 4 /* space for 8 */ -#define CNID_META_CDATE_LEN 4 /* space for 8 */ -#define CNID_META_BDATE_LEN 4 /* ditto */ -#define CNID_META_ADATE_LEN 4 /* ditto */ -#define CNID_META_AFPI_LEN 4 /* plus permission bits */ -#define CNID_META_FINDERI_LEN 32 -#define CNID_META_PRODOSI_LEN 8 -#define CNID_META_RFORKLEN_LEN 4 /* space for 8 */ -#define CNID_META_MACNAME_LEN 32 /* maximum size */ -#define CNID_META_SHORTNAME_LEN 12 /* max size (8.3) */ -#define CNID_META_FILLER_LEN 4 - -#define CNID_META_CNID_OFF 0 -#define CNID_META_MDATE_OFF (CNID_META_CNID_OFF + CNID_META_CNID_LEN + \ - CNID_META_FILLER_LEN) -#define CNID_META_CDATE_OFF (CNID_META_MDATE_OFF + CNID_META_MDATE_LEN + \ - CNID_META_FILLER_LEN) -#define CNID_META_BDATE_OFF (CNID_META_CDATE_OFF + CNID_META_CDATE_LEN + \ - CNID_META_FILLER_LEN) -#define CNID_META_ADATE_OFF (CNID_META_BDATE_OFF + CNID_META_BDATE_LEN + \ - CNID_META_FILLER_LEN) -#define CNID_META_AFPI_OFF (CNID_META_ADATE_OFF + CNID_META_ADATE_LEN) -#define CNID_META_FINDERI_OFF (CNID_META_AFPI_OFF + CNID_META_AFPI_LEN) -#define CNID_META_PRODOSI_OFF (CNID_META_FINDERI_OFF + CNID_META_FINDERI_LEN) -#define CNID_META_RFORKLEN_OFF (CNID_META_PRODOSI_OFF + CNID_META_PRODOSI_LEN) -#define CNID_META_MACNAME_OFF (CNID_META_RFORKLEN_OFF + \ - CNID_META_RFORKLEN_LEN) -#define CNID_META_SHORTNAME_OFF (CNID_META_MACNAME_OFF + - - -#define cnid_meta_clear(a) -#define cnid_meta_get(id) - -#define cnid_meta_cnid(a) -#define cnid_meta_modifydate(a) -#define cnid_meta_createdate(a) -#define cnid_meta_backupdate(a) -#define cnid_meta_accessdate(a) -#define cnid_meta_afpi(a) -#define cnid_meta_finderi(a) -#define cnid_meta_prodosi(a) -#define cnid_meta_rforklen(a) -#define cnid_meta_macname(a) -#define cnid_meta_shortname(a) -#define cnid_meta_longname(a) - diff --git a/libatalk/cnid/cdb/cnid_cdb_nextid.c b/libatalk/cnid/cdb/cnid_cdb_nextid.c deleted file mode 100644 index ba14bd8e46..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_nextid.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB - -#ifdef unused -#include "cnid_cdb_private.h" - -/* return the next id. we use the fact that ad files are memory - * mapped. */ -cnid_t cnid_cdb_nextid(struct _cnid_db *cdb) -{ - CNID_private *db; - cnid_t id; - - if (!cdb || !(db = cdb->_private)) - return 0; - - memcpy(&id, ad_entry(&db->rootinfo, ADEID_DID), sizeof(id)); - return id; -} -#endif - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_open.c b/libatalk/cnid/cdb/cnid_cdb_open.c deleted file mode 100644 index 0a8cfa39ed..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_open.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - * CNID database support. - * - * here's the deal: - * 1) afpd already caches did's. - * 2) the database stores cnid's as both did/name and dev/ino pairs. - * 3) RootInfo holds the value of the NextID. - * 4) the cnid database gets called in the following manner -- - * start a database: - * cnid = cnid_open(root_dir); - * - * allocate a new id: - * newid = cnid_add(cnid, dev, ino, parent did, - * name, id); id is a hint for a specific id. pass 0 if you don't - * care. if the id is already assigned, you won't get what you - * requested. - * - * given an id, get a did/name and dev/ino pair. - * name = cnid_get(cnid, &id); given an id, return the corresponding - * info. - * return code = cnid_delete(cnid, id); delete an entry. - * - * with AFP, CNIDs 0-2 have special meanings. here they are: - * 0 -- invalid cnid - * 1 -- parent of root directory (handled by afpd) - * 2 -- root directory (handled by afpd) - * - * CNIDs 4-16 are reserved according to page 31 of the AFP 3.0 spec so, - * CNID_START begins at 17. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB - -#include <atalk/volume.h> -#include <atalk/cnid_private.h> -#include "cnid_cdb_private.h" - -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif /* ! MIN */ - -#define DBHOME ".AppleDB" -#define DBCNID "cnid2.db" -#define DBDEVINO "devino.db" -#define DBDIDNAME "didname.db" /* did/full name mapping */ -#define DBLOCKFILE "cnid.lock" - -#define DBHOMELEN 8 -#define DBLEN 10 - -#define DBOPTIONS (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL) - -#define MAXITER 0xFFFF /* maximum number of simultaneously open CNID - * databases. */ - -static char *old_dbfiles[] = {"cnid.db", NULL}; - -/* --------------- */ -static int didname(DB *dbp _U_, const DBT *pkey _U_, const DBT *pdata, DBT *skey) -{ -int len; - - memset(skey, 0, sizeof(DBT)); - skey->data = (char *)pdata->data + CNID_DID_OFS; - len = strlen((char *)skey->data + CNID_DID_LEN); - skey->size = CNID_DID_LEN + len + 1; - return (0); -} - -/* --------------- */ -static int devino(DB *dbp _U_, const DBT *pkey _U_, const DBT *pdata, DBT *skey) -{ - memset(skey, 0, sizeof(DBT)); - skey->data = (char *)pdata->data + CNID_DEVINO_OFS; - skey->size = CNID_DEVINO_LEN; - return (0); -} - -/* --------------- */ -static int my_associate (DB *p, DB *s, - int (*callback)(DB *, const DBT *,const DBT *, DBT *), - u_int32_t flags) -{ -#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) - return p->associate(p, NULL, s, callback, flags); -#else -#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0) - return p->associate(p, s, callback, flags); -#else - return 0; /* FIXME */ -#endif -#endif -} - -/* --------------- */ -static int my_open(DB * p, const char *f, const char *d, DBTYPE t, u_int32_t flags, int mode) -{ -#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) - return p->open(p, NULL, f, d, t, flags, mode); -#else - return p->open(p, f, d, t, flags, mode); -#endif -} - -/* --------------- */ -static struct _cnid_db *cnid_cdb_new(struct vol *vol) -{ - struct _cnid_db *cdb; - int major, minor, patch; - char *version_str; - - version_str = db_version(&major, &minor, &patch); - - /* check library match, ignore if only patch level changed */ - if ( major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR) - { - LOG(log_error, logtype_cnid, "cnid_cdb_new: the Berkeley DB library version used does not match the version compiled with: (%u.%u)/(%u.%u)", DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor); - return NULL; - } - - if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL) - return NULL; - - cdb->cnid_db_vol = vol; - cdb->cnid_db_flags = CNID_FLAG_PERSISTENT; - cdb->cnid_add = cnid_cdb_add; - cdb->cnid_delete = cnid_cdb_delete; - cdb->cnid_get = cnid_cdb_get; - cdb->cnid_lookup = cnid_cdb_lookup; - cdb->cnid_nextid = NULL; /*cnid_cdb_nextid;*/ - cdb->cnid_resolve = cnid_cdb_resolve; - cdb->cnid_update = cnid_cdb_update; - cdb->cnid_close = cnid_cdb_close; - cdb->cnid_getstamp = cnid_cdb_getstamp; - cdb->cnid_rebuild_add = cnid_cdb_rebuild_add; - cdb->cnid_wipe = NULL; - return cdb; -} - -/* --------------- */ -static int upgrade_required(char *dbdir) -{ - char path[MAXPATHLEN + 1]; - int len, i; - int found = 0; - struct stat st; - - strcpy(path, dbdir); - - len = strlen(path); - if (path[len - 1] != '/') { - strcat(path, "/"); - len++; - } - - for (i = 0; old_dbfiles[i] != NULL; i++) { - strcpy(path + len, old_dbfiles[i]); - if ( !(stat(path, &st) < 0) ) { - found++; - continue; - } - if (errno != ENOENT) { - LOG(log_error, logtype_default, "cnid_open: Checking %s gave %s", path, strerror(errno)); - found++; - } - } - return found; -} - -/* --------------- */ -struct _cnid_db *cnid_cdb_open(struct cnid_open_args *args) -{ - struct stat st; - char path[MAXPATHLEN + 1]; - CNID_private *db; - struct _cnid_db *cdb; - int open_flag, len; - static int first = 0; - int rc; - struct vol *vol = args->cnid_args_vol; - - /* this checks .AppleDB. - We need space for dir + '/' + DBHOMELEN + '/' + DBLEN */ - if ((len = strlen(vol->v_path)) > (MAXPATHLEN - DBHOMELEN - DBLEN - 2)) { - LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", vol->v_path); - return NULL; - } - - if ((cdb = cnid_cdb_new(vol)) == NULL) { - LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database"); - return NULL; - } - - if ((db = (CNID_private *) calloc(1, sizeof(CNID_private))) == NULL) { - LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database"); - goto fail_cdb; - } - - cdb->cnid_db_private = (void *) db; - - strcpy(path, vol->v_path); - if (path[len - 1] != '/') { - strcat(path, "/"); - len++; - } - - strcpy(path + len, DBHOME); - if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~vol->v_umask) < 0)) { - LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path); - goto fail_adouble; - } - - if (upgrade_required(path)) { - LOG(log_error, logtype_default, "cnid_open: Found version 1 of the CNID database. Please upgrade to version 2"); - goto fail_adouble; - } - - /* Print out the version of BDB we're linked against. */ - if (!first) { - first = 1; - LOG(log_info, logtype_default, "CNID DB initialized using %s", db_version(NULL, NULL, NULL)); - } - - open_flag = DB_CREATE; - - /* We need to be able to open the database environment with full - * transaction, logging, and locking support if we ever hope to - * be a true multi-acess file server. */ - if ((rc = db_env_create(&db->dbenv, 0)) != 0) { - LOG(log_error, logtype_default, "cnid_open: db_env_create: %s", db_strerror(rc)); - goto fail_lock; - } - - /* Open the database environment. */ - if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~vol->v_umask)) != 0) { - LOG(log_error, logtype_default, "cnid_open: dbenv->open (rw) of %s failed: %s", path, db_strerror(rc)); - /* FIXME: This should probably go. Even if it worked, any use for a read-only DB? Didier? */ - if (rc == DB_RUNRECOVERY) { - /* This is the mother of all errors. We _must_ fail here. */ - LOG(log_error, logtype_default, - "cnid_open: CATASTROPHIC ERROR opening database environment %s. Run db_recovery -c immediately", path); - goto fail_lock; - } - - /* We can't get a full transactional environment, so multi-access - * is out of the question. Let's assume a read-only environment, - * and try to at least get a shared memory pool. */ - if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~vol->v_umask)) != 0) { - /* Nope, not a MPOOL, either. Last-ditch effort: we'll try to - * open the environment with no flags. */ - if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~vol->v_umask)) != 0) { - LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s", path, db_strerror(rc)); - goto fail_lock; - } - } - db->flags |= CNIDFLAG_DB_RO; - open_flag = DB_RDONLY; - LOG(log_info, logtype_default, "cnid_open: Obtained read-only database environment %s", path); - } - - /* ---------------------- */ - /* Main CNID database. Use a hash for this one. */ - - if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to create cnid database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - if ((rc = my_open(db->db_cnid, DBCNID, DBCNID, DB_BTREE, open_flag, 0666 & ~vol->v_umask)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - /* ---------------------- */ - /* did/name reverse mapping. We use a BTree for this one. */ - - if ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to create did/name database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - if ((rc = my_open(db->db_didname, DBCNID, DBDIDNAME, DB_BTREE, open_flag, 0666 & ~vol->v_umask))) { - LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - /* ---------------------- */ - /* dev/ino reverse mapping. Use a hash for this one. */ - - if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to create dev/ino database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - if ((rc = my_open(db->db_devino, DBCNID, DBDEVINO, DB_BTREE, open_flag, 0666 & ~vol->v_umask)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - /* ---------------------- */ - /* Associate the secondary with the primary. */ - if ((rc = my_associate(db->db_cnid, db->db_didname, didname, 0)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to associate didname database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - if ((rc = my_associate(db->db_cnid, db->db_devino, devino, 0)) != 0) { - LOG(log_error, logtype_default, "cnid_open: Failed to associate devino database: %s", - db_strerror(rc)); - goto fail_appinit; - } - - /* ---------------------- */ - /* Check for version. "cdb" only supports CNID_VERSION_0, cf cnid_private.h */ - - DBT key, data; - uint32_t version; - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - key.data = ROOTINFO_KEY; - key.size = ROOTINFO_KEYLEN; - - if ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0)) == 0) { - /* If not found, ignore it */ - memcpy(&version, data.data + CNID_DID_OFS, sizeof(version)); - version = ntohl(version); - LOG(log_debug, logtype_default, "CNID db version %u", version); - if (version != CNID_VERSION_0) { - LOG(log_error, logtype_default, "Unsupported CNID db version %u, use CNID backend \"dbd\"", version); - goto fail_appinit; - } - } - - return cdb; - - fail_appinit: - if (db->db_didname) - db->db_didname->close(db->db_didname, 0); - if (db->db_devino) - db->db_devino->close(db->db_devino, 0); - if (db->db_cnid) - db->db_cnid->close(db->db_cnid, 0); - LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment"); - db->dbenv->close(db->dbenv, 0); - - fail_lock: - - fail_adouble: - - free(db); - - fail_cdb: - free(cdb); - - return NULL; -} - -struct _cnid_module cnid_cdb_module = { - "cdb", - {NULL, NULL}, - cnid_cdb_open, - CNID_FLAG_SETUID | CNID_FLAG_BLOCK -}; - - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_private.h b/libatalk/cnid/cdb/cnid_cdb_private.h deleted file mode 100644 index ff28be84c9..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_private.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef LIBATALK_CDB_PRIVATE_H -#define LIBATALK_CDB_PRIVATE_H 1 - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <time.h> -#include <arpa/inet.h> - -#include <db.h> - -#include <atalk/logger.h> -#include <atalk/adouble.h> -#include <atalk/cnid_private.h> -#include <atalk/cnid.h> -#include <atalk/util.h> -#include "cnid_cdb.h" - -/* record structure - cnid 4 - dev 8 - inode 8 - type/last cnid 4 Not used - did 4 - name strlen(name) +1 - -primary key -cnid -secondary keys -dev/inode -did/name - -*/ - -typedef struct cnid_record { /* helper for debug don't use */ - unsigned int cnid; - dev_t dev; - ino_t inode; - unsigned int type; - unsigned int did; - char name[50]; -} cnid_record; - -typedef struct CNID_private { - u_int32_t magic; - DB *db_cnid; - DB *db_didname; - DB *db_devino; - DB_ENV *dbenv; - int lockfd, flags; - char lock_file[MAXPATHLEN + 1]; -} CNID_private; - -/* XXX stuff below is outdate */ -/* on-disk data format (in network byte order where appropriate) -- - * db_cnid: (key: cnid) - * name size (in bytes) - * dev 4 - * ino 4 - * did 4 - * unix name strlen(name) + 1 - * - * db_didname: (key: did/unix name) - * -- this also caches the bits of .AppleDouble used by FPGetFilDirParam - * so that we don't have to open the header file. - * NOTE: FPCatSearch has to search through all of the directories as - * this stuff doesn't get entered until needed. - * if the entire volume is in the database, though, we can use - * cursor operations to make this faster. - * - * version number is stored with did/name key of 0/0 - * - * cnid 4 - * modfiller 4 (dates only use 4 bytes right now, but we leave space - * moddate 4 for 8. moddate is also used to keep this info - * createfiller 4 up-to-date.) - * createdate 4 - * backfiller 4 - * backupdate 4 - * accfiller 4 (unused) - * accdate 4 (unused) - * AFP info 4 (stores a couple permission bits as well) - * finder info 32 - * prodos info 8 - * rforkfiller 4 - * rforklen 4 - * macname 32 (nul-terminated) - * shortname 12 (nul-terminated) - * longname longnamelen (nul-terminated) - * --------------- - * 132 bytes + longnamelen - * - * db_devino: (key: dev/ino) - * -- this is only used for consistency checks and isn't 1-1 - * cnid 4 - * - * these correspond to the different path types. longname is for the - * 255 unicode character names (path type == ?), macname is for the - * 32-character names (path type == 2), and shortname is for the - * 8+3-character names (path type == 1). - * - * db_longname: (key: did/longname) - * name namelen = strlen(name) + 1 - * - * db_macname: (key: did/macname) - * name namelen = strlen(name) + 1 - * - * db_shortname: (key: did/shortname) - * name namelen = strlen(name) + 1 - */ - -/* construct db_cnid data. NOTE: this is not re-entrant. */ -extern unsigned char *make_cnid_data (u_int32_t flags, const struct stat *,const cnid_t , - const char *, const size_t ); - -#endif /* atalk/cnid/cnid_private.h */ diff --git a/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c b/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c deleted file mode 100644 index 951674656c..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * All Rights Reserved. See COPYRIGHT. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include "cnid_cdb_private.h" - -#define tid NULL -#define DEBUG 1 - -#include "cnid_cdb.h" - -/* ----------------------------- */ -static cnid_t set_max_cnid(CNID_private *db, cnid_t hint) -{ - DBT rootinfo_key, rootinfo_data; - int rc; - char buf[ROOTINFO_DATALEN]; - cnid_t id, id1; - time_t t; - - memset(&rootinfo_key, 0, sizeof(rootinfo_key)); - memset(&rootinfo_data, 0, sizeof(rootinfo_data)); - - rootinfo_key.data = ROOTINFO_KEY; - rootinfo_key.size = ROOTINFO_KEYLEN; - - switch ((rc = db->db_cnid->get(db->db_cnid, tid, &rootinfo_key, &rootinfo_data, 0))) { - case 0: - memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN); - break; - case DB_NOTFOUND: - /* FIXME: This duplicates stuff from cnid_cdb_add.c. - We also implicitely assume that sizeof(time_t) <= CNID_DEV_LEN */ - memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN); - t = time(NULL); - memset(buf + CNID_DEV_OFS, 0, CNID_DEV_LEN); - memcpy(buf + CNID_DEV_OFS, &t, sizeof(time_t)); - id = htonl(CNID_START); - memcpy(buf + CNID_TYPE_OFS, &id, sizeof(id)); - break; - default: - LOG(log_error, logtype_default, "set_max_cnid: Unable to read rootinfo: %s", db_strerror(rc)); - errno = CNID_ERR_DB; - goto cleanup; - } - - memcpy(&id, buf + CNID_TYPE_OFS, sizeof(id)); - id = ntohl(id); - id1 = ntohl(hint); - - if (id1 > id) { - memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint)); - rootinfo_data.data = buf; - rootinfo_data.size = ROOTINFO_DATALEN; - if ((rc = db->db_cnid->put(db->db_cnid, tid, &rootinfo_key, &rootinfo_data, 0))) { - LOG(log_error, logtype_default, "set_max_cnid: Unable to write rootinfo: %s", db_strerror(rc)); - errno = CNID_ERR_DB; - goto cleanup; - } - } - - return hint; - -cleanup: - return CNID_INVALID; -} - -cnid_t cnid_cdb_rebuild_add(struct _cnid_db *cdb, const struct stat *st, - cnid_t did, const char *name, size_t len, cnid_t hint) -{ - CNID_private *db; - DBT key, data; - int rc; - - if (!cdb || !(db = cdb->cnid_db_private) || !st || !name || hint == CNID_INVALID || hint < CNID_START) { - errno = CNID_ERR_PARAM; - return CNID_INVALID; - } - -#if 0 - /* FIXME: Bjoern does a lookup. Should we not overwrite unconditionally? */ - /* Do a lookup. */ - id = cnid_cdb_lookup(cdb, st, did, name, len); - /* ... Return id if it is valid, or if Rootinfo is read-only. */ - if (id || (db->flags & CNIDFLAG_DB_RO)) { -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id)); -#endif - return id; - } -#endif - - /* Initialize our DBT data structures. */ - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - if ((data.data = make_cnid_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) { - LOG(log_error, logtype_default, "cnid_add: Path name is too long"); - errno = CNID_ERR_PATH; - return CNID_INVALID; - } - data.size = CNID_HEADER_LEN + len + 1; - - memcpy(data.data, &hint, sizeof(hint)); - - key.data = &hint; - key.size = sizeof(hint); - - /* Now we need to add the CNID data to the databases. */ - if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) { - LOG(log_error, logtype_default - , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", - name, ntohl(hint), db_strerror(rc)); - errno = CNID_ERR_DB; - goto cleanup; - } - - if (set_max_cnid(db, hint) == CNID_INVALID) { - errno = CNID_ERR_DB; - goto cleanup; - } - -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint)); -#endif - - return hint; - -cleanup: - return CNID_INVALID; -} - -#endif /* CNID_BACKEND_CDB */ diff --git a/libatalk/cnid/cdb/cnid_cdb_resolve.c b/libatalk/cnid/cdb/cnid_cdb_resolve.c deleted file mode 100644 index d3f6dab97a..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_resolve.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include "cnid_cdb_private.h" - -/* Return the did/name pair corresponding to a CNID. */ -char *cnid_cdb_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len) { - CNID_private *db; - DBT key, data; - int rc; - - if (!cdb || !(db = cdb->cnid_db_private) || !id || !(*id)) { - return NULL; - } - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - data.data = buffer; - data.ulen = len; - data.flags = DB_DBT_USERMEM; - - key.data = id; - key.size = sizeof(cnid_t); - while ((rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0))) { - - if (rc != DB_NOTFOUND) { - LOG(log_error, logtype_default, "cnid_resolve: Unable to get did/name: %s", - db_strerror(rc)); - } - - *id = 0; - return NULL; - } - - memcpy(id, (char *)data.data +CNID_DID_OFS, sizeof(cnid_t)); -#ifdef DEBUG - LOG(log_debug9, logtype_default, "cnid_resolve: Returning id = %u, did/name = %s", - ntohl(*id), (char *)data.data + CNID_NAME_OFS); -#endif - return (char *)data.data + CNID_NAME_OFS; -} - -#endif diff --git a/libatalk/cnid/cdb/cnid_cdb_update.c b/libatalk/cnid/cdb/cnid_cdb_update.c deleted file mode 100644 index 90c7d93ff5..0000000000 --- a/libatalk/cnid/cdb/cnid_cdb_update.c +++ /dev/null @@ -1,104 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifdef CNID_BACKEND_CDB -#include "cnid_cdb_private.h" - -#define tid NULL - -/* cnid_update: takes the given cnid and updates the metadata. To - * handle the did/name data, there are a bunch of functions to get - * and set the various fields. */ -int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st, - cnid_t did, const char *name, size_t len) -{ - unsigned char *buf; - CNID_private *db; - DBT key, pkey, data; - int rc; - int notfound = 0; - char getbuf[CNID_HEADER_LEN + MAXPATHLEN +1]; - - if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) { - return -1; - } - - memset(&key, 0, sizeof(key)); - memset(&pkey, 0, sizeof(pkey)); - memset(&data, 0, sizeof(data)); - - buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len); - - key.data = buf +CNID_DEVINO_OFS; - key.size = CNID_DEVINO_LEN; - data.data = getbuf; - data.size = CNID_HEADER_LEN + MAXPATHLEN + 1; - - if (0 != (rc = db->db_devino->pget(db->db_devino, tid, &key, &pkey, &data, 0)) ) { -#if DB_VERSION_MAJOR >= 4 - if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) { -#else - if (rc != DB_NOTFOUND) { -#endif - LOG(log_error, logtype_default, "cnid_update: Unable to get devino CNID %u, name %s: %s", - ntohl(did), name, db_strerror(rc)); - goto fin; - } - notfound = 1; - } else { - if ((rc = db->db_cnid->del(db->db_cnid, tid, &pkey, 0))) { - LOG(log_error, logtype_default, "cnid_update: Unable to delete CNID %u: %s", - ntohl(id), db_strerror(rc)); - } - } - - memset(&pkey, 0, sizeof(pkey)); - buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len); - key.data = buf + CNID_DID_OFS; - key.size = CNID_DID_LEN + len + 1; - - if (0 != (rc = db->db_didname->pget(db->db_didname, tid, &key, &pkey, &data, 0)) ) { -#if DB_VERSION_MAJOR >= 4 - if (rc != DB_NOTFOUND && rc != DB_SECONDARY_BAD) { -#else - if (rc != DB_NOTFOUND) { -#endif - LOG(log_error, logtype_default, "cnid_update: Unable to get didname CNID %u, name %s: %s", - ntohl(did), name, db_strerror(rc)); - goto fin; - } - notfound |= 2; - } else { - if ((rc = db->db_cnid->del(db->db_cnid, tid, &pkey, 0))) { - LOG(log_error, logtype_default, "cnid_update: Unable to delete CNID %u: %s", - ntohl(id), db_strerror(rc)); - } - } - - - memset(&key, 0, sizeof(key)); - key.data = (cnid_t *)&id; - key.size = sizeof(id); - - memset(&data, 0, sizeof(data)); - /* Make a new entry. */ - buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len); - data.data = buf; - memcpy(data.data, &id, sizeof(id)); - data.size = CNID_HEADER_LEN + len + 1; - - /* Update the old CNID with the new info. */ - if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) { - LOG(log_error, logtype_default, "cnid_update: (%d) Unable to update CNID %u:%s: %s", - notfound, ntohl(id), name, db_strerror(rc)); - goto fin; - } - - return 0; -fin: - return -1; - -} - -#endif diff --git a/libatalk/cnid/cnid_init.c b/libatalk/cnid/cnid_init.c index 03cad38868..2646baee3b 100644 --- a/libatalk/cnid/cnid_init.c +++ b/libatalk/cnid/cnid_init.c @@ -28,68 +28,28 @@ #include <stdlib.h> -#ifdef CNID_BACKEND_DB3 -extern struct _cnid_module cnid_db3_module; -#endif - -#ifdef CNID_BACKEND_HASH -extern struct _cnid_module cnid_hash_module; -#endif - #ifdef CNID_BACKEND_LAST extern struct _cnid_module cnid_last_module; #endif -#ifdef CNID_BACKEND_MTAB -extern struct _cnid_module cnid_mtab_module; -#endif - -#ifdef CNID_BACKEND_CDB -extern struct _cnid_module cnid_cdb_module; -#endif - #ifdef CNID_BACKEND_DBD extern struct _cnid_module cnid_dbd_module; #endif -#ifdef CNID_BACKEND_TDB -extern struct _cnid_module cnid_tdb_module; -#endif - #ifdef CNID_BACKEND_MYSQL extern struct _cnid_module cnid_mysql_module; #endif void cnid_init(void) { -#ifdef CNID_BACKEND_DB3 - cnid_register(&cnid_db3_module); -#endif - -#ifdef CNID_BACKEND_HASH - cnid_register(&cnid_hash_module); -#endif - #ifdef CNID_BACKEND_LAST cnid_register(&cnid_last_module); #endif -#ifdef CNID_BACKEND_MTAB - cnid_register(&cnid_mtab_module); -#endif - -#ifdef CNID_BACKEND_CDB - cnid_register(&cnid_cdb_module); -#endif - #ifdef CNID_BACKEND_DBD cnid_register(&cnid_dbd_module); #endif -#ifdef CNID_BACKEND_TDB - cnid_register(&cnid_tdb_module); -#endif - #ifdef CNID_BACKEND_MYSQL cnid_register(&cnid_mysql_module); #endif diff --git a/libatalk/cnid/tdb/.gitignore b/libatalk/cnid/tdb/.gitignore deleted file mode 100644 index 0839a374d6..0000000000 --- a/libatalk/cnid/tdb/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -Makefile -Makefile.in -*.lo -*.la -.deps -.libs -.gitignore -cnid_tdb_add.o cnid_tdb_close.o cnid_tdb_delete.o cnid_tdb_get.o cnid_tdb_lookup.o cnid_tdb_open.o cnid_tdb_resolve.o cnid_tdb_update.o diff --git a/libatalk/cnid/tdb/Makefile.am b/libatalk/cnid/tdb/Makefile.am deleted file mode 100644 index 93c289aa5f..0000000000 --- a/libatalk/cnid/tdb/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# Makefile.am for libatalk/cnid/ - -if USE_TDB_BACKEND -noinst_LTLIBRARIES = libcnid_tdb.la -endif - -libcnid_tdb_la_SOURCES = cnid_tdb_add.c \ - cnid_tdb_close.c \ - cnid_tdb_delete.c \ - cnid_tdb_get.c \ - cnid_tdb_lookup.c \ - cnid_tdb_open.c \ - cnid_tdb_resolve.c \ - cnid_tdb_update.c \ - cnid_tdb.h - -libcnid_tdb_la_CFLAGS = @TDB_CFLAGS@ -libcnid_tdb_la_LIBADD = @TDB_LIBS@ - -EXTRA_DIST = README cnid_tdb_nextid.c diff --git a/libatalk/cnid/tdb/README b/libatalk/cnid/tdb/README deleted file mode 100644 index b39889bfce..0000000000 --- a/libatalk/cnid/tdb/README +++ /dev/null @@ -1,35 +0,0 @@ -the catalog database keeps track of three mappings: - CNID -> dev/ino and did/name - dev/ino -> CNID - did/name -> CNID - -dev/ino is used to keep track of magically moved files. did/name is -for quick lookups of CNIDs. - -NOTE: the database will append a nul byte to the end of name. in -addition, name should be given as it appears on disk. this allows the -creation of cnid updating/cleaning programs that don't have to deal -with knowing what the particular codepage is. - -here's the ritual: - 1) open a volume. call cnid_open. - 2) every time you need a CNID, call cnid_add(). it will - automatically look for an existing cnid and add a new one - if one isn't already there. you can pass a hint if you - want. the only use this has right now is to enable - consistency between AFP and HFS. in the future, it would - allow people to write conversion utilities that - pre-instantiate a database without needing to re-assign - CNIDs. - 3) if you want to just look for a CNID without automatically - adding one in, you have two choices: - a) cnid_resolve takes a CNID, returns name, and - over-writes the CNID given with the parent DID. this - is good for FPResolveID. - b) cnid_lookup returns a CNID corresponding to the - dev/ino,did/name keys. it will auto-update the catalog - database if there's a discrepancy. - NOTE: cnid_add calls this before adding a new CNID. - 4) when you delete a file or directory, you need to call - cnid_delete with the CNID for that file/directory. - 5) call cnid_close when closing the volume. diff --git a/libatalk/cnid/tdb/cnid_tdb.h b/libatalk/cnid/tdb/cnid_tdb.h deleted file mode 100644 index c6be7e2b55..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * interface for database access to cnids. i do it this way to abstract - * things a bit in case we want to change the underlying implementation. - */ - -#ifndef _ATALK_CNID_TDB__H -#define _ATALK_CNID_TDB__H 1 - -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <sys/param.h> -#include <arpa/inet.h> - -#include <atalk/cnid.h> -#include <atalk/cnid_private.h> -#define STANDALONE 1 - -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <signal.h> -#if USE_BUILTIN_TDB -#include <atalk/tdb.h> -#else -#include <tdb.h> -#endif - -#define TDB_ERROR_LINK 1 -#define TDB_ERROR_DEV 2 -#define TDB_ERROR_INODE 4 - -struct _cnid_tdb_private { - dev_t st_dev; - int st_set; - int error; - int flags; - TDB_CONTEXT *tdb_cnid; - TDB_CONTEXT *tdb_didname; - TDB_CONTEXT *tdb_devino; - -}; - -/* cnid_open.c */ -extern struct _cnid_module cnid_tdb_module; -extern struct _cnid_db *cnid_tdb_open (struct cnid_open_args *args); - -/* cnid_close.c */ -extern void cnid_tdb_close (struct _cnid_db *); - -/* cnid_add.c */ -extern cnid_t cnid_tdb_add (struct _cnid_db *, const struct stat *, cnid_t, - const char *, size_t, cnid_t); - -/* cnid_get.c */ -extern cnid_t cnid_tdb_get (struct _cnid_db *, cnid_t, const char *, size_t); -extern char *cnid_tdb_resolve (struct _cnid_db *, cnid_t *, void *, size_t); -extern cnid_t cnid_tdb_lookup (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t); - -/* cnid_update.c */ -extern int cnid_tdb_update (struct _cnid_db *, cnid_t, const struct stat *, - cnid_t, const char *, size_t); - -/* cnid_delete.c */ -extern int cnid_tdb_delete (struct _cnid_db *, const cnid_t); - -/* cnid_nextid.c */ -extern cnid_t cnid_tdb_nextid (struct _cnid_db *); - -/* construct db_cnid data. NOTE: this is not re-entrant. */ -extern unsigned char *make_tdb_data(uint32_t flags, const struct stat *st, const cnid_t did, const char *name, const size_t len); - -#endif /* include/atalk/cnid_tdb.h */ diff --git a/libatalk/cnid/tdb/cnid_tdb_add.c b/libatalk/cnid/tdb/cnid_tdb_add.c deleted file mode 100644 index b3babcd35f..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_add.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB -#include "cnid_tdb.h" -#include <atalk/util.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <atalk/logger.h> - -static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino) -{ - buf[CNID_DEV_LEN - 1] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 2] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 3] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 4] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 5] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 6] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 7] = dev; dev >>= 8; - buf[CNID_DEV_LEN - 8] = dev; - - buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8; - buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino; -} - -unsigned char *make_tdb_data(uint32_t flags, const struct stat *st,const cnid_t did, - const char *name, const size_t len) -{ - static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1]; - unsigned char *buf = start +CNID_LEN; - uint32_t i; - - if (len > MAXPATHLEN) - return NULL; - - make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino); - buf += CNID_DEVINO_LEN; - - i = S_ISDIR(st->st_mode)?1:0; - i = htonl(i); - memcpy(buf, &i, sizeof(i)); - buf += sizeof(i); - - /* did is already in network byte order */ - memcpy(buf, &did, sizeof(did)); - buf += sizeof(did); - - memcpy(buf, name, len); - *(buf + len) = '\0'; - - return start; -} - -/* add an entry to the CNID databases. we do this as a transaction - * to prevent messiness. - * key: cnid - * data: - */ -static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) { - TDB_DATA altkey, altdata; - - memset(&altkey, 0, sizeof(altkey)); - memset(&altdata, 0, sizeof(altdata)); - - - /* main database */ - if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) { - goto abort; - } - - /* dev/ino database */ - altkey.dptr = data->dptr +CNID_DEVINO_OFS; - altkey.dsize = CNID_DEVINO_LEN; - altdata.dptr = key->dptr; - altdata.dsize = key->dsize; - if (tdb_store(db->tdb_devino, altkey, altdata, TDB_REPLACE)) { - goto abort; - } - - /* did/name database */ - altkey.dptr = data->dptr +CNID_DID_OFS; - altkey.dsize = data->dsize -CNID_DID_OFS; - if (tdb_store(db->tdb_didname, altkey, altdata, TDB_REPLACE)) { - goto abort; - } - return 0; - -abort: - return -1; -} - -/* ----------------------- */ -static cnid_t get_cnid(struct _cnid_tdb_private *db) -{ - TDB_DATA rootinfo_key, data; - cnid_t hint,id; - - memset(&rootinfo_key, 0, sizeof(rootinfo_key)); - memset(&data, 0, sizeof(data)); - rootinfo_key.dptr = (unsigned char *)ROOTINFO_KEY; - rootinfo_key.dsize = ROOTINFO_KEYLEN; - - tdb_chainlock(db->tdb_didname, rootinfo_key); - data = tdb_fetch(db->tdb_didname, rootinfo_key); - if (data.dptr) - { - memcpy(&hint, data.dptr, sizeof(cnid_t)); - free(data.dptr); - id = ntohl(hint); - /* If we've hit the max CNID allowed, we return a fatal error. CNID - * needs to be recycled before proceding. */ - if (++id == CNID_INVALID) { - LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit."); - errno = CNID_ERR_MAX; - goto cleanup; - } - hint = htonl(id); - } - else { - hint = htonl(CNID_START); - } - - memset(&data, 0, sizeof(data)); - data.dptr = (unsigned char *)&hint; - data.dsize = sizeof(hint); - if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) { - goto cleanup; - } - - tdb_chainunlock(db->tdb_didname, rootinfo_key ); - return hint; -cleanup: - tdb_chainunlock(db->tdb_didname, rootinfo_key); - return CNID_INVALID; -} - - -/* ------------------------ */ -cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st, - cnid_t did, const char *name, size_t len, cnid_t hint) -{ - const struct stat *lstp; - cnid_t id; - struct _cnid_tdb_private *priv; - TDB_DATA key, data; - int rc; - - if (!cdb || !(priv = cdb->cnid_db_private) || !st || !name) { - errno = CNID_ERR_PARAM; - return CNID_INVALID; - } - /* Do a lookup. */ - id = cnid_tdb_lookup(cdb, st, did, name, len); - /* ... Return id if it is valid, or if Rootinfo is read-only. */ - if (id || (priv->flags & CNIDFLAG_DB_RO)) { - return id; - } - -#if 0 - struct stat lst; - lstp = lstat(name, &lst) < 0 ? st : &lst; -#endif - lstp = st; - - /* Initialize our DBT data structures. */ - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - key.dptr = (unsigned char *)&hint; - key.dsize = sizeof(cnid_t); - if ((data.dptr = make_tdb_data(cdb->cnid_db_flags, lstp, did, name, len)) == NULL) { - LOG(log_error, logtype_default, "tdb_add: Path name is too long"); - errno = CNID_ERR_PATH; - return CNID_INVALID; - } - data.dsize = CNID_HEADER_LEN + len + 1; - hint = get_cnid(priv); - if (hint == 0) { - errno = CNID_ERR_DB; - return CNID_INVALID; - } - memcpy(data.dptr, &hint, sizeof(hint)); - - /* Now we need to add the CNID data to the databases. */ - rc = add_cnid(priv, &key, &data); - if (rc) { - LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint)); - errno = CNID_ERR_DB; - return CNID_INVALID; - } - - return hint; -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_close.c b/libatalk/cnid/tdb/cnid_tdb_close.c deleted file mode 100644 index 4879e10bba..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_close.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" - -void cnid_tdb_close(struct _cnid_db *cdb) -{ - struct _cnid_tdb_private *db; - - db = (struct _cnid_tdb_private *)cdb->cnid_db_private; - tdb_close(db->tdb_cnid); - free(cdb->cnid_db_private); - free(cdb); -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_delete.c b/libatalk/cnid/tdb/cnid_tdb_delete.c deleted file mode 100644 index 95441098bf..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_delete.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - * cnid_delete: delete a CNID from the database - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" - -int cnid_tdb_delete(struct _cnid_db *cdb, const cnid_t id) -{ - struct _cnid_tdb_private *db; - TDB_DATA key, data; - - if (!cdb || !(db = cdb->cnid_db_private) || !id) { - return -1; - } - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - key.dptr = (unsigned char *)&id; - key.dsize = sizeof(cnid_t); - data = tdb_fetch(db->tdb_cnid, key); - if (!data.dptr) - { - return 0; - } - - tdb_delete(db->tdb_cnid, key); - - key.dptr = data.dptr +CNID_DEVINO_OFS; - key.dsize = CNID_DEVINO_LEN; - tdb_delete(db->tdb_devino, key); - - key.dptr = data.dptr +CNID_DID_OFS; - key.dsize = data.dsize -CNID_DID_OFS; - tdb_delete(db->tdb_didname, key); - - free(data.dptr); - return 0; -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_get.c b/libatalk/cnid/tdb/cnid_tdb_get.c deleted file mode 100644 index 5c7536777e..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_get.c +++ /dev/null @@ -1,40 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" - -/* Return CNID for a given did/name. */ -cnid_t cnid_tdb_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len) -{ - char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf; - struct _cnid_tdb_private *db; - TDB_DATA key, data; - cnid_t id; - - if (!cdb || !(db = cdb->cnid_db_private) || (len > MAXPATHLEN)) { - return 0; - } - - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - - buf = start; - memcpy(buf, &did, sizeof(did)); - buf += sizeof(did); - memcpy(buf, name, len); - *(buf + len) = '\0'; /* Make it a C-string. */ - key.dptr = (unsigned char *)start; - key.dsize = CNID_DID_LEN + len + 1; - data = tdb_fetch(db->tdb_didname, key); - if (!data.dptr) - return 0; - - memcpy(&id, data.dptr, sizeof(id)); - free(data.dptr); - return id; -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_lookup.c b/libatalk/cnid/tdb/cnid_tdb_lookup.c deleted file mode 100644 index 7c7bdff14c..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_lookup.c +++ /dev/null @@ -1,152 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" -#include <atalk/logger.h> - -cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did, const char *name, size_t len) -{ - char *buf; - struct _cnid_tdb_private *db; - TDB_DATA key, devdata, diddata, cniddata; - int devino = 1, didname = 1; - char dev[CNID_DEV_LEN]; - char ino[CNID_INO_LEN]; - uint32_t type_devino = (unsigned)-1; - uint32_t type_didname = (unsigned)-1; - uint32_t type; - int update = 0; - cnid_t id_devino = 0, id_didname = 0,id = 0; - - if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) { - return 0; - } - - if ((buf = (char *)make_tdb_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) { - LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long"); - return 0; - } - memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type)); - type = ntohl(type); - - memset(&key, 0, sizeof(key)); - memset(&devdata, 0, sizeof(devdata)); - memset(&diddata, 0, sizeof(diddata)); - memset(&cniddata, 0, sizeof(cniddata)); - - /* Look for a CNID. We have two options: dev/ino or did/name. If we - * only get a match in one of them, that means a file has moved. */ - memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN); - memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN); - - key.dptr = (unsigned char *)buf + CNID_DEVINO_OFS; - key.dsize = CNID_DEVINO_LEN; - cniddata = tdb_fetch(db->tdb_devino, key); - if (!cniddata.dptr) { - devino = 0; - } - else { - - key.dptr = cniddata.dptr; - key.dsize = sizeof(id); - - devdata = tdb_fetch(db->tdb_cnid, key); - free(cniddata.dptr); - if (devdata.dptr) { - memcpy(&id_devino, devdata.dptr, sizeof(cnid_t)); - memcpy(&type_devino, (char *)devdata.dptr +CNID_TYPE_OFS, sizeof(type_devino)); - type_devino = ntohl(type_devino); - } - else { - devino = 0; - } - } - - /* did/name now */ - key.dptr = (unsigned char *)buf + CNID_DID_OFS; - key.dsize = CNID_DID_LEN + len + 1; - cniddata = tdb_fetch(db->tdb_didname, key); - if (!cniddata.dptr) { - didname = 0; - } - else { - - key.dptr = cniddata.dptr; - key.dsize = sizeof(id); - - diddata = tdb_fetch(db->tdb_cnid, key); - free(cniddata.dptr); - if (diddata.dptr) { - memcpy(&id_didname, diddata.dptr, sizeof(cnid_t)); - memcpy(&type_didname, (char *)diddata.dptr +CNID_TYPE_OFS, sizeof(type_didname)); - type_didname = ntohl(type_didname); - } - else { - didname = 0; - } - } - /* Set id. Honor did/name over dev/ino as dev/ino isn't necessarily - * 1-1. */ - if (!devino && !didname) { - free(devdata.dptr); - free(diddata.dptr); - return 0; - } - - if (devino && didname && id_devino == id_didname && type_devino == type) { - /* the same */ - free(devdata.dptr); - free(diddata.dptr); - return id_didname; - } - - if (didname) { - id = id_didname; - /* we have a did:name - * if it's the same dev or not the same type - * just delete it - */ - if (!memcmp(dev, (char *)diddata.dptr + CNID_DEV_OFS, CNID_DEV_LEN) || - type_didname != type) { - if (cnid_tdb_delete(cdb, id) < 0) { - free(devdata.dptr); - free(diddata.dptr); - return 0; - } - } - else { - update = 1; - } - } - - if (devino) { - id = id_devino; - if (type_devino != type) { - /* same dev:inode but not same type one is a folder the other - * is a file,it's an inode reused, delete the record - */ - if (cnid_tdb_delete(cdb, id) < 0) { - free(devdata.dptr); - free(diddata.dptr); - return 0; - } - } - else { - update = 1; - } - } - free(devdata.dptr); - free(diddata.dptr); - if (!update) { - return 0; - } - - /* Fix up the database. */ - cnid_tdb_update(cdb, id, st, did, name, len); - return id; -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_nextid.c b/libatalk/cnid/tdb/cnid_tdb_nextid.c deleted file mode 100644 index 8e7b12616f..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_nextid.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" - -cnid_t cnid_tdb_nextid(struct _cnid_db *cdb) -{ - return CNID_INVALID; -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_open.c b/libatalk/cnid/tdb/cnid_tdb_open.c deleted file mode 100644 index 7e2558fe3c..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_open.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) - * All Rights Reserved. See COPYRIGHT. - * - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB -#include <sys/param.h> - -#include "cnid_tdb.h" -#include <atalk/logger.h> -#include <atalk/volume.h> - -#include <stdlib.h> -#define DBHOME ".AppleDB" -#define DBHOMELEN 9 /* strlen(DBHOME) +1 for / */ -#define DBLEN 12 -#define DBCNID "cnid2.tdb" - -#define DBVERSION_KEY "\0\0\0\0Version" -#define DBVERSION_KEYLEN (sizeof(DBVERSION_KEY)) -#define DBVERSION2 0x00000002U -#define DBVERSION DBVERSION2 - -static struct _cnid_db *cnid_tdb_new(struct vol *vol) -{ - struct _cnid_db *cdb; - - if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL) - return NULL; - - cdb->cnid_db_vol = vol; - - if ((cdb->cnid_db_private = calloc(1, sizeof(struct _cnid_tdb_private))) == NULL) { - free(cdb); - return NULL; - } - - /* Set up standard fields */ - cdb->cnid_db_flags = CNID_FLAG_PERSISTENT; - - cdb->cnid_add = cnid_tdb_add; - cdb->cnid_delete = cnid_tdb_delete; - cdb->cnid_get = cnid_tdb_get; - cdb->cnid_lookup = cnid_tdb_lookup; - cdb->cnid_nextid = NULL; /*cnid_tdb_nextid;*/ - cdb->cnid_resolve = cnid_tdb_resolve; - cdb->cnid_update = cnid_tdb_update; - cdb->cnid_close = cnid_tdb_close; - cdb->cnid_wipe = NULL; - - return cdb; -} - -/* ---------------------------- */ -struct _cnid_db *cnid_tdb_open(struct cnid_open_args *args) -{ - struct stat st; - struct _cnid_db *cdb; - struct _cnid_tdb_private *db; - size_t len; - char path[MAXPATHLEN + 1]; - TDB_DATA key, data; - int hash_size = 131071; - int tdb_flags = 0; - struct vol *vol = args->cnid_args_vol; - - if ((cdb = cnid_tdb_new(vol)) == NULL) { - LOG(log_error, logtype_default, "tdb_open: Unable to allocate memory for tdb"); - return NULL; - } - - if ((len = strlen(vol->v_path)) > (MAXPATHLEN - DBLEN - 1)) { - LOG(log_error, logtype_default, "tdb_open: Pathname too large: %s", vol->v_path); - return NULL; - } - - strcpy(path, vol->v_path); - if (path[len - 1] != '/') { - strcat(path, "/"); - len++; - } - - strcpy(path + len, DBHOME); - if (!(args->cnid_args_flags & CNID_FLAG_MEMORY)) { - if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~vol->v_umask) < 0)) { - LOG(log_error, logtype_default, "tdb_open: DBHOME mkdir failed for %s", path); - goto fail; - } - } - else { - hash_size = 0; - tdb_flags = TDB_INTERNAL; - } - strcat(path, "/"); - - db = (struct _cnid_tdb_private *)cdb->cnid_db_private; - - path[len + DBHOMELEN] = '\0'; - strcat(path, DBCNID); - - db->tdb_cnid = tdb_open(path, hash_size, tdb_flags , O_RDWR | O_CREAT, 0666 & ~vol->v_umask); - if (!db->tdb_cnid) { - LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path); - goto fail; - } - /* ------------- */ - db->tdb_didname = db->tdb_cnid; - db->tdb_devino = db->tdb_cnid; - - /* Check for version. This way we can update the database if we need - * to change the format in any way. */ - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - key.dptr = (unsigned char *)DBVERSION_KEY; - key.dsize = DBVERSION_KEYLEN; - - data = tdb_fetch(db->tdb_didname, key); - if (!data.dptr) { - uint32_t version = htonl(DBVERSION); - - data.dptr = (unsigned char *)&version; - data.dsize = sizeof(version); - if (tdb_store(db->tdb_didname, key, data, TDB_REPLACE)) { - LOG(log_error, logtype_default, "tdb_open: Error putting new version"); - goto fail; - } - } - else { - free(data.dptr); - } - - return cdb; - -fail: - free(cdb->cnid_db_private); - free(cdb); - - return NULL; -} - -struct _cnid_module cnid_tdb_module = { - "tdb", - {NULL, NULL}, - cnid_tdb_open, - CNID_FLAG_SETUID | CNID_FLAG_BLOCK -}; - - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_resolve.c b/libatalk/cnid/tdb/cnid_tdb_resolve.c deleted file mode 100644 index b999ca3e00..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_resolve.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" - -/* Return the did/name pair corresponding to a CNID. */ -char *cnid_tdb_resolve(struct _cnid_db *cdb, cnid_t * id, void *buffer, size_t len) -{ - struct _cnid_tdb_private *db; - TDB_DATA key, data; - - if (!cdb || !(db = cdb->cnid_db_private) || !id || !(*id)) { - return NULL; - } - key.dptr = (unsigned char *)id; - key.dsize = sizeof(cnid_t); - data = tdb_fetch(db->tdb_cnid, key); - if (data.dptr) - { - if (data.dsize < len && data.dsize > sizeof(cnid_t)) { - memcpy(id, (char *)data.dptr + +CNID_DID_OFS, sizeof(cnid_t)); - strcpy(buffer, (char *)data.dptr + CNID_NAME_OFS); - free(data.dptr); - return buffer; - } - free(data.dptr); - } - return NULL; -} - -#endif diff --git a/libatalk/cnid/tdb/cnid_tdb_update.c b/libatalk/cnid/tdb/cnid_tdb_update.c deleted file mode 100644 index 9688d866c5..0000000000 --- a/libatalk/cnid/tdb/cnid_tdb_update.c +++ /dev/null @@ -1,108 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef CNID_BACKEND_TDB - -#include "cnid_tdb.h" -#include <atalk/logger.h> - -int cnid_tdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st, - cnid_t did, const char *name, size_t len) -{ - struct _cnid_tdb_private *db; - TDB_DATA key, data, altdata; - - if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) { - return -1; - } - - memset(&key, 0, sizeof(key)); - memset(&altdata, 0, sizeof(altdata)); - - - /* Get the old info. search by dev/ino */ - data.dptr = make_tdb_data(cdb->cnid_db_flags, st, did, name, len); - data.dsize = CNID_HEADER_LEN + len + 1; - key.dptr = data.dptr +CNID_DEVINO_OFS; - key.dsize = CNID_DEVINO_LEN; - altdata = tdb_fetch(db->tdb_devino, key); - if (altdata.dptr) { - tdb_delete(db->tdb_devino, key); - - key.dptr = altdata.dptr; - key.dsize = sizeof(id); - - data = tdb_fetch(db->tdb_cnid, key); - tdb_delete(db->tdb_cnid, key); - free(altdata.dptr); - - if (data.dptr) { - key.dptr = (unsigned char *)data.dptr +CNID_DID_OFS; - key.dsize = data.dsize - CNID_DID_OFS; - tdb_delete(db->tdb_didname, key); - - free(data.dptr); - } - } - - /* search by did/name */ - data.dptr = make_tdb_data(cdb->cnid_db_flags, st, did, name, len); - data.dsize = CNID_HEADER_LEN + len + 1; - key.dptr = (unsigned char *)data.dptr +CNID_DID_OFS; - key.dsize = data.dsize - CNID_DID_OFS; - altdata = tdb_fetch(db->tdb_didname, key); - if (altdata.dptr) { - tdb_delete(db->tdb_didname, key); - - key.dptr = altdata.dptr; - key.dsize = sizeof(id); - data = tdb_fetch(db->tdb_cnid, key); - tdb_delete(db->tdb_cnid, key); - free(altdata.dptr); - - if (data.dptr) { - key.dptr = data.dptr +CNID_DEVINO_OFS; - key.dsize = CNID_DEVINO_LEN; - tdb_delete(db->tdb_devino, key); - free(data.dptr); - } - } - - - /* Make a new entry. */ - data.dptr = make_tdb_data(cdb->cnid_db_flags, st, did, name, len); - data.dsize = CNID_HEADER_LEN + len + 1; - memcpy(data.dptr, &id, sizeof(id)); - - /* Update the old CNID with the new info. */ - key.dptr = (unsigned char *) &id; - key.dsize = sizeof(id); - if (tdb_store(db->tdb_cnid, key, data, TDB_REPLACE)) { - goto update_err; - } - - /* Put in a new dev/ino mapping. */ - key.dptr = data.dptr +CNID_DEVINO_OFS; - key.dsize = CNID_DEVINO_LEN; - altdata.dptr = (unsigned char *) &id; - altdata.dsize = sizeof(id); - if (tdb_store(db->tdb_devino, key, altdata, TDB_REPLACE)) { - goto update_err; - } - /* put in a new did/name mapping. */ - key.dptr = (unsigned char *) data.dptr +CNID_DID_OFS; - key.dsize = data.dsize -CNID_DID_OFS; - - if (tdb_store(db->tdb_didname, key, altdata, TDB_REPLACE)) { - goto update_err; - } - - return 0; -update_err: - LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u", ntohl(id)); - return -1; - -} - -#endif diff --git a/libatalk/tdb/.gitignore b/libatalk/tdb/.gitignore deleted file mode 100644 index 1045c8c919..0000000000 --- a/libatalk/tdb/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -Makefile -Makefile.in -*.lo -*.la -.deps -.libs -.gitignore -spinlock.o tdb.o diff --git a/libatalk/tdb/Makefile.am b/libatalk/tdb/Makefile.am deleted file mode 100644 index 874baef6cb..0000000000 --- a/libatalk/tdb/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -# Makefile.am for libatalk/tdb/ - -noinst_LTLIBRARIES = libtdb.la -noinst_HEADERS = tdb_private.h -libtdb_la_SOURCES = check.c \ - dump.c \ - error.c \ - freelist.c \ - freelistcheck.c \ - io.c \ - lock.c \ - open.c \ - tdb.c \ - transaction.c \ - traverse.c - diff --git a/libatalk/tdb/check.c b/libatalk/tdb/check.c deleted file mode 100644 index f0a15f801b..0000000000 --- a/libatalk/tdb/check.c +++ /dev/null @@ -1,423 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Rusty Russell 2009 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ -#include "tdb_private.h" - -/* Since we opened it, these shouldn't fail unless it's recent corruption. */ -static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery) -{ - struct tdb_header hdr; - - if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), DOCONV()) == -1) - return false; - if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) - goto corrupt; - - CONVERT(hdr); - if (hdr.version != TDB_VERSION) - goto corrupt; - - if (hdr.rwlocks != 0) - goto corrupt; - - if (hdr.hash_size == 0) - goto corrupt; - - if (hdr.hash_size != tdb->header.hash_size) - goto corrupt; - - if (hdr.recovery_start != 0 && - hdr.recovery_start < TDB_DATA_START(tdb->header.hash_size)) - goto corrupt; - - *recovery = hdr.recovery_start; - return true; - -corrupt: - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "Header is corrupt\n")); - return false; -} - -/* Generic record header check. */ -static bool tdb_check_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec) -{ - tdb_off_t tailer; - - /* Check rec->next: 0 or points to record offset, aligned. */ - if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->header.hash_size)){ - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too small next %d\n", - off, rec->next)); - goto corrupt; - } - if (rec->next + sizeof(*rec) < rec->next) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too large next %d\n", - off, rec->next)); - goto corrupt; - } - if ((rec->next % TDB_ALIGNMENT) != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d misaligned next %d\n", - off, rec->next)); - goto corrupt; - } - if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0)) - goto corrupt; - - /* Check rec_len: similar to rec->next, implies next record. */ - if ((rec->rec_len % TDB_ALIGNMENT) != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d misaligned length %d\n", - off, rec->rec_len)); - goto corrupt; - } - /* Must fit tailer. */ - if (rec->rec_len < sizeof(tailer)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too short length %d\n", - off, rec->rec_len)); - goto corrupt; - } - /* OOB allows "right at the end" access, so this works for last rec. */ - if (tdb->methods->tdb_oob(tdb, off+sizeof(*rec)+rec->rec_len, 0)) - goto corrupt; - - /* Check tailer. */ - if (tdb_ofs_read(tdb, off+sizeof(*rec)+rec->rec_len-sizeof(tailer), - &tailer) == -1) - goto corrupt; - if (tailer != sizeof(*rec) + rec->rec_len) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d invalid tailer\n", off)); - goto corrupt; - } - - return true; - -corrupt: - tdb->ecode = TDB_ERR_CORRUPT; - return false; -} - -/* Grab some bytes: may copy if can't use mmap. - Caller has already done bounds check. */ -static TDB_DATA get_bytes(struct tdb_context *tdb, - tdb_off_t off, tdb_len_t len) -{ - TDB_DATA d; - - d.dsize = len; - - if (tdb->transaction == NULL && tdb->map_ptr != NULL) - d.dptr = (unsigned char *)tdb->map_ptr + off; - else - d.dptr = tdb_alloc_read(tdb, off, d.dsize); - return d; -} - -/* Frees data if we're not able to simply use mmap. */ -static void put_bytes(struct tdb_context *tdb, TDB_DATA d) -{ - if (tdb->transaction == NULL && tdb->map_ptr != NULL) - return; - free(d.dptr); -} - -/* We use the excellent Jenkins lookup3 hash; this is based on hash_word2. - * See: http://burtleburtle.net/bob/c/lookup3.c - */ -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) -static void hash(uint32_t key, uint32_t *pc, uint32_t *pb) -{ - uint32_t a,b,c; - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + *pc; - c += *pb; - a += key; - c ^= b; c -= rot(b,14); - a ^= c; a -= rot(c,11); - b ^= a; b -= rot(a,25); - c ^= b; c -= rot(b,16); - a ^= c; a -= rot(c,4); - b ^= a; b -= rot(a,14); - c ^= b; c -= rot(b,24); - *pc=c; *pb=b; -} - -/* - We want to check that all free records are in the free list - (only once), and all free list entries are free records. Similarly - for each hash chain of used records. - - Doing that naively (without walking hash chains, since we want to be - linear) means keeping a list of records which have been seen in each - hash chain, and another of records pointed to (ie. next pointers - from records and the initial hash chain heads). These two lists - should be equal. This will take 8 bytes per record, and require - sorting at the end. - - So instead, we record each offset in a bitmap such a way that - recording it twice will cancel out. Since each offset should appear - exactly twice, the bitmap should be zero at the end. - - The approach was inspired by Bloom Filters (see Wikipedia). For - each value, we flip K bits in a bitmap of size N. The number of - distinct arrangements is: - - N! / (K! * (N-K)!) - - Of course, not all arrangements are actually distinct, but testing - shows this formula to be close enough. - - So, if K == 8 and N == 256, the probability of two things flipping the same - bits is 1 in 409,663,695,276,000. - - Given that ldb uses a hash size of 10000, using 32 bytes per hash chain - (320k) seems reasonable. -*/ -#define NUM_HASHES 8 -#define BITMAP_BITS 256 - -static void bit_flip(unsigned char bits[], unsigned int idx) -{ - bits[idx / CHAR_BIT] ^= (1 << (idx % CHAR_BIT)); -} - -/* We record offsets in a bitmap for the particular chain it should be in. */ -static void record_offset(unsigned char bits[], tdb_off_t off) -{ - uint32_t h1 = off, h2 = 0; - unsigned int i; - - /* We get two good hash values out of jhash2, so we use both. Then - * we keep going to produce further hash values. */ - for (i = 0; i < NUM_HASHES / 2; i++) { - hash(off, &h1, &h2); - bit_flip(bits, h1 % BITMAP_BITS); - bit_flip(bits, h2 % BITMAP_BITS); - h2++; - } -} - -/* Check that an in-use record is valid. */ -static bool tdb_check_used_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec, - unsigned char **hashes, - int (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data) -{ - TDB_DATA key, data; - - if (!tdb_check_record(tdb, off, rec)) - return false; - - /* key + data + tailer must fit in record */ - if (rec->key_len + rec->data_len + sizeof(tdb_off_t) > rec->rec_len) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too short for contents\n", off)); - return false; - } - - key = get_bytes(tdb, off + sizeof(*rec), rec->key_len); - if (!key.dptr) - return false; - - if (tdb->hash_fn(&key) != rec->full_hash) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d has incorrect hash\n", off)); - goto fail_put_key; - } - - /* Mark this offset as a known value for this hash bucket. */ - record_offset(hashes[BUCKET(rec->full_hash)+1], off); - /* And similarly if the next pointer is valid. */ - if (rec->next) - record_offset(hashes[BUCKET(rec->full_hash)+1], rec->next); - - /* If they supply a check function and this record isn't dead, - get data and feed it. */ - if (check && rec->magic != TDB_DEAD_MAGIC) { - data = get_bytes(tdb, off + sizeof(*rec) + rec->key_len, - rec->data_len); - if (!data.dptr) - goto fail_put_key; - - if (check(key, data, private_data) == -1) - goto fail_put_data; - put_bytes(tdb, data); - } - - put_bytes(tdb, key); - return true; - -fail_put_data: - put_bytes(tdb, data); -fail_put_key: - put_bytes(tdb, key); - return false; -} - -/* Check that an unused record is valid. */ -static bool tdb_check_free_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec, - unsigned char **hashes) -{ - if (!tdb_check_record(tdb, off, rec)) - return false; - - /* Mark this offset as a known value for the free list. */ - record_offset(hashes[0], off); - /* And similarly if the next pointer is valid. */ - if (rec->next) - record_offset(hashes[0], rec->next); - return true; -} - -int tdb_check(struct tdb_context *tdb, - int (*check)(TDB_DATA key, TDB_DATA data, void *private_data), - void *private_data) -{ - unsigned int h; - unsigned char **hashes; - tdb_off_t off, recovery_start; - struct tdb_record rec; - bool found_recovery = false; - - if (tdb_lockall(tdb) == -1) - return -1; - - /* Make sure we know true size of the underlying file. */ - tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1); - - /* Header must be OK: also gets us the recovery ptr, if any. */ - if (!tdb_check_header(tdb, &recovery_start)) - goto unlock; - - /* We should have the whole header, too. */ - if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n")); - goto unlock; - } - - /* One big malloc: pointers then bit arrays. */ - hashes = (unsigned char **)calloc( - 1, sizeof(hashes[0]) * (1+tdb->header.hash_size) - + BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size)); - if (!hashes) { - tdb->ecode = TDB_ERR_OOM; - goto unlock; - } - - /* Initialize pointers */ - hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]); - for (h = 1; h < 1+tdb->header.hash_size; h++) - hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT; - - /* Freelist and hash headers are all in a row: read them. */ - for (h = 0; h < 1+tdb->header.hash_size; h++) { - if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t), - &off) == -1) - goto free; - if (off) - record_offset(hashes[h], off); - } - - /* For each record, read it in and check it's ok. */ - for (off = TDB_DATA_START(tdb->header.hash_size); - off < tdb->map_size; - off += sizeof(rec) + rec.rec_len) { - if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), - DOCONV()) == -1) - goto free; - switch (rec.magic) { - case TDB_MAGIC: - case TDB_DEAD_MAGIC: - if (!tdb_check_used_record(tdb, off, &rec, hashes, - check, private_data)) - goto free; - break; - case TDB_FREE_MAGIC: - if (!tdb_check_free_record(tdb, off, &rec, hashes)) - goto free; - break; - case TDB_RECOVERY_MAGIC: - case 0: /* Used for invalid (or in-progress) recovery area. */ - if (recovery_start != off) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Unexpected recovery record at offset %d\n", - off)); - goto free; - } - found_recovery = true; - break; - default: - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Bad magic 0x%x at offset %d\n", - rec.magic, off)); - goto free; - } - } - - /* Now, hashes should all be empty: each record exists and is referred - * to by one other. */ - for (h = 0; h < 1+tdb->header.hash_size; h++) { - unsigned int i; - for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) { - if (hashes[h][i] != 0) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Hashes do not match records\n")); - goto free; - } - } - } - - /* We must have found recovery area if there was one. */ - if (recovery_start != 0 && !found_recovery) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Expected %s recovery area, got %s\n", - recovery_start ? "a" : "no", - found_recovery ? "one" : "none")); - goto free; - } - - free(hashes); - tdb_unlockall(tdb); - return 0; - -free: - free(hashes); -unlock: - tdb_unlockall(tdb); - return -1; -} diff --git a/libatalk/tdb/dump.c b/libatalk/tdb/dump.c deleted file mode 100644 index bdcbfab139..0000000000 --- a/libatalk/tdb/dump.c +++ /dev/null @@ -1,137 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash, - tdb_off_t offset) -{ - struct tdb_record rec; - tdb_off_t tailer_ofs, tailer; - - if (tdb->methods->tdb_read(tdb, offset, (char *)&rec, - sizeof(rec), DOCONV()) == -1) { - printf("ERROR: failed to read record at %u\n", offset); - return 0; - } - - printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d " - "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n", - hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, - rec.full_hash, rec.magic); - - tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t); - - if (tdb_ofs_read(tdb, tailer_ofs, &tailer) == -1) { - printf("ERROR: failed to read tailer at %u\n", tailer_ofs); - return rec.next; - } - - if (tailer != rec.rec_len + sizeof(rec)) { - printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n", - (unsigned int)tailer, (unsigned int)(rec.rec_len + sizeof(rec))); - } - return rec.next; -} - -static int tdb_dump_chain(struct tdb_context *tdb, int i) -{ - tdb_off_t rec_ptr, top; - - top = TDB_HASH_TOP(i); - - if (tdb_lock(tdb, i, F_WRLCK) != 0) - return -1; - - if (tdb_ofs_read(tdb, top, &rec_ptr) == -1) - return tdb_unlock(tdb, i, F_WRLCK); - - if (rec_ptr) - printf("hash=%d\n", i); - - while (rec_ptr) { - rec_ptr = tdb_dump_record(tdb, i, rec_ptr); - } - - return tdb_unlock(tdb, i, F_WRLCK); -} - -void tdb_dump_all(struct tdb_context *tdb) -{ - int i; - for (i=0;i<tdb->header.hash_size;i++) { - tdb_dump_chain(tdb, i); - } - printf("freelist:\n"); - tdb_dump_chain(tdb, -1); -} - -int tdb_printfreelist(struct tdb_context *tdb) -{ - int ret; - long total_free = 0; - tdb_off_t offset, rec_ptr; - struct tdb_record rec; - - if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0) - return ret; - - offset = FREELIST_TOP; - - /* read in the freelist top */ - if (tdb_ofs_read(tdb, offset, &rec_ptr) == -1) { - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - } - - printf("freelist top=[0x%08x]\n", rec_ptr ); - while (rec_ptr) { - if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec, - sizeof(rec), DOCONV()) == -1) { - tdb_unlock(tdb, -1, F_WRLCK); - return -1; - } - - if (rec.magic != TDB_FREE_MAGIC) { - printf("bad magic 0x%08x in free list\n", rec.magic); - tdb_unlock(tdb, -1, F_WRLCK); - return -1; - } - - printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n", - rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len); - total_free += rec.rec_len; - - /* move to the next record */ - rec_ptr = rec.next; - } - printf("total rec_len = [0x%08x (%d)]\n", (int)total_free, - (int)total_free); - - return tdb_unlock(tdb, -1, F_WRLCK); -} - diff --git a/libatalk/tdb/error.c b/libatalk/tdb/error.c deleted file mode 100644 index 195ab23815..0000000000 --- a/libatalk/tdb/error.c +++ /dev/null @@ -1,57 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -enum TDB_ERROR tdb_error(struct tdb_context *tdb) -{ - return tdb->ecode; -} - -static struct tdb_errname { - enum TDB_ERROR ecode; const char *estring; -} emap[] = { {TDB_SUCCESS, "Success"}, - {TDB_ERR_CORRUPT, "Corrupt database"}, - {TDB_ERR_IO, "IO Error"}, - {TDB_ERR_LOCK, "Locking error"}, - {TDB_ERR_OOM, "Out of memory"}, - {TDB_ERR_EXISTS, "Record exists"}, - {TDB_ERR_NOLOCK, "Lock exists on other keys"}, - {TDB_ERR_EINVAL, "Invalid parameter"}, - {TDB_ERR_NOEXIST, "Record does not exist"}, - {TDB_ERR_RDONLY, "write not permitted"} }; - -/* Error string for the last tdb error */ -const char *tdb_errorstr(struct tdb_context *tdb) -{ - uint32_t i; - for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++) - if (tdb->ecode == emap[i].ecode) - return emap[i].estring; - return "Invalid error code"; -} - diff --git a/libatalk/tdb/freelist.c b/libatalk/tdb/freelist.c deleted file mode 100644 index 8113b54951..0000000000 --- a/libatalk/tdb/freelist.c +++ /dev/null @@ -1,386 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -/* 'right' merges can involve O(n^2) cost when combined with a - traverse, so they are disabled until we find a way to do them in - O(1) time -*/ -#define USE_RIGHT_MERGES 0 - -/* read a freelist record and check for simple errors */ -int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct tdb_record *rec) -{ - if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1) - return -1; - - if (rec->magic == TDB_MAGIC) { - /* this happens when a app is showdown while deleting a record - we should - not completely fail when this happens */ - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n", - rec->magic, off)); - rec->magic = TDB_FREE_MAGIC; - if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1) - return -1; - } - - if (rec->magic != TDB_FREE_MAGIC) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n", - rec->magic, off)); - return -1; - } - if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0) - return -1; - return 0; -} - - -#if USE_RIGHT_MERGES -/* Remove an element from the freelist. Must have alloc lock. */ -static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_t next) -{ - tdb_off_t last_ptr, i; - - /* read in the freelist top */ - last_ptr = FREELIST_TOP; - while (tdb_ofs_read(tdb, last_ptr, &i) != -1 && i != 0) { - if (i == off) { - /* We've found it! */ - return tdb_ofs_write(tdb, last_ptr, &next); - } - /* Follow chain (next offset is at start of record) */ - last_ptr = i; - } - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off)); - return -1; -} -#endif - - -/* update a record tailer (must hold allocation lock) */ -static int update_tailer(struct tdb_context *tdb, tdb_off_t offset, - const struct tdb_record *rec) -{ - tdb_off_t totalsize; - - /* Offset of tailer from record header */ - totalsize = sizeof(*rec) + rec->rec_len; - return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t), - &totalsize); -} - -/* Add an element into the freelist. Merge adjacent records if - neccessary. */ -int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) -{ - /* Allocation and tailer lock */ - if (tdb_lock(tdb, -1, F_WRLCK) != 0) - return -1; - - /* set an initial tailer, so if we fail we don't leave a bogus record */ - if (update_tailer(tdb, offset, rec) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n")); - goto fail; - } - -#if USE_RIGHT_MERGES - /* Look right first (I'm an Australian, dammit) */ - if (offset + sizeof(*rec) + rec->rec_len + sizeof(*rec) <= tdb->map_size) { - tdb_off_t right = offset + sizeof(*rec) + rec->rec_len; - struct tdb_record r; - - if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right)); - goto left; - } - - /* If it's free, expand to include it. */ - if (r.magic == TDB_FREE_MAGIC) { - if (remove_from_freelist(tdb, right, r.next) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right)); - goto left; - } - rec->rec_len += sizeof(r) + r.rec_len; - if (update_tailer(tdb, offset, rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset)); - goto fail; - } - } - } -left: -#endif - - /* Look left */ - if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) { - tdb_off_t left = offset - sizeof(tdb_off_t); - struct tdb_record l; - tdb_off_t leftsize; - - /* Read in tailer and jump back to header */ - if (tdb_ofs_read(tdb, left, &leftsize) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left)); - goto update; - } - - /* it could be uninitialised data */ - if (leftsize == 0 || leftsize == TDB_PAD_U32) { - goto update; - } - - left = offset - leftsize; - - if (leftsize > offset || - left < TDB_DATA_START(tdb->header.hash_size)) { - goto update; - } - - /* Now read in the left record */ - if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize)); - goto update; - } - - /* If it's free, expand to include it. */ - if (l.magic == TDB_FREE_MAGIC) { - /* we now merge the new record into the left record, rather than the other - way around. This makes the operation O(1) instead of O(n). This change - prevents traverse from being O(n^2) after a lot of deletes */ - l.rec_len += sizeof(*rec) + rec->rec_len; - if (tdb_rec_write(tdb, left, &l) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left)); - goto fail; - } - if (update_tailer(tdb, left, &l) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset)); - goto fail; - } - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - } - } - -update: - - /* Now, prepend to free list */ - rec->magic = TDB_FREE_MAGIC; - - if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 || - tdb_rec_write(tdb, offset, rec) == -1 || - tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset)); - goto fail; - } - - /* And we're done. */ - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return -1; -} - - - -/* - the core of tdb_allocate - called when we have decided which - free list entry to use - - Note that we try to allocate by grabbing data from the end of an existing record, - not the beginning. This is so the left merge in a free is more likely to be - able to free up the record without fragmentation - */ -static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, - tdb_len_t length, tdb_off_t rec_ptr, - struct tdb_record *rec, tdb_off_t last_ptr) -{ -#define MIN_REC_SIZE (sizeof(struct tdb_record) + sizeof(tdb_off_t) + 8) - - if (rec->rec_len < length + MIN_REC_SIZE) { - /* we have to grab the whole record */ - - /* unlink it from the previous record */ - if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) { - return 0; - } - - /* mark it not free */ - rec->magic = TDB_MAGIC; - if (tdb_rec_write(tdb, rec_ptr, rec) == -1) { - return 0; - } - return rec_ptr; - } - - /* we're going to just shorten the existing record */ - rec->rec_len -= (length + sizeof(*rec)); - if (tdb_rec_write(tdb, rec_ptr, rec) == -1) { - return 0; - } - if (update_tailer(tdb, rec_ptr, rec) == -1) { - return 0; - } - - /* and setup the new record */ - rec_ptr += sizeof(*rec) + rec->rec_len; - - memset(rec, '\0', sizeof(*rec)); - rec->rec_len = length; - rec->magic = TDB_MAGIC; - - if (tdb_rec_write(tdb, rec_ptr, rec) == -1) { - return 0; - } - - if (update_tailer(tdb, rec_ptr, rec) == -1) { - return 0; - } - - return rec_ptr; -} - -/* allocate some space from the free list. The offset returned points - to a unconnected tdb_record within the database with room for at - least length bytes of total data - - 0 is returned if the space could not be allocated - */ -tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec) -{ - tdb_off_t rec_ptr, last_ptr, newrec_ptr; - struct { - tdb_off_t rec_ptr, last_ptr; - tdb_len_t rec_len; - } bestfit; - float multiplier = 1.0; - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) - return 0; - - /* over-allocate to reduce fragmentation */ - length *= 1.25; - - /* Extra bytes required for tailer */ - length += sizeof(tdb_off_t); - length = TDB_ALIGN(length, TDB_ALIGNMENT); - - again: - last_ptr = FREELIST_TOP; - - /* read in the freelist top */ - if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) - goto fail; - - bestfit.rec_ptr = 0; - bestfit.last_ptr = 0; - bestfit.rec_len = 0; - - /* - this is a best fit allocation strategy. Originally we used - a first fit strategy, but it suffered from massive fragmentation - issues when faced with a slowly increasing record size. - */ - while (rec_ptr) { - if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) { - goto fail; - } - - if (rec->rec_len >= length) { - if (bestfit.rec_ptr == 0 || - rec->rec_len < bestfit.rec_len) { - bestfit.rec_len = rec->rec_len; - bestfit.rec_ptr = rec_ptr; - bestfit.last_ptr = last_ptr; - } - } - - /* move to the next record */ - last_ptr = rec_ptr; - rec_ptr = rec->next; - - /* if we've found a record that is big enough, then - stop searching if its also not too big. The - definition of 'too big' changes as we scan - through */ - if (bestfit.rec_len > 0 && - bestfit.rec_len < length * multiplier) { - break; - } - - /* this multiplier means we only extremely rarely - search more than 50 or so records. At 50 records we - accept records up to 11 times larger than what we - want */ - multiplier *= 1.05; - } - - if (bestfit.rec_ptr != 0) { - if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) { - goto fail; - } - - newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, - rec, bestfit.last_ptr); - tdb_unlock(tdb, -1, F_WRLCK); - return newrec_ptr; - } - - /* we didn't find enough space. See if we can expand the - database and if we can then try again */ - if (tdb_expand(tdb, length + sizeof(*rec)) == 0) - goto again; - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return 0; -} - - - -/* - return the size of the freelist - used to decide if we should repack -*/ -int tdb_freelist_size(struct tdb_context *tdb) -{ - tdb_off_t ptr; - int count=0; - - if (tdb_lock(tdb, -1, F_RDLCK) == -1) { - return -1; - } - - ptr = FREELIST_TOP; - while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) { - count++; - } - - tdb_unlock(tdb, -1, F_RDLCK); - return count; -} diff --git a/libatalk/tdb/freelistcheck.c b/libatalk/tdb/freelistcheck.c deleted file mode 100644 index 8d1ebabe04..0000000000 --- a/libatalk/tdb/freelistcheck.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Jeremy Allison 2006 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -/* Check the freelist is good and contains no loops. - Very memory intensive - only do this as a consistency - checker. Heh heh - uses an in memory tdb as the storage - for the "seen" record list. For some reason this strikes - me as extremely clever as I don't have to write another tree - data structure implementation :-). - */ - -static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr) -{ - TDB_DATA key, data; - - memset(&data, '\0', sizeof(data)); - key.dptr = (unsigned char *)&rec_ptr; - key.dsize = sizeof(rec_ptr); - return tdb_store(mem_tdb, key, data, TDB_INSERT); -} - -int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) -{ - struct tdb_context *mem_tdb = NULL; - struct tdb_record rec; - tdb_off_t rec_ptr, last_ptr; - int ret = -1; - - *pnum_entries = 0; - - mem_tdb = tdb_open("flval", tdb->header.hash_size, - TDB_INTERNAL, O_RDWR, 0600); - if (!mem_tdb) { - return -1; - } - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - tdb_close(mem_tdb); - return 0; - } - - last_ptr = FREELIST_TOP; - - /* Store the FREELIST_TOP record. */ - if (seen_insert(mem_tdb, last_ptr) == -1) { - tdb->ecode = TDB_ERR_CORRUPT; - ret = -1; - goto fail; - } - - /* read in the freelist top */ - if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) { - goto fail; - } - - while (rec_ptr) { - - /* If we can't store this record (we've seen it - before) then the free list has a loop and must - be corrupt. */ - - if (seen_insert(mem_tdb, rec_ptr)) { - tdb->ecode = TDB_ERR_CORRUPT; - ret = -1; - goto fail; - } - - if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) { - goto fail; - } - - /* move to the next record */ - last_ptr = rec_ptr; - rec_ptr = rec.next; - *pnum_entries += 1; - } - - ret = 0; - - fail: - - tdb_close(mem_tdb); - tdb_unlock(tdb, -1, F_WRLCK); - return ret; -} diff --git a/libatalk/tdb/io.c b/libatalk/tdb/io.c deleted file mode 100644 index 88ff7accd4..0000000000 --- a/libatalk/tdb/io.c +++ /dev/null @@ -1,472 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -/* check for an out of bounds access - if it is out of bounds then - see if the database has been expanded by someone else and expand - if necessary - note that "len" is the minimum length needed for the db -*/ -static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe) -{ - struct stat st; - if (len <= tdb->map_size) - return 0; - if (tdb->flags & TDB_INTERNAL) { - if (!probe) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n", - (int)len, (int)tdb->map_size)); - } - return -1; - } - - if (fstat(tdb->fd, &st) == -1) { - tdb->ecode = TDB_ERR_IO; - return -1; - } - - if (st.st_size < (size_t)len) { - if (!probe) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n", - (int)len, (int)st.st_size)); - } - return -1; - } - - /* Unmap, update size, remap */ - if (tdb_munmap(tdb) == -1) { - tdb->ecode = TDB_ERR_IO; - return -1; - } - tdb->map_size = st.st_size; - tdb_mmap(tdb); - return 0; -} - -/* write a lump of data at a specified offset */ -static int tdb_write(struct tdb_context *tdb, tdb_off_t off, - const void *buf, tdb_len_t len) -{ - if (len == 0) { - return 0; - } - - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) - return -1; - - if (tdb->map_ptr) { - memcpy(off + (char *)tdb->map_ptr, buf, len); - } else { - ssize_t written = pwrite(tdb->fd, buf, len, off); - if ((written != (ssize_t)len) && (written != -1)) { - /* try once more */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only " - "%d of %d bytes at %d, trying once more\n", - (int)written, len, off)); - written = pwrite(tdb->fd, (const char *)buf+written, - len-written, - off+written); - } - if (written == -1) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d " - "len=%d (%s)\n", off, len, strerror(errno))); - return -1; - } else if (written != (ssize_t)len) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to " - "write %d bytes at %d in two attempts\n", - len, off)); - return -1; - } - } - return 0; -} - -/* Endian conversion: we only ever deal with 4 byte quantities */ -void *tdb_convert(void *buf, uint32_t size) -{ - uint32_t i, *p = (uint32_t *)buf; - for (i = 0; i < size / 4; i++) - p[i] = TDB_BYTEREV(p[i]); - return buf; -} - - -/* read a lump of data at a specified offset, maybe convert */ -static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, - tdb_len_t len, int cv) -{ - if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) { - return -1; - } - - if (tdb->map_ptr) { - memcpy(buf, off + (char *)tdb->map_ptr, len); - } else { - ssize_t ret = pread(tdb->fd, buf, len, off); - if (ret != (ssize_t)len) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d " - "len=%d ret=%d (%s) map_size=%d\n", - (int)off, (int)len, (int)ret, strerror(errno), - (int)tdb->map_size)); - return -1; - } - } - if (cv) { - tdb_convert(buf, len); - } - return 0; -} - - - -/* - do an unlocked scan of the hash table heads to find the next non-zero head. The value - will then be confirmed with the lock held -*/ -static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain) -{ - uint32_t h = *chain; - if (tdb->map_ptr) { - for (;h < tdb->header.hash_size;h++) { - if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) { - break; - } - } - } else { - uint32_t off=0; - for (;h < tdb->header.hash_size;h++) { - if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) { - break; - } - } - } - (*chain) = h; -} - - -int tdb_munmap(struct tdb_context *tdb) -{ - if (tdb->flags & TDB_INTERNAL) - return 0; - -#ifdef HAVE_MMAP - if (tdb->map_ptr) { - int ret; - - ret = munmap(tdb->map_ptr, tdb->map_size); - if (ret != 0) - return ret; - } -#endif - tdb->map_ptr = NULL; - return 0; -} - -void tdb_mmap(struct tdb_context *tdb) -{ - if (tdb->flags & TDB_INTERNAL) - return; - -#ifdef HAVE_MMAP - if (!(tdb->flags & TDB_NOMMAP)) { - tdb->map_ptr = mmap(NULL, tdb->map_size, - PROT_READ|(tdb->read_only? 0:PROT_WRITE), - MAP_SHARED, tdb->fd, 0); - - /* - * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!! - */ - - if (tdb->map_ptr == MAP_FAILED) { - tdb->map_ptr = NULL; - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", - tdb->map_size, strerror(errno))); - } - } else { - tdb->map_ptr = NULL; - } -#else - tdb->map_ptr = NULL; -#endif -} - -/* expand a file. we prefer to use ftruncate, as that is what posix - says to use for mmap expansion */ -static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition) -{ - char buf[8192]; - - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - if (ftruncate(tdb->fd, size+addition) == -1) { - char b = 0; - ssize_t written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); - if (written == 0) { - /* try once more, potentially revealing errno */ - written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); - } - if (written == 0) { - /* again - give up, guessing errno */ - errno = ENOSPC; - } - if (written != 1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", - size+addition, strerror(errno))); - return -1; - } - } - - /* now fill the file with something. This ensures that the - file isn't sparse, which would be very bad if we ran out of - disk. This must be done with write, not via mmap */ - memset(buf, TDB_PAD_BYTE, sizeof(buf)); - while (addition) { - size_t n = addition>sizeof(buf)?sizeof(buf):addition; - ssize_t written = pwrite(tdb->fd, buf, n, size); - if (written == 0) { - /* prevent infinite loops: try _once_ more */ - written = pwrite(tdb->fd, buf, n, size); - } - if (written == 0) { - /* give up, trying to provide a useful errno */ - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write " - "returned 0 twice: giving up!\n")); - errno = ENOSPC; - return -1; - } else if (written == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of " - "%d bytes failed (%s)\n", (int)n, - strerror(errno))); - return -1; - } else if (written != n) { - TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote " - "only %d of %d bytes - retrying\n", (int)written, - (int)n)); - } - addition -= written; - size += written; - } - return 0; -} - - -/* expand the database at least size bytes by expanding the underlying - file and doing the mmap again if necessary */ -int tdb_expand(struct tdb_context *tdb, tdb_off_t size) -{ - struct tdb_record rec; - tdb_off_t offset, new_size; - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n")); - return -1; - } - - /* must know about any previous expansions by another process */ - tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1); - - /* always make room for at least 100 more records, and at - least 25% more space. Round the database up to a multiple - of the page size */ - new_size = MAX(tdb->map_size + size*100, tdb->map_size * 1.25); - size = TDB_ALIGN(new_size, tdb->page_size) - tdb->map_size; - - if (!(tdb->flags & TDB_INTERNAL)) - tdb_munmap(tdb); - - /* - * We must ensure the file is unmapped before doing this - * to ensure consistency with systems like OpenBSD where - * writes and mmaps are not consistent. - */ - - /* expand the file itself */ - if (!(tdb->flags & TDB_INTERNAL)) { - if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0) - goto fail; - } - - tdb->map_size += size; - - if (tdb->flags & TDB_INTERNAL) { - char *new_map_ptr = (char *)realloc(tdb->map_ptr, - tdb->map_size); - if (!new_map_ptr) { - tdb->map_size -= size; - goto fail; - } - tdb->map_ptr = new_map_ptr; - } else { - /* - * We must ensure the file is remapped before adding the space - * to ensure consistency with systems like OpenBSD where - * writes and mmaps are not consistent. - */ - - /* We're ok if the mmap fails as we'll fallback to read/write */ - tdb_mmap(tdb); - } - - /* form a new freelist record */ - memset(&rec,'\0',sizeof(rec)); - rec.rec_len = size - sizeof(rec); - - /* link it into the free list */ - offset = tdb->map_size - size; - if (tdb_free(tdb, offset, &rec) == -1) - goto fail; - - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return -1; -} - -/* read/write a tdb_off_t */ -int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d) -{ - return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV()); -} - -int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d) -{ - tdb_off_t off = *d; - return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d)); -} - - -/* read a lump of data, allocating the space for it */ -unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len) -{ - unsigned char *buf; - - /* some systems don't like zero length malloc */ - - if (!(buf = (unsigned char *)malloc(len ? len : 1))) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_OOM; - TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n", - len, strerror(errno))); - return NULL; - } - if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) { - SAFE_FREE(buf); - return NULL; - } - return buf; -} - -/* Give a piece of tdb data to a parser */ - -int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key, - tdb_off_t offset, tdb_len_t len, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) -{ - TDB_DATA data; - int result; - - data.dsize = len; - - if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) { - /* - * Optimize by avoiding the malloc/memcpy/free, point the - * parser directly at the mmap area. - */ - if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) { - return -1; - } - data.dptr = offset + (unsigned char *)tdb->map_ptr; - return parser(key, data, private_data); - } - - if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) { - return -1; - } - - result = parser(key, data, private_data); - free(data.dptr); - return result; -} - -/* read/write a record */ -int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) -{ - if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1) - return -1; - if (TDB_BAD_MAGIC(rec)) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset)); - return -1; - } - return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0); -} - -int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) -{ - struct tdb_record r = *rec; - return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r)); -} - -static const struct tdb_methods io_methods = { - tdb_read, - tdb_write, - tdb_next_hash_chain, - tdb_oob, - tdb_expand_file, - tdb_brlock -}; - -/* - initialise the default methods table -*/ -void tdb_io_init(struct tdb_context *tdb) -{ - tdb->methods = &io_methods; -} diff --git a/libatalk/tdb/lock.c b/libatalk/tdb/lock.c deleted file mode 100644 index 0984e516ea..0000000000 --- a/libatalk/tdb/lock.c +++ /dev/null @@ -1,592 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -#define TDB_MARK_LOCK 0x80000000 - -void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) -{ - tdb->interrupt_sig_ptr = ptr; -} - -/* a byte range locking function - return 0 on success - this functions locks/unlocks 1 byte at the specified offset. - - On error, errno is also set so that errors are passed back properly - through tdb_open(). - - note that a len of zero means lock to end of file -*/ -int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, - int rw_type, int lck_type, int probe, size_t len) -{ - struct flock fl; - int ret; - - if (tdb->flags & TDB_NOLOCK) { - return 0; - } - - if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - fl.l_type = rw_type; - fl.l_whence = SEEK_SET; - fl.l_start = offset; - fl.l_len = len; - fl.l_pid = 0; - - do { - ret = fcntl(tdb->fd,lck_type,&fl); - - /* Check for a sigalarm break. */ - if (ret == -1 && errno == EINTR && - tdb->interrupt_sig_ptr && - *tdb->interrupt_sig_ptr) { - break; - } - } while (ret == -1 && errno == EINTR); - - if (ret == -1) { - tdb->ecode = TDB_ERR_LOCK; - /* Generic lock error. errno set by fcntl. - * EAGAIN is an expected return from non-blocking - * locks. */ - if (!probe && lck_type != F_SETLK) { - TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n", - tdb->fd, offset, rw_type, lck_type, (int)len)); - } - return -1; - } - return 0; -} - - -/* - upgrade a read lock to a write lock. This needs to be handled in a - special way as some OSes (such as solaris) have too conservative - deadlock detection and claim a deadlock when progress can be - made. For those OSes we may loop for a while. -*/ -int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len) -{ - int count = 1000; - while (count--) { - struct timeval tv; - if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) { - return 0; - } - if (errno != EDEADLK) { - break; - } - /* sleep for as short a time as we can - more portable than usleep() */ - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, NULL, NULL, NULL, &tv); - } - TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock_upgrade failed at offset %d\n", offset)); - return -1; -} - - -/* lock a list in the database. list -1 is the alloc list */ -static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op) -{ - struct tdb_lock_type *new_lck; - int i; - bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); - - ltype &= ~TDB_MARK_LOCK; - - /* a global lock allows us to avoid per chain locks */ - if (tdb->global_lock.count && - (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { - return 0; - } - - if (tdb->global_lock.count) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (list < -1 || list >= (int)tdb->header.hash_size) { - tdb->ecode = TDB_ERR_LOCK; - TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n", - list, ltype)); - return -1; - } - if (tdb->flags & TDB_NOLOCK) - return 0; - - for (i=0; i<tdb->num_lockrecs; i++) { - if (tdb->lockrecs[i].list == list) { - if (tdb->lockrecs[i].count == 0) { - /* - * Can't happen, see tdb_unlock(). It should - * be an assert. - */ - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: " - "lck->count == 0 for list %d", list)); - } - /* - * Just increment the in-memory struct, posix locks - * don't stack. - */ - tdb->lockrecs[i].count++; - return 0; - } - } - - new_lck = (struct tdb_lock_type *)realloc( - tdb->lockrecs, - sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1)); - if (new_lck == NULL) { - errno = ENOMEM; - return -1; - } - tdb->lockrecs = new_lck; - - /* Since fcntl locks don't nest, we do a lock for the first one, - and simply bump the count for future ones */ - if (!mark_lock && - tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list, ltype, op, - 0, 1)) { - return -1; - } - - tdb->num_locks++; - - tdb->lockrecs[tdb->num_lockrecs].list = list; - tdb->lockrecs[tdb->num_lockrecs].count = 1; - tdb->lockrecs[tdb->num_lockrecs].ltype = ltype; - tdb->num_lockrecs += 1; - - return 0; -} - -/* lock a list in the database. list -1 is the alloc list */ -int tdb_lock(struct tdb_context *tdb, int list, int ltype) -{ - int ret; - ret = _tdb_lock(tdb, list, ltype, F_SETLKW); - if (ret) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d " - "ltype=%d (%s)\n", list, ltype, strerror(errno))); - } - return ret; -} - -/* lock a list in the database. list -1 is the alloc list. non-blocking lock */ -int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype) -{ - return _tdb_lock(tdb, list, ltype, F_SETLK); -} - - -/* unlock the database: returns void because it's too late for errors. */ - /* changed to return int it may be interesting to know there - has been an error --simo */ -int tdb_unlock(struct tdb_context *tdb, int list, int ltype) -{ - int ret = -1; - int i; - struct tdb_lock_type *lck = NULL; - bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); - - ltype &= ~TDB_MARK_LOCK; - - /* a global lock allows us to avoid per chain locks */ - if (tdb->global_lock.count && - (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { - return 0; - } - - if (tdb->global_lock.count) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->flags & TDB_NOLOCK) - return 0; - - /* Sanity checks */ - if (list < -1 || list >= (int)tdb->header.hash_size) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size)); - return ret; - } - - for (i=0; i<tdb->num_lockrecs; i++) { - if (tdb->lockrecs[i].list == list) { - lck = &tdb->lockrecs[i]; - break; - } - } - - if ((lck == NULL) || (lck->count == 0)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n")); - return -1; - } - - if (lck->count > 1) { - lck->count--; - return 0; - } - - /* - * This lock has count==1 left, so we need to unlock it in the - * kernel. We don't bother with decrementing the in-memory array - * element, we're about to overwrite it with the last array element - * anyway. - */ - - if (mark_lock) { - ret = 0; - } else { - ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, - F_SETLKW, 0, 1); - } - tdb->num_locks--; - - /* - * Shrink the array by overwriting the element just unlocked with the - * last array element. - */ - - if (tdb->num_lockrecs > 1) { - *lck = tdb->lockrecs[tdb->num_lockrecs-1]; - } - tdb->num_lockrecs -= 1; - - /* - * We don't bother with realloc when the array shrinks, but if we have - * a completely idle tdb we should get rid of the locked array. - */ - - if (tdb->num_lockrecs == 0) { - SAFE_FREE(tdb->lockrecs); - } - - if (ret) - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); - return ret; -} - -/* - get the transaction lock - */ -int tdb_transaction_lock(struct tdb_context *tdb, int ltype) -{ - if (tdb->global_lock.count) { - return 0; - } - if (tdb->transaction_lock_count > 0) { - tdb->transaction_lock_count++; - return 0; - } - - if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype, - F_SETLKW, 0, 1) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n")); - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - tdb->transaction_lock_count++; - return 0; -} - -/* - release the transaction lock - */ -int tdb_transaction_unlock(struct tdb_context *tdb) -{ - int ret; - if (tdb->global_lock.count) { - return 0; - } - if (tdb->transaction_lock_count > 1) { - tdb->transaction_lock_count--; - return 0; - } - ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); - if (ret == 0) { - tdb->transaction_lock_count = 0; - } - return ret; -} - - - - -/* lock/unlock entire database */ -static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op) -{ - bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); - - ltype &= ~TDB_MARK_LOCK; - - /* There are no locks on read-only dbs */ - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) { - tdb->global_lock.count++; - return 0; - } - - if (tdb->global_lock.count) { - /* a global lock of a different type exists */ - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->num_locks != 0) { - /* can't combine global and chain locks */ - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (!mark_lock && - tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op, - 0, 4*tdb->header.hash_size)) { - if (op == F_SETLKW) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno))); - } - return -1; - } - - tdb->global_lock.count = 1; - tdb->global_lock.ltype = ltype; - - return 0; -} - - - -/* unlock entire db */ -static int _tdb_unlockall(struct tdb_context *tdb, int ltype) -{ - bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); - - ltype &= ~TDB_MARK_LOCK; - - /* There are no locks on read-only dbs */ - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->global_lock.count > 1) { - tdb->global_lock.count--; - return 0; - } - - if (!mark_lock && - tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, - 0, 4*tdb->header.hash_size)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno))); - return -1; - } - - tdb->global_lock.count = 0; - tdb->global_lock.ltype = 0; - - return 0; -} - -/* lock entire database with write lock */ -int tdb_lockall(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall"); - return _tdb_lockall(tdb, F_WRLCK, F_SETLKW); -} - -/* lock entire database with write lock - mark only */ -int tdb_lockall_mark(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall_mark"); - return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW); -} - -/* unlock entire database with write lock - unmark only */ -int tdb_lockall_unmark(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall_unmark"); - return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK); -} - -/* lock entire database with write lock - nonblocking varient */ -int tdb_lockall_nonblock(struct tdb_context *tdb) -{ - int ret = _tdb_lockall(tdb, F_WRLCK, F_SETLK); - tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret); - return ret; -} - -/* unlock entire database with write lock */ -int tdb_unlockall(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_unlockall"); - return _tdb_unlockall(tdb, F_WRLCK); -} - -/* lock entire database with read lock */ -int tdb_lockall_read(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall_read"); - return _tdb_lockall(tdb, F_RDLCK, F_SETLKW); -} - -/* lock entire database with read lock - nonblock varient */ -int tdb_lockall_read_nonblock(struct tdb_context *tdb) -{ - int ret = _tdb_lockall(tdb, F_RDLCK, F_SETLK); - tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret); - return ret; -} - -/* unlock entire database with read lock */ -int tdb_unlockall_read(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_unlockall_read"); - return _tdb_unlockall(tdb, F_RDLCK); -} - -/* lock/unlock one hash chain. This is meant to be used to reduce - contention - it cannot guarantee how many records will be locked */ -int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) -{ - int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); - tdb_trace_1rec(tdb, "tdb_chainlock", key); - return ret; -} - -/* lock/unlock one hash chain, non-blocking. This is meant to be used - to reduce contention - it cannot guarantee how many records will be - locked */ -int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key) -{ - int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); - tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret); - return ret; -} - -/* mark a chain as locked without actually locking it. Warning! use with great caution! */ -int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) -{ - int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); - tdb_trace_1rec(tdb, "tdb_chainlock_mark", key); - return ret; -} - -/* unmark a chain as locked without actually locking it. Warning! use with great caution! */ -int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key); - return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); -} - -int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_trace_1rec(tdb, "tdb_chainunlock", key); - return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); -} - -int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) -{ - int ret; - ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); - tdb_trace_1rec(tdb, "tdb_chainlock_read", key); - return ret; -} - -int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_trace_1rec(tdb, "tdb_chainunlock_read", key); - return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); -} - - - -/* record lock stops delete underneath */ -int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off) -{ - if (tdb->global_lock.count) { - return 0; - } - return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0; -} - -/* - Write locks override our own fcntl readlocks, so check it here. - Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not - an error to fail to get the lock here. -*/ -int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off) -{ - struct tdb_traverse_lock *i; - for (i = &tdb->travlocks; i; i = i->next) - if (i->off == off) - return -1; - return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1); -} - -/* - Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not - an error to fail to get the lock here. -*/ -int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off) -{ - return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1); -} - -/* fcntl locks don't stack: avoid unlocking someone else's */ -int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off) -{ - struct tdb_traverse_lock *i; - uint32_t count = 0; - - if (tdb->global_lock.count) { - return 0; - } - - if (off == 0) - return 0; - for (i = &tdb->travlocks; i; i = i->next) - if (i->off == off) - count++; - return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0); -} diff --git a/libatalk/tdb/open.c b/libatalk/tdb/open.c deleted file mode 100644 index 4d4f95a3da..0000000000 --- a/libatalk/tdb/open.c +++ /dev/null @@ -1,552 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */ -static struct tdb_context *tdbs = NULL; - - -/* This is based on the hash algorithm from gdbm */ -static unsigned int default_tdb_hash(TDB_DATA *key) -{ - uint32_t value; /* Used to compute the hash value. */ - uint32_t i; /* Used to cycle through random values. */ - - /* Set the initial value from the key size. */ - for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) - value = (value + (key->dptr[i] << (i*5 % 24))); - - return (1103515243 * value + 12345); -} - - -/* initialise a new database with a specified hash size */ -static int tdb_new_database(struct tdb_context *tdb, int hash_size) -{ - struct tdb_header *newdb; - size_t size; - int ret = -1; - ssize_t written; - - /* We make it up in memory, then write it out if not internal */ - size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t); - if (!(newdb = (struct tdb_header *)calloc(size, 1))) { - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - /* Fill in the header */ - newdb->version = TDB_VERSION; - newdb->hash_size = hash_size; - if (tdb->flags & TDB_INTERNAL) { - tdb->map_size = size; - tdb->map_ptr = (char *)newdb; - memcpy(&tdb->header, newdb, sizeof(tdb->header)); - /* Convert the `ondisk' version if asked. */ - CONVERT(*newdb); - return 0; - } - if (lseek(tdb->fd, 0, SEEK_SET) == -1) - goto fail; - - if (ftruncate(tdb->fd, 0) == -1) - goto fail; - - /* This creates an endian-converted header, as if read from disk */ - CONVERT(*newdb); - memcpy(&tdb->header, newdb, sizeof(tdb->header)); - /* Don't endian-convert the magic food! */ - memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); - /* we still have "ret == -1" here */ - written = write(tdb->fd, newdb, size); - if (written == size) { - ret = 0; - } else if (written != -1) { - /* call write once again, this usually should return -1 and - * set errno appropriately */ - size -= written; - written = write(tdb->fd, newdb+written, size); - if (written == size) { - ret = 0; - } else if (written >= 0) { - /* a second incomplete write - we give up. - * guessing the errno... */ - errno = ENOSPC; - } - } - - fail: - SAFE_FREE(newdb); - return ret; -} - - - -static int tdb_already_open(dev_t device, - ino_t ino) -{ - struct tdb_context *i; - - for (i = tdbs; i; i = i->next) { - if (i->device == device && i->inode == ino) { - return 1; - } - } - - return 0; -} - -/* open the database, creating it if necessary - - The open_flags and mode are passed straight to the open call on the - database file. A flags value of O_WRONLY is invalid. The hash size - is advisory, use zero for a default value. - - Return is NULL on error, in which case errno is also set. Don't - try to call tdb_error or tdb_errname, just do strerror(errno). - - @param name may be NULL for internal databases. */ -struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode) -{ - return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL); -} - -/* a default logging function */ -static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); -static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) -{ -} - - -struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode, - const struct tdb_logging_context *log_ctx, - tdb_hash_func hash_fn) -{ - struct tdb_context *tdb; - struct stat st; - int rev = 0, locked = 0; - unsigned char *vp; - uint32_t vertest; - unsigned v; - - if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { - /* Can't log this */ - errno = ENOMEM; - goto fail; - } - tdb_io_init(tdb); - tdb->fd = -1; -#ifdef TDB_TRACE - tdb->tracefd = -1; -#endif - tdb->name = NULL; - tdb->map_ptr = NULL; - tdb->flags = tdb_flags; - tdb->open_flags = open_flags; - if (log_ctx) { - tdb->log = *log_ctx; - } else { - tdb->log.log_fn = null_log_fn; - tdb->log.log_private = NULL; - } - tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; - - /* cache the page size */ - tdb->page_size = getpagesize(); - if (tdb->page_size <= 0) { - tdb->page_size = 0x2000; - } - - tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0; - - if ((open_flags & O_ACCMODE) == O_WRONLY) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n", - name)); - errno = EINVAL; - goto fail; - } - - if (hash_size == 0) - hash_size = DEFAULT_HASH_SIZE; - if ((open_flags & O_ACCMODE) == O_RDONLY) { - tdb->read_only = 1; - /* read only databases don't do locking or clear if first */ - tdb->flags |= TDB_NOLOCK; - tdb->flags &= ~TDB_CLEAR_IF_FIRST; - } - - if ((tdb->flags & TDB_ALLOW_NESTING) && - (tdb->flags & TDB_DISALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "allow_nesting and disallow_nesting are not allowed together!")); - errno = EINVAL; - goto fail; - } - - /* - * TDB_ALLOW_NESTING is the default behavior. - * Note: this may change in future versions! - */ - if (!(tdb->flags & TDB_DISALLOW_NESTING)) { - tdb->flags |= TDB_ALLOW_NESTING; - } - - /* internal databases don't mmap or lock, and start off cleared */ - if (tdb->flags & TDB_INTERNAL) { - tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP); - tdb->flags &= ~TDB_CLEAR_IF_FIRST; - if (tdb_new_database(tdb, hash_size) != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!")); - goto fail; - } - goto internal; - } - - if ((tdb->fd = open(name, open_flags, mode)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n", - name, strerror(errno))); - goto fail; /* errno set by open(2) */ - } - - /* on exec, don't inherit the fd */ - v = fcntl(tdb->fd, F_GETFD, 0); - fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC); - - /* ensure there is only one process initialising at once */ - if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n", - name, strerror(errno))); - goto fail; /* errno set by tdb_brlock */ - } - - /* we need to zero database if we are the only one with it open */ - if ((tdb_flags & TDB_CLEAR_IF_FIRST) && - (!tdb->read_only) && - (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) { - open_flags |= O_CREAT; - if (ftruncate(tdb->fd, 0) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "failed to truncate %s: %s\n", - name, strerror(errno))); - goto fail; /* errno set by ftruncate */ - } - } - - errno = 0; - if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header) - || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) { - if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) { - if (errno == 0) { - errno = EIO; /* ie bad format or something */ - } - goto fail; - } - rev = (tdb->flags & TDB_CONVERT); - } else if (tdb->header.version != TDB_VERSION - && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION)))) { - /* wrong version */ - errno = EIO; - goto fail; - } - vp = (unsigned char *)&tdb->header.version; - vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) | - (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3]; - tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0; - if (!rev) - tdb->flags &= ~TDB_CONVERT; - else { - tdb->flags |= TDB_CONVERT; - tdb_convert(&tdb->header, sizeof(tdb->header)); - } - if (fstat(tdb->fd, &st) == -1) - goto fail; - - if (tdb->header.rwlocks != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n")); - goto fail; - } - - /* Is it already in the open list? If so, fail. */ - if (tdb_already_open(st.st_dev, st.st_ino)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " - "%s (%d,%d) is already open in this process\n", - name, (int)st.st_dev, (int)st.st_ino)); - errno = EBUSY; - goto fail; - } - - if (!(tdb->name = (char *)strdup(name))) { - errno = ENOMEM; - goto fail; - } - - tdb->map_size = st.st_size; - tdb->device = st.st_dev; - tdb->inode = st.st_ino; - tdb_mmap(tdb); - if (locked) { - if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " - "failed to take ACTIVE_LOCK on %s: %s\n", - name, strerror(errno))); - goto fail; - } - - } - - /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if - we didn't get the initial exclusive lock as we need to let all other - users know we're using it. */ - - if (tdb_flags & TDB_CLEAR_IF_FIRST) { - /* leave this lock in place to indicate it's in use */ - if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1) - goto fail; - } - - /* if needed, run recovery */ - if (tdb_transaction_recover(tdb) == -1) { - goto fail; - } - -#ifdef TDB_TRACE - { - char tracefile[strlen(name) + 32]; - - snprintf(tracefile, sizeof(tracefile), - "%s.trace.%li", name, (long)getpid()); - tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600); - if (tdb->tracefd >= 0) { - tdb_enable_seqnum(tdb); - tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags, - open_flags); - } else - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile)); - } -#endif - - internal: - /* Internal (memory-only) databases skip all the code above to - * do with disk files, and resume here by releasing their - * global lock and hooking into the active list. */ - if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1) - goto fail; - tdb->next = tdbs; - tdbs = tdb; - return tdb; - - fail: - { int save_errno = errno; - - if (!tdb) - return NULL; - -#ifdef TDB_TRACE - close(tdb->tracefd); -#endif - if (tdb->map_ptr) { - if (tdb->flags & TDB_INTERNAL) - SAFE_FREE(tdb->map_ptr); - else - tdb_munmap(tdb); - } - SAFE_FREE(tdb->name); - if (tdb->fd != -1) - if (close(tdb->fd) != 0) - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n")); - SAFE_FREE(tdb); - errno = save_errno; - return NULL; - } -} - -/* - * Set the maximum number of dead records per hash chain - */ - -void tdb_set_max_dead(struct tdb_context *tdb, int max_dead) -{ - tdb->max_dead_records = max_dead; -} - -/** - * Close a database. - * - * @returns -1 for error; 0 for success. - **/ -int tdb_close(struct tdb_context *tdb) -{ - struct tdb_context **i; - int ret = 0; - - tdb_trace(tdb, "tdb_close"); - if (tdb->transaction) { - _tdb_transaction_cancel(tdb); - } - - if (tdb->map_ptr) { - if (tdb->flags & TDB_INTERNAL) - SAFE_FREE(tdb->map_ptr); - else - tdb_munmap(tdb); - } - SAFE_FREE(tdb->name); - if (tdb->fd != -1) { - ret = close(tdb->fd); - tdb->fd = -1; - } - SAFE_FREE(tdb->lockrecs); - - /* Remove from contexts list */ - for (i = &tdbs; *i; i = &(*i)->next) { - if (*i == tdb) { - *i = tdb->next; - break; - } - } - -#ifdef TDB_TRACE - close(tdb->tracefd); -#endif - memset(tdb, 0, sizeof(*tdb)); - SAFE_FREE(tdb); - - return ret; -} - -/* register a loging function */ -void tdb_set_logging_function(struct tdb_context *tdb, - const struct tdb_logging_context *log_ctx) -{ - tdb->log = *log_ctx; -} - -void *tdb_get_logging_private(struct tdb_context *tdb) -{ - return tdb->log.log_private; -} - -static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock) -{ -#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \ - !defined(LIBREPLACE_PWRITE_NOT_REPLACED) - struct stat st; -#endif - - if (tdb->flags & TDB_INTERNAL) { - return 0; /* Nothing to do. */ - } - - if (tdb->num_locks != 0 || tdb->global_lock.count) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n")); - goto fail; - } - - if (tdb->transaction != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n")); - goto fail; - } - -/* If we have real pread & pwrite, we can skip reopen. */ -#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \ - !defined(LIBREPLACE_PWRITE_NOT_REPLACED) - if (tdb_munmap(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno))); - goto fail; - } - if (close(tdb->fd) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n")); - tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0); - if (tdb->fd == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno))); - goto fail; - } - if (fstat(tdb->fd, &st) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno))); - goto fail; - } - if (st.st_ino != tdb->inode || st.st_dev != tdb->device) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n")); - goto fail; - } - tdb_mmap(tdb); -#endif /* fake pread or pwrite */ - - if (active_lock && - (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n")); - goto fail; - } - - return 0; - -fail: - tdb_close(tdb); - return -1; -} - -/* reopen a tdb - this can be used after a fork to ensure that we have an independent - seek pointer from our parent and to re-establish locks */ -int tdb_reopen(struct tdb_context *tdb) -{ - return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST); -} - -/* reopen all tdb's */ -int tdb_reopen_all(int parent_longlived) -{ - struct tdb_context *tdb; - - for (tdb=tdbs; tdb; tdb = tdb->next) { - bool active_lock = (tdb->flags & TDB_CLEAR_IF_FIRST); - - /* - * If the parent is longlived (ie. a - * parent daemon architecture), we know - * it will keep it's active lock on a - * tdb opened with CLEAR_IF_FIRST. Thus - * for child processes we don't have to - * add an active lock. This is essential - * to improve performance on systems that - * keep POSIX locks as a non-scalable data - * structure in the kernel. - */ - if (parent_longlived) { - /* Ensure no clear-if-first. */ - active_lock = false; - } - - if (tdb_reopen_internal(tdb, active_lock) != 0) - return -1; - } - - return 0; -} diff --git a/libatalk/tdb/tdb.c b/libatalk/tdb/tdb.c deleted file mode 100644 index d2688def04..0000000000 --- a/libatalk/tdb/tdb.c +++ /dev/null @@ -1,1140 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -TDB_DATA tdb_null; - -/* - non-blocking increment of the tdb sequence number if the tdb has been opened using - the TDB_SEQNUM flag -*/ -void tdb_increment_seqnum_nonblock(struct tdb_context *tdb) -{ - tdb_off_t seqnum=0; - - if (!(tdb->flags & TDB_SEQNUM)) { - return; - } - - /* we ignore errors from this, as we have no sane way of - dealing with them. - */ - tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); - seqnum++; - tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum); -} - -/* - increment the tdb sequence number if the tdb has been opened using - the TDB_SEQNUM flag -*/ -static void tdb_increment_seqnum(struct tdb_context *tdb) -{ - if (!(tdb->flags & TDB_SEQNUM)) { - return; - } - - if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) { - return; - } - - tdb_increment_seqnum_nonblock(tdb); - - tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1); -} - -static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data) -{ - return memcmp(data.dptr, key.dptr, data.dsize); -} - -/* Returns 0 on fail. On success, return offset of record, and fills - in rec */ -static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, - struct tdb_record *r) -{ - tdb_off_t rec_ptr; - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - return 0; - - /* keep looking until we find the right record */ - while (rec_ptr) { - if (tdb_rec_read(tdb, rec_ptr, r) == -1) - return 0; - - if (!TDB_DEAD(r) && hash==r->full_hash - && key.dsize==r->key_len - && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r), - r->key_len, tdb_key_compare, - NULL) == 0) { - return rec_ptr; - } - /* detect tight infinite loop */ - if (rec_ptr == r->next) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_find: loop detected.\n")); - return 0; - } - rec_ptr = r->next; - } - tdb->ecode = TDB_ERR_NOEXIST; - return 0; -} - -/* As tdb_find, but if you succeed, keep the lock */ -tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype, - struct tdb_record *rec) -{ - uint32_t rec_ptr; - - if (tdb_lock(tdb, BUCKET(hash), locktype) == -1) - return 0; - if (!(rec_ptr = tdb_find(tdb, key, hash, rec))) - tdb_unlock(tdb, BUCKET(hash), locktype); - return rec_ptr; -} - -static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key); - -/* update an entry in place - this only works if the new data size - is <= the old data size and the key exists. - on failure return -1. -*/ -static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf) -{ - struct tdb_record rec; - tdb_off_t rec_ptr; - - /* find entry */ - if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) - return -1; - - /* it could be an exact duplicate of what is there - this is - * surprisingly common (eg. with a ldb re-index). */ - if (rec.key_len == key.dsize && - rec.data_len == dbuf.dsize && - rec.full_hash == hash) { - TDB_DATA data = _tdb_fetch(tdb, key); - if (data.dsize == dbuf.dsize && - memcmp(data.dptr, dbuf.dptr, data.dsize) == 0) { - if (data.dptr) { - free(data.dptr); - } - return 0; - } - if (data.dptr) { - free(data.dptr); - } - } - - - /* must be long enough key, data and tailer */ - if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) { - tdb->ecode = TDB_SUCCESS; /* Not really an error */ - return -1; - } - - if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len, - dbuf.dptr, dbuf.dsize) == -1) - return -1; - - if (dbuf.dsize != rec.data_len) { - /* update size */ - rec.data_len = dbuf.dsize; - return tdb_rec_write(tdb, rec_ptr, &rec); - } - - return 0; -} - -/* find an entry in the database given a key */ -/* If an entry doesn't exist tdb_err will be set to - * TDB_ERR_NOEXIST. If a key has no data attached - * then the TDB_DATA will have zero length but - * a non-zero pointer - */ -static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_off_t rec_ptr; - struct tdb_record rec; - TDB_DATA ret; - uint32_t hash; - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) - return tdb_null; - - ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len, - rec.data_len); - ret.dsize = rec.data_len; - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - return ret; -} - -TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key) -{ - TDB_DATA ret = _tdb_fetch(tdb, key); - - tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret); - return ret; -} - -/* - * Find an entry in the database and hand the record's data to a parsing - * function. The parsing function is executed under the chain read lock, so it - * should be fast and should not block on other syscalls. - * - * DONT CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS. - * - * For mmapped tdb's that do not have a transaction open it points the parsing - * function directly at the mmap area, it avoids the malloc/memcpy in this - * case. If a transaction is open or no mmap is available, it has to do - * malloc/read/parse/free. - * - * This is interesting for all readers of potentially large data structures in - * the tdb records, ldb indexes being one example. - */ - -int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) -{ - tdb_off_t rec_ptr; - struct tdb_record rec; - int ret; - uint32_t hash; - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - - if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { - tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1); - tdb->ecode = TDB_ERR_NOEXIST; - return 0; - } - tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0); - - ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len, - rec.data_len, parser, private_data); - - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - - return ret; -} - -/* check if an entry in the database exists - - note that 1 is returned if the key is found and 0 is returned if not found - this doesn't match the conventions in the rest of this module, but is - compatible with gdbm -*/ -static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash) -{ - struct tdb_record rec; - - if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0) - return 0; - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - return 1; -} - -int tdb_exists(struct tdb_context *tdb, TDB_DATA key) -{ - uint32_t hash = tdb->hash_fn(&key); - int ret; - - ret = tdb_exists_hash(tdb, key, hash); - tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret); - return ret; -} - -/* actually delete an entry in the database given the offset */ -int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec) -{ - tdb_off_t last_ptr, i; - struct tdb_record lastrec; - - if (tdb->read_only || tdb->traverse_read) return -1; - - if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) || - tdb_write_lock_record(tdb, rec_ptr) == -1) { - /* Someone traversing here: mark it as dead */ - rec->magic = TDB_DEAD_MAGIC; - return tdb_rec_write(tdb, rec_ptr, rec); - } - if (tdb_write_unlock_record(tdb, rec_ptr) != 0) - return -1; - - /* find previous record in hash chain */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1) - return -1; - for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next) - if (tdb_rec_read(tdb, i, &lastrec) == -1) - return -1; - - /* unlink it: next ptr is at start of record. */ - if (last_ptr == 0) - last_ptr = TDB_HASH_TOP(rec->full_hash); - if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) - return -1; - - /* recover the space */ - if (tdb_free(tdb, rec_ptr, rec) == -1) - return -1; - return 0; -} - -static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash) -{ - int res = 0; - tdb_off_t rec_ptr; - struct tdb_record rec; - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - return 0; - - while (rec_ptr) { - if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) - return 0; - - if (rec.magic == TDB_DEAD_MAGIC) { - res += 1; - } - rec_ptr = rec.next; - } - return res; -} - -/* - * Purge all DEAD records from a hash chain - */ -static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash) -{ - int res = -1; - struct tdb_record rec; - tdb_off_t rec_ptr; - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - return -1; - } - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - goto fail; - - while (rec_ptr) { - tdb_off_t next; - - if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) { - goto fail; - } - - next = rec.next; - - if (rec.magic == TDB_DEAD_MAGIC - && tdb_do_delete(tdb, rec_ptr, &rec) == -1) { - goto fail; - } - rec_ptr = next; - } - res = 0; - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return res; -} - -/* delete an entry in the database given a key */ -static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash) -{ - tdb_off_t rec_ptr; - struct tdb_record rec; - int ret; - - if (tdb->max_dead_records != 0) { - - /* - * Allow for some dead records per hash chain, mainly for - * tdb's with a very high create/delete rate like locking.tdb. - */ - - if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) - return -1; - - if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) { - /* - * Don't let the per-chain freelist grow too large, - * delete all existing dead records - */ - tdb_purge_dead(tdb, hash); - } - - if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) { - tdb_unlock(tdb, BUCKET(hash), F_WRLCK); - return -1; - } - - /* - * Just mark the record as dead. - */ - rec.magic = TDB_DEAD_MAGIC; - ret = tdb_rec_write(tdb, rec_ptr, &rec); - } - else { - if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, - &rec))) - return -1; - - ret = tdb_do_delete(tdb, rec_ptr, &rec); - } - - if (ret == 0) { - tdb_increment_seqnum(tdb); - } - - if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0) - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n")); - return ret; -} - -int tdb_delete(struct tdb_context *tdb, TDB_DATA key) -{ - uint32_t hash = tdb->hash_fn(&key); - int ret; - - ret = tdb_delete_hash(tdb, key, hash); - tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret); - return ret; -} - -/* - * See if we have a dead record around with enough space - */ -static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash, - struct tdb_record *r, tdb_len_t length) -{ - tdb_off_t rec_ptr; - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - return 0; - - /* keep looking until we find the right record */ - while (rec_ptr) { - if (tdb_rec_read(tdb, rec_ptr, r) == -1) - return 0; - - if (TDB_DEAD(r) && r->rec_len >= length) { - /* - * First fit for simple coding, TODO: change to best - * fit - */ - return rec_ptr; - } - rec_ptr = r->next; - } - return 0; -} - -static int _tdb_store(struct tdb_context *tdb, TDB_DATA key, - TDB_DATA dbuf, int flag, uint32_t hash) -{ - struct tdb_record rec; - tdb_off_t rec_ptr; - char *p = NULL; - int ret = -1; - - /* check for it existing, on insert. */ - if (flag == TDB_INSERT) { - if (tdb_exists_hash(tdb, key, hash)) { - tdb->ecode = TDB_ERR_EXISTS; - goto fail; - } - } else { - /* first try in-place update, on modify or replace. */ - if (tdb_update_hash(tdb, key, hash, dbuf) == 0) { - goto done; - } - if (tdb->ecode == TDB_ERR_NOEXIST && - flag == TDB_MODIFY) { - /* if the record doesn't exist and we are in TDB_MODIFY mode then - we should fail the store */ - goto fail; - } - } - /* reset the error code potentially set by the tdb_update() */ - tdb->ecode = TDB_SUCCESS; - - /* delete any existing record - if it doesn't exist we don't - care. Doing this first reduces fragmentation, and avoids - coalescing with `allocated' block before it's updated. */ - if (flag != TDB_INSERT) - tdb_delete_hash(tdb, key, hash); - - /* Copy key+value *before* allocating free space in case malloc - fails and we are left with a dead spot in the tdb. */ - - if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) { - tdb->ecode = TDB_ERR_OOM; - goto fail; - } - - memcpy(p, key.dptr, key.dsize); - if (dbuf.dsize) - memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize); - - if (tdb->max_dead_records != 0) { - /* - * Allow for some dead records per hash chain, look if we can - * find one that can hold the new record. We need enough space - * for key, data and tailer. If we find one, we don't have to - * consult the central freelist. - */ - rec_ptr = tdb_find_dead( - tdb, hash, &rec, - key.dsize + dbuf.dsize + sizeof(tdb_off_t)); - - if (rec_ptr != 0) { - rec.key_len = key.dsize; - rec.data_len = dbuf.dsize; - rec.full_hash = hash; - rec.magic = TDB_MAGIC; - if (tdb_rec_write(tdb, rec_ptr, &rec) == -1 - || tdb->methods->tdb_write( - tdb, rec_ptr + sizeof(rec), - p, key.dsize + dbuf.dsize) == -1) { - goto fail; - } - goto done; - } - } - - /* - * We have to allocate some space from the freelist, so this means we - * have to lock it. Use the chance to purge all the DEAD records from - * the hash chain under the freelist lock. - */ - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - goto fail; - } - - if ((tdb->max_dead_records != 0) - && (tdb_purge_dead(tdb, hash) == -1)) { - tdb_unlock(tdb, -1, F_WRLCK); - goto fail; - } - - /* we have to allocate some space */ - rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec); - - tdb_unlock(tdb, -1, F_WRLCK); - - if (rec_ptr == 0) { - goto fail; - } - - /* Read hash top into next ptr */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1) - goto fail; - - rec.key_len = key.dsize; - rec.data_len = dbuf.dsize; - rec.full_hash = hash; - rec.magic = TDB_MAGIC; - - /* write out and point the top of the hash chain at it */ - if (tdb_rec_write(tdb, rec_ptr, &rec) == -1 - || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1 - || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) { - /* Need to tdb_unallocate() here */ - goto fail; - } - - done: - ret = 0; - fail: - if (ret == 0) { - tdb_increment_seqnum(tdb); - } - - SAFE_FREE(p); - return ret; -} - -/* store an element in the database, replacing any existing element - with the same key - - return 0 on success, -1 on failure -*/ -int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) -{ - uint32_t hash; - int ret; - - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1); - return -1; - } - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) - return -1; - - ret = _tdb_store(tdb, key, dbuf, flag, hash); - tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret); - tdb_unlock(tdb, BUCKET(hash), F_WRLCK); - return ret; -} - -/* Append to an entry. Create if not exist. */ -int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf) -{ - uint32_t hash; - TDB_DATA dbuf; - int ret = -1; - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) - return -1; - - dbuf = _tdb_fetch(tdb, key); - - if (dbuf.dptr == NULL) { - dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize); - } else { - unsigned int new_len = dbuf.dsize + new_dbuf.dsize; - unsigned char *new_dptr; - - /* realloc '0' is special: don't do that. */ - if (new_len == 0) - new_len = 1; - new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len); - if (new_dptr == NULL) { - free(dbuf.dptr); - } - dbuf.dptr = new_dptr; - } - - if (dbuf.dptr == NULL) { - tdb->ecode = TDB_ERR_OOM; - goto failed; - } - - memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize); - dbuf.dsize += new_dbuf.dsize; - - ret = _tdb_store(tdb, key, dbuf, 0, hash); - tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf); - -failed: - tdb_unlock(tdb, BUCKET(hash), F_WRLCK); - SAFE_FREE(dbuf.dptr); - return ret; -} - - -/* - return the name of the current tdb file - useful for external logging functions -*/ -const char *tdb_name(struct tdb_context *tdb) -{ - return tdb->name; -} - -/* - return the underlying file descriptor being used by tdb, or -1 - useful for external routines that want to check the device/inode - of the fd -*/ -int tdb_fd(struct tdb_context *tdb) -{ - return tdb->fd; -} - -/* - return the current logging function - useful for external tdb routines that wish to log tdb errors -*/ -tdb_log_func tdb_log_fn(struct tdb_context *tdb) -{ - return tdb->log.log_fn; -} - - -/* - get the tdb sequence number. Only makes sense if the writers opened - with TDB_SEQNUM set. Note that this sequence number will wrap quite - quickly, so it should only be used for a 'has something changed' - test, not for code that relies on the count of the number of changes - made. If you want a counter then use a tdb record. - - The aim of this sequence number is to allow for a very lightweight - test of a possible tdb change. -*/ -int tdb_get_seqnum(struct tdb_context *tdb) -{ - tdb_off_t seqnum=0; - - tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); - return seqnum; -} - -int tdb_hash_size(struct tdb_context *tdb) -{ - return tdb->header.hash_size; -} - -size_t tdb_map_size(struct tdb_context *tdb) -{ - return tdb->map_size; -} - -int tdb_get_flags(struct tdb_context *tdb) -{ - return tdb->flags; -} - -void tdb_add_flags(struct tdb_context *tdb, unsigned flags) -{ - if ((flags & TDB_ALLOW_NESTING) && - (flags & TDB_DISALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: " - "allow_nesting and disallow_nesting are not allowed together!")); - return; - } - - if (flags & TDB_ALLOW_NESTING) { - tdb->flags &= ~TDB_DISALLOW_NESTING; - } - if (flags & TDB_DISALLOW_NESTING) { - tdb->flags &= ~TDB_ALLOW_NESTING; - } - - tdb->flags |= flags; -} - -void tdb_remove_flags(struct tdb_context *tdb, unsigned flags) -{ - if ((flags & TDB_ALLOW_NESTING) && - (flags & TDB_DISALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: " - "allow_nesting and disallow_nesting are not allowed together!")); - return; - } - - if (flags & TDB_ALLOW_NESTING) { - tdb->flags |= TDB_DISALLOW_NESTING; - } - if (flags & TDB_DISALLOW_NESTING) { - tdb->flags |= TDB_ALLOW_NESTING; - } - - tdb->flags &= ~flags; -} - - -/* - enable sequence number handling on an open tdb -*/ -void tdb_enable_seqnum(struct tdb_context *tdb) -{ - tdb->flags |= TDB_SEQNUM; -} - - -/* - add a region of the file to the freelist. Length is the size of the region in bytes, - which includes the free list header that needs to be added - */ -static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length) -{ - struct tdb_record rec; - if (length <= sizeof(rec)) { - /* the region is not worth adding */ - return 0; - } - if (length + offset > tdb->map_size) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n")); - return -1; - } - memset(&rec,'\0',sizeof(rec)); - rec.rec_len = length - sizeof(rec); - if (tdb_free(tdb, offset, &rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n")); - return -1; - } - return 0; -} - -/* - wipe the entire database, deleting all records. This can be done - very fast by using a global lock. The entire data portion of the - file becomes a single entry in the freelist. - - This code carefully steps around the recovery area, leaving it alone - */ -int tdb_wipe_all(struct tdb_context *tdb) -{ - int i; - tdb_off_t offset = 0; - ssize_t data_len; - tdb_off_t recovery_head; - tdb_len_t recovery_size = 0; - - if (tdb_lockall(tdb) != 0) { - return -1; - } - - tdb_trace(tdb, "tdb_wipe_all"); - - /* see if the tdb has a recovery area, and remember its size - if so. We don't want to lose this as otherwise each - tdb_wipe_all() in a transaction will increase the size of - the tdb by the size of the recovery area */ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n")); - goto failed; - } - - if (recovery_head != 0) { - struct tdb_record rec; - if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n")); - return -1; - } - recovery_size = rec.rec_len + sizeof(rec); - } - - /* wipe the hashes */ - for (i=0;i<tdb->header.hash_size;i++) { - if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i)); - goto failed; - } - } - - /* wipe the freelist */ - if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n")); - goto failed; - } - - /* add all the rest of the file to the freelist, possibly leaving a gap - for the recovery area */ - if (recovery_size == 0) { - /* the simple case - the whole file can be used as a freelist */ - data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size)); - if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) { - goto failed; - } - } else { - /* we need to add two freelist entries - one on either - side of the recovery area - - Note that we cannot shift the recovery area during - this operation. Only the transaction.c code may - move the recovery area or we risk subtle data - corruption - */ - data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size)); - if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) { - goto failed; - } - /* and the 2nd free list entry after the recovery area - if any */ - data_len = tdb->map_size - (recovery_head+recovery_size); - if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) { - goto failed; - } - } - - if (tdb_unlockall(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n")); - goto failed; - } - - return 0; - -failed: - tdb_unlockall(tdb); - return -1; -} - -struct traverse_state { - bool error; - struct tdb_context *dest_db; -}; - -/* - traverse function for repacking - */ -static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data) -{ - struct traverse_state *state = (struct traverse_state *)private_data; - if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) { - state->error = true; - return -1; - } - return 0; -} - -/* - repack a tdb - */ -int tdb_repack(struct tdb_context *tdb) -{ - struct tdb_context *tmp_db; - struct traverse_state state; - - tdb_trace(tdb, "tdb_repack"); - - if (tdb_transaction_start(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n")); - return -1; - } - - tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0); - if (tmp_db == NULL) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n")); - tdb_transaction_cancel(tdb); - return -1; - } - - state.error = false; - state.dest_db = tmp_db; - - if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (state.error) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (tdb_wipe_all(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - state.error = false; - state.dest_db = tdb; - - if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (state.error) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - tdb_close(tmp_db); - - if (tdb_transaction_commit(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n")); - return -1; - } - - return 0; -} - -#ifdef TDB_TRACE -static void tdb_trace_write(struct tdb_context *tdb, const char *str) -{ - if (write(tdb->tracefd, str, strlen(str)) != strlen(str)) { - close(tdb->tracefd); - tdb->tracefd = -1; - } -} - -static void tdb_trace_start(struct tdb_context *tdb) -{ - tdb_off_t seqnum=0; - char msg[sizeof(tdb_off_t) * 4 + 1]; - - tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); - snprintf(msg, sizeof(msg), "%u ", seqnum); - tdb_trace_write(tdb, msg); -} - -static void tdb_trace_end(struct tdb_context *tdb) -{ - tdb_trace_write(tdb, "\n"); -} - -static void tdb_trace_end_ret(struct tdb_context *tdb, int ret) -{ - char msg[sizeof(ret) * 4 + 4]; - snprintf(msg, sizeof(msg), " = %i\n", ret); - tdb_trace_write(tdb, msg); -} - -static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec) -{ - char msg[20 + rec.dsize*2], *p; - unsigned int i; - - /* We differentiate zero-length records from non-existent ones. */ - if (rec.dptr == NULL) { - tdb_trace_write(tdb, " NULL"); - return; - } - - /* snprintf here is purely cargo-cult programming. */ - p = msg; - p += snprintf(p, sizeof(msg), " %zu:", rec.dsize); - for (i = 0; i < rec.dsize; i++) - p += snprintf(p, 2, "%02x", rec.dptr[i]); - - tdb_trace_write(tdb, msg); -} - -void tdb_trace(struct tdb_context *tdb, const char *op) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_end(tdb); -} - -void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op) -{ - char msg[sizeof(tdb_off_t) * 4 + 1]; - - snprintf(msg, sizeof(msg), "%u ", seqnum); - tdb_trace_write(tdb, msg); - tdb_trace_write(tdb, op); - tdb_trace_end(tdb); -} - -void tdb_trace_open(struct tdb_context *tdb, const char *op, - unsigned hash_size, unsigned tdb_flags, unsigned open_flags) -{ - char msg[128]; - - snprintf(msg, sizeof(msg), - "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags); - tdb_trace_start(tdb); - tdb_trace_write(tdb, msg); - tdb_trace_end(tdb); -} - -void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_end_ret(tdb, ret); -} - -void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_write(tdb, " ="); - tdb_trace_record(tdb, ret); - tdb_trace_end(tdb); -} - -void tdb_trace_1rec(struct tdb_context *tdb, const char *op, - TDB_DATA rec) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec); - tdb_trace_end(tdb); -} - -void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec, int ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec); - tdb_trace_end_ret(tdb, ret); -} - -void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec, TDB_DATA ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec); - tdb_trace_write(tdb, " ="); - tdb_trace_record(tdb, ret); - tdb_trace_end(tdb); -} - -void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec1, TDB_DATA rec2, unsigned flag, - int ret) -{ - char msg[1 + sizeof(ret) * 4]; - - snprintf(msg, sizeof(msg), " %#x", flag); - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec1); - tdb_trace_record(tdb, rec2); - tdb_trace_write(tdb, msg); - tdb_trace_end_ret(tdb, ret); -} - -void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec1); - tdb_trace_record(tdb, rec2); - tdb_trace_write(tdb, " ="); - tdb_trace_record(tdb, ret); - tdb_trace_end(tdb); -} -#endif diff --git a/libatalk/tdb/tdb_private.h b/libatalk/tdb/tdb_private.h deleted file mode 100644 index de5dd02b14..0000000000 --- a/libatalk/tdb/tdb_private.h +++ /dev/null @@ -1,279 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - private includes - - Copyright (C) Andrew Tridgell 2005 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/select.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <time.h> -#include <utime.h> -#include <sys/wait.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <stdio.h> -#include <errno.h> -#include <sys/param.h> -#include <stddef.h> - -#ifndef __STRING -#define __STRING(x) #x -#endif - -#ifndef __STRINGSTRING -#define __STRINGSTRING(x) __STRING(x) -#endif - -#ifndef __LINESTR__ -#define __LINESTR__ __STRINGSTRING(__LINE__) -#endif - -#ifndef __location__ -#define __location__ __FILE__ ":" __LINESTR__ -#endif - -#include <atalk/util.h> -#include "atalk/tdb.h" - -/* #define TDB_TRACE 1 */ -#ifndef HAVE_GETPAGESIZE -#define getpagesize() 0x2000 -#endif - -typedef uint32_t tdb_len_t; -typedef uint32_t tdb_off_t; - -#define TDB_MAGIC_FOOD "TDB file\n" -#define TDB_VERSION (0x26011967 + 6) -#define TDB_MAGIC (0x26011999U) -#define TDB_FREE_MAGIC (~TDB_MAGIC) -#define TDB_DEAD_MAGIC (0xFEE1DEAD) -#define TDB_RECOVERY_MAGIC (0xf53bc0e7U) -#define TDB_ALIGNMENT 4 -#define DEFAULT_HASH_SIZE 131 -#define FREELIST_TOP (sizeof(struct tdb_header)) -#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1)) -#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24)) -#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC) -#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r)) -#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t)) -#define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t)) -#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t)) -#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start) -#define TDB_SEQNUM_OFS offsetof(struct tdb_header, sequence_number) -#define TDB_PAD_BYTE 0x42 -#define TDB_PAD_U32 0x42424242 - -/* NB assumes there is a local variable called "tdb" that is the - * current context, also takes doubly-parenthesized print-style - * argument. */ -#define TDB_LOG(x) tdb->log.log_fn x - -#ifdef TDB_TRACE -void tdb_trace(struct tdb_context *tdb, const char *op); -void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op); -void tdb_trace_open(struct tdb_context *tdb, const char *op, - unsigned hash_size, unsigned tdb_flags, unsigned open_flags); -void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret); -void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret); -void tdb_trace_1rec(struct tdb_context *tdb, const char *op, - TDB_DATA rec); -void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec, int ret); -void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec, TDB_DATA ret); -void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec1, TDB_DATA rec2, unsigned flag, - int ret); -void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret); -#else -#define tdb_trace(tdb, op) -#define tdb_trace_seqnum(tdb, seqnum, op) -#define tdb_trace_open(tdb, op, hash_size, tdb_flags, open_flags) -#define tdb_trace_ret(tdb, op, ret) -#define tdb_trace_retrec(tdb, op, ret) -#define tdb_trace_1rec(tdb, op, rec) -#define tdb_trace_1rec_ret(tdb, op, rec, ret) -#define tdb_trace_1rec_retrec(tdb, op, rec, ret) -#define tdb_trace_2rec_flag_ret(tdb, op, rec1, rec2, flag, ret) -#define tdb_trace_2rec_retrec(tdb, op, rec1, rec2, ret) -#endif /* !TDB_TRACE */ - -/* lock offsets */ -#define GLOBAL_LOCK 0 -#define ACTIVE_LOCK 4 -#define TRANSACTION_LOCK 8 - -/* free memory if the pointer is valid and zero the pointer */ -#ifndef SAFE_FREE -#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0) -#endif - -#define BUCKET(hash) ((hash) % tdb->header.hash_size) - -#define DOCONV() (tdb->flags & TDB_CONVERT) -#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x) - - -/* the body of the database is made of one tdb_record for the free space - plus a separate data list for each hash value */ -struct tdb_record { - tdb_off_t next; /* offset of the next record in the list */ - tdb_len_t rec_len; /* total byte length of record */ - tdb_len_t key_len; /* byte length of key */ - tdb_len_t data_len; /* byte length of data */ - uint32_t full_hash; /* the full 32 bit hash of the key */ - uint32_t magic; /* try to catch errors */ - /* the following union is implied: - union { - char record[rec_len]; - struct { - char key[key_len]; - char data[data_len]; - } - uint32_t totalsize; (tailer) - } - */ -}; - - -/* this is stored at the front of every database */ -struct tdb_header { - char magic_food[32]; /* for /etc/magic */ - uint32_t version; /* version of the code */ - uint32_t hash_size; /* number of hash entries */ - tdb_off_t rwlocks; /* obsolete - kept to detect old formats */ - tdb_off_t recovery_start; /* offset of transaction recovery region */ - tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */ - tdb_off_t reserved[29]; -}; - -struct tdb_lock_type { - int list; - uint32_t count; - uint32_t ltype; -}; - -struct tdb_traverse_lock { - struct tdb_traverse_lock *next; - uint32_t off; - uint32_t hash; - int lock_rw; -}; - - -struct tdb_methods { - int (*tdb_read)(struct tdb_context *, tdb_off_t , void *, tdb_len_t , int ); - int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t); - void (*next_hash_chain)(struct tdb_context *, uint32_t *); - int (*tdb_oob)(struct tdb_context *, tdb_off_t , int ); - int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t ); - int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t); -}; - -struct tdb_context { - char *name; /* the name of the database */ - void *map_ptr; /* where it is currently mapped */ - int fd; /* open file descriptor for the database */ - tdb_len_t map_size; /* how much space has been mapped */ - int read_only; /* opened read-only */ - int traverse_read; /* read-only traversal */ - int traverse_write; /* read-write traversal */ - struct tdb_lock_type global_lock; - int num_lockrecs; - struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */ - enum TDB_ERROR ecode; /* error code for last tdb error */ - struct tdb_header header; /* a cached copy of the header */ - uint32_t flags; /* the flags passed to tdb_open */ - struct tdb_traverse_lock travlocks; /* current traversal locks */ - struct tdb_context *next; /* all tdbs to avoid multiple opens */ - dev_t device; /* uniquely identifies this tdb */ - ino_t inode; /* uniquely identifies this tdb */ - struct tdb_logging_context log; - unsigned int (*hash_fn)(TDB_DATA *key); - int open_flags; /* flags used in the open - needed by reopen */ - unsigned int num_locks; /* number of chain locks held */ - const struct tdb_methods *methods; - struct tdb_transaction *transaction; - int page_size; - int max_dead_records; - int transaction_lock_count; -#ifdef TDB_TRACE - int tracefd; -#endif - volatile sig_atomic_t *interrupt_sig_ptr; -}; - - -/* - internal prototypes -*/ -int tdb_munmap(struct tdb_context *tdb); -void tdb_mmap(struct tdb_context *tdb); -int tdb_lock(struct tdb_context *tdb, int list, int ltype); -int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype); -int tdb_unlock(struct tdb_context *tdb, int list, int ltype); -int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len); -int tdb_transaction_lock(struct tdb_context *tdb, int ltype); -int tdb_transaction_unlock(struct tdb_context *tdb); -int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len); -int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off); -int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off); -int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); -int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); -void *tdb_convert(void *buf, uint32_t size); -int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); -tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec); -int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); -int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); -int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off); -int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off); -int _tdb_transaction_cancel(struct tdb_context *tdb); -int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); -int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); -int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec); -unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len); -int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key, - tdb_off_t offset, tdb_len_t len, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data); -tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype, - struct tdb_record *rec); -void tdb_io_init(struct tdb_context *tdb); -int tdb_expand(struct tdb_context *tdb, tdb_off_t size); -int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, - struct tdb_record *rec); - - diff --git a/libatalk/tdb/transaction.c b/libatalk/tdb/transaction.c deleted file mode 100644 index b8988ea830..0000000000 --- a/libatalk/tdb/transaction.c +++ /dev/null @@ -1,1236 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 2005 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -/* - transaction design: - - - only allow a single transaction at a time per database. This makes - using the transaction API simpler, as otherwise the caller would - have to cope with temporary failures in transactions that conflict - with other current transactions - - - keep the transaction recovery information in the same file as the - database, using a special 'transaction recovery' record pointed at - by the header. This removes the need for extra journal files as - used by some other databases - - - dynamically allocated the transaction recover record, re-using it - for subsequent transactions. If a larger record is needed then - tdb_free() the old record to place it on the normal tdb freelist - before allocating the new record - - - during transactions, keep a linked list of writes all that have - been performed by intercepting all tdb_write() calls. The hooked - transaction versions of tdb_read() and tdb_write() check this - linked list and try to use the elements of the list in preference - to the real database. - - - don't allow any locks to be held when a transaction starts, - otherwise we can end up with deadlock (plus lack of lock nesting - in posix locks would mean the lock is lost) - - - if the caller gains a lock during the transaction but doesn't - release it then fail the commit - - - allow for nested calls to tdb_transaction_start(), re-using the - existing transaction record. If the inner transaction is cancelled - then a subsequent commit will fail - - - keep a mirrored copy of the tdb hash chain heads to allow for the - fast hash heads scan on traverse, updating the mirrored copy in - the transaction version of tdb_write - - - allow callers to mix transaction and non-transaction use of tdb, - although once a transaction is started then an exclusive lock is - gained until the transaction is committed or cancelled - - - the commit stategy involves first saving away all modified data - into a linearised buffer in the transaction recovery area, then - marking the transaction recovery area with a magic value to - indicate a valid recovery record. In total 4 fsync/msync calls are - needed per commit to prevent race conditions. It might be possible - to reduce this to 3 or even 2 with some more work. - - - check for a valid recovery record on open of the tdb, while the - global lock is held. Automatically recover from the transaction - recovery area if needed, then continue with the open as - usual. This allows for smooth crash recovery with no administrator - intervention. - - - if TDB_NOSYNC is passed to flags in tdb_open then transactions are - still available, but no transaction recovery area is used and no - fsync/msync calls are made. - - - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using - tdb_add_flags() transaction nesting is enabled. - It resets the TDB_DISALLOW_NESTING flag, as both cannot be used together. - The default is that transaction nesting is allowed. - Note: this default may change in future versions of tdb. - - Beware. when transactions are nested a transaction successfully - completed with tdb_transaction_commit() can be silently unrolled later. - - - if TDB_DISALLOW_NESTING is passed to flags in tdb open, or added using - tdb_add_flags() transaction nesting is disabled. - It resets the TDB_ALLOW_NESTING flag, as both cannot be used together. - An attempt create a nested transaction will fail with TDB_ERR_NESTING. - The default is that transaction nesting is allowed. - Note: this default may change in future versions of tdb. -*/ - - -/* - hold the context of any current transaction -*/ -struct tdb_transaction { - /* we keep a mirrored copy of the tdb hash heads here so - tdb_next_hash_chain() can operate efficiently */ - uint32_t *hash_heads; - - /* the original io methods - used to do IOs to the real db */ - const struct tdb_methods *io_methods; - - /* the list of transaction blocks. When a block is first - written to, it gets created in this list */ - uint8_t **blocks; - uint32_t num_blocks; - uint32_t block_size; /* bytes in each block */ - uint32_t last_block_size; /* number of valid bytes in the last block */ - - /* non-zero when an internal transaction error has - occurred. All write operations will then fail until the - transaction is ended */ - int transaction_error; - - /* when inside a transaction we need to keep track of any - nested tdb_transaction_start() calls, as these are allowed, - but don't create a new transaction */ - int nesting; - - /* set when a prepare has already occurred */ - bool prepared; - tdb_off_t magic_offset; - - /* set when the GLOBAL_LOCK has been taken */ - bool global_lock_taken; - - /* old file size before transaction */ - tdb_len_t old_map_size; - - /* we should re-pack on commit */ - bool need_repack; -}; - - -/* - read while in a transaction. We need to check first if the data is in our list - of transaction elements, then if not do a real read -*/ -static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, - tdb_len_t len, int cv) -{ - uint32_t blk; - - /* break it down into block sized ops */ - while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); - if (transaction_read(tdb, off, buf, len2, cv) != 0) { - return -1; - } - len -= len2; - off += len2; - buf = (void *)(len2 + (char *)buf); - } - - if (len == 0) { - return 0; - } - - blk = off / tdb->transaction->block_size; - - /* see if we have it in the block list */ - if (tdb->transaction->num_blocks <= blk || - tdb->transaction->blocks[blk] == NULL) { - /* nope, do a real read */ - if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) { - goto fail; - } - return 0; - } - - /* it is in the block list. Now check for the last block */ - if (blk == tdb->transaction->num_blocks-1) { - if (len > tdb->transaction->last_block_size) { - goto fail; - } - } - - /* now copy it out of this block */ - memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len); - if (cv) { - tdb_convert(buf, len); - } - return 0; - -fail: - TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len)); - tdb->ecode = TDB_ERR_IO; - tdb->transaction->transaction_error = 1; - return -1; -} - - -/* - write while in a transaction -*/ -static int transaction_write(struct tdb_context *tdb, tdb_off_t off, - const void *buf, tdb_len_t len) -{ - uint32_t blk; - - /* Only a commit is allowed on a prepared transaction */ - if (tdb->transaction->prepared) { - tdb->ecode = TDB_ERR_EINVAL; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n")); - tdb->transaction->transaction_error = 1; - return -1; - } - - /* if the write is to a hash head, then update the transaction - hash heads */ - if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP && - off < FREELIST_TOP+TDB_HASHTABLE_SIZE(tdb)) { - uint32_t chain = (off-FREELIST_TOP) / sizeof(tdb_off_t); - memcpy(&tdb->transaction->hash_heads[chain], buf, len); - } - - /* break it up into block sized chunks */ - while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); - if (transaction_write(tdb, off, buf, len2) != 0) { - return -1; - } - len -= len2; - off += len2; - if (buf != NULL) { - buf = (const void *)(len2 + (const char *)buf); - } - } - - if (len == 0) { - return 0; - } - - blk = off / tdb->transaction->block_size; - off = off % tdb->transaction->block_size; - - if (tdb->transaction->num_blocks <= blk) { - uint8_t **new_blocks; - /* expand the blocks array */ - if (tdb->transaction->blocks == NULL) { - new_blocks = (uint8_t **)malloc( - (blk+1)*sizeof(uint8_t *)); - } else { - new_blocks = (uint8_t **)realloc( - tdb->transaction->blocks, - (blk+1)*sizeof(uint8_t *)); - } - if (new_blocks == NULL) { - tdb->ecode = TDB_ERR_OOM; - goto fail; - } - memset(&new_blocks[tdb->transaction->num_blocks], 0, - (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *)); - tdb->transaction->blocks = new_blocks; - tdb->transaction->num_blocks = blk+1; - tdb->transaction->last_block_size = 0; - } - - /* allocate and fill a block? */ - if (tdb->transaction->blocks[blk] == NULL) { - tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1); - if (tdb->transaction->blocks[blk] == NULL) { - tdb->ecode = TDB_ERR_OOM; - tdb->transaction->transaction_error = 1; - return -1; - } - if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size; - if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) { - len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size); - } - if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size, - tdb->transaction->blocks[blk], - len2, 0) != 0) { - SAFE_FREE(tdb->transaction->blocks[blk]); - tdb->ecode = TDB_ERR_IO; - goto fail; - } - if (blk == tdb->transaction->num_blocks-1) { - tdb->transaction->last_block_size = len2; - } - } - } - - /* overwrite part of an existing block */ - if (buf == NULL) { - memset(tdb->transaction->blocks[blk] + off, 0, len); - } else { - memcpy(tdb->transaction->blocks[blk] + off, buf, len); - } - if (blk == tdb->transaction->num_blocks-1) { - if (len + off > tdb->transaction->last_block_size) { - tdb->transaction->last_block_size = len + off; - } - } - - return 0; - -fail: - TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", - (blk*tdb->transaction->block_size) + off, len)); - tdb->transaction->transaction_error = 1; - return -1; -} - - -/* - write while in a transaction - this varient never expands the transaction blocks, it only - updates existing blocks. This means it cannot change the recovery size -*/ -static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off, - const void *buf, tdb_len_t len) -{ - uint32_t blk; - - /* break it up into block sized chunks */ - while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); - if (transaction_write_existing(tdb, off, buf, len2) != 0) { - return -1; - } - len -= len2; - off += len2; - if (buf != NULL) { - buf = (const void *)(len2 + (const char *)buf); - } - } - - if (len == 0) { - return 0; - } - - blk = off / tdb->transaction->block_size; - off = off % tdb->transaction->block_size; - - if (tdb->transaction->num_blocks <= blk || - tdb->transaction->blocks[blk] == NULL) { - return 0; - } - - if (blk == tdb->transaction->num_blocks-1 && - off + len > tdb->transaction->last_block_size) { - if (off >= tdb->transaction->last_block_size) { - return 0; - } - len = tdb->transaction->last_block_size - off; - } - - /* overwrite part of an existing block */ - memcpy(tdb->transaction->blocks[blk] + off, buf, len); - - return 0; -} - - -/* - accelerated hash chain head search, using the cached hash heads -*/ -static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain) -{ - uint32_t h = *chain; - for (;h < tdb->header.hash_size;h++) { - /* the +1 takes account of the freelist */ - if (0 != tdb->transaction->hash_heads[h+1]) { - break; - } - } - (*chain) = h; -} - -/* - out of bounds check during a transaction -*/ -static int transaction_oob(struct tdb_context *tdb, tdb_off_t len, int probe) -{ - if (len <= tdb->map_size) { - return 0; - } - tdb->ecode = TDB_ERR_IO; - return -1; -} - -/* - transaction version of tdb_expand(). -*/ -static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size, - tdb_off_t addition) -{ - /* add a write to the transaction elements, so subsequent - reads see the zero data */ - if (transaction_write(tdb, size, NULL, addition) != 0) { - return -1; - } - - tdb->transaction->need_repack = true; - - return 0; -} - -/* - brlock during a transaction - ignore them -*/ -static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset, - int rw_type, int lck_type, int probe, size_t len) -{ - return 0; -} - -static const struct tdb_methods transaction_methods = { - transaction_read, - transaction_write, - transaction_next_hash_chain, - transaction_oob, - transaction_expand_file, - transaction_brlock -}; - - -/* - start a tdb transaction. No token is returned, as only a single - transaction is allowed to be pending per tdb_context -*/ -int tdb_transaction_start(struct tdb_context *tdb) -{ - /* some sanity checks */ - if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n")); - tdb->ecode = TDB_ERR_EINVAL; - return -1; - } - - /* cope with nested tdb_transaction_start() calls */ - if (tdb->transaction != NULL) { - if (!(tdb->flags & TDB_ALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - return -1; - } - tdb->transaction->nesting++; - TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", - tdb->transaction->nesting)); - return 0; - } - - if (tdb->num_locks != 0 || tdb->global_lock.count) { - /* the caller must not have any locks when starting a - transaction as otherwise we'll be screwed by lack - of nested locks in posix */ - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n")); - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->travlocks.next != NULL) { - /* you cannot use transactions inside a traverse (although you can use - traverse inside a transaction) as otherwise you can end up with - deadlock */ - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n")); - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - tdb->transaction = (struct tdb_transaction *) - calloc(sizeof(struct tdb_transaction), 1); - if (tdb->transaction == NULL) { - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - /* a page at a time seems like a reasonable compromise between compactness and efficiency */ - tdb->transaction->block_size = tdb->page_size; - - /* get the transaction write lock. This is a blocking lock. As - discussed with Volker, there are a number of ways we could - make this async, which we will probably do in the future */ - if (tdb_transaction_lock(tdb, F_WRLCK) == -1) { - SAFE_FREE(tdb->transaction->blocks); - SAFE_FREE(tdb->transaction); - return -1; - } - - /* get a read lock from the freelist to the end of file. This - is upgraded to a write lock during the commit */ - if (tdb_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n")); - tdb->ecode = TDB_ERR_LOCK; - goto fail; - } - - /* setup a copy of the hash table heads so the hash scan in - traverse can be fast */ - tdb->transaction->hash_heads = (uint32_t *) - calloc(tdb->header.hash_size+1, sizeof(uint32_t)); - if (tdb->transaction->hash_heads == NULL) { - tdb->ecode = TDB_ERR_OOM; - goto fail; - } - if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads, - TDB_HASHTABLE_SIZE(tdb), 0) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n")); - tdb->ecode = TDB_ERR_IO; - goto fail; - } - - /* make sure we know about any file expansions already done by - anyone else */ - tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1); - tdb->transaction->old_map_size = tdb->map_size; - - /* finally hook the io methods, replacing them with - transaction specific methods */ - tdb->transaction->io_methods = tdb->methods; - tdb->methods = &transaction_methods; - - /* Trace at the end, so we get sequence number correct. */ - tdb_trace(tdb, "tdb_transaction_start"); - return 0; - -fail: - tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0); - tdb_transaction_unlock(tdb); - SAFE_FREE(tdb->transaction->blocks); - SAFE_FREE(tdb->transaction->hash_heads); - SAFE_FREE(tdb->transaction); - return -1; -} - - -/* - sync to disk -*/ -static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length) -{ - if (tdb->flags & TDB_NOSYNC) { - return 0; - } - - if (fsync(tdb->fd) != 0) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); - return -1; - } -#ifdef HAVE_MMAP - if (tdb->map_ptr) { - tdb_off_t moffset = offset & ~(tdb->page_size-1); - if (msync(moffset + (char *)tdb->map_ptr, - length + (offset - moffset), MS_SYNC) != 0) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n", - strerror(errno))); - return -1; - } - } -#endif - return 0; -} - - -int _tdb_transaction_cancel(struct tdb_context *tdb) -{ - int i, ret = 0; - - if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n")); - return -1; - } - - if (tdb->transaction->nesting != 0) { - tdb->transaction->transaction_error = 1; - tdb->transaction->nesting--; - return 0; - } - - tdb->map_size = tdb->transaction->old_map_size; - - /* free all the transaction blocks */ - for (i=0;i<tdb->transaction->num_blocks;i++) { - if (tdb->transaction->blocks[i] != NULL) { - free(tdb->transaction->blocks[i]); - } - } - SAFE_FREE(tdb->transaction->blocks); - - if (tdb->transaction->magic_offset) { - const struct tdb_methods *methods = tdb->transaction->io_methods; - uint32_t zero = 0; - - /* remove the recovery marker */ - if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &zero, 4) == -1 || - transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n")); - ret = -1; - } - } - - if (tdb->transaction->global_lock_taken) { - tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); - tdb->transaction->global_lock_taken = false; - } - - /* remove any global lock created during the transaction */ - if (tdb->global_lock.count != 0) { - tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size); - tdb->global_lock.count = 0; - } - - /* remove any locks created during the transaction */ - if (tdb->num_locks != 0) { - for (i=0;i<tdb->num_lockrecs;i++) { - tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list, - F_UNLCK,F_SETLKW, 0, 1); - } - tdb->num_locks = 0; - tdb->num_lockrecs = 0; - SAFE_FREE(tdb->lockrecs); - } - - /* restore the normal io methods */ - tdb->methods = tdb->transaction->io_methods; - - tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0); - tdb_transaction_unlock(tdb); - SAFE_FREE(tdb->transaction->hash_heads); - SAFE_FREE(tdb->transaction); - - return ret; -} - -/* - cancel the current transaction -*/ -int tdb_transaction_cancel(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_transaction_cancel"); - return _tdb_transaction_cancel(tdb); -} - -/* - work out how much space the linearised recovery data will consume -*/ -static tdb_len_t tdb_recovery_size(struct tdb_context *tdb) -{ - tdb_len_t recovery_size = 0; - int i; - - recovery_size = sizeof(uint32_t); - for (i=0;i<tdb->transaction->num_blocks;i++) { - if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) { - break; - } - if (tdb->transaction->blocks[i] == NULL) { - continue; - } - recovery_size += 2*sizeof(tdb_off_t); - if (i == tdb->transaction->num_blocks-1) { - recovery_size += tdb->transaction->last_block_size; - } else { - recovery_size += tdb->transaction->block_size; - } - } - - return recovery_size; -} - -/* - allocate the recovery area, or use an existing recovery area if it is - large enough -*/ -static int tdb_recovery_allocate(struct tdb_context *tdb, - tdb_len_t *recovery_size, - tdb_off_t *recovery_offset, - tdb_len_t *recovery_max_size) -{ - struct tdb_record rec; - const struct tdb_methods *methods = tdb->transaction->io_methods; - tdb_off_t recovery_head; - - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n")); - return -1; - } - - rec.rec_len = 0; - - if (recovery_head != 0 && - methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n")); - return -1; - } - - *recovery_size = tdb_recovery_size(tdb); - - if (recovery_head != 0 && *recovery_size <= rec.rec_len) { - /* it fits in the existing area */ - *recovery_max_size = rec.rec_len; - *recovery_offset = recovery_head; - return 0; - } - - /* we need to free up the old recovery area, then allocate a - new one at the end of the file. Note that we cannot use - tdb_allocate() to allocate the new one as that might return - us an area that is being currently used (as of the start of - the transaction) */ - if (recovery_head != 0) { - if (tdb_free(tdb, recovery_head, &rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to free previous recovery area\n")); - return -1; - } - } - - /* the tdb_free() call might have increased the recovery size */ - *recovery_size = tdb_recovery_size(tdb); - - /* round up to a multiple of page size */ - *recovery_max_size = TDB_ALIGN(sizeof(rec) + *recovery_size, tdb->page_size) - sizeof(rec); - *recovery_offset = tdb->map_size; - recovery_head = *recovery_offset; - - if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, - (tdb->map_size - tdb->transaction->old_map_size) + - sizeof(rec) + *recovery_max_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n")); - return -1; - } - - /* remap the file (if using mmap) */ - methods->tdb_oob(tdb, tdb->map_size + 1, 1); - - /* we have to reset the old map size so that we don't try to expand the file - again in the transaction commit, which would destroy the recovery area */ - tdb->transaction->old_map_size = tdb->map_size; - - /* write the recovery header offset and sync - we can sync without a race here - as the magic ptr in the recovery record has not been set */ - CONVERT(recovery_head); - if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD, - &recovery_head, sizeof(tdb_off_t)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n")); - return -1; - } - if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n")); - return -1; - } - - return 0; -} - - -/* - setup the recovery data that will be used on a crash during commit -*/ -static int transaction_setup_recovery(struct tdb_context *tdb, - tdb_off_t *magic_offset) -{ - tdb_len_t recovery_size; - unsigned char *data, *p; - const struct tdb_methods *methods = tdb->transaction->io_methods; - struct tdb_record *rec; - tdb_off_t recovery_offset, recovery_max_size; - tdb_off_t old_map_size = tdb->transaction->old_map_size; - uint32_t magic, tailer; - int i; - - /* - check that the recovery area has enough space - */ - if (tdb_recovery_allocate(tdb, &recovery_size, - &recovery_offset, &recovery_max_size) == -1) { - return -1; - } - - data = (unsigned char *)malloc(recovery_size + sizeof(*rec)); - if (data == NULL) { - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - rec = (struct tdb_record *)data; - memset(rec, 0, sizeof(*rec)); - - rec->magic = 0; - rec->data_len = recovery_size; - rec->rec_len = recovery_max_size; - rec->key_len = old_map_size; - CONVERT(rec); - - /* build the recovery data into a single blob to allow us to do a single - large write, which should be more efficient */ - p = data + sizeof(*rec); - for (i=0;i<tdb->transaction->num_blocks;i++) { - tdb_off_t offset; - tdb_len_t length; - - if (tdb->transaction->blocks[i] == NULL) { - continue; - } - - offset = i * tdb->transaction->block_size; - length = tdb->transaction->block_size; - if (i == tdb->transaction->num_blocks-1) { - length = tdb->transaction->last_block_size; - } - - if (offset >= old_map_size) { - continue; - } - if (offset + length > tdb->transaction->old_map_size) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n")); - free(data); - tdb->ecode = TDB_ERR_CORRUPT; - return -1; - } - memcpy(p, &offset, 4); - memcpy(p+4, &length, 4); - if (DOCONV()) { - tdb_convert(p, 8); - } - /* the recovery area contains the old data, not the - new data, so we have to call the original tdb_read - method to get it */ - if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) { - free(data); - tdb->ecode = TDB_ERR_IO; - return -1; - } - p += 8 + length; - } - - /* and the tailer */ - tailer = sizeof(*rec) + recovery_max_size; - memcpy(p, &tailer, 4); - CONVERT(p); - - /* write the recovery data to the recovery area */ - if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n")); - free(data); - tdb->ecode = TDB_ERR_IO; - return -1; - } - if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n")); - free(data); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* as we don't have ordered writes, we have to sync the recovery - data before we update the magic to indicate that the recovery - data is present */ - if (transaction_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) { - free(data); - return -1; - } - - free(data); - - magic = TDB_RECOVERY_MAGIC; - CONVERT(magic); - - *magic_offset = recovery_offset + offsetof(struct tdb_record, magic); - - if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* ensure the recovery magic marker is on disk */ - if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) { - return -1; - } - - return 0; -} - -static int _tdb_transaction_prepare_commit(struct tdb_context *tdb) -{ - const struct tdb_methods *methods; - - if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n")); - return -1; - } - - if (tdb->transaction->prepared) { - tdb->ecode = TDB_ERR_EINVAL; - _tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n")); - return -1; - } - - if (tdb->transaction->transaction_error) { - tdb->ecode = TDB_ERR_IO; - _tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n")); - return -1; - } - - - if (tdb->transaction->nesting != 0) { - return 0; - } - - /* check for a null transaction */ - if (tdb->transaction->blocks == NULL) { - return 0; - } - - methods = tdb->transaction->io_methods; - - /* if there are any locks pending then the caller has not - nested their locks properly, so fail the transaction */ - if (tdb->num_locks || tdb->global_lock.count) { - tdb->ecode = TDB_ERR_LOCK; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - - /* upgrade the main transaction lock region to a write lock */ - if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); - tdb->ecode = TDB_ERR_LOCK; - _tdb_transaction_cancel(tdb); - return -1; - } - - /* get the global lock - this prevents new users attaching to the database - during the commit */ - if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n")); - tdb->ecode = TDB_ERR_LOCK; - _tdb_transaction_cancel(tdb); - return -1; - } - - tdb->transaction->global_lock_taken = true; - - if (!(tdb->flags & TDB_NOSYNC)) { - /* write the recovery data to the end of the file */ - if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - } - - tdb->transaction->prepared = true; - - /* expand the file to the new size if needed */ - if (tdb->map_size != tdb->transaction->old_map_size) { - if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, - tdb->map_size - - tdb->transaction->old_map_size) == -1) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - tdb->map_size = tdb->transaction->old_map_size; - methods->tdb_oob(tdb, tdb->map_size + 1, 1); - } - - /* Keep the global lock until the actual commit */ - - return 0; -} - -/* - prepare to commit the current transaction -*/ -int tdb_transaction_prepare_commit(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_transaction_prepare_commit"); - return _tdb_transaction_prepare_commit(tdb); -} - -/* - commit the current transaction -*/ -int tdb_transaction_commit(struct tdb_context *tdb) -{ - const struct tdb_methods *methods; - int i; - bool need_repack; - - if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n")); - return -1; - } - - tdb_trace(tdb, "tdb_transaction_commit"); - - if (tdb->transaction->transaction_error) { - tdb->ecode = TDB_ERR_IO; - _tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n")); - return -1; - } - - - if (tdb->transaction->nesting != 0) { - tdb->transaction->nesting--; - return 0; - } - - /* check for a null transaction */ - if (tdb->transaction->blocks == NULL) { - _tdb_transaction_cancel(tdb); - return 0; - } - - if (!tdb->transaction->prepared) { - int ret = _tdb_transaction_prepare_commit(tdb); - if (ret) - return ret; - } - - methods = tdb->transaction->io_methods; - - /* perform all the writes */ - for (i=0;i<tdb->transaction->num_blocks;i++) { - tdb_off_t offset; - tdb_len_t length; - - if (tdb->transaction->blocks[i] == NULL) { - continue; - } - - offset = i * tdb->transaction->block_size; - length = tdb->transaction->block_size; - if (i == tdb->transaction->num_blocks-1) { - length = tdb->transaction->last_block_size; - } - - if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n")); - - /* we've overwritten part of the data and - possibly expanded the file, so we need to - run the crash recovery code */ - tdb->methods = methods; - tdb_transaction_recover(tdb); - - _tdb_transaction_cancel(tdb); - - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n")); - return -1; - } - SAFE_FREE(tdb->transaction->blocks[i]); - } - - SAFE_FREE(tdb->transaction->blocks); - tdb->transaction->num_blocks = 0; - - /* ensure the new data is on disk */ - if (transaction_sync(tdb, 0, tdb->map_size) == -1) { - return -1; - } - - /* - TODO: maybe write to some dummy hdr field, or write to magic - offset without mmap, before the last sync, instead of the - utime() call - */ - - /* on some systems (like Linux 2.6.x) changes via mmap/msync - don't change the mtime of the file, this means the file may - not be backed up (as tdb rounding to block sizes means that - file size changes are quite rare too). The following forces - mtime changes when a transaction completes */ -#ifdef HAVE_UTIME - utime(tdb->name, NULL); -#endif - - need_repack = tdb->transaction->need_repack; - - /* use a transaction cancel to free memory and remove the - transaction locks */ - _tdb_transaction_cancel(tdb); - - if (need_repack) { - return tdb_repack(tdb); - } - - return 0; -} - - -/* - recover from an aborted transaction. Must be called with exclusive - database write access already established (including the global - lock to prevent new processes attaching) -*/ -int tdb_transaction_recover(struct tdb_context *tdb) -{ - tdb_off_t recovery_head, recovery_eof; - unsigned char *data, *p; - uint32_t zero = 0; - struct tdb_record rec; - - /* find the recovery area */ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - if (recovery_head == 0) { - /* we have never allocated a recovery record */ - return 0; - } - - /* read the recovery record */ - if (tdb->methods->tdb_read(tdb, recovery_head, &rec, - sizeof(rec), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - if (rec.magic != TDB_RECOVERY_MAGIC) { - /* there is no valid recovery data */ - return 0; - } - - if (tdb->read_only) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n")); - tdb->ecode = TDB_ERR_CORRUPT; - return -1; - } - - recovery_eof = rec.key_len; - - data = (unsigned char *)malloc(rec.data_len); - if (data == NULL) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n")); - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - /* read the full recovery data */ - if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data, - rec.data_len, 0) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* recover the file data */ - p = data; - while (p+8 < data + rec.data_len) { - uint32_t ofs, len; - if (DOCONV()) { - tdb_convert(p, 8); - } - memcpy(&ofs, p, 4); - memcpy(&len, p+4, 4); - - if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) { - free(data); - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs)); - tdb->ecode = TDB_ERR_IO; - return -1; - } - p += 8 + len; - } - - free(data); - - if (transaction_sync(tdb, 0, tdb->map_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* if the recovery area is after the recovered eof then remove it */ - if (recovery_eof <= recovery_head) { - if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - } - - /* remove the recovery magic */ - if (tdb_ofs_write(tdb, recovery_head + offsetof(struct tdb_record, magic), - &zero) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* reduce the file size to the old size */ - tdb_munmap(tdb); - if (ftruncate(tdb->fd, recovery_eof) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - tdb->map_size = recovery_eof; - tdb_mmap(tdb); - - if (transaction_sync(tdb, 0, recovery_eof) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n", - recovery_eof)); - - /* all done */ - return 0; -} diff --git a/libatalk/tdb/traverse.c b/libatalk/tdb/traverse.c deleted file mode 100644 index c340dd354b..0000000000 --- a/libatalk/tdb/traverse.c +++ /dev/null @@ -1,366 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "tdb_private.h" - -#define TDB_NEXT_LOCK_ERR ((tdb_off_t)-1) - -/* Uses traverse lock: 0 = finish, TDB_NEXT_LOCK_ERR = error, - other = record offset */ -static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock, - struct tdb_record *rec) -{ - int want_next = (tlock->off != 0); - - /* Lock each chain from the start one. */ - for (; tlock->hash < tdb->header.hash_size; tlock->hash++) { - if (!tlock->off && tlock->hash != 0) { - /* this is an optimisation for the common case where - the hash chain is empty, which is particularly - common for the use of tdb with ldb, where large - hashes are used. In that case we spend most of our - time in tdb_brlock(), locking empty hash chains. - - To avoid this, we do an unlocked pre-check to see - if the hash chain is empty before starting to look - inside it. If it is empty then we can avoid that - hash chain. If it isn't empty then we can't believe - the value we get back, as we read it without a - lock, so instead we get the lock and re-fetch the - value below. - - Notice that not doing this optimisation on the - first hash chain is critical. We must guarantee - that we have done at least one fcntl lock at the - start of a search to guarantee that memory is - coherent on SMP systems. If records are added by - others during the search then thats OK, and we - could possibly miss those with this trick, but we - could miss them anyway without this trick, so the - semantics don't change. - - With a non-indexed ldb search this trick gains us a - factor of around 80 in speed on a linux 2.6.x - system (testing using ldbtest). - */ - tdb->methods->next_hash_chain(tdb, &tlock->hash); - if (tlock->hash == tdb->header.hash_size) { - continue; - } - } - - if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1) - return TDB_NEXT_LOCK_ERR; - - /* No previous record? Start at top of chain. */ - if (!tlock->off) { - if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash), - &tlock->off) == -1) - goto fail; - } else { - /* Otherwise unlock the previous record. */ - if (tdb_unlock_record(tdb, tlock->off) != 0) - goto fail; - } - - if (want_next) { - /* We have offset of old record: grab next */ - if (tdb_rec_read(tdb, tlock->off, rec) == -1) - goto fail; - tlock->off = rec->next; - } - - /* Iterate through chain */ - while( tlock->off) { - tdb_off_t current; - if (tdb_rec_read(tdb, tlock->off, rec) == -1) - goto fail; - - /* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */ - if (tlock->off == rec->next) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n")); - goto fail; - } - - if (!TDB_DEAD(rec)) { - /* Woohoo: we found one! */ - if (tdb_lock_record(tdb, tlock->off) != 0) - goto fail; - return tlock->off; - } - - /* Try to clean dead ones from old traverses */ - current = tlock->off; - tlock->off = rec->next; - if (!(tdb->read_only || tdb->traverse_read) && - tdb_do_delete(tdb, current, rec) != 0) - goto fail; - } - tdb_unlock(tdb, tlock->hash, tlock->lock_rw); - want_next = 0; - } - /* We finished iteration without finding anything */ - tdb->ecode = TDB_SUCCESS; - return 0; - - fail: - tlock->off = 0; - if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n")); - return TDB_NEXT_LOCK_ERR; -} - -/* traverse the entire database - calling fn(tdb, key, data) on each element. - return -1 on error or the record count traversed - if fn is NULL then it is not called - a non-zero return value from fn() indicates that the traversal should stop - */ -static int tdb_traverse_internal(struct tdb_context *tdb, - tdb_traverse_func fn, void *private_data, - struct tdb_traverse_lock *tl) -{ - TDB_DATA key, dbuf; - struct tdb_record rec; - int ret = 0, count = 0; - tdb_off_t off; - - /* This was in the initializaton, above, but the IRIX compiler - * did not like it. crh - */ - tl->next = tdb->travlocks.next; - - /* fcntl locks don't stack: beware traverse inside traverse */ - tdb->travlocks.next = tl; - - /* tdb_next_lock places locks on the record returned, and its chain */ - while ((off = tdb_next_lock(tdb, tl, &rec)) != 0) { - if (off == TDB_NEXT_LOCK_ERR) { - ret = -1; - goto out; - } - count++; - /* now read the full record */ - key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), - rec.key_len + rec.data_len); - if (!key.dptr) { - ret = -1; - if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) - goto out; - if (tdb_unlock_record(tdb, tl->off) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n")); - goto out; - } - key.dsize = rec.key_len; - dbuf.dptr = key.dptr + rec.key_len; - dbuf.dsize = rec.data_len; - - tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf); - - /* Drop chain lock, call out */ - if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) { - ret = -1; - SAFE_FREE(key.dptr); - goto out; - } - if (fn && fn(tdb, key, dbuf, private_data)) { - /* They want us to terminate traversal */ - tdb_trace_ret(tdb, "tdb_traverse_end", count); - if (tdb_unlock_record(tdb, tl->off) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));; - ret = -1; - } - SAFE_FREE(key.dptr); - goto out; - } - SAFE_FREE(key.dptr); - } - tdb_trace(tdb, "tdb_traverse_end"); -out: - tdb->travlocks.next = tl->next; - if (ret < 0) - return -1; - else - return count; -} - - -/* - a write style traverse - temporarily marks the db read only -*/ -int tdb_traverse_read(struct tdb_context *tdb, - tdb_traverse_func fn, void *private_data) -{ - struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK }; - int ret; - - /* we need to get a read lock on the transaction lock here to - cope with the lock ordering semantics of solaris10 */ - if (tdb_transaction_lock(tdb, F_RDLCK)) { - return -1; - } - - tdb->traverse_read++; - tdb_trace(tdb, "tdb_traverse_read_start"); - ret = tdb_traverse_internal(tdb, fn, private_data, &tl); - tdb->traverse_read--; - - tdb_transaction_unlock(tdb); - - return ret; -} - -/* - a write style traverse - needs to get the transaction lock to - prevent deadlocks - - WARNING: The data buffer given to the callback fn does NOT meet the - alignment restrictions malloc gives you. -*/ -int tdb_traverse(struct tdb_context *tdb, - tdb_traverse_func fn, void *private_data) -{ - struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; - int ret; - - if (tdb->read_only || tdb->traverse_read) { - return tdb_traverse_read(tdb, fn, private_data); - } - - if (tdb_transaction_lock(tdb, F_WRLCK)) { - return -1; - } - - tdb->traverse_write++; - tdb_trace(tdb, "tdb_traverse_start"); - ret = tdb_traverse_internal(tdb, fn, private_data, &tl); - tdb->traverse_write--; - - tdb_transaction_unlock(tdb); - - return ret; -} - - -/* find the first entry in the database and return its key */ -TDB_DATA tdb_firstkey(struct tdb_context *tdb) -{ - TDB_DATA key; - struct tdb_record rec; - tdb_off_t off; - - /* release any old lock */ - if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) - return tdb_null; - tdb->travlocks.off = tdb->travlocks.hash = 0; - tdb->travlocks.lock_rw = F_RDLCK; - - /* Grab first record: locks chain and returned record. */ - off = tdb_next_lock(tdb, &tdb->travlocks, &rec); - if (off == 0 || off == TDB_NEXT_LOCK_ERR) { - tdb_trace_retrec(tdb, "tdb_firstkey", tdb_null); - return tdb_null; - } - /* now read the key */ - key.dsize = rec.key_len; - key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize); - - tdb_trace_retrec(tdb, "tdb_firstkey", key); - - /* Unlock the hash chain of the record we just read. */ - if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n")); - return key; -} - -/* find the next entry in the database, returning its key */ -TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey) -{ - uint32_t oldhash; - TDB_DATA key = tdb_null; - struct tdb_record rec; - unsigned char *k = NULL; - tdb_off_t off; - - /* Is locked key the old key? If so, traverse will be reliable. */ - if (tdb->travlocks.off) { - if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw)) - return tdb_null; - if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1 - || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec), - rec.key_len)) - || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) { - /* No, it wasn't: unlock it and start from scratch */ - if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) { - tdb_trace_1rec_retrec(tdb, "tdb_nextkey", - oldkey, tdb_null); - SAFE_FREE(k); - return tdb_null; - } - if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) { - SAFE_FREE(k); - return tdb_null; - } - tdb->travlocks.off = 0; - } - - SAFE_FREE(k); - } - - if (!tdb->travlocks.off) { - /* No previous element: do normal find, and lock record */ - tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec); - if (!tdb->travlocks.off) { - tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null); - return tdb_null; - } - tdb->travlocks.hash = BUCKET(rec.full_hash); - if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno))); - return tdb_null; - } - } - oldhash = tdb->travlocks.hash; - - /* Grab next record: locks chain and returned record, - unlocks old record */ - off = tdb_next_lock(tdb, &tdb->travlocks, &rec); - if (off != TDB_NEXT_LOCK_ERR && off != 0) { - key.dsize = rec.key_len; - key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec), - key.dsize); - /* Unlock the chain of this new record */ - if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n")); - } - /* Unlock the chain of old record */ - if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n")); - tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key); - return key; -} - diff --git a/macros/cnid-backend.m4 b/macros/cnid-backend.m4 index 6efebd17ca..5af15e286b 100644 --- a/macros/cnid-backend.m4 +++ b/macros/cnid-backend.m4 @@ -29,33 +29,6 @@ AC_DEFUN([AC_NETATALK_CNID], [ fi AM_CONDITIONAL(BUILD_DBD_DAEMON, test x"$use_dbd_backend" = x"yes") - dnl Determine whether or not to use BDB Concurrent Data Store - AC_MSG_CHECKING([whether or not to use BDB Concurrent Data Store]) - AC_ARG_WITH(cnid-cdb-backend, - [ --with-cnid-cdb-backend build CNID with Concurrent BDB Data Store [[no]]],[ - if test x"$withval" = x"no"; then - use_cdb_backend=no - else - use_cdb_backend=yes - fi - ],[ - use_cdb_backend=no - ]) - - - if test $use_cdb_backend = yes; then - AC_MSG_RESULT([yes]) - AC_DEFINE(CNID_BACKEND_CDB, 1, [Define if CNID Concurrent BDB backend should be compiled.]) - if test x"$DEFAULT_CNID_SCHEME" = x; then - DEFAULT_CNID_SCHEME=cdb - fi - bdb_required=yes - compiled_backends="$compiled_backends cdb" - else - AC_MSG_RESULT([no]) - fi - AM_CONDITIONAL(USE_CDB_BACKEND, test x"$use_cdb_backend" = x"yes") - dnl Determine whether or not to use LAST DID scheme AC_MSG_CHECKING([whether or not to use LAST DID scheme]) AC_ARG_WITH(cnid-last-backend, @@ -82,32 +55,6 @@ AC_DEFUN([AC_NETATALK_CNID], [ fi AM_CONDITIONAL(USE_LAST_BACKEND, test x"$use_last_backend" = x"yes") - dnl Determine whether or not to use TDB DID scheme - AC_MSG_CHECKING([whether or not to use TDB DID scheme]) - AC_ARG_WITH(cnid-tdb-backend, - [ --with-cnid-tdb-backend build TDB CNID scheme [[yes]]], - [ - if test x"$withval" = x"no"; then - use_tdb_backend=no - else - use_tdb_backend=yes - fi - ],[ - use_tdb_backend=yes - ]) - - if test $use_tdb_backend = yes; then - AC_MSG_RESULT([yes]) - AC_DEFINE(CNID_BACKEND_TDB, 1, [Define if CNID TDB scheme backend should be compiled.]) - if test x"$DEFAULT_CNID_SCHEME" = x; then - DEFAULT_CNID_SCHEME=tdb - fi - compiled_backends="$compiled_backends tdb" - else - AC_MSG_RESULT([no]) - fi - AM_CONDITIONAL(USE_TDB_BACKEND, test x"$use_tdb_backend" = x"yes") - dnl Check for mysql CNID backend AC_ARG_VAR(MYSQL_CFLAGS, [C compiler flags for MySQL, overriding checks]) AC_ARG_VAR(MYSQL_LIBS, [linker flags for MySQL, overriding checks]) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index 2e3383fcf9..6579f2aec2 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -235,31 +235,6 @@ AC_DEFUN([AC_NETATALK_LIBEVENT], [ AC_SUBST(LIBEVENT_LIBS) ]) -dnl Whether to disable bundled tdb -AC_DEFUN([AC_NETATALK_TDB], [ - AC_ARG_WITH( - tdb, - [AS_HELP_STRING([--with-tdb],[whether to use the bundled tdb (default: yes)])], - use_bundled_tdb=$withval, - use_bundled_tdb=yes - ) - AC_MSG_CHECKING([whether to use bundled tdb]) - AC_MSG_RESULT([$use_bundled_tdb]) - - if test x"$use_bundled_tdb" = x"yes" ; then - AC_DEFINE(USE_BUILTIN_TDB, 1, [Use internal tbd]) - else - if test -z "$TDB_LIBS" ; then - PKG_CHECK_MODULES(TDB, tdb, , [AC_MSG_ERROR([couldn't find tdb with pkg-config])]) - fi - use_bundled_tdb=no - fi - - AC_SUBST(TDB_CFLAGS) - AC_SUBST(TDB_LIBS) - AM_CONDITIONAL(USE_BUILTIN_TDB, test x"$use_bundled_tdb" = x"yes") -]) - dnl Whether to disable bundled talloc AC_DEFUN([AC_NETATALK_TALLOC], [ AC_ARG_WITH( diff --git a/macros/summary.m4 b/macros/summary.m4 index eed011dfa7..65c007e619 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -148,13 +148,6 @@ AC_DEFUN([AC_NETATALK_LIBS_SUMMARY], [ AC_MSG_RESULT([ LIBEVENT:]) AC_MSG_RESULT([ LIBS = $LIBEVENT_LIBS]) AC_MSG_RESULT([ CFLAGS = $LIBEVENT_CFLAGS]) - AC_MSG_RESULT([ TDB:]) - if test x"$use_bundled_tdb" = x"yes"; then - AC_MSG_RESULT([ bundled]) - else - AC_MSG_RESULT([ LIBS = $TDB_LIBS]) - AC_MSG_RESULT([ CFLAGS = $TDB_CFLAGS]) - fi AC_MSG_RESULT([ TALLOC:]) if test x"$use_bundled_talloc" = x"yes"; then AC_MSG_RESULT([ bundled])