cnid_metad_SOURCES = cnid_metad.c usockfd.c db_param.c
cnid_metad_LDADD = $(top_builddir)/libatalk/libatalk.la
-dbd_SOURCES = dbd.c dbif.c pack.c
+dbd_SOURCES = dbd.c dbif.c pack.c cmd_dbd_scanvol.c
dbd_CFLAGS = $(AM_CFLAGS)
dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@
-noinst_HEADERS = dbif.h pack.h db_param.h dbd.h usockfd.h comm.h
+noinst_HEADERS = dbif.h pack.h db_param.h dbd.h usockfd.h comm.h cmd_dbd.h
EXTRA_DIST = README
--- /dev/null
+#ifndef CMD_DBD_H
+#define CMD_DBD_H
+
+#include <atalk/volinfo.h>
+#include "dbif.h"
+
+enum logtype {LOGSTD, LOGDEBUG};
+typedef unsigned int dbd_flags_t;
+
+#define DBD_FLAGS_SCAN (1 << 0)
+#define DBD_FLAGS_FORCE (1 << 0)
+
+#define ADv2_DIRNAME ".AppleDouble"
+
+#define DIR_DOT_OR_DOTDOT(a) \
+ ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
+
+#define STRCMP(a,b,c) \
+ (strcmp(a,c) b 0)
+
+extern void dbd_log(enum logtype lt, char *fmt, ...);
+extern int cmd_dbd_scanvol(DBD *dbd, struct volinfo *volinfo, dbd_flags_t flags);
+
+#endif /* CMD_DBD_H */
--- /dev/null
+/*
+ $Id: cmd_dbd_scanvol.c,v 1.1 2009-05-06 11:54:24 franklahm Exp $
+
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+/*
+ dbd specs and implementation progress
+ =====================================
+
+ St Type Check (Status of implementation progress, type: file/dir)
+ -- ---- -----
+ OK D Make sure .AppleDouble dir exist, create if missing. Error creating
+ it is fatal as that shouldn't happen as root
+ OK F Make sure ad file exists
+ OK F/D Delete orphaned ad-files, log dirs in ad-dir
+ OK F/D Check name encoding by roundtripping, log on error
+ .. F/D try: read CNID from ad file (if cnid caching is on)
+ try: fetch CNID from database
+ on mismatch: keep CNID from file, update database
+ on no CNID id ad file: write CNID from database to ad file
+ on no CNID in database: add CNID from ad file to database
+ on no CNID at all: create one and store in both places
+*/
+
+/* FIXME: set id */
+#if 0
+ ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include <atalk/adouble.h>
+#include <atalk/unicode.h>
+#include <atalk/volinfo.h>
+#include "cmd_dbd.h"
+#include "dbif.h"
+#include "db_param.h"
+
+static DBD *dbd_rebuild;
+static struct volinfo *volinfo;
+static dbd_flags_t dbd_flags;
+static char cwdbuf[MAXPATHLEN+1];
+static char *netatalk_dirs[] = {
+ ".AppleDB",
+ ".AppleDesktop",
+ NULL
+};
+
+/*
+ Taken form afpd/desktop.c
+*/
+static char *utompath(char *upath)
+{
+ static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
+ char *m, *u;
+ uint16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+ size_t outlen;
+
+ if (!upath)
+ return NULL;
+
+ m = mpath;
+ u = upath;
+ outlen = strlen(upath);
+
+ if ((volinfo->v_casefold & AFPVOL_UTOMUPPER))
+ flags |= CONV_TOUPPER;
+ else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER))
+ flags |= CONV_TOLOWER;
+
+ if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
+ flags |= CONV__EILSEQ;
+ }
+
+ /* convert charsets */
+ if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset,
+ CH_UTF8_MAC,
+ volinfo->v_maccharset,
+ u, outlen, mpath, MAXPATHLEN, &flags)) ) {
+ dbd_log( LOGSTD, "Conversion from %s to %s for %s failed.",
+ volinfo->v_volcodepage, volinfo->v_maccodepage, u);
+ return NULL;
+ }
+
+ return(m);
+}
+
+/*
+ Taken form afpd/desktop.c
+*/
+static char *mtoupath(char *mpath)
+{
+ static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
+ char *m, *u;
+ size_t inplen;
+ size_t outlen;
+ u_int16_t flags = 0;
+
+ if (!mpath)
+ return NULL;
+
+ if ( *mpath == '\0' ) {
+ return( "." );
+ }
+
+ /* set conversion flags */
+ if (!(volinfo->v_flags & AFPVOL_NOHEX))
+ flags |= CONV_ESCAPEHEX;
+ if (!(volinfo->v_flags & AFPVOL_USEDOTS))
+ flags |= CONV_ESCAPEDOTS;
+
+ if ((volinfo->v_casefold & AFPVOL_MTOUUPPER))
+ flags |= CONV_TOUPPER;
+ else if ((volinfo->v_casefold & AFPVOL_MTOULOWER))
+ flags |= CONV_TOLOWER;
+
+ if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
+ flags |= CONV__EILSEQ;
+ }
+
+ m = mpath;
+ u = upath;
+
+ inplen = strlen(m);
+ outlen = MAXPATHLEN;
+
+ if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
+ volinfo->v_volcharset,
+ volinfo->v_maccharset,
+ m, inplen, u, outlen, &flags)) ) {
+ dbd_log( LOGSTD, "conversion from UTF8-MAC to %s for %s failed.",
+ volinfo->v_volcodepage, mpath);
+ return NULL;
+ }
+
+ return( upath );
+}
+
+/*
+ Check for wrong encoding e.g. "." at the beginning is not CAP encoded (:2e) although volume is default !AFPVOL_USEDOTS.
+ We do it by roundtripiping from volcharset to UTF8-MAC and back and then compare the result.
+*/
+static int check_name_encoding(char *uname)
+{
+ char *roundtripped;
+
+ roundtripped = mtoupath(utompath(uname));
+ if (!roundtripped) {
+ dbd_log( LOGSTD, "Error checking encoding for %s/%s", cwdbuf, uname);
+ return -1;
+ }
+
+ if ( STRCMP(uname, !=, roundtripped)) {
+ dbd_log( LOGSTD, "Bad encoding for %s/%s", cwdbuf, uname);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+ Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+ int c;
+
+ for (c=0; netatalk_dirs[c]; c++) {
+ if ((strcmp(name, netatalk_dirs[c])) == 0)
+ return netatalk_dirs[c];
+ }
+ return NULL;
+}
+
+/*
+ Check for .AppleDouble file, create if missing
+*/
+static int check_adfile(const char *fname, const struct stat *st)
+{
+ int ret;
+ struct adouble ad;
+ char *adname;
+
+ adname = volinfo->ad_path(fname, 0);
+
+ if ((ret = access( adname, F_OK)) != 0) {
+ if (errno != ENOENT) {
+ dbd_log(LOGSTD, "Access error for ad-file '%s/%s': %s",
+ cwdbuf, adname, strerror(errno));
+ return -1;
+ }
+ /* Missing. Log and create it */
+ dbd_log(LOGSTD, "Missing AppleDoube file '%s/%s'", cwdbuf, adname);
+
+ if (dbd_flags & DBD_FLAGS_SCAN)
+ /* Scan only requested, dont change anything */
+ return 0;
+
+ /* Create ad file */
+ ad_init(&ad, volinfo->v_adouble, volinfo->v_flags);
+
+ if ((ret = ad_open_metadata( fname, 0, O_CREAT, &ad)) != 0) {
+ dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s",
+ cwdbuf, adname, strerror(errno));
+ return -1;
+ }
+
+ /* Set name in ad-file */
+ ad_setname(&ad, utompath((char *)fname));
+ ad_flush(&ad);
+ ad_close_metadata(&ad);
+
+ chown(adname, st->st_uid, st->st_gid);
+ /* FIXME: should we inherit mode too here ? */
+#if 0
+ chmod(adname, st->st_mode);
+#endif
+ }
+ return 0;
+}
+
+/*
+ Check for .AppleDouble folder, create if missing
+*/
+static int check_addir(int volroot)
+{
+ int ret;
+ struct stat st;
+ struct adouble ad;
+
+ if ((ret = access(ADv2_DIRNAME, F_OK)) != 0) {
+ if (errno != ENOENT) {
+ dbd_log(LOGSTD, "Access error in directory %s: %s", cwdbuf, strerror(errno));
+ return -1;
+ }
+ /* Missing. Log and create it */
+ dbd_log(LOGSTD, "Missing %s directory %s", ADv2_DIRNAME, cwdbuf);
+
+ if (dbd_flags & DBD_FLAGS_SCAN)
+ /* Scan only requested, dont change anything */
+ return 0;
+
+ /* Create ad dir and set name and id */
+ ad_init(&ad, volinfo->v_adouble, volinfo->v_flags);
+
+ if ((ret = ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad)) != 0) {
+ dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno));
+ return -1;
+ }
+
+ /* Get basename of cwd from cwdbuf */
+ char *mname = utompath(strrchr(cwdbuf, '/') + 1);
+
+ /* Update name in ad file */
+ ad_setname(&ad, mname);
+ ad_flush(&ad);
+ ad_close_metadata(&ad);
+
+ /* Inherit owner/group from "." to ".AppleDouble" and ".Parent" */
+ if ((stat(".", &st)) != 0) {
+ dbd_log( LOGSTD, "Couldnt stat %s: %s", cwdbuf, strerror(errno));
+ return -1;
+ }
+ chown(ADv2_DIRNAME, st.st_uid, st.st_gid);
+ chown(volinfo->ad_path(".", ADFLAGS_DIR), st.st_uid, st.st_gid);
+ }
+
+ return 0;
+}
+
+static int read_addir(void)
+{
+ DIR *dp;
+ struct dirent *ep;
+ struct stat st;
+ static char fname[NAME_MAX] = "../";
+
+ if ((chdir(ADv2_DIRNAME)) != 0) {
+ dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s",
+ cwdbuf, ADv2_DIRNAME, strerror(errno));
+ return -1;
+ }
+
+ if ((dp = opendir(".")) == NULL) {
+ dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s",
+ cwdbuf, ADv2_DIRNAME, strerror(errno));
+ return -1;
+ }
+
+ while ((ep = readdir(dp))) {
+ /* Check if its "." or ".." */
+ if (DIR_DOT_OR_DOTDOT(ep->d_name))
+ continue;
+
+ if ((stat(ep->d_name, &st)) < 0) {
+ dbd_log( LOGSTD, "Lost file while reading dir '%s/%s/%s', probably removed: %s",
+ cwdbuf, ADv2_DIRNAME, ep->d_name, strerror(errno));
+ continue;
+ }
+
+ /* Check for dirs */
+ if (S_ISDIR(st.st_mode)) {
+ dbd_log( LOGSTD, "Unexpected directory '%s' in AppleDouble dir '%s/%s'",
+ ep->d_name, cwdbuf, ADv2_DIRNAME);
+ continue;
+ }
+
+ /* Skip ".Parent" */
+ if (STRCMP(ep->d_name, ==, ".Parent"))
+ continue;
+
+ /* Check for data file */
+ strcpy(fname+3, ep->d_name);
+ if ((access( fname, F_OK)) != 0) {
+ if (errno != ENOENT) {
+ dbd_log(LOGSTD, "Access error for file '%s/%s': %s",
+ cwdbuf, ep->d_name, strerror(errno));
+ continue;
+ }
+ /* Orphaned ad-file*/
+ dbd_log(LOGSTD, "Orphaned AppleDoube file '%s/%s/%s'",
+ cwdbuf, ADv2_DIRNAME, ep->d_name);
+
+ if (dbd_flags & DBD_FLAGS_SCAN)
+ /* Scan only requested, dont change anything */
+ continue;;
+
+ if ((unlink(ep->d_name)) != 0) {
+ dbd_log(LOGSTD, "Error unlinking orphaned AppleDoube file '%s/%s/%s'",
+ cwdbuf, ADv2_DIRNAME, ep->d_name);
+
+ }
+ }
+ }
+
+ if ((chdir("..")) != 0) {
+ dbd_log(LOGSTD, "Couldn't chdir back to '%s' from AppleDouble dir: %s",
+ cwdbuf, strerror(errno));
+ /* This really is EOT! */
+ exit(1);
+ }
+
+ closedir(dp);
+
+ return 0;
+}
+
+static int dbd_readdir(int volroot, cnid_t did)
+{
+ int cwd, ret = 0, encoding_ok;
+ const char *name;
+ DIR *dp;
+ struct dirent *ep;
+ static struct stat st; /* Save some stack space */
+
+ /* Check for .AppleDouble folder */
+ if ((check_addir(volroot)) != 0)
+ return -1;
+
+ /* Check AppleDouble files in AppleDouble folder */
+ if ((ret = read_addir()) != 0)
+ return -1;
+
+ if ((dp = opendir (".")) == NULL) {
+ dbd_log(LOGSTD, "Couldn't open the directory: %s",strerror(errno));
+ return -1;
+ }
+
+ while ((ep = readdir (dp))) {
+ /* Check if its "." or ".." */
+ if (DIR_DOT_OR_DOTDOT(ep->d_name))
+ continue;
+
+ /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+ if ((name = check_netatalk_dirs(ep->d_name)) != NULL) {
+ if (! volroot)
+ dbd_log(LOGSTD, "Nested %s in %s", name, cwdbuf);
+ continue;
+ }
+
+ /* Skip .AppleDouble dir in this loop */
+ if (STRCMP(ep->d_name, == , ADv2_DIRNAME))
+ continue;
+
+ if ((ret = stat(ep->d_name, &st)) < 0) {
+ dbd_log( LOGSTD, "Lost file while reading dir '%s/%s', probably removed: %s", cwdbuf, ep->d_name, strerror(errno));
+ continue;
+ }
+
+ /**************************************************************************
+ Tests
+ **************************************************************************/
+
+ /* Check encoding */
+ if ( -1 == (encoding_ok = check_name_encoding(ep->d_name)) ) {
+ /* If its a file: skipp all other tests now ! */
+ /* For dirs we skip tests too, but later */
+ if (S_ISREG(st.st_mode))
+ continue;
+ }
+
+ /* Check for appledouble file, create if missing */
+ if (S_ISREG(st.st_mode)) {
+ if ( 0 != check_adfile(ep->d_name, &st))
+ continue;
+ }
+
+ /**************************************************************************
+ Recursion
+ **************************************************************************/
+ if (S_ISDIR(st.st_mode)) {
+ strcat(cwdbuf, "/");
+ strcat(cwdbuf, ep->d_name);
+ dbd_log( LOGDEBUG, "Entering directory: %s", cwdbuf);
+ if (-1 == (cwd = open(".", O_RDONLY))) {
+ dbd_log( LOGSTD, "Cant open directory '%s': %s", cwdbuf, strerror(errno));
+ continue;
+ }
+ if (0 != chdir(ep->d_name)) {
+ dbd_log( LOGSTD, "Cant chdir to directory '%s': %s", cwdbuf, strerror(errno));
+ close(cwd);
+ continue;
+ }
+
+ ret = dbd_readdir(0, did);
+
+ fchdir(cwd);
+ close(cwd);
+ *(strrchr(cwdbuf, '/')) = 0;
+ if (ret < 0)
+ continue;
+ }
+ }
+
+ /*
+ Use results of previous checks
+ */
+
+exit_cleanup:
+ closedir(dp);
+ return ret;
+}
+
+static int scanvol(struct volinfo *vi, dbd_flags_t flags)
+{
+ /* Dont scanvol on no-appledouble vols */
+ if (vi->v_flags & AFPVOL_NOADOUBLE) {
+ dbd_log( LOGSTD, "Volume without AppleDouble support: skipping volume scanning.");
+ return 0;
+ }
+
+ /* Make this stuff accessible from all funcs easily */
+ volinfo = vi;
+ dbd_flags = flags;
+
+ /* Run with umask 0 */
+ umask(0);
+
+ /* chdir to vol */
+ strcpy(cwdbuf, volinfo->v_path);
+ if (cwdbuf[strlen(cwdbuf) - 1] == '/')
+ cwdbuf[strlen(cwdbuf) - 1] = 0;
+ chdir(volinfo->v_path);
+
+ /* Start recursion */
+ if (dbd_readdir(1, 2) < 0) /* 2 = volumeroot CNID */
+ return -1;
+
+ return 0;
+}
+
+int cmd_dbd_scanvol(DBD *dbd, struct volinfo *volinfo, dbd_flags_t flags)
+{
+ int ret = 0;
+
+ /* We only support unicode volumes ! */
+ if ( volinfo->v_volcharset != CH_UTF8) {
+ dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", volinfo->v_volcodepage, volinfo->v_volcharset, CH_UTF8);
+ return -1;
+ }
+
+ /* open/create dbd, copy rootinfo key */
+ if (NULL == (dbd_rebuild = dbif_init(NULL)))
+ return -1;
+ if (0 != (dbif_open(dbd_rebuild, NULL, 0)))
+ return -1;
+ if (0 != (ret = dbif_copy_rootinfokey(dbd, dbd_rebuild)))
+ goto exit_cleanup;
+
+ dbd_log( LOGSTD, "dumping rebuilddb");
+ dbif_dump(dbd_rebuild, 0);
+
+ /* scanvol */
+ if ( (scanvol(volinfo, flags)) != 0)
+ return -1;
+
+exit_cleanup:
+ dbif_close(dbd_rebuild);
+ return ret;
+}
/*
- * $Id: db_param.c,v 1.4 2009-04-21 08:55:44 franklahm Exp $
+ * $Id: db_param.c,v 1.5 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* Copyright (c) Frank Lahm 2009
}
/* Config for dbd only */
- else if (id == DBD ) {
+ else if (id == CNID_DBD ) {
if (! strcmp(key, "fd_table_size")) {
params.fd_table_size = parse_int(val);
LOG(log_info, logtype_cnid, "db_param: setting max number of concurrent afpd connections per volume (fd_table_size) to %d", params.fd_table_size);
/*
- * $Id: db_param.h,v 1.3 2009-04-21 08:55:44 franklahm Exp $
+ * $Id: db_param.h,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
enum identity {
METAD,
- DBD
+ CNID_DBD
};
struct db_param {
/*
- $Id: dbd.c,v 1.2 2009-04-28 14:09:00 franklahm Exp $
+ $Id: dbd.c,v 1.3 2009-05-06 11:54:24 franklahm Exp $
Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
#include <atalk/logger.h>
#include <atalk/cnid_dbd_private.h>
#include <atalk/volinfo.h>
+#include "cmd_dbd.h"
#include "dbif.h"
#include "db_param.h"
#define LOCKFILENAME "lock"
-#define DBOPTIONS (DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN)
+#define DBOPTIONS (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN)
-enum logtype {LOGSTD, LOGDEBUG};
+static DBD *dbd;
static volatile sig_atomic_t alarmed;
-static int verbose; /* Logging flag */
-static int exclusive; /* How to open the bdb database */
-static struct volinfo volinfo;
+static int verbose; /* Logging flag */
+static int exclusive; /* Exclusive volume access */
static struct db_param db_param = {
NULL, /* Volume dirpath */
1, /* bdb logfile autoremove */
/*
Provide some logging
*/
-static void dblog(enum logtype lt, char *fmt, ...)
+void dbd_log(enum logtype lt, char *fmt, ...)
{
int len;
static char logbuffer[1024];
sigemptyset(&sv.sa_mask);
sigaddset(&sv.sa_mask, SIGTERM);
if (sigaction(SIGTERM, &sv, NULL) < 0) {
- dblog( LOGSTD, "error in sigaction(SIGTERM): %s", strerror(errno));
+ dbd_log( LOGSTD, "error in sigaction(SIGTERM): %s", strerror(errno));
exit(EXIT_FAILURE);
}
sigemptyset(&sv.sa_mask);
if (sigaction(SIGINT, &sv, NULL) < 0) {
- dblog( LOGSTD, "error in sigaction(SIGINT): %s", strerror(errno));
+ dbd_log( LOGSTD, "error in sigaction(SIGINT): %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (sigaction(SIGABRT, &sv, NULL) < 0) {
- dblog( LOGSTD, "error in sigaction(SIGABRT): %s", strerror(errno));
+ dbd_log( LOGSTD, "error in sigaction(SIGABRT): %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (sigaction(SIGHUP, &sv, NULL) < 0) {
- dblog( LOGSTD, "error in sigaction(SIGHUP): %s", strerror(errno));
+ dbd_log( LOGSTD, "error in sigaction(SIGHUP): %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (sigaction(SIGQUIT, &sv, NULL) < 0) {
- dblog( LOGSTD, "error in sigaction(SIGQUIT): %s", strerror(errno));
+ dbd_log( LOGSTD, "error in sigaction(SIGQUIT): %s", strerror(errno));
exit(EXIT_FAILURE);
}
}
struct flock lock;
if ((lockfd = open(LOCKFILENAME, O_RDWR | O_CREAT, 0644)) < 0) {
- dblog( LOGSTD, "Error opening lockfile: %s", strerror(errno));
+ dbd_log( LOGSTD, "Error opening lockfile: %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (fcntl(lockfd, F_SETLK, &lock) < 0) {
if (errno == EACCES || errno == EAGAIN) {
if (exclusive) {
- dblog( LOGDEBUG, "Database is in use and exlusive was requested", strerror(errno));
+ dbd_log( LOGSTD, "Database is in use and exlusive was requested", strerror(errno));
exit(EXIT_FAILURE);
};
} else {
- dblog( LOGSTD, "Error getting fcntl F_WRLCK on lockfile: %s", strerror(errno));
+ dbd_log( LOGSTD, "Error getting fcntl F_WRLCK on lockfile: %s", strerror(errno));
exit(EXIT_FAILURE);
}
}
{
printf("Usage: dbd [-e|-v|-x] -d [-i] | -s | -r [-f] <path to netatalk volume>\n"
"dbd can dump, scan, reindex and rebuild Netatalk dbd CNID databases.\n"
- "dbd must run with appropiate permissions i.e. as root.\n\n"
+ "dbd must be run with appropiate permissions i.e. as root.\n\n"
"Main commands are:\n"
- " -d dump\n"
- " Dump CNID database\n"
+ " -d Dump CNID database\n"
" Option: -i dump indexes too\n"
- " -s scan\n"
- " Compare database with volume\n"
- " -r rebuild\n"
- " Rebuild CNID database\n"
- " Option: -f wipe database and rebuild from IDs stored in AppleDouble files\n\n"
+ " -s Scan volume:\n"
+ " 1. Compare database with volume\n"
+ " 2. Check if .AppleDouble dirs exist\n"
+ " 3. Check if AppleDouble file exist\n"
+ " 4. Report orphaned AppleDouble files\n"
+ " 5. Check for directories inside AppleDouble directories\n"
+ " 6. Check name encoding by roundtripping, log on error\n"
+ " -r Rebuild volume:\n"
+ " 1. Sync database with volume\n"
+ " 2. Make sure .AppleDouble dir exist, create if missing\n"
+ " 3. Make sure AppleDouble file exists, create if missing\n"
+ " 4. Delete orphaned AppleDouble files\n"
+ " 5. Check for directories inside AppleDouble directories\n"
+ " 6. Check name encoding by roundtripping, log on error\n"
+ " Option: -f wipe database and rebuild from IDs stored in AppleDouble files,\n"
+ " only available for volumes with 'cachecnid' option\n\n"
"General options:\n"
" -e only work on inactive volumes and lock them (exclusive)\n"
" -x rebuild indexes\n"
" -v verbose\n"
"\n"
- "28-04-2009: -s and -r and not yet implemented\n"
+ "05-05-2009: -s and -r already check/repair the AppleDouble stuff and encoding,\n"
+ " no CNID database maintanance is done yet\n"
);
}
int main(int argc, char **argv)
{
- int c, ret, lockfd;
+ int c, lockfd;
int dump=0, scan=0, rebuild=0, rebuildindexes=0, dumpindexes=0, force=0;
+ dbd_flags_t flags = 0;
char *volpath;
+ struct volinfo volinfo;
if (geteuid() != 0) {
usage();
exit(EXIT_FAILURE);
}
- while ((c = getopt(argc, argv, ":dsrvxif")) != -1) {
+ while ((c = getopt(argc, argv, ":dsrvxife")) != -1) {
switch(c) {
case 'd':
dump = 1;
break;
case 's':
scan = 1;
+ flags = DBD_FLAGS_SCAN;
break;
case 'r':
rebuild = 1;
break;
case 'f':
force = 1;
+ flags = DBD_FLAGS_FORCE;
break;
case ':':
case '?':
/* Put "/.AppleDB" at end of volpath */
if ( (strlen(volpath) + strlen("/.AppleDB")) > (PATH_MAX -1) ) {
- dblog( LOGSTD, "Volume pathname too long");
+ dbd_log( LOGSTD, "Volume pathname too long");
exit(EXIT_FAILURE);
}
char dbpath[PATH_MAX];
strncpy(dbpath, volpath, PATH_MAX - 1);
strcat(dbpath, "/.AppleDB");
- if ( -1 == (ret = loadvolinfo(volpath, &volinfo)) ) {
- dblog( LOGSTD, "Unkown volume options!");
+ /* cd to .AppleDB dir */
+ int cdir;
+ if ((cdir = open(".", O_RDONLY)) < 0) {
+ dbd_log( LOGSTD, "Can't open dir: %s", strerror(errno));
exit(EXIT_FAILURE);
}
-
if (chdir(dbpath) < 0) {
- dblog( LOGSTD, "chdir to %s failed: %s", dbpath, strerror(errno));
+ dbd_log( LOGSTD, "chdir to %s failed: %s", dbpath, strerror(errno));
exit(EXIT_FAILURE);
}
-
+
/*
Before we do anything else, check if there is an instance of cnid_dbd
running already and silently exit if yes.
else
setuplog("default log_debug /dev/tty");
+ /* Load .volinfo file */
+ if ( -1 == loadvolinfo(volpath, &volinfo)) {
+ dbd_log( LOGSTD, "Unkown volume options!");
+ exit(EXIT_FAILURE);
+ }
+ if ( -1 == vol_load_charsets(&volinfo)) {
+ dbd_log( LOGSTD, "Error loading charsets!");
+ exit(EXIT_FAILURE);
+ }
+
/*
Lets start with the BerkeleyDB stuff
*/
- if (dbif_env_init(&db_param, DBOPTIONS) < 0) {
- dblog( LOGSTD, "error opening database!");
+ if (NULL == (dbd = dbif_init("cnid2.db")))
+ exit(2);
+
+ if (dbif_env_open(dbd, &db_param, DBOPTIONS) < 0) {
+ dbd_log( LOGSTD, "error opening database!");
exit(EXIT_FAILURE);
}
- dblog( LOGDEBUG, "Finished opening BerkeleyDB databases including recovery.");
+ dbd_log( LOGDEBUG, "Finished opening BerkeleyDB databases including recovery.");
- if (dbif_open(&db_param, rebuildindexes) < 0) {
- dbif_close();
+ if (dbif_open(dbd, &db_param, rebuildindexes) < 0) {
+ dbif_close(dbd);
exit(EXIT_FAILURE);
}
+ if ((fchdir(cdir)) < 0) {
+ dbd_log(LOGSTD, "fchdir: %s", strerror(errno));
+ goto cleanup;
+ }
+
if (dump) {
- if (dbif_dump(dumpindexes) < 0) {
- dblog( LOGSTD, "Error dumping database");
+ if (dbif_dump(dbd, dumpindexes) < 0) {
+ dbd_log( LOGSTD, "Error dumping database");
+ }
+ } else if (rebuild || scan) {
+ if (cmd_dbd_scanvol(dbd, &volinfo, flags) < 0) {
+ dbd_log( LOGSTD, "Fatal error repairing database. Please rm -r it.");
}
}
- if (dbif_close() < 0)
+cleanup:
+ if (dbif_close(dbd) < 0)
exit(EXIT_FAILURE);
free_lock(lockfd);
/*
- * $Id: dbd.h,v 1.3 2009-04-21 08:55:44 franklahm Exp $
+ * $Id: dbd.h,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
+ * Copyright (C) Frank Lahm 2009
* All Rights Reserved. See COPYING.
*/
#include <atalk/cnid_dbd_private.h>
-extern int dbd_stamp __P((void));
-extern int dbd_add __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_get __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_resolve __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_lookup __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_update __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_delete __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_getstamp __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_rebuild_add __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_check_indexes __P((char *));
+extern int dbd_stamp(DBD *dbd);
+extern int dbd_add(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_get(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_resolve(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_lookup(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_update(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_delete(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_getstamp(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_rebuild_add(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
+extern int dbd_check_indexes(DBD *dbd, char *);
#endif /* CNID_DBD_DBD_H */
/*
- * $Id: dbd_add.c,v 1.4 2009-05-04 09:09:43 franklahm Exp $
+ * $Id: dbd_add.c,v 1.5 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include "pack.h"
#include "dbd.h"
-static int add_cnid(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+static int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
DBT key, data;
int rc;
memcpy(data.data, &rply->cnid, sizeof(rply->cnid));
/* main database */
- if ((rc = dbif_put(DBIF_IDX_CNID, &key, &data, DB_NOOVERWRITE))) {
+ if ((rc = dbif_put(dbd, DBIF_CNID, &key, &data, DB_NOOVERWRITE))) {
/* This could indicate a database error or that the key already exists
(because of DB_NOOVERWRITE). In that case we still look at some sort of
database corruption since that is not supposed to happen. */
, (char *)data.data + CNID_NAME_OFS);
rqst->cnid = rply->cnid;
- rc = dbd_update(rqst, rply);
+ rc = dbd_update(dbd, rqst, rply);
if (rc < 0) {
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
}
/* ---------------------- */
-static int get_cnid(struct cnid_dbd_rply *rply)
+static int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
{
DBT rootinfo_key, rootinfo_data;
int rc;
rootinfo_key.data = ROOTINFO_KEY;
rootinfo_key.size = ROOTINFO_KEYLEN;
- if ((rc = dbif_get(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0)) <= 0) {
+ if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) <= 0) {
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
}
hint = htonl(id);
memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
- if (dbif_put(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
+ if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
}
/* ---------------
*/
-int dbd_stamp(void)
+int dbd_stamp(DBD *dbd)
{
DBT rootinfo_key, rootinfo_data;
cnid_t hint;
rootinfo_key.data = ROOTINFO_KEY;
rootinfo_key.size = ROOTINFO_KEYLEN;
- switch (dbif_get(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0)) {
+ switch (dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) {
case 0:
hint = htonl(CNID_START);
memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
rootinfo_data.data = buf;
rootinfo_data.size = ROOTINFO_DATALEN;
- if (dbif_stamp(stamp, CNID_DEV_LEN) < 0) {
+ if (dbif_stamp(dbd, stamp, CNID_DEV_LEN) < 0) {
return -1;
}
- memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
- memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
- if (dbif_put(DBIF_IDX_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
+ memcpy((char *)rootinfo_data.data + CNID_TYPE_OFS, &hint, sizeof(hint));
+ memcpy((char *)rootinfo_data.data + CNID_DEV_OFS, stamp, sizeof(stamp));
+ if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
return -1;
}
return 0;
}
/* ------------------------ */
-int dbd_add(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
rply->namelen = 0;
/* See if we have an entry already and return it if yes */
- if (dbd_lookup(rqst, rply) < 0)
+ if (dbd_lookup(dbd, rqst, rply) < 0)
return -1;
if (rply->result == CNID_DBD_RES_OK) {
return 1;
}
- if (get_cnid(rply) < 0) {
+ if (get_cnid(dbd, rply) < 0) {
if (rply->result == CNID_DBD_RES_ERR_MAX) {
LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
/* This will cause an abort/rollback if transactions are used */
}
}
- if (add_cnid(rqst, rply) < 0) {
+ if (add_cnid(dbd, rqst, rply) < 0) {
if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
LOG(log_error, logtype_cnid, "dbd_add: Cannot add CNID %u. Corrupt/invalid Rootkey?.", ntohl(rply->cnid));
/* abort/rollback, see above */
/*
- * $Id: dbd_dbcheck.c,v 1.3 2009-04-21 08:55:44 franklahm Exp $
+ * $Id: dbd_dbcheck.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include "dbif.h"
#include "dbd.h"
-int dbd_check_indexes(char *dbdir)
+int dbd_check_indexes(DBD *dbd, char *dbdir)
{
u_int32_t c_didname = 0, c_devino = 0, c_cnid = 0;
LOG(log_note, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
- if (dbif_count(DBIF_IDX_CNID, &c_cnid))
+ if (dbif_count(dbd, DBIF_CNID, &c_cnid))
return -1;
- if (dbif_count(DBIF_IDX_DEVINO, &c_devino))
+ if (dbif_count(dbd, DBIF_IDX_DEVINO, &c_devino))
return -1;
/* bailout after the first error */
return 1;
}
- if (dbif_count(DBIF_IDX_DIDNAME, &c_didname))
+ if (dbif_count(dbd, DBIF_IDX_DIDNAME, &c_didname))
return -1;
if ( c_cnid != c_didname) {
/*
- * $Id: dbd_delete.c,v 1.3 2009-05-04 09:09:43 franklahm Exp $
+ * $Id: dbd_delete.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include "dbd.h"
#include "pack.h"
-int dbd_delete(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_delete(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
DBT key;
int rc;
key.data = (void *) &rqst->cnid;
key.size = sizeof(rqst->cnid);
- if ((rc = dbif_del(DBIF_IDX_CNID, &key, 0)) < 0) {
+ if ((rc = dbif_del(dbd, DBIF_CNID, &key, 0)) < 0) {
LOG(log_error, logtype_cnid, "dbd_delete: Unable to delete entry for CNID %u", ntohl(rqst->cnid));
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
/*
- * $Id: dbd_get.c,v 1.3 2009-05-04 09:09:43 franklahm Exp $
+ * $Id: dbd_get.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
/* Return CNID for a given did/name. */
-int dbd_get(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_get(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
DBT key, data;
key.data = start;
key.size = CNID_DID_LEN + rqst->namelen + 1;
- if ((rc = dbif_get(DBIF_IDX_DIDNAME, &key, &data, 0)) < 0) {
+ if ((rc = dbif_get(dbd, DBIF_IDX_DIDNAME, &key, &data, 0)) < 0) {
LOG(log_error, logtype_cnid, "dbd_get: Unable to get CNID %u, name %s", ntohl(rqst->did), rqst->name);
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
/*
- * $Id: dbd_getstamp.c,v 1.3 2009-04-21 08:55:44 franklahm Exp $
+ * $Id: dbd_getstamp.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
/* Return the unique stamp associated with this database */
-int dbd_getstamp(struct cnid_dbd_rqst *rqst _U_, struct cnid_dbd_rply *rply)
+int dbd_getstamp(DBD *dbd, struct cnid_dbd_rqst *rqst _U_, struct cnid_dbd_rply *rply)
{
DBT key, data;
int rc;
key.data = ROOTINFO_KEY;
key.size = ROOTINFO_KEYLEN;
- if ((rc = dbif_get(DBIF_IDX_CNID, &key, &data, 0)) < 0) {
+ if ((rc = dbif_get(dbd, DBIF_CNID, &key, &data, 0)) < 0) {
LOG(log_error, logtype_cnid, "dbd_getstamp: Error getting rootinfo record");
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
/*
- * $Id: dbd_lookup.c,v 1.5 2009-05-04 09:09:43 franklahm Exp $
+ * $Id: dbd_lookup.c,v 1.6 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
* up the database if there's a problem.
*/
-int dbd_lookup(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_lookup(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
unsigned char *buf;
DBT key, devdata, diddata;
key.data = buf + CNID_DEVINO_OFS;
key.size = CNID_DEVINO_LEN;
- if ((rc = dbif_get(DBIF_IDX_DEVINO, &key, &devdata, 0)) < 0) {
+ if ((rc = dbif_get(dbd, DBIF_IDX_DEVINO, &key, &devdata, 0)) < 0) {
LOG(log_error, logtype_cnid, "dbd_lookup: Unable to get CNID %u, name %s",
ntohl(rqst->did), rqst->name);
rply->result = CNID_DBD_RES_ERR_DB;
key.data = buf + CNID_DID_OFS;
key.size = CNID_DID_LEN + rqst->namelen + 1;
- if ((rc = dbif_get(DBIF_IDX_DIDNAME, &key, &diddata, 0)) < 0) {
+ if ((rc = dbif_get(dbd, DBIF_IDX_DIDNAME, &key, &diddata, 0)) < 0) {
LOG(log_error, logtype_cnid, "dbd_lookup: Unable to get CNID %u, name %s",
ntohl(rqst->did), rqst->name);
rply->result = CNID_DBD_RES_ERR_DB;
*/
if (!memcmp(dev, (char *)diddata.data + CNID_DEV_OFS, CNID_DEV_LEN) ||
type_didname != rqst->type) {
- if (dbd_delete(rqst, rply) < 0) {
+ if (dbd_delete(dbd, rqst, rply) < 0) {
return -1;
}
}
/* 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 (dbd_delete(rqst, rply) < 0) {
+ if (dbd_delete(dbd, rqst, rply) < 0) {
return -1;
}
}
return 1;
}
/* Fix up the database. assume it was a file move and rename */
- rc = dbd_update(rqst, rply);
+ rc = dbd_update(dbd, rqst, rply);
if (rc >0) {
rply->cnid = rqst->cnid;
}
/*
- * $Id: dbd_rebuild_add.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ * $Id: dbd_rebuild_add.c,v 1.3 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2005
* All Rights Reserved. See COPYING.
/* rebuild_add: Enter all fields (including the CNID) into the database and
update the current cnid, for emergency repairs. */
-int dbd_rebuild_add(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_rebuild_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
DBT key, data;
cnid_t cur, tmp, id;
/* FIXME: In cnid_cdb.c Bjoern does a lookup here and returns the CNID found if sucessful. Why? */
- if (dbif_put(DBIF_IDX_CNID, &key, &data, 0) < 0) {
+ if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0) {
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
}
key.data = ROOTINFO_KEY;
key.size = ROOTINFO_KEYLEN;
- if (dbif_get(DBIF_IDX_CNID, &key, &data, 0) <= 0) {
+ if (dbif_get(dbd, DBIF_CNID, &key, &data, 0) <= 0) {
/* FIXME: If we cannot find ROOTINFO_KEY, should this be considered
fatal or should we just return 0 and roll back? */
rply->result = CNID_DBD_RES_ERR_DB;
if (id > cur) {
data.size = ROOTINFO_DATALEN;
memcpy((char *) data.data + CNID_TYPE_OFS, &rqst->cnid, sizeof(cnid_t));
- if (dbif_put(DBIF_IDX_CNID, &key, &data, 0) < 0) {
+ if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0) {
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
}
/*
- * $Id: dbd_resolve.c,v 1.3 2009-05-04 09:09:43 franklahm Exp $
+ * $Id: dbd_resolve.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
/* Return the did/name pair corresponding to a CNID. */
-int dbd_resolve(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_resolve(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
DBT key, data;
int rc;
key.data = (void *) &rqst->cnid;
key.size = sizeof(cnid_t);
- if ((rc = dbif_get(DBIF_IDX_CNID, &key, &data, 0)) < 0) {
+ if ((rc = dbif_get(dbd, DBIF_CNID, &key, &data, 0)) < 0) {
LOG(log_error, logtype_cnid, "dbd_resolve: DB Error resolving CNID %u", ntohl(rqst->cnid));
rply->result = CNID_DBD_RES_ERR_DB;
return -1;
/*
- * $Id: dbd_update.c,v 1.4 2009-05-04 09:09:43 franklahm Exp $
+ * $Id: dbd_update.c,v 1.5 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
other secondary index.
*/
-int dbd_update(struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+int dbd_update(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
DBT key,pkey, data;
int rc;
data.data = getbuf;
data.size = CNID_HEADER_LEN + MAXPATHLEN + 1;
- if ((rc = dbif_pget(DBIF_IDX_DEVINO, &key, &pkey, &data, 0)) < 0 ) {
+ if ((rc = dbif_pget(dbd, DBIF_IDX_DEVINO, &key, &pkey, &data, 0)) < 0 ) {
goto err_db;
}
else if (rc > 0) {
LOG(log_debug, logtype_cnid, "dbd_update: Deleting %u corresponding to dev/ino 0x%llx/0x%llx from cnid2.db",
ntohl(tmpcnid), ntoh64((unsigned long long int)rqst->dev), ntoh64((unsigned long long int)rqst->ino));
- if ((rc = dbif_del(DBIF_IDX_CNID, &pkey, 0)) < 0 ) {
+ if ((rc = dbif_del(dbd, DBIF_CNID, &pkey, 0)) < 0 ) {
goto err_db;
}
else if (!rc) {
key.size = CNID_DID_LEN + rqst->namelen +1;
memset(&pkey, 0, sizeof(pkey));
- if ((rc = dbif_pget(DBIF_IDX_DIDNAME, &key, &pkey, &data, 0)) < 0) {
+ if ((rc = dbif_pget(dbd, DBIF_IDX_DIDNAME, &key, &pkey, &data, 0)) < 0) {
goto err_db;
}
else if (rc > 0) {
- memcpy(&tmpcnid, pkey.data, sizeof(cnid_t));
-
- LOG(log_debug, logtype_cnid, "dbd_update: Deleting %u corresponding to did %u name %s from cnid2.db",
- ntohl(tmpcnid), ntohl(rqst->did), rqst->name);
-
- if ((rc = dbif_del(DBIF_IDX_CNID, &pkey, 0)) < 0) {
+ memcpy(&tmpcnid, pkey.data, sizeof(cnid_t));
+
+ LOG(log_debug, logtype_cnid, "dbd_update: Deleting %u corresponding to did %u name %s from cnid2.db",
+ ntohl(tmpcnid), ntohl(rqst->did), rqst->name);
+
+ if ((rc = dbif_del(dbd, DBIF_CNID, &pkey, 0)) < 0) {
goto err_db;
}
else if (!rc) {
memcpy(data.data, &rqst->cnid, sizeof(rqst->cnid));
data.size = CNID_HEADER_LEN + rqst->namelen + 1;
- if (dbif_put(DBIF_IDX_CNID, &key, &data, 0) < 0)
+ if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0)
goto err_db;
LOG(log_info, logtype_cnid, "dbd_update: Updated cnid2.db with dev/ino 0x%llx/0x%llx did %u name %s cnid %u",
/*
- * $Id: dbif.c,v 1.7 2009-04-28 13:01:24 franklahm Exp $
+ * $Id: dbif.c,v 1.8 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* Copyright (C) Frank Lahm 2009
#define DB_ERRLOGFILE "db_errlog"
-static DB_ENV *db_env = NULL;
-static DB_TXN *db_txn = NULL;
-static FILE *db_errlog = NULL;
-
-static struct db_table {
- char *name;
- DB *db;
- u_int32_t general_flags;
- DBTYPE type;
-} db_table[] =
-{
- { "cnid2.db", NULL, 0, DB_BTREE},
- { "devino.db", NULL, 0, DB_BTREE},
- { "didname.db", NULL, 0, DB_BTREE},
-};
-
static char *old_dbfiles[] = {"cnid.db", NULL};
-/* --------------- */
-static int db_compat_associate (DB *p, DB *s,
- int (*callback)(DB *, const DBT *,const DBT *, DBT *),
- u_int32_t flags)
-{
- return p->associate(p, NULL, s, callback, flags);
-}
-
-/* --------------- */
-static int db_compat_open(DB *db, char *file, char *name, DBTYPE type, int mode)
-{
- int ret;
-
- ret = db->open(db, NULL, file, name, type, DB_CREATE, mode);
-
- if (ret) {
- LOG(log_error, logtype_cnid, "error opening database %s: %s", name, db_strerror(ret));
- return -1;
- } else {
- return 0;
- }
-}
-
/* --------------- */
static int upgrade_required()
{
}
/* --------------- */
-int dbif_stamp(void *buffer, int size)
+int dbif_stamp(DBD *dbd, void *buffer, int size)
{
struct stat st;
int rc;
if (size < 8)
return -1;
- if ((rc = stat(db_table[0].name, &st)) < 0) {
- LOG(log_error, logtype_cnid, "error stating database %s: %s", db_table[0].name, db_strerror(rc));
+ if ((rc = stat(dbd->db_table[DBIF_CNID].name, &st)) < 0) {
+ LOG(log_error, logtype_cnid, "error stating database %s: %s", dbd->db_table[DBIF_CNID].name, db_strerror(rc));
return -1;
}
memset(buffer, 0, size);
return 0;
}
+/* --------------- */
+DBD *dbif_init(const char *filename)
+{
+ DBD *dbd;
+
+ if ( NULL == (dbd = calloc(sizeof(DBD), 1)) )
+ return NULL;
+
+ /* filename == NULL means in memory db */
+ if (filename) {
+ dbd->db_filename = strdup(filename);
+ if (NULL == dbd->db_filename) {
+ free(dbd);
+ return NULL;
+ }
+ }
+
+ dbd->db_table[DBIF_CNID].name = "cnid2.db";
+ dbd->db_table[DBIF_IDX_DEVINO].name = "devino.db";
+ dbd->db_table[DBIF_IDX_DIDNAME].name = "didname.db";
+
+ dbd->db_table[DBIF_CNID].type = DB_BTREE;
+ dbd->db_table[DBIF_IDX_DEVINO].type = DB_BTREE;
+ dbd->db_table[DBIF_IDX_DIDNAME].type = DB_BTREE;
+
+ if (filename == NULL) {
+ /* Without an environment we must pass DB_CREATE to db->open */
+ dbd->db_table[DBIF_CNID].openflags = DB_CREATE;
+ dbd->db_table[DBIF_IDX_DEVINO].openflags = DB_CREATE;
+ dbd->db_table[DBIF_IDX_DIDNAME].openflags = DB_CREATE;
+ }
+
+ return dbd;
+}
+
/* --------------- */
/*
* We assume our current directory is already the BDB homedir. Otherwise
* opening the databases will not work as expected.
*/
-int dbif_env_init(struct db_param *dbp, uint32_t dbenv_oflags)
+int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags)
{
int ret;
char **logfiles = NULL;
return -1;
}
- if ((db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
+ if ((dbd->db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
- if ((ret = db_env_create(&db_env, 0))) {
+ if ((ret = db_env_create(&dbd->db_env, 0))) {
LOG(log_error, logtype_cnid, "error creating DB environment: %s",
db_strerror(ret));
- db_env = NULL;
+ dbd->db_env = NULL;
return -1;
}
- if (db_errlog != NULL) {
- db_env->set_errfile(db_env, db_errlog);
- db_env->set_msgfile(db_env, db_errlog);
+ if (dbd->db_errlog != NULL) {
+ dbd->db_env->set_errfile(dbd->db_env, dbd->db_errlog);
+ dbd->db_env->set_msgfile(dbd->db_env, dbd->db_errlog);
}
- db_env->set_verbose(db_env, DB_VERB_RECOVERY, 1);
+ dbd->db_env->set_verbose(dbd->db_env, DB_VERB_RECOVERY, 1);
- /* Open the database for recovery using DB_PRIVATE option which is faster */
- if ((ret = db_env->open(db_env, ".", dbenv_oflags | DB_PRIVATE | DB_RECOVER, 0))) {
- LOG(log_error, logtype_cnid, "error opening DB environment: %s",
- db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
- return -1;
- }
+ if (dbenv_oflags & DB_RECOVER) {
+ /* Open the database for recovery using DB_PRIVATE option which is faster */
+ if ((ret = dbd->db_env->open(dbd->db_env, ".", dbenv_oflags | DB_PRIVATE, 0))) {
+ LOG(log_error, logtype_cnid, "error opening DB environment: %s",
+ db_strerror(ret));
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
+ return -1;
+ }
+ dbenv_oflags = (dbenv_oflags & ~DB_RECOVER);
- if (db_errlog != NULL)
- fflush(db_errlog);
+ if (dbd->db_errlog != NULL)
+ fflush(dbd->db_errlog);
- if ((ret = db_env->close(db_env, 0))) {
- LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s",
- db_strerror(ret));
- db_env = NULL;
- return -1;
- }
+ if ((ret = dbd->db_env->close(dbd->db_env, 0))) {
+ LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s",
+ db_strerror(ret));
+ dbd->db_env = NULL;
+ return -1;
+ }
- if ((ret = db_env_create(&db_env, 0))) {
- LOG(log_error, logtype_cnid, "error creating DB environment after recovery: %s",
- db_strerror(ret));
- db_env = NULL;
- return -1;
+ if ((ret = db_env_create(&dbd->db_env, 0))) {
+ LOG(log_error, logtype_cnid, "error creating DB environment after recovery: %s",
+ db_strerror(ret));
+ dbd->db_env = NULL;
+ return -1;
+ }
}
- if ((ret = db_env->set_cachesize(db_env, 0, 1024 * dbp->cachesize, 0))) {
+ if ((ret = dbd->db_env->set_cachesize(dbd->db_env, 0, 1024 * dbp->cachesize, 0))) {
LOG(log_error, logtype_cnid, "error setting DB environment cachesize to %i: %s",
dbp->cachesize, db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
return -1;
}
- if (db_errlog != NULL) {
- db_env->set_errfile(db_env, db_errlog);
- db_env->set_msgfile(db_env, db_errlog);
+ if (dbd->db_errlog != NULL) {
+ dbd->db_env->set_errfile(dbd->db_env, dbd->db_errlog);
+ dbd->db_env->set_msgfile(dbd->db_env, dbd->db_errlog);
}
- if ((ret = db_env->open(db_env, ".", dbenv_oflags, 0))) {
+ if ((ret = dbd->db_env->open(dbd->db_env, ".", dbenv_oflags, 0))) {
LOG(log_error, logtype_cnid, "error opening DB environment after recovery: %s",
db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
return -1;
}
- if ((ret = db_env->set_flags(db_env, DB_AUTO_COMMIT, 1))) {
+ if ((ret = dbd->db_env->set_flags(dbd->db_env, DB_AUTO_COMMIT, 1))) {
LOG(log_error, logtype_cnid, "error setting DB_AUTO_COMMIT flag: %s",
db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
return -1;
}
if (dbp->logfile_autoremove) {
- if (db_env->log_archive(db_env, &logfiles, 0)) {
+ if (dbd->db_env->log_archive(dbd->db_env, &logfiles, 0)) {
LOG(log_error, logtype_cnid, "error getting list of stale logfiles: %s",
db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
return -1;
}
if (logfiles != NULL) {
}
#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 7)
- if ((ret = db_env->log_set_config(db_env, DB_LOG_AUTO_REMOVE, 1))) {
+ if ((ret = dbd->db_env->log_set_config(dbd->db_env, DB_LOG_AUTO_REMOVE, 1))) {
LOG(log_error, logtype_cnid, "error setting DB_LOG_AUTO_REMOVE flag: %s",
db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
return -1;
}
#else
- if ((ret = db_env->set_flags(db_env, DB_LOG_AUTOREMOVE, 1))) {
+ if ((ret = dbd->db_env->set_flags(dbd->db_env, DB_LOG_AUTOREMOVE, 1))) {
LOG(log_error, logtype_cnid, "error setting DB_LOG_AUTOREMOVE flag: %s",
db_strerror(ret));
- db_env->close(db_env, 0);
- db_env = NULL;
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
return -1;
}
#endif
}
/* --------------- */
-int dbif_open(struct db_param *dbp _U_, int do_truncate)
+int dbif_open(DBD *dbd, struct db_param *dbp _U_, int do_truncate)
{
int ret;
int i;
u_int32_t count;
for (i = 0; i != DBIF_DB_CNT; i++) {
- if ((ret = db_create(&(db_table[i].db), db_env, 0))) {
+ if ((ret = db_create(&dbd->db_table[i].db, dbd->db_env, 0))) {
LOG(log_error, logtype_cnid, "error creating handle for database %s: %s",
- db_table[i].name, db_strerror(ret));
+ dbd->db_table[i].name, db_strerror(ret));
return -1;
}
- if (db_table[i].general_flags) {
- if ((ret = db_table[i].db->set_flags(db_table[i].db, db_table[i].general_flags))) {
+ if (dbd->db_table[i].flags) {
+ if ((ret = dbd->db_table[i].db->set_flags(dbd->db_table[i].db,
+ dbd->db_table[i].flags))) {
LOG(log_error, logtype_cnid, "error setting flags for database %s: %s",
- db_table[i].name, db_strerror(ret));
+ dbd->db_table[i].name, db_strerror(ret));
return -1;
}
}
- if (db_compat_open(db_table[i].db, db_table[0].name, db_table[i].name, db_table[i].type, 0664) < 0)
+ if (dbd->db_table[i].db->open(dbd->db_table[i].db,
+ dbd->db_txn,
+ dbd->db_filename,
+ dbd->db_table[i].name,
+ dbd->db_table[i].type,
+ dbd->db_table[i].openflags,
+ 0664) < 0) {
+ LOG(log_error, logtype_cnid, "Cant open database");
return -1;
- if (db_errlog != NULL)
- db_table[i].db->set_errfile(db_table[i].db, db_errlog);
+ }
+ if (dbd->db_errlog != NULL)
+ dbd->db_table[i].db->set_errfile(dbd->db_table[i].db, dbd->db_errlog);
if (do_truncate && i > 0) {
LOG(log_info, logtype_cnid, "Truncating CNID index.");
- if ((ret = db_table[i].db->truncate(db_table[i].db, NULL, &count, 0))) {
+ if ((ret = dbd->db_table[i].db->truncate(dbd->db_table[i].db, NULL, &count, 0))) {
LOG(log_error, logtype_cnid, "error truncating database %s: %s",
- db_table[i].name, db_strerror(ret));
+ dbd->db_table[i].name, db_strerror(ret));
return -1;
}
}
/* TODO: Implement CNID DB versioning info on new databases. */
/* Associate the secondary with the primary. */
- LOG(log_debug, logtype_cnid, "Associating DBIF_IDX_DIDNAME index. Possibly reindexing...");
- if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DIDNAME].db, didname, (do_truncate)?DB_CREATE:0)) != 0) {
+ if (do_truncate)
+ LOG(log_info, logtype_cnid, "Reindexing did/name index...");
+ if ((ret = dbd->db_table[0].db->associate(dbd->db_table[DBIF_CNID].db,
+ dbd->db_txn,
+ dbd->db_table[DBIF_IDX_DIDNAME].db,
+ didname,
+ (do_truncate) ? DB_CREATE : 0))
+ != 0) {
LOG(log_error, logtype_cnid, "Failed to associate didname database: %s",db_strerror(ret));
return -1;
}
- LOG(log_debug, logtype_cnid, "... done.");
-
- LOG(log_debug, logtype_cnid, "Associating DBIF_IDX_DEVINO index. Possibly reindexing...");
- if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DEVINO].db, devino, (do_truncate)?DB_CREATE:0)) != 0) {
+ if (do_truncate)
+ LOG(log_info, logtype_cnid, "... done.");
+
+ if (do_truncate)
+ LOG(log_info, logtype_cnid, "Reindexing dev/ino index...");
+ if ((ret = dbd->db_table[0].db->associate(dbd->db_table[0].db,
+ dbd->db_txn,
+ dbd->db_table[DBIF_IDX_DEVINO].db,
+ devino,
+ (do_truncate) ? DB_CREATE : 0))
+ != 0) {
LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
return -1;
}
- LOG(log_debug, logtype_cnid, "... done.");
-
+ if (do_truncate)
+ LOG(log_info, logtype_cnid, "... done.");
+
return 0;
}
/* ------------------------ */
-int dbif_closedb()
+int dbif_closedb(DBD *dbd)
{
int i;
int ret;
int err = 0;
for (i = DBIF_DB_CNT -1; i >= 0; i--) {
- if (db_table[i].db != NULL && (ret = db_table[i].db->close(db_table[i].db, 0))) {
- LOG(log_error, logtype_cnid, "error closing database %s: %s", db_table[i].name, db_strerror(ret));
+ if (dbd->db_table[i].db != NULL && (ret = dbd->db_table[i].db->close(dbd->db_table[i].db, 0))) {
+ LOG(log_error, logtype_cnid, "error closing database %s: %s", dbd->db_table[i].name, db_strerror(ret));
err++;
}
}
}
/* ------------------------ */
-int dbif_close()
+int dbif_close(DBD *dbd)
{
int ret;
int err = 0;
- if (dbif_closedb())
+ if (dbif_closedb(dbd))
err++;
- if (db_env != NULL && (ret = db_env->close(db_env, 0))) {
+ if (dbd->db_env != NULL && (ret = dbd->db_env->close(dbd->db_env, 0))) {
LOG(log_error, logtype_cnid, "error closing DB environment: %s", db_strerror(ret));
err++;
}
- if (db_errlog != NULL && fclose(db_errlog) == EOF) {
+ if (dbd->db_errlog != NULL && fclose(dbd->db_errlog) == EOF) {
LOG(log_error, logtype_cnid, "error closing DB logfile: %s", strerror(errno));
err++;
}
+
+ free(dbd->db_filename);
+ free(dbd);
+ dbd = NULL;
+
if (err)
return -1;
return 0;
* functions are not expected and therefore error conditions.
*/
-int dbif_get(const int dbi, DBT *key, DBT *val, u_int32_t flags)
+int dbif_get(DBD *dbd, const int dbi, DBT *key, DBT *val, u_int32_t flags)
{
int ret;
- DB *db = db_table[dbi].db;
- ret = db->get(db, db_txn, key, val, flags);
+ ret = dbd->db_table[dbi].db->get(dbd->db_table[dbi].db,
+ dbd->db_txn,
+ key,
+ val,
+ flags);
if (ret == DB_NOTFOUND)
return 0;
if (ret) {
- LOG(log_error, logtype_cnid, "error retrieving value from %s: %s", db_table[dbi].name, db_strerror(errno));
+ LOG(log_error, logtype_cnid, "error retrieving value from %s: %s",
+ dbd->db_table[dbi].name, db_strerror(errno));
return -1;
} else
return 1;
}
/* search by secondary return primary */
-int dbif_pget(const int dbi, DBT *key, DBT *pkey, DBT *val, u_int32_t flags)
+int dbif_pget(DBD *dbd, const int dbi, DBT *key, DBT *pkey, DBT *val, u_int32_t flags)
{
int ret;
- DB *db = db_table[dbi].db;
- ret = db->pget(db, db_txn, key, pkey, val, flags);
+ ret = dbd->db_table[dbi].db->pget(dbd->db_table[dbi].db,
+ dbd->db_txn,
+ key,
+ pkey,
+ val,
+ flags);
if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD) {
return 0;
}
if (ret) {
- LOG(log_error, logtype_cnid, "error retrieving value from %s: %s", db_table[dbi].name, db_strerror(errno));
+ LOG(log_error, logtype_cnid, "error retrieving value from %s: %s",
+ dbd->db_table[dbi].name, db_strerror(errno));
return -1;
} else
return 1;
}
/* -------------------------- */
-int dbif_put(const int dbi, DBT *key, DBT *val, u_int32_t flags)
+int dbif_put(DBD *dbd, const int dbi, DBT *key, DBT *val, u_int32_t flags)
{
int ret;
- DB *db = db_table[dbi].db;
- if (dbif_txn_begin() < 0) {
- LOG(log_error, logtype_cnid, "error setting key/value in %s: %s", db_table[dbi].name, db_strerror(errno));
+ if (dbif_txn_begin(dbd) < 0) {
+ LOG(log_error, logtype_cnid, "error setting key/value in %s: %s",
+ dbd->db_table[dbi].name, db_strerror(errno));
return -1;
}
- ret = db->put(db, db_txn, key, val, flags);
-
+ ret = dbd->db_table[dbi].db->put(dbd->db_table[dbi].db,
+ dbd->db_txn,
+ key,
+ val,
+ flags);
+
if (ret) {
if ((flags & DB_NOOVERWRITE) && ret == DB_KEYEXIST) {
return 1;
} else {
- LOG(log_error, logtype_cnid, "error setting key/value in %s: %s", db_table[dbi].name, db_strerror(errno));
+ LOG(log_error, logtype_cnid, "error setting key/value in %s: %s",
+ dbd->db_table[dbi].name, db_strerror(errno));
return -1;
}
} else
return 0;
}
-int dbif_del(const int dbi, DBT *key, u_int32_t flags)
+int dbif_del(DBD *dbd, const int dbi, DBT *key, u_int32_t flags)
{
int ret;
- DB *db = db_table[dbi].db;
- if (dbif_txn_begin() < 0) {
- LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s", db_table[dbi].name, db_strerror(errno));
+ if (dbif_txn_begin(dbd) < 0) {
+ LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s",
+ dbd->db_table[dbi].name, db_strerror(errno));
return -1;
}
- ret = db->del(db, db_txn, key, flags);
-
+ ret = dbd->db_table[dbi].db->del(dbd->db_table[dbi].db,
+ dbd->db_txn,
+ key,
+ flags);
+
if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD)
return 0;
if (ret) {
- LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s", db_table[dbi].name, db_strerror(errno));
+ LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s",
+ dbd->db_table[dbi].name, db_strerror(errno));
return -1;
} else
return 1;
}
-int dbif_txn_begin()
+int dbif_txn_begin(DBD *dbd)
{
int ret;
- /* If we already have a acitve txn, just return */
- if (db_txn)
+ /* If we already have an active txn, just return */
+ if (dbd->db_txn)
+ return 0;
+
+ /* If our DBD has no env, just return (-> in memory db) */
+ if (dbd->db_env == NULL)
return 0;
- ret = db_env->txn_begin(db_env, NULL, &db_txn, 0);
+ ret = dbd->db_env->txn_begin(dbd->db_env, NULL, &dbd->db_txn, 0);
if (ret) {
LOG(log_error, logtype_cnid, "error starting transaction: %s", db_strerror(errno));
return 0;
}
-int dbif_txn_commit()
+int dbif_txn_commit(DBD *dbd)
{
int ret;
- if (!db_txn)
+ if (! dbd->db_txn)
return 0;
- ret = db_txn->commit(db_txn, 0);
- db_txn = NULL;
+ /* If our DBD has no env, just return (-> in memory db) */
+ if (dbd->db_env == NULL)
+ return 0;
+
+ ret = dbd->db_txn->commit(dbd->db_txn, 0);
+ dbd->db_txn = NULL;
if (ret) {
LOG(log_error, logtype_cnid, "error committing transaction: %s", db_strerror(errno));
return 1;
}
-int dbif_txn_abort()
+int dbif_txn_abort(DBD *dbd)
{
int ret;
- if (!db_txn)
+ if (! dbd->db_txn)
return 0;
- ret = db_txn->abort(db_txn);
- db_txn = NULL;
+ /* If our DBD has no env, just return (-> in memory db) */
+ if (dbd->db_env == NULL)
+ return 0;
+
+ ret = dbd->db_txn->abort(dbd->db_txn);
+ dbd->db_txn = NULL;
if (ret) {
LOG(log_error, logtype_cnid, "error aborting transaction: %s", db_strerror(errno));
return 0;
}
-int dbif_txn_checkpoint(u_int32_t kbyte, u_int32_t min, u_int32_t flags)
+int dbif_txn_checkpoint(DBD *dbd, u_int32_t kbyte, u_int32_t min, u_int32_t flags)
{
int ret;
- ret = db_env->txn_checkpoint(db_env, kbyte, min, flags);
+ ret = dbd->db_env->txn_checkpoint(dbd->db_env, kbyte, min, flags);
if (ret) {
LOG(log_error, logtype_cnid, "error checkpointing transaction susystem: %s", db_strerror(errno));
return -1;
return 0;
}
-int dbif_count(const int dbi, u_int32_t *count)
+int dbif_count(DBD *dbd, const int dbi, u_int32_t *count)
{
int ret;
DB_BTREE_STAT *sp;
- DB *db = db_table[dbi].db;
+ DB *db = dbd->db_table[dbi].db;
ret = db->stat(db, NULL, &sp, 0);
return 0;
}
-int dbif_dump(int dumpindexes)
+int dbif_copy_rootinfokey(DBD *srcdbd, DBD *destdbd)
+{
+ DBT key, data;
+ int rc;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+
+ if ((rc = dbif_get(srcdbd, DBIF_CNID, &key, &data, 0)) <= 0) {
+ LOG(log_error, logtype_cnid, "dbif_copy_rootinfokey: Error getting rootinfo record");
+ return -1;
+ }
+
+ memset(&key, 0, sizeof(key));
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+
+ if ((rc = dbif_put(destdbd, DBIF_CNID, &key, &data, 0))) {
+ LOG(log_error, logtype_cnid, "dbif_copy_rootinfokey: Error writing rootinfo key");
+ return -1;
+ }
+
+ return 0;
+}
+
+int dbif_dump(DBD *dbd, int dumpindexes)
{
int rc;
- uint32_t max = 0, count = 0, cnid, type, did;
+ uint32_t max = 0, count = 0, cnid, type, did, lastid;
uint64_t dev, ino;
+ time_t stamp;
DBC *cur;
DBT key = { 0 }, data = { 0 };
- DB *db = db_table[DBIF_IDX_CNID].db;
+ DB *db = dbd->db_table[DBIF_CNID].db;
char *typestring[2] = {"f", "d"};
+ char timebuf[64];
- printf("CNID database:\n");
+ printf("CNID database dump:\n");
rc = db->cursor(db, NULL, &cur, 0);
if (rc) {
/* Rootinfo node ? */
if (cnid == 0) {
+ memcpy(&stamp, data.data + 4, sizeof(time_t));
+ memcpy(&lastid, data.data + 20, sizeof(cnid_t));
+ lastid = ntohl(lastid);
+ strftime(timebuf, sizeof(timebuf), "%b %d %Y %H:%M:%S", localtime(&stamp));
+ printf("dbd stamp: 0x%08x (%s), next free CNID: %u\n", (unsigned int)stamp, timebuf, lastid + 1);
} else {
/* dev */
memcpy(&dev, data.data + CNID_DEV_OFS, 8);
/* DBIF_IDX_DEVINO */
printf("\ndev/inode index:\n");
count = 0;
- db = db_table[DBIF_IDX_DEVINO].db;
+ db = dbd->db_table[DBIF_IDX_DEVINO].db;
rc = db->cursor(db, NULL, &cur, 0);
if (rc) {
LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(errno));
/* Now dump DBIF_IDX_DIDNAME */
printf("\ndid/name index:\n");
count = 0;
- db = db_table[DBIF_IDX_DIDNAME].db;
+ db = dbd->db_table[DBIF_IDX_DIDNAME].db;
rc = db->cursor(db, NULL, &cur, 0);
if (rc) {
LOG(log_error, logtype_cnid, "Couldn't create cursor: %s", db_strerror(errno));
/*
- * $Id: dbif.h,v 1.4 2009-04-28 13:01:24 franklahm Exp $
- *
- * Copyright (C) Joerg Lenneis 2003
- * Copyright (C) Frank Lahm 2009
- * All Rights Reserved. See COPYING.
- */
+ $Id: dbif.h,v 1.5 2009-05-06 11:54:24 franklahm Exp $
+
+ Copyright (C) Joerg Lenneis 2003
+ Copyright (C) Frank Lahm 2009
+ All Rights Reserved. See COPYING.
+
+
+ API usage
+ =========
+
+ Initialisation
+ --------------
+ 1. Provide storage for a DBD * handle
+ DBD *dbd;
+ 2. Call dbif_init with a filename to receive a DBD handle:
+ dbd = dbif_init("cnid2.db");
+ Pass NULL to create an in-memory db.
+ Note: the DBD type is NOT from BerkeleyDB ! We've defined it.
+ 3. Optional:
+ Call dbif_env_open to open an dbd environment, chdir to it beforehand
+ 4. Call dbif_open to finally open the CNID database itself
+
+ Querying the CNID database
+ --------------------------
+ Call dbif_[get|pget|put|del]. They map to the corresponding BerkeleyDB calls
+ with the same names.
+
+ Transactions
+ ------------
+ We use AUTO_COMMIT for the BDB database accesses. This avoids explicit transactions
+ for every bdb access which speeds up reads. But in order to be able to rollback
+ in case of errors we start a transaction once we encounter the first write from
+ dbif_put or dbif_del.
+ Thus you shouldn't call dbif_txn_[begin|abort|commit], they're used internally.
+
+ Checkpoiting
+ ------------
+ Call dbif_txn_checkpoint.
+
+ Closing
+ -------
+ Call dbif_close.
+*/
#ifndef CNID_DBD_DBIF_H
#define CNID_DBD_DBIF_H 1
#include "db_param.h"
#define DBIF_DB_CNT 3
-
-#define DBIF_IDX_CNID 0
+
+#define DBIF_CNID 0
#define DBIF_IDX_DEVINO 1
#define DBIF_IDX_DIDNAME 2
-extern int dbif_stamp(void *, int);
-extern int dbif_env_init(struct db_param *, uint32_t);
-extern int dbif_open(struct db_param *, int);
-extern int dbif_close(void);
-extern int dbif_closedb(void);
-extern int dbif_get(const int, DBT *, DBT *, u_int32_t);
-extern int dbif_pget(const int, DBT *, DBT *, DBT *, u_int32_t);
-extern int dbif_put(const int, DBT *, DBT *, u_int32_t);
-extern int dbif_del(const int, DBT *, u_int32_t);
+/* Structures */
+typedef struct {
+ char *name;
+ DB *db;
+ uint32_t flags;
+ uint32_t openflags;
+ DBTYPE type;
+} db_table;
+
+typedef struct {
+ DB_ENV *db_env;
+ DB_TXN *db_txn;
+ char *db_filename;
+ FILE *db_errlog;
+ db_table db_table[3];
+} DBD;
+
+/* Functions */
+extern DBD *dbif_init(const char *dbname);
+extern int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags);
+extern int dbif_open(DBD *dbd, struct db_param *dbp, int do_truncate);
+extern int dbif_close(DBD *dbd);
+
+extern int dbif_get(DBD *, const int, DBT *, DBT *, u_int32_t);
+extern int dbif_pget(DBD *, const int, DBT *, DBT *, DBT *, u_int32_t);
+extern int dbif_put(DBD *, const int, DBT *, DBT *, u_int32_t);
+extern int dbif_del(DBD *, const int, DBT *, u_int32_t);
-extern int dbif_count(const int, u_int32_t *);
+extern int dbif_count(DBD *, const int, u_int32_t *);
+extern int dbif_stamp(DBD *, void *, int);
+extern int dbif_copy_rootinfokey(DBD *srcdbd, DBD *destdbd);
+extern int dbif_txn_begin(DBD *);
+extern int dbif_txn_commit(DBD *);
+extern int dbif_txn_abort(DBD *);
+extern int dbif_txn_checkpoint(DBD *, u_int32_t, u_int32_t, u_int32_t);
-extern int dbif_txn_begin(void);
-extern int dbif_txn_commit(void);
-extern int dbif_txn_abort(void);
-extern int dbif_txn_checkpoint(u_int32_t, u_int32_t, u_int32_t);
+extern int dbif_dump(DBD *, int dumpindexes);
-extern int dbif_dump(int dumpindexes);
#endif
/*
- * $Id: main.c,v 1.5 2009-04-28 13:01:24 franklahm Exp $
+ * $Id: main.c,v 1.6 2009-05-06 11:54:24 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* Copyright (c) Frank Lahm 2009
* All Rights Reserved. See COPYING.
*/
-/*
- dbd and transactions
- ====================
-
- We use AUTO_COMMIT for our BerkeleyDB environment. This avoids explicit transactions
- for every bdb access which speeds up reads. But in order to be able to rollback
- in case of errors we start a transaction once we encounter the first write.
- The logic to do this is stuffed two levels lower into the dbif.c file and functions
- dbif_put and dbif_del.
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
Note: DB_INIT_LOCK is here so we can run the db_* utilities while netatalk is running.
It's a likey performance hit, but it might we worth it.
*/
-#define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN)
+#define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER)
+
+static DBD *dbd;
static int exit_sig = 0;
ret = 1;
break;
case CNID_DBD_OP_ADD:
- ret = dbd_add(&rqst, &rply);
+ ret = dbd_add(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_GET:
- ret = dbd_get(&rqst, &rply);
+ ret = dbd_get(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_RESOLVE:
- ret = dbd_resolve(&rqst, &rply);
+ ret = dbd_resolve(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_LOOKUP:
- ret = dbd_lookup(&rqst, &rply);
+ ret = dbd_lookup(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_UPDATE:
- ret = dbd_update(&rqst, &rply);
+ ret = dbd_update(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_DELETE:
- ret = dbd_delete(&rqst, &rply);
+ ret = dbd_delete(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_GETSTAMP:
- ret = dbd_getstamp(&rqst, &rply);
+ ret = dbd_getstamp(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_REBUILD_ADD:
- ret = dbd_rebuild_add(&rqst, &rply);
+ ret = dbd_rebuild_add(dbd, &rqst, &rply);
break;
default:
LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op);
}
if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
- dbif_txn_abort();
+ dbif_txn_abort(dbd);
return -1;
}
if (ret == 0 || cret == 0) {
- if (dbif_txn_abort() < 0)
+ if (dbif_txn_abort(dbd) < 0)
return -1;
} else {
- ret = dbif_txn_commit();
+ ret = dbif_txn_commit(dbd);
if ( ret < 0)
return -1;
else if ( ret > 0 )
*/
if (now > time_next_flush) {
LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB for volume '%s'", dbp->dir);
- if (dbif_txn_checkpoint(0, 0, 0) < 0)
+ if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0)
return -1;
count = 0;
time_next_flush = now + dbp->flush_interval;
*/
if (count > dbp->flush_frequency) {
LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB after %d writes for volume '%s'", count, dbp->dir);
- if (dbif_txn_checkpoint(0, 0, 0) < 0)
+ if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0)
return -1;
count = 0;
}
only shut down after one second of inactivity. */
block_sigs_onoff(1);
- if ((dbp = db_param_read(dir, DBD)) == NULL)
+ if ((dbp = db_param_read(dir, CNID_DBD)) == NULL)
exit(1);
LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file");
- if (dbif_env_init(dbp, DBOPTIONS) < 0)
+ if (NULL == (dbd = dbif_init("cnid2.db")))
+ exit(2);
+
+ if (dbif_env_open(dbd, dbp, DBOPTIONS) < 0)
exit(2); /* FIXME: same exit code as failure for dbif_open() */
LOG(log_debug, logtype_cnid, "Finished initializing BerkeleyDB environment");
- if (dbif_open(dbp, 0) < 0) {
- dbif_close();
+ if (dbif_open(dbd, dbp, 0) < 0) {
+ dbif_close(dbd);
exit(2);
}
LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
- if (dbd_stamp() < 0) {
- dbif_close();
+ if (dbd_stamp(dbd) < 0) {
+ dbif_close(dbd);
exit(5);
}
LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp");
if (comm_init(dbp, ctrlfd, clntfd) < 0) {
- dbif_close();
+ dbif_close(dbd);
exit(3);
}
if (loop(dbp) < 0)
err++;
- if (dbif_close() < 0)
+ if (dbif_close(dbd) < 0)
err++;
free_lock(lockfd);