/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * This library is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * */ /** * SECTION: e-db3-utils * @short_description: Utilities for Berkeley DB databases * * Utilities for coping with Berkeley DB file format changes. **/ #include "config.h" #include #include #include #include #ifndef O_BINARY #define O_BINARY 0 #endif #include #include "db.h" #include "e-db3-utils.h" static gchar * get_check_filename (const gchar *filename) { return g_strdup_printf ("%s-upgrading", filename); } static gchar * get_copy_filename (const gchar *filename) { return g_strdup_printf ("%s-copy", filename); } static gint cp_file (const gchar *src, const gchar *dest) { gint i; gint o; gchar buffer[1024]; gint length; gint place; i = g_open (src, O_RDONLY | O_BINARY, 0); if (i == -1) return -1; o = g_open ( dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE); if (o == -1) { close (i); return -1; } while (1) { length = read (i, &buffer, sizeof (buffer)); if (length == 0) break; if (length == -1) { if (errno == EINTR) continue; else { close (i); close (o); g_unlink (dest); return -1; } } place = 0; while (length != 0) { gint count; count = write (o, buffer + place, length); if (count == -1) { if (errno == EINTR) continue; else { close (i); close (o); g_unlink (dest); return -1; } } length -= count; place += count; } } i = close (i); if (close (o) == -1) i = -1; return (i == -1) ? -1 : 0; } static gint touch_file (const gchar *file) { gint fd; fd = g_open ( file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE); if (fd == -1) return -1; return close (fd); } static gint resume_upgrade (const gchar *filename, const gchar *copy_filename, const gchar *check_filename) { DB *db; gint ret_val; ret_val = db_create (&db, NULL, 0); if (ret_val == 0) ret_val = cp_file (copy_filename, filename); if (ret_val == 0) ret_val = db->upgrade (db, filename, 0); if (ret_val == 0) ret_val = g_unlink (check_filename); if (ret_val == 0) ret_val = g_unlink (copy_filename); db->close (db, 0); return ret_val; } /** * e_db3_utils_maybe_recover: * @filename: path to a Berkeley DB file * * Tries to recover from a failed file format upgrade. * * Returns: 0 if successful, -1 on failure **/ gint e_db3_utils_maybe_recover (const gchar *filename) { gint ret_val = 0; gchar *copy_filename; gchar *check_filename; copy_filename = get_copy_filename (filename); check_filename = get_check_filename (filename); if (g_file_test (check_filename, G_FILE_TEST_EXISTS)) { ret_val = resume_upgrade (filename, copy_filename, check_filename); } else if (g_file_test (copy_filename, G_FILE_TEST_EXISTS)) { g_unlink (copy_filename); } g_free (copy_filename); g_free (check_filename); return ret_val; } /** * e_db3_utils_upgrade_format: * @filename: path to a Berkeley DB file * * Upgrades the file format of a Berkeley DB file from a previous version. * * Returns: 0 if successful, -1 on failure **/ gint e_db3_utils_upgrade_format (const gchar *filename) { gchar *copy_filename; gchar *check_filename; DB *db; gint ret_val; ret_val = db_create (&db, NULL, 0); if (ret_val != 0) return ret_val; copy_filename = get_copy_filename (filename); check_filename = get_check_filename (filename); ret_val = cp_file (filename, copy_filename); if (ret_val == 0) ret_val = touch_file (check_filename); if (ret_val == 0) ret_val = db->upgrade (db, filename, 0); if (ret_val == 0) ret_val = g_unlink (check_filename); if (ret_val == 0) ret_val = g_unlink (copy_filename); db->close (db, 0); g_free (check_filename); g_free (copy_filename); return ret_val; }