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 archive_name = extfs_get_archive_name (archive);
960 quoted_archive_name = name_quote (archive_name, FALSE);
961 g_free (archive_name);
962
963 if (quoted_archive_name == NULL)
964 {
965 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\nwrong archive name"));
966 g_string_free (quoted_file, TRUE);
967 return (-1);
968 }
969
970 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, archive->fstype);
971
972
973 file = extfs_skip_leading_dotslash (quoted_file->str);
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_file, TRUE);
983 g_string_free (quoted_archive_name, TRUE);
984
985 if (localname != NULL && *localname != '\0')
986 {
987 GString *quoted_localname;
988
989 quoted_localname = name_quote (localname, FALSE);
990 g_string_append_c (cmd, ' ');
991 mc_g_string_concat (cmd, quoted_localname);
992 g_string_free (quoted_localname, TRUE);
993 }
994
995
996 pip = mc_popen (cmd->str, FALSE, TRUE, &error);
997 g_string_free (cmd, TRUE);
998
999 if (pip == NULL)
1000 {
1001 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), error->message);
1002 g_error_free (error);
1003 return (-1);
1004 }
1005
1006 pip->err.null_term = TRUE;
1007
1008 mc_pread (pip, &error);
1009 if (error != NULL)
1010 {
1011 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), error->message);
1012 g_error_free (error);
1013 retval = -1;
1014 }
1015 else if (pip->err.len > 0)
1016 message (D_ERROR, MSG_ERROR, _ ("EXTFS virtual file system:\n%s"), pip->err.buf);
1017
1018 mc_pclose (pip, NULL);
1019
1020 return retval;
1021 }
1022
1023
1024
1025 static void
1026 extfs_run (const vfs_path_t *vpath)
1027 {
1028 struct extfs_super_t *archive = NULL;
1029 const char *p;
1030 GString *quoted_name;
1031 char *archive_name;
1032 GString *quoted_archive_name;
1033 GString *cmd;
1034 const extfs_plugin_info_t *info;
1035
1036 p = extfs_get_path (vpath, &archive, FL_NONE);
1037 if (p == NULL)
1038 return;
1039
1040 quoted_name = name_quote (p, FALSE);
1041 archive_name = extfs_get_archive_name (archive);
1042 quoted_archive_name = name_quote (archive_name, FALSE);
1043 g_free (archive_name);
1044
1045 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, archive->fstype);
1046
1047 cmd = g_string_new (info->path);
1048 g_string_append (cmd, info->prefix);
1049 g_string_append (cmd, " run ");
1050 mc_g_string_concat (cmd, quoted_archive_name);
1051 g_string_append_c (cmd, ' ');
1052 mc_g_string_concat (cmd, quoted_name);
1053
1054 g_string_free (quoted_archive_name, TRUE);
1055 g_string_free (quoted_name, TRUE);
1056
1057 shell_execute (cmd->str, 0);
1058
1059 g_string_free (cmd, TRUE);
1060 }
1061
1062
1063
1064 static void *
1065 extfs_open (const vfs_path_t *vpath, int flags, mode_t mode)
1066 {
1067 vfs_file_handler_t *extfs_info;
1068 struct extfs_super_t *archive = NULL;
1069 const char *q;
1070 struct vfs_s_entry *entry;
1071 int local_handle;
1072 gboolean created = FALSE;
1073
1074 q = extfs_get_path (vpath, &archive, FL_NONE);
1075 if (q == NULL)
1076 return NULL;
1077 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1078 if ((entry == NULL) && ((flags & O_CREAT) != 0))
1079 {
1080
1081 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_MKFILE);
1082 created = (entry != NULL);
1083 }
1084
1085 if (entry == NULL)
1086 return NULL;
1087 entry = extfs_resolve_symlinks (entry);
1088 if (entry == NULL)
1089 return NULL;
1090
1091 if (S_ISDIR (entry->ino->st.st_mode))
1092 ERRNOR (EISDIR, NULL);
1093
1094 if (entry->ino->localname == NULL)
1095 {
1096 vfs_path_t *local_filename_vpath;
1097 const char *local_filename;
1098
1099 local_handle = vfs_mkstemps (&local_filename_vpath, "extfs", entry->name);
1100
1101 if (local_handle == -1)
1102 return NULL;
1103 close (local_handle);
1104 local_filename = vfs_path_get_last_path_str (local_filename_vpath);
1105
1106 if (!created && ((flags & O_TRUNC) == 0)
1107 && extfs_cmd (" copyout ", archive, entry, local_filename))
1108 {
1109 unlink (local_filename);
1110 vfs_path_free (local_filename_vpath, TRUE);
1111 my_errno = EIO;
1112 return NULL;
1113 }
1114 entry->ino->localname = g_strdup (local_filename);
1115 vfs_path_free (local_filename_vpath, TRUE);
1116 }
1117
1118 local_handle = open (entry->ino->localname, NO_LINEAR (flags), mode);
1119
1120 if (local_handle == -1)
1121 {
1122
1123 flags = ~O_CREAT & (NO_LINEAR (flags) | O_TRUNC);
1124 local_handle = open (entry->ino->localname, flags, mode);
1125 }
1126
1127 if (local_handle == -1)
1128 ERRNOR (EIO, NULL);
1129
1130 extfs_info = g_new (vfs_file_handler_t, 1);
1131 vfs_s_init_fh (extfs_info, entry->ino, created);
1132 extfs_info->handle = local_handle;
1133
1134
1135 vfs_rmstamp (vfs_extfs_ops, (vfsid) archive);
1136 VFS_SUPER (archive)->fd_usage++;
1137 return extfs_info;
1138 }
1139
1140
1141
1142 static ssize_t
1143 extfs_read (void *fh, char *buffer, size_t count)
1144 {
1145 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1146
1147 return read (file->handle, buffer, count);
1148 }
1149
1150
1151
1152 static int
1153 extfs_close (void *fh)
1154 {
1155 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1156 int errno_code = 0;
1157
1158 close (file->handle);
1159 file->handle = -1;
1160
1161
1162 if (file->changed)
1163 {
1164 struct stat file_status;
1165
1166 if (extfs_cmd (" copyin ", EXTFS_SUPER (VFS_FILE_HANDLER_SUPER (fh)), file->ino->ent,
1167 file->ino->localname))
1168 errno_code = EIO;
1169
1170 if (stat (file->ino->localname, &file_status) != 0)
1171 errno_code = EIO;
1172 else
1173 file->ino->st.st_size = file_status.st_size;
1174
1175 file->ino->st.st_mtime = time (NULL);
1176 }
1177
1178 if (--VFS_FILE_HANDLER_SUPER (fh)->fd_usage == 0)
1179 vfs_stamp_create (vfs_extfs_ops, VFS_FILE_HANDLER_SUPER (fh));
1180
1181 g_free (fh);
1182 if (errno_code != 0)
1183 ERRNOR (EIO, -1);
1184 return 0;
1185 }
1186
1187
1188
1189 static int
1190 extfs_errno (struct vfs_class *me)
1191 {
1192 (void) me;
1193 return my_errno;
1194 }
1195
1196
1197
1198 static void *
1199 extfs_opendir (const vfs_path_t *vpath)
1200 {
1201 struct extfs_super_t *archive = NULL;
1202 const char *q;
1203 struct vfs_s_entry *entry;
1204 GList **info;
1205
1206 q = extfs_get_path (vpath, &archive, FL_NONE);
1207 if (q == NULL)
1208 return NULL;
1209 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1210 if (entry == NULL)
1211 return NULL;
1212 entry = extfs_resolve_symlinks (entry);
1213 if (entry == NULL)
1214 return NULL;
1215 if (!S_ISDIR (entry->ino->st.st_mode))
1216 ERRNOR (ENOTDIR, NULL);
1217
1218 info = g_new (GList *, 1);
1219 *info = g_queue_peek_head_link (entry->ino->subdir);
1220
1221 return info;
1222 }
1223
1224
1225
1226 static struct vfs_dirent *
1227 extfs_readdir (void *data)
1228 {
1229 struct vfs_dirent *dir;
1230 GList **info = (GList **) data;
1231
1232 if (*info == NULL)
1233 return NULL;
1234
1235 dir = vfs_dirent_init (NULL, VFS_ENTRY ((*info)->data)->name, 0, DT_UNKNOWN);
1236
1237 *info = g_list_next (*info);
1238
1239 return dir;
1240 }
1241
1242
1243
1244 static int
1245 extfs_closedir (void *data)
1246 {
1247 g_free (data);
1248 return 0;
1249 }
1250
1251
1252
1253 static void
1254 extfs_stat_move (struct stat *buf, const struct vfs_s_inode *inode)
1255 {
1256 const time_t atime = inode->st.st_atime;
1257 const time_t mtime = inode->st.st_mtime;
1258 const time_t ctime = inode->st.st_ctime;
1259
1260 *buf = inode->st;
1261
1262 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1263 buf->st_blksize = RECORDSIZE;
1264 #endif
1265
1266 vfs_adjust_stat (buf);
1267 vfs_zero_stat_times (buf);
1268
1269 buf->st_atime = atime;
1270 buf->st_mtime = mtime;
1271 buf->st_ctime = ctime;
1272 }
1273
1274
1275
1276 static int
1277 extfs_internal_stat (const vfs_path_t *vpath, struct stat *buf, gboolean resolve)
1278 {
1279 struct extfs_super_t *archive;
1280 const char *q;
1281 struct vfs_s_entry *entry;
1282 int result = -1;
1283
1284 q = extfs_get_path (vpath, &archive, FL_NONE);
1285 if (q == NULL)
1286 goto cleanup;
1287 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1288 if (entry == NULL)
1289 goto cleanup;
1290 if (resolve)
1291 {
1292 entry = extfs_resolve_symlinks (entry);
1293 if (entry == NULL)
1294 goto cleanup;
1295 }
1296 extfs_stat_move (buf, entry->ino);
1297 result = 0;
1298 cleanup:
1299 return result;
1300 }
1301
1302
1303
1304 static int
1305 extfs_stat (const vfs_path_t *vpath, struct stat *buf)
1306 {
1307 return extfs_internal_stat (vpath, buf, TRUE);
1308 }
1309
1310
1311
1312 static int
1313 extfs_lstat (const vfs_path_t *vpath, struct stat *buf)
1314 {
1315 return extfs_internal_stat (vpath, buf, FALSE);
1316 }
1317
1318
1319
1320 static int
1321 extfs_fstat (void *fh, struct stat *buf)
1322 {
1323 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1324
1325 extfs_stat_move (buf, file->ino);
1326 return 0;
1327 }
1328
1329
1330
1331 static int
1332 extfs_readlink (const vfs_path_t *vpath, char *buf, size_t size)
1333 {
1334 struct extfs_super_t *archive;
1335 const char *q;
1336 size_t len;
1337 struct vfs_s_entry *entry;
1338 int result = -1;
1339
1340 q = extfs_get_path (vpath, &archive, FL_NONE);
1341 if (q == NULL)
1342 goto cleanup;
1343 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1344 if (entry == NULL)
1345 goto cleanup;
1346 if (!S_ISLNK (entry->ino->st.st_mode))
1347 {
1348 VFS_CLASS (vfs_path_get_last_path_vfs (vpath))->verrno = EINVAL;
1349 goto cleanup;
1350 }
1351 len = strlen (entry->ino->linkname);
1352 if (size < len)
1353 len = size;
1354
1355 result = len;
1356 memcpy (buf, entry->ino->linkname, result);
1357 cleanup:
1358 return result;
1359 }
1360
1361
1362
1363 static ssize_t
1364 extfs_write (void *fh, const char *buf, size_t nbyte)
1365 {
1366 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1367
1368 file->changed = TRUE;
1369 return write (file->handle, buf, nbyte);
1370 }
1371
1372
1373
1374 static int
1375 extfs_unlink (const vfs_path_t *vpath)
1376 {
1377 struct extfs_super_t *archive;
1378 const char *q;
1379 struct vfs_s_entry *entry;
1380 int result = -1;
1381
1382 q = extfs_get_path (vpath, &archive, FL_NONE);
1383 if (q == NULL)
1384 goto cleanup;
1385 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1386 if (entry == NULL)
1387 goto cleanup;
1388 entry = extfs_resolve_symlinks (entry);
1389 if (entry == NULL)
1390 goto cleanup;
1391 if (S_ISDIR (entry->ino->st.st_mode))
1392 {
1393 VFS_CLASS (vfs_path_get_last_path_vfs (vpath))->verrno = EISDIR;
1394 goto cleanup;
1395 }
1396 if (extfs_cmd (" rm ", archive, entry, ""))
1397 {
1398 my_errno = EIO;
1399 goto cleanup;
1400 }
1401 vfs_s_free_entry (VFS_SUPER (archive)->me, entry);
1402 result = 0;
1403 cleanup:
1404 return result;
1405 }
1406
1407
1408
1409 static int
1410 extfs_mkdir (const vfs_path_t *vpath, mode_t mode)
1411 {
1412 struct extfs_super_t *archive;
1413 const char *q;
1414 struct vfs_s_entry *entry;
1415 int result = -1;
1416 struct vfs_class *me;
1417
1418 (void) mode;
1419
1420 me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
1421 q = extfs_get_path (vpath, &archive, FL_NONE);
1422 if (q == NULL)
1423 goto cleanup;
1424 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1425 if (entry != NULL)
1426 {
1427 me->verrno = EEXIST;
1428 goto cleanup;
1429 }
1430 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_MKDIR);
1431 if (entry == NULL)
1432 goto cleanup;
1433 entry = extfs_resolve_symlinks (entry);
1434 if (entry == NULL)
1435 goto cleanup;
1436 if (!S_ISDIR (entry->ino->st.st_mode))
1437 {
1438 me->verrno = ENOTDIR;
1439 goto cleanup;
1440 }
1441
1442 if (extfs_cmd (" mkdir ", archive, entry, ""))
1443 {
1444 my_errno = EIO;
1445 vfs_s_free_entry (VFS_SUPER (archive)->me, entry);
1446 goto cleanup;
1447 }
1448 result = 0;
1449 cleanup:
1450 return result;
1451 }
1452
1453
1454
1455 static int
1456 extfs_rmdir (const vfs_path_t *vpath)
1457 {
1458 struct extfs_super_t *archive;
1459 const char *q;
1460 struct vfs_s_entry *entry;
1461 int result = -1;
1462
1463 q = extfs_get_path (vpath, &archive, FL_NONE);
1464 if (q == NULL)
1465 goto cleanup;
1466 entry = extfs_find_entry (VFS_SUPER (archive)->root, q, FL_NONE);
1467 if (entry == NULL)
1468 goto cleanup;
1469 entry = extfs_resolve_symlinks (entry);
1470 if (entry == NULL)
1471 goto cleanup;
1472 if (!S_ISDIR (entry->ino->st.st_mode))
1473 {
1474 VFS_CLASS (vfs_path_get_last_path_vfs (vpath))->verrno = ENOTDIR;
1475 goto cleanup;
1476 }
1477
1478 if (extfs_cmd (" rmdir ", archive, entry, ""))
1479 {
1480 my_errno = EIO;
1481 goto cleanup;
1482 }
1483 vfs_s_free_entry (VFS_SUPER (archive)->me, entry);
1484 result = 0;
1485 cleanup:
1486 return result;
1487 }
1488
1489
1490
1491 static int
1492 extfs_chdir (const vfs_path_t *vpath)
1493 {
1494 void *data;
1495
1496 my_errno = ENOTDIR;
1497 data = extfs_opendir (vpath);
1498 if (data == NULL)
1499 return (-1);
1500 extfs_closedir (data);
1501 my_errno = 0;
1502 return 0;
1503 }
1504
1505
1506
1507 static off_t
1508 extfs_lseek (void *fh, off_t offset, int whence)
1509 {
1510 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1511
1512 return lseek (file->handle, offset, whence);
1513 }
1514
1515
1516
1517 static vfsid
1518 extfs_getid (const vfs_path_t *vpath)
1519 {
1520 struct extfs_super_t *archive = NULL;
1521 const char *p;
1522
1523 p = extfs_get_path (vpath, &archive, FL_NO_OPEN);
1524 return (p == NULL ? NULL : (vfsid) archive);
1525 }
1526
1527
1528
1529 static vfs_path_t *
1530 extfs_getlocalcopy (const vfs_path_t *vpath)
1531 {
1532 vfs_file_handler_t *fh;
1533 vfs_path_t *p;
1534
1535 fh = VFS_FILE_HANDLER (extfs_open (vpath, O_RDONLY, 0));
1536 if (fh == NULL)
1537 return NULL;
1538 if (fh->ino->localname == NULL)
1539 {
1540 extfs_close ((void *) fh);
1541 return NULL;
1542 }
1543 p = vfs_path_from_str (fh->ino->localname);
1544 VFS_FILE_HANDLER_SUPER (fh)->fd_usage++;
1545 extfs_close ((void *) fh);
1546 return p;
1547 }
1548
1549
1550
1551 static int
1552 extfs_ungetlocalcopy (const vfs_path_t *vpath, const vfs_path_t *local, gboolean has_changed)
1553 {
1554 vfs_file_handler_t *fh;
1555
1556 fh = VFS_FILE_HANDLER (extfs_open (vpath, O_RDONLY, 0));
1557 if (fh == NULL)
1558 return 0;
1559
1560 if (strcmp (fh->ino->localname, vfs_path_get_last_path_str (local)) == 0)
1561 {
1562 VFS_FILE_HANDLER_SUPER (fh)->fd_usage--;
1563 if (has_changed)
1564 fh->changed = TRUE;
1565 extfs_close ((void *) fh);
1566 return 0;
1567 }
1568 else
1569 {
1570
1571 extfs_close ((void *) fh);
1572 return 0;
1573 }
1574 }
1575
1576
1577
1578 static gboolean
1579 extfs_get_plugins (const char *where, gboolean silent)
1580 {
1581 char *dirname;
1582 GDir *dir;
1583 const char *filename;
1584
1585 dirname = g_build_path (PATH_SEP_STR, where, MC_EXTFS_DIR, (char *) NULL);
1586 dir = g_dir_open (dirname, 0, NULL);
1587
1588
1589
1590
1591 if (dir == NULL)
1592 {
1593 if (!silent)
1594 fprintf (stderr, _ ("Warning: cannot open %s directory\n"), dirname);
1595 g_free (dirname);
1596 return FALSE;
1597 }
1598
1599 if (extfs_plugins == NULL)
1600 extfs_plugins = g_array_sized_new (FALSE, TRUE, sizeof (extfs_plugin_info_t), 32);
1601
1602 while ((filename = g_dir_read_name (dir)) != NULL)
1603 {
1604 char fullname[MC_MAXPATHLEN];
1605 struct stat s;
1606
1607 g_snprintf (fullname, sizeof (fullname), "%s" PATH_SEP_STR "%s", dirname, filename);
1608
1609 if ((stat (fullname, &s) == 0) && S_ISREG (s.st_mode) && !S_ISDIR (s.st_mode)
1610 && is_exe (s.st_mode))
1611 {
1612 int f;
1613
1614 f = open (fullname, O_RDONLY);
1615
1616 if (f >= 0)
1617 {
1618 size_t len, i;
1619 extfs_plugin_info_t info;
1620 gboolean found = FALSE;
1621
1622 close (f);
1623
1624
1625
1626
1627 len = strlen (filename);
1628 info.need_archive = (filename[len - 1] != '+');
1629 info.path = g_strconcat (dirname, PATH_SEP_STR, (char *) NULL);
1630 info.prefix = g_strndup (filename, len);
1631
1632
1633 if (!info.need_archive)
1634 info.prefix[len - 1] = '\0';
1635
1636
1637 for (i = 0; i < extfs_plugins->len && !found; i++)
1638 {
1639 extfs_plugin_info_t *p;
1640
1641 p = &g_array_index (extfs_plugins, extfs_plugin_info_t, i);
1642
1643
1644 found =
1645 strcmp (info.path, p->path) != 0 && strcmp (info.prefix, p->prefix) == 0;
1646 }
1647
1648 if (found)
1649 {
1650 g_free (info.path);
1651 g_free (info.prefix);
1652 }
1653 else
1654 {
1655
1656 if (!info.need_archive)
1657 info.prefix[len - 1] = '+';
1658 g_array_append_val (extfs_plugins, info);
1659 }
1660 }
1661 }
1662 }
1663
1664 g_dir_close (dir);
1665 g_free (dirname);
1666
1667 return TRUE;
1668 }
1669
1670
1671
1672 static int
1673 extfs_init (struct vfs_class *me)
1674 {
1675 gboolean d1, d2;
1676
1677 (void) me;
1678
1679
1680 d1 = extfs_get_plugins (mc_config_get_data_path (), TRUE);
1681
1682 d2 = extfs_get_plugins (LIBEXECDIR, d1);
1683
1684 return (d1 || d2 ? 1 : 0);
1685 }
1686
1687
1688
1689 static void
1690 extfs_done (struct vfs_class *me)
1691 {
1692 size_t i;
1693
1694 while (VFS_SUBCLASS (me)->supers != NULL)
1695 me->free ((vfsid) VFS_SUBCLASS (me)->supers->data);
1696
1697 if (extfs_plugins == NULL)
1698 return;
1699
1700 for (i = 0; i < extfs_plugins->len; i++)
1701 {
1702 extfs_plugin_info_t *info;
1703
1704 info = &g_array_index (extfs_plugins, extfs_plugin_info_t, i);
1705 g_free (info->path);
1706 g_free (info->prefix);
1707 }
1708
1709 g_array_free (extfs_plugins, TRUE);
1710 }
1711
1712
1713
1714 static int
1715 extfs_setctl (const vfs_path_t *vpath, int ctlop, void *arg)
1716 {
1717 (void) arg;
1718
1719 if (ctlop == VFS_SETCTL_RUN)
1720 {
1721 extfs_run (vpath);
1722 return 1;
1723 }
1724 return 0;
1725 }
1726
1727
1728
1729
1730
1731 void
1732 vfs_init_extfs (void)
1733 {
1734 vfs_init_subclass (&extfs_subclass, "extfs", VFSF_UNKNOWN, NULL);
1735 vfs_extfs_ops->init = extfs_init;
1736 vfs_extfs_ops->done = extfs_done;
1737 vfs_extfs_ops->fill_names = extfs_fill_names;
1738 vfs_extfs_ops->which = extfs_which;
1739 vfs_extfs_ops->open = extfs_open;
1740 vfs_extfs_ops->close = extfs_close;
1741 vfs_extfs_ops->read = extfs_read;
1742 vfs_extfs_ops->write = extfs_write;
1743 vfs_extfs_ops->opendir = extfs_opendir;
1744 vfs_extfs_ops->readdir = extfs_readdir;
1745 vfs_extfs_ops->closedir = extfs_closedir;
1746 vfs_extfs_ops->stat = extfs_stat;
1747 vfs_extfs_ops->lstat = extfs_lstat;
1748 vfs_extfs_ops->fstat = extfs_fstat;
1749 vfs_extfs_ops->readlink = extfs_readlink;
1750 vfs_extfs_ops->unlink = extfs_unlink;
1751 vfs_extfs_ops->chdir = extfs_chdir;
1752 vfs_extfs_ops->ferrno = extfs_errno;
1753 vfs_extfs_ops->lseek = extfs_lseek;
1754 vfs_extfs_ops->getid = extfs_getid;
1755 vfs_extfs_ops->getlocalcopy = extfs_getlocalcopy;
1756 vfs_extfs_ops->ungetlocalcopy = extfs_ungetlocalcopy;
1757 vfs_extfs_ops->mkdir = extfs_mkdir;
1758 vfs_extfs_ops->rmdir = extfs_rmdir;
1759 vfs_extfs_ops->setctl = extfs_setctl;
1760 extfs_subclass.free_inode = extfs_free_inode;
1761 extfs_subclass.free_archive = extfs_free_archive;
1762 vfs_register_class (vfs_extfs_ops);
1763 }
1764
1765