Fix some file header comments.
[platform/upstream/evolution-data-server.git] / services / evolution-source-registry / evolution-source-registry-migrate-basedir.c
1 /*
2  * evolution-source-registry-migrate-basedir.c
3  *
4  * This program 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 of the License, or (at your option) version 3.
8  *
9  * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  */
18
19 #include <errno.h>
20 #include <glib/gstdio.h>
21 #include <libedataserver/libedataserver.h>
22
23 /* Forward Declarations */
24 void evolution_source_registry_migrate_basedir (void);
25
26 static gboolean
27 migrate_rename (const gchar *old_filename,
28                 const gchar *new_filename)
29 {
30         gboolean old_filename_is_dir;
31         gboolean old_filename_exists;
32         gboolean new_filename_exists;
33         gboolean success = TRUE;
34
35         old_filename_is_dir = g_file_test (old_filename, G_FILE_TEST_IS_DIR);
36         old_filename_exists = g_file_test (old_filename, G_FILE_TEST_EXISTS);
37         new_filename_exists = g_file_test (new_filename, G_FILE_TEST_EXISTS);
38
39         if (!old_filename_exists)
40                 return TRUE;
41
42         g_print ("  mv %s %s\n", old_filename, new_filename);
43
44         /* It's safe to go ahead and move directories because rename()
45          * will fail if the new directory already exists with content.
46          * With regular files we have to be careful not to overwrite
47          * new files with old files. */
48         if (old_filename_is_dir || !new_filename_exists) {
49                 if (g_rename (old_filename, new_filename) < 0) {
50                         g_printerr ("  FAILED: %s\n", g_strerror (errno));
51                         success = FALSE;
52                 }
53         } else {
54                 g_printerr ("  FAILED: Destination file already exists\n");
55                 success = FALSE;
56         }
57
58         return success;
59 }
60
61 static gboolean
62 migrate_rmdir (const gchar *dirname)
63 {
64         GDir *dir = NULL;
65         gboolean success = TRUE;
66
67         if (g_file_test (dirname, G_FILE_TEST_IS_DIR)) {
68                 g_print ("  rmdir %s\n", dirname);
69                 if (g_rmdir (dirname) < 0) {
70                         g_printerr ("  FAILED: %s", g_strerror (errno));
71                         if (errno == ENOTEMPTY) {
72                                 dir = g_dir_open (dirname, 0, NULL);
73                                 g_printerr (" (contents follows)");
74                         }
75                         g_printerr ("\n");
76                         success = FALSE;
77                 }
78         }
79
80         /* List the directory's contents to aid debugging. */
81         if (dir != NULL) {
82                 const gchar *basename;
83
84                 /* Align the filenames beneath the error message. */
85                 while ((basename = g_dir_read_name (dir)) != NULL)
86                         g_print ("          %s\n", basename);
87
88                 g_dir_close (dir);
89         }
90
91         return success;
92 }
93
94 static void
95 migrate_process_corrections (GHashTable *corrections)
96 {
97         GHashTableIter iter;
98         gpointer old_filename;
99         gpointer new_filename;
100
101         g_hash_table_iter_init (&iter, corrections);
102
103         while (g_hash_table_iter_next (&iter, &old_filename, &new_filename)) {
104                 migrate_rename (old_filename, new_filename);
105                 g_hash_table_iter_remove (&iter);
106         }
107 }
108
109 static gboolean
110 migrate_move_contents (const gchar *src_directory,
111                        const gchar *dst_directory)
112 {
113         GDir *dir;
114         GHashTable *corrections;
115         const gchar *basename;
116
117         dir = g_dir_open (src_directory, 0, NULL);
118         if (dir == NULL)
119                 return FALSE;
120
121         /* This is to avoid renaming files while we're iterating over the
122          * directory.  POSIX says the outcome of that is unspecified. */
123         corrections = g_hash_table_new_full (
124                 g_str_hash, g_str_equal,
125                 (GDestroyNotify) g_free,
126                 (GDestroyNotify) g_free);
127
128         g_mkdir_with_parents (dst_directory, 0700);
129
130         while ((basename = g_dir_read_name (dir)) != NULL) {
131                 gchar *old_filename;
132                 gchar *new_filename;
133
134                 old_filename = g_build_filename (src_directory, basename, NULL);
135                 new_filename = g_build_filename (dst_directory, basename, NULL);
136
137                 g_hash_table_insert (corrections, old_filename, new_filename);
138         }
139
140         g_dir_close (dir);
141
142         migrate_process_corrections (corrections);
143         g_hash_table_destroy (corrections);
144
145         /* It's tempting to want to remove the source directory here.
146          * Don't.  We might be iterating over the source directory's
147          * parent directory, and removing the source directory would
148          * screw up the iteration. */
149
150         return TRUE;
151 }
152
153 static void
154 migrate_fix_exchange_bug (const gchar *old_base_dir)
155 {
156         GDir *dir;
157         GHashTable *corrections;
158         const gchar *basename;
159         gchar *exchange_dir;
160         gchar *old_cache_dir;
161
162         /* The exchange backend mistakenly cached calendar attachments in
163          * ~/.evolution/exchange instead of ~/.evolution/cache/calendar.
164          * Fix that before we migrate the cache directory. */
165
166         exchange_dir = g_build_filename (old_base_dir, "exchange", NULL);
167         old_cache_dir = g_build_filename (old_base_dir, "cache", "calendar", NULL);
168
169         dir = g_dir_open (exchange_dir, 0, NULL);
170         if (dir == NULL)
171                 goto exit;
172
173         /* This is to avoid renaming files while we're iterating over the
174          * directory.  POSIX says the outcome of that is unspecified. */
175         corrections = g_hash_table_new_full (
176                 g_str_hash, g_str_equal,
177                 (GDestroyNotify) g_free,
178                 (GDestroyNotify) g_free);
179
180         while ((basename = g_dir_read_name (dir)) != NULL) {
181                 gchar *old_filename;
182                 gchar *new_filename;
183
184                 if (!g_str_has_prefix (basename, "exchange___"))
185                         continue;
186
187                 old_filename = g_build_filename (exchange_dir, basename, NULL);
188                 new_filename = g_build_filename (old_cache_dir, basename, NULL);
189
190                 g_hash_table_insert (corrections, old_filename, new_filename);
191         }
192
193         g_dir_close (dir);
194
195         migrate_process_corrections (corrections);
196         g_hash_table_destroy (corrections);
197
198 exit:
199         g_free (exchange_dir);
200         g_free (old_cache_dir);
201 }
202
203 static void
204 migrate_fix_memos_cache_bug (const gchar *old_base_dir)
205 {
206         gchar *src_directory;
207         gchar *dst_directory;
208
209         /* Some calendar backends cached memo data under
210          * ~/.evolution/cache/journal instead of ~/.evolution/cache/memos.
211          * Fix that before we migrate the cache directory. */
212
213         src_directory = g_build_filename (old_base_dir, "cache", "journal", NULL);
214         dst_directory = g_build_filename (old_base_dir, "cache", "memos", NULL);
215
216         migrate_move_contents (src_directory, dst_directory);
217         migrate_rmdir (src_directory);
218
219         g_free (src_directory);
220         g_free (dst_directory);
221 }
222
223 static void
224 migrate_fix_groupwise_bug (const gchar *old_base_dir)
225 {
226         GDir *dir;
227         GHashTable *corrections;
228         const gchar *basename;
229         gchar *old_data_dir;
230         gchar *old_cache_dir;
231
232         /* The groupwise backend mistakenly put its addressbook
233          * cache files in ~/.evolution/addressbook instead of
234          * ~/.evolution/cache/addressbook.  Fix that before
235          * we migrate the cache directory. */
236
237         old_data_dir = g_build_filename (old_base_dir, "addressbook", NULL);
238         old_cache_dir = g_build_filename (old_base_dir, "cache", "addressbook", NULL);
239
240         dir = g_dir_open (old_data_dir, 0, NULL);
241         if (dir == NULL)
242                 goto exit;
243
244         /* This is to avoid renaming files while we're iterating over the
245          * directory.  POSIX says the outcome of that is unspecified. */
246         corrections = g_hash_table_new_full (
247                 g_str_hash, g_str_equal,
248                 (GDestroyNotify) g_free,
249                 (GDestroyNotify) g_free);
250
251         while ((basename = g_dir_read_name (dir)) != NULL) {
252                 gchar *old_filename;
253                 gchar *new_filename;
254
255                 if (!g_str_has_prefix (basename, "groupwise___"))
256                         continue;
257
258                 old_filename = g_build_filename (old_data_dir, basename, NULL);
259                 new_filename = g_build_filename (old_cache_dir, basename, NULL);
260
261                 g_hash_table_insert (corrections, old_filename, new_filename);
262         }
263
264         g_dir_close (dir);
265
266         migrate_process_corrections (corrections);
267         g_hash_table_destroy (corrections);
268
269 exit:
270         g_free (old_data_dir);
271         g_free (old_cache_dir);
272 }
273
274 static void
275 migrate_to_user_cache_dir (const gchar *old_base_dir)
276 {
277         const gchar *new_cache_dir;
278         gchar *old_cache_dir;
279         gchar *src_directory;
280         gchar *dst_directory;
281
282         old_cache_dir = g_build_filename (old_base_dir, "cache", NULL);
283         new_cache_dir = e_get_user_cache_dir ();
284
285         g_print ("Migrating cached backend data\n");
286
287         /* We don't want to move the source directory directly because the
288          * destination directory may already exist with content.  Instead
289          * we want to merge the content of the source directory into the
290          * destination directory.
291          *
292          * For example, given:
293          *
294          *    $(src_directory)/A   and   $(dst_directory)/B
295          *    $(src_directory)/C
296          *
297          * we want to end up with:
298          *
299          *    $(dst_directory)/A
300          *    $(dst_directory)/B
301          *    $(dst_directory)/C
302          *
303          * Any name collisions will be left in the source directory.
304          */
305
306         src_directory = g_build_filename (old_cache_dir, "addressbook", NULL);
307         dst_directory = g_build_filename (new_cache_dir, "addressbook", NULL);
308
309         migrate_move_contents (src_directory, dst_directory);
310         migrate_rmdir (src_directory);
311
312         g_free (src_directory);
313         g_free (dst_directory);
314
315         src_directory = g_build_filename (old_cache_dir, "calendar", NULL);
316         dst_directory = g_build_filename (new_cache_dir, "calendar", NULL);
317
318         migrate_move_contents (src_directory, dst_directory);
319         migrate_rmdir (src_directory);
320
321         g_free (src_directory);
322         g_free (dst_directory);
323
324         src_directory = g_build_filename (old_cache_dir, "memos", NULL);
325         dst_directory = g_build_filename (new_cache_dir, "memos", NULL);
326
327         migrate_move_contents (src_directory, dst_directory);
328         migrate_rmdir (src_directory);
329
330         g_free (src_directory);
331         g_free (dst_directory);
332
333         src_directory = g_build_filename (old_cache_dir, "tasks", NULL);
334         dst_directory = g_build_filename (new_cache_dir, "tasks", NULL);
335
336         migrate_move_contents (src_directory, dst_directory);
337         migrate_rmdir (src_directory);
338
339         g_free (src_directory);
340         g_free (dst_directory);
341
342         /* Try to remove the old cache directory.  Good chance this will
343          * fail on the first try, since Evolution puts stuff here too. */
344         migrate_rmdir (old_cache_dir);
345
346         g_free (old_cache_dir);
347 }
348
349 static void
350 migrate_to_user_data_dir (const gchar *old_base_dir)
351 {
352         const gchar *new_data_dir;
353         gchar *src_directory;
354         gchar *dst_directory;
355
356         new_data_dir = e_get_user_data_dir ();
357
358         g_print ("Migrating local backend data\n");
359
360         /* We don't want to move the source directory directly because the
361          * destination directory may already exist with content.  Instead
362          * we want to merge the content of the source directory into the
363          * destination directory.
364          *
365          * For example, given:
366          *
367          *    $(src_directory)/A   and   $(dst_directory)/B
368          *    $(src_directory)/C
369          *
370          * we want to end up with:
371          *
372          *    $(dst_directory)/A
373          *    $(dst_directory)/B
374          *    $(dst_directory)/C
375          *
376          * Any name collisions will be left in the source directory.
377          */
378
379         src_directory = g_build_filename (old_base_dir, "addressbook", "local", NULL);
380         dst_directory = g_build_filename (new_data_dir, "addressbook", NULL);
381
382         migrate_move_contents (src_directory, dst_directory);
383         migrate_rmdir (src_directory);
384
385         g_free (src_directory);
386         g_free (dst_directory);
387
388         src_directory = g_build_filename (old_base_dir, "calendar", "local", NULL);
389         dst_directory = g_build_filename (new_data_dir, "calendar", NULL);
390
391         migrate_move_contents (src_directory, dst_directory);
392         migrate_rmdir (src_directory);
393
394         g_free (src_directory);
395         g_free (dst_directory);
396
397         src_directory = g_build_filename (old_base_dir, "memos", "local", NULL);
398         dst_directory = g_build_filename (new_data_dir, "memos", NULL);
399
400         migrate_move_contents (src_directory, dst_directory);
401         migrate_rmdir (src_directory);
402
403         g_free (src_directory);
404         g_free (dst_directory);
405
406         src_directory = g_build_filename (old_base_dir, "tasks", "local", NULL);
407         dst_directory = g_build_filename (new_data_dir, "tasks", NULL);
408
409         migrate_move_contents (src_directory, dst_directory);
410         migrate_rmdir (src_directory);
411
412         g_free (src_directory);
413         g_free (dst_directory);
414
415         /* XXX This is not really the right place to be migrating
416          *     exchange data, but since we already cleaned out the
417          *     cached attachment files from this directory, may as
418          *     well move the user accounts too while we're at it. */
419
420         src_directory = g_build_filename (old_base_dir, "exchange", NULL);
421         dst_directory = g_build_filename (new_data_dir, "exchange", NULL);
422
423         migrate_move_contents (src_directory, dst_directory);
424         migrate_rmdir (src_directory);
425
426         g_free (src_directory);
427         g_free (dst_directory);
428 }
429
430 void
431 evolution_source_registry_migrate_basedir (void)
432 {
433         const gchar *home_dir;
434         gchar *old_base_dir;
435
436         /* XXX This blocks, but it's all just local directory
437          *     renames so it should be nearly instantaneous. */
438
439         home_dir = g_get_home_dir ();
440         old_base_dir = g_build_filename (home_dir, ".evolution", NULL);
441
442         /* Is there even anything to migrate? */
443         if (!g_file_test (old_base_dir, G_FILE_TEST_IS_DIR))
444                 goto exit;
445
446         /* Miscellaneous tweaks before we start. */
447         migrate_fix_exchange_bug (old_base_dir);
448         migrate_fix_memos_cache_bug (old_base_dir);
449         migrate_fix_groupwise_bug (old_base_dir);
450
451         migrate_to_user_cache_dir (old_base_dir);
452         migrate_to_user_data_dir (old_base_dir);
453
454         /* Try to remove the old base directory.  Good chance this will
455          * fail on the first try, since Evolution puts stuff here too. */
456         migrate_rmdir (old_base_dir);
457
458 exit:
459         g_free (old_base_dir);
460 }