- /* 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 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;
-
- /* 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);
- return -1;
- }
-
- /* Get volume stamp */
- dbd_getstamp(dbd, &rqst, &rply);
- if (rply.result != CNID_DBD_RES_OK) {
- ret = -1;
- 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 (setjmp(jmp) != 0) {
- ret = 0; /* Got signal, jump from dbd_readdir */
- goto exit;
- }
-
- /* scanvol */
- if ((scanvol(vol, flags)) != 0) {
- ret = -1;
- goto exit;
- }
-
-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;