/* carefully backup a tdb, validating the contents and only doing the backup if its OK this function is also used for restore */ static int backup_tdb(const char *old_name, const char *new_name, int hash_size, int nolock) { TDB_CONTEXT *tdb; TDB_CONTEXT *tdb_new; char *tmp_name; struct stat st; int count1, count2; tmp_name = add_suffix(new_name, ".tmp"); /* stat the old tdb to find its permissions */ if (stat(old_name, &st) != 0) { perror(old_name); free(tmp_name); return 1; } /* open the old tdb */ tdb = tdb_open_ex(old_name, 0, TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0), O_RDWR, 0, &log_ctx, NULL); if (!tdb) { printf("Failed to open %s\n", old_name); free(tmp_name); return 1; } /* create the new tdb */ unlink(tmp_name); tdb_new = tdb_open_ex(tmp_name, hash_size ? hash_size : tdb_hash_size(tdb), TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777, &log_ctx, NULL); if (!tdb_new) { perror(tmp_name); free(tmp_name); return 1; } if (tdb_transaction_start(tdb) != 0) { printf("Failed to start transaction on old tdb\n"); tdb_close(tdb); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } /* lock the backup tdb so that nobody else can change it */ if (tdb_lockall(tdb_new) != 0) { printf("Failed to lock backup tdb\n"); tdb_close(tdb); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } failed = 0; /* traverse and copy */ count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new); if (count1 < 0 || failed) { fprintf(stderr,"failed to copy %s\n", old_name); tdb_close(tdb); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } /* close the old tdb */ tdb_close(tdb); /* copy done, unlock the backup tdb */ tdb_unlockall(tdb_new); #ifdef HAVE_FDATASYNC if (fdatasync(tdb_fd(tdb_new)) != 0) { #else if (fsync(tdb_fd(tdb_new)) != 0) { #endif /* not fatal */ fprintf(stderr, "failed to fsync backup file\n"); } /* close the new tdb and re-open read-only */ tdb_close(tdb_new); tdb_new = tdb_open_ex(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0, &log_ctx, NULL); if (!tdb_new) { fprintf(stderr,"failed to reopen %s\n", tmp_name); unlink(tmp_name); perror(tmp_name); free(tmp_name); return 1; } /* traverse the new tdb to confirm */ count2 = tdb_traverse(tdb_new, test_fn, NULL); if (count2 != count1) { fprintf(stderr,"failed to copy %s\n", old_name); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } /* close the new tdb and rename it to .bak */ tdb_close(tdb_new); if (rename(tmp_name, new_name) != 0) { perror(new_name); free(tmp_name); return 1; } free(tmp_name); return 0; } /* verify a tdb and if it is corrupt then restore from *.bak */ static int verify_tdb(const char *fname, const char *bak_name) { TDB_CONTEXT *tdb; int count = -1; /* open the tdb */ tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &log_ctx, NULL); /* traverse the tdb, then close it */ if (tdb) { count = tdb_traverse(tdb, test_fn, NULL); tdb_close(tdb); } /* count is < 0 means an error */ if (count < 0) { printf("restoring %s\n", fname); return backup_tdb(bak_name, fname, 0, 0); } printf("%s : %d records\n", fname, count); return 0; }
/* carefully backup a tdb, validating the contents and only doing the backup if its OK this function is also used for restore */ int backup_tdb(const char *old_name, const char *new_name, int hash_size) { TDB_CONTEXT *tdb; TDB_CONTEXT *tdb_new; char *tmp_name; struct stat st; int count1, count2; tmp_name = add_suffix(new_name, ".tmp"); /* stat the old tdb to find its permissions */ if (stat(old_name, &st) != 0) { perror(old_name); free(tmp_name); return 1; } /* open the old tdb */ tdb = tdb_open(old_name, 0, 0, O_RDWR, 0); if (!tdb) { printf("Failed to open %s\n", old_name); free(tmp_name); return 1; } /* create the new tdb */ unlink(tmp_name); tdb_new = tdb_open(tmp_name, hash_size ? hash_size : tdb_hash_size(tdb), TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777); if (!tdb_new) { perror(tmp_name); free(tmp_name); return 1; } /* lock the old tdb */ if (tdb_lockall(tdb) != 0) { fprintf(stderr,"Failed to lock %s\n", old_name); tdb_close(tdb); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } failed = 0; /* traverse and copy */ count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new); if (count1 < 0 || failed) { fprintf(stderr,"failed to copy %s\n", old_name); tdb_close(tdb); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } /* close the old tdb */ tdb_close(tdb); /* close the new tdb and re-open read-only */ tdb_close(tdb_new); tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0); if (!tdb_new) { fprintf(stderr,"failed to reopen %s\n", tmp_name); unlink(tmp_name); perror(tmp_name); free(tmp_name); return 1; } /* traverse the new tdb to confirm */ count2 = tdb_traverse(tdb_new, test_fn, 0); if (count2 != count1) { fprintf(stderr,"failed to copy %s\n", old_name); tdb_close(tdb_new); unlink(tmp_name); free(tmp_name); return 1; } /* make sure the new tdb has reached stable storage */ fsync(tdb_fd(tdb_new)); /* close the new tdb and rename it to .bak */ tdb_close(tdb_new); unlink(new_name); if (rename(tmp_name, new_name) != 0) { perror(new_name); free(tmp_name); return 1; } free(tmp_name); return 0; }
/* this backup function is essentially taken from lib/tdb/tools/tdbbackup.tdb */ static int tdb_backup(TALLOC_CTX *ctx, const char *src_path, const char *dst_path, int hash_size) { struct tdb_context *src_tdb = NULL; struct tdb_context *dst_tdb = NULL; char *tmp_path = NULL; struct stat st; int count1, count2; int saved_errno = 0; int ret = -1; if (stat(src_path, &st) != 0) { DEBUG(3, ("Could not stat '%s': %s\n", src_path, strerror(errno))); goto done; } /* open old tdb RDWR - so we can lock it */ src_tdb = tdb_open_log(src_path, 0, TDB_DEFAULT, O_RDWR, 0); if (src_tdb == NULL) { DEBUG(3, ("Failed to open tdb '%s'\n", src_path)); goto done; } if (tdb_lockall(src_tdb) != 0) { DEBUG(3, ("Failed to lock tdb '%s'\n", src_path)); goto done; } tmp_path = talloc_asprintf(ctx, "%s%s", dst_path, ".tmp"); unlink(tmp_path); dst_tdb = tdb_open_log(tmp_path, hash_size ? hash_size : tdb_hash_size(src_tdb), TDB_DEFAULT, O_RDWR | O_CREAT | O_EXCL, st.st_mode & 0777); if (dst_tdb == NULL) { DEBUG(3, ("Error creating tdb '%s': %s\n", tmp_path, strerror(errno))); saved_errno = errno; unlink(tmp_path); goto done; } count1 = tdb_copy(src_tdb, dst_tdb); if (count1 < 0) { DEBUG(3, ("Failed to copy tdb '%s': %s\n", src_path, strerror(errno))); tdb_close(dst_tdb); goto done; } /* reopen ro and do basic verification */ tdb_close(dst_tdb); dst_tdb = tdb_open_log(tmp_path, 0, TDB_DEFAULT, O_RDONLY, 0); if (!dst_tdb) { DEBUG(3, ("Failed to reopen tdb '%s': %s\n", tmp_path, strerror(errno))); goto done; } count2 = tdb_verify_basic(dst_tdb); if (count2 != count1) { DEBUG(3, ("Failed to verify result of copying tdb '%s'.\n", src_path)); tdb_close(dst_tdb); goto done; } DEBUG(10, ("tdb_backup: successfully copied %d entries\n", count1)); /* make sure the new tdb has reached stable storage * then rename it to its destination */ fsync(tdb_fd(dst_tdb)); tdb_close(dst_tdb); unlink(dst_path); if (rename(tmp_path, dst_path) != 0) { DEBUG(3, ("Failed to rename '%s' to '%s': %s\n", tmp_path, dst_path, strerror(errno))); goto done; } /* success */ ret = 0; done: if (src_tdb != NULL) { tdb_close(src_tdb); } if (tmp_path != NULL) { unlink(tmp_path); TALLOC_FREE(tmp_path); } if (saved_errno != 0) { errno = saved_errno; } return ret; }
static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure) { PyErr_TDB_RAISE_IF_CLOSED(self); return PyInt_FromLong(tdb_hash_size(self->ctx)); }