1 /*
2 * Copyright (C) 2009, Nokia
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 * Author: Philip Van Hoof <philip@codeminded.be>
20 */
21
22 #include "config.h"
23
24 #include <string.h>
25 #include <glib.h>
26 #include <glib/gstdio.h>
27
28 #include <sqlite3.h>
29
30 #include <libtracker-data/tracker-ontology.h>
31 #include <libtracker-data/tracker-ontologies.h>
32 #include <libtracker-data/tracker-db-manager.h>
33 #include <libtracker-data/tracker-db-interface-sqlite.h>
34
35 #include "tracker-db-backup.h"
36
37 #define TRACKER_DB_BACKUP_META_FILENAME_T "meta-backup.db.tmp"
38
39 typedef struct {
40 GFile *destination;
41 GFile *file;
42 TrackerDBBackupFinished callback;
43 gpointer user_data;
44 GDestroyNotify destroy;
45 GError *error;
46 } BackupInfo;
47
48 GQuark
tracker_db_backup_error_quark(void)49 tracker_db_backup_error_quark (void)
50 {
51 return g_quark_from_static_string ("tracker-db-backup-error-quark");
52 }
53
54 static gboolean
perform_callback(gpointer user_data)55 perform_callback (gpointer user_data)
56 {
57 BackupInfo *info = user_data;
58
59 if (info->callback) {
60 info->callback (info->error, info->user_data);
61 }
62
63 return FALSE;
64 }
65
66 static void
backup_info_free(gpointer user_data)67 backup_info_free (gpointer user_data)
68 {
69 BackupInfo *info = user_data;
70
71 if (info->destination) {
72 g_object_unref (info->destination);
73 }
74
75 if (info->file) {
76 g_object_unref (info->file);
77 }
78
79 if (info->destroy) {
80 info->destroy (info->user_data);
81 }
82
83 g_clear_error (&info->error);
84
85 g_slice_free (BackupInfo, info);
86 }
87
88 static void
backup_job(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)89 backup_job (GTask *task,
90 gpointer source_object,
91 gpointer task_data,
92 GCancellable *cancellable)
93 {
94 BackupInfo *info = task_data;
95
96 GFile *parent_file, *temp_file;
97 gchar *temp_path, *src_path;
98
99 sqlite3 *src_db = NULL;
100 sqlite3 *temp_db = NULL;
101 sqlite3_backup *backup = NULL;
102
103 src_path = g_file_get_path (info->file);
104 parent_file = g_file_get_parent (info->destination);
105 temp_file = g_file_get_child (parent_file, TRACKER_DB_BACKUP_META_FILENAME_T);
106 g_file_delete (temp_file, NULL, NULL);
107 temp_path = g_file_get_path (temp_file);
108
109 if (sqlite3_open_v2 (src_path, &src_db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
110 g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
111 "Could not open sqlite3 database:'%s'", src_path);
112 }
113
114 if (!info->error && sqlite3_open (temp_path, &temp_db) != SQLITE_OK) {
115 g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
116 "Could not open sqlite3 database:'%s'", temp_path);
117 }
118
119 if (!info->error) {
120 backup = sqlite3_backup_init (temp_db, "main", src_db, "main");
121
122 if (!backup) {
123 g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
124 "Unable to initialize sqlite3 backup from '%s' to '%s'", src_path, temp_path);
125 }
126 }
127
128 if (!info->error && sqlite3_backup_step (backup, -1) != SQLITE_DONE) {
129 g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
130 "Unable to complete sqlite3 backup");
131 }
132
133 if (backup) {
134 if (sqlite3_backup_finish (backup) != SQLITE_OK) {
135 if (info->error) {
136 /* sqlite3_backup_finish can provide more detailed error message */
137 g_clear_error (&info->error);
138 }
139 g_set_error (&info->error,
140 TRACKER_DB_BACKUP_ERROR,
141 TRACKER_DB_BACKUP_ERROR_UNKNOWN,
142 "Unable to finish sqlite3 backup: %s",
143 sqlite3_errmsg (temp_db));
144 }
145 backup = NULL;
146 }
147
148 if (temp_db) {
149 sqlite3_close (temp_db);
150 temp_db = NULL;
151 }
152
153 if (src_db) {
154 sqlite3_close (src_db);
155 src_db = NULL;
156 }
157
158 if (!info->error) {
159 g_file_move (temp_file, info->destination,
160 G_FILE_COPY_OVERWRITE,
161 NULL, NULL, NULL,
162 &info->error);
163 }
164
165 g_free (src_path);
166 g_free (temp_path);
167 g_object_unref (temp_file);
168 g_object_unref (parent_file);
169
170 g_idle_add_full (G_PRIORITY_DEFAULT, perform_callback, info,
171 backup_info_free);
172 }
173
174 void
tracker_db_backup_save(GFile * destination,GFile * file,TrackerDBBackupFinished callback,gpointer user_data,GDestroyNotify destroy)175 tracker_db_backup_save (GFile *destination,
176 GFile *file,
177 TrackerDBBackupFinished callback,
178 gpointer user_data,
179 GDestroyNotify destroy)
180 {
181 GTask *task;
182 BackupInfo *info;
183
184 info = g_slice_new0 (BackupInfo);
185
186 info->destination = g_object_ref (destination);
187 info->file = g_object_ref (file);
188
189 info->callback = callback;
190 info->user_data = user_data;
191 info->destroy = destroy;
192
193 task = g_task_new (NULL, NULL, NULL, NULL);
194
195 g_task_set_task_data (task, info, NULL);
196 g_task_run_in_thread (task, backup_job);
197 g_object_unref (task);
198 }
199
200