1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* translate-method.c - translator method for GNOME Virtual File System
4 Copyright (C) 1999, 2000 Red Hat Inc.
6 The Gnome Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The Gnome Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the Gnome Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Author: Elliot Lee <sopwith@redhat.com> */
27 #include <glib/galloca.h>
28 #include <glib/gmessages.h>
29 #include <glib/gstrfuncs.h>
30 #include <glib/gthread.h>
31 #include <libgnomevfs/gnome-vfs-method.h>
32 #include <libgnomevfs/gnome-vfs-mime.h>
33 #include <libgnomevfs/gnome-vfs-mime-utils.h>
34 #include <libgnomevfs/gnome-vfs-module.h>
35 #include <libgnomevfs/gnome-vfs-private-utils.h>
39 #include <sys/types.h>
48 char *default_mime_type;
49 char *real_method_name;
58 char *orig_string; /* this string gets chopped up into argv--it exists for freeing only */
64 /* State used for -exec -retain */
67 FILE * retain_to; /* pipe to child */
68 FILE * retain_from; /* pipe from child */
69 pid_t retain_pid; /* PID of child */
73 GnomeVFSMethod base_method;
75 GnomeVFSMethod *real_method;
80 tr_apply_default_mime_type(TranslateMethod * tm,
81 GnomeVFSFileInfo * file_info)
83 /* Only apply the default mime-type if the real method returns
84 * unknown mime-type and the the TranslateMethod /has/ a mime-type */
85 if (file_info->mime_type == NULL) {
86 /* FIXME bugzilla.eazel.com 2799:
87 * this may not be needed since methods need to
88 * return application/octet-stream if it is an unknown
89 * mime-type, not NULL */
90 if (tm->pa.default_mime_type) {
91 file_info->mime_type =
92 g_strdup (tm->pa.default_mime_type);
93 file_info->valid_fields |=
94 GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
98 if ((strcmp (file_info->mime_type, GNOME_VFS_MIME_TYPE_UNKNOWN) == 0) &&
99 (tm->pa.default_mime_type != NULL)) {
100 g_free (file_info->mime_type);
101 file_info->mime_type =
102 g_strdup (tm->pa.default_mime_type);
103 file_info->valid_fields |=
104 GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
114 static void /* GnomeVFSProcessInitFunc */ tr_forkexec_cb (gpointer data)
116 TrForkCBData *cb_data;
118 g_assert (NULL != data);
119 cb_data = (TrForkCBData *) data;
121 if ( -1 == dup2 (cb_data->child_in_fd, STDIN_FILENO) ) {
125 if ( -1 == dup2 (cb_data->child_out_fd, STDOUT_FILENO) ) {
132 static pid_t tr_exec_open_child (char **argv, /*OUT*/ FILE ** p_from_stream, /*OUT*/ FILE ** p_to_stream)
136 TrForkCBData cb_data;
138 int pipe_to_child[2] = { -1, -1 };
139 int pipe_to_parent[2] = { -1, -1 };
141 g_assert ( NULL != p_from_stream );
142 g_assert ( NULL != p_to_stream );
145 *p_from_stream = NULL;
147 /* Blocking SIGPIPE here is probably unnecessary --
148 * GnomeVFS already does this on init
150 sigpipe_old = signal (SIGPIPE, SIG_IGN);
152 err = pipe (pipe_to_child);
155 g_warning ("pipe returned error %d", errno);
160 err = pipe (pipe_to_parent);
163 g_warning ("pipe returned error %d", errno);
168 cb_data.child_out_fd = pipe_to_parent[1];
169 cb_data.child_in_fd = pipe_to_child[0];
171 /* Strictly speaking, this is unnecessary since these handles will be closed anyway*/
172 err = fcntl ( pipe_to_parent[0], F_SETFD, FD_CLOEXEC ) ;
173 g_assert (0 == err );
174 err = fcntl ( pipe_to_child[1], F_SETFD, FD_CLOEXEC ) ;
175 g_assert (0 == err );
177 ret = gnome_vfs_forkexec ( argv[0],
178 (const char * const*)argv,
179 GNOME_VFS_PROCESS_CLOSEFDS,
184 close (pipe_to_parent[1]);
185 pipe_to_parent[1] = -1;
186 close (pipe_to_child[0]);
187 pipe_to_child[0] = -1;
190 g_warning ("fork returned error %d", errno);
194 *p_to_stream = fdopen (pipe_to_child[1], "w");
195 g_assert ( NULL != *p_to_stream );
196 pipe_to_child[1] = -1;
198 *p_from_stream = fdopen (pipe_to_parent[0], "r");
199 g_assert ( NULL != *p_from_stream );
200 pipe_to_parent[0] = -1;
202 setvbuf (*p_to_stream, NULL, _IOLBF, 0);
203 setvbuf (*p_from_stream, NULL, _IOLBF, 0);
206 if ( -1 != pipe_to_parent[0] ) { close ( pipe_to_parent[0]); }
207 if ( -1 != pipe_to_parent[1] ) { close ( pipe_to_parent[1]); }
208 if ( -1 != pipe_to_child[0] ) { close ( pipe_to_child[0]); }
209 if ( -1 != pipe_to_child[1] ) { close ( pipe_to_child[1]); }
211 signal (SIGPIPE, sigpipe_old);
216 #define GETLINE_DELTA 256
217 static char * tr_getline (FILE* stream)
223 gboolean got_newline;
225 ret = g_malloc( GETLINE_DELTA * sizeof(char) );
226 ret_size = GETLINE_DELTA;
228 for ( ret_used = 0, got_newline = FALSE ;
229 !got_newline && (EOF != (char_read = fgetc (stream))) ;
232 if (ret_size == (ret_used + 1)) {
233 ret_size += GETLINE_DELTA;
234 ret = g_realloc (ret, ret_size);
236 if ('\n' == char_read || '\r' == char_read ) {
238 ret [ret_used] = '\0';
240 ret [ret_used] = char_read;
253 static void tr_exec_pass_uri (char *uri_string, FILE * out_stream)
257 /*shave off the scheme--pass only the right hand side to the child*/
258 tmpstr = strchr (uri_string, ':');
259 fprintf (out_stream, "%s\n", tmpstr ? tmpstr + 1 : uri_string);
266 static char * tr_exec_do_retain (TranslateMethod *tm, char * uri_string)
268 char * child_result = NULL;
271 g_mutex_lock (tm->exec_state.retain_lock);
274 /* re-execute the child process in case it unexpectedly disappears */
275 for (tries = 0 ; ( ! child_result ) && tries < 3 ; tries ++) {
276 if ( 0 == tm->exec_state.retain_pid ) {
277 tm->exec_state.retain_pid = tr_exec_open_child (tm->pa.u.exec.argv, &(tm->exec_state.retain_from), &(tm->exec_state.retain_to));
278 if ( -1 == tm->exec_state.retain_pid ) {
279 tm->exec_state.retain_pid = 0;
284 g_assert (uri_string);
285 tr_exec_pass_uri (uri_string, tm->exec_state.retain_to);
287 child_result = tr_getline (tm->exec_state.retain_from);
289 if (NULL == child_result) {
290 tm->exec_state.retain_pid = 0;
295 g_mutex_unlock (tm->exec_state.retain_lock);
303 * USAGE: -exec <exec_string> -real-method <method> [-retain]
305 * -exec allows a child process to filter and translate URI's passed to GNOME-VFS.
306 * -exec requires a URI scheme to be specified via -real-method, and does not
307 * allow the child process to change that method
309 * <exec_string> is a string that will be tokenized and passed to execv()
310 * <method> is the URI scheme that all requests will be translated to.
313 * The child process is exec()'d. The URI minus the scheme is presented
314 * as standard input. On success, the child is expected to print out
315 * a translated URI minus the scheme and exit(0). On failure, the child
316 * should print out ":\n" or exit with a non-zero value
319 * The child process is exec()'d and fed multiple URI's, each newline terminated,
320 * via standard in. For each URI, the child must print to standard out a
321 * translated URI followed by a newline or a ":" followed by a newline on error.
323 * Note than children written to work with -retain that use stdio need
324 * to set their stdin and stdout buffering discipline to "line" instead of "block"
326 * setvbuf (stdin, NULL, _IOLBF, 0);
327 * setvbuf (stdout, NULL, _IOLBF, 0);
329 * Config file example:
331 * foo: libvfs-translate.so -real-method http -exec "/bin/sed -e s/\/\/www.microsoft.com/\/\/www.eazel.com/"
333 * (note that sed won't work with -retain)
336 /* FIXME bugzilla.eazel.com 2796: this may be broken when the child produces compound URI's */
337 static GnomeVFSURI *tr_handle_exec (TranslateMethod *tm, const GnomeVFSURI * uri)
344 char *uri_string = NULL;
345 char *child_result = NULL;
346 GnomeVFSURI * retval = NULL;
349 * Note that normally having a parent and child communicate
350 * bi-directionally via pipes is a bad idea. However, in this case,
351 * the parent will write everything and then close, so it'll all be OK
352 * as long as the child doesnt intermix reads and writes and fill
353 * up their output pipe's buffer before the parent is done writing.
356 uri_string = gnome_vfs_uri_to_string (uri, 0);
358 if ( NULL == uri_string ) {
362 if (tm->pa.u.exec.retain) {
363 child_result = tr_exec_do_retain (tm, uri_string);
365 if ( NULL == child_result ) {
370 FILE *from_stream, *to_stream;
372 child_pid = tr_exec_open_child (tm->pa.u.exec.argv, &from_stream, &to_stream);
374 if ( -1 == child_pid ) {
378 uri_string = gnome_vfs_uri_to_string (uri, 0);
379 g_assert (uri_string);
380 tr_exec_pass_uri (uri_string, to_stream);
385 child_result = tr_getline (from_stream);
387 err = waitpid (child_pid, &child_status, 0);
389 g_assert ( child_pid == err );
391 if (! WIFEXITED (child_status) ) {
395 if (NULL == child_result) {
396 g_warning ("Child produced no result");
402 /* FIXME bugzilla.eazel.com 2797:
403 * just because we've appended the same scheme, doesn't mean
404 * we're going to get the same method from gnome_vfs_uri_new
407 /* A child result that ends in a :\n indicates an error */
408 if ( ':' != child_result[ strlen(child_result) - 1 ]) {
409 /* append the real scheme */
410 tmpstr = g_strconcat (tm->pa.real_method_name, ":", child_result, NULL);
411 g_free (child_result);
412 child_result = tmpstr;
415 retval = gnome_vfs_uri_new_private (child_result, FALSE, TRUE, TRUE);
417 if ( NULL == retval ) {
418 g_warning ("Unable to make URI from child process's result '%s'", child_result);
425 g_free (child_result);
432 tr_exec_init (ExecState *exec_state)
434 exec_state->retain_lock = g_mutex_new();
438 tr_exec_cleanup (ExecState *exec_state)
440 if (NULL != exec_state->retain_lock) {
441 g_mutex_free (exec_state->retain_lock);
444 if (NULL != exec_state->retain_to) {
445 fclose (exec_state->retain_to);
447 if (NULL != exec_state->retain_from) {
448 fclose (exec_state->retain_from);
451 if ( 0 != exec_state->retain_pid ) {
452 int child_status, err;
454 kill (exec_state->retain_pid, SIGTERM);
455 err = waitpid (exec_state->retain_pid, &child_status, 0);
456 g_assert (err == exec_state->retain_pid);
460 static GnomeVFSURI *tr_uri_translate(TranslateMethod * tm,
461 const GnomeVFSURI * uri)
463 const char *text_uri;
464 const char *text_uri_no_method;
465 char *translated_text;
466 char *translated_uri;
471 if (uri->method != (GnomeVFSMethod *) tm)
472 return gnome_vfs_uri_ref((GnomeVFSURI *) uri); /* Don't translate things that don't belong to us */
474 /* Hack it all up to pieces */
476 if (MODE_BASIC == tm->pa.mode) {
477 text_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
478 text_uri_no_method = strchr (text_uri, ':');
480 if (text_uri_no_method == NULL) {
481 text_uri_no_method = text_uri;
483 text_uri_no_method = text_uri_no_method + 1;
486 translated_text = g_strdup_printf (tm->pa.u.basic.trans_string,
487 uri->text, uri->text,
488 uri->text, uri->text, uri->text);
489 translated_uri = g_strconcat (tm->pa.real_method_name, ":",
490 translated_text, NULL);
492 retval = gnome_vfs_uri_new_private (translated_uri, FALSE, TRUE, TRUE);
494 g_free (translated_text);
495 g_free (translated_uri);
496 } else if (MODE_EXEC == tm->pa.mode) {
497 retval = tr_handle_exec (tm, uri);
505 static GnomeVFSResult
506 tr_do_open(GnomeVFSMethod * method,
507 GnomeVFSMethodHandle ** method_handle_return,
509 GnomeVFSOpenMode mode, GnomeVFSContext * context)
511 TranslateMethod *tm = (TranslateMethod *) method;
512 GnomeVFSURI *real_uri;
513 GnomeVFSResult retval;
515 real_uri = tr_uri_translate(tm, uri);
517 if ( NULL != real_uri ) {
519 tm->real_method->open(tm->real_method, method_handle_return,
520 real_uri, mode, context);
522 gnome_vfs_uri_unref(real_uri);
524 retval = GNOME_VFS_ERROR_NOT_FOUND;
530 static GnomeVFSResult
531 tr_do_create(GnomeVFSMethod * method,
533 ** method_handle_return,
535 GnomeVFSOpenMode mode,
536 gboolean exclusive, guint perm, GnomeVFSContext * context)
538 TranslateMethod *tm = (TranslateMethod *) method;
539 GnomeVFSURI *real_uri;
540 GnomeVFSResult retval;
542 real_uri = tr_uri_translate(tm, uri);
544 if ( NULL != real_uri ) {
546 tm->real_method->create(tm->real_method, method_handle_return,
547 real_uri, mode, exclusive, perm,
549 gnome_vfs_uri_unref(real_uri);
551 retval = GNOME_VFS_ERROR_NOT_FOUND;
557 static GnomeVFSResult
558 tr_do_close(GnomeVFSMethod * method,
559 GnomeVFSMethodHandle * method_handle,
560 GnomeVFSContext * context)
562 TranslateMethod *tm = (TranslateMethod *) method;
563 return tm->real_method->close(tm->real_method, method_handle,
567 static GnomeVFSResult
568 tr_do_read(GnomeVFSMethod * method,
569 GnomeVFSMethodHandle * method_handle,
571 GnomeVFSFileSize num_bytes,
572 GnomeVFSFileSize * bytes_read_return, GnomeVFSContext * context)
574 TranslateMethod *tm = (TranslateMethod *) method;
575 return tm->real_method->read(tm->real_method, method_handle,
576 buffer, num_bytes, bytes_read_return,
580 static GnomeVFSResult
581 tr_do_write(GnomeVFSMethod * method,
582 GnomeVFSMethodHandle * method_handle,
583 gconstpointer buffer,
584 GnomeVFSFileSize num_bytes,
585 GnomeVFSFileSize * bytes_written_return,
586 GnomeVFSContext * context)
588 TranslateMethod *tm = (TranslateMethod *) method;
589 return tm->real_method->write(tm->real_method, method_handle,
591 bytes_written_return, context);
594 static GnomeVFSResult
595 tr_do_seek(GnomeVFSMethod * method,
596 GnomeVFSMethodHandle * method_handle,
597 GnomeVFSSeekPosition whence,
598 GnomeVFSFileOffset offset, GnomeVFSContext * context)
600 TranslateMethod *tm = (TranslateMethod *) method;
601 return tm->real_method->seek(tm->real_method, method_handle,
602 whence, offset, context);
605 static GnomeVFSResult
606 tr_do_tell(GnomeVFSMethod * method,
607 GnomeVFSMethodHandle * method_handle,
608 GnomeVFSFileOffset * offset_return)
610 TranslateMethod *tm = (TranslateMethod *) method;
611 return tm->real_method->tell(tm->real_method, method_handle,
615 static GnomeVFSResult
616 tr_do_open_directory(GnomeVFSMethod * method,
617 GnomeVFSMethodHandle ** method_handle,
619 GnomeVFSFileInfoOptions options,
620 GnomeVFSContext * context)
622 TranslateMethod *tm = (TranslateMethod *) method;
623 GnomeVFSURI *real_uri;
624 GnomeVFSResult retval;
626 real_uri = tr_uri_translate(tm, uri);
628 if ( NULL != real_uri ) {
630 tm->real_method->open_directory(tm->real_method, method_handle,
633 gnome_vfs_uri_unref(real_uri);
635 retval = GNOME_VFS_ERROR_NOT_FOUND;
641 static GnomeVFSResult
642 tr_do_close_directory(GnomeVFSMethod * method,
643 GnomeVFSMethodHandle * method_handle,
644 GnomeVFSContext * context)
646 TranslateMethod *tm = (TranslateMethod *) method;
647 return tm->real_method->close_directory(tm->real_method,
648 method_handle, context);
651 static GnomeVFSResult
652 tr_do_read_directory(GnomeVFSMethod * method,
653 GnomeVFSMethodHandle * method_handle,
654 GnomeVFSFileInfo * file_info,
655 GnomeVFSContext * context)
657 TranslateMethod *tm = (TranslateMethod *) method;
658 GnomeVFSResult retval;
661 tm->real_method->read_directory(tm->real_method, method_handle,
664 tr_apply_default_mime_type(tm, file_info);
669 static GnomeVFSResult
670 tr_do_get_file_info(GnomeVFSMethod * method,
672 GnomeVFSFileInfo * file_info,
673 GnomeVFSFileInfoOptions options,
674 GnomeVFSContext * context)
676 TranslateMethod *tm = (TranslateMethod *) method;
677 GnomeVFSURI *real_uri;
678 GnomeVFSResult retval;
680 real_uri = tr_uri_translate(tm, uri);
682 if ( NULL != real_uri ) {
684 tm->real_method->get_file_info(tm->real_method, real_uri,
688 gnome_vfs_uri_unref(real_uri);
690 retval = GNOME_VFS_ERROR_NOT_FOUND;
693 tr_apply_default_mime_type(tm, file_info);
698 static GnomeVFSResult
699 tr_do_get_file_info_from_handle(GnomeVFSMethod * method,
700 GnomeVFSMethodHandle * method_handle,
701 GnomeVFSFileInfo * file_info,
702 GnomeVFSFileInfoOptions options,
703 GnomeVFSContext * context)
705 TranslateMethod *tm = (TranslateMethod *) method;
706 GnomeVFSResult retval;
709 tm->real_method->get_file_info_from_handle(tm->real_method,
715 tr_apply_default_mime_type(tm, file_info);
720 static GnomeVFSResult
721 tr_do_truncate(GnomeVFSMethod * method,
723 GnomeVFSFileSize length, GnomeVFSContext * context)
725 TranslateMethod *tm = (TranslateMethod *) method;
726 GnomeVFSURI *real_uri;
727 GnomeVFSResult retval;
729 real_uri = tr_uri_translate(tm, uri);
731 if ( NULL != real_uri ) {
733 tm->real_method->truncate(tm->real_method, real_uri, length,
736 gnome_vfs_uri_unref(real_uri);
738 retval = GNOME_VFS_ERROR_NOT_FOUND;
744 static GnomeVFSResult
745 tr_do_truncate_handle(GnomeVFSMethod * method,
746 GnomeVFSMethodHandle * method_handle,
747 GnomeVFSFileSize length, GnomeVFSContext * context)
749 TranslateMethod *tm = (TranslateMethod *) method;
751 return tm->real_method->truncate_handle(tm->real_method,
752 method_handle, length,
757 tr_do_is_local(GnomeVFSMethod * method, const GnomeVFSURI * uri)
759 TranslateMethod *tm = (TranslateMethod *) method;
760 GnomeVFSURI *real_uri;
761 GnomeVFSResult retval;
763 real_uri = tr_uri_translate(tm, uri);
765 if ( NULL != real_uri ) {
766 retval = tm->real_method->is_local(tm->real_method, real_uri);
768 gnome_vfs_uri_unref(real_uri);
770 retval = GNOME_VFS_ERROR_NOT_FOUND;
776 static GnomeVFSResult
777 tr_do_make_directory(GnomeVFSMethod * method,
779 guint perm, GnomeVFSContext * context)
781 TranslateMethod *tm = (TranslateMethod *) method;
782 GnomeVFSURI *real_uri;
783 GnomeVFSResult retval;
785 real_uri = tr_uri_translate(tm, uri);
787 if ( NULL != real_uri ) {
789 tm->real_method->make_directory(tm->real_method, real_uri,
792 gnome_vfs_uri_unref(real_uri);
794 retval = GNOME_VFS_ERROR_NOT_FOUND;
800 static GnomeVFSResult
801 tr_do_find_directory(GnomeVFSMethod * method,
802 GnomeVFSURI * near_uri,
803 GnomeVFSFindDirectoryKind kind,
804 GnomeVFSURI ** result_uri,
805 gboolean create_if_needed,
806 gboolean find_if_needed,
807 guint permissions, GnomeVFSContext * context)
809 TranslateMethod *tm = (TranslateMethod *) method;
810 GnomeVFSURI *real_uri;
811 GnomeVFSResult retval;
813 real_uri = tr_uri_translate(tm, near_uri);
815 if ( NULL != real_uri ) {
817 tm->real_method->find_directory(tm->real_method, real_uri,
819 create_if_needed, find_if_needed,
823 gnome_vfs_uri_unref(real_uri);
825 retval = GNOME_VFS_ERROR_NOT_FOUND;
833 static GnomeVFSResult
834 tr_do_remove_directory(GnomeVFSMethod * method,
835 GnomeVFSURI * uri, GnomeVFSContext * context)
837 TranslateMethod *tm = (TranslateMethod *) method;
838 GnomeVFSURI *real_uri;
839 GnomeVFSResult retval;
841 real_uri = tr_uri_translate(tm, uri);
843 if ( NULL != real_uri ) {
845 tm->real_method->remove_directory(tm->real_method, real_uri,
848 gnome_vfs_uri_unref(real_uri);
850 retval = GNOME_VFS_ERROR_NOT_FOUND;
856 static GnomeVFSResult
857 tr_do_move(GnomeVFSMethod * method,
858 GnomeVFSURI * old_uri,
859 GnomeVFSURI * new_uri,
860 gboolean force_replace, GnomeVFSContext * context)
862 TranslateMethod *tm = (TranslateMethod *) method;
863 GnomeVFSURI *real_uri_old, *real_uri_new;
864 GnomeVFSResult retval;
866 real_uri_old = tr_uri_translate(tm, old_uri);
867 real_uri_new = tr_uri_translate(tm, new_uri);
869 if ( NULL != real_uri_old && NULL != real_uri_new ) {
871 tm->real_method->move(tm->real_method, real_uri_old,
872 real_uri_new, force_replace, context);
875 retval = GNOME_VFS_ERROR_NOT_FOUND;
878 if (real_uri_old) {gnome_vfs_uri_unref(real_uri_old);}
879 if (real_uri_new) {gnome_vfs_uri_unref(real_uri_new);}
884 static GnomeVFSResult
885 tr_do_unlink(GnomeVFSMethod * method,
886 GnomeVFSURI * uri, GnomeVFSContext * context)
888 TranslateMethod *tm = (TranslateMethod *) method;
889 GnomeVFSURI *real_uri;
890 GnomeVFSResult retval;
892 real_uri = tr_uri_translate(tm, uri);
894 if ( NULL != real_uri ) {
896 tm->real_method->unlink(tm->real_method, real_uri, context);
898 gnome_vfs_uri_unref(real_uri);
900 retval = GNOME_VFS_ERROR_NOT_FOUND;
906 static GnomeVFSResult
907 tr_do_check_same_fs(GnomeVFSMethod * method,
910 gboolean * same_fs_return, GnomeVFSContext * context)
912 TranslateMethod *tm = (TranslateMethod *) method;
913 GnomeVFSURI *real_uri_a, *real_uri_b;
914 GnomeVFSResult retval;
916 real_uri_a = tr_uri_translate(tm, a);
917 real_uri_b = tr_uri_translate(tm, b);
919 if ( NULL != real_uri_a && NULL != real_uri_b ) {
921 tm->real_method->check_same_fs(tm->real_method, real_uri_a,
922 real_uri_b, same_fs_return,
925 retval = GNOME_VFS_ERROR_NOT_FOUND;
928 if (real_uri_a) {gnome_vfs_uri_unref(real_uri_a);}
929 if (real_uri_b) {gnome_vfs_uri_unref(real_uri_b);}
934 static GnomeVFSResult
935 tr_do_set_file_info(GnomeVFSMethod * method,
937 const GnomeVFSFileInfo * info,
938 GnomeVFSSetFileInfoMask mask,
939 GnomeVFSContext * context)
941 TranslateMethod *tm = (TranslateMethod *) method;
942 GnomeVFSURI *real_uri_a;
943 GnomeVFSResult retval;
945 real_uri_a = tr_uri_translate(tm, a);
947 if ( NULL != real_uri_a ) {
949 tm->real_method->set_file_info(tm->real_method, real_uri_a,
950 info, mask, context);
952 gnome_vfs_uri_unref(real_uri_a);
954 retval = GNOME_VFS_ERROR_NOT_FOUND;
960 /******** from poptparse.c:
961 Copyright (c) 1998 Red Hat Software
963 Permission is hereby granted, free of charge, to any person obtaining a copy
964 of this software and associated documentation files (the "Software"), to deal
965 in the Software without restriction, including without limitation the rights
966 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
967 copies of the Software, and to permit persons to whom the Software is
968 furnished to do so, subject to the following conditions:
970 The above copyright notice and this permission notice shall be included in
971 all copies or substantial portions of the Software.
973 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
974 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
975 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
976 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
977 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
978 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
980 Except as contained in this notice, the name of the X Consortium shall not be
981 used in advertising or otherwise to promote the sale, use or other dealings
982 in this Software without prior written authorization from the X Consortium.
986 #define POPT_ARGV_ARRAY_GROW_DELTA 5
987 static int my_poptParseArgvString(char *buf, int *argcPtr, char ***argvPtr)
991 int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
992 char **argv = g_new(char *, argvAlloced);
996 s = g_alloca(strlen(buf) + 1);
1001 for (src = s; *src; src++) {
1002 if (quote == *src) {
1015 } else if (g_ascii_isspace(*src)) {
1019 /* leave one empty argv at the end */
1020 if (argc == argvAlloced - 1) {
1022 POPT_ARGV_ARRAY_GROW_DELTA;
1050 if (strlen(argv[argc])) {
1054 /* add NULL to the end of argv */
1063 static gboolean tr_args_parse(ParsedArgs * pa, const char *args)
1069 gboolean badargs = FALSE;
1070 gboolean mode_determined = FALSE;
1072 memset(pa, 0, sizeof(ParsedArgs));
1074 tmp_args = g_alloca(strlen(args) + 1);
1075 strcpy(tmp_args, args);
1077 if (my_poptParseArgvString(tmp_args, &argc, &argv)) {
1078 g_warning("Failed to parse arguments: %s", args);
1082 for (i = 0; i < argc; i++) {
1083 #define CHECK_ARG() if((++i) >= argc) { badargs = TRUE; goto out; }
1084 #define CHECK_MODE(my_mode) if (mode_determined && pa->mode != (my_mode)) { badargs = TRUE ; goto out; } else { pa->mode = my_mode; mode_determined = TRUE; }
1085 if (g_ascii_strcasecmp(argv[i], "-pattern") == 0) {
1087 CHECK_MODE(MODE_BASIC);
1088 pa->u.basic.trans_string = g_strdup(argv[i]);
1089 } else if (g_ascii_strcasecmp(argv[i], "-real-method") == 0) {
1091 pa->real_method_name = g_strdup(argv[i]);
1092 } else if (g_ascii_strcasecmp(argv[i], "-exec") == 0) {
1094 CHECK_MODE(MODE_EXEC);
1095 pa->u.exec.orig_string = g_strdup(argv[i]);
1096 } else if (g_ascii_strcasecmp(argv[i], "-retain") == 0) {
1097 CHECK_MODE(MODE_EXEC);
1098 pa->u.exec.retain = TRUE;
1099 } else if (g_ascii_strcasecmp(argv[i], "-default-mime-type") == 0) {
1101 pa->default_mime_type = g_strdup(argv[i]);
1103 g_warning("Unknown option `%s'", argv[i]);
1111 if ( ! mode_determined ) {
1112 g_warning("Need a -pattern option or -exec option");
1114 } else if (MODE_BASIC == pa->mode) {
1115 if (!pa->real_method_name) {
1116 g_warning("Need a -real-method option");
1118 } else if (!pa->u.basic.trans_string) {
1119 g_warning("Need a -pattern option");
1122 } else if (MODE_EXEC == pa->mode) {
1123 if (!pa->real_method_name) {
1124 g_warning("Need a -real-method option");
1126 } else if (!pa->u.exec.orig_string) {
1127 g_warning("Need a -exec option");
1131 /* Chop up the exec string here */
1132 if (my_poptParseArgvString (
1133 pa->u.exec.orig_string,
1137 g_warning ("Failed to parse -exec args");
1149 static GnomeVFSMethod base_vfs_method = {
1150 sizeof (GnomeVFSMethod),
1158 tr_do_truncate_handle,
1159 tr_do_open_directory,
1160 tr_do_close_directory,
1161 tr_do_read_directory,
1162 tr_do_get_file_info,
1163 tr_do_get_file_info_from_handle,
1165 tr_do_make_directory,
1166 tr_do_remove_directory,
1169 tr_do_check_same_fs,
1170 tr_do_set_file_info,
1172 tr_do_find_directory,
1173 NULL /* create_symbolic_link can't be supported */
1174 /* Hey YOU! If you add a GnomeVFS method, you need to do two things
1175 * in the translate-method module:
1177 * 1. Add a line to the CHECK_NULL_METHOD list in vfs_module_init
1178 * 2. Implement the function in this module. This is pretty simple--
1179 * just follow the pattern of existing functions
1183 static void tr_args_free(ParsedArgs * pa)
1185 g_free(pa->default_mime_type);
1186 g_free(pa->real_method_name);
1188 if (MODE_BASIC == pa->mode) {
1189 g_free(pa->u.basic.trans_string);
1191 g_free(pa->u.exec.orig_string);
1195 GnomeVFSMethod *vfs_module_init(const char *method_name, const char *args)
1197 TranslateMethod *retval;
1200 if (!tr_args_parse(&pa, args))
1203 retval = g_new0(TranslateMethod, 1);
1205 retval->real_method = gnome_vfs_method_get(pa.real_method_name);
1207 if (!retval->real_method) {
1208 tr_args_free(&retval->pa);
1213 tr_exec_init(&(retval->exec_state));
1215 retval->base_method = base_vfs_method;
1217 #define CHECK_NULL_METHOD(x) if(!VFS_METHOD_HAS_FUNC (retval->real_method, x)) retval->base_method.x = NULL
1218 CHECK_NULL_METHOD(open);
1219 CHECK_NULL_METHOD(create);
1220 CHECK_NULL_METHOD(close);
1221 CHECK_NULL_METHOD(read);
1222 CHECK_NULL_METHOD(write);
1223 CHECK_NULL_METHOD(seek);
1224 CHECK_NULL_METHOD(tell);
1225 CHECK_NULL_METHOD(truncate);
1226 CHECK_NULL_METHOD(open_directory);
1227 CHECK_NULL_METHOD(close_directory);
1228 CHECK_NULL_METHOD(read_directory);
1229 CHECK_NULL_METHOD(get_file_info);
1230 CHECK_NULL_METHOD(get_file_info_from_handle);
1231 CHECK_NULL_METHOD(is_local);
1232 CHECK_NULL_METHOD(make_directory);
1233 CHECK_NULL_METHOD(remove_directory);
1234 CHECK_NULL_METHOD(move);
1235 CHECK_NULL_METHOD(unlink);
1236 CHECK_NULL_METHOD(check_same_fs);
1237 CHECK_NULL_METHOD(set_file_info);
1238 CHECK_NULL_METHOD(truncate_handle);
1239 CHECK_NULL_METHOD(find_directory);
1240 /*CHECK_NULL_METHOD(create_symbolic_link);*/
1241 retval->base_method.create_symbolic_link = NULL;
1242 #undef CHECK_NULL_METHOD
1244 return (GnomeVFSMethod *) retval;
1248 vfs_module_shutdown (GnomeVFSMethod * method)
1250 TranslateMethod *tmethod = (TranslateMethod *) method;
1252 tr_exec_cleanup (&(tmethod->exec_state));
1254 tr_args_free(&tmethod->pa);