1 /* Virtual File System: External file system.
2 Copyright (C) 1995 The Free Software Foundation
4 Written by: 1995 Jakub Jelinek
5 Rewritten by: 1998 Pavel Machek
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License
9 as published by the Free Software Foundation; either version 2 of
10 the License, or (at your option) any later version.
12 This program 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
15 GNU Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* Namespace: exports only vfs_extfs_ops */
28 #include <sys/types.h>
33 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/timeb.h> /* alex: for struct timeb definition */
39 #endif /* SCO_FLAVOR */
42 #include "../src/dialog.h"
43 #include "../src/main.h" /* For shell_execute */
47 #define ERRNOR(x,y) do { my_errno = x; return y; } while(0)
50 find_entry (struct entry
*dir
, char *name
, int make_dirs
, int make_file
);
51 static int extfs_which (vfs
*me
, char *path
);
53 static struct archive
*first_archive
= NULL
;
54 static int my_errno
= 0;
55 static struct stat hstat
; /* Stat struct corresponding */
58 static char *extfs_prefixes
[MAXEXTFS
];
59 static char extfs_need_archive
[MAXEXTFS
];
60 static int extfs_no
= 0;
62 static void extfs_fill_names (vfs
*me
, void (*func
)(char *))
64 struct archive
*a
= first_archive
;
68 name
= g_strconcat (extfs_prefixes
[a
->fstype
], "#",
69 (a
->name
? a
->name
: ""), "/",
70 a
->current_dir
->name
, NULL
);
77 static void make_dot_doubledot (struct entry
*ent
)
79 struct entry
*entry
= g_new (struct entry
, 1);
80 struct entry
*parentry
= ent
->dir
;
81 struct inode
*inode
= ent
->inode
, *parent
;
83 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
84 entry
->name
= g_strdup (".");
85 entry
->has_changed
= 0;
88 inode
->local_filename
= NULL
;
89 inode
->first_in_subdir
= entry
;
90 inode
->last_in_subdir
= entry
;
92 entry
->next_in_dir
= g_new (struct entry
, 1);
93 entry
=entry
->next_in_dir
;
94 entry
->name
= g_strdup ("..");
95 entry
->has_changed
= 0;
96 inode
->last_in_subdir
= entry
;
97 entry
->next_in_dir
= NULL
;
99 entry
->inode
= parent
;
100 entry
->dir
= parentry
;
103 entry
->inode
= inode
;
109 static struct entry
*generate_entry (struct archive
*archive
,
110 char *name
, struct entry
*parentry
, mode_t mode
)
113 struct inode
*inode
, *parent
;
116 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
117 entry
= g_new (struct entry
, 1);
119 entry
->name
= g_strdup (name
);
120 entry
->has_changed
= 0;
121 entry
->next_in_dir
= NULL
;
122 entry
->dir
= parentry
;
123 if (parent
!= NULL
) {
124 parent
->last_in_subdir
->next_in_dir
= entry
;
125 parent
->last_in_subdir
= entry
;
127 inode
= g_new (struct inode
, 1);
128 entry
->inode
= inode
;
129 inode
->has_changed
= 0;
130 inode
->local_filename
= NULL
;
132 inode
->inode
= (archive
->__inode_counter
)++;
133 inode
->dev
= archive
->rdev
;
134 inode
->archive
= archive
;
135 myumask
= umask (022);
137 inode
->mode
= mode
& ~myumask
;
140 inode
->uid
= getuid ();
141 inode
->gid
= getgid ();
143 inode
->mtime
= time (NULL
);
144 inode
->atime
= inode
->mtime
;
145 inode
->ctime
= inode
->mtime
;
148 make_dot_doubledot (entry
);
152 static void free_entries (struct entry
*entry
)
157 static void free_archive (struct archive
*archive
)
159 free_entries (archive
->root_entry
);
160 if (archive
->local_name
!= NULL
) {
163 mc_stat (archive
->local_name
, &my
);
164 mc_ungetlocalcopy (archive
->name
, archive
->local_name
,
165 archive
->local_stat
.st_mtime
!= my
.st_mtime
);
166 /* ungetlocalcopy frees local_name for us */
169 g_free (archive
->name
);
173 static FILE *open_archive (int fstype
, char *name
, struct archive
**pparc
)
175 static dev_t __extfs_no
= 0;
181 struct archive
*current_archive
;
182 struct entry
*root_entry
;
183 char *local_name
= NULL
, *tmp
= 0;
184 int uses_archive
= extfs_need_archive
[fstype
];
187 if (mc_stat (name
, &mystat
) == -1)
189 if (!vfs_file_is_local (name
)) {
190 local_name
= mc_getlocalcopy (name
);
191 if (local_name
== NULL
)
194 tmp
= name_quote (name
, 0);
198 /* Sorry, what is this good for? */
199 if (uses_archive
== EFS_NEED_ARG
){
200 tmp
= name_quote (name
, 0);
204 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
205 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[fstype
],
206 " list ", local_name
? local_name
: tmp
, NULL
);
209 result
= popen (cmd
, "r");
211 g_free (mc_extfsdir
);
212 if (result
== NULL
) {
213 if (local_name
!= NULL
&& uses_archive
)
214 mc_ungetlocalcopy (name
, local_name
, 0);
218 current_archive
= g_new (struct archive
, 1);
219 current_archive
->fstype
= fstype
;
220 current_archive
->name
= name
? g_strdup (name
): name
;
221 current_archive
->local_name
= local_name
;
223 if (local_name
!= NULL
)
224 mc_stat (local_name
, ¤t_archive
->local_stat
);
225 current_archive
->__inode_counter
= 0;
226 current_archive
->fd_usage
= 0;
227 current_archive
->extfsstat
= mystat
;
228 current_archive
->rdev
= __extfs_no
++;
229 current_archive
->next
= first_archive
;
230 first_archive
= current_archive
;
231 mode
= current_archive
->extfsstat
.st_mode
& 07777;
239 root_entry
= generate_entry (current_archive
, "/", NULL
, mode
);
240 root_entry
->inode
->uid
= current_archive
->extfsstat
.st_uid
;
241 root_entry
->inode
->gid
= current_archive
->extfsstat
.st_gid
;
242 root_entry
->inode
->atime
= current_archive
->extfsstat
.st_atime
;
243 root_entry
->inode
->ctime
= current_archive
->extfsstat
.st_ctime
;
244 root_entry
->inode
->mtime
= current_archive
->extfsstat
.st_mtime
;
245 current_archive
->root_entry
= root_entry
;
246 current_archive
->current_dir
= root_entry
;
248 *pparc
= current_archive
;
254 * Main loop for reading an archive.
255 * Returns 0 on success, -1 on error.
257 static int read_archive (int fstype
, char *name
, struct archive
**pparc
)
261 struct archive
*current_archive
;
262 char *current_file_name
, *current_link_name
;
265 if ((extfsd
= open_archive (fstype
, name
, ¤t_archive
)) == NULL
) {
266 message_3s (1, MSG_ERROR
, _("Couldn't open %s archive\n%s"),
267 extfs_prefixes
[fstype
], name
);
271 buffer
= g_malloc (4096);
272 while (fgets (buffer
, 4096, extfsd
) != NULL
) {
273 current_link_name
= NULL
;
274 if (vfs_parse_ls_lga (buffer
, &hstat
, ¤t_file_name
, ¤t_link_name
)) {
275 struct entry
*entry
, *pent
;
277 char *p
, *q
, *cfn
= current_file_name
;
283 if (p
!= NULL
&& p
!= cfn
&& *(p
- 1) == '/')
285 p
= strrchr (cfn
, '/');
293 if (S_ISDIR (hstat
.st_mode
) &&
294 (!strcmp (p
, ".") || !strcmp (p
, "..")))
295 goto read_extfs_continue
;
296 pent
= find_entry (current_archive
->root_entry
, q
, 1, 0) ;
298 message_1s (1, MSG_ERROR
, _("Inconsistent extfs archive"));
299 /* FIXME: Should clean everything one day */
304 entry
= g_new (struct entry
, 1);
305 entry
->name
= g_strdup (p
);
306 entry
->has_changed
= 0;
307 entry
->next_in_dir
= NULL
;
310 if (pent
->inode
->last_in_subdir
){
311 pent
->inode
->last_in_subdir
->next_in_dir
= entry
;
312 pent
->inode
->last_in_subdir
= entry
;
315 if (!S_ISLNK (hstat
.st_mode
) && current_link_name
!= NULL
) {
316 pent
= find_entry (current_archive
->root_entry
, current_link_name
, 0, 0);
318 message_1s (1, MSG_ERROR
, _("Inconsistent extfs archive"));
319 /* FIXME: Should clean everything one day */
324 entry
->inode
= pent
->inode
;
325 pent
->inode
->nlink
++;
328 inode
= g_new (struct inode
, 1);
329 entry
->inode
= inode
;
330 inode
->local_filename
= NULL
;
331 inode
->has_changed
= 0;
332 inode
->inode
= (current_archive
->__inode_counter
)++;
334 inode
->dev
= current_archive
->rdev
;
335 inode
->archive
= current_archive
;
336 inode
->mode
= hstat
.st_mode
;
338 inode
->rdev
= hstat
.st_rdev
;
342 inode
->uid
= hstat
.st_uid
;
343 inode
->gid
= hstat
.st_gid
;
344 inode
->size
= hstat
.st_size
;
345 inode
->mtime
= hstat
.st_mtime
;
346 inode
->atime
= hstat
.st_atime
;
347 inode
->ctime
= hstat
.st_ctime
;
348 if (current_link_name
!= NULL
&& S_ISLNK (hstat
.st_mode
)) {
349 inode
->linkname
= current_link_name
;
350 current_link_name
= NULL
;
352 if (S_ISLNK( hstat
.st_mode
))
353 inode
->mode
&= ~S_IFLNK
; /* You *DON'T* want to do this always */
354 inode
->linkname
= NULL
;
356 if (S_ISDIR (hstat
.st_mode
))
357 make_dot_doubledot (entry
);
361 g_free (current_file_name
);
362 if (current_link_name
!= NULL
)
363 g_free (current_link_name
);
368 waitpid(-1,NULL
,WNOHANG
);
369 #endif /* SCO_FLAVOR */
370 *pparc
= current_archive
;
375 static char *get_path (char *inname
, struct archive
**archive
, int is_dir
,
378 /* Returns path inside argument. Returned char* is inside inname, which is mangled
379 * by this operation (so you must not free it's return value)
381 static char *get_path_mangle (char *inname
, struct archive
**archive
, int is_dir
,
384 char *local
, *archive_name
, *op
;
386 struct archive
*parc
;
387 struct vfs_stamping
*parent
;
391 archive_name
= inname
;
392 vfs_split( inname
, &local
, &op
);
393 fstype
= extfs_which( NULL
, op
); /* FIXME: we really should pass
394 self pointer. But as we know that extfs_which does not touch vfs
395 *me, it does not matter for now */
401 /* All filesystems should have some local archive, at least
404 * Actually, we should implement an alias mechanism that would
405 * translate: "a:" to "dos:a.
408 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
410 if (!strcmp (parc
->name
, archive_name
)) {
411 struct stat
*s
=&(parc
->extfsstat
);
412 if (vfs_uid
&& (!(s
->st_mode
& 0004)))
413 if ((s
->st_gid
!= vfs_gid
) || !(s
->st_mode
& 0040))
414 if ((s
->st_uid
!= vfs_uid
) || !(s
->st_mode
& 0400))
416 /* This is not too secure - in some cases (/#mtools) files created
417 under user a are probably visible to everyone else since / usually
418 has permissions 755 */
419 vfs_stamp (&vfs_extfs_ops
, (vfsid
) parc
);
424 result
= do_not_open
? -1 : read_archive (fstype
, archive_name
, &parc
);
425 if (result
== -1) ERRNOR (EIO
, NULL
);
428 v
= vfs_type (archive_name
);
429 if (v
== &vfs_local_ops
) {
432 parent
= g_new (struct vfs_stamping
, 1);
435 parent
->id
= (*v
->getid
) (v
, archive_name
, &(parent
->parent
));
437 vfs_add_noncurrent_stamps (&vfs_extfs_ops
, (vfsid
) parc
, parent
);
438 vfs_rm_parents (parent
);
445 /* Returns allocated path (without leading slash) inside the archive */
446 static char *get_path_from_entry (struct entry
*entry
)
455 for (len
= 0, head
= 0; entry
->dir
; entry
= entry
->dir
) {
456 p
= g_new (struct list
, 1);
458 p
->name
= entry
->name
;
460 len
+= strlen (entry
->name
) + 1;
463 localpath
= g_malloc (len
);
466 strcat (localpath
, head
->name
);
468 strcat (localpath
, "/");
477 struct loop_protect
{
479 struct loop_protect
*next
;
484 static struct entry
*
485 __find_entry (struct entry
*dir
, char *name
,
486 struct loop_protect
*list
, int make_dirs
, int make_file
);
488 static struct entry
*
489 __resolve_symlinks (struct entry
*entry
,
490 struct loop_protect
*list
)
493 struct loop_protect
*looping
;
495 if (!S_ISLNK (entry
->inode
->mode
))
497 for (looping
= list
; looping
!= NULL
; looping
= looping
->next
)
498 if (entry
== looping
->entry
) { /* Here we protect us against symlink looping */
502 looping
= g_new (struct loop_protect
, 1);
503 looping
->entry
= entry
;
504 looping
->next
= list
;
505 pent
= __find_entry (entry
->dir
, entry
->inode
->linkname
, looping
, 0, 0);
512 static struct entry
*my_resolve_symlinks (struct entry
*entry
)
518 res
= __resolve_symlinks (entry
, NULL
);
529 struct archive
*archive
;
530 unsigned int has_changed
:1;
535 static char *get_archive_name (struct archive
*archive
)
539 if (archive
->local_name
)
540 archive_name
= archive
->local_name
;
542 archive_name
= archive
->name
;
544 if (!archive_name
|| !*archive_name
)
545 return "no_archive_name";
550 /* FIXME: we really should not have non-static procedures - it
551 * pollutes namespace. */
553 void extfs_run (char *file
)
555 struct archive
*archive
;
556 char *p
, *q
, *archive_name
, *mc_extfsdir
;
559 if ((p
= get_path (file
, &archive
, 0, 0)) == NULL
)
561 q
= name_quote (p
, 0);
563 archive_name
= name_quote (get_archive_name(archive
), 0);
564 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
565 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
566 " run ", archive_name
, " ", q
, NULL
);
567 g_free (mc_extfsdir
);
568 g_free (archive_name
);
570 #ifndef VFS_STANDALONE
571 shell_execute(cmd
, 0);
573 vfs_die( "shell_execute: implement me!" );
579 static void *extfs_open (vfs
*me
, char *file
, int flags
, int mode
)
581 struct pseudofile
*extfs_info
;
582 struct archive
*archive
;
587 const int do_create
= (flags
& O_ACCMODE
) != O_RDONLY
;
589 if ((q
= get_path_mangle (file
, &archive
, 0, 0)) == NULL
)
591 entry
= find_entry (archive
->root_entry
, q
, 0, do_create
);
594 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
596 if (S_ISDIR (entry
->inode
->mode
)) ERRNOR (EISDIR
, NULL
);
597 if (entry
->inode
->local_filename
== NULL
) {
599 char *archive_name
, *p
;
601 entry
->inode
->local_filename
= g_strdup (tempnam (NULL
, "extfs"));
605 handle
= open(entry
->inode
->local_filename
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
610 p
= get_path_from_entry (entry
);
611 q
= name_quote (p
, 0);
613 archive_name
= name_quote (get_archive_name (archive
), 0);
615 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
616 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
619 " ", q
, " ", entry
->inode
->local_filename
, NULL
);
621 g_free (mc_extfsdir
);
622 g_free (archive_name
);
623 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
) && !do_create
){
624 g_free (entry
->inode
->local_filename
);
625 entry
->inode
->local_filename
= NULL
;
633 local_handle
= open (entry
->inode
->local_filename
, flags
, mode
);
634 if (local_handle
== -1) ERRNOR (EIO
, NULL
);
636 extfs_info
= g_new (struct pseudofile
, 1);
637 extfs_info
->archive
= archive
;
638 extfs_info
->entry
= entry
;
639 extfs_info
->has_changed
= 0;
640 extfs_info
->local_handle
= local_handle
;
642 /* i.e. we had no open files and now we have one */
643 vfs_rmstamp (&vfs_extfs_ops
, (vfsid
) archive
, 1);
648 static int extfs_read (void *data
, char *buffer
, int count
)
650 struct pseudofile
*file
= (struct pseudofile
*)data
;
652 return read (file
->local_handle
, buffer
, count
);
655 static int extfs_close (void *data
)
657 struct pseudofile
*file
;
659 file
= (struct pseudofile
*)data
;
661 close (file
->local_handle
);
663 /* Commit the file if it has changed */
664 if (file
->has_changed
){
665 struct archive
*archive
;
666 char *archive_name
, *file_name
;
671 archive
= file
->archive
;
672 archive_name
= name_quote (get_archive_name (archive
), 0);
673 p
= get_path_from_entry (file
->entry
);
674 file_name
= name_quote (p
, 0);
677 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
678 cmd
= g_strconcat (mc_extfsdir
,
679 extfs_prefixes
[archive
->fstype
],
680 " copyin ", archive_name
, " ",
682 file
->entry
->inode
->local_filename
, NULL
);
683 g_free (archive_name
);
685 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
))
688 g_free (mc_extfsdir
);
690 struct stat file_status
;
691 if( stat(file
->entry
->inode
->local_filename
,&file_status
) != 0 )
693 else file
->entry
->inode
->size
= file_status
.st_size
;
696 file
->entry
->inode
->mtime
= time (NULL
);
699 file
->archive
->fd_usage
--;
700 if (!file
->archive
->fd_usage
) {
701 struct vfs_stamping
*parent
;
704 if (!file
->archive
->name
|| !*file
->archive
->name
|| (v
= vfs_type (file
->archive
->name
)) == &vfs_local_ops
) {
707 parent
= g_new (struct vfs_stamping
, 1);
710 parent
->id
= (*v
->getid
) (v
, file
->archive
->name
, &(parent
->parent
));
712 vfs_add_noncurrent_stamps (&vfs_extfs_ops
, (vfsid
) (file
->archive
), parent
);
713 vfs_rm_parents (parent
);
717 if (errno_code
) ERRNOR (EIO
, -1);
721 #define RECORDSIZE 512
722 #include "shared_tar_ext.c"
724 static int extfs_chmod (vfs
*me
, char *path
, int mode
)
729 static int extfs_write (void *data
, char *buf
, int nbyte
)
731 struct pseudofile
*file
= (struct pseudofile
*)data
;
733 file
->has_changed
= 1;
734 return write (file
->local_handle
, buf
, nbyte
);
737 static int extfs_chdir (vfs
*me
, char *path
)
739 struct archive
*archive
;
744 if ((q
= get_path_mangle (path
, &archive
, 1, 0)) == NULL
)
746 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
749 entry
= my_resolve_symlinks (entry
);
750 if ((!entry
) || (!S_ISDIR (entry
->inode
->mode
)))
752 entry
->inode
->archive
->current_dir
= entry
;
754 entry
->inode
->archive
->name
, "#", extfs_prefixes
[entry
->inode
->archive
->fstype
],
760 static int extfs_lseek (void *data
, off_t offset
, int whence
)
762 struct pseudofile
*file
= (struct pseudofile
*) data
;
764 return lseek (file
->local_handle
, offset
, whence
);
767 static vfsid
extfs_getid (vfs
*me
, char *path
, struct vfs_stamping
**parent
)
769 struct archive
*archive
;
772 struct vfs_stamping
*par
;
776 if (!(p
= get_path (path
, &archive
, 1, 1)))
780 v
= vfs_type (archive
->name
);
781 id
= (*v
->getid
) (v
, archive
->name
, &par
);
782 if (id
!= (vfsid
)-1) {
783 *parent
= g_new (struct vfs_stamping
, 1);
786 (*parent
)->parent
= par
;
787 (*parent
)->next
= NULL
;
790 return (vfsid
) archive
;
793 static int extfs_nothingisopen (vfsid id
)
795 if (((struct archive
*)id
)->fd_usage
<= 0)
801 static void free_entry (struct entry
*e
)
803 int i
= --(e
->inode
->nlink
);
804 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
805 struct entry
*f
= e
->inode
->first_in_subdir
;
807 e
->inode
->first_in_subdir
= NULL
;
811 if (e
->inode
->local_filename
!= NULL
) {
812 unlink (e
->inode
->local_filename
);
813 g_free (e
->inode
->local_filename
);
815 if (e
->inode
->linkname
!= NULL
)
816 g_free (e
->inode
->linkname
);
819 if (e
->next_in_dir
!= NULL
)
820 free_entry (e
->next_in_dir
);
825 static void extfs_free (vfsid id
)
827 struct archive
*parc
;
828 struct archive
*archive
= (struct archive
*)id
;
830 free_entry (archive
->root_entry
);
831 if (archive
== first_archive
) {
832 first_archive
= archive
->next
;
834 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
835 if (parc
->next
== archive
)
838 parc
->next
= archive
->next
;
840 free_archive (archive
);
843 static char *extfs_getlocalcopy (vfs
*me
, char *path
)
845 struct pseudofile
*fp
=
846 (struct pseudofile
*) extfs_open (me
, path
, O_RDONLY
, 0);
851 if (fp
->entry
->inode
->local_filename
== NULL
) {
852 extfs_close ((void *) fp
);
855 p
= g_strdup (fp
->entry
->inode
->local_filename
);
856 fp
->archive
->fd_usage
++;
857 extfs_close ((void *) fp
);
861 static void extfs_ungetlocalcopy (vfs
*me
, char *path
, char *local
, int has_changed
)
863 struct pseudofile
*fp
=
864 (struct pseudofile
*) extfs_open (me
, path
, O_WRONLY
, 0);
868 if (!strcmp (fp
->entry
->inode
->local_filename
, local
)) {
869 fp
->entry
->inode
->has_changed
= has_changed
;
870 fp
->archive
->fd_usage
--;
871 extfs_close ((void *) fp
);
874 /* Should not happen */
875 extfs_close ((void *) fp
);
876 mc_def_ungetlocalcopy (me
, path
, local
, has_changed
);
881 #include "../src/profile.h"
882 static int extfs_init (vfs
*me
)
887 mc_extfsini
= concat_dir_and_file (mc_home
, "extfs/extfs.ini");
888 cfg
= fopen (mc_extfsini
, "r");
889 g_free (mc_extfsini
);
892 fprintf( stderr
, "Warning: " LIBDIR
"extfs/extfs.ini not found\n" );
897 while ( extfs_no
< MAXEXTFS
) {
901 if (!fgets( key
, sizeof (key
)-1, cfg
))
904 /* Handle those with a trailing ':', those flag that the
905 * file system does not require an archive to work
909 /* We may not use vfs_die() message or message_1s or similar,
910 * UI is not initialized at this time and message would not
911 * appear on screen. */
912 fprintf( stderr
, "Warning: You need to update your " LIBDIR
"extfs/extfs.ini file.\n" );
919 if ((c
= strchr( key
, '\n')))
921 c
= &key
[strlen (key
)-1];
922 extfs_need_archive
[extfs_no
] = !(*c
==':');
927 extfs_prefixes
[extfs_no
] = g_strdup (key
);
934 /* Do NOT use me argument in this function */
935 static int extfs_which (vfs
*me
, char *path
)
939 for (i
= 0; i
< extfs_no
; i
++)
940 if (!strcmp (path
, extfs_prefixes
[i
]))
945 static void extfs_done (vfs
*me
)
949 for (i
= 0; i
< extfs_no
; i
++ )
950 g_free (extfs_prefixes
[i
]);
954 static int extfs_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
956 if (ctlop
== MCCTL_EXTFS_RUN
) {
963 vfs vfs_extfs_ops
= {
964 NULL
, /* This is place of next pointer */
965 "Extended filesystems",
990 extfs_chmod
, /* chmod ... strange, returns success? */
1007 extfs_nothingisopen
,
1011 extfs_ungetlocalcopy
,