source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-method.c @ 18154

Revision 18154, 9.3 KB checked in by ghudson, 22 years ago (diff)
Work around Solaris #defines for truncate, tell, and stat.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* gnome-vfs-method.c - Handling of access methods in the GNOME
3   Virtual File System.
4
5   Copyright (C) 1999 Free Software Foundation
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   Author: Ettore Perazzoli <ettore@gnu.org> */
23
24#include <config.h>
25#include "gnome-vfs-method.h"
26
27#include <stdlib.h>
28#include <string.h>
29#include <sys/types.h>
30#include <unistd.h>
31
32#include <glib.h>
33#include <gmodule.h>
34
35#include <libgnomevfs/gnome-vfs-transform.h>
36#include <libgnomevfs/gnome-vfs-module.h>
37#include <libgnomevfs/gnome-vfs-private.h>
38
39
40struct _ModuleElement {
41        char *name;
42        const char *args;
43        GnomeVFSMethod *method;
44        GnomeVFSTransform *transform;
45        int nusers;
46};
47typedef struct _ModuleElement ModuleElement;
48
49static gboolean method_already_initialized = FALSE;
50G_LOCK_DEFINE_STATIC (method_already_initialized);
51
52static GHashTable *module_hash = NULL;
53G_LOCK_DEFINE_STATIC (module_hash);
54
55static GList *module_path_list = NULL;
56G_LOCK_DEFINE_STATIC (module_path_list);
57
58
59static gboolean
60init_hash_table (void)
61{
62        G_LOCK (module_hash);
63        module_hash = g_hash_table_new (g_str_hash, g_str_equal);
64        G_UNLOCK (module_hash);
65
66        return TRUE;
67}
68
69static gboolean
70install_path_list (const gchar *user_path_list)
71{
72        const gchar *p, *oldp;
73
74        /* Notice that this assumes the list has already been locked.  */
75
76        oldp = user_path_list;
77        while (1) {
78                gchar *elem;
79
80                p = strchr (oldp, ':');
81
82                if (p == NULL) {
83                        if (*oldp != '\0') {
84                                elem = g_strdup (oldp);
85                                module_path_list = g_list_append
86                                                       (module_path_list, elem);
87                        }
88                        break;
89                } else if (p != oldp) {
90                        elem = g_strndup (oldp, p - oldp);
91                        module_path_list = g_list_append (module_path_list,
92                                                          elem);
93                } else {
94                        elem = NULL;
95                }
96
97                oldp = p + 1;
98        }
99
100        return TRUE;
101}
102
103static gboolean
104init_path_list (void)
105{
106        const gchar *user_path_list;
107        gboolean retval;
108
109        retval = TRUE;
110
111        G_LOCK (module_path_list);
112
113        if (module_path_list != NULL) {
114                retval = TRUE;
115                goto end;
116        }
117
118        /* User-supplied path.  */
119
120        user_path_list = getenv ("GNOME_VFS_MODULE_PATH");
121        if (user_path_list != NULL) {
122                if (! install_path_list (user_path_list)) {
123                        retval = FALSE;
124                        goto end;
125                }
126        }
127
128        /* Default path.  It comes last so that users can override it.  */
129
130        module_path_list = g_list_append (module_path_list,
131                                          g_strdup (GNOME_VFS_MODULE_DIR));
132
133 end:
134        G_UNLOCK (module_path_list);
135        return retval;
136}
137
138gboolean
139gnome_vfs_method_init (void)
140{
141        G_LOCK (method_already_initialized);
142
143        if (method_already_initialized) {
144                G_UNLOCK (method_already_initialized);
145                return TRUE;
146        }
147
148        if (! init_hash_table ())
149                return FALSE;
150        if (! init_path_list ())
151                return FALSE;
152
153        method_already_initialized = TRUE;
154        G_UNLOCK (method_already_initialized);
155
156        return TRUE;
157}
158
159/* Athena hack to work around Solaris #define of "tell" */
160#undef tell
161
162static void
163load_module (const gchar *module_name, const char *method_name, const char *args,
164             GnomeVFSMethod **method, GnomeVFSTransform **transform)
165{
166        GModule *module;
167        GnomeVFSMethod *temp_method = NULL;
168        GnomeVFSTransform *temp_transform = NULL;
169       
170        GnomeVFSMethodInitFunc init_function = NULL;
171        GnomeVFSTransformInitFunc transform_function = NULL;
172        GnomeVFSMethodShutdownFunc shutdown_function = NULL;
173
174        *method = NULL;
175        *transform = NULL;
176
177        module = g_module_open (module_name, G_MODULE_BIND_LAZY);
178        if (module == NULL) {
179                g_warning ("Cannot load module `%s' (%s)", module_name, g_module_error ());
180                return;
181        }
182
183        g_module_symbol (module, GNOME_VFS_MODULE_INIT,
184                         (gpointer *) &init_function);
185        g_module_symbol (module, GNOME_VFS_MODULE_TRANSFORM,
186                         (gpointer *) &transform_function);
187        g_module_symbol (module, GNOME_VFS_MODULE_SHUTDOWN,
188                         (gpointer *) &shutdown_function);
189       
190        if ((init_function == NULL || shutdown_function == NULL) &&
191            (transform_function == NULL)) {
192                g_warning ("module '%s' has no init function; may be an out-of-date module", module_name);
193                return;
194        }
195
196        if (init_function)
197                temp_method = (* init_function) (method_name, args);
198
199        if (temp_method == NULL && init_function) {
200                g_warning ("module '%s' returned a NULL handle", module_name);
201                return;
202        }
203
204        if (temp_method != NULL) {
205                /* Some basic checks */
206                if (temp_method->method_table_size == 0) {
207                        g_warning ("module '%s' has 0 table size", module_name);
208                        return;
209                } else if (temp_method->method_table_size > (0x100 * sizeof (GnomeVFSMethod))) {
210                        g_warning ("module '%s' has unreasonable table size, perhaps it is using the old GnomeVFSMethod struct?", module_name);
211                        return;
212                } else if (!VFS_METHOD_HAS_FUNC(temp_method, open)) {
213                        g_warning ("module '%s' has no open fn", module_name);
214                        return;
215#if 0
216                } else if (!VFS_METHOD_HAS_FUNC(temp_method, create)) {
217                        g_warning ("module '%s' has no create fn", module_name);
218                        return;
219#endif
220                } else if (!VFS_METHOD_HAS_FUNC(temp_method, is_local)) {
221                        g_warning ("module '%s' has no is-local fn", module_name);
222                        return;
223#if 0
224                } else if (!VFS_METHOD_HAS_FUNC(temp_method, get_file_info)) {
225                        g_warning ("module '%s' has no get-file-info fn", module_name);
226                        return;
227#endif
228                }
229
230                /* More advanced assumptions.  */
231                if (VFS_METHOD_HAS_FUNC(temp_method, tell) && !VFS_METHOD_HAS_FUNC(temp_method, seek)) {
232                        g_warning ("module '%s' has tell and no seek", module_name);
233                        return;
234                }
235
236                if (VFS_METHOD_HAS_FUNC(temp_method, seek) && !VFS_METHOD_HAS_FUNC(temp_method, tell)) {
237                        g_warning ("module '%s' has seek and no tell", module_name);
238                        return;
239                }
240        }
241
242        if (transform_function)
243                temp_transform = (* transform_function) (method_name, args);
244        if (temp_transform) {
245                if (temp_transform->transform == NULL) {
246                        g_warning ("module '%s' has no transform method", module_name);
247                        return;
248                }
249        }
250
251        *method = temp_method;
252        *transform = temp_transform;
253}
254
255static void
256load_module_in_path_list (const gchar *base_name, const char *method_name, const char *args,
257                          GnomeVFSMethod **method, GnomeVFSTransform **transform)
258{
259        GList *p;
260
261        *method = NULL;
262        *transform = NULL;
263       
264        for (p = module_path_list; p != NULL; p = p->next) {
265                const gchar *path;
266                gchar *name;
267
268                path = p->data;
269                name = g_module_build_path (path, base_name);
270
271                load_module (name, method_name, args, method, transform);
272                g_free (name);
273
274                if (*method != NULL || *transform != NULL)
275                        return;
276        }
277}
278
279static gboolean
280gnome_vfs_add_module_to_hash_table (const gchar *name)
281{
282        GnomeVFSMethod *method = NULL;
283        GnomeVFSTransform *transform = NULL;
284        ModuleElement *module_element;
285        const char *module_name;
286        pid_t saved_uid;
287        gid_t saved_gid;
288        const char *args;
289
290        G_LOCK (module_hash);
291        module_element = g_hash_table_lookup (module_hash, name);
292        G_UNLOCK (module_hash);
293
294        if (module_element != NULL)
295                return TRUE;
296
297        module_name = gnome_vfs_configuration_get_module_path (name, &args);
298        if (module_name == NULL)
299                return FALSE;
300
301        /* Set the effective UID/GID to the user UID/GID to prevent attacks to
302           setuid/setgid executables.  */
303
304        saved_uid = geteuid ();
305        saved_gid = getegid ();
306        seteuid (getuid ());
307        setegid (getgid ());
308
309        if (g_path_is_absolute (module_name))
310                load_module (module_name, name, args, &method, &transform);
311        else
312                load_module_in_path_list (module_name, name, args, &method, &transform);
313
314        seteuid (saved_uid);
315        setegid (saved_gid);
316
317        if (method == NULL && transform == NULL)
318                return FALSE;
319
320        module_element = g_new (ModuleElement, 1);
321        module_element->name = g_strdup (name);
322        module_element->method = method;
323        module_element->transform = transform;
324
325        G_LOCK (module_hash);
326        g_hash_table_insert (module_hash, module_element->name, module_element);
327        G_UNLOCK (module_hash);
328
329        return TRUE;
330}
331
332GnomeVFSMethod *
333gnome_vfs_method_get (const gchar *name)
334{
335        ModuleElement *module_element;
336
337        g_return_val_if_fail (name != NULL, NULL);
338
339        G_LOCK (module_hash);
340        module_element = g_hash_table_lookup (module_hash, name);
341        G_UNLOCK (module_hash);
342
343        if (module_element != NULL)
344                return module_element->method;
345
346        if (gnome_vfs_add_module_to_hash_table (name)) {
347                G_LOCK (module_hash);
348                module_element = g_hash_table_lookup (module_hash, name);
349                G_UNLOCK (module_hash);
350               
351                if (module_element != NULL)
352                        return module_element->method;
353        }
354
355        return NULL;
356}
357
358GnomeVFSTransform *
359gnome_vfs_transform_get (const gchar *name)
360{
361        ModuleElement *module_element;
362
363        g_return_val_if_fail (name != NULL, NULL);
364
365        G_LOCK (module_hash);
366        module_element = g_hash_table_lookup (module_hash, name);
367        G_UNLOCK (module_hash);
368
369        if (module_element != NULL)
370                return module_element->transform;
371
372        if (gnome_vfs_add_module_to_hash_table (name)) {
373                G_LOCK (module_hash);
374                module_element = g_hash_table_lookup (module_hash, name);
375                G_UNLOCK (module_hash);
376               
377                if (module_element != NULL)
378                        return module_element->transform;
379        }
380
381        return NULL;
382}
Note: See TracBrowser for help on using the repository browser.