+Changes in 2.2alpha5
+====================
+
+* UPD: afpd: new option "searchdb" which enables fast catalog searches
+ using the CNID db.
+* UPD: Case-insensitive fast search with the CNID db
+* UPD: cnid_dbd: afpd now passes the volume path, not the db path when
+ connecting for a volume. cnid_dbd will read the
+ ".AppleDesktop/.volinfo" file of the volume in order to figure
+ out the CNID db path and the volume charset encoding.
+
Changes in 2.2alpha4
====================
* NEW: afpd: support for fast catalog searches
* NEW: ad utility: ad find
* UPD: afpd: CNID database versioning check for "cdb" scheme
-* UPD: cnid_dbd: CNID database versioning
-* UPD: cnid_dbd: CNID database upgrading
-* UPD: cnid_dbd: additional CNID database index for fast name searches
+* UPD: cnid_dbd: CNID database versioning and upgrading. Additional
+ CNID database index for fast name searches.
Changes in 2.2alpha3
====================
#include <atalk/bstradd.h>
#include <atalk/directory.h>
#include <atalk/util.h>
+#include <atalk/unicode.h>
#include "ad.h"
static volatile sig_atomic_t alarmed;
if (openvol(srchvol, &vol) != 0)
ERROR("Cant open volume \"%s\"", srchvol);
+ uint16_t flags = CONV_TOLOWER;
+ char namebuf[MAXPATHLEN + 1];
+ if (convert_charset(vol.volinfo.v_volcharset,
+ vol.volinfo.v_volcharset,
+ vol.volinfo.v_maccharset,
+ argv[optind],
+ strlen(argv[optind]),
+ namebuf,
+ MAXPATHLEN,
+ &flags) == (size_t)-1) {
+ ERROR("conversion error");
+ }
+
int count;
char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)];
- if ((count = cnid_find(vol.volume.v_cdb, argv[optind], strlen(argv[optind]), resbuf, sizeof(resbuf))) < 1) {
+ if ((count = cnid_find(vol.volume.v_cdb,
+ namebuf,
+ strlen(namebuf),
+ resbuf,
+ sizeof(resbuf))) < 1) {
ret = 1;
} else {
ret = 0;
if ((vol->volinfo.v_flags & AFPVOL_NODEV))
flags |= CNID_FLAG_NODEV;
- if ((vol->volume.v_cdb = cnid_open(vol->volinfo.v_dbpath,
+ if ((vol->volume.v_cdb = cnid_open(vol->volinfo.v_path,
0000,
"dbd",
flags,
dnl --------------------- Netatalk Webmin
NETATALK_WEBMIN
-dnl --------------------- Check for libuuid which is required for TimeMachine
-AC_SEARCH_LIBS([uuid_generate],
- [uuid], ,
- AC_MSG_ERROR([missing library libuuid required for TimeMachine]))
-AC_CHECK_HEADER([uuid/uuid.h],
- AC_DEFINE([HAVE_UUID], 1, [have libuuid]),
- AC_MSG_ERROR([missing header <uuid/uuid.> from libuuid required for TimeMachine]))
-
dnl --------------------- last minute substitutions
dnl Request SUSv3 standard interfaces
CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D__EXTENSIONS__"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-
-/* STDC check */
-#if STDC_HEADERS
#include <string.h>
-#else /* STDC_HEADERS */
-#ifndef HAVE_STRCHR
-#define strchr index
-#define strrchr index
-#endif /* HAVE_STRCHR */
-char *strchr (), *strrchr ();
-#ifndef HAVE_MEMCPY
-#define memcpy(d,s,n) bcopy ((s), (d), (n))
-#define memmove(d,s,n) bcopy ((s), (d), (n))
-#endif /* ! HAVE_MEMCPY */
-#endif /* STDC_HEADERS */
-
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
#include <ctype.h>
-#include <atalk/logger.h>
-#include <atalk/util.h>
-
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#ifdef USE_SRVLOC
+#include <slp.h>
+#endif /* USE_SRVLOC */
+
+#include <atalk/logger.h>
+#include <atalk/util.h>
#include <atalk/dsi.h>
#include <atalk/atp.h>
#include <atalk/asp.h>
#include <atalk/afp.h>
#include <atalk/compat.h>
#include <atalk/server_child.h>
-#ifdef USE_SRVLOC
-#include <slp.h>
-#endif /* USE_SRVLOC */
+
#ifdef HAVE_LDAP
#include <atalk/ldapconfig.h>
#endif
#include <stdio.h>
#include <stdlib.h>
-
-/* STDC check */
-#if STDC_HEADERS
#include <string.h>
-#else /* STDC_HEADERS */
-#ifndef HAVE_STRCHR
-#define strchr index
-#define strrchr index
-#endif /* HAVE_STRCHR */
-char *strchr (), *strrchr ();
-#ifndef HAVE_MEMCPY
-#define memcpy(d,s,n) bcopy ((s), (d), (n))
-#define memmove(d,s,n) bcopy ((s), (d), (n))
-#endif /* ! HAVE_MEMCPY */
-#endif /* STDC_HEADERS */
-
#include <ctype.h>
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
#include <sys/param.h>
#include <sys/socket.h>
#include <atalk/logger.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif /* HAVE_NETDB_H */
+#ifdef ADMIN_GRP
+#include <grp.h>
+#include <sys/types.h>
+#endif /* ADMIN_GRP */
+
#include <atalk/paths.h>
#include <atalk/util.h>
+#include <atalk/compat.h>
+
#include "globals.h"
#include "status.h"
#include "auth.h"
#include "dircache.h"
-#include <atalk/compat.h>
-
-#ifdef ADMIN_GRP
-#include <grp.h>
-#include <sys/types.h>
-#endif /* ADMIN_GRP */
-
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif /* MIN */
#include <atalk/cnid_dbd_private.h>
#include <atalk/util.h>
#include <atalk/bstradd.h>
+#include <atalk/unicode.h>
#include "desktop.h"
#include "directory.h"
int result = AFP_OK;
struct path path;
char *rrbuf = rbuf;
+ char buffer[MAXPATHLEN +2];
+ uint16_t flags = CONV_TOLOWER;
LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u, name: %s}",
*pos, cur_pos, uname);
}
if (cur_pos == 0 || *pos == 0) {
+ if (convert_charset(vol->v_volcharset,
+ vol->v_volcharset,
+ vol->v_maccharset,
+ uname,
+ strlen(uname),
+ buffer,
+ MAXPATHLEN,
+ &flags) == (size_t)-1) {
+ LOG(log_error, logtype_cnid, "catsearch_db: conversion error");
+ result = AFPERR_MISC;
+ goto catsearch_end;
+ }
+
+ LOG(log_debug, logtype_afpd, "catsearch_db: %s", buffer);
+
if ((num_matches = cnid_find(vol->v_cdb,
- uname,
+ buffer,
strlen(uname),
resbuf,
sizeof(resbuf))) == -1) {
switch (errno) {
case EACCES:
case ELOOP:
- case ENOENT:
goto next;
+ case ENOENT:
+
default:
result = AFPERR_MISC;
goto catsearch_end;
/* Call search */
*rbuflen = 24;
- if ((c1.rbitmap & (1 << FILPBIT_PDINFO)) && (strcmp(vol->v_cnidscheme, "dbd") == 0))
+ if ((c1.rbitmap & (1 << FILPBIT_PDINFO))
+ && (strcmp(vol->v_cnidscheme, "dbd") == 0)
+ && (vol->v_flags & AFPVOL_SEARCHDB))
/* we've got a name and it's a dbd volume, so search CNID database */
ret = catsearch_db(vol, vol->v_root, uname, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
else
options->sigconffile, strerror(errno));
goto server_signature_random;
}
- } else { /* conf file don't exist */
+ } else { /* conf file don't exist */
if (( fd = creat(options->sigconffile, 0644 )) < 0 ) {
- LOG(log_error, logtype_atalkd, "ERROR: Cannot create %s (%s). Using one-time signature.",
+ LOG(log_error, logtype_atalkd, "Cannot create %s (%s). Using one-time signature.",
options->sigconffile, strerror(errno));
goto server_signature_random;
}
if (( fp = fdopen( fd, "w" )) == NULL ) {
- LOG(log_error, logtype_atalkd, "ERROR: Cannot fdopen %s (%s). Using one-time signature.",
+ LOG(log_error, logtype_atalkd, "Cannot fdopen %s (%s). Using one-time signature.",
options->sigconffile, strerror(errno));
close(fd);
goto server_signature_random;
server_signature_random:
/* generate signature from random number */
- if ((randomp = fopen("/dev/urandom", "r")) != NULL) { /* generate from /dev/urandom */
- for (i=0 ; i<16 ; i++) {
- (options->signature)[i] = fgetc(randomp);
- }
- LOG(log_note, logtype_afpd,
- "generate %s's signature %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X from /dev/urandom",
- server_tmp,
- (options->signature)[ 0], (options->signature)[ 1],
- (options->signature)[ 2], (options->signature)[ 3],
- (options->signature)[ 4], (options->signature)[ 5],
- (options->signature)[ 6], (options->signature)[ 7],
- (options->signature)[ 8], (options->signature)[ 9],
- (options->signature)[10], (options->signature)[11],
- (options->signature)[12], (options->signature)[13],
- (options->signature)[14], (options->signature)[15]);
-
- } else { /* genarate from random() because cannot open /dev/urandom */
- srandom((unsigned int)time(NULL) + (unsigned int)options + (unsigned int)server_tmp);
- for (i=0 ; i<16 ; i++) {
- (options->signature)[i] = random() & 0xFF;
- }
- LOG(log_note, logtype_afpd,
- "generate %s's signature %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X from random()",
- server_tmp,
- (options->signature)[ 0], (options->signature)[ 1],
- (options->signature)[ 2], (options->signature)[ 3],
- (options->signature)[ 4], (options->signature)[ 5],
- (options->signature)[ 6], (options->signature)[ 7],
- (options->signature)[ 8], (options->signature)[ 9],
- (options->signature)[10], (options->signature)[11],
- (options->signature)[12], (options->signature)[13],
- (options->signature)[14], (options->signature)[15]);
- }
+ randombytes(options->signature, 16);
- if (fp && header) { /* conf file is created or size=0 */
+ if (fp && header) { /* conf file is created or size=0 */
fprintf(fp, "# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n");
fprintf(fp, "# This file is auto-generated by afpd.\n");
fprintf(fp, "# \n");
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <uuid/uuid.h>
-
#include <atalk/asp.h>
#include <atalk/dsi.h>
#include <atalk/adouble.h>
#include <atalk/volinfo.h>
#include <atalk/logger.h>
#include <atalk/vfs.h>
-#include <atalk/ea.h>
+#include <atalk/uuid.h>
+
#ifdef CNID_DB
#include <atalk/cnid.h>
#endif /* CNID_DB*/
options[VOLOPT_FLAGS].i_value &= ~AFPVOL_CACHE;
else if (strcasecmp(p, "tm") == 0)
options[VOLOPT_FLAGS].i_value |= AFPVOL_TM;
+ else if (strcasecmp(p, "searchdb") == 0)
+ options[VOLOPT_FLAGS].i_value |= AFPVOL_SEARCHDB;
/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
#if 0
else if (strcasecmp(p, "cdrom") == 0)
volume->v_vid = htons(volume->v_vid);
#ifdef HAVE_ACLS
if (check_vol_acl_support(volume))
- volume->v_flags |= AFPVOL_ACLS;
+ volume->v_flags |= AFPVOL_ACLS
+;
#endif
/* handle options */
}
#endif
- volume->v_cdb = cnid_open(volume->v_dbpath ? volume->v_dbpath : volume->v_path,
+ volume->v_cdb = cnid_open(volume->v_path,
volume->v_umask,
volume->v_cnidscheme,
flags,
}
/* generate uuid and write to file */
- uuid_t id;
- uuid_generate(id);
- uuid_unparse(id, uuid);
- for (int i=0; uuid[i]; i++)
- uuid[i] = toupper(uuid[i]);
- LOG(log_debug, logtype_afpd, "get_uuid('%s'): generated UUID '%s'", volname, uuid);
-
- fprintf(fp, "\"%s\"\t%36s\n", volname, uuid);
+ atalk_uuid_t id;
+ const char *cp;
+ randombytes((void *)id, 16);
+ cp = uuid_bin2string(id);
+
+ LOG(log_debug, logtype_afpd, "get_uuid('%s'): generated UUID '%s'", volname, cp);
+
+ fprintf(fp, "\"%s\"\t%36s\n", volname, cp);
fclose(fp);
return strdup(uuid);
/*
- $Id: cmd_dbd.c,v 1.26 2010-04-20 16:46:20 hat001 Exp $
-
Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
This program is free software; you can redistribute it and/or modify
int nocniddb = 0; /* Dont open CNID database, only scan filesystem */
volatile sig_atomic_t alarmed;
+struct volinfo volinfo;
static DBD *dbd;
static int verbose; /* Logging flag */
-1,
-1
};
-static char dbpath[PATH_MAX]; /* Path to the dbd database */
+static char dbpath[MAXPATHLEN+1]; /* Path to the dbd database */
/*
Provide some logging
int dump=0, scan=0, rebuild=0, prep_upgrade=0, rebuildindexes=0, dumpindexes=0, force=0;
dbd_flags_t flags = 0;
char *volpath;
- struct volinfo volinfo;
int cdir;
if (geteuid() != 0) {
exit(EXIT_FAILURE);
}
+ /* Enuser dbpath is there, create if necessary */
+ struct stat st;
+ if (stat(volinfo.v_dbpath, &st) != 0) {
+ if (errno != ENOENT) {
+ dbd_log( LOGSTD, "Can't stat dbpath \"%s\": %s", volinfo.v_dbpath, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if ((mkdir(volinfo.v_dbpath, 0755)) != 0) {
+ dbd_log( LOGSTD, "Can't create dbpath \"%s\": %s", dbpath, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
/* Put "/.AppleDB" at end of volpath, get path from volinfo file */
- if ( (strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > (PATH_MAX - 1) ) {
+ if ( (strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) {
dbd_log( LOGSTD, "Volume pathname too long");
exit(EXIT_FAILURE);
}
- strncpy(dbpath, volinfo.v_dbpath, PATH_MAX - 9 - 1);
+ strncpy(dbpath, volinfo.v_dbpath, MAXPATHLEN - strlen("/.AppleDB"));
strcat(dbpath, "/.AppleDB");
/* Check or create dbpath */
/* Check if -f is requested and wipe db if yes */
if ((flags & DBD_FLAGS_FORCE) && rebuild && (volinfo.v_flags & AFPVOL_CACHE)) {
char cmd[8 + MAXPATHLEN];
- snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", dbpath);
+ snprintf(cmd, 8 + MAXPATHLEN, "rm -rf \"%s\"", dbpath);
dbd_log( LOGDEBUG, "Removing old database of volume: '%s'", volpath);
system(cmd);
+ if ((mkdir(dbpath, 0755)) != 0) {
+ dbd_log( LOGSTD, "Can't create dbpath \"%s\": %s", dbpath, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
dbd_log( LOGDEBUG, "Removed old database.");
}
dbif_close(dbd);
goto exit_failure;
}
-
- if (dbd_stamp(dbd) < 0) {
- dbif_close(dbd);
- goto exit_failure;
- }
}
/* Now execute given command scan|rebuild|dump */
extern int nocniddb; /* Dont open CNID database, only scan filesystem */
extern volatile sig_atomic_t alarmed;
-extern struct volinfo *volinfo;
+// extern struct volinfo *volinfo;
extern char cwdbuf[MAXPATHLEN+1];
extern void dbd_log(enum logtype lt, char *fmt, ...);
dbd_log(LOGSTD, "Orphaned CNID in database: %u", dbd_cnid);
if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
rqst.cnid = htonl(dbd_cnid);
- ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
+ if ((ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID)) == -1) {
+ dbd_log(LOGSTD, "Error deleting CNID %u", dbd_cnid);
+ (void)dbif_txn_abort(dbd);
+ goto cleanup;
+ }
+
dbif_txn_close(dbd, ret);
deleted++;
}
if (dbd_cnid < rebuild_cnid) {
/* CNID is orphaned -> delete */
- dbd_log(LOGSTD, "Orphaned CNID in database: %u.", dbd_cnid);
+ dbd_log(LOGSTD, "One orphaned CNID in database: %u.", dbd_cnid);
if ( ! (dbd_flags & DBD_FLAGS_SCAN)) {
rqst.cnid = htonl(dbd_cnid);
- ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID);
+ if ((ret = dbd_delete(dbd, &rqst, &rply, DBIF_CNID)) == -1) {
+ dbd_log(LOGSTD, "Error deleting CNID %u", dbd_cnid);
+ (void)dbif_txn_abort(dbd);
+ goto cleanup;
+ }
dbif_txn_close(dbd, ret);
deleted++;
}
dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */
goto cleanup;
}
- }
+ } /* while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) */
cleanup:
dbif_idwalk(dbd, NULL, 1); /* Close cursor */
#include <atalk/logger.h>
#include <atalk/cnid_dbd_private.h>
#include <atalk/paths.h>
+#include <atalk/volinfo.h>
-#include "db_param.h"
#include "usockfd.h"
#define DBHOME ".AppleDB"
#define DEFAULTPORT "4700"
struct server {
- char *name;
+ struct volinfo *volinfo;
pid_t pid;
time_t tm; /* When respawned last */
int count; /* Times respawned in the last TESTTIME secondes */
daemon_exit(0);
}
-static struct server *test_usockfn(char *dir)
+static struct server *test_usockfn(struct volinfo *volinfo)
{
int i;
for (i = 0; i < MAXVOLS; i++) {
- if (srv[i].name && !strcmp(srv[i].name, dir)) {
+ if ((srv[i].volinfo) && (strcmp(srv[i].volinfo->v_path, volinfo->v_path) == 0)) {
return &srv[i];
}
}
}
/* -------------------- */
-static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
+static int maybe_start_dbd(char *dbdpn, struct volinfo *volinfo)
{
pid_t pid;
struct server *up;
time_t t;
char buf1[8];
char buf2[8];
+ char *volpath = volinfo->v_path;
- LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: dbdir: '%s', UNIX socket file: '%s'",
- dbdir, usockfn);
+ LOG(log_debug, logtype_cnid, "maybe_start_dbd: Volume: \"%s\"", volpath);
- up = test_usockfn(dbdir);
+ up = test_usockfn(volinfo);
if (up && up->pid) {
/* we already have a process, send our fd */
if (send_cred(up->control_fd, rqstfd) < 0) {
return 0;
}
- LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: no cnid_dbd for that volume yet. Starting one ...");
+ LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: no cnid_dbd for that volume yet");
time(&t);
if (!up) {
/* find an empty slot */
for (i = 0; i < MAXVOLS; i++) {
- if ( !srv[i].name ) {
+ if (srv[i].volinfo == NULL) {
up = &srv[i];
+ up->volinfo = volinfo;
+ retainvolinfo(volinfo);
up->tm = t;
up->count = 0;
- up->name = strdup(dbdir);
break;
}
}
LOG(log_error, logtype_cnid, "no free slot for cnid_dbd child. Configured maximum: %d. Do you have so many volumes?", MAXVOLS);
return -1;
}
- }
- else {
+ } else {
/* we have a slot but no process, check for respawn too fast */
if ( (t < (up->tm + TESTTIME)) /* We're in the respawn time window */
&&
/* there's a pb with the db inform child
* it will run recover, delete the db whatever
*/
- LOG(log_error, logtype_cnid, "try with -d %s", up->name);
- ret = execlp(dbdpn, dbdpn, "-d", dbdir, buf1, buf2, logconfig, NULL);
+ LOG(log_error, logtype_cnid, "try with -d %s", up->volinfo->v_path);
+ ret = execlp(dbdpn, dbdpn, "-d", volpath, buf1, buf2, logconfig, NULL);
}
else {
- ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, logconfig, NULL);
+ ret = execlp(dbdpn, dbdpn, volpath, buf1, buf2, logconfig, NULL);
}
/* Yikes! We're still here, so exec failed... */
LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
}
/* ------------------ */
-static int set_dbdir(char *dbdir, int len)
+static int set_dbdir(char *dbdir)
{
+ int len;
struct stat st;
- if (!len)
- return -1;
+ len = strlen(dbdir);
if (stat(dbdir, &st) < 0 && mkdir(dbdir, 0755) < 0) {
LOG(log_error, logtype_cnid, "set_dbdir: mkdir failed for %s", dbdir);
/* ------------------ */
int main(int argc, char *argv[])
{
- char dbdir[MAXPATHLEN + 1];
+ char volpath[MAXPATHLEN + 1];
int len, actual_len;
pid_t pid;
int status;
char *dbdpn = _PATH_CNID_DBD;
char *host = DEFAULTHOST;
char *port = DEFAULTPORT;
- struct db_param *dbp;
int i;
int cc;
uid_t uid = 0;
char *loglevel = NULL;
char *logfile = NULL;
sigset_t set;
+ struct volinfo *volinfo;
set_processname("cnid_metad");
}
/* Check PID lockfile and become a daemon */
- switch(server_lock("cnid_metad", _PATH_CNID_METAD_LOCK, 0)) {
+ switch(server_lock("cnid_metad", _PATH_CNID_METAD_LOCK, debug)) {
case -1: /* error */
daemon_exit(EXITERR_SYS);
case 0: /* child */
goto loop_end;
}
- actual_len = readt(rqstfd, dbdir, len, 1, 5);
+ actual_len = readt(rqstfd, volpath, len, 1, 5);
if (actual_len < 0) {
LOG(log_severe, logtype_cnid, "Read(2) error : %s", strerror(errno));
goto loop_end;
LOG(log_error, logtype_cnid, "error/short read (dir): %s", strerror(errno));
goto loop_end;
}
- dbdir[len] = '\0';
+ volpath[len] = '\0';
- if (set_dbdir(dbdir, len) < 0) {
+ /* Load .volinfo file */
+ if ((volinfo = allocvolinfo(volpath)) == NULL) {
+ LOG(log_severe, logtype_cnid, "allocvolinfo: %s", strerror(errno));
goto loop_end;
}
- if ((dbp = db_param_read(dbdir, METAD)) == NULL) {
- LOG(log_error, logtype_cnid, "Error reading config file");
+ if (set_dbdir(volinfo->v_dbpath) < 0) {
goto loop_end;
}
- maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);
+
+ maybe_start_dbd(dbdpn, volinfo);
+
+ (void)closevolinfo(volinfo);
loop_end:
close(rqstfd);
buffer overflow) nor elegant, we need to add support for whitespace in
filenames as well. */
-struct db_param *db_param_read(char *dir, enum identity id)
+struct db_param *db_param_read(char *dir)
{
FILE *fp;
static char key[MAXKEYLEN + 1];
LOG(log_info, logtype_cnid, "db_param: setting UNIX domain socket filename to %s", params.usock_file);
}
- /* Config for cnid_metad only */
- if ( id == METAD ) {
- /* Currently empty */
+ 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);
+ } else if (! strcmp(key, "logfile_autoremove")) {
+ params.logfile_autoremove = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting logfile_autoremove to %d", params.logfile_autoremove);
+ } else if (! strcmp(key, "cachesize")) {
+ params.cachesize = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting cachesize to %d", params.cachesize);
+ } else if (! strcmp(key, "maxlocks")) {
+ params.maxlocks = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting maxlocks to %d", params.maxlocks);
+ } else if (! strcmp(key, "maxlockobjs")) {
+ params.maxlockobjs = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting maxlockobjs to %d", params.maxlockobjs);
+ } else if (! strcmp(key, "flush_frequency")) {
+ params.flush_frequency = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting flush_frequency to %d", params.flush_frequency);
+ } else if (! strcmp(key, "flush_interval")) {
+ params.flush_interval = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting flush_interval to %d", params.flush_interval);
+ } else if (! strcmp(key, "idle_timeout")) {
+ params.idle_timeout = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting idle timeout to %d", params.idle_timeout);
}
- /* Config for dbd only */
- 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);
- } else if (! strcmp(key, "logfile_autoremove")) {
- params.logfile_autoremove = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting logfile_autoremove to %d", params.logfile_autoremove);
- } else if (! strcmp(key, "cachesize")) {
- params.cachesize = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting cachesize to %d", params.cachesize);
- } else if (! strcmp(key, "maxlocks")) {
- params.maxlocks = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting maxlocks to %d", params.maxlocks);
- } else if (! strcmp(key, "maxlockobjs")) {
- params.maxlockobjs = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting maxlockobjs to %d", params.maxlockobjs);
- } else if (! strcmp(key, "flush_frequency")) {
- params.flush_frequency = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting flush_frequency to %d", params.flush_frequency);
- } else if (! strcmp(key, "flush_interval")) {
- params.flush_interval = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting flush_interval to %d", params.flush_interval);
- } else if (! strcmp(key, "idle_timeout")) {
- params.idle_timeout = parse_int(val);
- LOG(log_info, logtype_cnid, "db_param: setting idle timeout to %d", params.idle_timeout);
- }
- }
if (parse_err)
break;
}
#include <sys/param.h>
#include <sys/cdefs.h>
-enum identity {
- METAD,
- CNID_DBD
-};
-
struct db_param {
char *dir;
int logfile_autoremove;
int max_vols;
};
-extern struct db_param * db_param_read (char *, enum identity);
-
+extern struct db_param *db_param_read (char *);
#endif /* CNID_DBD_DB_PARAM_H */
extern int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply);
extern int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply);
-extern int dbd_stamp(DBD *dbd);
extern int dbd_add(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *, int nolookup);
extern int dbd_lookup(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *, int roflag);
extern int dbd_get(DBD *dbd, struct cnid_dbd_rqst *, struct cnid_dbd_rply *);
return 0;
}
-/* ---------------
-*/
-int dbd_stamp(DBD *dbd)
-{
- DBT rootinfo_key, rootinfo_data;
- cnid_t hint;
- char buf[ROOTINFO_DATALEN];
- char stamp[CNID_DEV_LEN];
-
- 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 (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(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(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
- return -1;
- }
- return 0;
-
- case 1: /* we already have one */
- return 0;
- default:
- return -1;
- }
- return -1;
-}
-
/* ------------------------ */
/* We need a nolookup version for `dbd` */
int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int nolookup)
+
/*
* $Id: dbd_getstamp.c,v 1.4 2009-05-06 11:54:24 franklahm Exp $
*
return ret;
}
+#include <atalk/util.h>
+
/* --------------- */
int dbif_stamp(DBD *dbd, void *buffer, int size)
{
LOG(log_error, logtype_cnid, "error stating database %s: %s", dbd->db_table[DBIF_CNID].name, db_strerror(errno));
return -1;
}
+
+ LOG(log_maxdebug, logtype_cnid,"stamp: %s", asctime(localtime(&st.st_ctime)));
+
memset(buffer, 0, size);
memcpy(buffer, &st.st_ctime, sizeof(st.st_ctime));
if (reindex)
LOG(log_info, logtype_cnid, "Reindexing name index...");
- int version = dbif_getversion(dbd);
- if (version == -1)
- return -1;
+
+ int version = CNID_VERSION;
+ if (dbd->db_envhome) {
+ if ((version = dbif_getversion(dbd)) == -1)
+ return -1;
+ }
+
if ((ret = dbd->db_table[0].db->associate(dbd->db_table[0].db,
dbd->db_txn,
dbd->db_table[DBIF_IDX_NAME].db,
if (reindex)
LOG(log_info, logtype_cnid, "... done.");
- if ((ret = dbif_upgrade(dbd)) != 0) {
+ if ((dbd->db_envhome) && ((ret = dbif_upgrade(dbd)) != 0)) {
LOG(log_error, logtype_cnid, "Error upgrading CNID database to version %d", CNID_VERSION);
return -1;
}
key,
flags);
- if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD)
+ if (ret == DB_NOTFOUND) {
+ LOG(log_info, logtype_cnid, "key not found");
return 0;
+ }
if (ret) {
LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s",
dbd->db_table[dbi].name, db_strerror(ret));
return 1;
}
+/*!
+ * Inititialize rootinfo key (which has CNID 0 as key)
+ *
+ * This also "stamps" the database, which means storing st.st_ctime of the
+ * "cnid2.db" file in the rootinfo data at the DEV offset
+ *
+ * @param dbd (rw) database handle
+ * @param version (r) database version number
+ *
+ * @returns -1 on error, 0 on success
+ */
+static int dbif_init_rootinfo(DBD *dbd, int version)
+{
+ DBT key, data;
+ uint32_t v;
+ char buf[ROOTINFO_DATALEN];
+
+ LOG(log_debug, logtype_cnid, "Setting CNID database version to %u", version);
+
+ v = version;
+ v = htonl(v);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+ data.data = buf;
+ data.size = ROOTINFO_DATALEN;
+
+ memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+ memcpy(buf + CNID_DID_OFS, &v, sizeof(v));
+ if (dbif_stamp(dbd, buf + CNID_DEV_OFS, CNID_DEV_LEN) < 0)
+ return -1;
+
+ if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
/*!
* Initialize or return CNID database version number
+ *
+ * Calls dbif_init_rootinfo if the rootinfo key does not exist yet
+ *
* @returns -1 on error, version number otherwise
*/
int dbif_getversion(DBD *dbd)
ret = version;
break;
case 0: /* not found */
- if (dbif_setversion(dbd, CNID_VERSION) != 0)
+ if (dbif_init_rootinfo(dbd, CNID_VERSION) != 0)
return -1;
ret = CNID_VERSION;
break;
}
/*!
- * Return CNID database version number
+ * Set CNID database version number
+ *
+ * Initializes rootinfo key as neccessary, as does dbif_getversion
* @returns -1 on error, version number otherwise
*/
int dbif_setversion(DBD *dbd, int version)
int ret;
DBT key, data;
uint32_t v;
- char buf[ROOTINFO_DATALEN];
LOG(log_debug, logtype_cnid, "Setting CNID database version to %u", version);
if ((ret = dbif_get(dbd, DBIF_CNID, &key, &data, 0)) == -1)
return -1;
if (ret == 0) {
- memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
- data.data = buf;
+ /* No rootinfo key yet, init it */
+ if (dbif_init_rootinfo(dbd, CNID_VERSION) != 0)
+ return -1;
+ /* Now try again */
+ if (dbif_get(dbd, DBIF_CNID, &key, &data, 0) == -1)
+ return -1;
}
memcpy((char *)data.data + CNID_DID_OFS, &v, sizeof(v));
data.size = ROOTINFO_DATALEN;
int dbif_dump(DBD *dbd, int dumpindexes)
{
int rc;
- uint32_t max = 0, count = 0, cnid, type, did, lastid;
+ uint32_t max = 0, count = 0, cnid, type, did, lastid, version;
uint64_t dev, ino;
time_t stamp;
DBC *cur;
/* Rootinfo node ? */
if (cnid == 0) {
- memcpy(&stamp, (char *)data.data + 4, sizeof(time_t));
- memcpy(&lastid, (char *)data.data + 20, sizeof(cnid_t));
+ memcpy(&stamp, (char *)data.data + CNID_DEV_OFS, sizeof(time_t));
+ memcpy(&lastid, (char *)data.data + CNID_TYPE_OFS, CNID_TYPE_LEN);
lastid = ntohl(lastid);
+ memcpy(&version, (char *)data.data + CNID_DID_OFS, CNID_DID_LEN);
+ version = ntohl(version);
+
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);
+ printf("CNID db version: %u, dbd stamp: 0x%08x (%s), next free CNID: %u\n",
+ version, (unsigned int)stamp, timebuf, lastid + 1);
} else {
/* dev */
memcpy(&dev, (char *)data.data + CNID_DEV_OFS, 8);
#include <netatalk/endian.h>
#include <atalk/cnid_dbd_private.h>
#include <atalk/logger.h>
+#include <atalk/volinfo.h>
#include "db_param.h"
#include "dbif.h"
*/
#define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER)
-static DBD *dbd;
+/* Global */
+struct volinfo volinfo;
+static DBD *dbd;
static int exit_sig = 0;
static void sig_exit(int signo)
if (fcntl(lockfd, F_SETLK, &lock) < 0) {
if (errno == EACCES || errno == EAGAIN) {
+ LOG(log_error, logtype_cnid, "get_lock: locked");
exit(0);
} else {
LOG(log_error, logtype_cnid, "main: fcntl F_WRLCK lockfile: %s", strerror(errno));
struct db_param *dbp;
int err = 0;
int lockfd, ctrlfd, clntfd;
- char *dir, *logconfig;
+ char *logconfig;
set_processname("cnid_dbd");
exit(1);
}
- dir = argv[1];
ctrlfd = atoi(argv[2]);
clntfd = atoi(argv[3]);
logconfig = strdup(argv[4]);
setuplog(logconfig);
- switch_to_user(dir);
+ /* Load .volinfo file */
+ if (loadvolinfo(argv[1], &volinfo) == -1) {
+ LOG(log_error, logtype_cnid, "Cant load volinfo for \"%s\"", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+ /* Put "/.AppleDB" at end of volpath, get path from volinfo file */
+ char dbpath[MAXPATHLEN+1];
+ if ((strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) {
+ LOG(log_error, logtype_cnid, "CNID db pathname too long: \"%s\"", volinfo.v_dbpath);
+ exit(EXIT_FAILURE);
+ }
+ strncpy(dbpath, volinfo.v_dbpath, MAXPATHLEN - strlen("/.AppleDB"));
+ strcat(dbpath, "/.AppleDB");
+
+ if (vol_load_charsets(&volinfo) == -1) {
+ LOG(log_error, logtype_cnid, "Error loading charsets!");
+ exit(EXIT_FAILURE);
+ }
+ LOG(log_debug, logtype_cnid, "db dir: \"%s\"", dbpath);
+
+ switch_to_user(dbpath);
/* Before we do anything else, check if there is an instance of cnid_dbd
running already and silently exit if yes. */
lockfd = get_lock();
- LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
-
set_signal();
/* SIGINT and SIGTERM are always off, unless we are in pselect */
block_sigs_onoff(1);
- if ((dbp = db_param_read(dir, CNID_DBD)) == NULL)
+ if ((dbp = db_param_read(dbpath)) == NULL)
exit(1);
LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file");
}
LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
- 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(dbd);
exit(3);
if (dbif_close(dbd) < 0)
err++;
- if (dbif_env_remove(dir) < 0)
+ if (dbif_env_remove(dbpath) < 0)
err++;
free_lock(lockfd);
#include <netatalk/endian.h>
#include <string.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif /* HAVE_SYS_TYPES_H */
+#include <inttypes.h>
#include <sys/param.h>
#include <sys/cdefs.h>
#include <db.h>
+#include <atalk/unicode.h>
+#include <atalk/volinfo.h>
+#include <atalk/logger.h>
#include <atalk/cnid_dbd_private.h>
#include "pack.h"
+/* in main.c for `cnid_dbd` or cmd_dbd.c for `dbd` */
+extern struct volinfo volinfo;
+
/* --------------- */
/*
* This implementation is portable, but could probably be faster by using htonl
/* --------------- */
int idxname(DB *dbp _U_, const DBT *pkey _U_, const DBT *pdata, DBT *skey)
{
+ char buffer[MAXPATHLEN +2];
+ uint16_t flags = CONV_TOLOWER;
memset(skey, 0, sizeof(DBT));
skey->data = (char *)pdata->data + CNID_NAME_OFS;
- skey->size = strlen((char *)skey->data) + 1;
+
+ if (convert_charset(volinfo.v_volcharset,
+ volinfo.v_volcharset,
+ volinfo.v_maccharset,
+ (char *)pdata->data + CNID_NAME_OFS,
+ strlen((char *)pdata->data + CNID_NAME_OFS),
+ buffer,
+ MAXPATHLEN,
+ &flags) == (size_t)-1) {
+ LOG(log_error, logtype_cnid, "idxname: conversion error");
+ }
+
+ skey->data = buffer;
+ skey->size = strlen(skey->data);
return (0);
}
#define CNID_INO_LEN 8
#define CNID_DEVINO_OFS CNID_LEN
-#define CNID_DEVINO_LEN (CNID_DEV_LEN +CNID_INO_LEN)
+#define CNID_DEVINO_LEN (CNID_DEV_LEN + CNID_INO_LEN)
-#define CNID_TYPE_OFS (CNID_DEVINO_OFS +CNID_DEVINO_LEN)
+#define CNID_TYPE_OFS (CNID_DEVINO_OFS + CNID_DEVINO_LEN)
#define CNID_TYPE_LEN 4
-#define CNID_DID_OFS (CNID_TYPE_OFS +CNID_TYPE_LEN)
+#define CNID_DID_OFS (CNID_TYPE_OFS + CNID_TYPE_LEN)
#define CNID_DID_LEN CNID_LEN
#define CNID_NAME_OFS (CNID_DID_OFS + CNID_DID_LEN)
extern const char *getcwdpath(void);
extern char *stripped_slashes_basename(char *p);
extern int lchdir(const char *dir);
-
+extern void randombytes(void *buf, int n);
#endif /* _ATALK_UTIL_H */
} vol_opt_name_t;
struct volinfo {
+ int retaincount;
+ int malloced;
+
char *v_name;
char *v_path;
int v_flags;
char *v_dbd_port;
};
+struct volinfo *allocvolinfo(char *path);
extern int loadvolinfo(char *path, struct volinfo *vol);
+extern void retainvolinfo(struct volinfo *vol);
+extern int closevolinfo(struct volinfo *vol);
extern int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_port);
extern int vol_load_charsets(struct volinfo *vol);
#define AFPVOL_CACHE (1 << 21) /* Use adouble v2 CNID caching. Default: yes */
#define AFPVOL_INV_DOTS (1 << 22) /* dots files are invisible */
-#define AFPVOL_TM (1 << 24) /* Supports TimeMachine */
-#define AFPVOL_ACLS (1 << 25) /* Volume supports ACLS */
-#define AFPVOL_CDROM (1 << 25) /* Ejectable media eg CD -> in memory CNID db */
+#define AFPVOL_TM (1 << 23) /* Supports TimeMachine */
+#define AFPVOL_ACLS (1 << 24) /* Volume supports ACLS */
+#define AFPVOL_SEARCHDB (1 << 25) /* Use fast CNID db search instead of filesystem */
+/* Found this in branch dir-rewrite, maybe we want to use it sometimes */
+#if 0
+#define AFPVOL_CDROM (1 << XX) /* Ejectable media eg CD -> in memory CNID db */
+#endif
/* Extended Attributes vfs indirection */
#define AFPVOL_EA_NONE 0 /* No EAs */
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
+#include <sys/time.h>
+#include <time.h>
#include <atalk/adouble.h>
#include <atalk/ea.h>
return 0;
}
+
+/*!
+ * Store n random bytes an buf
+ */
+void randombytes(void *buf, int n)
+{
+ char *p = (char *)buf;
+ int fd, i;
+ struct timeval tv;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) != -1) {
+ /* generate from /dev/urandom */
+ if (read(fd, buf, n) != n) {
+ close(fd);
+ fd = -1;
+ } else {
+ close(fd);
+ /* fd now != -1, so srandom wont be called below */
+ }
+ }
+
+ if (fd == -1) {
+ gettimeofday(&tv, NULL);
+ srandom((unsigned int)tv.tv_usec);
+ for (i=0 ; i < n ; i++)
+ p[i] = random() & 0xFF;
+ }
+
+ return;
+}
}
break;
case CNID_DBPATH:
- if ((vol->v_dbpath = strdup(value)) == NULL) {
- fprintf (stderr, "strdup: %s", strerror(errno));
- return -1;
- }
+ if ((vol->v_dbpath = malloc(MAXPATHLEN+1)) == NULL)
+ return -1;
+ strcpy(vol->v_dbpath, value);
break;
case ADOUBLE_VER:
if (strcasecmp(value, "v2") == 0) {
char volinfofile[MAXPATHLEN];
char buf[MAXPATHLEN];
struct flock lock;
- int fd;
+ int fd, len;
FILE *fp;
if ( !path || !vol)
return -1;
if ((vol->v_path = strdup(volinfofile)) == NULL ) {
- fprintf (stderr, "strdup: %s", strerror(errno));
+ fprintf (stderr, "strdup: %s", strerror(errno));
return (-1);
}
+ /* Remove trailing slashes */
+ len = strlen(vol->v_path);
+ while (len && (vol->v_path[len-1] == '/')) {
+ vol->v_path[len-1] = 0;
+ len--;
+ }
+
strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
if ((vol->v_flags & AFPVOL_INV_DOTS))
vol->v_ad_options |= ADVOL_INVDOTS;
+ vol->retaincount = 1;
+
fclose(fp);
return 0;
}
+/*!
+ * Allocate a struct volinfo object for refcounting usage with retain and close, and
+ * call loadvolinfo with it
+ */
+struct volinfo *allocvolinfo(char *path)
+{
+ struct volinfo *p = malloc(sizeof(struct volinfo));
+ if (p == NULL)
+ return NULL;
+
+ if (loadvolinfo(path, p) == -1)
+ return NULL;
+
+ p->malloced = 1;
+
+ return p;
+}
+
+void retainvolinfo(struct volinfo *vol)
+{
+ vol->retaincount++;
+}
+
+/*!
+ * Decrement retain count, free resources when retaincount reaches 0
+ */
+int closevolinfo(struct volinfo *volinfo)
+{
+ if (volinfo->retaincount <= 0)
+ abort();
+
+ volinfo->retaincount--;
+
+ if (volinfo->retaincount == 0) {
+ free(volinfo->v_name); volinfo->v_name = NULL;
+ free(volinfo->v_path); volinfo->v_path = NULL;
+ free(volinfo->v_cnidscheme); volinfo->v_cnidscheme = NULL;
+ free(volinfo->v_dbpath); volinfo->v_dbpath = NULL;
+ free(volinfo->v_volcodepage); volinfo->v_volcodepage = NULL;
+ free(volinfo->v_maccodepage); volinfo->v_maccodepage = NULL;
+ free(volinfo->v_dbd_host); volinfo->v_dbd_host = NULL;
+ free(volinfo->v_dbd_port); volinfo->v_dbd_port = NULL;
+ if (volinfo->malloced) {
+ volinfo->malloced = 0;
+ free(volinfo);
+ }
+ }
+
+ return 0;
+}
+
/*
* Save the volume options to a file, used by shell utilities. Writing the file
* everytime a volume is opened is unnecessary, but it shouldn't hurt much.
.\" Title: AppleVolumes.default
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 22 Apr 2010
+.\" Date: 07 Dec 2010
.\" Manual: Netatalk 2.2
.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "APPLEVOLUMES\&.DEFAU" "5" "22 Apr 2010" "Netatalk 2.2" "Netatalk 2.2"
+.TH "APPLEVOLUMES\&.DEFAU" "5" "07 Dec 2010" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.RS 4
This allows multiple options to be specified in a comma delimited format\&. The available options are:
.PP
+searchdb
+.RS 4
+Use fast CNID database namesearch instead of slow recursive filesystem search\&. Relies on a consistent CNID database, ie Samba or local filesystem access lead to inaccurate or wrong results\&. Works only for "dbd" CNID db volumes\&.
+.RE
+.PP
tm
.RS 4
Enable Time Machine suport for this volume\&.
.\" Title: cnid_dbd
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 21 Mar 2009
-.\" Manual: Netatalk 2.1
-.\" Source: Netatalk 2.1
+.\" Date: 10 Dec 2010
+.\" Manual: Netatalk 2.2
+.\" Source: Netatalk 2.2
.\" Language: English
.\"
-.TH "CNID_DBD" "8" "21 Mar 2009" "Netatalk 2.1" "Netatalk 2.1"
+.TH "CNID_DBD" "8" "10 Dec 2010" "Netatalk 2.2" "Netatalk 2.2"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
cnid_dbd \- implement access to CNID databases through a dedicated daemon process
.SH "SYNOPSIS"
.HP \w'\fBcnid_dbd\fR\fB\fR\fB\fR\fB\fR\ 'u
-\fBcnid_dbd\fR\fB\fR\fB\fR\fB\fR \fIdbdir\fR \fIctrlfd\fR \fIclntfd\fR \fIlogconfig_string\fR
+\fBcnid_dbd\fR\fB\fR\fB\fR\fB\fR \fIvolpath\fR \fIctrlfd\fR \fIclntfd\fR \fIlogconfig_string\fR
.SH "DESCRIPTION"
.PP
\fBcnid_dbd\fR
\fBcnid_dbd\fR
is never started via the command line or system startup scripts but only by the
\fBcnid_metad\fR
-daemon\&. There is at most one instance of
+daemon\&. There is one instance of
\fBcnid_dbd\fR
per netatalk volume\&.
.PP
backend with transactions will avoid corruption of the CNID database even if the system crashes unexpectedly\&.
.PP
\fBcnid_dbd\fR
-uses the same on\-disk database format as the
-\fBcdb\fR
-backend\&. It is therefore possible to switch between the two backends as necessary\&.
-.PP
-\fBcnid_dbd\fR
inherits the effective userid and groupid from
\fBcnid_metad\fR
on startup, which is normally caused by
\fBlogfile_autoremove\fR
option is specified in the
\fIdb_param\fR
-configuration file (see below)\&.
+configuration file (see below) with a value of 0 (default 1)\&.
.PP
Do not use
\fBcnid_dbd\fR
.RE
.SH "UPDATING"
.PP
-In order to update between Netatalk releases using different BerkeleyDB library versions, follow this steps:
+Note that the first version to appear
+\fIafter\fR
+Netatalk 2\&.1 ie Netatalk 2\&.1\&.1, will support BerkeleyDB updates on the fly without manual intervention\&. In other words Netatalk 2\&.1 does contain code to prepare the BerkeleyDB database for upgrades and to upgrade it in case it has been prepared before\&. That means it can\'t upgrade a 2\&.0\&.x version because that one didn\'t prepare the database\&.
+.PP
+In order to update between older Netatalk releases using different BerkeleyDB library versions, follow this steps:
.sp
.RS 4
.ie n \{\
.\}
Start the the new version of Netatalk
.RE
-.PP
-Note that the first version to appear
-\fIafter\fR
-Netatalk 2\&.1 ie Netatalk 2\&.1\&.1, will support BerkeleyDB updates on the fly without manual intervention\&. In other words Netatalk 2\&.1 does contain code to prepare the BerkeleyDB database for upgrades and to upgrade it in case it has been prepared before\&. That means it can\'t upgrade a 2\&.0\&.x version because that one didn\'t prepare the database\&.
.SH "SEE ALSO"
.PP
\fBcnid_metad\fR(8),