2 * lufs interface module file objects implementation for libcaptive
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
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
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.
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
22 #include <glib/gmessages.h>
23 #include "captivefs-misc.h"
24 #include "captivefs-attr.h"
25 #include "captivefs-vfs.h"
28 #include <captive/client-vfs.h>
29 #include <captive/client-file.h>
30 #include <captive/client.h>
36 #define CLIENT_LUFS_USE_COUNT "client-lufs-use_count"
39 /* map: (const gchar *utf8) -> (CaptiveFileObject *) */
40 static GHashTable *FileHandle_hash;
41 G_LOCK_DEFINE_STATIC(FileHandle_hash);
43 static void FileHandle_hash_init(void)
45 G_LOCK(FileHandle_hash);
46 if (!FileHandle_hash) {
47 FileHandle_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
48 (GDestroyNotify)g_free, /* key_destroy_func */
49 (GDestroyNotify)NULL); /* value_destroy_func; handled by FileHandle_hash_captive_file_object_weak_notify() */
51 G_UNLOCK(FileHandle_hash);
54 /* Do not: GObject->ref_count
55 * as 'ref_count' may be increased for deleted files by ParentConnector
56 * until the volume gets unmounted. Therefore any deleted file would not
57 * be removed from our 'FileHandle_hash' and no object would be reinstantiable
58 * under the original deleted name.
60 static gint FileHandle_get_use_count(CaptiveFileObject *captive_file_object)
62 g_return_val_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object),0);
64 return GPOINTER_TO_INT(g_object_get_data(G_OBJECT(captive_file_object),CLIENT_LUFS_USE_COUNT));
67 static void FileHandle_set_use_count(CaptiveFileObject *captive_file_object,gint use_count)
69 g_return_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
71 g_object_set_data(G_OBJECT(captive_file_object),CLIENT_LUFS_USE_COUNT,GINT_TO_POINTER(use_count));
74 /* FileHandle_hash_init(); must be executed! */
75 /* G_LOCK(FileHandle_hash); must be held! */
76 static void FileHandle_enter
77 (struct captivefs_vfs *captivefs_vfs,CaptiveFileObject *captive_file_object,const gchar *name_normalized)
81 g_return_if_fail(captivefs_vfs_validate(captivefs_vfs));
82 g_return_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
83 g_return_if_fail(name_normalized);
85 use_count=FileHandle_get_use_count(captive_file_object);
86 if (captivefs_vfs->options.debug_messages)
87 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"FileHandle_enter: name_normalized=%s, use_count++=%d",
88 name_normalized,(int)use_count);
89 g_assert(use_count>=0);
91 FileHandle_set_use_count(captive_file_object,use_count);
93 g_assert(captive_file_object==g_hash_table_lookup(FileHandle_hash,name_normalized));
96 g_assert(NULL==g_hash_table_lookup(FileHandle_hash,name_normalized));
97 g_object_ref(captive_file_object);
98 g_hash_table_insert(FileHandle_hash,g_strdup(name_normalized),captive_file_object);
101 /* FileHandle_hash_init(); must be executed! */
102 /* G_LOCK(FileHandle_hash); must be held! */
103 /* G_LOCK(libcaptive); must NOT be held! */
104 static void FileHandle_leave_locked
105 (struct captivefs_vfs *captivefs_vfs,CaptiveFileObject *captive_file_object,const gchar *name)
109 gchar *name_normalized;
111 g_return_if_fail(captivefs_vfs_validate(captivefs_vfs));
112 g_return_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
113 g_return_if_fail(name);
115 name_normalized=captive_path_normalize(name);
116 use_count=FileHandle_get_use_count(captive_file_object);
117 if (captivefs_vfs->options.debug_messages)
118 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"FileHandle_leave_locked: name_normalized=%s, use_count--=%d",
119 name_normalized,(int)use_count);
120 g_assert(use_count>=1);
122 FileHandle_set_use_count(captive_file_object,use_count);
123 g_assert(captive_file_object==g_hash_table_lookup(FileHandle_hash,name_normalized));
125 g_free(name_normalized);
128 errbool=g_hash_table_remove(FileHandle_hash,name_normalized);
129 g_assert(errbool==TRUE);
131 g_object_unref(captive_file_object);
132 G_UNLOCK(libcaptive);
133 g_assert(NULL==g_hash_table_lookup(FileHandle_hash,name_normalized));
134 g_free(name_normalized);
137 /* FileHandle_hash_init(); must be executed! */
138 /* G_LOCK(FileHandle_hash); must NOT be held! */
139 /* G_LOCK(libcaptive); must NOT be held! */
140 static void FileHandle_leave(struct captivefs_vfs *captivefs_vfs,CaptiveFileObject *captive_file_object,const gchar *name)
142 g_return_if_fail(captivefs_vfs_validate(captivefs_vfs));
143 g_return_if_fail(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
144 g_return_if_fail(name);
146 G_LOCK(FileHandle_hash);
147 FileHandle_leave_locked(captivefs_vfs,captive_file_object,name);
148 G_UNLOCK(FileHandle_hash);
151 /* 'name' is required to exist. */
152 static CaptiveFileObject *FileHandle_lookup_enter(struct captivefs_vfs *captivefs_vfs,const char *name)
154 CaptiveFileObject *captive_file_object;
155 gchar *name_normalized;
157 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),NULL);
158 g_return_val_if_fail(name!=NULL,NULL);
160 name_normalized=captive_path_normalize(name);
161 FileHandle_hash_init();
162 G_LOCK(FileHandle_hash);
163 captive_file_object=g_hash_table_lookup(FileHandle_hash,name_normalized);
164 if (!captive_file_object) {
165 G_UNLOCK(FileHandle_hash);
166 g_warning("FileHandle_lookup_enter: FileHandle not found of: %s",name_normalized);
167 g_free(name_normalized);
170 g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
171 FileHandle_enter(captivefs_vfs,captive_file_object,name_normalized);
172 G_UNLOCK(FileHandle_hash);
173 g_free(name_normalized);
175 return captive_file_object;
178 /* 'name' will be opened if needed. */
179 static CaptiveFileObject *FileHandle_lookup_open_enter(struct captivefs_vfs *captivefs_vfs,const char *name,gboolean create)
181 CaptiveFileObject *captive_file_object;
182 GnomeVFSResult errvfsresult;
183 gchar *name_normalized;
185 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),NULL);
186 g_return_val_if_fail(name!=NULL,NULL);
188 name_normalized=captive_path_normalize(name);
189 FileHandle_hash_init();
190 G_LOCK(FileHandle_hash);
191 captive_file_object=g_hash_table_lookup(FileHandle_hash,name_normalized);
192 if (!create && captive_file_object) {
193 g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
194 FileHandle_enter(captivefs_vfs,captive_file_object,name_normalized);
195 G_UNLOCK(FileHandle_hash);
196 g_free(name_normalized);
197 return captive_file_object;
199 if ( create && captive_file_object) {
200 g_assert(CAPTIVE_FILE_IS_OBJECT(captive_file_object));
201 FileHandle_enter(captivefs_vfs,captive_file_object,name_normalized);
202 G_UNLOCK(FileHandle_hash);
203 g_free(name_normalized);
207 /* FIXME: Respect 'gnome_vfs_open_mode'.
208 * We would have to do some reopens of files already contained in 'FileHandle_hash'.
209 * As W32 filesystem will allow us to open file 'GNOME_VFS_OPEN_WRITE'
210 * even on read-only media we use the full open permissions always.
214 errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,name_normalized,
215 GNOME_VFS_OPEN_READ|GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM);
216 G_UNLOCK(libcaptive);
217 /* HIDDEN SYSTEM files (FIXME: or just HIDDEN or just SYSTEM?)
218 * refuse to be GNOME_VFS_OPEN_WRITE-opened.
220 if (errvfsresult==GNOME_VFS_ERROR_ACCESS_DENIED) {
222 errvfsresult=captive_file_new_open(&captive_file_object,captivefs_vfs->captive_vfs_object,name_normalized,
223 GNOME_VFS_OPEN_READ|GNOME_VFS_OPEN_RANDOM);
224 G_UNLOCK(libcaptive);
229 errvfsresult=captive_file_new_create(&captive_file_object,captivefs_vfs->captive_vfs_object,name_normalized,
230 GNOME_VFS_OPEN_READ|GNOME_VFS_OPEN_WRITE|GNOME_VFS_OPEN_RANDOM, /* mode */
231 FALSE, /* exclusive */
233 G_UNLOCK(libcaptive);
235 if (errvfsresult!=GNOME_VFS_OK) {
236 G_UNLOCK(FileHandle_hash);
237 g_free(name_normalized);
240 FileHandle_enter(captivefs_vfs,captive_file_object,name_normalized);
241 G_UNLOCK(FileHandle_hash);
242 g_object_unref(captive_file_object); /* for captive_file_new_open() / captive_file_new_create() */
243 g_free(name_normalized);
245 return captive_file_object;
248 /* Read a file/dir's attributes
249 * Fill all relevant data into the fattr structure.
250 * The uid/gid fields are just ownership hints hints:
251 * != 0 => we own the file
252 * == 0 => we don't own it
253 * The credentials structure (if applicable and saved from _init)
254 * can help determine ownership based on remote uids/gids.
257 * If your filesysem doesn't natively support '.' or '..',
258 * don't forget to special-case them here.
259 * It is best to assume that name is a relative path, not an
260 * absolute one. Thus, you need to either be keeping track of the
261 * last accessed directory in readdir, or, as this code does, changing
262 * to the current directory there.
264 int captivefs_stat(struct captivefs_vfs *captivefs_vfs,const char *name,struct lufs_fattr *fattr)
266 GnomeVFSResult errvfsresult;
267 CaptiveFileObject *captive_file_object;
268 GnomeVFSFileInfo file_info;
270 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
271 g_return_val_if_fail(name!=NULL,-1);
272 g_return_val_if_fail(fattr!=NULL,-1);
274 if (captivefs_vfs->options.debug_messages)
275 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_stat: name=%s",name);
277 name=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(name);
279 captive_file_object=FileHandle_lookup_open_enter(captivefs_vfs,name,FALSE);
280 if (!captive_file_object)
284 errvfsresult=captive_file_file_info_get(captive_file_object,&file_info);
285 G_UNLOCK(libcaptive);
287 FileHandle_leave(captivefs_vfs,captive_file_object,name);
289 if (errvfsresult!=GNOME_VFS_OK)
292 if (!captivefs_GnomeVFSFileInfo_to_lufs_fattr(captivefs_vfs,fattr,&file_info))
301 int captivefs_create(struct captivefs_vfs *captivefs_vfs,const char *file,int mode)
303 CaptiveFileObject *captive_file_object;
305 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
306 g_return_val_if_fail(file!=NULL,-1);
308 if (captivefs_vfs->options.debug_messages)
309 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_create: file=%s,mode=0x%X",file,mode);
311 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
313 captive_file_object=FileHandle_lookup_open_enter(captivefs_vfs,file,TRUE);
314 if (!captive_file_object)
317 FileHandle_leave(captivefs_vfs,captive_file_object,file);
325 int captivefs_unlink(struct captivefs_vfs *captivefs_vfs,const char *file)
327 GnomeVFSResult errvfsresult;
328 CaptiveFileObject *captive_file_object;
330 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
331 g_return_val_if_fail(file!=NULL,-1);
333 if (captivefs_vfs->options.debug_messages)
334 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_unlink: file=%s",file);
336 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
338 captive_file_object=FileHandle_lookup_open_enter(captivefs_vfs,file,FALSE);
339 if (!captive_file_object)
343 errvfsresult=captive_file_remove(captive_file_object);
344 G_UNLOCK(libcaptive);
346 FileHandle_leave(captivefs_vfs,captive_file_object,file);
348 if (errvfsresult!=GNOME_VFS_OK)
357 int captivefs_rename(struct captivefs_vfs *captivefs_vfs,const char *old_name,const char *new_name)
359 GnomeVFSResult errvfsresult;
360 CaptiveFileObject *captive_file_object;
363 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
364 g_return_val_if_fail(old_name!=NULL,-1);
365 g_return_val_if_fail(new_name!=NULL,-1);
367 if (captivefs_vfs->options.debug_messages)
368 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_rename: old_name=%s,new_name=%s",old_name,new_name);
370 old_name=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(old_name);
371 new_name=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(new_name);
373 captive_file_object=FileHandle_lookup_open_enter(captivefs_vfs,old_name,FALSE);
374 if (!captive_file_object)
377 G_LOCK(FileHandle_hash);
378 use_count=FileHandle_get_use_count(captive_file_object);
379 g_assert(use_count>=1);
381 if (captivefs_vfs->options.debug_messages)
382 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_rename: old_name=%s,new_name=%s: BUSY use_count=%d",
383 old_name,new_name,(int)use_count);
384 G_UNLOCK(FileHandle_hash);
385 FileHandle_leave(captivefs_vfs,captive_file_object,old_name);
390 errvfsresult=captive_file_move(captive_file_object,new_name,
391 FALSE); /* force_replace */
392 G_UNLOCK(libcaptive);
394 FileHandle_leave_locked(captivefs_vfs,captive_file_object,old_name);
395 G_UNLOCK(FileHandle_hash);
397 if (errvfsresult!=GNOME_VFS_OK)
407 * By default, LUFS has no concept of file handles. To implement file
408 * handles, take a look at the atbl class in sshfs - it is easy to cut&paste
409 * for use, and can be easily adapted for whatever purpose you need handles
412 * Unlike the POSIX open command which has both a "mode" variable and
413 * a "flags" variable, this only has a "mode" variable. To convert to the
414 * POSIX version, ->flags=mode^O_ACCMODE and ->mode=mode&O_ACCMODE.
416 int captivefs_open(struct captivefs_vfs *captivefs_vfs,const char *file,unsigned mode)
418 CaptiveFileObject *captive_file_object;
419 GnomeVFSOpenMode gnome_vfs_open_mode;
421 /* We may be called from the parent. */
422 g_return_val_if_fail(captivefs_vfs!=NULL,FALSE);
423 g_return_val_if_fail(file!=NULL,-1);
425 if (captivefs_vfs->options.debug_messages)
426 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_open: file=%s,mode=0x%X",file,mode);
428 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
430 if (!captivefs_vfs_validate(captivefs_vfs))
433 if (mode & ~(O_RDONLY|O_WRONLY|O_RDWR)) {
434 g_warning("captivefs_open: Unrecognized 'mode' 0x%X",mode);
437 switch (mode & (O_RDONLY|O_WRONLY|O_RDWR)) {
438 case O_RDONLY: gnome_vfs_open_mode=GNOME_VFS_OPEN_READ; break;
439 case O_WRONLY: gnome_vfs_open_mode=GNOME_VFS_OPEN_WRITE; break;
440 case O_RDWR: gnome_vfs_open_mode=GNOME_VFS_OPEN_READ|GNOME_VFS_OPEN_WRITE; break;
442 g_warning("captivefs_open: Unrecognized 'mode' 0x%X",mode);
446 captive_file_object=FileHandle_lookup_open_enter(captivefs_vfs,file,FALSE);
447 if (!captive_file_object)
450 /* Leave 'captive_file_object' entered. */
455 int captivefs_release(struct captivefs_vfs *captivefs_vfs,const char *file)
457 CaptiveFileObject *captive_file_object;
459 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
460 g_return_val_if_fail(file!=NULL,-1);
462 if (captivefs_vfs->options.debug_messages)
463 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_release: file=%s",file);
465 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
467 if (!(captive_file_object=FileHandle_lookup_enter(captivefs_vfs,file)))
470 FileHandle_leave(captivefs_vfs,captive_file_object,file); /* for FileHandle_lookup_enter() */
471 FileHandle_leave(captivefs_vfs,captive_file_object,file);
477 /* Read from a file. Changed to use the (2) routines not for efficiency,
478 * but to make it work with 64-bit offsets :-(.
480 int captivefs_read(struct captivefs_vfs *captivefs_vfs,const char *file,long long offset,unsigned long count,void *buf)
482 CaptiveFileObject *captive_file_object;
483 GnomeVFSFileSize bytes_read;
484 GnomeVFSResult errvfsresult;
486 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
487 g_return_val_if_fail(file!=NULL,-1);
488 g_return_val_if_fail(buf!=NULL || count==0,-1);
490 if (captivefs_vfs->options.debug_messages)
491 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_read: file=%s,offset=%" G_GINT64_FORMAT ",count=0x%lX",
492 file,(gint64)offset,count);
494 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
496 if (!(captive_file_object=FileHandle_lookup_enter(captivefs_vfs,file)))
499 /* Do not unlock 'libcaptive' between seek() and read()! */
501 errvfsresult=captive_file_seek(captive_file_object,GNOME_VFS_SEEK_START,offset);
502 if (errvfsresult!=GNOME_VFS_OK) {
503 G_UNLOCK(libcaptive);
504 FileHandle_leave(captivefs_vfs,captive_file_object,file);
508 errvfsresult=captive_file_read(captive_file_object,buf,count,&bytes_read);
509 G_UNLOCK(libcaptive);
510 FileHandle_leave(captivefs_vfs,captive_file_object,file);
511 if (errvfsresult!=GNOME_VFS_OK)
514 if (bytes_read>INT_MAX) {
515 g_warning("captivefs_read: Read %" G_GUINT64_FORMAT " bytes > INT_MAX=%d; dropped data",
516 (guint64)bytes_read,INT_MAX);
526 int captivefs_write(struct captivefs_vfs *captivefs_vfs,const char *file,long long offset,unsigned long count,const void *buf)
528 CaptiveFileObject *captive_file_object;
529 GnomeVFSFileSize bytes_written;
530 GnomeVFSResult errvfsresult;
532 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
533 g_return_val_if_fail(file!=NULL,-1);
534 g_return_val_if_fail(buf!=NULL || count==0,-1);
536 if (captivefs_vfs->options.debug_messages)
537 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_write: file=%s,offset=%" G_GINT64_FORMAT ",count=0x%lX",
538 file,(gint64)offset,count);
540 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
542 if (!(captive_file_object=FileHandle_lookup_enter(captivefs_vfs,file)))
545 /* Do not unlock 'libcaptive' between seek() and write()! */
547 errvfsresult=captive_file_seek(captive_file_object,GNOME_VFS_SEEK_START,offset);
548 if (errvfsresult!=GNOME_VFS_OK) {
549 G_UNLOCK(libcaptive);
550 FileHandle_leave(captivefs_vfs,captive_file_object,file);
554 errvfsresult=captive_file_write(captive_file_object,buf,count,&bytes_written);
555 G_UNLOCK(libcaptive);
556 FileHandle_leave(captivefs_vfs,captive_file_object,file);
557 if (errvfsresult!=GNOME_VFS_OK)
560 if (bytes_written>INT_MAX) {
561 g_warning("captivefs_written: Written %" G_GUINT64_FORMAT " bytes > INT_MAX=%d; dropped data",
562 (guint64)bytes_written,INT_MAX);
563 bytes_written=INT_MAX;
566 return bytes_written;
570 /* Change a file/dir's attributes
572 int captivefs_setattr(struct captivefs_vfs *captivefs_vfs,const char *file,const struct lufs_fattr *fattr)
574 GnomeVFSFileInfo file_info;
575 GnomeVFSResult errvfsresult;
576 CaptiveFileObject *captive_file_object;
578 g_return_val_if_fail(captivefs_vfs_validate(captivefs_vfs),-1);
579 g_return_val_if_fail(file!=NULL,-1);
580 g_return_val_if_fail(fattr!=NULL,-1);
582 if (captivefs_vfs->options.debug_messages)
583 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"captivefs_setattr: file=%s",file);
585 file=CAPTIVEFS_FILENAME_TO_UTF8_ALLOCA(file);
587 if (!captivefs_lufs_fattr_to_GnomeVFSFileInfo(&file_info,fattr))
590 captive_file_object=FileHandle_lookup_open_enter(captivefs_vfs,file,FALSE);
591 if (!captive_file_object)
595 errvfsresult=captive_file_file_info_set(captive_file_object,&file_info,
597 | 0 /* 'GNOME_VFS_SET_FILE_INFO_NAME' is never set */
598 | (!(file_info.valid_fields&GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS) ? 0 : GNOME_VFS_SET_FILE_INFO_PERMISSIONS)
599 | 0 /* 'GNOME_VFS_SET_FILE_INFO_OWNER' is never set */
600 | (!(file_info.valid_fields&(0
601 | GNOME_VFS_FILE_INFO_FIELDS_ATIME
602 | GNOME_VFS_FILE_INFO_FIELDS_MTIME
603 | GNOME_VFS_FILE_INFO_FIELDS_CTIME))
604 ? 0 : GNOME_VFS_SET_FILE_INFO_TIME));
605 G_UNLOCK(libcaptive);
607 if (errvfsresult==GNOME_VFS_OK)
608 errvfsresult=captive_file_truncate(captive_file_object,fattr->f_size);
609 G_UNLOCK(libcaptive);
610 FileHandle_leave(captivefs_vfs,captive_file_object,file);
611 if (errvfsresult!=GNOME_VFS_OK)