1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* caja-file-utilities.c - implementation of file manipulation routines.
4
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6
7 The Mate Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The Mate Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the Mate Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21
22 Authors: John Sullivan <sullivan@eazel.com>
23 */
24
25 #include <config.h>
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
29 #include <gio/gio.h>
30 #include <stdlib.h>
31
32 #include <eel/eel-glib-extensions.h>
33 #include <eel/eel-stock-dialogs.h>
34 #include <eel/eel-string.h>
35 #include <eel/eel-debug.h>
36
37 #include "caja-file-utilities.h"
38 #include "caja-global-preferences.h"
39 #include "caja-lib-self-check-functions.h"
40 #include "caja-metadata.h"
41 #include "caja-file.h"
42 #include "caja-file-operations.h"
43 #include "caja-search-directory.h"
44 #include "caja-signaller.h"
45
46 #define DEFAULT_CAJA_DIRECTORY_MODE (0755)
47
48 #define DESKTOP_DIRECTORY_NAME "Desktop"
49 #define DEFAULT_DESKTOP_DIRECTORY_MODE (0755)
50
51 static void update_xdg_dir_cache (void);
52 static void schedule_user_dirs_changed (void);
53 static void desktop_dir_changed (void);
54
55 char *
caja_compute_title_for_location(GFile * location)56 caja_compute_title_for_location (GFile *location)
57 {
58 char *title;
59
60 /* TODO-gio: This doesn't really work all that great if the
61 info about the file isn't known atm... */
62
63 title = NULL;
64 if (location)
65 {
66 CajaFile *file;
67
68 file = caja_file_get (location);
69 title = caja_file_get_description (file);
70 if (title == NULL)
71 {
72 title = caja_file_get_display_name (file);
73 }
74 caja_file_unref (file);
75 }
76
77 if (title == NULL)
78 {
79 title = g_strdup ("");
80 }
81
82 return title;
83 }
84
85
86 /**
87 * caja_get_user_directory:
88 *
89 * Get the path for the directory containing caja settings.
90 *
91 * Return value: the directory path.
92 **/
caja_get_user_directory(void)93 char* caja_get_user_directory(void)
94 {
95 /* FIXME bugzilla.gnome.org 41286:
96 * How should we handle the case where this mkdir fails?
97 * Note that caja_application_startup will refuse to launch if this
98 * directory doesn't get created, so that case is OK. But the directory
99 * could be deleted after Caja was launched, and perhaps
100 * there is some bad side-effect of not handling that case.
101 * <<<
102 * Si alguien tiene tiempo, puede enviar este codigo a Nautilus.
103 * Obviamente, con los comentarios traducidos al Inglés.
104 */
105 char* user_directory = g_build_filename(g_get_user_config_dir(), "caja", NULL);
106 /* Se necesita que esta dirección sea una carpeta, con los permisos
107 * DEFAULT_CAJA_DIRECTORY_MODE. Pero si es un archivo, el programa intentará
108 * eliminar el archivo silenciosamente. */
109 if (g_file_test(user_directory, G_FILE_TEST_IS_DIR) == FALSE ||
110 g_access(user_directory, DEFAULT_CAJA_DIRECTORY_MODE) == -1)
111 {
112 /* Se puede obtener un enlace simbolico a una carpeta */
113 if (g_file_test(user_directory, G_FILE_TEST_IS_SYMLINK) == TRUE)
114 {
115 /* intentaremos saber si el enlace es una carpeta, y tiene los
116 * permisos adecuados */
117 char* link = g_file_read_link(user_directory, NULL);
118
119 if (link)
120 {
121 /* Si el enlace no es un directorio, o si falla al hacer chmod,
122 * se borra el enlace y se crea la carpeta */
123 if (g_file_test(link, G_FILE_TEST_IS_DIR) != TRUE ||
124 g_chmod(link, DEFAULT_CAJA_DIRECTORY_MODE) != 0)
125 {
126 /* podemos borrar el enlace y crear la carpeta */
127 g_unlink(user_directory);
128 g_mkdir(user_directory, DEFAULT_CAJA_DIRECTORY_MODE);
129 }
130
131 g_free(link);
132 }
133 }
134 else if (g_file_test(user_directory, G_FILE_TEST_IS_DIR) == TRUE)
135 {
136 g_chmod(user_directory, DEFAULT_CAJA_DIRECTORY_MODE);
137 }
138 else if (g_file_test(user_directory, G_FILE_TEST_EXISTS) == TRUE)
139 {
140 /* podemos borrar el enlace y crear la carpeta */
141 g_unlink(user_directory);
142 g_mkdir(user_directory, DEFAULT_CAJA_DIRECTORY_MODE);
143 }
144 else
145 {
146 /* Si no existe ningun archivo, se crea la carpeta */
147 g_mkdir_with_parents(user_directory, DEFAULT_CAJA_DIRECTORY_MODE);
148 }
149
150 /* Faltan permisos */
151 if (g_chmod(user_directory, DEFAULT_CAJA_DIRECTORY_MODE) != 0)
152 {
153 GtkWidget* dialog = gtk_message_dialog_new(
154 NULL,
155 GTK_DIALOG_DESTROY_WITH_PARENT,
156 GTK_MESSAGE_ERROR,
157 GTK_BUTTONS_CLOSE,
158 "The path for the directory containing caja settings need read and write permissions: %s",
159 user_directory);
160
161 gtk_dialog_run(GTK_DIALOG(dialog));
162 gtk_widget_destroy(dialog);
163
164 exit(0);
165 }
166 }
167
168 return user_directory;
169 }
170
171 /**
172 * caja_get_accel_map_file:
173 *
174 * Get the path for the filename containing caja accelerator map.
175 * The filename need not exist.
176 *
177 * Return value: the filename path
178 **/
caja_get_accel_map_file(void)179 char* caja_get_accel_map_file(void)
180 {
181 return g_build_filename (g_get_user_config_dir (), "caja", "accels", NULL);
182 }
183
184 typedef struct {
185 char*type;
186 char*path;
187 CajaFile* file;
188 } XdgDirEntry;
189
190
191 static XdgDirEntry *
parse_xdg_dirs(const char * config_file)192 parse_xdg_dirs (const char *config_file)
193 {
194 GArray *array;
195 char *config_file_free = NULL;
196 XdgDirEntry dir;
197 char *data;
198 char **lines;
199 char *p;
200 char *unescaped;
201 gboolean relative;
202
203 array = g_array_new (TRUE, TRUE, sizeof (XdgDirEntry));
204
205 if (config_file == NULL)
206 {
207 config_file_free = g_build_filename (g_get_user_config_dir (),
208 "user-dirs.dirs", NULL);
209 config_file = (const char *)config_file_free;
210 }
211
212 if (g_file_get_contents (config_file, &data, NULL, NULL))
213 {
214 int i;
215
216 lines = g_strsplit (data, "\n", 0);
217 g_free (data);
218 for (i = 0; lines[i] != NULL; i++)
219 {
220 char *d;
221 char *type_start, *type_end;
222 char *value;
223
224 p = lines[i];
225 while (g_ascii_isspace (*p))
226 p++;
227
228 if (*p == '#')
229 continue;
230
231 value = strchr (p, '=');
232 if (value == NULL)
233 continue;
234 *value++ = 0;
235
236 g_strchug (g_strchomp (p));
237 if (!g_str_has_prefix (p, "XDG_"))
238 continue;
239 if (!g_str_has_suffix (p, "_DIR"))
240 continue;
241 type_start = p + 4;
242 type_end = p + strlen (p) - 4;
243
244 while (g_ascii_isspace (*value))
245 value++;
246
247 if (*value != '"')
248 continue;
249 value++;
250
251 relative = FALSE;
252 if (g_str_has_prefix (value, "$HOME"))
253 {
254 relative = TRUE;
255 value += 5;
256 while (*value == '/')
257 value++;
258 }
259 else if (*value != '/')
260 continue;
261
262 d = unescaped = g_malloc (strlen (value) + 1);
263 while (*value && *value != '"')
264 {
265 if ((*value == '\\') && (*(value + 1) != 0))
266 value++;
267 *d++ = *value++;
268 }
269 *d = 0;
270
271 *type_end = 0;
272 dir.type = g_strdup (type_start);
273 if (relative)
274 {
275 dir.path = g_build_filename (g_get_home_dir (), unescaped, NULL);
276 g_free (unescaped);
277 }
278 else
279 dir.path = unescaped;
280
281 g_array_append_val (array, dir);
282 }
283
284 g_strfreev (lines);
285 }
286
287 g_free (config_file_free);
288
289 return (XdgDirEntry *) (gpointer) g_array_free (array, FALSE);
290 }
291
292 static XdgDirEntry *cached_xdg_dirs = NULL;
293 static GFileMonitor *cached_xdg_dirs_monitor = NULL;
294
295 static void
xdg_dir_changed(CajaFile * file,XdgDirEntry * dir)296 xdg_dir_changed (CajaFile *file,
297 XdgDirEntry *dir)
298 {
299 GFile *location, *dir_location;
300 char *path;
301
302 location = caja_file_get_location (file);
303 dir_location = g_file_new_for_path (dir->path);
304 if (!g_file_equal (location, dir_location))
305 {
306 path = g_file_get_path (location);
307
308 if (path)
309 {
310 char *argv[5];
311 int i;
312
313 g_free (dir->path);
314 dir->path = path;
315
316 i = 0;
317 argv[i++] = "xdg-user-dirs-update";
318 argv[i++] = "--set";
319 argv[i++] = dir->type;
320 argv[i++] = dir->path;
321 argv[i++] = NULL;
322
323 /* We do this sync, to avoid possible race-conditions
324 if multiple dirs change at the same time. Its
325 blocking the main thread, but these updates should
326 be very rare and very fast. */
327 g_spawn_sync (NULL,
328 argv, NULL,
329 G_SPAWN_SEARCH_PATH |
330 G_SPAWN_STDOUT_TO_DEV_NULL |
331 G_SPAWN_STDERR_TO_DEV_NULL,
332 NULL, NULL,
333 NULL, NULL, NULL, NULL);
334 g_reload_user_special_dirs_cache ();
335 schedule_user_dirs_changed ();
336 desktop_dir_changed ();
337 /* Icon might have changed */
338 caja_file_invalidate_attributes (file, CAJA_FILE_ATTRIBUTE_INFO);
339 }
340 }
341 g_object_unref (location);
342 g_object_unref (dir_location);
343 }
344
345 static void
xdg_dir_cache_changed_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type)346 xdg_dir_cache_changed_cb (GFileMonitor *monitor,
347 GFile *file,
348 GFile *other_file,
349 GFileMonitorEvent event_type)
350 {
351 if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
352 event_type == G_FILE_MONITOR_EVENT_CREATED)
353 {
354 update_xdg_dir_cache ();
355 }
356 }
357
358 static int user_dirs_changed_tag = 0;
359
360 static gboolean
emit_user_dirs_changed_idle(gpointer data)361 emit_user_dirs_changed_idle (gpointer data)
362 {
363 g_signal_emit_by_name (caja_signaller_get_current (),
364 "user_dirs_changed");
365 user_dirs_changed_tag = 0;
366 return FALSE;
367 }
368
369 static void
schedule_user_dirs_changed(void)370 schedule_user_dirs_changed (void)
371 {
372 if (user_dirs_changed_tag == 0)
373 {
374 user_dirs_changed_tag = g_idle_add (emit_user_dirs_changed_idle, NULL);
375 }
376 }
377
378 static void
unschedule_user_dirs_changed(void)379 unschedule_user_dirs_changed (void)
380 {
381 if (user_dirs_changed_tag != 0)
382 {
383 g_source_remove (user_dirs_changed_tag);
384 user_dirs_changed_tag = 0;
385 }
386 }
387
388 static void
free_xdg_dir_cache(void)389 free_xdg_dir_cache (void)
390 {
391 if (cached_xdg_dirs != NULL)
392 {
393 int i;
394
395 for (i = 0; cached_xdg_dirs[i].type != NULL; i++)
396 {
397 if (cached_xdg_dirs[i].file != NULL)
398 {
399 caja_file_monitor_remove (cached_xdg_dirs[i].file,
400 &cached_xdg_dirs[i]);
401 g_signal_handlers_disconnect_by_func (cached_xdg_dirs[i].file,
402 G_CALLBACK (xdg_dir_changed),
403 &cached_xdg_dirs[i]);
404 caja_file_unref (cached_xdg_dirs[i].file);
405 }
406 g_free (cached_xdg_dirs[i].type);
407 g_free (cached_xdg_dirs[i].path);
408 }
409 g_free (cached_xdg_dirs);
410 }
411 }
412
413 static void
destroy_xdg_dir_cache(void)414 destroy_xdg_dir_cache (void)
415 {
416 free_xdg_dir_cache ();
417 unschedule_user_dirs_changed ();
418 desktop_dir_changed ();
419
420 if (cached_xdg_dirs_monitor != NULL)
421 {
422 g_object_unref (cached_xdg_dirs_monitor);
423 cached_xdg_dirs_monitor = NULL;
424 }
425 }
426
427 static void
update_xdg_dir_cache(void)428 update_xdg_dir_cache (void)
429 {
430 char *uri;
431 int i;
432
433 free_xdg_dir_cache ();
434 g_reload_user_special_dirs_cache ();
435 schedule_user_dirs_changed ();
436 desktop_dir_changed ();
437
438 cached_xdg_dirs = parse_xdg_dirs (NULL);
439
440 for (i = 0 ; cached_xdg_dirs[i].type != NULL; i++)
441 {
442 cached_xdg_dirs[i].file = NULL;
443 if (strcmp (cached_xdg_dirs[i].path, g_get_home_dir ()) != 0)
444 {
445 uri = g_filename_to_uri (cached_xdg_dirs[i].path, NULL, NULL);
446 cached_xdg_dirs[i].file = caja_file_get_by_uri (uri);
447 caja_file_monitor_add (cached_xdg_dirs[i].file,
448 &cached_xdg_dirs[i],
449 CAJA_FILE_ATTRIBUTE_INFO);
450 g_signal_connect (cached_xdg_dirs[i].file,
451 "changed", G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]);
452 g_free (uri);
453 }
454 }
455
456 if (cached_xdg_dirs_monitor == NULL)
457 {
458 GFile *file;
459 char *config_file;
460
461 config_file = g_build_filename (g_get_user_config_dir (),
462 "user-dirs.dirs", NULL);
463 file = g_file_new_for_path (config_file);
464 cached_xdg_dirs_monitor = g_file_monitor_file (file, 0, NULL, NULL);
465 g_signal_connect (cached_xdg_dirs_monitor, "changed",
466 G_CALLBACK (xdg_dir_cache_changed_cb), NULL);
467 g_object_unref (file);
468 g_free (config_file);
469
470 eel_debug_call_at_shutdown (destroy_xdg_dir_cache);
471 }
472 }
473
474 char *
caja_get_xdg_dir(const char * type)475 caja_get_xdg_dir (const char *type)
476 {
477 int i;
478
479 if (cached_xdg_dirs == NULL)
480 {
481 update_xdg_dir_cache ();
482 }
483
484 for (i = 0 ; cached_xdg_dirs != NULL && cached_xdg_dirs[i].type != NULL; i++)
485 {
486 if (strcmp (cached_xdg_dirs[i].type, type) == 0)
487 {
488 return g_strdup (cached_xdg_dirs[i].path);
489 }
490 }
491 if (strcmp ("DESKTOP", type) == 0)
492 {
493 return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL);
494 }
495 if (strcmp ("TEMPLATES", type) == 0)
496 {
497 return g_build_filename (g_get_home_dir (), "Templates", NULL);
498 }
499
500 return g_strdup (g_get_home_dir ());
501 }
502
503 static char *
get_desktop_path(void)504 get_desktop_path (void)
505 {
506 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_DESKTOP_IS_HOME_DIR))
507 {
508 return g_strdup (g_get_home_dir());
509 }
510 else
511 {
512 return caja_get_xdg_dir ("DESKTOP");
513 }
514 }
515
516 /**
517 * caja_get_desktop_directory:
518 *
519 * Get the path for the directory containing files on the desktop.
520 *
521 * Return value: the directory path.
522 **/
523 char *
caja_get_desktop_directory(void)524 caja_get_desktop_directory (void)
525 {
526 char *desktop_directory;
527
528 desktop_directory = get_desktop_path ();
529
530 /* Don't try to create a home directory */
531 if (!g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_DESKTOP_IS_HOME_DIR))
532 {
533 if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS))
534 {
535 g_mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE);
536 /* FIXME bugzilla.gnome.org 41286:
537 * How should we handle the case where this mkdir fails?
538 * Note that caja_application_startup will refuse to launch if this
539 * directory doesn't get created, so that case is OK. But the directory
540 * could be deleted after Caja was launched, and perhaps
541 * there is some bad side-effect of not handling that case.
542 */
543 }
544 }
545
546 return desktop_directory;
547 }
548
549 GFile *
caja_get_desktop_location(void)550 caja_get_desktop_location (void)
551 {
552 char *desktop_directory;
553 GFile *res;
554
555 desktop_directory = get_desktop_path ();
556
557 res = g_file_new_for_path (desktop_directory);
558 g_free (desktop_directory);
559 return res;
560 }
561
562
563 /**
564 * caja_get_desktop_directory_uri:
565 *
566 * Get the uri for the directory containing files on the desktop.
567 *
568 * Return value: the directory path.
569 **/
570 char *
caja_get_desktop_directory_uri(void)571 caja_get_desktop_directory_uri (void)
572 {
573 char *desktop_path;
574 char *desktop_uri;
575
576 desktop_path = caja_get_desktop_directory ();
577 desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
578 g_free (desktop_path);
579
580 return desktop_uri;
581 }
582
583 char *
caja_get_home_directory_uri(void)584 caja_get_home_directory_uri (void)
585 {
586 return g_filename_to_uri (g_get_home_dir (), NULL, NULL);
587 }
588
589
590 gboolean
caja_should_use_templates_directory(void)591 caja_should_use_templates_directory (void)
592 {
593 char *dir;
594 gboolean res;
595
596 dir = caja_get_xdg_dir ("TEMPLATES");
597 res = strcmp (dir, g_get_home_dir ()) != 0;
598 g_free (dir);
599 return res;
600 }
601
602 char *
caja_get_templates_directory(void)603 caja_get_templates_directory (void)
604 {
605 return caja_get_xdg_dir ("TEMPLATES");
606 }
607
608 void
caja_create_templates_directory(void)609 caja_create_templates_directory (void)
610 {
611 char *dir;
612
613 dir = caja_get_templates_directory ();
614 if (!g_file_test (dir, G_FILE_TEST_EXISTS))
615 {
616 g_mkdir (dir, DEFAULT_CAJA_DIRECTORY_MODE);
617 }
618 g_free (dir);
619 }
620
621 char *
caja_get_templates_directory_uri(void)622 caja_get_templates_directory_uri (void)
623 {
624 char *directory, *uri;
625
626 directory = caja_get_templates_directory ();
627 uri = g_filename_to_uri (directory, NULL, NULL);
628 g_free (directory);
629 return uri;
630 }
631
632 /* These need to be reset to NULL when desktop_is_home_dir changes */
633 static GFile *desktop_dir = NULL;
634 static GFile *desktop_dir_dir = NULL;
635 static char *desktop_dir_filename = NULL;
636 static gboolean desktop_dir_changed_callback_installed = FALSE;
637
638
639 static void
desktop_dir_changed(void)640 desktop_dir_changed (void)
641 {
642 if (desktop_dir)
643 {
644 g_object_unref (desktop_dir);
645 }
646 if (desktop_dir_dir)
647 {
648 g_object_unref (desktop_dir_dir);
649 }
650 g_free (desktop_dir_filename);
651 desktop_dir = NULL;
652 desktop_dir_dir = NULL;
653 desktop_dir_filename = NULL;
654 }
655
656 static void
desktop_dir_changed_callback(gpointer callback_data)657 desktop_dir_changed_callback (gpointer callback_data)
658 {
659 desktop_dir_changed ();
660 }
661
662 static void
update_desktop_dir(void)663 update_desktop_dir (void)
664 {
665 char *path;
666 char *dirname;
667
668 path = get_desktop_path ();
669 desktop_dir = g_file_new_for_path (path);
670
671 dirname = g_path_get_dirname (path);
672 desktop_dir_dir = g_file_new_for_path (dirname);
673 g_free (dirname);
674 desktop_dir_filename = g_path_get_basename (path);
675 g_free (path);
676 }
677
678 gboolean
caja_is_home_directory_file(GFile * dir,const char * filename)679 caja_is_home_directory_file (GFile *dir,
680 const char *filename)
681 {
682 static GFile *home_dir_dir = NULL;
683 static char *home_dir_filename = NULL;
684
685 if (home_dir_dir == NULL)
686 {
687 char *dirname;
688
689 dirname = g_path_get_dirname (g_get_home_dir ());
690 home_dir_dir = g_file_new_for_path (dirname);
691 g_free (dirname);
692 home_dir_filename = g_path_get_basename (g_get_home_dir ());
693 }
694
695 return (g_file_equal (dir, home_dir_dir) &&
696 strcmp (filename, home_dir_filename) == 0);
697 }
698
699 gboolean
caja_is_home_directory(GFile * dir)700 caja_is_home_directory (GFile *dir)
701 {
702 static GFile *home_dir = NULL;
703
704 if (home_dir == NULL)
705 {
706 home_dir = g_file_new_for_path (g_get_home_dir ());
707 }
708
709 return g_file_equal (dir, home_dir);
710 }
711
712 gboolean
caja_is_root_directory(GFile * dir)713 caja_is_root_directory (GFile *dir)
714 {
715 static GFile *root_dir = NULL;
716
717 if (root_dir == NULL)
718 {
719 root_dir = g_file_new_for_path ("/");
720 }
721
722 return g_file_equal (dir, root_dir);
723 }
724
725
726 gboolean
caja_is_desktop_directory_file(GFile * dir,const char * file)727 caja_is_desktop_directory_file (GFile *dir,
728 const char *file)
729 {
730
731 if (!desktop_dir_changed_callback_installed)
732 {
733 g_signal_connect_swapped (caja_preferences, "changed::" CAJA_PREFERENCES_DESKTOP_IS_HOME_DIR,
734 G_CALLBACK(desktop_dir_changed_callback),
735 NULL);
736 desktop_dir_changed_callback_installed = TRUE;
737 }
738
739 if (desktop_dir == NULL)
740 {
741 update_desktop_dir ();
742 }
743
744 return (g_file_equal (dir, desktop_dir_dir) &&
745 strcmp (file, desktop_dir_filename) == 0);
746 }
747
748 gboolean
caja_is_desktop_directory(GFile * dir)749 caja_is_desktop_directory (GFile *dir)
750 {
751
752 if (!desktop_dir_changed_callback_installed)
753 {
754 g_signal_connect_swapped (caja_preferences, "changed::" CAJA_PREFERENCES_DESKTOP_IS_HOME_DIR,
755 G_CALLBACK(desktop_dir_changed_callback),
756 NULL);
757 desktop_dir_changed_callback_installed = TRUE;
758 }
759
760 if (desktop_dir == NULL)
761 {
762 update_desktop_dir ();
763 }
764
765 return g_file_equal (dir, desktop_dir);
766 }
767
768 GMount *
caja_get_mounted_mount_for_root(GFile * location)769 caja_get_mounted_mount_for_root (GFile *location)
770 {
771 GVolumeMonitor *volume_monitor;
772 GList *mounts;
773 GList *l;
774 GMount *mount = NULL;
775 GMount *result = NULL;
776 GFile *root = NULL;
777 GFile *default_location = NULL;
778
779 volume_monitor = g_volume_monitor_get ();
780 mounts = g_volume_monitor_get_mounts (volume_monitor);
781
782 for (l = mounts; l != NULL; l = l->next) {
783 mount = l->data;
784
785 if (g_mount_is_shadowed (mount)) {
786 continue;
787 }
788
789 root = g_mount_get_root (mount);
790 if (g_file_equal (location, root)) {
791 result = g_object_ref (mount);
792 break;
793 }
794
795 default_location = g_mount_get_default_location (mount);
796 if (!g_file_equal (default_location, root) &&
797 g_file_equal (location, default_location)) {
798 result = g_object_ref (mount);
799 break;
800 }
801 }
802
803 g_clear_object (&root);
804 g_clear_object (&default_location);
805 g_list_free_full (mounts, g_object_unref);
806
807 return result;
808 }
809
810 /**
811 * caja_get_pixmap_directory
812 *
813 * Get the path for the directory containing Caja pixmaps.
814 *
815 * Return value: the directory path.
816 **/
817 char *
caja_get_pixmap_directory(void)818 caja_get_pixmap_directory (void)
819 {
820 return g_strdup (DATADIR "/pixmaps/caja");
821 }
822
823 /* FIXME bugzilla.gnome.org 42423:
824 * Callers just use this and dereference so we core dump if
825 * pixmaps are missing. That is lame.
826 */
827 char *
caja_pixmap_file(const char * partial_path)828 caja_pixmap_file (const char *partial_path)
829 {
830 char *path;
831
832 path = g_build_filename (DATADIR "/pixmaps/caja", partial_path, NULL);
833 if (g_file_test (path, G_FILE_TEST_EXISTS))
834 {
835 return path;
836 }
837 else
838 {
839 char *tmp;
840 tmp = caja_get_pixmap_directory ();
841 g_debug ("Failed to locate \"%s\" in Caja pixmap path \"%s\". Incomplete installation?", partial_path, tmp);
842 g_free (tmp);
843 }
844 g_free (path);
845 return NULL;
846 }
847
848 char *
caja_get_data_file_path(const char * partial_path)849 caja_get_data_file_path (const char *partial_path)
850 {
851 char *path;
852 char *user_directory;
853
854 /* first try the user's home directory */
855 user_directory = caja_get_user_directory ();
856 path = g_build_filename (user_directory, partial_path, NULL);
857 g_free (user_directory);
858 if (g_file_test (path, G_FILE_TEST_EXISTS))
859 {
860 return path;
861 }
862 g_free (path);
863
864 /* next try the shared directory */
865 path = g_build_filename (CAJA_DATADIR, partial_path, NULL);
866 if (g_file_test (path, G_FILE_TEST_EXISTS))
867 {
868 return path;
869 }
870 g_free (path);
871
872 return NULL;
873 }
874
875 char *
caja_ensure_unique_file_name(const char * directory_uri,const char * base_name,const char * extension)876 caja_ensure_unique_file_name (const char *directory_uri,
877 const char *base_name,
878 const char *extension)
879 {
880 GFileInfo *info;
881 char *filename;
882 GFile *dir, *child;
883 int copy;
884 char *res;
885
886 dir = g_file_new_for_uri (directory_uri);
887
888 info = g_file_query_info (dir, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL);
889 if (info == NULL)
890 {
891 g_object_unref (dir);
892 return NULL;
893 }
894 g_object_unref (info);
895
896 filename = g_strdup_printf ("%s%s",
897 base_name,
898 extension);
899 child = g_file_get_child (dir, filename);
900 g_free (filename);
901
902 copy = 1;
903 while ((info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL)) != NULL)
904 {
905 g_object_unref (info);
906 g_object_unref (child);
907
908 filename = g_strdup_printf ("%s-%d%s",
909 base_name,
910 copy,
911 extension);
912 child = g_file_get_child (dir, filename);
913 g_free (filename);
914
915 copy++;
916 }
917
918 res = g_file_get_uri (child);
919 g_object_unref (child);
920 g_object_unref (dir);
921
922 return res;
923 }
924
925 GFile *
caja_find_existing_uri_in_hierarchy(GFile * location)926 caja_find_existing_uri_in_hierarchy (GFile *location)
927 {
928 GFileInfo *info = NULL;
929 GFile *tmp = NULL;
930
931 g_assert (location != NULL);
932
933 location = g_object_ref (location);
934 while (location != NULL)
935 {
936 info = g_file_query_info (location,
937 G_FILE_ATTRIBUTE_STANDARD_NAME,
938 0, NULL, NULL);
939 g_object_unref (info);
940 if (info != NULL)
941 {
942 return location;
943 }
944 tmp = location;
945 location = g_file_get_parent (location);
946 g_object_unref (tmp);
947 }
948
949 return location;
950 }
951
952 gboolean
caja_is_engrampa_installed(void)953 caja_is_engrampa_installed (void)
954 {
955 static int installed = -1;
956
957 if (installed < 0)
958 {
959 gchar *found = g_find_program_in_path ("engrampa");
960 installed = found ? 1 : 0;
961 g_free (found);
962 }
963
964 return installed > 0 ? TRUE : FALSE;
965 }
966
967 #define GSM_NAME "org.gnome.SessionManager"
968 #define GSM_PATH "/org/gnome/SessionManager"
969 #define GSM_INTERFACE "org.gnome.SessionManager"
970
971 /* The following values come from
972 * https://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html#org.gnome.SessionManager.Inhibit
973 */
974 #define INHIBIT_LOGOUT (1U)
975 #define INHIBIT_SUSPEND (4U)
976
977 static GDBusConnection *
get_dbus_connection(void)978 get_dbus_connection (void)
979 {
980 static GDBusConnection *conn = NULL;
981
982 if (conn == NULL)
983 {
984 GError *error = NULL;
985
986 conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
987
988 if (conn == NULL)
989 {
990 g_warning ("Could not connect to session bus: %s", error->message);
991 g_error_free (error);
992 }
993 }
994
995 return conn;
996 }
997
998 /**
999 * caja_inhibit_power_manager:
1000 * @message: a human readable message for the reason why power management
1001 * is being suspended.
1002 *
1003 * Inhibits the power manager from logging out or suspending the machine
1004 * (e.g. whenever Caja is doing file operations).
1005 *
1006 * Returns: an integer cookie, which must be passed to
1007 * caja_uninhibit_power_manager() to resume
1008 * normal power management.
1009 */
1010 int
caja_inhibit_power_manager(const char * message)1011 caja_inhibit_power_manager (const char *message)
1012 {
1013 GDBusConnection *connection;
1014 GVariant *result;
1015 GError *error = NULL;
1016 guint cookie = 0;
1017
1018 g_return_val_if_fail (message != NULL, -1);
1019
1020 connection = get_dbus_connection ();
1021
1022 if (connection == NULL)
1023 {
1024 return -1;
1025 }
1026
1027 result = g_dbus_connection_call_sync (connection,
1028 GSM_NAME,
1029 GSM_PATH,
1030 GSM_INTERFACE,
1031 "Inhibit",
1032 g_variant_new ("(susu)",
1033 "Caja",
1034 (guint) 0,
1035 message,
1036 (guint) (INHIBIT_LOGOUT | INHIBIT_SUSPEND)),
1037 G_VARIANT_TYPE ("(u)"),
1038 G_DBUS_CALL_FLAGS_NO_AUTO_START,
1039 -1,
1040 NULL,
1041 &error);
1042
1043 if (error != NULL)
1044 {
1045 g_warning ("Could not inhibit power management: %s", error->message);
1046 g_error_free (error);
1047 return -1;
1048 }
1049
1050 g_variant_get (result, "(u)", &cookie);
1051 g_variant_unref (result);
1052
1053 return (int) cookie;
1054 }
1055
1056 /**
1057 * caja_uninhibit_power_manager:
1058 * @cookie: the cookie value returned by caja_inhibit_power_manager()
1059 *
1060 * Uninhibits power management. This function must be called after the task
1061 * which inhibited power management has finished, or the system will not
1062 * return to normal power management.
1063 */
1064 void
caja_uninhibit_power_manager(gint cookie)1065 caja_uninhibit_power_manager (gint cookie)
1066 {
1067 GDBusConnection *connection;
1068 GVariant *result;
1069 GError *error = NULL;
1070
1071 g_return_if_fail (cookie > 0);
1072
1073 connection = get_dbus_connection ();
1074
1075 if (connection == NULL)
1076 {
1077 return;
1078 }
1079
1080 result = g_dbus_connection_call_sync (connection,
1081 GSM_NAME,
1082 GSM_PATH,
1083 GSM_INTERFACE,
1084 "Uninhibit",
1085 g_variant_new ("(u)", (guint) cookie),
1086 NULL,
1087 G_DBUS_CALL_FLAGS_NO_AUTO_START,
1088 -1,
1089 NULL,
1090 &error);
1091
1092 if (result == NULL)
1093 {
1094 g_warning ("Could not uninhibit power management: %s", error->message);
1095 g_error_free (error);
1096 return;
1097 }
1098
1099 g_variant_unref (result);
1100 }
1101
1102 /* Returns TRUE if the file is in XDG_DATA_DIRS. This is used for
1103 deciding if a desktop file is "trusted" based on the path */
1104 gboolean
caja_is_in_system_dir(GFile * file)1105 caja_is_in_system_dir (GFile *file)
1106 {
1107 const char * const * data_dirs;
1108 char *path;
1109 int i;
1110 gboolean res;
1111
1112 if (!g_file_is_native (file))
1113 {
1114 return FALSE;
1115 }
1116
1117 path = g_file_get_path (file);
1118
1119 res = FALSE;
1120
1121 data_dirs = g_get_system_data_dirs ();
1122 for (i = 0; path != NULL && data_dirs[i] != NULL; i++)
1123 {
1124 if (g_str_has_prefix (path, data_dirs[i]))
1125 {
1126 res = TRUE;
1127 break;
1128 }
1129
1130 }
1131
1132 g_free (path);
1133
1134 return res;
1135 }
1136
1137 gboolean
caja_is_in_desktop_dir(GFile * file)1138 caja_is_in_desktop_dir (GFile *file)
1139 {
1140 char *path;
1141 char *dirname;
1142 gboolean res = FALSE;
1143
1144 if (!g_file_is_native (file))
1145 {
1146 return res;
1147 }
1148
1149 path = g_file_get_path (file);
1150 dirname = g_path_get_dirname (path);
1151 if (g_strcmp0 (dirname, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
1152 {
1153 res = TRUE;
1154 }
1155
1156 g_free (path);
1157 g_free (dirname);
1158
1159 return res;
1160 }
1161
1162 GHashTable *
caja_trashed_files_get_original_directories(GList * files,GList ** unhandled_files)1163 caja_trashed_files_get_original_directories (GList *files,
1164 GList **unhandled_files)
1165 {
1166 GHashTable *directories;
1167 GList *l, *m;
1168 CajaFile *file = NULL;
1169 CajaFile *original_file = NULL;
1170 CajaFile *original_dir = NULL;
1171
1172 directories = NULL;
1173
1174 if (unhandled_files != NULL)
1175 {
1176 *unhandled_files = NULL;
1177 }
1178
1179 for (l = files; l != NULL; l = l->next)
1180 {
1181 file = CAJA_FILE (l->data);
1182 original_file = caja_file_get_trash_original_file (file);
1183
1184 original_dir = NULL;
1185 if (original_file != NULL)
1186 {
1187 original_dir = caja_file_get_parent (original_file);
1188 }
1189
1190 if (original_dir != NULL)
1191 {
1192 if (directories == NULL)
1193 {
1194 directories = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1195 (GDestroyNotify) caja_file_unref,
1196 (GDestroyNotify) caja_file_list_unref);
1197 }
1198 caja_file_ref (original_dir);
1199 m = g_hash_table_lookup (directories, original_dir);
1200 if (m != NULL)
1201 {
1202 g_hash_table_steal (directories, original_dir);
1203 caja_file_unref (original_dir);
1204 }
1205 m = g_list_append (m, caja_file_ref (file));
1206 g_hash_table_insert (directories, original_dir, m);
1207 }
1208 else if (unhandled_files != NULL)
1209 {
1210 *unhandled_files = g_list_append (*unhandled_files, caja_file_ref (file));
1211 }
1212
1213 if (original_file != NULL)
1214 {
1215 caja_file_unref (original_file);
1216 }
1217
1218 if (original_dir != NULL)
1219 {
1220 caja_file_unref (original_dir);
1221 }
1222 }
1223
1224 return directories;
1225 }
1226
1227 static GList *
locations_from_file_list(GList * file_list)1228 locations_from_file_list (GList *file_list)
1229 {
1230 GList *l, *ret;
1231 CajaFile *file = NULL;
1232
1233 ret = NULL;
1234
1235 for (l = file_list; l != NULL; l = l->next)
1236 {
1237 file = CAJA_FILE (l->data);
1238 ret = g_list_prepend (ret, caja_file_get_location (file));
1239 }
1240
1241 return g_list_reverse (ret);
1242 }
1243
1244 void
caja_restore_files_from_trash(GList * files,GtkWindow * parent_window)1245 caja_restore_files_from_trash (GList *files,
1246 GtkWindow *parent_window)
1247 {
1248 GHashTable *original_dirs_hash;
1249 GList *original_dirs, *unhandled_files;
1250 GList *l;
1251 CajaFile *file = NULL;
1252
1253 original_dirs_hash = caja_trashed_files_get_original_directories (files, &unhandled_files);
1254
1255 for (l = unhandled_files; l != NULL; l = l->next)
1256 {
1257 char *message, *file_name;
1258
1259 file = CAJA_FILE (l->data);
1260 file_name = caja_file_get_display_name (file);
1261 message = g_strdup_printf (_("Could not determine original location of \"%s\" "), file_name);
1262 g_free (file_name);
1263
1264 eel_show_warning_dialog (message,
1265 _("The item cannot be restored from trash"),
1266 parent_window);
1267 g_free (message);
1268 }
1269
1270 if (original_dirs_hash != NULL)
1271 {
1272 CajaFile *original_dir = NULL;
1273 GFile *original_dir_location = NULL;
1274 GList *locations = NULL;
1275
1276 original_dirs = g_hash_table_get_keys (original_dirs_hash);
1277 for (l = original_dirs; l != NULL; l = l->next)
1278 {
1279 original_dir = CAJA_FILE (l->data);
1280 original_dir_location = caja_file_get_location (original_dir);
1281
1282 files = g_hash_table_lookup (original_dirs_hash, original_dir);
1283 locations = locations_from_file_list (files);
1284
1285 caja_file_operations_move
1286 (locations, NULL,
1287 original_dir_location,
1288 parent_window,
1289 NULL, NULL);
1290
1291 g_list_free_full (locations, g_object_unref);
1292 g_object_unref (original_dir_location);
1293 }
1294
1295 g_list_free (original_dirs);
1296 g_hash_table_destroy (original_dirs_hash);
1297 }
1298
1299 caja_file_list_unref (unhandled_files);
1300 }
1301
1302 char *
caja_get_filesystem_id_by_location(GFile * location,gboolean follow)1303 caja_get_filesystem_id_by_location (GFile *location, gboolean follow)
1304 {
1305 GFileInfo *info;
1306 GFileQueryInfoFlags flags;
1307 char *filesystem_id = NULL;
1308
1309 if (follow) {
1310 flags = G_FILE_QUERY_INFO_NONE;
1311 } else {
1312 flags = G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS;
1313 }
1314
1315 info = g_file_query_info (location, G_FILE_ATTRIBUTE_ID_FILESYSTEM, flags, NULL, NULL);
1316 if (info) {
1317 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM)) {
1318 filesystem_id = g_strdup (
1319 g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM));
1320 }
1321 g_object_unref (info);
1322 }
1323 return filesystem_id;
1324 }
1325
1326 char *
caja_get_filesystem_id_by_uri(const char * uri,gboolean follow)1327 caja_get_filesystem_id_by_uri (const char *uri, gboolean follow)
1328 {
1329 GFile *location;
1330 char *filesystem_id;
1331
1332 location = g_file_new_for_uri (uri);
1333 filesystem_id = caja_get_filesystem_id_by_location (location, follow);
1334 g_object_unref (location);
1335 return filesystem_id;
1336 }
1337
1338 #if !defined (CAJA_OMIT_SELF_CHECK)
1339
1340 void
caja_self_check_file_utilities(void)1341 caja_self_check_file_utilities (void)
1342 {
1343 }
1344
1345 #endif /* !CAJA_OMIT_SELF_CHECK */
1346