/* * do a backup of a tdb, moving the destination out of the way first */ static int tdb_backup_with_rotate(TALLOC_CTX *ctx, const char *src_path, const char *dst_path, int hash_size, const char *rotate_suffix, bool retry_norotate_if_nospc, bool rename_as_last_resort_if_nospc) { int ret; rename_file_with_suffix(ctx, dst_path, rotate_suffix); ret = tdb_backup(ctx, src_path, dst_path, hash_size); if (ret != 0) { DEBUG(10, ("backup of %s failed: %s\n", src_path, strerror(errno))); } if ((ret != 0) && (errno == ENOSPC) && retry_norotate_if_nospc) { char *rotate_path = talloc_asprintf(ctx, "%s%s", dst_path, rotate_suffix); DEBUG(10, ("backup of %s failed due to lack of space\n", src_path)); DEBUGADD(10, ("trying to free some space by removing rotated " "dst %s\n", rotate_path)); if (unlink(rotate_path) == -1) { DEBUG(10, ("unlink of %s failed: %s\n", rotate_path, strerror(errno))); } else { ret = tdb_backup(ctx, src_path, dst_path, hash_size); } TALLOC_FREE(rotate_path); } if ((ret != 0) && (errno == ENOSPC) && rename_as_last_resort_if_nospc) { DEBUG(10, ("backup of %s failed due to lack of space\n", src_path)); DEBUGADD(10, ("using 'rename' as a last resort\n")); ret = rename(src_path, dst_path); } return ret; }
static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx, const char *tdb_path, struct rpc_pipe_client *winreg_pipe) { const char *backup_suffix = ".bak"; TDB_DATA kbuf, newkey, dbuf; TDB_CONTEXT *tdb; NTSTATUS status; int rc; tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0600); if (tdb == NULL && errno == ENOENT) { /* if we have no printers database then migration is considered successful */ DEBUG(4, ("No printers database to migrate in %s\n", tdb_path)); return NT_STATUS_OK; } if (tdb == NULL) { DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path)); return NT_STATUS_NO_SUCH_FILE; } for (kbuf = tdb_firstkey(tdb); kbuf.dptr; newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey) { dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) { continue; } if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) { status = printing_tdb_migrate_form(mem_ctx, winreg_pipe, (const char *) kbuf.dptr + strlen(FORMS_PREFIX), dbuf.dptr, dbuf.dsize); SAFE_FREE(dbuf.dptr); if (!NT_STATUS_IS_OK(status)) { tdb_close(tdb); return status; } continue; } if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) { status = printing_tdb_migrate_driver(mem_ctx, winreg_pipe, (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX), dbuf.dptr, dbuf.dsize, false); SAFE_FREE(dbuf.dptr); if (!NT_STATUS_IS_OK(status)) { tdb_close(tdb); return status; } continue; } if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) { const char *printer_name = (const char *)(kbuf.dptr + strlen(PRINTERS_PREFIX)); status = printing_tdb_migrate_printer(mem_ctx, winreg_pipe, printer_name, dbuf.dptr, dbuf.dsize, false); SAFE_FREE(dbuf.dptr); if (!NT_STATUS_IS_OK(status)) { tdb_close(tdb); return status; } continue; } SAFE_FREE(dbuf.dptr); } for (kbuf = tdb_firstkey(tdb); kbuf.dptr; newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey) { dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) { continue; } if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) { const char *secdesc_name = (const char *)(kbuf.dptr + strlen(SECDESC_PREFIX)); status = printing_tdb_migrate_secdesc(mem_ctx, winreg_pipe, secdesc_name, dbuf.dptr, dbuf.dsize); SAFE_FREE(dbuf.dptr); if (NT_STATUS_EQUAL(status, werror_to_ntstatus(WERR_FILE_NOT_FOUND))) { DEBUG(2, ("Skipping secdesc migration for non-existent " "printer: %s\n", secdesc_name)); } else if (!NT_STATUS_IS_OK(status)) { tdb_close(tdb); return status; } continue; } SAFE_FREE(dbuf.dptr); } tdb_close(tdb); rc = rename_file_with_suffix(mem_ctx, tdb_path, backup_suffix); if (rc != 0) { DEBUG(0, ("Error moving tdb to '%s%s'\n", tdb_path, backup_suffix)); } return NT_STATUS_OK; }
/* * validation function with backup handling: * * - calls tdb_validate * - if the tdb is ok, create a backup "name.bak", possibly moving * existing backup to name.bak.old, * return 0 (success) even if the backup fails * - if the tdb is corrupt: * - move the tdb to "name.corrupt" * - check if there is valid backup. * if so, restore the backup. * if restore is successful, return 0 (success), * - otherwise return -1 (failure) */ int tdb_validate_and_backup(const char *tdb_path, tdb_validate_data_func validate_fn) { int ret = -1; const char *backup_suffix = ".bak"; const char *corrupt_suffix = ".corrupt"; const char *rotate_suffix = ".old"; char *tdb_path_backup; struct stat st; TALLOC_CTX *ctx = NULL; ctx = talloc_new(NULL); if (ctx == NULL) { DEBUG(0, ("tdb_validate_and_backup: out of memory\n")); goto done; } tdb_path_backup = talloc_asprintf(ctx, "%s%s", tdb_path, backup_suffix); ret = tdb_validate_open(tdb_path, validate_fn); if (ret == 0) { DEBUG(1, ("tdb '%s' is valid\n", tdb_path)); ret = tdb_backup_with_rotate(ctx, tdb_path, tdb_path_backup, 0, rotate_suffix, True, False); if (ret != 0) { DEBUG(1, ("Error creating backup of tdb '%s'\n", tdb_path)); /* the actual validation was successful: */ ret = 0; } else { DEBUG(1, ("Created backup '%s' of tdb '%s'\n", tdb_path_backup, tdb_path)); } } else { DEBUG(1, ("tdb '%s' is invalid\n", tdb_path)); ret =stat(tdb_path_backup, &st); if (ret != 0) { DEBUG(5, ("Could not stat '%s': %s\n", tdb_path_backup, strerror(errno))); DEBUG(1, ("No backup found.\n")); } else { DEBUG(1, ("backup '%s' found.\n", tdb_path_backup)); ret = tdb_validate_open(tdb_path_backup, validate_fn); if (ret != 0) { DEBUG(1, ("Backup '%s' is invalid.\n", tdb_path_backup)); } } if (ret != 0) { int renamed = rename_file_with_suffix(ctx, tdb_path, corrupt_suffix); if (renamed != 0) { DEBUG(1, ("Error moving tdb to '%s%s'\n", tdb_path, corrupt_suffix)); } else { DEBUG(1, ("Corrupt tdb stored as '%s%s'\n", tdb_path, corrupt_suffix)); } goto done; } DEBUG(1, ("valid backup '%s' found\n", tdb_path_backup)); ret = tdb_backup_with_rotate(ctx, tdb_path_backup, tdb_path, 0, corrupt_suffix, True, True); if (ret != 0) { DEBUG(1, ("Error restoring backup from '%s'\n", tdb_path_backup)); } else { DEBUG(1, ("Restored tdb backup from '%s'\n", tdb_path_backup)); } } done: TALLOC_FREE(ctx); return ret; }