This source file includes following definitions.
- extfs_super_new
- extfs_entry_new
- extfs_fill_name
- extfs_cmp_archive
- extfs_generate_entry
- extfs_find_entry_int
- extfs_find_entry
- extfs_fill_names
- extfs_free_inode
- extfs_free_archive
- extfs_skip_leading_dotslash
- extfs_add_file
- extfs_open_archive
- extfs_read_archive
- extfs_which
- extfs_open_and_read_archive
- extfs_get_path
- extfs_get_path_from_entry
- extfs_resolve_symlinks_int
- extfs_resolve_symlinks
- extfs_get_archive_name
- extfs_cmd
- extfs_run
- extfs_open
- extfs_read
- extfs_close
- extfs_errno
- extfs_opendir
- extfs_readdir
- extfs_closedir
- extfs_stat_move
- extfs_internal_stat
- extfs_stat
- extfs_lstat
- extfs_fstat
- extfs_readlink
- extfs_write
- extfs_unlink
- extfs_mkdir
- extfs_rmdir
- extfs_chdir
- extfs_lseek
- extfs_getid
- extfs_getlocalcopy
- extfs_ungetlocalcopy
- extfs_get_plugins
- extfs_init
- extfs_done
- extfs_setctl
- vfs_init_extfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <config.h>
41
42 #include <stdio.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <signal.h>
50 #include <errno.h>
51 #include <sys/wait.h>
52
53 #include "lib/global.h"
54 #include "lib/fileloc.h"
55 #include "lib/mcconfig.h"
56 #include "lib/util.h"
57 #include "lib/widget.h"
58
59 #include "src/execute.h"
60
61 #include "lib/vfs/vfs.h"
62 #include "lib/vfs/utilvfs.h"
63 #include "lib/vfs/xdirentry.h"
64 #include "lib/vfs/gc.h"
65
66 #include "extfs.h"
67
68
69
70
71
72 #undef ERRNOR
73 #define ERRNOR(x, y) \
74 do \
75 { \
76 my_errno = x; \
77 return y; \
78 } \
79 while (0)
80
81 #define RECORDSIZE 512
82
83 #define EXTFS_SUPER(a) ((struct extfs_super_t *) (a))
84
85
86
87 struct extfs_super_t
88 {
89 struct vfs_s_super base;
90
91 int fstype;
92 char *local_name;
93 struct stat local_stat;
94 dev_t rdev;
95 };
96
97 typedef struct
98 {
99 char *path;
100 char *prefix;
101 gboolean need_archive;
102 } extfs_plugin_info_t;
103
104
105
106 static struct vfs_s_entry *extfs_resolve_symlinks_int (struct vfs_s_entry *entry, GSList *list);
107
108
109
110 static GArray *extfs_plugins = NULL;
111
112 static gboolean errloop;
113 static gboolean notadir;
114
115 static struct vfs_s_subclass extfs_subclass;
116 static struct vfs_class *vfs_extfs_ops = VFS_CLASS (&extfs_subclass);
117
118 static int my_errno = 0;
119
120
121
122
123
124 static struct extfs_super_t *
125 extfs_super_new (struct vfs_class *me, const char *name, const vfs_path_t *local_name_vpath,
126 int fstype)
127 {
128 struct extfs_super_t *super;
129 struct vfs_s_super *vsuper;
130
131 super = g_new0 (struct extfs_super_t, 1);
132 vsuper = VFS_SUPER (super);
133
134 vsuper->me = me;
135 vsuper->name = g_strdup (name);
136
137 super->fstype = fstype;
138
139 if (local_name_vpath != NULL)
140 {
141 super->local_name = g_strdup (vfs_path_get_last_path_str (local_name_vpath));
142 mc_stat (local_name_vpath, &super->local_stat);
143 }
144
145 VFS_SUBCLASS (me)->supers = g_list_prepend (VFS_SUBCLASS (me)->supers, super);
146
147 return super;
148 }
149
150
151
152
153 static struct vfs_s_entry *
154 extfs_entry_new (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
155 {
156 struct vfs_s_entry *entry;
157
158 (void) me;
159
160 entry = g_new0 (struct vfs_s_entry, 1);
161
162 entry->name = g_strdup (name);
163 entry->ino = inode;
164
165 return entry;
166 }
167
168
169
170 static void
171 extfs_fill_name (void *data, void *user_data)
172 {
173 struct vfs_s_super *a = VFS_SUPER (data);
174 fill_names_f func = (fill_names_f) user_data;
175 extfs_plugin_info_t *info;
176 char *name;
177
178 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, EXTFS_SUPER (a)->fstype);
179 name = g_strconcat (a->name != NULL ? a->name : "", PATH_SEP_STR, info->prefix,
180 VFS_PATH_URL_DELIMITER, (char *) NULL);
181 func (name);
182 g_free (name);
183 }
184
185
186
187 static gint
188 extfs_cmp_archive (const void *a, const void *b)
189 {
190 const struct vfs_s_super *ar = (const struct vfs_s_super *) a;
191 const char *archive_name = (const char *) b;
192
193 return (ar->name != NULL && strcmp (ar->name, archive_name) == 0) ? 0 : 1;
194 }
195
196
197
198 static struct vfs_s_entry *
199 extfs_generate_entry (struct extfs_super_t *archive, const char *name, struct vfs_s_inode *parent,
200 mode_t mode)
201 {
202 struct vfs_class *me = VFS_SUPER (archive)->me;
203 struct stat st;
204 mode_t myumask;
205 struct vfs_s_inode *inode;
206 struct vfs_s_entry *entry;
207
208 memset (&st, 0, sizeof (st));
209 st.st_ino = VFS_SUPER (archive)->ino_usage++;
210 st.st_dev = archive->rdev;
211 myumask = umask (022);
212 umask (myumask);
213 st.st_mode = mode & ~myumask;
214 st.st_uid = getuid ();
215 st.st_gid = getgid ();
216 st.st_mtime = time (NULL);
217 st.st_atime = st.st_mtime;
218 st.st_ctime = st.st_mtime;
219 st.st_nlink = 1;
220
221 inode = vfs_s_new_inode (me, VFS_SUPER (archive), &st);
222 entry = vfs_s_new_entry (me, name, inode);
223 if (parent != NULL)
224 vfs_s_insert_entry (me, parent, entry);
225
226 return entry;
227 }
228
229
230
231 static struct vfs_s_entry *
232 extfs_find_entry_int (struct vfs_s_inode *dir, const char *name, GSList *list, int flags)
233 {
234 struct vfs_s_entry *pent, *pdir;
235 const char *p, *name_end;
236 char *q;
237 char c = PATH_SEP;
238 struct extfs_super_t *super;
239
240 if (g_path_is_absolute (name))
241 {
242
243 name = g_path_skip_root (name);
244 dir = dir->super->root;
245 }
246
247 super = EXTFS_SUPER (dir->super);
248 pent = dir->ent;
249 p = name;
250 name_end = name + strlen (name);
251
252 while ((pent != NULL) && (c != '\0') && (*p != '\0'))
253 {
254 q = strchr (p, PATH_SEP);
255 if (q == NULL)
256 q = (char *) name_end;
257
258 c = *q;
259 *q = '\0';
260
261 if (DIR_IS_DOTDOT (p))
262 pent = pent->dir != NULL ? pent->dir->ent : NULL;
263 else
264 {
265 GList *pl;
266
267 pent = extfs_resolve_symlinks_int (pent, list);
268 if (pent == NULL)
269 {
270 *q = c;
271 return NULL;
272 }
273
274 if (!S_ISDIR (pent->ino->st.st_mode))
275 {
276 *q = c;
277 notadir = TRUE;
278 return NULL;
279 }
280
281 pdir = pent;
282 pl = g_queue_find_custom (pent->ino->subdir, p, vfs_s_entry_compare);
283 pent = pl != NULL ? VFS_ENTRY (pl->data) : NULL;
284 if (pent != NULL && q + 1 > name_end)
285 {
286
287 *q = c;
288 notadir = !S_ISDIR (pent->ino->st.st_mode);
289 return pent;
290 }
291
292
293 if (pent == NULL && (flags & FL_MKDIR) != 0)
294 pent = extfs_generate_entry (super, p, pdir->ino, S_IFDIR | 0777);
295 if (pent == NULL && (flags & FL_MKFILE) != 0)
296 pent = extfs_generate_entry (super, p, pdir->ino, S_IFREG | 0666);
297 }
298
299
300 *q = c;
301 if (c != '\0')
302 p = q + 1;
303 }
304 if (pent == NULL)
305 my_errno = ENOENT;
306 return pent;
307 }
308
309
310
311 static struct vfs_s_entry *
312 extfs_find_entry (struct vfs_s_inode *dir, const char *name, int flags)
313 {
314 struct vfs_s_entry *res;
315
316 errloop = FALSE;
317 notadir = FALSE;
318
319 res = extfs_find_entry_int (dir, name, NULL, flags);
320 if (res == NULL)
321 {
322 if (errloop)
323 my_errno = ELOOP;
324 else if (notadir)
325 my_errno = ENOTDIR;
326 }
327 return res;
328 }
329
330
331
332 static void
333 extfs_fill_names (struct vfs_class *me, fill_names_f func)
334 {
335 g_list_foreach (VFS_SUBCLASS (me)->supers, extfs_fill_name, func);
336 }
337
338
339
340
341 static void
342 extfs_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
343 {
344 (void) me;
345
346 if (ino->localname != NULL)
347 {
348 unlink (ino->localname);
349 MC_PTR_FREE (ino->localname);
350 }
351 }
352
353
354
355 static void
356 extfs_free_archive (struct vfs_class *me, struct vfs_s_super *psup)
357 {
358 struct extfs_super_t *archive = EXTFS_SUPER (psup);
359
360 (void) me;
361
362 if (archive->local_name != NULL)
363 {
364 struct stat my;
365 vfs_path_t *local_name_vpath, *name_vpath;
366
367 local_name_vpath = vfs_path_from_str (archive->local_name);
368 name_vpath = vfs_path_from_str (psup->name);
369 mc_stat (local_name_vpath, &my);
370 mc_ungetlocalcopy (name_vpath, local_name_vpath,
371 archive->local_stat.st_mtime != my.st_mtime);
372 vfs_path_free (local_name_vpath, TRUE);
373 vfs_path_free (name_vpath, TRUE);
374 g_free (archive->local_name);
375 }
376 }
377
378
379
380 static inline char *
381 extfs_skip_leading_dotslash (char *s)
382 {
383
384
385
386
387
388
389
390
391
392 if (s[0] == '.' && s[1] == PATH_SEP)
393 s += 2;
394
395 return s;
396 }
397
398
399
400 static int
401 extfs_add_file (struct extfs_super_t *archive, const char *file_name)
402 {
403 struct vfs_s_super *super = VFS_SUPER (archive);
404 struct stat hstat;
405 char *current_file_name = NULL, *current_link_name = NULL;
406 int ret = 0;
407
408 if (vfs_parse_ls_lga (file_name, &hstat, ¤t_file_name, ¤t_link_name, NULL))
409 {
410 char *cfn = current_file_name;
411
412 if (*cfn != '\0')
413 {
414 struct vfs_s_entry *entry;
415 struct vfs_s_entry *pent = NULL;
416 struct vfs_s_inode *inode;
417 char *p, *q;
418
419 cfn = extfs_skip_leading_dotslash (cfn);
420 if (IS_PATH_SEP (*cfn))
421 cfn++;
422 p = strchr (cfn, '\0');
423 if (p != cfn && IS_PATH_SEP (p[-1]))
424 p[-1] = '\0';
425 p = strrchr (cfn, PATH_SEP);
426 if (p == NULL)
427 {
428 p = cfn;
429 q = strchr (cfn, '\0');
430 }
431 else
432 {
433 *(p++) = '\0';
434 q = cfn;
435 }
436
437 if (*q != '\0')
438 {
439 pent = extfs_find_entry (super->root, q, FL_MKDIR);
440 if (pent == NULL)
441 {
442 ret = -1;
443 goto done;
444 }
445 }
446
447 if (pent != NULL)
448 {
449 entry = extfs_entry_new (super->me, p, pent->ino);
450 entry->dir = pent->ino;
451 g_queue_push_tail (pent->ino->subdir, entry);
452 }
453 else
454 {
455 entry = extfs_entry_new (super->me, p, super->root);
456 entry->dir = super->root;
457 g_queue_push_tail (super->root->subdir, entry);
458 }
459
460 if (!S_ISLNK (hstat.st_mode) && (current_link_name != NULL))
461 {
462 pent = extfs_find_entry (super->root, current_link_name, FL_NONE);
463 if (pent == NULL)
464 {
465 ret = -1;
466 goto done;
467 }
468
469 pent->ino->st.st_nlink++;
470 entry->ino = pent->ino;
471 }
472 else
473 {
474 struct stat st;
475
476 memset (&st, 0, sizeof (st));
477 st.st_ino = super->ino_usage++;
478 st.st_nlink = 1;
479 st.st_dev = archive->rdev;
480 st.st_mode = hstat.st_mode;
481 #ifdef HAVE_STRUCT_STAT_ST_RDEV
482 st.st_rdev = hstat.st_rdev;
483 #endif
484 st.st_uid = hstat.st_uid;
485 st.st_gid = hstat.st_gid;
486 st.st_size = hstat.st_size;
487 st.st_mtime = hstat.st_mtime;
488 st.st_atime = hstat.st_atime;
489 st.st_ctime = hstat.st_ctime;
490
491 if (current_link_name == NULL && S_ISLNK (hstat.st_mode))
492 st.st_mode &= ~S_IFLNK;
493
494 inode = vfs_s_new_inode (super->me, super, &st);
495 inode->ent = entry;
496 entry->ino = inode;
497
498 if (current_link_name != NULL && S_ISLNK (hstat.st_mode))
499 {
500 inode->linkname = current_link_name;
501 current_link_name = NULL;
502 }
503 }
504 }
505
506 done:
507 g_free (current_file_name);
508 g_free (current_link_name);
509 }
510
511 return ret;
512 }
513
514
515
516 static mc_pipe_t *
517 extfs_open_archive (int fstype, const char *name, struct extfs_super_t **pparc, GError **error)
518 {
519 const extfs_plugin_info_t *info;
520 static dev_t archive_counter = 0;
521 mc_pipe_t *result = NULL;
522 mode_t mode;
523 GString *cmd;
524 struct stat mystat;
525 struct extfs_super_t *current_archive;
526 struct vfs_s_entry *root_entry;
527 GString *quoted_name = NULL;
528 vfs_path_t *local_name_vpath = NULL;
529 vfs_path_t *name_vpath;
530
531 memset (&mystat, 0, sizeof (mystat));
532
533 name_vpath = vfs_path_from_str (name);
534 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, fstype);
535
536 if (info->need_archive)
537 {
538 if (mc_stat (name_vpath, &mystat) == -1)
539 {
540 mc_propagate_error (error, 0, "%s", unix_error_string (errno));
541 goto ret;
542 }
543
544 if (!vfs_file_is_local (name_vpath))
545 {
546 local_name_vpath = mc_getlocalcopy (name_vpath);
547 if (local_name_vpath == NULL)
548 goto ret;
549 }
550
551 quoted_name = name_quote (vfs_path_get_last_path_str (name_vpath), FALSE);
552 }
553
554 const char *local_last_path = vfs_path_get_last_path_str (local_name_vpath);
555
556 cmd = g_string_new (info->path);
557 g_string_append (cmd, info->prefix);
558 g_string_append (cmd, " list ");
559
560 if (local_last_path != NULL)
561 g_string_append (cmd, local_last_path);
562 else if (quoted_name != NULL)
563 {
564 mc_g_string_concat (cmd, quoted_name);
565 g_string_free (quoted_name, TRUE);
566 }
567
568 result = mc_popen (cmd->str, TRUE, TRUE, error);
569 g_string_free (cmd, TRUE);
570
571 if (result == NULL)
572 {
573 if (local_name_vpath != NULL)
574 {
575 mc_ungetlocalcopy (name_vpath, local_name_vpath, FALSE);
576 vfs_path_free (local_name_vpath, TRUE);
577 }
578 goto ret;
579 }
580
581 current_archive = extfs_super_new (vfs_extfs_ops, name, local_name_vpath, fstype);
582 current_archive->rdev = archive_counter++;
583 vfs_path_free (local_name_vpath, TRUE);
584
585 mode = mystat.st_mode & 07777;
586 if (mode & 0400)
587 mode |= 0100;
588 if (mode & 0040)
589 mode |= 0010;
590 if (mode & 0004)
591 mode |= 0001;
592 mode |= S_IFDIR;
593
594 root_entry = extfs_generate_entry (current_archive, PATH_SEP_STR, NULL, mode);
595 root_entry->ino->st.st_uid = mystat.st_uid;
596 root_entry->ino->st.st_gid = mystat.st_gid;
597 root_entry->ino->st.st_atime = mystat.st_atime;
598 root_entry->ino->st.st_ctime = mystat.st_ctime;
599 root_entry->ino->st.st_mtime = mystat.st_mtime;
600 root_entry->ino->ent = root_entry;
601 VFS_SUPER (current_archive)->root = root_entry->ino;
602
603 *pparc = current_archive;
604
605 ret:
606 vfs_path_free (name_vpath, TRUE);
607 return result;
608 }
609
610
611
612
613
614
615
616 static int
617 extfs_read_archive (mc_pipe_t *pip, struct extfs_super_t *archive, GError **error)
618 {
619 int ret = 0;
620 GString *buffer;
621 GString *err_msg = NULL;
622 GString *remain_file_name = NULL;
623
624 while (ret != -1)
625 {
626
627 pip->out.len = MC_PIPE_BUFSIZE;
628 pip->err.len = MC_PIPE_BUFSIZE;
629
630 mc_pread (pip, error);
631
632 if (*error != NULL)
633 return (-1);
634
635 if (pip->err.len > 0)
636 {
637
638 if (err_msg == NULL)
639 err_msg = g_string_new_len (pip->err.buf, pip->err.len);
640 else
641 {
642 if (err_msg->str[err_msg->len - 1] != '\n')
643 g_string_append_c (err_msg, '\n');
644 g_string_append_len (err_msg, pip->err.buf, pip->err.len);
645 }
646 }
647
648 if (pip->out.len == MC_PIPE_STREAM_EOF)
649 break;
650
651 if (pip->out.len == 0)
652 continue;
653
654 if (pip->out.len == MC_PIPE_ERROR_READ)
655 return (-1);
656
657 while (ret != -1 && (buffer = mc_pstream_get_string (&pip->out)) != NULL)
658 {
659
660
661 if (buffer->str[buffer->len - 1] == '\n')
662 {
663
664
665 g_string_truncate (buffer, buffer->len - 1);
666
667
668 if (remain_file_name != NULL)
669 {
670 g_string_append_len (remain_file_name, buffer->str, buffer->len);
671 g_string_free (buffer, TRUE);
672 buffer = remain_file_name;
673 remain_file_name = NULL;
674 }
675 }
676 else
677 {
678
679
680 if (remain_file_name == NULL)
681 remain_file_name = buffer;
682 else
683 {
684 g_string_append_len (remain_file_name, buffer->str, buffer->len);
685 g_string_free (buffer, TRUE);
686 }
687
688 continue;
689 }
690
691 ret = extfs_add_file (archive, buffer->str);
692
693 g_string_free (buffer, TRUE);
694 }
695 }
696
697 if (remain_file_name != NULL)
698 g_string_free (remain_file_name, TRUE);
699
700 if (err_msg != NULL)
701 {
702 if (*error == NULL)
703 mc_propagate_error (error, 0, "%s", err_msg->str);
704
705 g_string_free (err_msg, TRUE);
706 }
707 else if (ret == -1)
708 mc_propagate_error (error, 0, "%s", _ ("Inconsistent archive"));
709
710 return ret;
711 }
712
713
714
715 static int
716 extfs_which (struct vfs_class *me, const char *path)
717 {
718 size_t path_len;
719 size_t i;
720
721 (void) me;
722
723 path_len = strlen (path);
724
725 for (i = 0; i < extfs_plugins->len; i++)
726 {
727 extfs_plugin_info_t *info;
728
729 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, i);
730
731 if ((strncmp (path, info->prefix, path_len) == 0)
732 && ((info->prefix[path_len] == '\0') || (info->prefix[path_len] == '+')))
733 return i;
734 }
735 return -1;
736 }
737
738
739
740 static int
741 extfs_open_and_read_archive (int fstype, const char *name, struct extfs_super_t **archive)
742 {
743 int result = -1;
744 struct extfs_super_t *a;
745 mc_pipe_t *pip;
746 GError *error = NULL;
747
748 pip = extfs_open_archive (fstype, name, archive, &error);
749
750 a = *archive;
751
752 if (pip == NULL)
753 {
754 const extfs_plugin_info_t *info;
755
756 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, fstype);
757 if (error == NULL)
758 message (D_ERROR, MSG_ERROR, _ ("Cannot open %s archive\n%s"), info->prefix, name);
759 else
760 {
761 message (D_ERROR, MSG_ERROR, _ ("Cannot open %s archive\n%s:\n%s"), info->prefix, name,
762 error->message);
763 g_error_free (error);
764 }
765 }
766 else
767 {
768 result = extfs_read_archive (pip, a, &error);
769
770 if (result != 0)
771 VFS_SUPER (a)->me->free (VFS_SUPER (a));
772
773 if (error != NULL)
774 {
775 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), error->message);
776 g_error_free (error);
777 }
778
779 mc_pclose (pip, NULL);
780 }
781
782 return result;
783 }
784
785
786
787
788
789 static const char *
790 extfs_get_path (const vfs_path_t *vpath, struct extfs_super_t **archive, int flags)
791 {
792 char *archive_name;
793 int result = -1;
794 GList *parc;
795 int fstype;
796 const vfs_path_element_t *path_element;
797 struct extfs_super_t *a = NULL;
798
799 path_element = vfs_path_get_by_index (vpath, -1);
800
801 fstype = extfs_which (path_element->class, path_element->vfs_prefix);
802 if (fstype == -1)
803 return NULL;
804
805 archive_name = vfs_path_to_str_elements_count (vpath, -1);
806
807
808 parc = g_list_find_custom (extfs_subclass.supers, archive_name, extfs_cmp_archive);
809 if (parc != NULL)
810 {
811 a = EXTFS_SUPER (parc->data);
812 vfs_stamp (vfs_extfs_ops, (vfsid) a);
813 g_free (archive_name);
814 }
815 else
816 {
817 if ((flags & FL_NO_OPEN) == 0)
818 result = extfs_open_and_read_archive (fstype, archive_name, &a);
819
820 g_free (archive_name);
821
822 if (result == -1)
823 {
824 path_element->class->verrno = EIO;
825 return NULL;
826 }
827 }
828
829 *archive = a;
830 return path_element->path;
831 }
832
833
834
835
836 static char *
837 extfs_get_path_from_entry (const struct vfs_s_entry *entry)
838 {
839 const struct vfs_s_entry *e;
840 GString *localpath;
841
842 localpath = g_string_new ("");
843
844 for (e = entry; e->dir != NULL; e = e->dir->ent)
845 {
846 g_string_prepend (localpath, e->name);
847 if (e->dir->ent->dir != NULL)
848 g_string_prepend_c (localpath, PATH_SEP);
849 }
850
851 return g_string_free (localpath, FALSE);
852 }
853
854
855
856 static struct vfs_s_entry *
857 extfs_resolve_symlinks_int (struct vfs_s_entry *entry, GSList *list)
858 {
859 struct vfs_s_entry *pent = NULL;
860
861 if (!S_ISLNK (entry->ino->st.st_mode))
862 return entry;
863
864 if (g_slist_find (list, entry) != NULL)
865 {
866
867 errloop = TRUE;
868 }
869 else
870 {
871 GSList *looping;
872
873 looping = g_slist_prepend (list, entry);
874 pent = extfs_find_entry_int (entry->dir, entry->ino->linkname, looping, FL_NONE);
875 looping = g_slist_delete_link (looping, looping);
876
877 if (pent == NULL)
878 my_errno = ENOENT;
879 }
880
881 return pent;
882 }
883
884
885
886 static struct vfs_s_entry *
887 extfs_resolve_symlinks (struct vfs_s_entry *entry)
888 {
889 struct vfs_s_entry *res;
890
891 errloop = FALSE;
892 notadir = FALSE;
893 res = extfs_resolve_symlinks_int (entry, NULL);
894 if (res == NULL)
895 {
896 if (errloop)
897 my_errno = ELOOP;
898 else if (notadir)
899 my_errno = ENOTDIR;
900 }
901 return res;
902 }
903
904
905
906 static char *
907 extfs_get_archive_name (const struct extfs_super_t *archive)
908 {
909 const char *archive_name;
910
911 if (archive->local_name != NULL)
912 archive_name = archive->local_name;
913 else
914 archive_name = CONST_VFS_SUPER (archive)->name;
915
916 if (archive_name == NULL || *archive_name == '\0')
917 return g_strdup ("no_archive_name");
918 else
919 {
920 char *ret_str;
921 vfs_path_t *vpath;
922 const char *path;
923
924 vpath = vfs_path_from_str (archive_name);
925 path = vfs_path_get_last_path_str (vpath);
926 ret_str = g_strdup (path);
927 vfs_path_free (vpath, TRUE);
928 return ret_str;
929 }
930 }
931
932
933
934
935 static int
936 extfs_cmd (const char *str_extfs_cmd, const struct extfs_super_t *archive,
937 const struct vfs_s_entry *entry, const char *localname)
938 {
939 char *file;
940 GString *quoted_file;
941 char *archive_name;
942 GString *quoted_archive_name;
943 const extfs_plugin_info_t *info;
944 GString *cmd;
945 int retval = 0;
946 GError *error = NULL;
947 mc_pipe_t *pip;
948
949 file = extfs_get_path_from_entry (entry);
950 quoted_file = name_quote (file, FALSE);
951 g_free (file);
952
953 if (quoted_file == NULL)
954 {
955 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\nwrong file name"));
956 return (-1);
957 }
958
959
960 file = extfs_skip_leading_dotslash (quoted_file->str);
961 g_string_free (quoted_file, TRUE);
962
963 archive_name = extfs_get_archive_name (archive);
964 quoted_archive_name = name_quote (archive_name, FALSE);
965 g_free (archive_name);
966
967 if (quoted_archive_name == NULL)
968 {
969 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\nwrong archive name"));
970 return (-1);
971 }
972
973 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, archive->fstype);
974
975 cmd = g_string_new (info->path);
976 g_string_append (cmd, info->prefix);
977 g_string_append (cmd, str_extfs_cmd);
978 mc_g_string_concat (cmd, quoted_archive_name);
979 g_string_append_c (cmd, ' ');
980 g_string_append (cmd, file);
981
982 g_string_free (quoted_archive_name, TRUE);
983
984 if (localname != NULL && *localname != '\0')
985 {
986 GString *quoted_localname;
987
988 quoted_localname = name_quote (localname, FALSE);
989 g_string_append_c (cmd, ' ');
990 mc_g_string_concat (cmd, quoted_localname);
991 g_string_free (quoted_localname, TRUE);
992 }
993
994
995 pip = mc_popen (cmd->str, FALSE, TRUE, &error);
996 g_string_free (cmd, TRUE);
997
998 if (pip == NULL)
999 {
1000 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), error->message);
1001 g_error_free (error);
1002 return (-1);
1003 }
1004
1005 pip->err.null_term = TRUE;
1006
1007 mc_pread (pip, &error);
1008 if (error != NULL)
1009 {
1010 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), error->message);
1011 g_error_free (error);
1012 retval = -1;
1013 }
1014 else if (pip->err.len > 0)
1015 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), pip->err.buf);
1016
1017 mc_pclose (pip, NULL);
1018
1019 return retval;
1020 }
1021
1022
1023
1024 static void
1025 extfs_run (const vfs_path_t *vpath)
1026 {
1027 struct extfs_super_t *archive = NULL;
1028 const char *p;
1029 GString *quoted_name;
1030 char *archive_name;
1031 GString *quoted_archive_name;
1032 GString *cmd;
1033 const extfs_plugin_info_t *info;
1034
1035 p = extfs_get_path (vpath, &archive, FL_NONE);
1036 if (p == NULL)
1037 return;
1038
1039 quoted_name = name_quote (p, FALSE);
1040 archive_name = extfs_get_archive_name (archive);
1041 quoted_archive_name = name_quote (archive_name, FALSE);
1042 g_free (archive_name);
1043
1044 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, archive->fstype);
1045
1046 cmd = g_string_new (info->path);
1047 g_string_append (cmd, info->prefix);
1048 g_string_append (cmd, " run ");
1049 mc_g_string_concat (cmd, quoted_archive_name);
1050 g_string_append_c (cmd, ' ');
1051 mc_g_string_concat (cmd, quoted_name);
1052
1053 g_string_free (quoted_archive_name, TRUE);
1054 g_string_free (quoted_name, TRUE);
1055
1056 shell_execute (cmd->str, 0);
1057
1058 g_string_free (cmd, TRUE);
1059 }
1060
1061
1062
1063 static void *
1064 extfs_open (const vfs_path_t *vpath, int flags, mode_t mode)
1065 {
1066 vfs_file_handler_t *extfs_info;
1067 struct extfs_super_t *archive = NULL;
1068 const char *q;
1069 struct vfs_s_entry *entry;
1070 int local_handle;
1071 gboolean created = FALSE;
1072
1073 q = extfs_get_path (vpath, &archive, FL_NONE);
1074 if (q == NULL)
1075 return NULL;
1076 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1077 if ((entry == NULL) && ((flags & O_CREAT) != 0))
1078 {
1079
1080 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_MKFILE);
1081 created = (entry != NULL);
1082 }
1083
1084 if (entry == NULL)
1085 return NULL;
1086 entry = extfs_resolve_symlinks (entry);
1087 if (entry == NULL)
1088 return NULL;
1089
1090 if (S_ISDIR (entry->ino->st.st_mode))
1091 ERRNOR (EISDIR, NULL);
1092
1093 if (entry->ino->localname == NULL)
1094 {
1095 vfs_path_t *local_filename_vpath;
1096 const char *local_filename;
1097
1098 local_handle = vfs_mkstemps (&local_filename_vpath, "extfs", entry->name);
1099
1100 if (local_handle == -1)
1101 return NULL;
1102 close (local_handle);
1103 local_filename = vfs_path_get_last_path_str (local_filename_vpath);
1104
1105 if (!created && ((flags & O_TRUNC) == 0)
1106 && extfs_cmd (" copyout ", archive, entry, local_filename))
1107 {
1108 unlink (local_filename);
1109 vfs_path_free (local_filename_vpath, TRUE);
1110 my_errno = EIO;
1111 return NULL;
1112 }
1113 entry->ino->localname = g_strdup (local_filename);
1114 vfs_path_free (local_filename_vpath, TRUE);
1115 }
1116
1117 local_handle = open (entry->ino->localname, NO_LINEAR (flags), mode);
1118
1119 if (local_handle == -1)
1120 {
1121
1122 flags = ~O_CREAT & (NO_LINEAR (flags) | O_TRUNC);
1123 local_handle = open (entry->ino->localname, flags, mode);
1124 }
1125
1126 if (local_handle == -1)
1127 ERRNOR (EIO, NULL);
1128
1129 extfs_info = g_new (vfs_file_handler_t, 1);
1130 vfs_s_init_fh (extfs_info, entry->ino, created);
1131 extfs_info->handle = local_handle;
1132
1133
1134 vfs_rmstamp (vfs_extfs_ops, (vfsid) archive);
1135 VFS_SUPER (archive)->fd_usage++;
1136 return extfs_info;
1137 }
1138
1139
1140
1141 static ssize_t
1142 extfs_read (void *fh, char *buffer, size_t count)
1143 {
1144 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1145
1146 return read (file->handle, buffer, count);
1147 }
1148
1149
1150
1151 static int
1152 extfs_close (void *fh)
1153 {
1154 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1155 int errno_code = 0;
1156
1157 close (file->handle);
1158 file->handle = -1;
1159
1160
1161 if (file->changed)
1162 {
1163 struct stat file_status;
1164
1165 if (extfs_cmd (" copyin ", EXTFS_SUPER (VFS_FILE_HANDLER_SUPER (fh)), file->ino->ent,
1166 file->ino->localname))
1167 errno_code = EIO;
1168
1169 if (stat (file->ino->localname, &file_status) != 0)
1170 errno_code = EIO;
1171 else
1172 file->ino->st.st_size = file_status.st_size;
1173
1174 file->ino->st.st_mtime = time (NULL);
1175 }
1176
1177 if (--VFS_FILE_HANDLER_SUPER (fh)->fd_usage == 0)
1178 vfs_stamp_create (vfs_extfs_ops, VFS_FILE_HANDLER_SUPER (fh));
1179
1180 g_free (fh);
1181 if (errno_code != 0)
1182 ERRNOR (EIO, -1);
1183 return 0;
1184 }
1185
1186
1187
1188 static int
1189 extfs_errno (struct vfs_class *me)
1190 {
1191 (void) me;
1192 return my_errno;
1193 }
1194
1195
1196
1197 static void *
1198 extfs_opendir (const vfs_path_t *vpath)
1199 {
1200 struct extfs_super_t *archive = NULL;
1201 const char *q;
1202 struct vfs_s_entry *entry;
1203 GList **info;
1204
1205 q = extfs_get_path (vpath, &archive, FL_NONE);
1206 if (q == NULL)
1207 return NULL;
1208 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1209 if (entry == NULL)
1210 return NULL;
1211 entry = extfs_resolve_symlinks (entry);
1212 if (entry == NULL)
1213 return NULL;
1214 if (!S_ISDIR (entry->ino->st.st_mode))
1215 ERRNOR (ENOTDIR, NULL);
1216
1217 info = g_new (GList *, 1);
1218 *info = g_queue_peek_head_link (entry->ino->subdir);
1219
1220 return info;
1221 }
1222
1223
1224
1225 static struct vfs_dirent *
1226 extfs_readdir (void *data)
1227 {
1228 struct vfs_dirent *dir;
1229 GList **info = (GList **) data;
1230
1231 if (*info == NULL)
1232 return NULL;
1233
1234 dir = vfs_dirent_init (NULL, VFS_ENTRY ((*info)->data)->name, 0, DT_UNKNOWN);
1235
1236 *info = g_list_next (*info);
1237
1238 return dir;
1239 }
1240
1241
1242
1243 static int
1244 extfs_closedir (void *data)
1245 {
1246 g_free (data);
1247 return 0;
1248 }
1249
1250
1251
1252 static void
1253 extfs_stat_move (struct stat *buf, const struct vfs_s_inode *inode)
1254 {
1255 const time_t atime = inode->st.st_atime;
1256 const time_t mtime = inode->st.st_mtime;
1257 const time_t ctime = inode->st.st_ctime;
1258
1259 *buf = inode->st;
1260
1261 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1262 buf->st_blksize = RECORDSIZE;
1263 #endif
1264
1265 vfs_adjust_stat (buf);
1266 vfs_zero_stat_times (buf);
1267
1268 buf->st_atime = atime;
1269 buf->st_mtime = mtime;
1270 buf->st_ctime = ctime;
1271 }
1272
1273
1274
1275 static int
1276 extfs_internal_stat (const vfs_path_t *vpath, struct stat *buf, gboolean resolve)
1277 {
1278 struct extfs_super_t *archive;
1279 const char *q;
1280 struct vfs_s_entry *entry;
1281 int result = -1;
1282
1283 q = extfs_get_path (vpath, &archive, FL_NONE);
1284 if (q == NULL)
1285 goto cleanup;
1286 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1287 if (entry == NULL)
1288 goto cleanup;
1289 if (resolve)
1290 {
1291 entry = extfs_resolve_symlinks (entry);
1292 if (entry == NULL)
1293 goto cleanup;
1294 }
1295 extfs_stat_move (buf, entry->ino);
1296 result = 0;
1297 cleanup:
1298 return result;
1299 }
1300
1301
1302
1303 static int
1304 extfs_stat (const vfs_path_t *vpath, struct stat *buf)
1305 {
1306 return extfs_internal_stat (vpath, buf, TRUE);
1307 }
1308
1309
1310
1311 static int
1312 extfs_lstat (const vfs_path_t *vpath, struct stat *buf)
1313 {
1314 return extfs_internal_stat (vpath, buf, FALSE);
1315 }
1316
1317
1318
1319 static int
1320 extfs_fstat (void *fh, struct stat *buf)
1321 {
1322 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1323
1324 extfs_stat_move (buf, file->ino);
1325 return 0;
1326 }
1327
1328
1329
1330 static int
1331 extfs_readlink (const vfs_path_t *vpath, char *buf, size_t size)
1332 {
1333 struct extfs_super_t *archive;
1334 const char *q;
1335 size_t len;
1336 struct vfs_s_entry *entry;
1337 int result = -1;
1338
1339 q = extfs_get_path (vpath, &archive, FL_NONE);
1340 if (q == NULL)
1341 goto cleanup;
1342 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1343 if (entry == NULL)
1344 goto cleanup;
1345 if (!S_ISLNK (entry->ino->st.st_mode))
1346 {
1347 VFS_CLASS (vfs_path_get_last_path_vfs (vpath))->verrno = EINVAL;
1348 goto cleanup;
1349 }
1350 len = strlen (entry->ino->linkname);
1351 if (size < len)
1352 len = size;
1353
1354 result = len;
1355 memcpy (buf, entry->ino->linkname, result);
1356 cleanup:
1357 return result;
1358 }
1359
1360
1361
1362 static ssize_t
1363 extfs_write (void *fh, const char *buf, size_t nbyte)
1364 {
1365 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1366
1367 file->changed = TRUE;
1368 return write (file->handle, buf, nbyte);
1369 }
1370
1371
1372
1373 static int
1374 extfs_unlink (const vfs_path_t *vpath)
1375 {
1376 struct extfs_super_t *archive;
1377 const char *q;
1378 struct vfs_s_entry *entry;
1379 int result = -1;
1380
1381 q = extfs_get_path (vpath, &archive, FL_NONE);
1382 if (q == NULL)
1383 goto cleanup;
1384 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1385 if (entry == NULL)
1386 goto cleanup;
1387 entry = extfs_resolve_symlinks (entry);
1388 if (entry == NULL)
1389 goto cleanup;
1390 if (S_ISDIR (entry->ino->st.st_mode))
1391 {
1392 VFS_CLASS (vfs_path_get_last_path_vfs (vpath))->verrno = EISDIR;
1393 goto cleanup;
1394 }
1395 if (extfs_cmd (" rm ", archive, entry, ""))
1396 {
1397 my_errno = EIO;
1398 goto cleanup;
1399 }
1400 vfs_s_free_entry (VFS_SUPER (archive)->me, entry);
1401 result = 0;
1402 cleanup:
1403 return result;
1404 }
1405
1406
1407
1408 static int
1409 extfs_mkdir (const vfs_path_t *vpath, mode_t mode)
1410 {
1411 struct extfs_super_t *archive;
1412 const char *q;
1413 struct vfs_s_entry *entry;
1414 int result = -1;
1415 struct vfs_class *me;
1416
1417 (void) mode;
1418
1419 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
1420 q = extfs_get_path (vpath, &archive, FL_NONE);
1421 if (q == NULL)
1422 goto cleanup;
1423 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1424 if (entry != NULL)
1425 {
1426 me->verrno = EEXIST;
1427 goto cleanup;
1428 }
1429 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_MKDIR);
1430 if (entry == NULL)
1431 goto cleanup;
1432 entry = extfs_resolve_symlinks (entry);
1433 if (entry == NULL)
1434 goto cleanup;
1435 if (!S_ISDIR (entry->ino->st.st_mode))
1436 {
1437 me->verrno = ENOTDIR;
1438 goto cleanup;
1439 }
1440
1441 if (extfs_cmd (" mkdir ", archive, entry, ""))
1442 {
1443 my_errno = EIO;
1444 vfs_s_free_entry (VFS_SUPER (archive)->me, entry);
1445 goto cleanup;
1446 }
1447 result = 0;
1448 cleanup:
1449 return result;
1450 }
1451
1452
1453
1454 static int
1455 extfs_rmdir (const vfs_path_t *vpath)
1456 {
1457 struct extfs_super_t *archive;
1458 const char *q;
1459 struct vfs_s_entry *entry;
1460 int result = -1;
1461
1462 q = extfs_get_path (vpath, &archive, FL_NONE);
1463 if (q == NULL)
1464 goto cleanup;
1465 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1466 if (entry == NULL)
1467 goto cleanup;
1468 entry = extfs_resolve_symlinks (entry);
1469 if (entry == NULL)
1470 goto cleanup;
1471 if (!S_ISDIR (entry->ino->st.st_mode))
1472 {
1473 VFS_CLASS (vfs_path_get_last_path_vfs (vpath))->verrno = ENOTDIR;
1474 goto cleanup;
1475 }
1476
1477 if (extfs_cmd (" rmdir ", archive, entry, ""))
1478 {
1479 my_errno = EIO;
1480 goto cleanup;
1481 }
1482 vfs_s_free_entry (VFS_SUPER (archive)->me, entry);
1483 result = 0;
1484 cleanup:
1485 return result;
1486 }
1487
1488
1489
1490 static int
1491 extfs_chdir (const vfs_path_t *vpath)
1492 {
1493 void *data;
1494
1495 my_errno = ENOTDIR;
1496 data = extfs_opendir (vpath);
1497 if (data == NULL)
1498 return (-1);
1499 extfs_closedir (data);
1500 my_errno = 0;
1501 return 0;
1502 }
1503
1504
1505
1506 static off_t
1507 extfs_lseek (void *fh, off_t offset, int whence)
1508 {
1509 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1510
1511 return lseek (file->handle, offset, whence);
1512 }
1513
1514
1515
1516 static vfsid
1517 extfs_getid (const vfs_path_t *vpath)
1518 {
1519 struct extfs_super_t *archive = NULL;
1520 const char *p;
1521
1522 p = extfs_get_path (vpath, &archive, FL_NO_OPEN);
1523 return (p == NULL ? NULL : (vfsid) archive);
1524 }
1525
1526
1527
1528 static vfs_path_t *
1529 extfs_getlocalcopy (const vfs_path_t *vpath)
1530 {
1531 vfs_file_handler_t *fh;
1532 vfs_path_t *p;
1533
1534 fh = VFS_FILE_HANDLER (extfs_open (vpath, O_RDONLY, 0));
1535 if (fh == NULL)
1536 return NULL;
1537 if (fh->ino->localname == NULL)
1538 {
1539 extfs_close ((void *) fh);
1540 return NULL;
1541 }
1542 p = vfs_path_from_str (fh->ino->localname);
1543 VFS_FILE_HANDLER_SUPER (fh)->fd_usage++;
1544 extfs_close ((void *) fh);
1545 return p;
1546 }
1547
1548
1549
1550 static int
1551 extfs_ungetlocalcopy (const vfs_path_t *vpath, const vfs_path_t *local, gboolean has_changed)
1552 {
1553 vfs_file_handler_t *fh;
1554
1555 fh = VFS_FILE_HANDLER (extfs_open (vpath, O_RDONLY, 0));
1556 if (fh == NULL)
1557 return 0;
1558
1559 if (strcmp (fh->ino->localname, vfs_path_get_last_path_str (local)) == 0)
1560 {
1561 VFS_FILE_HANDLER_SUPER (fh)->fd_usage--;
1562 if (has_changed)
1563 fh->changed = TRUE;
1564 extfs_close ((void *) fh);
1565 return 0;
1566 }
1567 else
1568 {
1569
1570 extfs_close ((void *) fh);
1571 return 0;
1572 }
1573 }
1574
1575
1576
1577 static gboolean
1578 extfs_get_plugins (const char *where, gboolean silent)
1579 {
1580 char *dirname;
1581 GDir *dir;
1582 const char *filename;
1583
1584 dirname = g_build_path (PATH_SEP_STR, where, MC_EXTFS_DIR, (char *) NULL);
1585 dir = g_dir_open (dirname, 0, NULL);
1586
1587
1588
1589
1590 if (dir == NULL)
1591 {
1592 if (!silent)
1593 fprintf (stderr, _ ("Warning: cannot open %s directory\n"), dirname);
1594 g_free (dirname);
1595 return FALSE;
1596 }
1597
1598 if (extfs_plugins == NULL)
1599 extfs_plugins = g_array_sized_new (FALSE, TRUE, sizeof (extfs_plugin_info_t), 32);
1600
1601 while ((filename = g_dir_read_name (dir)) != NULL)
1602 {
1603 char fullname[MC_MAXPATHLEN];
1604 struct stat s;
1605
1606 g_snprintf (fullname, sizeof (fullname), "%s" PATH_SEP_STR "%s", dirname, filename);
1607
1608 if ((stat (fullname, &s) == 0) && S_ISREG (s.st_mode) && !S_ISDIR (s.st_mode)
1609 && is_exe (s.st_mode))
1610 {
1611 int f;
1612
1613 f = open (fullname, O_RDONLY);
1614
1615 if (f >= 0)
1616 {
1617 size_t len, i;
1618 extfs_plugin_info_t info;
1619 gboolean found = FALSE;
1620
1621 close (f);
1622
1623
1624
1625
1626 len = strlen (filename);
1627 info.need_archive = (filename[len - 1] != '+');
1628 info.path = g_strconcat (dirname, PATH_SEP_STR, (char *) NULL);
1629 info.prefix = g_strndup (filename, len);
1630
1631
1632 if (!info.need_archive)
1633 info.prefix[len - 1] = '\0';
1634
1635
1636 for (i = 0; i < extfs_plugins->len && !found; i++)
1637 {
1638 extfs_plugin_info_t *p;
1639
1640 p = &g_array_index (extfs_plugins, extfs_plugin_info_t, i);
1641
1642
1643 found =
1644 strcmp (info.path, p->path) != 0 && strcmp (info.prefix, p->prefix) == 0;
1645 }
1646
1647 if (found)
1648 {
1649 g_free (info.path);
1650 g_free (info.prefix);
1651 }
1652 else
1653 {
1654
1655 if (!info.need_archive)
1656 info.prefix[len - 1] = '+';
1657 g_array_append_val (extfs_plugins, info);
1658 }
1659 }
1660 }
1661 }
1662
1663 g_dir_close (dir);
1664 g_free (dirname);
1665
1666 return TRUE;
1667 }
1668
1669
1670
1671 static int
1672 extfs_init (struct vfs_class *me)
1673 {
1674 gboolean d1, d2;
1675
1676 (void) me;
1677
1678
1679 d1 = extfs_get_plugins (mc_config_get_data_path (), TRUE);
1680
1681 d2 = extfs_get_plugins (LIBEXECDIR, d1);
1682
1683 return (d1 || d2 ? 1 : 0);
1684 }
1685
1686
1687
1688 static void
1689 extfs_done (struct vfs_class *me)
1690 {
1691 size_t i;
1692
1693 while (VFS_SUBCLASS (me)->supers != NULL)
1694 me->free ((vfsid) VFS_SUBCLASS (me)->supers->data);
1695
1696 if (extfs_plugins == NULL)
1697 return;
1698
1699 for (i = 0; i < extfs_plugins->len; i++)
1700 {
1701 extfs_plugin_info_t *info;
1702
1703 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, i);
1704 g_free (info->path);
1705 g_free (info->prefix);
1706 }
1707
1708 g_array_free (extfs_plugins, TRUE);
1709 }
1710
1711
1712
1713 static int
1714 extfs_setctl (const vfs_path_t *vpath, int ctlop, void *arg)
1715 {
1716 (void) arg;
1717
1718 if (ctlop == VFS_SETCTL_RUN)
1719 {
1720 extfs_run (vpath);
1721 return 1;
1722 }
1723 return 0;
1724 }
1725
1726
1727
1728
1729
1730 void
1731 vfs_init_extfs (void)
1732 {
1733 vfs_init_subclass (&extfs_subclass, "extfs", VFSF_UNKNOWN, NULL);
1734 vfs_extfs_ops->init = extfs_init;
1735 vfs_extfs_ops->done = extfs_done;
1736 vfs_extfs_ops->fill_names = extfs_fill_names;
1737 vfs_extfs_ops->which = extfs_which;
1738 vfs_extfs_ops->open = extfs_open;
1739 vfs_extfs_ops->close = extfs_close;
1740 vfs_extfs_ops->read = extfs_read;
1741 vfs_extfs_ops->write = extfs_write;
1742 vfs_extfs_ops->opendir = extfs_opendir;
1743 vfs_extfs_ops->readdir = extfs_readdir;
1744 vfs_extfs_ops->closedir = extfs_closedir;
1745 vfs_extfs_ops->stat = extfs_stat;
1746 vfs_extfs_ops->lstat = extfs_lstat;
1747 vfs_extfs_ops->fstat = extfs_fstat;
1748 vfs_extfs_ops->readlink = extfs_readlink;
1749 vfs_extfs_ops->unlink = extfs_unlink;
1750 vfs_extfs_ops->chdir = extfs_chdir;
1751 vfs_extfs_ops->ferrno = extfs_errno;
1752 vfs_extfs_ops->lseek = extfs_lseek;
1753 vfs_extfs_ops->getid = extfs_getid;
1754 vfs_extfs_ops->getlocalcopy = extfs_getlocalcopy;
1755 vfs_extfs_ops->ungetlocalcopy = extfs_ungetlocalcopy;
1756 vfs_extfs_ops->mkdir = extfs_mkdir;
1757 vfs_extfs_ops->rmdir = extfs_rmdir;
1758 vfs_extfs_ops->setctl = extfs_setctl;
1759 extfs_subclass.free_inode = extfs_free_inode;
1760 extfs_subclass.free_archive = extfs_free_archive;
1761 vfs_register_class (vfs_extfs_ops);
1762 }
1763
1764