From 4913dbbc5b69642dacbe7302fc25d25f47e9c00c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 7 Dec 2012 18:33:32 +0100 Subject: [PATCH] Rewrite dbd to use CNID IPC instead of opening the db directly In order to fix buf #447 (race condition between dbd and cnid_dbd) dbd must be converted to work over the network IPC channel with cnid_dbd instead of directly working on the BerkeleyDB CNID database. Add CNID db IPC command for wiping the db --- etc/cnid_dbd/cmd_dbd.c | 347 +++++++----------------- etc/cnid_dbd/cmd_dbd.h | 19 +- etc/cnid_dbd/cmd_dbd_scanvol.c | 433 +++++------------------------- etc/cnid_dbd/main.c | 93 +++++-- include/atalk/cnid.h | 2 + include/atalk/cnid_dbd_private.h | 1 + libatalk/cnid/cdb/cnid_cdb_open.c | 2 +- libatalk/cnid/cnid.c | 12 + libatalk/cnid/dbd/cnid_dbd.c | 53 +++- libatalk/cnid/dbd/cnid_dbd.h | 2 +- libatalk/cnid/last/cnid_last.c | 3 +- libatalk/cnid/tdb/cnid_tdb_open.c | 3 +- 12 files changed, 307 insertions(+), 663 deletions(-) diff --git a/etc/cnid_dbd/cmd_dbd.c b/etc/cnid_dbd/cmd_dbd.c index eb53af79..8a12bfad 100644 --- a/etc/cnid_dbd/cmd_dbd.c +++ b/etc/cnid_dbd/cmd_dbd.c @@ -27,65 +27,29 @@ #include #include -#include #include #include #include +#include #include "cmd_dbd.h" -#include "dbd.h" -#include "dbif.h" -#include "db_param.h" -#include "pack.h" -#define DBOPTIONS (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN) +enum dbd_cmd {dbd_scan, dbd_rebuild}; -int nocniddb = 0; /* Dont open CNID database, only scan filesystem */ +/* Global variables */ volatile sig_atomic_t alarmed; /* flags for signals */ -int db_locked; /* have we got the fcntl lock on lockfile ? */ - -static DBD *dbd; -static int verbose; /* Logging flag */ -static int exclusive; /* Exclusive volume access */ -static struct db_param db_param = { - NULL, /* Volume dirpath */ - 1, /* bdb logfile autoremove */ - 64 * 1024, /* bdb cachesize (64 MB) */ - DEFAULT_MAXLOCKS, /* maxlocks */ - DEFAULT_MAXLOCKOBJS, /* maxlockobjs */ - 0, /* flush_interval */ - 0, /* flush_frequency */ - 0, /* usock_file */ - -1, /* fd_table_size */ - -1, /* idle_timeout */ - -1 /* max_vols */ -}; -static char dbpath[MAXPATHLEN+1]; /* Path to the dbd database */ -/* - Provide some logging - */ -void dbd_log(enum logtype lt, char *fmt, ...) -{ - int len; - static char logbuffer[1024]; - va_list args; +/* Local variables */ +static dbd_flags_t flags; - if ( (lt == LOGSTD) || (verbose == 1)) { - va_start(args, fmt); - len = vsnprintf(logbuffer, 1023, fmt, args); - va_end(args); - logbuffer[1023] = 0; +/*************************************************************************** + * Local functions + ***************************************************************************/ - printf("%s\n", logbuffer); - } -} - -/* - SIGNAL handling: - catch SIGINT and SIGTERM which cause clean exit. Ignore anything else. +/* + * SIGNAL handling: + * catch SIGINT and SIGTERM which cause clean exit. Ignore anything else. */ - static void sig_handler(int signo) { alarmed = 1; @@ -128,99 +92,75 @@ static void set_signal(void) static void usage (void) { - printf("dbd (Netatalk %s)\n" - "Usage: dbd [-CeFtvx] -d [-i] | -s [-c|-n]| -r [-c|-f] | -u \n" - "dbd can dump, scan, reindex and rebuild Netatalk dbd CNID databases.\n" - "dbd must be run with appropiate permissions i.e. as root.\n\n" - "Main commands are:\n" - " -d Dump CNID database\n" - " Option: -i dump indexes too\n\n" + printf("Usage: dbd [-cfFstvV] \n" + "dbd scans or reindex Netatalk CNID databases of AFP volumes.\n" + "dbd must be run with appropiate permissions i.e. as root.\n" + "By default dbd rebuilds the CNID database of the volume.\n\n" + "Options:\n" " -s Scan volume:\n" - " Options: -c Don't check .AppleDouble stuff, only ckeck orphaned.\n" - " -n Don't open CNID database, skip CNID checks.\n\n" - " -r Rebuild volume:\n" - " Options: -c Don't create .AppleDouble stuff, only cleanup orphaned.\n" - " -f wipe database and rebuild from IDs stored in AppleDouble\n" - " metadata file or EA. Implies -e.\n\n" - " -u Upgrade:\n" - " Opens the database which triggers any necessary upgrades,\n" - " then closes and exits.\n\n" - "General options:\n" - " -C convert from adouble:v2 to adouble:ea (use with -r)\n" + " -c convert from adouble:v2 to adouble:ea (use with -r)\n" " -F location of the afp.conf config file\n" - " -e only work on inactive volumes and lock them (exclusive)\n" - " -x rebuild indexes (just for completeness, mostly useless!)\n" + " -f delete and recreate CNID database\n" " -t show statistics while running\n" - " -v verbose\n\n" - , VERSION + " -v verbose\n" + " -V show version info\n\n" ); } -int main(int argc, char **argv) +/*************************************************************************** + * Global functions + ***************************************************************************/ + +void dbd_log(enum logtype lt, char *fmt, ...) { - int c, lockfd, ret = -1; - int dump=0, scan=0, rebuild=0, prep_upgrade=0, rebuildindexes=0, dumpindexes=0, force=0; - dbd_flags_t flags = 0; - char *volpath; - int cdir; - AFPObj obj = { 0 }; - struct vol *vol; + int len; + static char logbuffer[1024]; + va_list args; - if (geteuid() != 0) { - usage(); - exit(EXIT_FAILURE); + if ( (lt == LOGSTD) || (flags & DBD_FLAGS_VERBOSE)) { + va_start(args, fmt); + len = vsnprintf(logbuffer, 1023, fmt, args); + va_end(args); + logbuffer[1023] = 0; + + printf("%s\n", logbuffer); } - /* Inhereting perms in ad_mkdir etc requires this */ - ad_setfuid(0); +} + +int main(int argc, char **argv) +{ + EC_INIT; + int dbd_cmd = dbd_rebuild; + int cdir = -1; + AFPObj obj = { 0 }; + struct vol *vol = NULL; + const char *volpath = NULL; - while ((c = getopt(argc, argv, ":cCdefFinrstuvx")) != -1) { + int c; + while ((c = getopt(argc, argv, ":cfF:stvV")) != -1) { switch(c) { case 'c': - flags |= DBD_FLAGS_CLEANUP; - break; - case 'C': flags |= DBD_FLAGS_V2TOEA; break; - case 'd': - dump = 1; + case 'f': + flags |= DBD_FLAGS_FORCE; break; - case 'i': - dumpindexes = 1; + case 'F': + obj.cmdlineconfigfile = strdup(optarg); break; case 's': - scan = 1; + dbd_cmd = dbd_scan; flags |= DBD_FLAGS_SCAN; break; - case 'n': - nocniddb = 1; /* FIXME: this could/should be a flag too for consistency */ - break; - case 'r': - rebuild = 1; - break; case 't': flags |= DBD_FLAGS_STATS; break; - case 'u': - prep_upgrade = 1; - break; case 'v': - verbose = 1; - break; - case 'e': - exclusive = 1; - flags |= DBD_FLAGS_EXCL; - break; - case 'x': - rebuildindexes = 1; - break; - case 'f': - force = 1; - exclusive = 1; - flags |= DBD_FLAGS_FORCE | DBD_FLAGS_EXCL; - break; - case 'F': - obj.cmdlineconfigfile = strdup(optarg); + flags |= DBD_FLAGS_VERBOSE; break; + case 'V': + printf("dbd %s\n", VERSION); + exit(0); case ':': case '?': usage(); @@ -229,16 +169,18 @@ int main(int argc, char **argv) } } - if ((dump + scan + rebuild + prep_upgrade) != 1) { + if ( (optind + 1) != argc ) { usage(); exit(EXIT_FAILURE); } + volpath = argv[optind]; - if ( (optind + 1) != argc ) { + if (geteuid() != 0) { usage(); exit(EXIT_FAILURE); } - volpath = argv[optind]; + /* Inhereting perms in ad_mkdir etc requires this */ + ad_setfuid(0); setvbuf(stdout, (char *) NULL, _IONBF, 0); @@ -257,11 +199,14 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + /* Initialize CNID subsystem */ + cnid_init(); + /* Setup logging. Should be portable among *NIXes */ - if (!verbose) - setuplog("default:info", "/dev/tty"); + if (flags & DBD_FLAGS_VERBOSE) + setuplog("default:note, cnid:debug", "/dev/tty"); else - setuplog("default:debug", "/dev/tty"); + setuplog("default:note", "/dev/tty"); if (load_volumes(&obj) != 0) { dbd_log( LOGSTD, "Couldn't load volumes"); @@ -278,7 +223,20 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - pack_setvol(vol); + /* open volume */ + if (STRCMP(vol->v_cnidscheme, != , "dbd")) { + dbd_log(LOGSTD, "\"%s\" isn't a \"dbd\" CNID volume", vol->v_path); + exit(EXIT_FAILURE); + } + if ((vol->v_cdb = cnid_open(vol->v_path, + 0000, + "dbd", + flags, + vol->v_cnidserver, + vol->v_cnidport)) == NULL) { + dbd_log(LOGSTD, "Cant initialize CNID database connection for %s", vol->v_path); + exit(EXIT_FAILURE); + } if (vol->v_adouble == AD_VERSION_EA) dbd_log( LOGDEBUG, "adouble:ea volume"); @@ -301,145 +259,28 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - /* Enuser dbpath is there, create if necessary */ - struct stat st; - if (stat(vol->v_dbpath, &st) != 0) { - if (errno != ENOENT) { - dbd_log( LOGSTD, "Can't stat dbpath \"%s\": %s", vol->v_dbpath, strerror(errno)); - exit(EXIT_FAILURE); - } - if ((mkdir(vol->v_dbpath, 0755)) != 0) { - dbd_log( LOGSTD, "Can't create dbpath \"%s\": %s", vol->v_dbpath, strerror(errno)); - exit(EXIT_FAILURE); - } - } - - /* Put "/.AppleDB" at end of volpath, get path from volinfo file */ - if ( (strlen(vol->v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) { - dbd_log( LOGSTD, "Volume pathname too long"); - exit(EXIT_FAILURE); - } - strncpy(dbpath, vol->v_dbpath, MAXPATHLEN - strlen("/.AppleDB")); - strcat(dbpath, "/.AppleDB"); - - /* Check or create dbpath */ - int dbdirfd = open(dbpath, O_RDONLY); - if (dbdirfd == -1 && errno == ENOENT) { - if (errno == ENOENT) { - if ((mkdir(dbpath, 0755)) != 0) { - dbd_log( LOGSTD, "Can't create .AppleDB for \"%s\": %s", dbpath, strerror(errno)); - exit(EXIT_FAILURE); - } - } else { - dbd_log( LOGSTD, "Somethings wrong with .AppleDB for \"%s\", giving up: %s", dbpath, strerror(errno)); - exit(EXIT_FAILURE); - } - } else { - close(dbdirfd); - } - - /* Get db lock */ - if ((db_locked = get_lock(LOCK_EXCL, dbpath)) == -1) - goto exit_noenv; - if (db_locked != LOCK_EXCL) { - dbd_log(LOGDEBUG, "Database is in use, acquiring shared lock"); - /* Couldn't get exclusive lock, try shared lock if -e wasn't requested */ - if (exclusive) { - dbd_log(LOGSTD, "Database is in use and exlusive was requested"); - goto exit_noenv; - } - if ((db_locked = get_lock(LOCK_SHRD, NULL)) != LOCK_SHRD) - goto exit_noenv; - } - - /* Check if -f is requested and wipe db if yes */ - if ((flags & DBD_FLAGS_FORCE) && rebuild) { - char cmd[8 + MAXPATHLEN]; - if ((db_locked = get_lock(LOCK_FREE, NULL)) != 0) - goto exit_noenv; - - 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."); - if ((db_locked = get_lock(LOCK_EXCL, dbpath)) == -1) - goto exit_noenv; - } - - /* - Lets start with the BerkeleyDB stuff - */ - if ( ! nocniddb) { - if ((dbd = dbif_init(dbpath, "cnid2.db")) == NULL) - goto exit_noenv; - - if (dbif_env_open(dbd, - &db_param, - (db_locked == LOCK_EXCL) ? (DBOPTIONS | DB_RECOVER) : DBOPTIONS) < 0) { - dbd_log( LOGSTD, "error opening database!"); - goto exit_noenv; - } - - if (db_locked == LOCK_EXCL) - dbd_log( LOGDEBUG, "Finished recovery."); - - if (dbif_open(dbd, NULL, rebuildindexes) < 0) { - dbif_close(dbd); - goto exit_failure; - } - - /* Prepare upgrade ? We're done */ - if (prep_upgrade) { - (void)dbif_txn_close(dbd, 1); - goto cleanup; + if (flags & DBD_FLAGS_FORCE) { + if (cnid_wipe(vol->v_cdb) != 0) { + dbd_log( LOGSTD, "Failed to wipe CNID db"); + EC_FAIL; } } - /* Downgrade db lock if not running exclusive */ - if (!exclusive && (db_locked == LOCK_EXCL)) { - if (get_lock(LOCK_UNLOCK, NULL) != 0) - goto exit_failure; - if (get_lock(LOCK_SHRD, NULL) != LOCK_SHRD) - goto exit_failure; - } - /* Now execute given command scan|rebuild|dump */ - if (dump && ! nocniddb) { - if (dbif_dump(dbd, dumpindexes) < 0) { - dbd_log( LOGSTD, "Error dumping database"); - } - } else if ((rebuild && ! nocniddb) || scan) { - if (cmd_dbd_scanvol(dbd, vol, flags) < 0) { + switch (dbd_cmd) { + case dbd_scan: + case dbd_rebuild: + if (cmd_dbd_scanvol(vol, flags) < 0) { dbd_log( LOGSTD, "Error repairing database."); } + break; } -cleanup: - /* Cleanup */ - dbd_log(LOGDEBUG, "Closing db"); - if (! nocniddb) { - if (dbif_close(dbd) < 0) { - dbd_log( LOGSTD, "Error closing database"); - goto exit_failure; - } - } - -exit_success: - ret = 0; - -exit_failure: - if (dbif_env_remove(dbpath) < 0) { - dbd_log( LOGSTD, "Error removing BerkeleyDB database environment"); - ret++; - } - get_lock(0, NULL); +EC_CLEANUP: + if (vol) + cnid_close(vol->v_cdb); -exit_noenv: - if ((fchdir(cdir)) < 0) + if (cdir != -1 && (fchdir(cdir) < 0)) dbd_log(LOGSTD, "fchdir: %s", strerror(errno)); if (ret == 0) diff --git a/etc/cnid_dbd/cmd_dbd.h b/etc/cnid_dbd/cmd_dbd.h index efec636b..9fcb3f4e 100644 --- a/etc/cnid_dbd/cmd_dbd.h +++ b/etc/cnid_dbd/cmd_dbd.h @@ -12,29 +12,18 @@ typedef unsigned int dbd_flags_t; #define DBD_FLAGS_SCAN (1 << 0) #define DBD_FLAGS_FORCE (1 << 1) -#define DBD_FLAGS_EXCL (1 << 2) -#define DBD_FLAGS_CLEANUP (1 << 3) /* Dont create AD stuff, but cleanup orphaned */ -#define DBD_FLAGS_STATS (1 << 4) -#define DBD_FLAGS_V2TOEA (1 << 5) /* Convert adouble:v2 to adouble:ea */ +#define DBD_FLAGS_STATS (1 << 2) +#define DBD_FLAGS_V2TOEA (1 << 3) /* Convert adouble:v2 to adouble:ea */ +#define DBD_FLAGS_VERBOSE (1 << 4) #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 int nocniddb; /* Dont open CNID database, only scan filesystem */ -extern int db_locked; /* have we got the fcntl lock on lockfd ? */ extern volatile sig_atomic_t alarmed; extern void dbd_log(enum logtype lt, char *fmt, ...); -extern int cmd_dbd_scanvol(DBD *dbd, struct vol *vol, dbd_flags_t flags); +extern int cmd_dbd_scanvol(struct vol *vol, dbd_flags_t flags); -/* - Functions for querying the database which couldn't be reused from the existing - funcs pool of dbd_* for one reason or another -*/ -extern int cmd_dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply); #endif /* CMD_DBD_H */ diff --git a/etc/cnid_dbd/cmd_dbd_scanvol.c b/etc/cnid_dbd/cmd_dbd_scanvol.c index dcbd4c74..37012f27 100644 --- a/etc/cnid_dbd/cmd_dbd_scanvol.c +++ b/etc/cnid_dbd/cmd_dbd_scanvol.c @@ -29,12 +29,13 @@ #include #include #include -#include +//#include #include #include #include #include #include +#include #include "cmd_dbd.h" #include "dbif.h" @@ -48,7 +49,7 @@ static struct vol *myvol; static char cwdbuf[MAXPATHLEN+1]; -static DBD *dbd; +static struct vol *vol; static DBD *dbd_rebuild; static dbd_flags_t dbd_flags; static char stamp[CNID_DEV_LEN]; @@ -65,6 +66,7 @@ static struct cnid_dbd_rqst rqst; static struct cnid_dbd_rply rply; static jmp_buf jmp; static char pname[MAXPATHLEN] = "../"; +static char cnidResBuf[12 + MAXPATHLEN + 1]; /* Taken form afpd/desktop.c @@ -189,43 +191,13 @@ static int update_cnid(cnid_t did, const struct stat *sp, const char *oldname, c int ret; cnid_t id; - /* Prepare request data */ - memset(&rqst, 0, sizeof(struct cnid_dbd_rqst)); - memset(&rply, 0, sizeof(struct cnid_dbd_rply)); - rqst.did = did; - rqst.cnid = 0; - if ( ! (myvol->v_flags & AFPVOL_NODEV)) - rqst.dev = sp->st_dev; - rqst.ino = sp->st_ino; - rqst.type = S_ISDIR(sp->st_mode) ? 1 : 0; - rqst.name = (char *)oldname; - rqst.namelen = strlen(oldname); - /* Query the database */ - ret = dbd_lookup(dbd, &rqst, &rply, (dbd_flags & DBD_FLAGS_SCAN) ? 1 : 0); - if (dbif_txn_close(dbd, ret) != 0) - return -1; - if (rply.result != CNID_DBD_RES_OK) + if ((id = cnid_lookup(vol->v_cdb, sp, did, (char *)oldname, strlen(oldname))) == CNID_INVALID) + /* not in db, no need to update */ return 0; - id = rply.cnid; - - /* Prepare request data */ - memset(&rqst, 0, sizeof(struct cnid_dbd_rqst)); - memset(&rply, 0, sizeof(struct cnid_dbd_rply)); - rqst.did = did; - rqst.cnid = id; - if ( ! (myvol->v_flags & AFPVOL_NODEV)) - rqst.dev = sp->st_dev; - rqst.ino = sp->st_ino; - rqst.type = S_ISDIR(sp->st_mode) ? 1 : 0; - rqst.name = (char *)newname; - rqst.namelen = strlen(newname); /* Update the database */ - ret = dbd_update(dbd, &rqst, &rply); - if (dbif_txn_close(dbd, ret) != 0) - return -1; - if (rply.result != CNID_DBD_RES_OK) + if (cnid_update(vol->v_cdb, id, sp, did, (char *)newname, strlen(newname)) < 0) return -1; return 0; @@ -258,9 +230,6 @@ static int check_adfile(const char *fname, const struct stat *st, const char **n return 0; } - if (dbd_flags & DBD_FLAGS_CLEANUP) - return 0; - if (S_ISDIR(st->st_mode)) adflags |= ADFLAGS_DIR; @@ -422,9 +391,6 @@ static int check_addir(int volroot) struct adouble ad; char *mname = NULL; - if (dbd_flags & DBD_FLAGS_CLEANUP) - return 0; - if (myvol->v_adouble == AD_VERSION_EA) return 0; @@ -644,31 +610,17 @@ static int read_addir(void) static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfile_ok) { int ret, adflags = ADFLAGS_HF; - cnid_t db_cnid, ad_cnid; + cnid_t db_cnid, ad_cnid, tmpid; struct adouble ad; adflags = ADFLAGS_HF | (S_ISDIR(st->st_mode) ? ADFLAGS_DIR : 0); - /* Force checkout every X items */ - static int cnidcount = 0; - cnidcount++; - if (cnidcount > 10000) { - cnidcount = 0; - if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0) { - dbd_log(LOGSTD, "Error checkpointing!"); - return CNID_INVALID; - } - } - /* Get CNID from ad-file */ - ad_cnid = 0; + ad_cnid = CNID_INVALID; if (ADFILE_OK) { ad_init(&ad, myvol); if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { - if (dbd_flags & DBD_FLAGS_CLEANUP) - return CNID_INVALID; - if (myvol->v_adouble != AD_VERSION_EA) { dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", cwdbuf, name, strerror(errno)); return CNID_INVALID; @@ -676,7 +628,6 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi dbd_log( LOGDEBUG, "File without meta EA: \"%s/%s\"", cwdbuf, name); adfile_ok = 1; } else { - if (dbd_flags & DBD_FLAGS_FORCE) { ad_cnid = ad_forcegetid(&ad); /* This ensures the changed stamp is written */ @@ -694,128 +645,26 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi } /* Get CNID from database */ - - /* Prepare request data */ - memset(&rqst, 0, sizeof(struct cnid_dbd_rqst)); - memset(&rply, 0, sizeof(struct cnid_dbd_rply)); - rqst.did = did; - rqst.cnid = ad_cnid; - if ( ! (myvol->v_flags & AFPVOL_NODEV)) - rqst.dev = st->st_dev; - rqst.ino = st->st_ino; - rqst.type = S_ISDIR(st->st_mode)?1:0; - rqst.name = (char *)name; - rqst.namelen = strlen(name); - - /* Query the database */ - ret = dbd_lookup(dbd, &rqst, &rply, (dbd_flags & DBD_FLAGS_SCAN) ? 1 : 0); - if (dbif_txn_close(dbd, ret) != 0) + if ((db_cnid = cnid_add(vol->v_cdb, st, did, (char *)name, strlen(name), ad_cnid)) == CNID_INVALID) return CNID_INVALID; - if (rply.result == CNID_DBD_RES_OK) { - db_cnid = rply.cnid; - } else if (rply.result == CNID_DBD_RES_NOTFOUND) { - if ( ! (dbd_flags & DBD_FLAGS_FORCE)) - dbd_log( LOGSTD, "No CNID for '%s/%s' in database", cwdbuf, name); - db_cnid = 0; - } else { - dbd_log( LOGSTD, "Fatal error resolving '%s/%s'", cwdbuf, name); - db_cnid = 0; - } - /* Compare results from both CNID searches */ - if (ad_cnid && db_cnid && (ad_cnid == db_cnid)) { - /* Everything is fine */ - return db_cnid; - } else if (ad_cnid && db_cnid && (ad_cnid != db_cnid)) { + /* Compare CNID from db and adouble file */ + if (ad_cnid != db_cnid && adfile_ok == 0) { /* Mismatch, overwrite ad file with value from db */ - dbd_log( LOGSTD, "CNID mismatch for '%s/%s', db: %u, ad-file: %u", cwdbuf, name, ntohl(db_cnid), ntohl(ad_cnid)); - if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - dbd_log(LOGSTD, "Updating AppleDouble file for '%s/%s' with CNID: %u from database", - cwdbuf, name, ntohl(db_cnid)); - ad_init(&ad, myvol); - if (ad_open(&ad, name, adflags | ADFLAGS_HF | ADFLAGS_RDWR) != 0) { - dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", - cwdbuf, name, strerror(errno)); - return CNID_INVALID; - } - ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); - ad_flush(&ad); - ad_close(&ad, ADFLAGS_HF); - } - return db_cnid; - } else if (ad_cnid && (db_cnid == 0)) { - /* in ad-file but not in db */ - if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - /* Ensure the cnid from the ad-file is not already occupied by another file */ - dbd_log(LOGDEBUG, "Checking whether CNID %u from ad-file is occupied", - ntohl(ad_cnid)); - - rqst.cnid = ad_cnid; - ret = dbd_resolve(dbd, &rqst, &rply); - if (rply.result == CNID_DBD_RES_OK) { - /* Occupied! Choose another, update ad-file */ - ret = dbd_add(dbd, &rqst, &rply, 1); - if (dbif_txn_close(dbd, ret) != 0) - return CNID_INVALID; - db_cnid = rply.cnid; - dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); - - if (ADFILE_OK && ( ! (dbd_flags & DBD_FLAGS_SCAN))) { - dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", - cwdbuf, name, ntohl(db_cnid)); - ad_init(&ad, myvol); - if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { - dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", - cwdbuf, name, strerror(errno)); - return CNID_INVALID; - } - ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); - ad_flush(&ad); - ad_close(&ad, ADFLAGS_HF); - } - return db_cnid; - } - - dbd_log(LOGDEBUG, "CNID rebuild add '%s/%s' with CNID from ad-file %u", - cwdbuf, name, ntohl(ad_cnid)); - rqst.cnid = ad_cnid; - ret = dbd_rebuild_add(dbd, &rqst, &rply); - if (dbif_txn_close(dbd, ret) != 0) - return CNID_INVALID; - } - return ad_cnid; - } else if ((db_cnid == 0) && (ad_cnid == 0)) { - /* No CNID at all, we clearly have to allocate a fresh one... */ - /* Note: the next test will use this new CNID too! */ - if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - /* add to db */ - ret = dbd_add(dbd, &rqst, &rply, 1); - if (dbif_txn_close(dbd, ret) != 0) - return CNID_INVALID; - db_cnid = rply.cnid; - dbd_log(LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); - } - } - - if ((ad_cnid == 0) && db_cnid) { - /* in db but zeroID in ad-file, write it to ad-file */ - if (ADFILE_OK && ! (dbd_flags & DBD_FLAGS_SCAN)) { - dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file", - cwdbuf, name, ntohl(db_cnid)); - ad_init(&ad, myvol); - if (ad_open(&ad, name, adflags | ADFLAGS_RDWR) != 0) { - dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", - cwdbuf, name, strerror(errno)); - return CNID_INVALID; - } - ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); - ad_flush(&ad); - ad_close(&ad, ADFLAGS_HF); + dbd_log(LOGSTD, "CNID mismatch for '%s/%s', CNID db: %u, ad-file: %u", + cwdbuf, name, ntohl(db_cnid), ntohl(ad_cnid)); + ad_init(&ad, myvol); + if (ad_open(&ad, name, adflags | ADFLAGS_HF | ADFLAGS_RDWR) != 0) { + dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s", + cwdbuf, name, strerror(errno)); + return CNID_INVALID; } - return db_cnid; + ad_setid( &ad, st->st_dev, st->st_ino, db_cnid, did, stamp); + ad_flush(&ad); + ad_close(&ad, ADFLAGS_HF); } - return CNID_INVALID; + return db_cnid; } /* @@ -939,30 +788,28 @@ static int dbd_readdir(int volroot, cnid_t did) update_cnid(did, &st, ep->d_name, name); } - if ( ! nocniddb) { - /* Check CNIDs */ - cnid = check_cnid(name, did, &st, adfile_ok); + /* Check CNIDs */ + cnid = check_cnid(name, did, &st, adfile_ok); - /* Now add this object to our rebuild dbd */ - if (cnid && dbd_rebuild) { - static uint count = 0; - rqst.cnid = rply.cnid; - ret = dbd_rebuild_add(dbd_rebuild, &rqst, &rply); - if (dbif_txn_close(dbd_rebuild, ret) != 0) - return -1; - if (rply.result != CNID_DBD_RES_OK) { - dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db", - cnid, cwdbuf, name); + /* Now add this object to our rebuild dbd */ + if (cnid && dbd_rebuild) { + static uint count = 0; + rqst.cnid = rply.cnid; + ret = dbd_rebuild_add(dbd_rebuild, &rqst, &rply); + if (dbif_txn_close(dbd_rebuild, ret) != 0) + return -1; + if (rply.result != CNID_DBD_RES_OK) { + dbd_log( LOGSTD, "Fatal error adding CNID: %u for '%s/%s' to in-memory rebuild-db", + cnid, cwdbuf, name); + return -1; + } + count++; + if (count == 10000) { + if (dbif_txn_checkpoint(dbd_rebuild, 0, 0, 0) < 0) { + dbd_log(LOGSTD, "Error checkpointing!"); return -1; } - count++; - if (count == 10000) { - if (dbif_txn_checkpoint(dbd_rebuild, 0, 0, 0) < 0) { - dbd_log(LOGSTD, "Error checkpointing!"); - return -1; - } - count = 0; - } + count = 0; } } @@ -973,7 +820,7 @@ static int dbd_readdir(int volroot, cnid_t did) /************************************************************************** Recursion **************************************************************************/ - if (S_ISDIR(st.st_mode) && (cnid || nocniddb)) { /* If we have no cnid for it we cant recur */ + if (S_ISDIR(st.st_mode) && cnid) { /* If we have no cnid for it we cant enter recursion */ strcat(cwdbuf, "/"); strcat(cwdbuf, name); dbd_log( LOGDEBUG, "Entering directory: %s", cwdbuf); @@ -1050,174 +897,39 @@ static int scanvol(struct vol *vol, dbd_flags_t flags) return 0; } -/* - Remove all CNIDs from dbd that are not in dbd_rebuild -*/ -static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) -{ - int ret = 0, deleted = 0; - cnid_t dbd_cnid = 0, rebuild_cnid = 0; - struct cnid_dbd_rqst rqst; - struct cnid_dbd_rply rply; - - /* jump over rootinfo key */ - if ( dbif_idwalk(dbd, &dbd_cnid, 0) != 1) - return; - if ( dbif_idwalk(dbd_rebuild, &rebuild_cnid, 0) != 1) - return; - - /* Get first id from dbd_rebuild */ - if ((dbif_idwalk(dbd_rebuild, &rebuild_cnid, 0)) == -1) - return; - - /* Start main loop through dbd: get CNID from dbd */ - while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) { - /* Check if we got a termination signal */ - if (alarmed) - longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ - - if (deleted > 1000) { - deleted = 0; - if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0) { - dbd_log(LOGSTD, "Error checkpointing!"); - goto cleanup; - } - } - - /* This should be the normal case: CNID is in both dbs */ - if (dbd_cnid == rebuild_cnid) { - /* Get next CNID from rebuild db */ - if ((ret = dbif_idwalk(dbd_rebuild, &rebuild_cnid, 0)) == -1) { - /* Some error */ - goto cleanup; - } else if (ret == 0) { - /* end of rebuild_cnid, delete all remaining CNIDs from dbd */ - while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) { - dbd_log(LOGSTD, "Orphaned CNID in database: %u", dbd_cnid); - if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - rqst.cnid = htonl(dbd_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; - } - - if (dbif_txn_close(dbd, ret) != 0) - return; - deleted++; - } - /* Check if we got a termination signal */ - if (alarmed) - longjmp(jmp, 1); /* this jumps back to cmd_dbd_scanvol() */ - } - return; - } else - /* Normal case (ret=1): continue while loop */ - continue; - } - - if (dbd_cnid < rebuild_cnid) { - /* CNID is orphaned -> delete */ - dbd_log(LOGSTD, "One orphaned CNID in database: %u.", dbd_cnid); - if ( ! (dbd_flags & DBD_FLAGS_SCAN)) { - rqst.cnid = htonl(dbd_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; - } - if (dbif_txn_close(dbd, ret) != 0) - return; - deleted++; - } - continue; - } - - if (dbd_cnid > rebuild_cnid) { - dbif_idwalk(dbd, NULL, 1); /* Close cursor */ - dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */ - (void)dbif_txn_close(dbd, 2); - (void)dbif_txn_close(dbd_rebuild, 2); - dbd_log(LOGSTD, "Ghost CNID: %u. This is fatal! Dumping rebuild db:\n", rebuild_cnid); - dbif_dump(dbd_rebuild, 0); - dbd_log(LOGSTD, "Send this dump and a `dbd -d ...` dump to the Netatalk Dev team!"); - goto cleanup; - } - } /* while ((dbif_idwalk(dbd, &dbd_cnid, 0)) == 1) */ - -cleanup: - dbif_idwalk(dbd, NULL, 1); /* Close cursor */ - dbif_idwalk(dbd_rebuild, NULL, 1); /* Close cursor */ - return; -} - -static const char *get_tmpdb_path(void) -{ - pid_t pid = getpid(); - static char path[MAXPATHLEN]; - snprintf(path, MAXPATHLEN, "/tmp/tmpdb-dbd.%u", pid); - if (mkdir(path, 0755) != 0) - return NULL; - return path; -} - /* Main func called from cmd_dbd.c */ -int cmd_dbd_scanvol(DBD *dbd_ref, struct vol *vol, dbd_flags_t flags) +int cmd_dbd_scanvol(struct vol *vol_in, dbd_flags_t flags) { int ret = 0; - struct db_param db_param = { 0 }; - const char *tmpdb_path = NULL; - - /* Set cachesize for in-memory rebuild db */ - db_param.cachesize = 64 * 1024; /* 64 MB */ - db_param.maxlocks = DEFAULT_MAXLOCKS; - db_param.maxlockobjs = DEFAULT_MAXLOCKOBJS; - db_param.logfile_autoremove = 1; - /* Make it accessible for all funcs */ - dbd = dbd_ref; + /* Make vol accessible for all funcs */ + vol = vol_in; /* We only support unicode volumes ! */ if (vol->v_volcharset != CH_UTF8) { - dbd_log( LOGSTD, "Not a Unicode volume: %s, %u != %u", vol->v_volcodepage, vol->v_volcharset, CH_UTF8); + dbd_log(LOGSTD, "Not a Unicode volume: %s, %u != %u", vol->v_volcodepage, vol->v_volcharset, CH_UTF8); return -1; } - /* Get volume stamp */ - dbd_getstamp(dbd, &rqst, &rply); - if (rply.result != CNID_DBD_RES_OK) { - ret = -1; + /* + * Get CNID database stamp, cnid_getstamp() passes the buffer, + * then cnid_resolve() actually gets the value from the db + */ + cnid_getstamp(vol->v_cdb, stamp, sizeof(stamp)); + cnid_t rootid = 0; + if (cnid_resolve(vol->v_cdb, &rootid, cnidResBuf, sizeof(cnidResBuf)) == NULL) { + dbd_log(LOGSTD, "error resolving rootinfo key"); goto exit; } - memcpy(stamp, rply.name, CNID_DEV_LEN); - - /* temporary rebuild db, used with -re rebuild to delete unused CNIDs, not used with -f */ - if (! nocniddb && (flags & DBD_FLAGS_EXCL) && !(flags & DBD_FLAGS_FORCE)) { - tmpdb_path = get_tmpdb_path(); - if (NULL == (dbd_rebuild = dbif_init(tmpdb_path, "cnid2.db"))) { - ret = -1; - goto exit; - } - - if (dbif_env_open(dbd_rebuild, - &db_param, - DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN) < 0) { - dbd_log(LOGSTD, "error opening tmp database!"); - goto exit; - } - - if (0 != (dbif_open(dbd_rebuild, NULL, 0))) { - ret = -1; - goto exit; - } - if (0 != (dbif_copy_rootinfokey(dbd, dbd_rebuild))) { - ret = -1; - goto exit; - } +#if 0 + if (0 != (dbif_copy_rootinfokey(dbd, dbd_rebuild))) { + ret = -1; + goto exit; } +#endif if (setjmp(jmp) != 0) { ret = 0; /* Got signal, jump from dbd_readdir */ @@ -1231,30 +943,5 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct vol *vol, dbd_flags_t flags) } exit: - if (! nocniddb) { - if (dbif_txn_close(dbd, ret == 0 ? 1 : 0) != 0) - ret = -1; - if (dbd_rebuild) - if (dbif_txn_close(dbd_rebuild, ret == 0 ? 1 : 0) != 0) - ret = -1; - if ((ret == 0) && dbd_rebuild && (flags & DBD_FLAGS_EXCL) && !(flags & DBD_FLAGS_FORCE)) - /* We can only do this in exclusive mode, otherwise we might delete CNIDs added from - other clients in between our pass 1 and 2 */ - delete_orphaned_cnids(dbd, dbd_rebuild, flags); - } - - if (dbd_rebuild) { - dbd_log(LOGDEBUG, "Closing tmp db"); - dbif_close(dbd_rebuild); - - if (tmpdb_path) { - char cmd[8 + MAXPATHLEN]; - snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", tmpdb_path); - dbd_log( LOGDEBUG, "Removing temp database '%s'", tmpdb_path); - system(cmd); - snprintf(cmd, 8 + MAXPATHLEN, "rmdir %s", tmpdb_path); - system(cmd); - } - } return ret; } diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c index 784ac422..e2a24d48 100644 --- a/etc/cnid_dbd/main.c +++ b/etc/cnid_dbd/main.c @@ -43,6 +43,8 @@ static DBD *dbd; static int exit_sig = 0; static int db_locked; +static bstring dbpath; +static struct db_param *dbp; static void sig_exit(int signo) { @@ -81,6 +83,74 @@ static void block_sigs_onoff(int block) #define min(a,b) ((a)<(b)?(a):(b)) #endif +static int delete_db(void) +{ + EC_INIT; + int cwd = -1; + + EC_NEG1( cwd = open(".", O_RDONLY) ); + + chdir(bdata(dbpath)); + system("rm -f cnid2.db lock log.* __db.*"); + if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) != LOCK_EXCL) { + LOG(log_error, logtype_cnid, "main: fatal db lock error"); + EC_FAIL; + } + +EC_CLEANUP: + if (cwd != -1) + fchdir(cwd); + EC_EXIT; +} + +static int wipe_db(void) +{ + EC_INIT; + DBT key, data; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + key.data = ROOTINFO_KEY; + key.size = ROOTINFO_KEYLEN; + + if (dbif_get(dbd, DBIF_CNID, &key, &data, 0) <= 0) { + LOG(log_error, logtype_cnid, "dbif_copy_rootinfokey: Error getting rootinfo record"); + EC_FAIL; + } + + EC_NEG1_LOG( dbif_close(dbd) ); + EC_NEG1_LOG( dbif_env_remove(bdata(dbpath)) ); + EC_ZERO_LOG( delete_db() ); + + /* Get db lock */ + if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) != LOCK_EXCL) { + LOG(log_error, logtype_cnid, "main: fatal db lock error"); + EC_FAIL; + } + + EC_NULL_LOG( dbd = dbif_init(bdata(dbpath), "cnid2.db") ); + + /* Only recover if we got the lock */ + EC_NEG1_LOG( dbif_env_open(dbd, dbp, DBOPTIONS | DB_RECOVER) ); + + LOG(log_debug, logtype_cnid, "Finished initializing BerkeleyDB environment"); + + EC_NEG1_LOG( dbif_open(dbd, dbp, 0) ); + + memset(&key, 0, sizeof(key)); + key.data = ROOTINFO_KEY; + key.size = ROOTINFO_KEYLEN; + + if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) != 0) { + LOG(log_error, logtype_cnid, "dbif_copy_rootinfokey: Error writing rootinfo key"); + EC_FAIL; + } + +EC_CLEANUP: + EC_EXIT; +} + static int loop(struct db_param *dbp) { struct cnid_dbd_rqst rqst; @@ -171,6 +241,9 @@ static int loop(struct db_param *dbp) case CNID_DBD_OP_SEARCH: ret = dbd_search(dbd, &rqst, &rply); break; + case CNID_DBD_OP_WIPE: + ret = wipe_db(); + break; default: LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op); ret = -1; @@ -274,14 +347,12 @@ static void set_signal(void) int main(int argc, char *argv[]) { EC_INIT; - struct db_param *dbp; int delete_bdb = 0; int ctrlfd = -1, clntfd = -1; char *logconfig; AFPObj obj = { 0 }; struct vol *vol; char *volpath = NULL; - bstring dbpath; while (( ret = getopt( argc, argv, "dF:l:p:t:vV")) != -1 ) { switch (ret) { @@ -327,26 +398,14 @@ int main(int argc, char *argv[]) switch_to_user(bdata(dbpath)); /* Get db lock */ - if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) == -1) { + if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) != LOCK_EXCL) { LOG(log_error, logtype_cnid, "main: fatal db lock error"); EC_FAIL; } - if (db_locked != LOCK_EXCL) { - /* Couldn't get exclusive lock, try shared lock */ - if ((db_locked = get_lock(LOCK_SHRD, NULL)) != LOCK_SHRD) { - LOG(log_error, logtype_cnid, "main: fatal db lock error"); - EC_FAIL; - } - } - if (delete_bdb && (db_locked == LOCK_EXCL)) { + if (delete_bdb) { LOG(log_warning, logtype_cnid, "main: too many CNID db opening attempts, wiping the slate clean"); - chdir(bdata(dbpath)); - system("rm -f cnid2.db lock log.* __db.*"); - if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) != LOCK_EXCL) { - LOG(log_error, logtype_cnid, "main: fatal db lock error"); - EC_FAIL; - } + EC_ZERO( delete_db() ); } set_signal(); diff --git a/include/atalk/cnid.h b/include/atalk/cnid.h index 2d3aa062..ba0b62fa 100644 --- a/include/atalk/cnid.h +++ b/include/atalk/cnid.h @@ -69,6 +69,7 @@ struct _cnid_db { const char *, size_t, cnid_t); int (*cnid_find) (struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen); + int (*cnid_wipe) (struct _cnid_db *cdb); }; typedef struct _cnid_db cnid_db; @@ -123,6 +124,7 @@ cnid_t cnid_rebuild_add(struct _cnid_db *cdb, const struct stat *st, const cnid_ char *name, const size_t len, cnid_t hint); int cnid_find (struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen); +int cnid_wipe (struct _cnid_db *cdb); void cnid_close (struct _cnid_db *db); #endif diff --git a/include/atalk/cnid_dbd_private.h b/include/atalk/cnid_dbd_private.h index d7484e42..b61f7a8c 100644 --- a/include/atalk/cnid_dbd_private.h +++ b/include/atalk/cnid_dbd_private.h @@ -25,6 +25,7 @@ #define CNID_DBD_OP_GETSTAMP 0x0b #define CNID_DBD_OP_REBUILD_ADD 0x0c #define CNID_DBD_OP_SEARCH 0x0d +#define CNID_DBD_OP_WIPE 0x0e #define CNID_DBD_RES_OK 0x00 #define CNID_DBD_RES_NOTFOUND 0x01 diff --git a/libatalk/cnid/cdb/cnid_cdb_open.c b/libatalk/cnid/cdb/cnid_cdb_open.c index 056420da..757d1b0d 100644 --- a/libatalk/cnid/cdb/cnid_cdb_open.c +++ b/libatalk/cnid/cdb/cnid_cdb_open.c @@ -144,7 +144,7 @@ static struct _cnid_db *cnid_cdb_new(const char *volpath) cdb->cnid_close = cnid_cdb_close; cdb->cnid_getstamp = cnid_cdb_getstamp; cdb->cnid_rebuild_add = cnid_cdb_rebuild_add; - + cdb->cnid_wipe = NULL; return cdb; } diff --git a/libatalk/cnid/cnid.c b/libatalk/cnid/cnid.c index 0a977e6a..7cf3af16 100644 --- a/libatalk/cnid/cnid.c +++ b/libatalk/cnid/cnid.c @@ -338,3 +338,15 @@ cnid_t ret; unblock_signal(cdb->flags); return ret; } + +/* --------------- */ +int cnid_wipe(struct _cnid_db *cdb) +{ + int ret = 0; + + block_signal(cdb->flags); + if (cdb->cnid_wipe) + ret = cdb->cnid_wipe(cdb); + unblock_signal(cdb->flags); + return ret; +} diff --git a/libatalk/cnid/dbd/cnid_dbd.c b/libatalk/cnid/dbd/cnid_dbd.c index 32be8f47..b654740a 100644 --- a/libatalk/cnid/dbd/cnid_dbd.c +++ b/libatalk/cnid/dbd/cnid_dbd.c @@ -456,7 +456,7 @@ static struct _cnid_db *cnid_dbd_new(const char *volpath) cdb->cnid_update = cnid_dbd_update; cdb->cnid_rebuild_add = cnid_dbd_rebuild_add; cdb->cnid_close = cnid_dbd_close; - + cdb->cnid_wipe = cnid_dbd_wipe; return cdb; } @@ -994,6 +994,57 @@ int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id) } } +int cnid_dbd_wipe(struct _cnid_db *cdb) +{ + CNID_private *db; + struct cnid_dbd_rqst rqst; + struct cnid_dbd_rply rply; + + if (!cdb || !(db = cdb->_private)) { + LOG(log_error, logtype_cnid, "cnid_wipe: Parameter error"); + errno = CNID_ERR_PARAM; + return -1; + } + + LOG(log_debug, logtype_cnid, "cnid_dbd_wipe"); + + RQST_RESET(&rqst); + rqst.op = CNID_DBD_OP_WIPE; + rqst.cnid = 0; + + rply.namelen = 0; + if (transmit(db, &rqst, &rply) < 0) { + errno = CNID_ERR_DB; + return -1; + } + + if (rply.result != CNID_DBD_RES_OK) { + errno = CNID_ERR_DB; + return -1; + } + LOG(log_debug, logtype_cnid, "cnid_dbd_wipe: ok"); + + struct cnid_dbd_rqst rqst_stamp; + struct cnid_dbd_rply rply_stamp; + char stamp[ADEDLEN_PRIVSYN]; + + dbd_initstamp(&rqst_stamp); + memset(stamp, 0, ADEDLEN_PRIVSYN); + rply_stamp.name = stamp; + rply_stamp.namelen = ADEDLEN_PRIVSYN; + + if (dbd_rpc(db, &rqst_stamp, &rply_stamp) < 0) + return -1; + if (dbd_reply_stamp(&rply_stamp ) < 0) + return -1; + + if (db->client_stamp) + memcpy(db->client_stamp, stamp, ADEDLEN_PRIVSYN); + memcpy(db->stamp, stamp, ADEDLEN_PRIVSYN); + + return 0; +} + struct _cnid_module cnid_dbd_module = { "dbd", diff --git a/libatalk/cnid/dbd/cnid_dbd.h b/libatalk/cnid/dbd/cnid_dbd.h index fdba4c04..69ff5a64 100644 --- a/libatalk/cnid/dbd/cnid_dbd.h +++ b/libatalk/cnid/dbd/cnid_dbd.h @@ -32,7 +32,7 @@ extern int cnid_dbd_update (struct _cnid_db *, cnid_t, const struct stat extern int cnid_dbd_delete (struct _cnid_db *, const cnid_t); extern cnid_t cnid_dbd_rebuild_add(struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t); - +extern int cnid_dbd_wipe (struct _cnid_db *cdb); /* FIXME: These functions could be static in cnid_dbd.c */ #endif /* include/atalk/cnid_dbd.h */ diff --git a/libatalk/cnid/last/cnid_last.c b/libatalk/cnid/last/cnid_last.c index 5903d03f..fd92cc5a 100644 --- a/libatalk/cnid/last/cnid_last.c +++ b/libatalk/cnid/last/cnid_last.c @@ -139,7 +139,8 @@ static struct _cnid_db *cnid_last_new(const char *volpath) cdb->cnid_resolve = cnid_last_resolve; cdb->cnid_update = cnid_last_update; cdb->cnid_close = cnid_last_close; - + cdb->cnid_wipe = NULL; + return cdb; } diff --git a/libatalk/cnid/tdb/cnid_tdb_open.c b/libatalk/cnid/tdb/cnid_tdb_open.c index d02ef0bc..889cea1e 100644 --- a/libatalk/cnid/tdb/cnid_tdb_open.c +++ b/libatalk/cnid/tdb/cnid_tdb_open.c @@ -56,7 +56,8 @@ static struct _cnid_db *cnid_tdb_new(const char *volpath) cdb->cnid_resolve = cnid_tdb_resolve; cdb->cnid_update = cnid_tdb_update; cdb->cnid_close = cnid_tdb_close; - + cdb->cnid_wipe = NULL; + return cdb; } -- 2.39.2