ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / modules / pipe-method.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* pipe-method.c - pipe access method for GNOME Virtual File System
3
4    Copyright (C) 1999, 2000 Red Hat Inc.
5
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.
10
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.
15
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.
20
21    Author: Elliot Lee <sopwith@redhat.com> */
22
23 #include <config.h>
24
25 #include <glib/gstrfuncs.h>
26 #include <libgnomevfs/gnome-vfs-cancellation.h>
27 #include <libgnomevfs/gnome-vfs-context.h>
28 #include <libgnomevfs/gnome-vfs-method.h>
29 #include <libgnomevfs/gnome-vfs-mime.h>
30 #include <libgnomevfs/gnome-vfs-mime-utils.h>
31 #include <libgnomevfs/gnome-vfs-module-shared.h>
32 #include <libgnomevfs/gnome-vfs-module.h>
33 #include <libgnomevfs/gnome-vfs-utils.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 struct _FileHandle {
38         GnomeVFSURI *uri;
39         FILE *fh;
40 };
41 typedef struct _FileHandle FileHandle;
42
43 static FileHandle *
44 file_handle_new (GnomeVFSURI *uri,
45                  FILE *fh)
46 {
47         FileHandle *new;
48
49         new = g_new (FileHandle, 1);
50
51         new->uri = gnome_vfs_uri_ref (uri);
52         new->fh = fh;
53
54         return new;
55 }
56
57 static void
58 file_handle_destroy (FileHandle *handle)
59 {
60         pclose(handle->fh);
61         gnome_vfs_uri_unref (handle->uri);
62         g_free (handle);
63 }
64
65 static char *
66 str_without_suffix (const char *str)
67 {
68         const char *semicolon;
69
70         semicolon = strchr (str, ';');
71         
72         return g_strndup (str, (semicolon == NULL) ? strlen (str) : semicolon - str);
73 }
74
75 static char *
76 mime_from_uri (const gchar *uri)
77 {
78         const char *mime;
79         char *result;
80         
81         mime = uri == NULL ? NULL : strstr (uri, ";mime-type=");
82         if (mime != NULL) {
83                 result = str_without_suffix (mime + 11);
84                 if (result[0] == '\0') {
85                         /* No mime-type specified */
86                         g_free (result);
87                         result = g_strdup (GNOME_VFS_MIME_TYPE_UNKNOWN);
88                 }
89         } else {
90                 result = g_strdup (GNOME_VFS_MIME_TYPE_UNKNOWN);
91         }
92         return result;
93 }
94
95
96 static void
97 set_default_file_info (GnomeVFSFileInfo *file_info,
98                        GnomeVFSURI *uri)
99 {
100         file_info->name = g_strdup (uri->text);
101         file_info->flags = GNOME_VFS_FILE_FLAGS_NONE;
102         file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
103         file_info->permissions = (GNOME_VFS_PERM_USER_READ
104                                   | GNOME_VFS_PERM_GROUP_READ
105                                   | GNOME_VFS_PERM_OTHER_READ);
106
107         file_info->valid_fields = (GNOME_VFS_FILE_INFO_FIELDS_FLAGS
108                                    | GNOME_VFS_FILE_INFO_FIELDS_TYPE 
109                                    | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS);
110 }
111
112 #define SAFE_POPEN_CHARACTERS "?'/. +:-_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
113
114
115 static GnomeVFSResult
116 do_open (GnomeVFSMethod *method,
117          GnomeVFSMethodHandle **method_handle,
118          GnomeVFSURI *uri,
119          GnomeVFSOpenMode mode,
120          GnomeVFSContext *context)
121 {
122         FileHandle *file_handle;
123         FILE *fh;
124         char *real_uri;
125
126         _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
127         _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
128
129         if (!(mode & GNOME_VFS_OPEN_READ))
130                 return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
131
132         real_uri = str_without_suffix (gnome_vfs_unescape_string (uri->text, ""));
133
134         /* Check that all the characters being passed to popen are "safe" */
135         /* If we allow just any characters through, it's easy to make URIs 
136          * that make dangerous command lines here. If we prevent any 
137          * interesting characters, then it's just simple parameters passed 
138          * to the command that's the first thing passed in, which is much 
139          * safer.
140          * Without this "man:ls&shutdown -h now" would have undesired effects.
141          */
142         if (strspn (real_uri, SAFE_POPEN_CHARACTERS) != strlen (real_uri)) {
143                 g_message ("real_uri is %s, has illegal chars, failing", real_uri);
144                 g_free (real_uri);
145                 return GNOME_VFS_ERROR_NOT_PERMITTED;
146         }
147
148         fh = popen (real_uri, "r");
149         g_free (real_uri);
150
151         if (!fh)
152                 return gnome_vfs_result_from_errno ();
153
154         file_handle = file_handle_new (uri, fh);
155         
156         *method_handle = (GnomeVFSMethodHandle *) file_handle;
157
158         return GNOME_VFS_OK;
159 }
160
161 static GnomeVFSResult
162 do_close (GnomeVFSMethod *method,
163           GnomeVFSMethodHandle *method_handle,
164           GnomeVFSContext *context)
165 {
166         FileHandle *file_handle;
167
168         g_return_val_if_fail (method_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
169
170         file_handle = (FileHandle *) method_handle;
171
172         file_handle_destroy (file_handle);
173
174         return GNOME_VFS_OK;
175 }
176
177 static GnomeVFSResult
178 do_read (GnomeVFSMethod *method,
179          GnomeVFSMethodHandle *method_handle,
180          gpointer buffer,
181          GnomeVFSFileSize num_bytes,
182          GnomeVFSFileSize *bytes_read,
183          GnomeVFSContext *context)
184 {
185         FileHandle *file_handle;
186         gint read_val;
187
188         g_return_val_if_fail (method_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
189
190         file_handle = (FileHandle *) method_handle;
191
192         read_val = fread (buffer, 1, num_bytes, file_handle->fh);
193
194         if (read_val <= 0) {
195                 *bytes_read = 0;
196                 return GNOME_VFS_ERROR_EOF;
197         } else {
198                 *bytes_read = read_val;
199                 return GNOME_VFS_OK;
200         }
201 }
202
203 static GnomeVFSResult
204 do_get_file_info (GnomeVFSMethod *method,
205                   GnomeVFSURI *uri,
206                   GnomeVFSFileInfo *file_info,
207                   GnomeVFSFileInfoOptions options,
208                   GnomeVFSContext *context)
209 {
210         set_default_file_info (file_info, uri);
211
212         file_info->mime_type = mime_from_uri (gnome_vfs_unescape_string (uri->text, ""));
213         file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
214
215         return GNOME_VFS_OK;
216 }
217
218 static GnomeVFSResult
219 do_get_file_info_from_handle (GnomeVFSMethod *method,
220                               GnomeVFSMethodHandle *method_handle,
221                               GnomeVFSFileInfo *file_info,
222                               GnomeVFSFileInfoOptions options,
223                               GnomeVFSContext *context)
224 {
225         FileHandle *handle;
226
227         handle = (FileHandle *) method_handle;
228
229         set_default_file_info (file_info, handle->uri);
230
231         file_info->mime_type = mime_from_uri (gnome_vfs_unescape_string (handle->uri->text, ""));
232         file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
233
234         return GNOME_VFS_OK;
235 }
236
237 static gboolean
238 is_local(GnomeVFSMethod *method,
239          const GnomeVFSURI *uri)
240 {
241         return TRUE;
242 }
243
244 static GnomeVFSMethod method = {
245         sizeof (GnomeVFSMethod),
246         do_open,
247         NULL, /* create */
248         do_close,
249         do_read,
250         NULL, /* write */
251         NULL, /* seek */
252         NULL, /* tell */
253         NULL, /* truncate_handle */
254         NULL, /* open_directory */
255         NULL, /* close_directory */
256         NULL, /* read_directory */
257         do_get_file_info,
258         do_get_file_info_from_handle,
259         is_local,
260         NULL, /* make_directory */
261         NULL, /* remove_directory */
262         NULL, /* move */
263         NULL, /* unlink */
264         NULL, /* check_same_fs */
265         NULL, /* set_file_info */
266         NULL, /* truncate */
267         NULL, /* find_directory */
268         NULL  /* create_symbolic_link */
269 };
270
271 GnomeVFSMethod *
272 vfs_module_init (const char *method_name, const char *args)
273 {
274         return &method;
275 }
276
277 void
278 vfs_module_shutdown (GnomeVFSMethod *method)
279 {
280 }