No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* nautilus-file-utilities.c - implementation of file manipulation routines.
4
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6
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.
11
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.
16
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.
21
22 Authors: John Sullivan <sullivan@eazel.com>
23 */
24
25 #include <config.h>
26 #include "nautilus-file-utilities.h"
27
28 #include "nautilus-global-preferences.h"
29 #include "nautilus-icon-names.h"
30 #include "nautilus-lib-self-check-functions.h"
31 #include "nautilus-metadata.h"
32 #include "nautilus-file.h"
33 #include "nautilus-file-operations.h"
34 #include "nautilus-search-directory.h"
35 #include "nautilus-signaller.h"
36 #include <eel/eel-glib-extensions.h>
37 #include <eel/eel-stock-dialogs.h>
38 #include <eel/eel-string.h>
39 #include <eel/eel-debug.h>
40 #include <glib.h>
41 #include <glib/gi18n.h>
42 #include <glib/gstdio.h>
43 #include <gio/gio.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46
47 #define NAUTILUS_USER_DIRECTORY_NAME "nautilus"
48 #define DEFAULT_NAUTILUS_DIRECTORY_MODE (0755)
49
50 #define DESKTOP_DIRECTORY_NAME "Desktop"
51 #define LEGACY_DESKTOP_DIRECTORY_NAME ".gnome-desktop"
52 #define DEFAULT_DESKTOP_DIRECTORY_MODE (0755)
53
54 static void update_xdg_dir_cache (void);
55 static void schedule_user_dirs_changed (void);
56 static void desktop_dir_changed (void);
57
58
59 /* Allowed characters outside alphanumeric for unreserved. */
60 #define G_URI_OTHER_UNRESERVED "-._~"
61
62 /* This or something equivalent will eventually go into glib/guri.h */
63 gboolean
64 nautilus_uri_parse (const char *uri,
65 char **host,
66 guint16 *port,
67 char **userinfo)
68 {
69 char *tmp_str;
70 const char *start, *p;
71 char c;
72
73 g_return_val_if_fail (uri != NULL, FALSE);
74
75 if (host)
76 *host = NULL;
77
78 if (port)
79 *port = 0;
80
81 if (userinfo)
82 *userinfo = NULL;
83
84 /* From RFC 3986 Decodes:
85 * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
86 * hier-part = "//" authority path-abempty
87 * path-abempty = *( "/" segment )
88 * authority = [ userinfo "@" ] host [ ":" port ]
89 */
90
91 /* Check we have a valid scheme */
92 tmp_str = g_uri_parse_scheme (uri);
93
94 if (tmp_str == NULL)
95 return FALSE;
96
97 g_free (tmp_str);
98
99 /* Decode hier-part:
100 * hier-part = "//" authority path-abempty
101 */
102 p = uri;
103 start = strstr (p, "//");
104
105 if (start == NULL)
106 return FALSE;
107
108 start += 2;
109
110 if (strchr (start, '@') != NULL)
111 {
112 /* Decode userinfo:
113 * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
114 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
115 * pct-encoded = "%" HEXDIG HEXDIG
116 */
117 p = start;
118 while (1)
119 {
120 c = *p++;
121
122 if (c == '@')
123 break;
124
125 /* pct-encoded */
126 if (c == '%')
127 {
128 if (!(g_ascii_isxdigit (p[0]) ||
129 g_ascii_isxdigit (p[1])))
130 return FALSE;
131
132 p++;
133
134 continue;
135 }
136
137 /* unreserved / sub-delims / : */
138 if (!(g_ascii_isalnum (c) ||
139 strchr (G_URI_OTHER_UNRESERVED, c) ||
140 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
141 c == ':'))
142 return FALSE;
143 }
144
145 if (userinfo)
146 *userinfo = g_strndup (start, p - start - 1);
147
148 start = p;
149 }
150 else
151 {
152 p = start;
153 }
154
155
156 /* decode host:
157 * host = IP-literal / IPv4address / reg-name
158 * reg-name = *( unreserved / pct-encoded / sub-delims )
159 */
160
161 /* If IPv6 or IPvFuture */
162 if (*p == '[')
163 {
164 start++;
165 p++;
166 while (1)
167 {
168 c = *p++;
169
170 if (c == ']')
171 break;
172
173 /* unreserved / sub-delims */
174 if (!(g_ascii_isalnum (c) ||
175 strchr (G_URI_OTHER_UNRESERVED, c) ||
176 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
177 c == ':' ||
178 c == '.'))
179 goto error;
180 }
181 }
182 else
183 {
184 while (1)
185 {
186 c = *p++;
187
188 if (c == ':' ||
189 c == '/' ||
190 c == '?' ||
191 c == '#' ||
192 c == '\0')
193 break;
194
195 /* pct-encoded */
196 if (c == '%')
197 {
198 if (!(g_ascii_isxdigit (p[0]) ||
199 g_ascii_isxdigit (p[1])))
200 goto error;
201
202 p++;
203
204 continue;
205 }
206
207 /* unreserved / sub-delims */
208 if (!(g_ascii_isalnum (c) ||
209 strchr (G_URI_OTHER_UNRESERVED, c) ||
210 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c)))
211 goto error;
212 }
213 }
214
215 if (host)
216 *host = g_uri_unescape_segment (start, p - 1, NULL);
217
218 if (c == ':')
219 {
220 /* Decode pot:
221 * port = *DIGIT
222 */
223 guint tmp = 0;
224
225 while (1)
226 {
227 c = *p++;
228
229 if (c == '/' ||
230 c == '?' ||
231 c == '#' ||
232 c == '\0')
233 break;
234
235 if (!g_ascii_isdigit (c))
236 goto error;
237
238 tmp = (tmp * 10) + (c - '0');
239
240 if (tmp > 65535)
241 goto error;
242 }
243 if (port)
244 *port = (guint16) tmp;
245 }
246
247 return TRUE;
248
249 error:
250 if (host && *host)
251 {
252 g_free (*host);
253 *host = NULL;
254 }
255
256 if (userinfo && *userinfo)
257 {
258 g_free (*userinfo);
259 *userinfo = NULL;
260 }
261
262 return FALSE;
263 }
264
265 char *
266 nautilus_compute_title_for_location (GFile *location)
267 {
268 NautilusFile *file;
269 char *title;
270
271 /* TODO-gio: This doesn't really work all that great if the
272 info about the file isn't known atm... */
273
274 if (nautilus_is_home_directory (location)) {
275 return g_strdup (_("Home"));
276 }
277
278 title = NULL;
279 if (location) {
280 file = nautilus_file_get (location);
281 title = nautilus_file_get_description (file);
282 if (title == NULL) {
283 title = nautilus_file_get_display_name (file);
284 }
285 nautilus_file_unref (file);
286 }
287
288 if (title == NULL) {
289 title = g_file_get_basename (location);
290 }
291
292 return title;
293 }
294
295
296 /**
297 * nautilus_get_user_directory:
298 *
299 * Get the path for the directory containing nautilus settings.
300 *
301 * Return value: the directory path.
302 **/
303 char *
304 nautilus_get_user_directory (void)
305 {
306 char *user_directory = NULL;
307
308 user_directory = g_build_filename (g_get_user_config_dir (),
309 NAUTILUS_USER_DIRECTORY_NAME,
310 NULL);
311
312 if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) {
313 g_mkdir (user_directory, DEFAULT_NAUTILUS_DIRECTORY_MODE);
314 /* FIXME bugzilla.gnome.org 41286:
315 * How should we handle the case where this mkdir fails?
316 * Note that nautilus_application_startup will refuse to launch if this
317 * directory doesn't get created, so that case is OK. But the directory
318 * could be deleted after Nautilus was launched, and perhaps
319 * there is some bad side-effect of not handling that case.
320 */
321 }
322
323 return user_directory;
324 }
325
326 /**
327 * nautilus_get_accel_map_file:
328 *
329 * Get the path for the filename containing nautilus accelerator map.
330 * The filename need not exist.
331 *
332 * Return value: the filename path
333 **/
334 char *
335 nautilus_get_accel_map_file (void)
336 {
337 return g_build_filename (g_get_user_config_dir (), "nautilus", "accels", NULL);
338 }
339
340 /**
341 * nautilus_get_scripts_directory_path:
342 *
343 * Get the path for the directory containing nautilus scripts.
344 *
345 * Return value: the directory path containing nautilus scripts
346 **/
347 char *
348 nautilus_get_scripts_directory_path (void)
349 {
350 return g_build_filename (g_get_user_data_dir (), "nautilus", "scripts", NULL);
351 }
352
353 typedef struct {
354 char *type;
355 char *path;
356 NautilusFile *file;
357 } XdgDirEntry;
358
359
360 static XdgDirEntry *
361 parse_xdg_dirs (const char *config_file)
362 {
363 GArray *array;
364 char *config_file_free = NULL;
365 XdgDirEntry dir;
366 char *data;
367 char **lines;
368 char *p, *d;
369 int i;
370 char *type_start, *type_end;
371 char *value, *unescaped;
372 gboolean relative;
373
374 array = g_array_new (TRUE, TRUE, sizeof (XdgDirEntry));
375
376 if (config_file == NULL)
377 {
378 config_file_free = g_build_filename (g_get_user_config_dir (),
379 "user-dirs.dirs", NULL);
380 config_file = (const char *)config_file_free;
381 }
382
383 if (g_file_get_contents (config_file, &data, NULL, NULL))
384 {
385 lines = g_strsplit (data, "\n", 0);
386 g_free (data);
387 for (i = 0; lines[i] != NULL; i++)
388 {
389 p = lines[i];
390 while (g_ascii_isspace (*p))
391 p++;
392
393 if (*p == '#')
394 continue;
395
396 value = strchr (p, '=');
397 if (value == NULL)
398 continue;
399 *value++ = 0;
400
401 g_strchug (g_strchomp (p));
402 if (!g_str_has_prefix (p, "XDG_"))
403 continue;
404 if (!g_str_has_suffix (p, "_DIR"))
405 continue;
406 type_start = p + 4;
407 type_end = p + strlen (p) - 4;
408
409 while (g_ascii_isspace (*value))
410 value++;
411
412 if (*value != '"')
413 continue;
414 value++;
415
416 relative = FALSE;
417 if (g_str_has_prefix (value, "$HOME"))
418 {
419 relative = TRUE;
420 value += 5;
421 while (*value == '/')
422 value++;
423 }
424 else if (*value != '/')
425 continue;
426
427 d = unescaped = g_malloc (strlen (value) + 1);
428 while (*value && *value != '"')
429 {
430 if ((*value == '\\') && (*(value + 1) != 0))
431 value++;
432 *d++ = *value++;
433 }
434 *d = 0;
435
436 *type_end = 0;
437 dir.type = g_strdup (type_start);
438 if (relative)
439 {
440 dir.path = g_build_filename (g_get_home_dir (), unescaped, NULL);
441 g_free (unescaped);
442 }
443 else
444 dir.path = unescaped;
445
446 g_array_append_val (array, dir);
447 }
448
449 g_strfreev (lines);
450 }
451
452 g_free (config_file_free);
453
454 return (XdgDirEntry *)g_array_free (array, FALSE);
455 }
456
457 static XdgDirEntry *cached_xdg_dirs = NULL;
458 static GFileMonitor *cached_xdg_dirs_monitor = NULL;
459
460 static void
461 xdg_dir_changed (NautilusFile *file,
462 XdgDirEntry *dir)
463 {
464 GFile *location, *dir_location;
465 char *path;
466
467 location = nautilus_file_get_location (file);
468 dir_location = g_file_new_for_path (dir->path);
469 if (!g_file_equal (location, dir_location)) {
470 path = g_file_get_path (location);
471
472 if (path) {
473 char *argv[5];
474 int i;
475
476 g_free (dir->path);
477 dir->path = path;
478
479 i = 0;
480 argv[i++] = "xdg-user-dirs-update";
481 argv[i++] = "--set";
482 argv[i++] = dir->type;
483 argv[i++] = dir->path;
484 argv[i++] = NULL;
485
486 /* We do this sync, to avoid possible race-conditions
487 if multiple dirs change at the same time. Its
488 blocking the main thread, but these updates should
489 be very rare and very fast. */
490 g_spawn_sync (NULL,
491 argv, NULL,
492 G_SPAWN_SEARCH_PATH |
493 G_SPAWN_STDOUT_TO_DEV_NULL |
494 G_SPAWN_STDERR_TO_DEV_NULL,
495 NULL, NULL,
496 NULL, NULL, NULL, NULL);
497 g_reload_user_special_dirs_cache ();
498 schedule_user_dirs_changed ();
499 desktop_dir_changed ();
500 /* Icon might have changed */
501 nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_INFO);
502 }
503 }
504 g_object_unref (location);
505 g_object_unref (dir_location);
506 }
507
508 static void
509 xdg_dir_cache_changed_cb (GFileMonitor *monitor,
510 GFile *file,
511 GFile *other_file,
512 GFileMonitorEvent event_type)
513 {
514 if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
515 event_type == G_FILE_MONITOR_EVENT_CREATED) {
516 update_xdg_dir_cache ();
517 }
518 }
519
520 static int user_dirs_changed_tag = 0;
521
522 static gboolean
523 emit_user_dirs_changed_idle (gpointer data)
524 {
525 g_signal_emit_by_name (nautilus_signaller_get_current (),
526 "user_dirs_changed");
527 user_dirs_changed_tag = 0;
528 return FALSE;
529 }
530
531 static void
532 schedule_user_dirs_changed (void)
533 {
534 if (user_dirs_changed_tag == 0) {
535 user_dirs_changed_tag = g_idle_add (emit_user_dirs_changed_idle, NULL);
536 }
537 }
538
539 static void
540 unschedule_user_dirs_changed (void)
541 {
542 if (user_dirs_changed_tag != 0) {
543 g_source_remove (user_dirs_changed_tag);
544 user_dirs_changed_tag = 0;
545 }
546 }
547
548 static void
549 free_xdg_dir_cache (void)
550 {
551 int i;
552
553 if (cached_xdg_dirs != NULL) {
554 for (i = 0; cached_xdg_dirs[i].type != NULL; i++) {
555 if (cached_xdg_dirs[i].file != NULL) {
556 nautilus_file_monitor_remove (cached_xdg_dirs[i].file,
557 &cached_xdg_dirs[i]);
558 g_signal_handlers_disconnect_by_func (cached_xdg_dirs[i].file,
559 G_CALLBACK (xdg_dir_changed),
560 &cached_xdg_dirs[i]);
561 nautilus_file_unref (cached_xdg_dirs[i].file);
562 }
563 g_free (cached_xdg_dirs[i].type);
564 g_free (cached_xdg_dirs[i].path);
565 }
566 g_free (cached_xdg_dirs);
567 }
568 }
569
570 static void
571 destroy_xdg_dir_cache (void)
572 {
573 free_xdg_dir_cache ();
574 unschedule_user_dirs_changed ();
575 desktop_dir_changed ();
576
577 if (cached_xdg_dirs_monitor != NULL) {
578 g_object_unref (cached_xdg_dirs_monitor);
579 cached_xdg_dirs_monitor = NULL;
580 }
581 }
582
583 static void
584 update_xdg_dir_cache (void)
585 {
586 GFile *file;
587 char *config_file, *uri;
588 int i;
589
590 free_xdg_dir_cache ();
591 g_reload_user_special_dirs_cache ();
592 schedule_user_dirs_changed ();
593 desktop_dir_changed ();
594
595 cached_xdg_dirs = parse_xdg_dirs (NULL);
596
597 for (i = 0 ; cached_xdg_dirs[i].type != NULL; i++) {
598 cached_xdg_dirs[i].file = NULL;
599 if (strcmp (cached_xdg_dirs[i].path, g_get_home_dir ()) != 0) {
600 uri = g_filename_to_uri (cached_xdg_dirs[i].path, NULL, NULL);
601 cached_xdg_dirs[i].file = nautilus_file_get_by_uri (uri);
602 nautilus_file_monitor_add (cached_xdg_dirs[i].file,
603 &cached_xdg_dirs[i],
604 NAUTILUS_FILE_ATTRIBUTE_INFO);
605 g_signal_connect (cached_xdg_dirs[i].file,
606 "changed", G_CALLBACK (xdg_dir_changed), &cached_xdg_dirs[i]);
607 g_free (uri);
608 }
609 }
610
611 if (cached_xdg_dirs_monitor == NULL) {
612 config_file = g_build_filename (g_get_user_config_dir (),
613 "user-dirs.dirs", NULL);
614 file = g_file_new_for_path (config_file);
615 cached_xdg_dirs_monitor = g_file_monitor_file (file, 0, NULL, NULL);
616 g_signal_connect (cached_xdg_dirs_monitor, "changed",
617 G_CALLBACK (xdg_dir_cache_changed_cb), NULL);
618 g_object_unref (file);
619 g_free (config_file);
620
621 eel_debug_call_at_shutdown (destroy_xdg_dir_cache);
622 }
623 }
624
625 char *
626 nautilus_get_xdg_dir (const char *type)
627 {
628 int i;
629
630 if (cached_xdg_dirs == NULL) {
631 update_xdg_dir_cache ();
632 }
633
634 for (i = 0 ; cached_xdg_dirs != NULL && cached_xdg_dirs[i].type != NULL; i++) {
635 if (strcmp (cached_xdg_dirs[i].type, type) == 0) {
636 return g_strdup (cached_xdg_dirs[i].path);
637 }
638 }
639 if (strcmp ("DESKTOP", type) == 0) {
640 return g_build_filename (g_get_home_dir (), DESKTOP_DIRECTORY_NAME, NULL);
641 }
642 if (strcmp ("TEMPLATES", type) == 0) {
643 return g_build_filename (g_get_home_dir (), "Templates", NULL);
644 }
645
646 return g_strdup (g_get_home_dir ());
647 }
648
649 static char *
650 get_desktop_path (void)
651 {
652 return nautilus_get_xdg_dir ("DESKTOP");
653 }
654
655 /**
656 * nautilus_get_desktop_directory:
657 *
658 * Get the path for the directory containing files on the desktop.
659 *
660 * Return value: the directory path.
661 **/
662 char *
663 nautilus_get_desktop_directory (void)
664 {
665 char *desktop_directory;
666
667 desktop_directory = get_desktop_path ();
668
669 /* Don't try to create a home directory */
670 if (!g_file_test (desktop_directory, G_FILE_TEST_EXISTS)) {
671 g_mkdir (desktop_directory, DEFAULT_DESKTOP_DIRECTORY_MODE);
672 /* FIXME bugzilla.gnome.org 41286:
673 * How should we handle the case where this mkdir fails?
674 * Note that nautilus_application_startup will refuse to launch if this
675 * directory doesn't get created, so that case is OK. But the directory
676 * could be deleted after Nautilus was launched, and perhaps
677 * there is some bad side-effect of not handling that case.
678 */
679 }
680
681 return desktop_directory;
682 }
683
684 GFile *
685 nautilus_get_desktop_location (void)
686 {
687 char *desktop_directory;
688 GFile *res;
689
690 desktop_directory = get_desktop_path ();
691
692 res = g_file_new_for_path (desktop_directory);
693 g_free (desktop_directory);
694 return res;
695 }
696
697 /**
698 * nautilus_get_desktop_directory_uri:
699 *
700 * Get the uri for the directory containing files on the desktop.
701 *
702 * Return value: the directory path.
703 **/
704 char *
705 nautilus_get_desktop_directory_uri (void)
706 {
707 char *desktop_path;
708 char *desktop_uri;
709
710 desktop_path = nautilus_get_desktop_directory ();
711 desktop_uri = g_filename_to_uri (desktop_path, NULL, NULL);
712 g_free (desktop_path);
713
714 return desktop_uri;
715 }
716
717 char *
718 nautilus_get_home_directory_uri (void)
719 {
720 return g_filename_to_uri (g_get_home_dir (), NULL, NULL);
721 }
722
723
724 gboolean
725 nautilus_should_use_templates_directory (void)
726 {
727 char *dir;
728 gboolean res;
729
730 dir = nautilus_get_xdg_dir ("TEMPLATES");
731 res = strcmp (dir, g_get_home_dir ()) != 0;
732 g_free (dir);
733 return res;
734 }
735
736 char *
737 nautilus_get_templates_directory (void)
738 {
739 return nautilus_get_xdg_dir ("TEMPLATES");
740 }
741
742 void
743 nautilus_create_templates_directory (void)
744 {
745 char *dir;
746
747 dir = nautilus_get_templates_directory ();
748 if (!g_file_test (dir, G_FILE_TEST_EXISTS)) {
749 g_mkdir (dir, DEFAULT_NAUTILUS_DIRECTORY_MODE);
750 }
751 g_free (dir);
752 }
753
754 char *
755 nautilus_get_templates_directory_uri (void)
756 {
757 char *directory, *uri;
758
759 directory = nautilus_get_templates_directory ();
760 uri = g_filename_to_uri (directory, NULL, NULL);
761 g_free (directory);
762 return uri;
763 }
764
765 char *
766 nautilus_get_searches_directory (void)
767 {
768 char *user_dir;
769 char *searches_dir;
770
771 user_dir = nautilus_get_user_directory ();
772 searches_dir = g_build_filename (user_dir, "searches", NULL);
773 g_free (user_dir);
774
775 if (!g_file_test (searches_dir, G_FILE_TEST_EXISTS))
776 g_mkdir (searches_dir, DEFAULT_NAUTILUS_DIRECTORY_MODE);
777
778 return searches_dir;
779 }
780
781 /* These need to be reset to NULL when desktop_is_home_dir changes */
782 static GFile *desktop_dir = NULL;
783 static GFile *desktop_dir_dir = NULL;
784 static char *desktop_dir_filename = NULL;
785
786
787 static void
788 desktop_dir_changed (void)
789 {
790 if (desktop_dir) {
791 g_object_unref (desktop_dir);
792 }
793 if (desktop_dir_dir) {
794 g_object_unref (desktop_dir_dir);
795 }
796 g_free (desktop_dir_filename);
797 desktop_dir = NULL;
798 desktop_dir_dir = NULL;
799 desktop_dir_filename = NULL;
800 }
801
802 static void
803 update_desktop_dir (void)
804 {
805 char *path;
806 char *dirname;
807
808 path = get_desktop_path ();
809 desktop_dir = g_file_new_for_path (path);
810
811 dirname = g_path_get_dirname (path);
812 desktop_dir_dir = g_file_new_for_path (dirname);
813 g_free (dirname);
814 desktop_dir_filename = g_path_get_basename (path);
815 g_free (path);
816 }
817
818 gboolean
819 nautilus_is_home_directory_file (GFile *dir,
820 const char *filename)
821 {
822 char *dirname;
823 static GFile *home_dir_dir = NULL;
824 static char *home_dir_filename = NULL;
825
826 if (home_dir_dir == NULL) {
827 dirname = g_path_get_dirname (g_get_home_dir ());
828 home_dir_dir = g_file_new_for_path (dirname);
829 g_free (dirname);
830 home_dir_filename = g_path_get_basename (g_get_home_dir ());
831 }
832
833 return (g_file_equal (dir, home_dir_dir) &&
834 strcmp (filename, home_dir_filename) == 0);
835 }
836
837 gboolean
838 nautilus_is_home_directory (GFile *dir)
839 {
840 static GFile *home_dir = NULL;
841
842 if (home_dir == NULL) {
843 home_dir = g_file_new_for_path (g_get_home_dir ());
844 }
845
846 return g_file_equal (dir, home_dir);
847 }
848
849 gboolean
850 nautilus_is_root_directory (GFile *dir)
851 {
852 static GFile *root_dir = NULL;
853
854 if (root_dir == NULL) {
855 root_dir = g_file_new_for_path ("/");
856 }
857
858 return g_file_equal (dir, root_dir);
859 }
860
861
862 gboolean
863 nautilus_is_desktop_directory_file (GFile *dir,
864 const char *file)
865 {
866
867 if (desktop_dir == NULL) {
868 update_desktop_dir ();
869 }
870
871 return (g_file_equal (dir, desktop_dir_dir) &&
872 strcmp (file, desktop_dir_filename) == 0);
873 }
874
875 gboolean
876 nautilus_is_desktop_directory (GFile *dir)
877 {
878
879 if (desktop_dir == NULL) {
880 update_desktop_dir ();
881 }
882
883 return g_file_equal (dir, desktop_dir);
884 }
885
886 GMount *
887 nautilus_get_mounted_mount_for_root (GFile *location)
888 {
889 GVolumeMonitor *volume_monitor;
890 GList *mounts;
891 GList *l;
892 GMount *mount;
893 GMount *result = NULL;
894 GFile *root = NULL;
895 GFile *default_location = NULL;
896
897 volume_monitor = g_volume_monitor_get ();
898 mounts = g_volume_monitor_get_mounts (volume_monitor);
899
900 for (l = mounts; l != NULL; l = l->next) {
901 mount = l->data;
902
903 if (g_mount_is_shadowed (mount)) {
904 continue;
905 }
906
907 root = g_mount_get_root (mount);
908 if (g_file_equal (location, root)) {
909 result = g_object_ref (mount);
910 break;
911 }
912
913 default_location = g_mount_get_default_location (mount);
914 if (!g_file_equal (default_location, root) &&
915 g_file_equal (location, default_location)) {
916 result = g_object_ref (mount);
917 break;
918 }
919 }
920
921 g_clear_object (&root);
922 g_clear_object (&default_location);
923 g_list_free_full (mounts, g_object_unref);
924
925 return result;
926 }
927
928 char *
929 nautilus_ensure_unique_file_name (const char *directory_uri,
930 const char *base_name,
931 const char *extension)
932 {
933 GFileInfo *info;
934 char *filename;
935 GFile *dir, *child;
936 int copy;
937 char *res;
938
939 dir = g_file_new_for_uri (directory_uri);
940
941 info = g_file_query_info (dir, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL);
942 if (info == NULL) {
943 g_object_unref (dir);
944 return NULL;
945 }
946 g_object_unref (info);
947
948 filename = g_strdup_printf ("%s%s",
949 base_name,
950 extension);
951 child = g_file_get_child (dir, filename);
952 g_free (filename);
953
954 copy = 1;
955 while ((info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL)) != NULL) {
956 g_object_unref (info);
957 g_object_unref (child);
958
959 filename = g_strdup_printf ("%s-%d%s",
960 base_name,
961 copy,
962 extension);
963 child = g_file_get_child (dir, filename);
964 g_free (filename);
965
966 copy++;
967 }
968
969 res = g_file_get_uri (child);
970 g_object_unref (child);
971 g_object_unref (dir);
972
973 return res;
974 }
975
976 GFile *
977 nautilus_find_existing_uri_in_hierarchy (GFile *location)
978 {
979 GFileInfo *info;
980 GFile *tmp;
981
982 g_assert (location != NULL);
983
984 location = g_object_ref (location);
985 while (location != NULL) {
986 info = g_file_query_info (location,
987 G_FILE_ATTRIBUTE_STANDARD_NAME,
988 0, NULL, NULL);
989 g_object_unref (info);
990 if (info != NULL) {
991 return location;
992 }
993 tmp = location;
994 location = g_file_get_parent (location);
995 g_object_unref (tmp);
996 }
997
998 return location;
999 }
1000
1001 static gboolean
1002 have_program_in_path (const char *name)
1003 {
1004 gchar *path;
1005 gboolean result;
1006
1007 path = g_find_program_in_path (name);
1008 result = (path != NULL);
1009 g_free (path);
1010 return result;
1011 }
1012
1013 static GIcon *
1014 special_directory_get_icon (GUserDirectory directory,
1015 gboolean symbolic)
1016 {
1017
1018 #define ICON_CASE(x) \
1019 case G_USER_DIRECTORY_ ## x: \
1020 return (symbolic) ? g_themed_icon_new (NAUTILUS_ICON_FOLDER_ ## x) : g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER_ ## x);
1021
1022 switch (directory) {
1023
1024 ICON_CASE (DOCUMENTS);
1025 ICON_CASE (DOWNLOAD);
1026 ICON_CASE (MUSIC);
1027 ICON_CASE (PICTURES);
1028 ICON_CASE (PUBLIC_SHARE);
1029 ICON_CASE (TEMPLATES);
1030 ICON_CASE (VIDEOS);
1031
1032 default:
1033 return (symbolic) ? g_themed_icon_new (NAUTILUS_ICON_FOLDER) : g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER);
1034 }
1035
1036 #undef ICON_CASE
1037 }
1038
1039 GIcon *
1040 nautilus_special_directory_get_symbolic_icon (GUserDirectory directory)
1041 {
1042 return special_directory_get_icon (directory, TRUE);
1043 }
1044
1045 GIcon *
1046 nautilus_special_directory_get_icon (GUserDirectory directory)
1047 {
1048 return special_directory_get_icon (directory, FALSE);
1049 }
1050
1051 gboolean
1052 nautilus_is_file_roller_installed (void)
1053 {
1054 static int installed = - 1;
1055
1056 if (installed < 0) {
1057 if (have_program_in_path ("file-roller")) {
1058 installed = 1;
1059 } else {
1060 installed = 0;
1061 }
1062 }
1063
1064 return installed > 0 ? TRUE : FALSE;
1065 }
1066
1067 /* Returns TRUE if the file is in XDG_DATA_DIRS. This is used for
1068 deciding if a desktop file is "trusted" based on the path */
1069 gboolean
1070 nautilus_is_in_system_dir (GFile *file)
1071 {
1072 const char * const * data_dirs;
1073 char *path;
1074 int i;
1075 gboolean res;
1076
1077 if (!g_file_is_native (file)) {
1078 return FALSE;
1079 }
1080
1081 path = g_file_get_path (file);
1082
1083 res = FALSE;
1084
1085 data_dirs = g_get_system_data_dirs ();
1086 for (i = 0; path != NULL && data_dirs[i] != NULL; i++) {
1087 if (g_str_has_prefix (path, data_dirs[i])) {
1088 res = TRUE;
1089 break;
1090 }
1091
1092 }
1093
1094 g_free (path);
1095
1096 return res;
1097 }
1098
1099 GHashTable *
1100 nautilus_trashed_files_get_original_directories (GList *files,
1101 GList **unhandled_files)
1102 {
1103 GHashTable *directories;
1104 NautilusFile *file, *original_file, *original_dir;
1105 GList *l, *m;
1106
1107 directories = NULL;
1108
1109 if (unhandled_files != NULL) {
1110 *unhandled_files = NULL;
1111 }
1112
1113 for (l = files; l != NULL; l = l->next) {
1114 file = NAUTILUS_FILE (l->data);
1115 original_file = nautilus_file_get_trash_original_file (file);
1116
1117 original_dir = NULL;
1118 if (original_file != NULL) {
1119 original_dir = nautilus_file_get_parent (original_file);
1120 }
1121
1122 if (original_dir != NULL) {
1123 if (directories == NULL) {
1124 directories = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1125 (GDestroyNotify) nautilus_file_unref,
1126 (GDestroyNotify) nautilus_file_list_free);
1127 }
1128 nautilus_file_ref (original_dir);
1129 m = g_hash_table_lookup (directories, original_dir);
1130 if (m != NULL) {
1131 g_hash_table_steal (directories, original_dir);
1132 nautilus_file_unref (original_dir);
1133 }
1134 m = g_list_append (m, nautilus_file_ref (file));
1135 g_hash_table_insert (directories, original_dir, m);
1136 } else if (unhandled_files != NULL) {
1137 *unhandled_files = g_list_append (*unhandled_files, nautilus_file_ref (file));
1138 }
1139
1140 if (original_file != NULL) {
1141 nautilus_file_unref (original_file);
1142 }
1143
1144 if (original_dir != NULL) {
1145 nautilus_file_unref (original_dir);
1146 }
1147 }
1148
1149 return directories;
1150 }
1151
1152 static GList *
1153 locations_from_file_list (GList *file_list)
1154 {
1155 NautilusFile *file;
1156 GList *l, *ret;
1157
1158 ret = NULL;
1159
1160 for (l = file_list; l != NULL; l = l->next) {
1161 file = NAUTILUS_FILE (l->data);
1162 ret = g_list_prepend (ret, nautilus_file_get_location (file));
1163 }
1164
1165 return g_list_reverse (ret);
1166 }
1167
1168 void
1169 nautilus_restore_files_from_trash (GList *files,
1170 GtkWindow *parent_window)
1171 {
1172 NautilusFile *file, *original_dir;
1173 GHashTable *original_dirs_hash;
1174 GList *original_dirs, *unhandled_files;
1175 GFile *original_dir_location;
1176 GList *locations, *l;
1177 char *message, *file_name;
1178
1179 original_dirs_hash = nautilus_trashed_files_get_original_directories (files, &unhandled_files);
1180
1181 for (l = unhandled_files; l != NULL; l = l->next) {
1182 file = NAUTILUS_FILE (l->data);
1183 file_name = nautilus_file_get_display_name (file);
1184 message = g_strdup_printf (_("Could not determine original location of â%sâ "), file_name);
1185 g_free (file_name);
1186
1187 eel_show_warning_dialog (message,
1188 _("The item cannot be restored from trash"),
1189 parent_window);
1190 g_free (message);
1191 }
1192
1193 if (original_dirs_hash != NULL) {
1194 original_dirs = g_hash_table_get_keys (original_dirs_hash);
1195 for (l = original_dirs; l != NULL; l = l->next) {
1196 original_dir = NAUTILUS_FILE (l->data);
1197 original_dir_location = nautilus_file_get_location (original_dir);
1198
1199 files = g_hash_table_lookup (original_dirs_hash, original_dir);
1200 locations = locations_from_file_list (files);
1201
1202 nautilus_file_operations_move
1203 (locations, NULL,
1204 original_dir_location,
1205 parent_window,
1206 NULL, NULL);
1207
1208 g_list_free_full (locations, g_object_unref);
1209 g_object_unref (original_dir_location);
1210 }
1211
1212 g_list_free (original_dirs);
1213 g_hash_table_destroy (original_dirs_hash);
1214 }
1215
1216 nautilus_file_list_unref (unhandled_files);
1217 }
1218
1219 typedef struct {
1220 NautilusMountGetContent callback;
1221 gpointer user_data;
1222 } GetContentTypesData;
1223
1224 static void
1225 get_types_cb (GObject *source_object,
1226 GAsyncResult *res,
1227 gpointer user_data)
1228 {
1229 GetContentTypesData *data;
1230 char **types;
1231
1232 data = user_data;
1233 types = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, NULL);
1234
1235 g_object_set_data_full (source_object,
1236 "nautilus-content-type-cache",
1237 g_strdupv (types),
1238 (GDestroyNotify)g_strfreev);
1239
1240 if (data->callback) {
1241 data->callback ((const char **) types, data->user_data);
1242 }
1243 g_strfreev (types);
1244 g_slice_free (GetContentTypesData, data);
1245 }
1246
1247 void
1248 nautilus_get_x_content_types_for_mount_async (GMount *mount,
1249 NautilusMountGetContent callback,
1250 GCancellable *cancellable,
1251 gpointer user_data)
1252 {
1253 char **cached;
1254 GetContentTypesData *data;
1255
1256 if (mount == NULL) {
1257 if (callback) {
1258 callback (NULL, user_data);
1259 }
1260 return;
1261 }
1262
1263 cached = g_object_get_data (G_OBJECT (mount), "nautilus-content-type-cache");
1264 if (cached != NULL) {
1265 if (callback) {
1266 callback ((const char **) cached, user_data);
1267 }
1268 return;
1269 }
1270
1271 data = g_slice_new0 (GetContentTypesData);
1272 data->callback = callback;
1273 data->user_data = user_data;
1274
1275 g_mount_guess_content_type (mount,
1276 FALSE,
1277 cancellable,
1278 get_types_cb,
1279 data);
1280 }
1281
1282 char **
1283 nautilus_get_cached_x_content_types_for_mount (GMount *mount)
1284 {
1285 char **cached;
1286
1287 if (mount == NULL) {
1288 return NULL;
1289 }
1290
1291 cached = g_object_get_data (G_OBJECT (mount), "nautilus-content-type-cache");
1292 if (cached != NULL) {
1293 return g_strdupv (cached);
1294 }
1295
1296 return NULL;
1297 }
1298
1299 #if !defined (NAUTILUS_OMIT_SELF_CHECK)
1300
1301 void
1302 nautilus_self_check_file_utilities (void)
1303 {
1304 }
1305
1306 #endif /* !NAUTILUS_OMIT_SELF_CHECK */