2007-12-11 A. Walton <awalton@svn.gnome.org>
[nautilus.git] / libnautilus-private / nautilus-file-utilities.c
blob20d3eb63b592c1a5ca545bcd746b029665c390cd
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* nautilus-file-utilities.c - implementation of file manipulation routines.
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
7 The Gnome 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.
12 The Gnome 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.
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Authors: John Sullivan <sullivan@eazel.com>
25 #include <config.h>
26 #include "nautilus-file-utilities.h"
28 #include "nautilus-global-preferences.h"
29 #include "nautilus-lib-self-check-functions.h"
30 #include "nautilus-metadata.h"
31 #include "nautilus-metafile.h"
32 #include "nautilus-file.h"
33 #include "nautilus-search-directory.h"
34 #include "nautilus-signaller.h"
35 #include <eel/eel-glib-extensions.h>
36 #include <eel/eel-string.h>
37 #include <eel/eel-debug.h>
38 #include <libgnome/gnome-util.h>
39 #include <glib/gi18n.h>
40 #include <gio/gfilemonitor.h>
41 #include <unistd.h>
42 #include <stdlib.h>
44 #define NAUTILUS_USER_DIRECTORY_NAME ".nautilus"
45 #define DEFAULT_NAUTILUS_DIRECTORY_MODE (0755)
47 #define DESKTOP_DIRECTORY_NAME "Desktop"
48 #define LEGACY_DESKTOP_DIRECTORY_NAME ".gnome-desktop"
49 #define DEFAULT_DESKTOP_DIRECTORY_MODE (0755)
51 static void update_xdg_dir_cache (void);
52 static void schedule_user_dirs_changed (void);
53 static void desktop_dir_changed (void);
56 char *
57 nautilus_compute_title_for_location (GFile *location)
59 NautilusFile *file;
60 char *title;
62 /* TODO-gio: This doesn't really work all that great if the
63 info about the file isn't known atm... */
65 title = NULL;
66 if (location) {
67 file = nautilus_file_get (location);
68 title = nautilus_file_get_display_name (file);
69 nautilus_file_unref (file);
72 if (title == NULL) {
73 title = g_strdup ("");
76 return title;
80 /**
81 * nautilus_get_user_directory:
83 * Get the path for the directory containing nautilus settings.
85 * Return value: the directory path.
86 **/
87 char *
88 nautilus_get_user_directory (void)
90 char *user_directory = NULL;
92 user_directory = g_build_filename (g_get_home_dir (),
93 NAUTILUS_USER_DIRECTORY_NAME,
94 NULL);
96 if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) {
97 mkdir (user_directory, DEFAULT_NAUTILUS_DIRECTORY_MODE);
98 /* FIXME bugzilla.gnome.org 41286:
99 * How should we handle the case where this mkdir fails?
100 * Note that nautilus_application_startup will refuse to launch if this
101 * directory doesn't get created, so that case is OK. But the directory
102 * could be deleted after Nautilus was launched, and perhaps
103 * there is some bad side-effect of not handling that case.
107 return user_directory;
110 typedef struct {
111 char *type;
112 char *path;
113 NautilusFile *file;
114 } XdgDirEntry;
117 static XdgDirEntry *
118 parse_xdg_dirs (const char *config_file)
120 GArray *array;
121 char *config_file_free = NULL;
122 XdgDirEntry dir;
123 char *data;
124 char **lines;
125 char *p, *d;
126 int i;
127 char *type_start, *type_end;
128 char *value, *unescaped;
129 gboolean relative;
131 array = g_array_new (TRUE, TRUE, sizeof (XdgDirEntry));
133 if (config_file == NULL)
135 config_file_free = g_build_filename (g_get_user_config_dir (),
136 "user-dirs.dirs", NULL);
137 config_file = (const char *)config_file_free;
140 if (g_file_get_contents (config_file, &data, NULL, NULL))
142 lines = g_strsplit (data, "\n", 0);
143 g_free (data);
144 for (i = 0; lines[i] != NULL; i++)
146 p = lines[i];
147 while (g_ascii_isspace (*p))
148 p++;
150 if (*p == '#')
151 continue;
153 value = strchr (p, '=');
154 if (value == NULL)
155 continue;
156 *value++ = 0;
158 g_strchug (g_strchomp (p));
159 if (!g_str_has_prefix (p, "XDG_"))
160 continue;
161 if (!g_str_has_suffix (p, "_DIR"))
162 continue;
163 type_start = p + 4;
164 type_end = p + strlen (p) - 4;
166 while (g_ascii_isspace (*value))
167 value++;
169 if (*value != '"')
170 continue;
171 value++;
173 relative = FALSE;
174 if (g_str_has_prefix (value, "$HOME"))
176 relative = TRUE;
177 value += 5;
178 while (*value == '/')
179 value++;
181 else if (*value != '/')
182 continue;
184 d = unescaped = g_malloc (strlen (value) + 1);
185 while (*value && *value != '"')
187 if ((*value == '\\') && (*(value + 1) != 0))
188 value++;
189 *d++ = *value++;
191 *d = 0;
193 *type_end = 0;
194 dir.type = g_strdup (type_start);
195 if (relative)
197 dir.path = g_build_filename (g_get_home_dir (), unescaped, NULL);
198 g_free (unescaped);
200 else
201 dir.path = unescaped;
203 g_array_append_val (array, dir);
206 g_strfreev (lines);
209 g_free (config_file_free);
211 return (XdgDirEntry *)g_array_free (array, FALSE);
214 static XdgDirEntry *cached_xdg_dirs = NULL;
215 static GFileMonitor *cached_xdg_dirs_monitor = NULL;
217 static void
218 xdg_dir_changed (NautilusFile *file,
219 XdgDirEntry *dir)
221 GFile *location, *dir_location;
222 char *path;
224 location = nautilus_file_get_location (file);
225 dir_location = g_file_new_for_path (dir->path);
226 if (!g_file_equal (location, dir_location)) {
227 path = g_file_get_path (location);
229 if (path) {
230 char *argv[5];
231 int i;
233 g_free (dir->path);
234 dir->path = path;
236 i = 0;
237 argv[i++] = "xdg-user-dirs-update";
238 argv[i++] = "--set";
239 argv[i++] = dir->type;
240 argv[i++] = dir->path;
241 argv[i++] = NULL;
243 /* We do this sync, to avoid possible race-conditions
244 if multiple dirs change at the same time. Its
245 blocking the main thread, but these updates should
246 be very rare and very fast. */
247 g_spawn_sync (NULL,
248 argv, NULL,
249 G_SPAWN_SEARCH_PATH |
250 G_SPAWN_STDOUT_TO_DEV_NULL |
251 G_SPAWN_STDERR_TO_DEV_NULL,
252 NULL, NULL,
253 NULL, NULL, NULL, NULL);
254 schedule_user_dirs_changed ();
255 desktop_dir_changed ();
258 g_object_unref (location);
259 g_object_unref (dir_location);
262 static void
263 xdg_dir_cache_changed_cb (GFileMonitor *monitor,
264 GFile *file,
265 GFile *other_file,
266 GFileMonitorEvent event_type)
268 if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
269 event_type == G_FILE_MONITOR_EVENT_CREATED) {
270 update_xdg_dir_cache ();
274 static int user_dirs_changed_tag = 0;
276 static gboolean
277 emit_user_dirs_changed_idle (gpointer data)
279 g_signal_emit_by_name (nautilus_signaller_get_current (),
280 "user_dirs_changed");
281 user_dirs_changed_tag = 0;
282 return FALSE;
285 static void
286 schedule_user_dirs_changed (void)
288 if (user_dirs_changed_tag == 0) {
289 user_dirs_changed_tag = g_idle_add (emit_user_dirs_changed_idle, NULL);
293 static void
294 unschedule_user_dirs_changed (void)
296 if (user_dirs_changed_tag != 0) {
297 g_source_remove (user_dirs_changed_tag);
298 user_dirs_changed_tag = 0;
302 static void
303 free_xdg_dir_cache (void)
305 int i;
307 if (cached_xdg_dirs != NULL) {
308 for (i = 0; cached_xdg_dirs[i].type != NULL; i++) {
309 if (cached_xdg_dirs[i].file != NULL) {
310 nautilus_file_monitor_remove (cached_xdg_dirs[i].file,
311 &cached_xdg_dirs[i]);
312 g_signal_handlers_disconnect_by_func (cached_xdg_dirs[i].file,
313 G_CALLBACK (xdg_dir_changed),
314 &cached_xdg_dirs[i]);
315 nautilus_file_unref (cached_xdg_dirs[i].file);
317 g_free (cached_xdg_dirs[i].type);
318 g_free (cached_xdg_dirs[i].path);
320 g_free (cached_xdg_dirs);
324 static void
325 destroy_xdg_dir_cache (void)
327 free_xdg_dir_cache ();
328 unschedule_user_dirs_changed ();
329 desktop_dir_changed ();
331 if (cached_xdg_dirs_monitor != NULL) {
332 g_object_unref (cached_xdg_dirs_monitor);
333 cached_xdg_dirs_monitor = NULL;
337 static void
338 update_xdg_dir_cache (void)
340 GFile *file;
341 char *config_file, *uri;
342 int i;
344 free_xdg_dir_cache ();
345 schedule_user_dirs_changed ();
346 desktop_dir_changed ();
348 cached_xdg_dirs = parse_xdg_dirs (NULL);
350 for (i = 0 ; cached_xdg_dirs[i].type != NULL; i++) {
351 cached_xdg_dirs[i].file = NULL;
352 if (strcmp (cached_xdg_dirs[i].path, g_get_home_dir ()) != 0) {
353 uri = g_filename_to_uri (cached_xdg_dirs[i].path, NULL, NULL);
354 cached_xdg_dirs[i].file = nautilus_file_get_by_uri (uri);
355 nautilus_file_monitor_add (cached_xdg_dirs[i].file,
356 &cached_xdg_dirs[i],
357 NAUTILUS_FILE_ATTRIBUTE_INFO);
358 g_signal_connect (cached_xdg_dirs[i].file,
359 "changed", G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]);
360 g_free (uri);
364 if (cached_xdg_dirs_monitor == NULL) {
365 config_file = g_build_filename (g_get_user_config_dir (),
366 "user-dirs.dirs", NULL);
367 file = g_file_new_for_path (config_file);
368 cached_xdg_dirs_monitor = g_file_monitor_file (file, 0, NULL);
369 g_signal_connect (cached_xdg_dirs_monitor, "changed",
370 G_CALLBACK (xdg_dir_cache_changed_cb), NULL);
371 g_object_unref (file);
372 g_free (config_file);
374 eel_debug_call_at_shutdown (destroy_xdg_dir_cache);
378 char *
379 nautilus_get_xdg_dir (const char *type)
381 int i;
383 if (cached_xdg_dirs == NULL) {
384 update_xdg_dir_cache ();
387 for (i = 0 ; cached_xdg_dirs != NULL && cached_xdg_dirs[i].type != NULL; i++) {
388 if (strcmp (cached_xdg_dirs[i].type, type) == 0) {
389 return g_strdup (cached_xdg_dirs[i].path);
392 if (strcmp ("DESKTOP", type) == 0) {
393 return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL);
395 if (strcmp ("TEMPLATES", type) == 0) {
396 return g_build_filename (g_get_home_dir (), "Templates", NULL);
399 return g_strdup (g_get_home_dir ());
402 static char *
403 get_desktop_path (void)
405 if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR)) {
406 return g_strdup (g_get_home_dir());
407 } else {
408 return nautilus_get_xdg_dir ("DESKTOP");
413 * nautilus_get_desktop_directory:
415 * Get the path for the directory containing files on the desktop.
417 * Return value: the directory path.
419 char *
420 nautilus_get_desktop_directory (void)
422 char *desktop_directory;
424 desktop_directory = get_desktop_path ();
426 /* Don't try to create a home directory */
427 if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR)) {
428 if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS)) {
429 mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE);
430 /* FIXME bugzilla.gnome.org 41286:
431 * How should we handle the case where this mkdir fails?
432 * Note that nautilus_application_startup will refuse to launch if this
433 * directory doesn't get created, so that case is OK. But the directory
434 * could be deleted after Nautilus was launched, and perhaps
435 * there is some bad side-effect of not handling that case.
440 return desktop_directory;
443 GFile *
444 nautilus_get_desktop_location (void)
446 char *desktop_directory;
447 GFile *res;
449 desktop_directory = get_desktop_path ();
451 res = g_file_new_for_path (desktop_directory);
452 g_free (desktop_directory);
453 return res;
458 * nautilus_get_desktop_directory_uri:
460 * Get the uri for the directory containing files on the desktop.
462 * Return value: the directory path.
464 char *
465 nautilus_get_desktop_directory_uri (void)
467 char *desktop_path;
468 char *desktop_uri;
470 desktop_path = nautilus_get_desktop_directory ();
471 desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
472 g_free (desktop_path);
474 return desktop_uri;
477 char *
478 nautilus_get_desktop_directory_uri_no_create (void)
480 char *desktop_path;
481 char *desktop_uri;
483 desktop_path = get_desktop_path ();
484 desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
485 g_free (desktop_path);
487 return desktop_uri;
490 char *
491 nautilus_get_home_directory_uri (void)
493 return g_filename_to_uri (g_get_home_dir (), NULL, NULL);
497 gboolean
498 nautilus_should_use_templates_directory (void)
500 char *dir;
501 gboolean res;
503 dir = nautilus_get_xdg_dir ("TEMPLATES");
504 res = strcmp (dir, g_get_home_dir ()) != 0;
505 g_free (dir);
506 return res;
509 char *
510 nautilus_get_templates_directory (void)
512 return nautilus_get_xdg_dir ("TEMPLATES");
515 void
516 nautilus_create_templates_directory (void)
518 char *dir;
520 dir = nautilus_get_templates_directory ();
521 if (!g_file_test (dir, G_FILE_TEST_EXISTS)) {
522 mkdir (dir, DEFAULT_NAUTILUS_DIRECTORY_MODE);
524 g_free (dir);
527 char *
528 nautilus_get_templates_directory_uri (void)
530 char *directory, *uri;
532 directory = nautilus_get_templates_directory ();
533 uri = g_filename_to_uri (directory, NULL, NULL);
534 g_free (directory);
535 return uri;
538 char *
539 nautilus_get_searches_directory (void)
541 char *user_dir;
542 char *searches_dir;
544 user_dir = nautilus_get_user_directory ();
545 searches_dir = g_build_filename (user_dir, "searches", NULL);
546 g_free (user_dir);
548 if (!g_file_test (searches_dir, G_FILE_TEST_EXISTS))
549 mkdir (searches_dir, DEFAULT_NAUTILUS_DIRECTORY_MODE);
551 return searches_dir;
554 /* These need to be reset to NULL when desktop_is_home_dir changes */
555 static GFile *desktop_dir = NULL;
556 static GFile *desktop_dir_dir = NULL;
557 static char *desktop_dir_filename = NULL;
558 static gboolean desktop_dir_changed_callback_installed = FALSE;
561 static void
562 desktop_dir_changed (void)
564 if (desktop_dir) {
565 g_object_unref (desktop_dir);
567 if (desktop_dir_dir) {
568 g_object_unref (desktop_dir_dir);
570 g_free (desktop_dir_filename);
571 desktop_dir = NULL;
572 desktop_dir_dir = NULL;
573 desktop_dir_filename = NULL;
576 static void
577 desktop_dir_changed_callback (gpointer callback_data)
579 desktop_dir_changed ();
582 static void
583 update_desktop_dir (void)
585 char *path;
586 char *dirname;
588 path = get_desktop_path ();
589 desktop_dir = g_file_new_for_path (path);
591 dirname = g_path_get_dirname (path);
592 desktop_dir_dir = g_file_new_for_path (dirname);
593 g_free (dirname);
594 desktop_dir_filename = g_path_get_basename (path);
595 g_free (path);
598 gboolean
599 nautilus_is_home_directory_file (GFile *dir,
600 const char *filename)
602 char *dirname;
603 static GFile *home_dir_dir = NULL;
604 static char *home_dir_filename = NULL;
606 if (home_dir_dir == NULL) {
607 dirname = g_path_get_dirname (g_get_home_dir ());
608 home_dir_dir = g_file_new_for_path (dirname);
609 g_free (dirname);
610 home_dir_filename = g_path_get_basename (g_get_home_dir ());
613 return (g_file_equal (dir, home_dir_dir) &&
614 strcmp (filename, home_dir_filename) == 0);
617 gboolean
618 nautilus_is_home_directory (GFile *dir)
620 static GFile *home_dir = NULL;
622 if (home_dir == NULL) {
623 home_dir = g_file_new_for_path (g_get_home_dir ());
626 return g_file_equal (dir, home_dir);
629 gboolean
630 nautilus_is_root_directory (GFile *dir)
632 static GFile *root_dir = NULL;
634 if (root_dir == NULL) {
635 root_dir = g_file_new_for_path ("/");
638 return g_file_equal (dir, root_dir);
642 gboolean
643 nautilus_is_desktop_directory_file (GFile *dir,
644 const char *file)
647 if (!desktop_dir_changed_callback_installed) {
648 eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
649 desktop_dir_changed_callback,
650 NULL);
651 desktop_dir_changed_callback_installed = TRUE;
654 if (desktop_dir == NULL) {
655 update_desktop_dir ();
658 return (g_file_equal (dir, desktop_dir_dir) &&
659 strcmp (file, desktop_dir_filename) == 0);
662 gboolean
663 nautilus_is_desktop_directory (GFile *dir)
666 if (!desktop_dir_changed_callback_installed) {
667 eel_preferences_add_callback (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
668 desktop_dir_changed_callback,
669 NULL);
670 desktop_dir_changed_callback_installed = TRUE;
673 if (desktop_dir == NULL) {
674 update_desktop_dir ();
677 return g_file_equal (dir, desktop_dir);
682 * nautilus_get_gmc_desktop_directory:
684 * Get the path for the directory containing the legacy gmc desktop.
686 * Return value: the directory path.
688 char *
689 nautilus_get_gmc_desktop_directory (void)
691 return g_build_filename (g_get_home_dir (), LEGACY_DESKTOP_DIRECTORY_NAME, NULL);
695 * nautilus_get_pixmap_directory
697 * Get the path for the directory containing Nautilus pixmaps.
699 * Return value: the directory path.
701 char *
702 nautilus_get_pixmap_directory (void)
704 return g_strdup (DATADIR "/pixmaps/nautilus");
707 /* FIXME bugzilla.gnome.org 42423:
708 * Callers just use this and dereference so we core dump if
709 * pixmaps are missing. That is lame.
711 char *
712 nautilus_pixmap_file (const char *partial_path)
714 char *path;
716 path = g_build_filename (DATADIR "/pixmaps/nautilus", partial_path, NULL);
717 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
718 return path;
719 } else {
720 char *tmp;
721 tmp = nautilus_get_pixmap_directory ();
722 g_debug ("Failed to locate \"%s\" in Nautilus pixmap path \"%s\". Incomplete installation?", partial_path, tmp);
723 g_free (tmp);
725 g_free (path);
726 return NULL;
729 char *
730 nautilus_get_data_file_path (const char *partial_path)
732 char *path;
733 char *user_directory;
735 /* first try the user's home directory */
736 user_directory = nautilus_get_user_directory ();
737 path = g_build_filename (user_directory, partial_path, NULL);
738 g_free (user_directory);
739 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
740 return path;
742 g_free (path);
744 /* next try the shared directory */
745 path = g_build_filename (NAUTILUS_DATADIR, partial_path, NULL);
746 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
747 return path;
749 g_free (path);
751 return NULL;
754 char *
755 nautilus_ensure_unique_file_name (const char *directory_uri,
756 const char *base_name,
757 const char *extension)
759 GFileInfo *info;
760 char *filename;
761 GFile *dir, *child;
762 int copy;
763 char *res;
765 dir = g_file_new_for_uri (directory_uri);
767 info = g_file_query_info (dir, G_FILE_ATTRIBUTE_STD_TYPE, 0, NULL, NULL);
768 if (info == NULL) {
769 g_object_unref (dir);
770 return NULL;
772 g_object_unref (info);
774 filename = g_strdup_printf ("%s%s",
775 base_name,
776 extension);
777 child = g_file_get_child (dir, filename);
778 g_free (filename);
780 copy = 1;
781 while ((info = g_file_query_info (child, G_FILE_ATTRIBUTE_STD_TYPE, 0, NULL, NULL)) != NULL) {
782 g_object_unref (info);
783 g_object_unref (child);
785 filename = g_strdup_printf ("%s-%d%s",
786 base_name,
787 copy,
788 extension);
789 child = g_file_get_child (dir, filename);
790 g_free (filename);
792 copy++;
795 res = g_file_get_uri (child);
796 g_object_unref (child);
797 g_object_unref (dir);
799 return res;
802 char *
803 nautilus_unique_temporary_file_name (void)
805 const char *prefix = "/tmp/nautilus-temp-file";
806 char *file_name;
807 int fd;
809 file_name = g_strdup_printf ("%sXXXXXX", prefix);
811 fd = mkstemp (file_name);
812 if (fd == -1) {
813 g_free (file_name);
814 file_name = NULL;
815 } else {
816 close (fd);
819 return file_name;
822 GFile *
823 nautilus_find_existing_uri_in_hierarchy (GFile *location)
825 GFileInfo *info;
826 GFile *tmp;
828 g_assert (location != NULL);
830 location = g_object_ref (location);
831 while (location != NULL) {
832 info = g_file_query_info (location,
833 "std:name",
834 0, NULL, NULL);
835 g_object_unref (info);
836 if (info != NULL) {
837 return location;
839 tmp = location;
840 location = g_file_get_parent (location);
841 g_object_unref (tmp);
844 return location;
847 #if !defined (NAUTILUS_OMIT_SELF_CHECK)
849 void
850 nautilus_self_check_file_utilities (void)
854 #endif /* !NAUTILUS_OMIT_SELF_CHECK */