Implemented sub-second W32 filesystem interface by new: CaptiveFileInfoObject
[captive.git] / src / client / gnomevfs / gnome-vfs-method.c
1 /* $Id$
2  * gnome-vfs init/shutdown implementation of interface to libcaptive
3  * Copyright (C) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "gnome-vfs-method.h"   /* self */
23 #include "giognomevfs.h"
24 #include <libgnomevfs/gnome-vfs-method.h>
25 #include <glib/gmessages.h>
26 #include "captive/macros.h"
27 #include "gnome-vfs-module.h"
28 #include "captive/client-directory.h"
29 #include "captive/client-file.h"
30 #include "captive/client-vfs.h"
31 #include <glib/ghash.h>
32
33
34 static GnomeVFSMethod GnomeVFSMethod_static;
35 G_LOCK_DEFINE_STATIC(GnomeVFSMethod_static);
36
37
38 /* map: (gchar *)method_name -> (struct method_name_info *) */
39 static GHashTable *method_name_hash;
40 G_LOCK_DEFINE_STATIC(method_name_hash);
41
42 struct method_name_info {
43         gchar *captive_args;
44         struct captive_options captive_options;
45         };
46
47 static void method_name_hash_key_destroy_func(gchar *key)
48 {
49         g_return_if_fail(key!=NULL);
50
51         g_free(key);
52 }
53
54 static void method_name_hash_value_destroy_func(struct method_name_info *value)
55 {
56         g_return_if_fail(value!=NULL);
57
58         g_free(value->captive_args);
59         captive_options_free(&value->captive_options);
60         g_free(value);
61 }
62
63 static void method_name_hash_init(void)
64 {
65         G_LOCK(method_name_hash);
66         if (!method_name_hash) {
67                 method_name_hash=g_hash_table_new_full(
68                                 g_str_hash,     /* hash_func */
69                                 g_str_equal,    /* key_equal_func */
70                                 (GDestroyNotify)method_name_hash_key_destroy_func,      /* key_destroy_func */
71                                 (GDestroyNotify)method_name_hash_value_destroy_func);   /* value_destroy_func */
72                 }
73         G_UNLOCK(method_name_hash);
74 }
75
76
77 /* map: (gchar *)uri_parent_string "method_name:uri_parent" -> (CaptiveVfsObject *)captive_vfs_object */
78 static GHashTable *uri_parent_string_hash;
79 G_LOCK_DEFINE_STATIC(uri_parent_string_hash);
80
81 static void uri_parent_string_hash_key_destroy_func(gchar *key)
82 {
83         g_return_if_fail(key!=NULL);
84
85         g_free(key);
86 }
87
88 static void uri_parent_string_hash_value_destroy_func(CaptiveVfsObject *value)
89 {
90         g_return_if_fail(value!=NULL);
91
92         g_object_unref(value);
93 }
94
95 static void uri_parent_string_hash_init(void)
96 {
97         G_LOCK(uri_parent_string_hash);
98         if (!uri_parent_string_hash) {
99                 uri_parent_string_hash=g_hash_table_new_full(
100                                 g_str_hash,     /* hash_func */
101                                 g_str_equal,    /* key_equal_func */
102                                 (GDestroyNotify)uri_parent_string_hash_key_destroy_func,        /* key_destroy_func */
103                                 (GDestroyNotify)uri_parent_string_hash_value_destroy_func);     /* value_destroy_func */
104                 }
105         G_UNLOCK(uri_parent_string_hash);
106 }
107
108
109 static GnomeVFSResult captive_gnomevfs_uri_parent_init(CaptiveVfsObject **captive_vfs_object_return,GnomeVFSURI *uri)
110 {
111 const gchar *uri_parent_string;
112 gchar *uri_parent_string_parent;
113 GnomeVFSResult errvfsresult;
114 CaptiveVfsObject *captive_vfs_object;
115
116         g_return_val_if_fail(uri!=NULL,GNOME_VFS_ERROR_INVALID_URI);
117         g_return_val_if_fail(captive_vfs_object_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
118
119         uri_parent_string_hash_init();
120
121         if (!uri->parent)
122                 return GNOME_VFS_ERROR_INVALID_URI;
123         if (!uri->text) /* not needed here but we don't permit non-specific fs-image reference */
124                 return GNOME_VFS_ERROR_INVALID_URI;
125         uri_parent_string_parent=gnome_vfs_uri_to_string(uri->parent,GNOME_VFS_URI_HIDE_NONE);
126         g_assert(uri_parent_string_parent!=NULL);
127
128         uri_parent_string=captive_printf_alloca("%s:%s",uri->method_string,uri_parent_string_parent);
129         g_assert(uri_parent_string!=NULL);
130
131         G_LOCK(uri_parent_string_hash);
132         captive_vfs_object=g_hash_table_lookup(uri_parent_string_hash,uri_parent_string);
133         G_UNLOCK(uri_parent_string_hash);
134         if (!captive_vfs_object) {
135 struct method_name_info *method_name_info;
136 struct captive_options options_captive;
137
138                 G_LOCK(method_name_hash);
139                 method_name_info=g_hash_table_lookup(method_name_hash,uri->method_string);
140                 G_UNLOCK(method_name_hash);
141                 if (!method_name_info)
142                         g_return_val_if_reached(GNOME_VFS_ERROR_INVALID_URI);   /* should not happend */
143                 captive_options_copy(&options_captive,&method_name_info->captive_options);
144
145                 g_assert(options_captive.image_iochannel==NULL);
146                 errvfsresult=captive_gnomevfs_giognomevfs_new(
147                                 (struct captive_gnomevfs_giognomevfs **)&options_captive.image_iochannel,       /* giognomevfsp */
148                                 uri->parent,    /* uri */
149                                 options_captive.rwmode);        /* rwmode */
150                 if (errvfsresult!=GNOME_VFS_OK) {
151                         captive_options_free(&options_captive);
152                         g_assert_not_reached();
153                         return errvfsresult;
154                         }
155
156                 errvfsresult=captive_vfs_new(&captive_vfs_object,&options_captive);
157                 if (errvfsresult!=GNOME_VFS_OK) {
158                         captive_options_free(&options_captive);
159                         g_assert_not_reached();
160                         return errvfsresult;
161                         }
162                 captive_options_free(&options_captive);
163                 G_LOCK(uri_parent_string_hash);
164                 g_hash_table_insert(uri_parent_string_hash,g_strdup(uri_parent_string),captive_vfs_object);
165                 G_UNLOCK(uri_parent_string_hash);
166                 }
167
168         *captive_vfs_object_return=captive_vfs_object;
169         return GNOME_VFS_OK;
170 }
171
172
173 static GnomeVFSResult captive_gnomevfs_open_directory(GnomeVFSMethod *method,
174                 GnomeVFSMethodHandle **method_handle,GnomeVFSURI *uri,GnomeVFSFileInfoOptions options,GnomeVFSContext *context)
175 {
176 GnomeVFSResult errvfsresult;
177 CaptiveVfsObject *captive_vfs_object;
178 CaptiveDirectoryObject *captive_directory_object;
179
180         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
181         g_return_val_if_fail(method_handle!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
182
183         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
184         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
185
186         G_LOCK(libcaptive);
187         errvfsresult=captive_directory_new_open(
188                         &captive_directory_object,      /* captive_directory_object_return */
189                         captive_vfs_object,     /* captive_vfs_object */
190                         uri->text);     /* pathname */
191         G_UNLOCK(libcaptive);
192
193         *method_handle=(GnomeVFSMethodHandle *)captive_directory_object;
194         return errvfsresult;
195 }
196
197
198 static GnomeVFSResult captive_gnomevfs_close_directory(GnomeVFSMethod *method,
199                 GnomeVFSMethodHandle *method_handle,GnomeVFSContext *context)
200 {
201 CaptiveDirectoryObject *captive_directory_object;
202
203         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
204         captive_directory_object=(CaptiveDirectoryObject *)method_handle;
205         g_return_val_if_fail(CAPTIVE_DIRECTORY_IS_OBJECT(captive_directory_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
206
207         G_LOCK(libcaptive);
208         g_object_unref(captive_directory_object);
209         G_UNLOCK(libcaptive);
210
211         return GNOME_VFS_OK;
212 }
213
214
215 static GnomeVFSResult captive_gnomevfs_read_directory(GnomeVFSMethod *method,
216                 GnomeVFSMethodHandle *method_handle,GnomeVFSFileInfo *file_info,GnomeVFSContext *context)
217 {
218 GnomeVFSResult errvfsresult;
219 CaptiveDirectoryObject *captive_directory_object;
220 CaptiveFileInfoObject *captive_file_info_object;
221
222         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
223         captive_directory_object=(CaptiveDirectoryObject *)method_handle;
224         g_return_val_if_fail(CAPTIVE_DIRECTORY_IS_OBJECT(captive_directory_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
225         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
226
227         G_LOCK(libcaptive);
228         errvfsresult=captive_directory_read(captive_directory_object,&captive_file_info_object);
229         G_UNLOCK(libcaptive);
230         if (GNOME_VFS_OK!=errvfsresult)
231                 return errvfsresult;
232
233         gnome_vfs_file_info_copy(file_info,&captive_file_info_object->p);
234         G_LOCK(libcaptive);
235         g_object_unref(captive_file_info_object);
236         G_UNLOCK(libcaptive);
237
238         return GNOME_VFS_OK;
239 }
240
241
242 static GnomeVFSResult captive_gnomevfs_make_directory(GnomeVFSMethod *method,
243                 GnomeVFSURI *uri,guint perm,GnomeVFSContext *context)
244 {
245 GnomeVFSResult errvfsresult;
246 CaptiveVfsObject *captive_vfs_object;
247 CaptiveDirectoryObject *captive_directory_object;
248
249         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
250
251         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
252         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
253
254         G_LOCK(libcaptive);
255         errvfsresult=captive_directory_new_make(
256                         &captive_directory_object,      /* captive_directory_object_return */
257                         captive_vfs_object,     /* captive_vfs_object */
258                         uri->text,      /* pathname */
259                         perm);  /* perm */
260         G_UNLOCK(libcaptive);
261         if (errvfsresult!=GNOME_VFS_OK)
262                 return errvfsresult;
263
264         G_LOCK(libcaptive);
265         g_object_unref(captive_directory_object);
266         G_UNLOCK(libcaptive);
267
268         return GNOME_VFS_OK;
269 }
270
271
272 static GnomeVFSResult captive_gnomevfs_remove_directory(GnomeVFSMethod *method,
273                 GnomeVFSURI *uri,GnomeVFSContext *context)
274 {
275 GnomeVFSResult errvfsresult;
276 CaptiveVfsObject *captive_vfs_object;
277 CaptiveDirectoryObject *captive_directory_object;
278
279         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
280
281         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
282         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
283
284         G_LOCK(libcaptive);
285         errvfsresult=captive_directory_new_open(
286                         &captive_directory_object,      /* captive_directory_object_return */
287                         captive_vfs_object,     /* captive_vfs_object */
288                         uri->text);     /* pathname */
289         G_UNLOCK(libcaptive);
290         if (errvfsresult!=GNOME_VFS_OK)
291                 return errvfsresult;
292
293         G_LOCK(libcaptive);
294         errvfsresult=captive_directory_remove(captive_directory_object);
295         G_UNLOCK(libcaptive);
296
297         G_LOCK(libcaptive);
298         g_object_unref(captive_directory_object);
299         G_UNLOCK(libcaptive);
300
301         return errvfsresult;
302 }
303
304
305 static GnomeVFSResult captive_gnomevfs_open(GnomeVFSMethod *method,
306                 GnomeVFSMethodHandle **method_handle_return,GnomeVFSURI *uri,GnomeVFSOpenMode mode,GnomeVFSContext *context)
307 {
308 GnomeVFSResult errvfsresult;
309 CaptiveVfsObject *captive_vfs_object;
310 CaptiveFileObject *captive_file_object;
311
312         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
313         g_return_val_if_fail(method_handle_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
314
315         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
316         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
317
318         G_LOCK(libcaptive);
319         errvfsresult=captive_file_new_open(
320                         &captive_file_object,   /* captive_file_object_return */
321                         captive_vfs_object,     /* captive_vfs_object */
322                         uri->text,      /* pathname */
323                         mode);  /* mode */
324         G_UNLOCK(libcaptive);
325
326         *method_handle_return=(GnomeVFSMethodHandle *)captive_file_object;
327         return errvfsresult;
328 }
329
330
331 static GnomeVFSResult captive_gnomevfs_create(GnomeVFSMethod *method,
332                 GnomeVFSMethodHandle **method_handle_return,GnomeVFSURI *uri,GnomeVFSOpenMode mode,gboolean exclusive,guint perm,
333                 GnomeVFSContext *context)
334 {
335 GnomeVFSResult errvfsresult;
336 CaptiveVfsObject *captive_vfs_object;
337 CaptiveFileObject *captive_file_object;
338
339         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
340         g_return_val_if_fail(method_handle_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
341
342         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
343         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
344
345         G_LOCK(libcaptive);
346         errvfsresult=captive_file_new_create(
347                         &captive_file_object,   /* captive_file_object_return */
348                         captive_vfs_object,     /* captive_vfs_object */
349                         uri->text,      /* pathname */
350                         mode,   /* mode */
351                         exclusive,      /* exclusive */
352                         perm);  /* perm */
353         G_UNLOCK(libcaptive);
354
355         *method_handle_return=(GnomeVFSMethodHandle *)captive_file_object;
356         return errvfsresult;
357 }
358
359
360 GnomeVFSResult captive_gnomevfs_unlink(GnomeVFSMethod *method,
361                 GnomeVFSURI *uri,GnomeVFSContext *context)
362 {
363 GnomeVFSResult errvfsresult;
364 CaptiveVfsObject *captive_vfs_object;
365 CaptiveFileObject *captive_file_object;
366
367         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
368
369         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
370         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
371
372         G_LOCK(libcaptive);
373         errvfsresult=captive_file_new_open(
374                         &captive_file_object,   /* captive_file_object_return */
375                         captive_vfs_object,     /* captive_vfs_object */
376                         uri->text,      /* pathname */
377                         (GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM));  /* mode; is it OK? */
378         G_UNLOCK(libcaptive);
379         if (errvfsresult!=GNOME_VFS_OK)
380                 return errvfsresult;
381
382         G_LOCK(libcaptive);
383         errvfsresult=captive_file_remove(captive_file_object);
384         G_UNLOCK(libcaptive);
385
386         G_LOCK(libcaptive);
387         g_object_unref(captive_file_object);
388         G_UNLOCK(libcaptive);
389
390         return errvfsresult;
391 }
392
393
394 static GnomeVFSResult captive_gnomevfs_close(GnomeVFSMethod *method,
395                 GnomeVFSMethodHandle *method_handle,GnomeVFSContext *context)
396 {
397 CaptiveFileObject *captive_file_object;
398
399         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
400         captive_file_object=(CaptiveFileObject *)method_handle;
401         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
402
403         G_LOCK(libcaptive);
404         g_object_unref(captive_file_object);
405         G_UNLOCK(libcaptive);
406
407         return GNOME_VFS_OK;
408 }
409
410
411 static GnomeVFSResult captive_gnomevfs_read(GnomeVFSMethod *method,GnomeVFSMethodHandle *method_handle,
412                 gpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_read_return,GnomeVFSContext *context)
413 {
414 GnomeVFSResult errvfsresult;
415 CaptiveFileObject *captive_file_object;
416
417         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
418         captive_file_object=(CaptiveFileObject *)method_handle;
419         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
420         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
421         g_return_val_if_fail(bytes_read_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
422
423         G_LOCK(libcaptive);
424         errvfsresult=captive_file_read(captive_file_object,buffer,num_bytes,bytes_read_return);
425         G_UNLOCK(libcaptive);
426
427         return errvfsresult;
428 }
429
430
431 static GnomeVFSResult captive_gnomevfs_write(GnomeVFSMethod *method,GnomeVFSMethodHandle *method_handle,
432                 gconstpointer buffer,GnomeVFSFileSize num_bytes,GnomeVFSFileSize *bytes_written_return,GnomeVFSContext *context)
433 {
434 GnomeVFSResult errvfsresult;
435 CaptiveFileObject *captive_file_object;
436
437         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
438         captive_file_object=(CaptiveFileObject *)method_handle;
439         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
440         g_return_val_if_fail(buffer!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
441         g_return_val_if_fail(bytes_written_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
442
443         G_LOCK(libcaptive);
444         errvfsresult=captive_file_write(captive_file_object,buffer,num_bytes,bytes_written_return);
445         G_UNLOCK(libcaptive);
446
447         return errvfsresult;
448 }
449
450
451 static GnomeVFSResult captive_gnomevfs_seek(GnomeVFSMethod *method,
452                 GnomeVFSMethodHandle *method_handle,GnomeVFSSeekPosition whence,GnomeVFSFileOffset offset,GnomeVFSContext *context)
453 {
454 GnomeVFSResult errvfsresult;
455 CaptiveFileObject *captive_file_object;
456
457         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
458         captive_file_object=(CaptiveFileObject *)method_handle;
459         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
460
461         G_LOCK(libcaptive);
462         errvfsresult=captive_file_seek(captive_file_object,whence,offset);
463         G_UNLOCK(libcaptive);
464
465         return errvfsresult;
466 }
467
468 static GnomeVFSResult captive_gnomevfs_tell(GnomeVFSMethod *method,
469                 GnomeVFSMethodHandle *method_handle,GnomeVFSFileOffset *offset_return)
470 {
471 GnomeVFSResult errvfsresult;
472 CaptiveFileObject *captive_file_object;
473
474         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
475         captive_file_object=(CaptiveFileObject *)method_handle;
476         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
477         g_return_val_if_fail(offset_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
478
479         G_LOCK(libcaptive);
480         errvfsresult=captive_file_tell(captive_file_object,offset_return);
481         G_UNLOCK(libcaptive);
482
483         return errvfsresult;
484 }
485
486
487 static gboolean captive_gnomevfs_is_local(GnomeVFSMethod *method,const GnomeVFSURI *uri)
488 {
489         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
490         g_return_val_if_fail(uri!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
491
492         return gnome_vfs_uri_is_local(uri->parent);
493 }
494
495
496 static GnomeVFSResult captive_gnomevfs_get_file_info(GnomeVFSMethod *method,
497                 GnomeVFSURI *uri,GnomeVFSFileInfo *file_info,GnomeVFSFileInfoOptions options,GnomeVFSContext *context)
498 {
499 GnomeVFSResult errvfsresult;
500 CaptiveVfsObject *captive_vfs_object;
501 CaptiveFileObject *captive_file_object;
502 CaptiveFileInfoObject *captive_file_info_object;
503
504         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
505         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
506         /* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
507
508         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
509         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
510
511         G_LOCK(libcaptive);
512         errvfsresult=captive_file_new_open(
513                         &captive_file_object,   /* captive_file_object_return */
514                         captive_vfs_object,     /* captive_vfs_object */
515                         uri->text,      /* pathname */
516                         0);     /* mode; 0 means FILE_READ_ATTRIBUTES */
517         G_UNLOCK(libcaptive);
518         if (errvfsresult!=GNOME_VFS_OK)
519                 return errvfsresult;
520
521         G_LOCK(libcaptive);
522         errvfsresult=captive_file_file_info_get(captive_file_object,&captive_file_info_object);
523         G_UNLOCK(libcaptive);
524         if (GNOME_VFS_OK!=errvfsresult)
525                 goto fail_g_object_unref_captive_file_object;
526
527         gnome_vfs_file_info_copy(file_info,&captive_file_info_object->p);
528         G_LOCK(libcaptive);
529         g_object_unref(captive_file_info_object);
530         G_UNLOCK(libcaptive);
531
532 fail_g_object_unref_captive_file_object:
533         G_LOCK(libcaptive);
534         g_object_unref(captive_file_object);
535         G_UNLOCK(libcaptive);
536
537         return errvfsresult;
538 }
539
540
541 GnomeVFSResult captive_gnomevfs_get_file_info_from_handle(GnomeVFSMethod *method,
542                 GnomeVFSMethodHandle *method_handle,GnomeVFSFileInfo *file_info,GnomeVFSFileInfoOptions options,GnomeVFSContext *context)
543 {
544 GnomeVFSResult errvfsresult;
545 CaptiveFileObject *captive_file_object;
546 CaptiveFileInfoObject *captive_file_info_object;
547
548         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
549         captive_file_object=(CaptiveFileObject *)method_handle;
550         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
551         g_return_val_if_fail(file_info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
552         /* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
553
554         G_LOCK(libcaptive);
555         errvfsresult=captive_file_file_info_get(captive_file_object,&captive_file_info_object);
556         G_UNLOCK(libcaptive);
557         if (GNOME_VFS_OK!=errvfsresult)
558                 return errvfsresult;
559
560         gnome_vfs_file_info_copy(file_info,&captive_file_info_object->p);
561         G_LOCK(libcaptive);
562         g_object_unref(captive_file_info_object);
563         G_UNLOCK(libcaptive);
564
565         return GNOME_VFS_OK;
566 }
567
568
569 GnomeVFSResult captive_gnomevfs_truncate_handle(GnomeVFSMethod *method,
570                 GnomeVFSMethodHandle *handle,GnomeVFSFileSize length,GnomeVFSContext *context)
571 {
572 GnomeVFSResult errvfsresult;
573 CaptiveFileObject *captive_file_object;
574
575         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
576         captive_file_object=(CaptiveFileObject *)handle;
577         g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),GNOME_VFS_ERROR_BAD_PARAMETERS);
578
579         G_LOCK(libcaptive);
580         errvfsresult=captive_file_truncate(captive_file_object,length);
581         G_UNLOCK(libcaptive);
582
583         return errvfsresult;
584 }
585
586 GnomeVFSResult captive_gnomevfs_truncate(GnomeVFSMethod *method,
587                 GnomeVFSURI *uri,GnomeVFSFileSize length,GnomeVFSContext *context)
588 {
589 GnomeVFSResult errvfsresult;
590 CaptiveVfsObject *captive_vfs_object;
591 CaptiveFileObject *captive_file_object;
592
593         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
594
595         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,uri);
596         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
597
598         G_LOCK(libcaptive);
599         errvfsresult=captive_file_new_open(
600                         &captive_file_object,   /* captive_file_object_return */
601                         captive_vfs_object,     /* captive_vfs_object */
602                         uri->text,      /* pathname */
603                         (GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM));  /* mode; is it OK? */
604         G_UNLOCK(libcaptive);
605         if (errvfsresult!=GNOME_VFS_OK)
606                 return errvfsresult;
607
608         G_LOCK(libcaptive);
609         errvfsresult=captive_file_truncate(captive_file_object,length);
610         G_UNLOCK(libcaptive);
611
612         G_LOCK(libcaptive);
613         g_object_unref(captive_file_object);
614         G_UNLOCK(libcaptive);
615
616         return errvfsresult;
617 }
618
619
620 GnomeVFSResult captive_gnomevfs_move(GnomeVFSMethod *method,
621                 GnomeVFSURI *old_uri,GnomeVFSURI *new_uri,gboolean force_replace,GnomeVFSContext *context)
622 {
623 GnomeVFSResult errvfsresult;
624 CaptiveVfsObject *captive_old_vfs_object;
625 CaptiveVfsObject *captive_new_vfs_object;
626 CaptiveFileObject *captive_old_file_object;
627
628         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
629
630         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_old_vfs_object,old_uri);
631         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
632
633         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_new_vfs_object,new_uri);
634         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
635
636         if (captive_old_vfs_object!=captive_new_vfs_object)
637                 return GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM;
638
639         G_LOCK(libcaptive);
640         errvfsresult=captive_file_new_open(
641                         &captive_old_file_object,       /* captive_file_object_return */
642                         captive_old_vfs_object, /* captive_vfs_object; ==captive_new_vfs_object */
643                         old_uri->text,  /* pathname */
644                         (GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_WRITE));  /* mode; is it OK? */
645         G_UNLOCK(libcaptive);
646         if (errvfsresult!=GNOME_VFS_OK)
647                 return errvfsresult;
648
649         G_LOCK(libcaptive);
650         errvfsresult=captive_file_move(captive_old_file_object,new_uri->text,force_replace);
651         G_UNLOCK(libcaptive);
652
653         G_LOCK(libcaptive);
654         g_object_unref(captive_old_file_object);
655         G_UNLOCK(libcaptive);
656
657         return errvfsresult;
658 }
659
660
661 GnomeVFSResult captive_gnomevfs_check_same_fs(GnomeVFSMethod *method,
662                 GnomeVFSURI *a,GnomeVFSURI *b,gboolean *same_fs_return,GnomeVFSContext *context)
663 {
664 CaptiveVfsObject *captive_vfs_object_a;
665 CaptiveVfsObject *captive_vfs_object_b;
666 GnomeVFSResult errvfsresult;
667
668         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
669         g_return_val_if_fail(same_fs_return!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
670
671         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object_a,a);
672         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
673
674         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object_b,b);
675         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
676
677         *same_fs_return=(captive_vfs_object_a==captive_vfs_object_b);
678
679         return GNOME_VFS_OK;
680 }
681
682
683 GnomeVFSResult captive_gnomevfs_set_file_info(GnomeVFSMethod *method,
684                 GnomeVFSURI *a,const GnomeVFSFileInfo *info,GnomeVFSSetFileInfoMask mask,GnomeVFSContext *context)
685 {
686 GnomeVFSResult errvfsresult;
687 CaptiveVfsObject *captive_vfs_object;
688 CaptiveFileObject *captive_file_object;
689 CaptiveFileInfoObject *captive_file_info_object;
690
691         g_return_val_if_fail(method==&GnomeVFSMethod_static,GNOME_VFS_ERROR_BAD_PARAMETERS);
692         g_return_val_if_fail(info!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
693
694         errvfsresult=captive_gnomevfs_uri_parent_init(&captive_vfs_object,a);
695         g_return_val_if_fail(errvfsresult==GNOME_VFS_OK,errvfsresult);
696
697         G_LOCK(libcaptive);
698         errvfsresult=captive_file_new_open(
699                         &captive_file_object,   /* captive_file_object_return */
700                         captive_vfs_object,     /* captive_vfs_object */
701                         a->text,        /* pathname */
702                         (GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_RANDOM));        /* mode; is it OK? */
703         G_UNLOCK(libcaptive);
704         if (errvfsresult!=GNOME_VFS_OK)
705                 return errvfsresult;
706
707         G_LOCK(libcaptive);
708         errvfsresult=captive_file_info_object_new(&captive_file_info_object);
709         G_UNLOCK(libcaptive);
710         if (errvfsresult!=GNOME_VFS_OK)
711                 goto fail_g_object_unref_captive_file_object;
712
713         captive_file_info_object->p=*info;
714         /* Unsupported by GnomeVFS, see: http://bugzilla.gnome.org/show_bug.cgi?id=325427 */
715         captive_file_info_object->atime_nsec=0;
716         captive_file_info_object->mtime_nsec=0;
717         captive_file_info_object->ctime_nsec=0;
718
719         G_LOCK(libcaptive);
720         errvfsresult=captive_file_file_info_set(captive_file_object,captive_file_info_object,mask);
721         G_UNLOCK(libcaptive);
722
723         G_LOCK(libcaptive);
724         g_object_unref(captive_file_info_object);
725         G_UNLOCK(libcaptive);
726
727 fail_g_object_unref_captive_file_object:
728         G_LOCK(libcaptive);
729         g_object_unref(captive_file_object);
730         G_UNLOCK(libcaptive);
731
732         return errvfsresult;
733 }
734
735
736 /**
737  * captive_gnomevfs_init:
738  *
739  * Returns: Initialized structure of #GnomeVFSMethod with static methods of libcaptive-gnomevfs.
740  */
741 GnomeVFSMethod *captive_gnomevfs_method_init(const gchar *method_name,const gchar *captive_args)
742 {
743 struct method_name_info *method_name_info;
744
745         g_return_val_if_fail(method_name!=NULL,NULL);
746         g_return_val_if_fail(captive_args!=NULL,NULL);
747
748         method_name_hash_init();
749
750         G_LOCK(method_name_hash);
751         method_name_info=g_hash_table_lookup(method_name_hash,method_name);
752         if (method_name_info && strcmp(method_name_info->captive_args,captive_args))
753                 method_name_info=NULL;
754         G_UNLOCK(method_name_hash);
755         if (!method_name_info) {
756                 captive_new(method_name_info);
757                 method_name_info->captive_args=g_strdup(captive_args);
758                 captive_options_init(&method_name_info->captive_options);
759                 if (!captive_options_parse(&method_name_info->captive_options,captive_args)) {
760                         g_assert_not_reached();
761                         g_free(method_name_info->captive_args);
762                         g_free(method_name_info);
763                         return NULL;
764                         }
765                 G_LOCK(method_name_hash);
766                 g_hash_table_replace(method_name_hash,g_strdup(method_name),method_name_info);
767                 G_UNLOCK(method_name_hash);
768                 }
769
770         G_LOCK(GnomeVFSMethod_static);
771         CAPTIVE_MEMZERO(&GnomeVFSMethod_static);
772         GnomeVFSMethod_static.method_table_size=sizeof(GnomeVFSMethod_static);
773         GnomeVFSMethod_static.open                     =captive_gnomevfs_open;  /* mandatory */
774         GnomeVFSMethod_static.create                   =captive_gnomevfs_create;        /* mandatory */
775         GnomeVFSMethod_static.close                    =captive_gnomevfs_close;
776         GnomeVFSMethod_static.read                     =captive_gnomevfs_read;
777         GnomeVFSMethod_static.write                    =captive_gnomevfs_write;
778         GnomeVFSMethod_static.seek                     =captive_gnomevfs_seek;
779         GnomeVFSMethod_static.tell                     =captive_gnomevfs_tell;
780         GnomeVFSMethod_static.truncate_handle          =captive_gnomevfs_truncate_handle;
781         GnomeVFSMethod_static.open_directory           =captive_gnomevfs_open_directory;
782         GnomeVFSMethod_static.close_directory          =captive_gnomevfs_close_directory;
783         GnomeVFSMethod_static.read_directory           =captive_gnomevfs_read_directory;
784         GnomeVFSMethod_static.get_file_info            =captive_gnomevfs_get_file_info; /* mandatory */
785         GnomeVFSMethod_static.get_file_info_from_handle=captive_gnomevfs_get_file_info_from_handle;
786         GnomeVFSMethod_static.is_local                 =captive_gnomevfs_is_local;      /* mandatory */
787         GnomeVFSMethod_static.make_directory           =captive_gnomevfs_make_directory;
788         GnomeVFSMethod_static.remove_directory         =captive_gnomevfs_remove_directory;
789         GnomeVFSMethod_static.move                     =captive_gnomevfs_move;
790         GnomeVFSMethod_static.unlink                   =captive_gnomevfs_unlink;
791         GnomeVFSMethod_static.check_same_fs            =captive_gnomevfs_check_same_fs;
792         GnomeVFSMethod_static.set_file_info            =captive_gnomevfs_set_file_info;
793         GnomeVFSMethod_static.truncate                 =captive_gnomevfs_truncate;
794         /* TODO: GnomeVFSMethodFindDirectoryFunc find_directory; */
795         /* TODO: GnomeVFSMethodCreateSymbolicLinkFunc create_symbolic_link; */
796         /* TODO: GnomeVFSMethodMonitorAddFunc monitor_add; */
797         /* TODO: GnomeVFSMethodMonitorCancelFunc monitor_cancel; */
798         /* TODO: GnomeVFSMethodFileControlFunc file_control; */
799         G_UNLOCK(GnomeVFSMethod_static);
800
801         return &GnomeVFSMethod_static;
802 }
803
804
805 /**
806  * captive_gnomevfs_method_shutdown:
807  *
808  * Shutdowns libcaptive-gnomevfs successfuly flushing all caches.
809  *
810  * This operation may not completely clean up the process space
811  * if libcaptive #sandbox is not in use.
812  *
813  * Sad note about gnome-vfs-2.1.5 is that it never calls this function. :-)
814  */ 
815 void captive_gnomevfs_method_shutdown(void)
816 {
817         uri_parent_string_hash_init();
818         G_LOCK(uri_parent_string_hash);
819         g_hash_table_destroy(uri_parent_string_hash);
820         uri_parent_string_hash=NULL;
821         G_UNLOCK(uri_parent_string_hash);
822
823         method_name_hash_init();
824         G_LOCK(method_name_hash);
825         g_hash_table_destroy(method_name_hash);
826         method_name_hash=NULL;
827         G_UNLOCK(method_name_hash);
828 }