ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / modules / extfs-method.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* extfs-method.c - Integrated support for various archiving methods via
3    helper scripts.
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@comm2000.it>
23    Based on the ideas from the extfs system implemented in the GNU Midnight
24    Commander.  */
25
26 /* TODO: Support archives on non-local file systems.  Although I am not
27    that sure it's such a terrific idea anymore.  */
28
29 #include <config.h>
30
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <glib/ghash.h>
34 #include <glib/gmessages.h>
35 #include <glib/gstrfuncs.h>
36 #include <glib/gthread.h>
37 #include <glib/gutils.h>
38 #include <libgnomevfs/gnome-vfs-cancellable-ops.h>
39 #include <libgnomevfs/gnome-vfs-mime.h>
40 #include <libgnomevfs/gnome-vfs-module-shared.h>
41 #include <libgnomevfs/gnome-vfs-module.h>
42 #include <libgnomevfs/gnome-vfs-ops.h>
43 #include <libgnomevfs/gnome-vfs-parse-ls.h>
44 #include <libgnomevfs/gnome-vfs-private-utils.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51
52 #ifndef HAVE_GETDELIM
53
54
55 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
56    (and null-terminate it). *LINEPTR is a pointer returned from malloc (or
57    NULL), pointing to *N characters of space.  It is realloc'd as
58    necessary.  Returns the number of characters read (not including the
59    null terminator), or -1 on error or EOF.  */
60
61
62
63 static ssize_t
64 getdelim (lineptr, n, terminator, stream)
65         char **lineptr;
66         size_t *n;
67         int terminator;
68         FILE *stream;
69 {
70         char *line, *p;
71         size_t size, copy;
72
73         if (lineptr == NULL || n == NULL)
74         {
75                 return -1;
76         }
77
78         if (ferror (stream))
79                 return -1;
80
81         /* Make sure we have a line buffer to start with.  */
82         if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars.  */
83         {
84 #ifndef MAX_CANON
85 #define MAX_CANON       256
86 #endif
87                 line = realloc (*lineptr, MAX_CANON);
88                 if (line == NULL)
89                         return -1;
90                 *lineptr = line;
91                 *n = MAX_CANON;
92         }
93
94         line = *lineptr;
95         size = *n;
96
97         copy = size;
98         p = line;
99
100         while (1)
101         {
102                 size_t len;
103                 while (--copy > 0)
104                 {
105                         register int c = getc (stream);
106                         if (c == EOF)
107                                 goto lose;
108                         else if ((*p++ = c) == terminator)
109                                 goto win;
110                 }
111
112                 /* Need to enlarge the line buffer.  */
113                 len = p - line;
114                 size *= 2;
115                 line = realloc (line, size);
116                 if (line == NULL)
117                         goto lose;
118                 *lineptr = line;
119                 *n = size;
120                 p = line + len;
121                 copy = size - len;
122         }
123
124         lose:
125                 if (p == *lineptr)
126                 return -1;
127         /* Return a partial line since we got an error in the middle.  */
128         win:
129                 *p = '\0';
130                 return p - *lineptr;
131         }
132
133
134 #endif
135
136 #define EXTFS_COMMAND_DIR       LIBDIR "/vfs/2.0/extfs"
137
138 /* Our private handle struct.  */
139 struct _ExtfsHandle {
140         GnomeVFSOpenMode open_mode;
141         GnomeVFSHandle *vfs_handle;
142         gchar *local_path;
143 };
144 typedef struct _ExtfsHandle ExtfsHandle;
145
146 #define VFS_HANDLE(method_handle) \
147         ((ExtfsHandle *) method_handle)->vfs_handle
148
149 /* List of current handles, for cleaning up in `vfs_module_shutdown_2()'.  */
150 static GList *handle_list;
151 G_LOCK_DEFINE_STATIC (handle_list);
152
153 \f
154 struct _ExtfsDirectoryEntry {
155         gchar *directory;
156         GnomeVFSFileInfo *info;
157 };
158 typedef struct _ExtfsDirectoryEntry ExtfsDirectoryEntry;
159
160 struct _ExtfsDirectory {
161         guint ref_count;
162         GnomeVFSURI *uri;
163         GList *entries;
164 };
165 typedef struct _ExtfsDirectory ExtfsDirectory;
166
167 /* Hash of directory lists.  */
168 /* Notice that, for the way the code currently works, this is useless.  But I
169    plan to add some caching (i.e. keep directory lists for a while to make
170    visiting easier) in the future, so this will help.  The main reason for not
171    doing so now right is that we need some support for expiration in the GNOME
172    VFS library core.  */
173 static GHashTable *uri_to_directory_hash;
174 G_LOCK_DEFINE_STATIC (uri_to_directory_hash);
175
176 \f
177 #define ERROR_IF_NOT_LOCAL(uri)                                 \
178         if ((!uri) || (!uri->parent) || (!(uri)->parent->method_string) || strcmp ((uri)->parent->method_string, "file") != 0)  \
179                 return GNOME_VFS_ERROR_NOT_SUPPORTED;
180
181 static GnomeVFSResult
182 extfs_handle_close (ExtfsHandle *handle)
183 {
184         GnomeVFSResult close_result;
185
186         close_result = gnome_vfs_close (handle->vfs_handle);
187
188         /* Maybe we could use the VFS functions here.  */
189         if (unlink (handle->local_path) != 0)
190                 g_warning ("Cannot unlink temporary file `%s': %s",
191                            handle->local_path, g_strerror (errno));
192
193         g_free (handle->local_path);
194         g_free (handle);
195
196         return close_result;
197 }
198
199 static gchar *
200 quote_file_name (const gchar *file_name)
201 {
202         guint len;
203         const gchar *p;
204         gchar *q;
205         gchar *new;
206
207         len = 2;
208         for (p = file_name; *p != 0; p++) {
209                 if (*p == '\'')
210                         len += 3;
211                 else
212                         len++;
213         }
214
215         new = g_malloc (len + 1);
216         new[0] = '\'';
217
218         for (p = file_name, q = new + 1; *p != 0; p++) {
219                 if (*p == '\'') {
220                         q[0] = '"';
221                         q[1] = '\'';
222                         q[2] = '"';
223                         q += 3;
224                 } else {
225                         *q = *p;
226                         q++;
227                 }
228         }
229
230         *q++ = '\'';
231         *q = 0;
232
233         return new;
234 }
235
236 static gchar *
237 get_script_path (const GnomeVFSURI *uri)
238 {
239         return g_strconcat (EXTFS_COMMAND_DIR, "/", uri->method_string, NULL);
240 }
241
242 static gchar *
243 strip_separators (const gchar *pth)
244 {
245         gchar *path_buf = g_strdup(pth);
246         gchar *path = path_buf, *p, *s;
247
248         while (*path == G_DIR_SEPARATOR) path++;
249         
250         p = path+strlen(path)-1;
251         while (p > path && *p == G_DIR_SEPARATOR) *(p--) = '\0';
252         s = g_strdup(path);
253
254         g_free(path_buf);
255
256         return s;
257 }
258
259 static gchar *
260 get_basename (const gchar *pth)
261 {
262         gchar *path = strip_separators(pth);
263         gchar *s;
264
265         s = g_path_get_basename (path);
266
267         g_free(path);
268
269         return s;
270 }
271
272 static gchar *
273 get_dirname (const gchar *pth)
274 {
275         gchar *p;
276         //gchar *s;
277         //guint len;
278         gchar *path = strip_separators(pth);
279
280         p = strrchr (path, G_DIR_SEPARATOR);
281         if (p == NULL)
282                 return g_strdup("");
283
284         *p = '\0';
285
286         return path;
287 }
288
289 \f
290 /* URI -> directory hash table handling.  */
291
292 static void
293 free_directory_entries (GList *entries)
294 {
295         GList *p;
296
297         for (p = entries; p != NULL; p = p->next) {
298                 ExtfsDirectoryEntry *entry;
299
300                 entry = p->data;
301                 gnome_vfs_file_info_unref (entry->info);
302                 g_free (entry->directory);
303                 g_free (entry);
304         }
305
306         g_list_free (entries);
307 }
308
309 static ExtfsDirectory *
310 extfs_directory_new (const GnomeVFSURI *uri,
311                      GList *entries)
312 {
313         ExtfsDirectory *new;
314         ExtfsDirectory *existing;
315
316         G_LOCK (uri_to_directory_hash);
317
318         /* First check that a new directory has not been registered for this
319            URI yet.  */
320         existing = g_hash_table_lookup (uri_to_directory_hash, uri);
321         if (existing != NULL) {
322                 free_directory_entries (entries);
323                 G_UNLOCK (uri_to_directory_hash);
324                 return existing;
325         }
326
327         new = g_new (ExtfsDirectory, 1);
328
329         new->uri = gnome_vfs_uri_dup (uri);
330         new->entries = entries;
331         new->ref_count = 1;
332
333         g_hash_table_insert (uri_to_directory_hash, new->uri, new);
334
335         G_UNLOCK (uri_to_directory_hash);
336
337         return new;
338 }
339
340 #if 0
341 static void
342 extfs_directory_unref (ExtfsDirectory *dir)
343 {
344         g_return_if_fail (dir->ref_count > 0);
345
346         G_LOCK (uri_to_directory_hash);
347
348         dir->ref_count--;
349         if (dir->ref_count == 0) {
350                 g_hash_table_remove (uri_to_directory_hash, dir->uri);
351
352                 free_directory_entries (dir->entries);
353                 gnome_vfs_uri_unref (dir->uri);
354                 g_free (dir);
355         }
356
357         G_UNLOCK (uri_to_directory_hash);
358 }
359 #endif
360
361 static ExtfsDirectory *
362 extfs_directory_lookup (GnomeVFSURI *uri)
363 {
364         ExtfsDirectory *directory;
365
366         G_LOCK (uri_to_directory_hash);
367         directory = g_hash_table_lookup (uri_to_directory_hash, uri);
368         if (directory != NULL)
369                 directory->ref_count++;
370         G_UNLOCK (uri_to_directory_hash);
371
372         return directory;
373 }
374
375 \f
376 static GnomeVFSResult
377 do_open (GnomeVFSMethod *method,
378          GnomeVFSMethodHandle **method_handle,
379          GnomeVFSURI *uri,
380          GnomeVFSOpenMode mode,
381          GnomeVFSContext *context)
382 {
383         GnomeVFSResult result;
384         GnomeVFSProcessResult process_result;
385         GnomeVFSHandle *temp_handle;
386         ExtfsHandle *handle;
387         gchar *script_path;
388         const gchar *stored_name;
389         const gchar *args[6];
390         gchar *temp_name;
391         gboolean cleanup;
392         gint process_exit_value;
393
394         ERROR_IF_NOT_LOCAL (uri);
395
396         /* TODO: Support write mode.  */
397         if (mode & GNOME_VFS_OPEN_WRITE)
398                 return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
399
400         if (uri->text == NULL)
401                 return GNOME_VFS_ERROR_INVALID_URI;
402
403         if (uri->method_string == NULL)
404                 return GNOME_VFS_ERROR_INTERNAL;
405
406         stored_name = uri->text;
407         while (*stored_name == G_DIR_SEPARATOR)
408                 stored_name++;
409
410         if (*stored_name == '\0')
411                 return GNOME_VFS_ERROR_INVALID_URI;
412
413         result = gnome_vfs_create_temp ("/tmp/extfs", &temp_name, &temp_handle);
414         if (result != GNOME_VFS_OK)
415                 return result;
416
417         handle = g_new (ExtfsHandle, 1);
418         handle->vfs_handle = temp_handle;
419         handle->open_mode = mode;
420         handle->local_path = temp_name;
421
422         script_path = get_script_path (uri);
423
424         args[0] = uri->method_string;
425         args[1] = "copyout";
426         args[2] = uri->parent->text;
427         args[3] = (gchar *) stored_name;
428         args[4] = temp_name;
429         args[5] = NULL;
430         
431         /* FIXME bugzilla.eazel.com 1223:
432          * args 
433          * Ettore needs to elaborate here some more, it is not clear what this
434          * FixMe is about
435          */
436         process_result = gnome_vfs_process_run_cancellable
437                 (script_path, args, GNOME_VFS_PROCESS_CLOSEFDS,
438                  context ? gnome_vfs_context_get_cancellation(context) : NULL,
439                  &process_exit_value);
440
441         switch (process_result) {
442         case GNOME_VFS_PROCESS_RUN_OK:
443                 if (process_exit_value == 0) {
444                         result = GNOME_VFS_OK;
445                         cleanup = FALSE;
446                 } else {
447                         /* This is not very accurate, but it should be
448                            enough.  */
449                         result = GNOME_VFS_ERROR_NOT_FOUND;
450                         cleanup = TRUE;
451                 }
452                 break;
453         case GNOME_VFS_PROCESS_RUN_CANCELLED:
454                 result = GNOME_VFS_ERROR_CANCELLED;
455                 cleanup = TRUE;
456                 break;
457         case GNOME_VFS_PROCESS_RUN_SIGNALED:
458                 result = GNOME_VFS_ERROR_INTERRUPTED;
459                 cleanup = TRUE;
460                 break;
461         case GNOME_VFS_PROCESS_RUN_STOPPED:
462                 result = GNOME_VFS_ERROR_INTERRUPTED;
463                 cleanup = TRUE;
464                 break;
465         case GNOME_VFS_PROCESS_RUN_ERROR:
466         default:
467                 /* If we get `GNOME_VFS_PROCESS_RUN_ERROR', it means that we
468                    could not run the executable for some weird reason.*/
469                 result = GNOME_VFS_ERROR_INTERNAL;
470                 cleanup = TRUE;
471                 break;
472         }
473
474         if (cleanup) {
475                 extfs_handle_close (handle);
476         } else {
477                 *method_handle = (GnomeVFSMethodHandle *) handle;
478                 G_LOCK (handle_list);
479                 handle_list = g_list_prepend (handle_list, handle);
480                 G_UNLOCK (handle_list);
481         }
482
483         g_free (script_path);
484         return result;
485 }
486
487 static GnomeVFSResult
488 do_create (GnomeVFSMethod *method,
489            GnomeVFSMethodHandle **method_handle,
490            GnomeVFSURI *uri,
491            GnomeVFSOpenMode mode,
492            gboolean exclusive,
493            guint perm,
494            GnomeVFSContext *context)
495 {
496         return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
497 }
498
499 static GnomeVFSResult
500 do_close (GnomeVFSMethod *method,
501           GnomeVFSMethodHandle *method_handle,
502           GnomeVFSContext *context)
503 {
504         ExtfsHandle *extfs_handle;
505         GnomeVFSResult result;
506
507         extfs_handle = (ExtfsHandle *) method_handle;
508         result = extfs_handle_close (extfs_handle);
509
510         if (result == GNOME_VFS_OK) {
511                 G_LOCK (handle_list);
512                 handle_list = g_list_remove (handle_list, extfs_handle);
513                 G_UNLOCK (handle_list);
514         }
515
516         return result;
517 }
518
519 static GnomeVFSResult
520 do_read (GnomeVFSMethod *method,
521          GnomeVFSMethodHandle *method_handle,
522          gpointer buffer,
523          GnomeVFSFileSize num_bytes,
524          GnomeVFSFileSize *bytes_read,
525          GnomeVFSContext *context)
526 {
527         return gnome_vfs_read_cancellable (VFS_HANDLE (method_handle),
528                                            buffer, num_bytes, bytes_read,
529                                            context);
530 }
531
532 static GnomeVFSResult
533 do_write (GnomeVFSMethod *method,
534           GnomeVFSMethodHandle *method_handle,
535           gconstpointer buffer,
536           GnomeVFSFileSize num_bytes,
537           GnomeVFSFileSize *bytes_written,
538           GnomeVFSContext *context)
539 {
540         return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
541 }
542
543 static GnomeVFSResult
544 do_seek (GnomeVFSMethod *method,
545          GnomeVFSMethodHandle *method_handle,
546          GnomeVFSSeekPosition whence,
547          GnomeVFSFileOffset offset,
548          GnomeVFSContext *context)
549 {
550         return gnome_vfs_seek_cancellable (VFS_HANDLE (method_handle),
551                                            whence, offset,
552                                            context);
553 }
554
555 static GnomeVFSResult
556 do_tell (GnomeVFSMethod *method,
557          GnomeVFSMethodHandle *method_handle,
558          GnomeVFSFileOffset *offset_return)
559 {
560         return gnome_vfs_tell (VFS_HANDLE (method_handle), offset_return);
561 }
562
563 static GnomeVFSResult
564 do_truncate_handle (GnomeVFSMethod *method,
565                     GnomeVFSMethodHandle *method_handle,
566                     GnomeVFSFileSize where,
567                     GnomeVFSContext *context)
568 {
569         return GNOME_VFS_ERROR_NOT_SUPPORTED;
570 }
571
572 static GnomeVFSResult
573 do_truncate (GnomeVFSMethod *method,
574              GnomeVFSURI *uri,
575              GnomeVFSFileSize where,
576              GnomeVFSContext *context)
577 {
578         return GNOME_VFS_ERROR_NOT_SUPPORTED;
579 }
580
581 \f
582 /* Directory reading.  */
583 static GnomeVFSResult
584 read_directory_list (FILE *p,
585                      GList **list_return,
586                      GnomeVFSFileInfoOptions info_options,
587                      GnomeVFSContext *context)
588 {
589         GnomeVFSResult result;
590         GList *list;
591         gchar *line_buffer;
592         size_t line_buffer_size = 0;
593
594         list = NULL;
595         line_buffer = NULL;
596         line_buffer_size = 0;
597         result = GNOME_VFS_OK;
598
599         while (1) {
600                 GnomeVFSFileInfo *info;
601                 ExtfsDirectoryEntry *entry;
602                 ssize_t chars_read;
603                 struct stat statbuf;
604                 gchar *name;
605                 gchar *symlink_name;
606
607                 if (gnome_vfs_context_check_cancellation(context)) {
608                         result = GNOME_VFS_ERROR_CANCELLED;
609                         break;
610                 }
611
612                 chars_read = getdelim (&line_buffer, &line_buffer_size, '\n', p);
613                 if (chars_read == -1)
614                         break;
615
616                 /* FIXME bugzilla.eazel.com 1223: */
617                 fputs (line_buffer, stdout);
618
619                 line_buffer[chars_read] = '\0';
620
621                 if (! gnome_vfs_parse_ls_lga (line_buffer, &statbuf,
622                                               &name, &symlink_name)) {
623                         continue;
624                 }
625
626                 info = gnome_vfs_file_info_new ();
627
628                 info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_NONE;
629                 gnome_vfs_stat_to_file_info (info, &statbuf);
630
631                 GNOME_VFS_FILE_INFO_SET_LOCAL (info, FALSE);
632                 info->name = g_strdup (get_basename (name));
633                 info->symlink_name = symlink_name;
634
635                 /* Notice that we always do stupid, fast MIME type checking.
636                    Real checking based on contents would be too expensive.  */
637                 if (info_options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE) {
638                         info->mime_type = g_strdup (gnome_vfs_get_file_mime_type(
639                                                     info->name, &statbuf, FALSE));
640                         info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
641                 }
642
643                 entry = g_new (ExtfsDirectoryEntry, 1);
644                 entry->info = info;
645                 entry->directory = get_dirname (name);
646
647                 g_free (name);
648
649                 /* Order does not really matter here.  */
650                 list = g_list_prepend (list, entry);
651         }
652
653         *list_return = list;
654         return result;
655 }
656
657 static GnomeVFSResult
658 do_open_directory (GnomeVFSMethod *method,
659                    GnomeVFSMethodHandle **method_handle,
660                    GnomeVFSURI *uri,
661                    GnomeVFSFileInfoOptions info_options,
662                    GnomeVFSContext *context)
663 {
664         GList **handle;
665         ExtfsDirectoryEntry *entry;
666         ExtfsDirectory *directory;
667         struct stat statbuf;
668         gchar *script_path;
669         gchar *quoted_file_name;
670         gchar *cmd;
671         gchar *sub_uri;
672         //const gchar *p;
673         //const GList *item;
674         GList *entries=NULL;
675         GList *l;
676         FILE *pipe;
677
678         ERROR_IF_NOT_LOCAL (uri);
679
680         directory = extfs_directory_lookup (uri->parent);
681         if (directory == NULL) {
682                 GList *list;
683                 GnomeVFSResult result;
684
685                 /* Check that the file exists first.  */
686                 if (stat (uri->parent->text, &statbuf) != 0)
687                         return GNOME_VFS_ERROR_NOT_FOUND;
688
689                 quoted_file_name = quote_file_name (uri->parent->text);
690                 script_path = get_script_path (uri);
691                 cmd = g_strconcat (script_path, " list ", quoted_file_name, 
692                                    NULL);
693
694                 pipe = popen (cmd, "r");
695
696                 g_free (cmd);
697                 g_free (script_path);
698                 g_free (quoted_file_name);
699
700                 if (pipe == NULL)
701                         return GNOME_VFS_ERROR_NOT_SUPPORTED;
702
703                 result = read_directory_list (pipe, &list, info_options,
704                                               context);
705
706                 if (pclose (pipe) == 0 && result == GNOME_VFS_OK) {
707                         directory = extfs_directory_new (uri->parent, list);
708                 } else {
709                         free_directory_entries (list);
710                         if (result == GNOME_VFS_OK)
711                                 return GNOME_VFS_ERROR_IO; /* FIXME bugzilla.eazel.com 1223:? */
712                         else
713                                 return result;
714                 }
715         }
716
717         /* Remove all leading slashes, as they don't matter for us.  */
718         if (uri->text != NULL) {
719                 sub_uri = strip_separators(uri->text);
720         } else {
721                 sub_uri = NULL;
722         }
723
724         l = directory->entries;
725         while (l != NULL) {
726                 entry = l->data;
727
728                 /* check if one of entry->directory or sub_uri is NULL */
729                 if ((entry->directory != NULL && sub_uri == NULL) 
730                                 || (entry->directory == NULL && 
731                                         sub_uri != NULL)) {
732                         l = l->next;
733                         continue;
734                 }
735
736                 /* check if the paths match */
737                 if(strcmp(entry->directory, sub_uri)) {
738                         l = l->next;
739                         continue;
740                 }
741
742                 entries = g_list_append(entries, entry->info);
743                 l = l->next;
744         }
745         
746         g_free (sub_uri);
747
748         if(entries) {
749                 handle = g_malloc( sizeof(GList *) );
750
751                 *handle = entries;
752
753                 *method_handle = (GnomeVFSMethodHandle *) handle;
754
755                 return GNOME_VFS_OK;
756         } else {
757                 return GNOME_VFS_ERROR_NOT_A_DIRECTORY;
758         }
759 }
760
761 static GnomeVFSResult
762 do_close_directory (GnomeVFSMethod *method,
763                     GnomeVFSMethodHandle *method_handle,
764                     GnomeVFSContext *context)
765 {
766         GList *item;
767        
768         item = *((GList **)method_handle);
769
770         g_list_free (g_list_first (item));
771
772         g_free(method_handle);
773
774         return GNOME_VFS_OK;
775 }
776
777 static GnomeVFSResult
778 do_read_directory (GnomeVFSMethod *method,
779                    GnomeVFSMethodHandle *method_handle,
780                    GnomeVFSFileInfo *file_info,
781                    GnomeVFSContext *context)
782 {
783         GList *item;
784        
785         item = *((GList **)method_handle);
786
787         if (item == NULL)
788                 return GNOME_VFS_ERROR_EOF;
789
790         gnome_vfs_file_info_copy (file_info, (GnomeVFSFileInfo *)item->data);
791
792         //gnome_vfs_file_info_unref((GnomeVFSFileInfo *)item->data);
793
794         *((GList **)method_handle) = item->next;
795
796         return GNOME_VFS_OK;
797 }
798
799 static GnomeVFSResult
800 do_get_file_info (GnomeVFSMethod *method,
801                   GnomeVFSURI *uri,
802                   GnomeVFSFileInfo *file_info,
803                   GnomeVFSFileInfoOptions options,
804                   GnomeVFSContext *context)
805 {
806         GnomeVFSMethodHandle *method_handle;
807         GnomeVFSResult result;
808         GnomeVFSURI *parent;
809         gchar *filename;
810
811         parent = gnome_vfs_uri_get_parent(uri);
812
813         if (parent == NULL) {
814                 return GNOME_VFS_ERROR_INVALID_URI;
815         }
816         
817         filename = gnome_vfs_uri_extract_short_name(uri);
818
819         if(strcmp(parent->method_string, uri->method_string)) {
820                 
821                 result = gnome_vfs_get_file_info_uri(parent, file_info, options);
822                 /* now we get evil and tell the app that this is in fact a dir */
823                 file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
824                 g_free(file_info->mime_type);
825                 file_info->mime_type = g_strdup("x-directory/normal");
826                 g_free(filename);
827                 return result;
828         }
829         
830         result = do_open_directory (method, &method_handle, parent, options, context);
831         if (result != GNOME_VFS_OK)
832                 return result;
833
834         while (TRUE) {
835                 result = do_read_directory (method, method_handle, file_info, context);
836                 if (result != GNOME_VFS_OK ||
837                     !strcmp (file_info->name, filename))
838                         break;
839         }
840         do_close_directory (method, method_handle, context);
841
842         if (result == GNOME_VFS_ERROR_EOF)
843                 result = GNOME_VFS_ERROR_NOT_FOUND;
844         
845         g_free (filename);
846         return result;
847 }
848
849 static GnomeVFSResult
850 do_get_file_info_from_handle (GnomeVFSMethod *method,
851                               GnomeVFSMethodHandle *method_handle,
852                               GnomeVFSFileInfo *file_info,
853                               GnomeVFSFileInfoOptions options,
854                               GnomeVFSContext *context)
855 {
856         return GNOME_VFS_ERROR_NOT_SUPPORTED;
857 }
858
859 static gboolean
860 do_is_local (GnomeVFSMethod *method,
861              const GnomeVFSURI *uri)
862 {
863         return FALSE;
864 }
865
866 static GnomeVFSResult
867 do_make_directory (GnomeVFSMethod *method,
868                    GnomeVFSURI *uri,
869                    guint perm,
870                    GnomeVFSContext *context)
871 {
872         return GNOME_VFS_ERROR_NOT_SUPPORTED;
873 }
874
875 static GnomeVFSResult
876 do_find_directory (GnomeVFSMethod *method,
877                    GnomeVFSURI *near_uri,
878                    GnomeVFSFindDirectoryKind kind,
879                    GnomeVFSURI **result_uri,
880                    gboolean create_if_needed,
881                    gboolean find_if_needed,
882                    guint permissions,
883                    GnomeVFSContext *context)
884 {
885         return GNOME_VFS_ERROR_NOT_SUPPORTED;
886 }
887
888
889 static GnomeVFSResult
890 do_remove_directory (GnomeVFSMethod *method,
891                      GnomeVFSURI *uri,
892                      GnomeVFSContext *context)
893 {
894         return GNOME_VFS_ERROR_NOT_SUPPORTED;
895 }
896
897 static GnomeVFSResult
898 do_move (GnomeVFSMethod *method,
899          GnomeVFSURI *old_uri,
900          GnomeVFSURI *new_uri,
901          gboolean force_replace,
902          GnomeVFSContext *context)
903 {
904         return GNOME_VFS_ERROR_NOT_SUPPORTED;
905 }
906
907
908 static GnomeVFSResult
909 do_unlink (GnomeVFSMethod *method,
910            GnomeVFSURI *uri,
911            GnomeVFSContext *context)
912 {
913         return GNOME_VFS_ERROR_NOT_SUPPORTED;
914 }
915
916 static GnomeVFSResult
917 do_check_same_fs (GnomeVFSMethod *method,
918                   GnomeVFSURI *a,
919                   GnomeVFSURI *b,
920                   gboolean *same_fs_return,
921                   GnomeVFSContext *context)
922 {
923         return GNOME_VFS_ERROR_NOT_SUPPORTED;
924 }
925
926 \f
927 static GnomeVFSMethod method = {
928         sizeof (GnomeVFSMethod),
929         do_open,
930         do_create,
931         do_close,
932         do_read,
933         do_write,
934         do_seek,
935         do_tell,
936         do_truncate_handle,
937         do_open_directory,
938         do_close_directory,
939         do_read_directory,
940         do_get_file_info,
941         do_get_file_info_from_handle,
942         do_is_local,
943         do_make_directory,
944         do_remove_directory,
945         do_move,
946         do_unlink,
947         do_check_same_fs,
948         NULL,
949         do_truncate,
950         do_find_directory,
951         NULL     /* FIXME bugzilla.eazel.com 2804: do_create_symbolic_link */
952 };
953
954 GnomeVFSMethod *
955 vfs_module_init (const char *method_name, const char *args)
956 {
957         handle_list = NULL;
958         uri_to_directory_hash = g_hash_table_new (gnome_vfs_uri_hash,
959                                                   gnome_vfs_uri_hequal);
960
961         return &method;
962 }
963
964 void
965 vfs_module_shutdown (GnomeVFSMethod *method)
966 {
967         GList *p;
968
969         for (p = handle_list; p != NULL; p = p->next)
970                 extfs_handle_close ((ExtfsHandle *) p->data);
971 }