1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
5 Copyright (C) 2001 Red Hat, 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.
23 /* URI scheme for remapping directories under magic URIs, used
24 * for the magic desktop file directories such as start-here.
32 #include <sys/types.h>
42 #include <libgnomevfs/gnome-vfs-mime.h>
44 #include <libgnomevfs/gnome-vfs-module.h>
45 #include <libgnomevfs/gnome-vfs-method.h>
46 #include <libgnomevfs/gnome-vfs-utils.h>
47 #include <libgnomevfs/gnome-vfs-ops.h>
48 #include <libgnomevfs/gnome-vfs-module-shared.h>
49 #include <libgnomevfs/gnome-vfs-monitor-private.h>
51 /* FIXME Maybe when chaining to file:, we should call the gnome-vfs wrapper
52 * functions, instead of the file: methods directly.
55 #define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
57 static GnomeVFSURI* desktop_uri_to_file_uri (GnomeVFSURI *desktop_uri);
59 static GnomeVFSResult open_merged_directory (GnomeVFSMethod *method,
60 GnomeVFSMethodHandle **method_handle,
62 GnomeVFSFileInfoOptions options,
63 GnomeVFSContext *context);
65 static char* create_file_uri_in_dir (const char *dir,
66 const char *filename);
68 static GnomeVFSMethod *parent_method = NULL;
71 do_open (GnomeVFSMethod *method,
72 GnomeVFSMethodHandle **method_handle,
74 GnomeVFSOpenMode mode,
75 GnomeVFSContext *context)
77 GnomeVFSURI *file_uri;
78 GnomeVFSResult result;
80 file_uri = desktop_uri_to_file_uri (uri);
81 result = (* parent_method->open) (parent_method,
86 gnome_vfs_uri_unref (file_uri);
92 do_create (GnomeVFSMethod *method,
93 GnomeVFSMethodHandle **method_handle,
95 GnomeVFSOpenMode mode,
98 GnomeVFSContext *context)
100 GnomeVFSURI *file_uri;
101 GnomeVFSResult result;
103 file_uri = desktop_uri_to_file_uri (uri);
104 result = (* parent_method->create) (parent_method,
111 gnome_vfs_uri_unref (file_uri);
116 static GnomeVFSResult
117 do_close (GnomeVFSMethod *method,
118 GnomeVFSMethodHandle *method_handle,
119 GnomeVFSContext *context)
121 GnomeVFSResult result;
123 result = (* parent_method->close) (parent_method,
130 static GnomeVFSResult
131 do_read (GnomeVFSMethod *method,
132 GnomeVFSMethodHandle *method_handle,
134 GnomeVFSFileSize num_bytes,
135 GnomeVFSFileSize *bytes_read,
136 GnomeVFSContext *context)
138 GnomeVFSResult result;
140 result = (* parent_method->read) (parent_method,
149 static GnomeVFSResult
150 do_write (GnomeVFSMethod *method,
151 GnomeVFSMethodHandle *method_handle,
152 gconstpointer buffer,
153 GnomeVFSFileSize num_bytes,
154 GnomeVFSFileSize *bytes_written,
155 GnomeVFSContext *context)
157 GnomeVFSResult result;
159 result = (* parent_method->write) (parent_method,
169 static GnomeVFSResult
170 do_seek (GnomeVFSMethod *method,
171 GnomeVFSMethodHandle *method_handle,
172 GnomeVFSSeekPosition whence,
173 GnomeVFSFileOffset offset,
174 GnomeVFSContext *context)
176 GnomeVFSResult result;
178 result = (* parent_method->seek) (parent_method,
186 static GnomeVFSResult
187 do_tell (GnomeVFSMethod *method,
188 GnomeVFSMethodHandle *method_handle,
189 GnomeVFSFileOffset *offset_return)
191 GnomeVFSResult result;
193 result = (* parent_method->tell) (parent_method,
201 static GnomeVFSResult
202 do_truncate_handle (GnomeVFSMethod *method,
203 GnomeVFSMethodHandle *method_handle,
204 GnomeVFSFileSize where,
205 GnomeVFSContext *context)
207 GnomeVFSResult result;
209 result = (* parent_method->truncate_handle) (parent_method,
217 static GnomeVFSResult
218 do_truncate (GnomeVFSMethod *method,
220 GnomeVFSFileSize where,
221 GnomeVFSContext *context)
223 GnomeVFSURI *file_uri;
224 GnomeVFSResult result;
226 file_uri = desktop_uri_to_file_uri (uri);
227 result = (* parent_method->truncate) (parent_method,
232 gnome_vfs_uri_unref (file_uri);
237 typedef struct _DirHandle DirHandle;
245 static GnomeVFSResult
246 do_open_directory (GnomeVFSMethod *method,
247 GnomeVFSMethodHandle **method_handle,
249 GnomeVFSFileInfoOptions options,
250 GnomeVFSContext *context)
252 return open_merged_directory (method, method_handle,
253 uri, options, context);
256 static GnomeVFSResult
257 do_close_directory (GnomeVFSMethod *method,
258 GnomeVFSMethodHandle *method_handle,
259 GnomeVFSContext *context)
261 GnomeVFSResult result;
265 dh = (DirHandle*) method_handle;
267 result = GNOME_VFS_OK;
269 while (tmp != NULL) {
270 GnomeVFSResult this_result;
272 this_result = (* parent_method->close_directory) (parent_method,
276 if (this_result != GNOME_VFS_OK)
277 result = this_result;
282 g_slist_free (dh->handles);
288 static GnomeVFSResult
289 do_read_directory (GnomeVFSMethod *method,
290 GnomeVFSMethodHandle *method_handle,
291 GnomeVFSFileInfo *file_info,
292 GnomeVFSContext *context)
294 GnomeVFSResult result;
295 GnomeVFSMethodHandle *parent_handle;
298 dh = (DirHandle*) method_handle;
300 if (dh->next == NULL) {
301 return GNOME_VFS_ERROR_EOF;
305 parent_handle = dh->next->data;
307 result = (* parent_method->read_directory) (parent_method,
312 if (result != GNOME_VFS_OK) {
313 dh->next = dh->next->next;
325 set_directory_mime_type (GnomeVFSFileInfo *file_info)
327 g_free (file_info->mime_type);
329 file_info->mime_type = g_strdup ("x-directory/vfolder-desktop");
330 file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
333 static GnomeVFSResult
334 do_get_file_info (GnomeVFSMethod *method,
336 GnomeVFSFileInfo *file_info,
337 GnomeVFSFileInfoOptions options,
338 GnomeVFSContext *context)
340 GnomeVFSURI *file_uri;
341 GnomeVFSResult result;
343 file_uri = desktop_uri_to_file_uri (uri);
344 result = (* parent_method->get_file_info) (parent_method,
350 if (file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
351 set_directory_mime_type (file_info);
353 gnome_vfs_uri_unref (file_uri);
358 static GnomeVFSResult
359 do_get_file_info_from_handle (GnomeVFSMethod *method,
360 GnomeVFSMethodHandle *method_handle,
361 GnomeVFSFileInfo *file_info,
362 GnomeVFSFileInfoOptions options,
363 GnomeVFSContext *context)
365 GnomeVFSResult result;
367 result = (* parent_method->get_file_info_from_handle) (parent_method,
373 if (file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
374 set_directory_mime_type (file_info);
381 do_is_local (GnomeVFSMethod *method,
382 const GnomeVFSURI *uri)
388 static GnomeVFSResult
389 do_make_directory (GnomeVFSMethod *method,
392 GnomeVFSContext *context)
394 GnomeVFSURI *file_uri;
395 GnomeVFSResult result;
397 file_uri = desktop_uri_to_file_uri (uri);
398 result = (* parent_method->make_directory) (parent_method,
403 gnome_vfs_uri_unref (file_uri);
408 static GnomeVFSResult
409 do_remove_directory (GnomeVFSMethod *method,
411 GnomeVFSContext *context)
413 GnomeVFSURI *file_uri;
414 GnomeVFSResult result;
416 file_uri = desktop_uri_to_file_uri (uri);
417 result = (* parent_method->remove_directory) (parent_method,
421 gnome_vfs_uri_unref (file_uri);
426 static GnomeVFSResult
427 do_find_directory (GnomeVFSMethod *method,
428 GnomeVFSURI *near_uri,
429 GnomeVFSFindDirectoryKind kind,
430 GnomeVFSURI **result_uri,
431 gboolean create_if_needed,
432 gboolean find_if_needed,
434 GnomeVFSContext *context)
436 GnomeVFSURI *file_uri;
437 GnomeVFSURI *file_result_uri;
438 GnomeVFSResult result;
440 file_result_uri = NULL;
441 file_uri = desktop_uri_to_file_uri (near_uri);
442 result = (* parent_method->find_directory) (parent_method,
451 gnome_vfs_uri_unref (file_uri);
454 *result_uri = file_result_uri;
456 if (file_result_uri == NULL)
457 result = GNOME_VFS_ERROR_NOT_FOUND;
462 static GnomeVFSResult
463 do_move (GnomeVFSMethod *method,
464 GnomeVFSURI *old_uri,
465 GnomeVFSURI *new_uri,
466 gboolean force_replace,
467 GnomeVFSContext *context)
469 GnomeVFSURI *old_file_uri;
470 GnomeVFSURI *new_file_uri;
471 GnomeVFSResult result;
473 old_file_uri = desktop_uri_to_file_uri (old_uri);
474 new_file_uri = desktop_uri_to_file_uri (new_uri);
476 result = (* parent_method->move) (parent_method,
481 gnome_vfs_uri_unref (old_file_uri);
482 gnome_vfs_uri_unref (new_file_uri);
487 static GnomeVFSResult
488 do_unlink (GnomeVFSMethod *method,
490 GnomeVFSContext *context)
492 GnomeVFSURI *file_uri;
493 GnomeVFSResult result;
495 file_uri = desktop_uri_to_file_uri (uri);
496 result = (* parent_method->unlink) (parent_method,
500 gnome_vfs_uri_unref (file_uri);
505 static GnomeVFSResult
506 do_create_symbolic_link (GnomeVFSMethod *method,
508 const char *target_reference,
509 GnomeVFSContext *context)
511 GnomeVFSURI *file_uri;
512 GnomeVFSResult result;
514 file_uri = desktop_uri_to_file_uri (uri);
515 result = (* parent_method->create_symbolic_link) (parent_method,
520 gnome_vfs_uri_unref (file_uri);
525 static GnomeVFSResult
526 do_check_same_fs (GnomeVFSMethod *method,
527 GnomeVFSURI *source_uri,
528 GnomeVFSURI *target_uri,
529 gboolean *same_fs_return,
530 GnomeVFSContext *context)
532 GnomeVFSURI *source_file_uri;
533 GnomeVFSURI *target_file_uri;
534 GnomeVFSResult result;
536 source_file_uri = desktop_uri_to_file_uri (source_uri);
537 target_file_uri = desktop_uri_to_file_uri (target_uri);
539 result = (* parent_method->check_same_fs) (parent_method,
544 gnome_vfs_uri_unref (source_file_uri);
545 gnome_vfs_uri_unref (target_file_uri);
550 static GnomeVFSResult
551 do_set_file_info (GnomeVFSMethod *method,
553 const GnomeVFSFileInfo *info,
554 GnomeVFSSetFileInfoMask mask,
555 GnomeVFSContext *context)
557 GnomeVFSURI *file_uri;
558 GnomeVFSResult result;
560 file_uri = desktop_uri_to_file_uri (uri);
561 result = (* parent_method->set_file_info) (parent_method,
567 gnome_vfs_uri_unref (file_uri);
573 GnomeVFSMonitorHandle *handle;
574 GnomeVFSURI *desktop_uri;
575 } DesktopMonitorHandle;
578 monitor_notify_cb (GnomeVFSMonitorHandle *handle,
579 const gchar *monitor_uri,
580 const gchar *info_uri,
581 GnomeVFSMonitorEventType event_type,
584 DesktopMonitorHandle *monitor_handle;
585 GnomeVFSURI *desktop_info_uri;
586 const gchar *uri_diff;
587 gint monitor_uri_len;
589 monitor_handle = (DesktopMonitorHandle *) user_data;
590 desktop_info_uri = NULL;
591 monitor_uri_len = strlen (monitor_uri);
593 if (info_uri != NULL &&
594 strncmp (info_uri, monitor_uri, monitor_uri_len) == 0) {
595 uri_diff = &info_uri [monitor_uri_len];
597 if (*uri_diff != '\0') {
599 gnome_vfs_uri_append_string (
600 monitor_handle->desktop_uri,
603 desktop_info_uri = monitor_handle->desktop_uri;
604 gnome_vfs_uri_ref (desktop_info_uri);
608 gnome_vfs_monitor_callback ((GnomeVFSMethodHandle *) monitor_handle,
612 gnome_vfs_uri_unref (desktop_info_uri);
615 static GnomeVFSResult
616 do_monitor_add (GnomeVFSMethod *method,
617 GnomeVFSMethodHandle **method_handle_return,
619 GnomeVFSMonitorType monitor_type)
621 DesktopMonitorHandle *monitor_handle;
622 GnomeVFSURI *file_uri;
623 GnomeVFSResult result;
625 monitor_handle = g_new0 (DesktopMonitorHandle, 1);
626 monitor_handle->desktop_uri = uri;
627 gnome_vfs_uri_ref (uri);
629 file_uri = desktop_uri_to_file_uri (uri);
630 result = gnome_vfs_monitor_do_add (parent_method,
631 &monitor_handle->handle,
636 gnome_vfs_uri_unref (file_uri);
638 if (result != GNOME_VFS_OK) {
639 gnome_vfs_uri_unref (monitor_handle->desktop_uri);
640 g_free (monitor_handle);
643 *method_handle_return = (GnomeVFSMethodHandle *) monitor_handle;
648 static GnomeVFSResult
649 do_monitor_cancel (GnomeVFSMethod *method,
650 GnomeVFSMethodHandle *method_handle)
652 DesktopMonitorHandle *monitor_handle;
653 GnomeVFSResult result;
655 monitor_handle = (DesktopMonitorHandle *) method_handle;
657 result = gnome_vfs_monitor_do_cancel (monitor_handle->handle);
659 gnome_vfs_uri_unref (monitor_handle->desktop_uri);
660 g_free (monitor_handle);
667 /* gnome-vfs bureaucracy */
669 static GnomeVFSMethod method = {
670 sizeof (GnomeVFSMethod),
683 do_get_file_info_from_handle,
693 do_create_symbolic_link,
704 SCHEME_SYSTEM_SETTINGS,
705 SCHEME_SERVER_SETTINGS,
709 #define MAX_DIRECTORIES 3
710 #define DIRECTORIES_INITIALIZER { NULL, NULL, NULL }
712 typedef struct _SchemeDescription SchemeDescription;
714 struct _SchemeDescription
720 char *directories[MAX_DIRECTORIES];
723 static SchemeDescription schemes[] =
725 { SCHEME_FAVORITES, "favorites",
726 DIRECTORIES_INITIALIZER },
727 { SCHEME_PREFERENCES, "preferences",
728 DIRECTORIES_INITIALIZER },
729 { SCHEME_START_HERE, "start-here",
730 DIRECTORIES_INITIALIZER },
731 { SCHEME_SYSTEM_SETTINGS, "system-settings",
732 DIRECTORIES_INITIALIZER },
733 { SCHEME_SERVER_SETTINGS, "server-settings",
734 DIRECTORIES_INITIALIZER },
735 { SCHEME_PROGRAMS, "programs",
736 DIRECTORIES_INITIALIZER }
740 vfs_module_init (const char *method_name,
745 parent_method = gnome_vfs_method_get ("file");
747 if (parent_method == NULL) {
748 g_error ("Could not find 'file' method for gnome-vfs");
753 while (i < N_ELEMENTS (schemes)) {
754 switch (schemes[i].id) {
755 case SCHEME_FAVORITES:
756 schemes[i].directories[0] =
757 g_strconcat (g_get_home_dir (),
761 case SCHEME_PREFERENCES:
762 /* FIXME I think the GNOME 2 control center will move
763 * this, but we don't know where to yet
765 schemes[i].directories[0] =
766 g_strconcat (DATADIR, "/control-center/capplets", NULL);
768 case SCHEME_START_HERE:
769 schemes[i].directories[0] = g_strconcat (SYSCONFDIR,
773 case SCHEME_SYSTEM_SETTINGS:
774 schemes[i].directories[0] =
775 g_strconcat (SYSCONFDIR, "/X11/sysconfig", NULL);
777 case SCHEME_SERVER_SETTINGS:
778 schemes[i].directories[0] =
779 g_strconcat (SYSCONFDIR, "/X11/serverconfig", NULL);
781 case SCHEME_PROGRAMS:
782 schemes[i].directories[0] = g_strconcat (SYSCONFDIR,
785 schemes[i].directories[1] =
786 g_strconcat (DATADIR, "gnome/apps", NULL);
789 g_assert_not_reached ();
800 vfs_module_shutdown (GnomeVFSMethod *method)
805 while (i < N_ELEMENTS (schemes)) {
809 while (j < MAX_DIRECTORIES) {
810 g_free (schemes[i].directories[j]);
811 schemes[i].directories[j] = NULL;
821 static const SchemeDescription*
822 get_desc_for_uri (GnomeVFSURI *desktop_uri)
824 const SchemeDescription *desc;
828 scheme = gnome_vfs_uri_get_scheme (desktop_uri);
832 while (i < N_ELEMENTS (schemes)) {
833 if (strcmp (schemes[i].scheme, scheme) == 0) {
845 desktop_uri_to_file_uri (GnomeVFSURI *desktop_uri)
847 const SchemeDescription *desc;
848 GnomeVFSURI *new_uri;
852 desc = get_desc_for_uri (desktop_uri);
855 gnome_vfs_uri_ref (desktop_uri);
859 /* Prepend the base for the desktop URI.
860 * If the SchemeDescription contains > 1 directory, we use the directory
861 * after the first if the given file actually exists there.
864 path = gnome_vfs_uri_get_path (desktop_uri);
866 while (desc->directories[i])
873 s = create_file_uri_in_dir (desc->directories[i], path);
875 new_uri = gnome_vfs_uri_new (s);
880 gnome_vfs_uri_exists (new_uri)) {
883 gnome_vfs_uri_unref (new_uri);
889 g_assert_not_reached ();
895 static GnomeVFSResult
896 open_merged_directory (GnomeVFSMethod *method,
897 GnomeVFSMethodHandle **method_handle,
898 GnomeVFSURI *desktop_uri,
899 GnomeVFSFileInfoOptions options,
900 GnomeVFSContext *context)
902 GnomeVFSResult result;
904 const SchemeDescription *desc;
909 desc = get_desc_for_uri (desktop_uri);
912 return GNOME_VFS_ERROR_NOT_FOUND;
915 dh = g_new0 (DirHandle, 1);
917 /* Prepend the base for the desktop URI.
918 * If the SchemeDescription contains > 1 directory, we use the directory
919 * after the first if the given file actually exists there.
922 path = gnome_vfs_uri_get_path (desktop_uri);
924 while (desc->directories[i]) {
926 GnomeVFSURI *file_uri;
927 GnomeVFSMethodHandle *parent_handle = NULL;
929 s = create_file_uri_in_dir (desc->directories[i], path);
931 file_uri = gnome_vfs_uri_new (s);
935 result = (* parent_method->open_directory) (parent_method,
941 if (result == GNOME_VFS_OK) {
943 dh->handles = g_slist_prepend (dh->handles, parent_handle);
946 gnome_vfs_uri_unref (file_uri);
951 dh->next = dh->handles;
953 *method_handle = (GnomeVFSMethodHandle*) dh;
955 return found ? GNOME_VFS_OK : GNOME_VFS_ERROR_NOT_FOUND;
960 create_file_uri_in_dir (const char *dir,
961 const char *filename)
966 dir_uri = gnome_vfs_get_uri_from_local_path (dir);
968 retval = g_strconcat (dir_uri, "/", filename, NULL);