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
6 Additional changes by: 1999 Andrew T. Veliath
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License
10 as published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22 /* Namespace: exports only vfs_extfs_ops */
29 #include <sys/types.h>
34 #ifdef HAVE_SYS_WAIT_H
39 #include <sys/timeb.h> /* alex: for struct timeb definition */
40 #endif /* SCO_FLAVOR */
43 #include "../src/dialog.h"
44 #include "../src/main.h" /* For shell_execute */
48 #define ERRNOR(x,y) do { my_errno = x; return y; } while(0)
51 find_entry (struct entry
*dir
, char *name
, int make_dirs
, int make_file
);
52 static int extfs_which (vfs
*me
, char *path
);
53 static void remove_entry (struct entry
*e
);
55 static struct archive
*first_archive
= NULL
;
56 static int my_errno
= 0;
57 static struct stat hstat
; /* Stat struct corresponding */
60 static char *extfs_prefixes
[MAXEXTFS
];
61 static char extfs_need_archive
[MAXEXTFS
];
62 static int extfs_no
= 0;
64 static void extfs_fill_names (vfs
*me
, void (*func
)(char *))
66 struct archive
*a
= first_archive
;
70 name
= g_strconcat (extfs_prefixes
[a
->fstype
], "#",
71 (a
->name
? a
->name
: ""), "/",
72 a
->current_dir
->name
, NULL
);
79 static void make_dot_doubledot (struct entry
*ent
)
81 struct entry
*entry
= g_new (struct entry
, 1);
82 struct entry
*parentry
= ent
->dir
;
83 struct inode
*inode
= ent
->inode
, *parent
;
85 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
86 entry
->name
= g_strdup (".");
87 entry
->has_changed
= 0;
90 inode
->local_filename
= NULL
;
91 inode
->first_in_subdir
= entry
;
92 inode
->last_in_subdir
= entry
;
94 entry
->next_in_dir
= g_new (struct entry
, 1);
95 entry
=entry
->next_in_dir
;
96 entry
->name
= g_strdup ("..");
97 entry
->has_changed
= 0;
98 inode
->last_in_subdir
= entry
;
99 entry
->next_in_dir
= NULL
;
100 if (parent
!= NULL
) {
101 entry
->inode
= parent
;
102 entry
->dir
= parentry
;
105 entry
->inode
= inode
;
111 static struct entry
*generate_entry (struct archive
*archive
,
112 char *name
, struct entry
*parentry
, mode_t mode
)
115 struct inode
*inode
, *parent
;
118 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
119 entry
= g_new (struct entry
, 1);
121 entry
->name
= g_strdup (name
);
122 entry
->has_changed
= 0;
123 entry
->next_in_dir
= NULL
;
124 entry
->dir
= parentry
;
125 if (parent
!= NULL
) {
126 parent
->last_in_subdir
->next_in_dir
= entry
;
127 parent
->last_in_subdir
= entry
;
129 inode
= g_new (struct inode
, 1);
130 entry
->inode
= inode
;
131 inode
->has_changed
= 0;
132 inode
->local_filename
= NULL
;
134 inode
->inode
= (archive
->__inode_counter
)++;
135 inode
->dev
= archive
->rdev
;
136 inode
->archive
= archive
;
137 myumask
= umask (022);
139 inode
->mode
= mode
& ~myumask
;
142 inode
->uid
= getuid ();
143 inode
->gid
= getgid ();
145 inode
->mtime
= time (NULL
);
146 inode
->atime
= inode
->mtime
;
147 inode
->ctime
= inode
->mtime
;
150 make_dot_doubledot (entry
);
154 static void free_entries (struct entry
*entry
)
159 static void free_archive (struct archive
*archive
)
161 free_entries (archive
->root_entry
);
162 if (archive
->local_name
!= NULL
) {
165 mc_stat (archive
->local_name
, &my
);
166 mc_ungetlocalcopy (archive
->name
, archive
->local_name
,
167 archive
->local_stat
.st_mtime
!= my
.st_mtime
);
168 /* ungetlocalcopy frees local_name for us */
171 g_free (archive
->name
);
175 static FILE *open_archive (int fstype
, char *name
, struct archive
**pparc
)
177 static dev_t __extfs_no
= 0;
183 struct archive
*current_archive
;
184 struct entry
*root_entry
;
185 char *local_name
= NULL
, *tmp
= 0;
186 int uses_archive
= extfs_need_archive
[fstype
];
189 if (mc_stat (name
, &mystat
) == -1)
191 if (!vfs_file_is_local (name
)) {
192 local_name
= mc_getlocalcopy (name
);
193 if (local_name
== NULL
)
196 tmp
= name_quote (name
, 0);
200 /* Sorry, what is this good for? */
201 if (uses_archive
== EFS_NEED_ARG
){
202 tmp
= name_quote (name
, 0);
206 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
207 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[fstype
],
208 " list ", local_name
? local_name
: tmp
, NULL
);
211 result
= popen (cmd
, "r");
213 g_free (mc_extfsdir
);
214 if (result
== NULL
) {
215 if (local_name
!= NULL
&& uses_archive
)
216 mc_ungetlocalcopy (name
, local_name
, 0);
220 current_archive
= g_new (struct archive
, 1);
221 current_archive
->fstype
= fstype
;
222 current_archive
->name
= name
? g_strdup (name
): name
;
223 current_archive
->local_name
= local_name
;
225 if (local_name
!= NULL
)
226 mc_stat (local_name
, ¤t_archive
->local_stat
);
227 current_archive
->__inode_counter
= 0;
228 current_archive
->fd_usage
= 0;
229 current_archive
->extfsstat
= mystat
;
230 current_archive
->rdev
= __extfs_no
++;
231 current_archive
->next
= first_archive
;
232 first_archive
= current_archive
;
233 mode
= current_archive
->extfsstat
.st_mode
& 07777;
241 root_entry
= generate_entry (current_archive
, "/", NULL
, mode
);
242 root_entry
->inode
->uid
= current_archive
->extfsstat
.st_uid
;
243 root_entry
->inode
->gid
= current_archive
->extfsstat
.st_gid
;
244 root_entry
->inode
->atime
= current_archive
->extfsstat
.st_atime
;
245 root_entry
->inode
->ctime
= current_archive
->extfsstat
.st_ctime
;
246 root_entry
->inode
->mtime
= current_archive
->extfsstat
.st_mtime
;
247 current_archive
->root_entry
= root_entry
;
248 current_archive
->current_dir
= root_entry
;
250 *pparc
= current_archive
;
256 * Main loop for reading an archive.
257 * Returns 0 on success, -1 on error.
259 static int read_archive (int fstype
, char *name
, struct archive
**pparc
)
263 struct archive
*current_archive
;
264 char *current_file_name
, *current_link_name
;
267 if ((extfsd
= open_archive (fstype
, name
, ¤t_archive
)) == NULL
) {
268 message_3s (1, MSG_ERROR
, _("Couldn't open %s archive\n%s"),
269 extfs_prefixes
[fstype
], name
);
273 buffer
= g_malloc (4096);
274 while (fgets (buffer
, 4096, extfsd
) != NULL
) {
275 current_link_name
= NULL
;
276 if (vfs_parse_ls_lga (buffer
, &hstat
, ¤t_file_name
, ¤t_link_name
)) {
277 struct entry
*entry
, *pent
;
279 char *p
, *q
, *cfn
= current_file_name
;
285 if (p
!= NULL
&& p
!= cfn
&& *(p
- 1) == '/')
287 p
= strrchr (cfn
, '/');
295 if (S_ISDIR (hstat
.st_mode
) &&
296 (!strcmp (p
, ".") || !strcmp (p
, "..")))
297 goto read_extfs_continue
;
298 pent
= find_entry (current_archive
->root_entry
, q
, 1, 0) ;
300 message_1s (1, MSG_ERROR
, _("Inconsistent extfs archive"));
301 /* FIXME: Should clean everything one day */
306 entry
= g_new (struct entry
, 1);
307 entry
->name
= g_strdup (p
);
308 entry
->has_changed
= 0;
309 entry
->next_in_dir
= NULL
;
312 if (pent
->inode
->last_in_subdir
){
313 pent
->inode
->last_in_subdir
->next_in_dir
= entry
;
314 pent
->inode
->last_in_subdir
= entry
;
317 if (!S_ISLNK (hstat
.st_mode
) && current_link_name
!= NULL
) {
318 pent
= find_entry (current_archive
->root_entry
, current_link_name
, 0, 0);
320 message_1s (1, MSG_ERROR
, _("Inconsistent extfs archive"));
321 /* FIXME: Should clean everything one day */
326 entry
->inode
= pent
->inode
;
327 pent
->inode
->nlink
++;
330 inode
= g_new (struct inode
, 1);
331 entry
->inode
= inode
;
332 inode
->local_filename
= NULL
;
333 inode
->has_changed
= 0;
334 inode
->inode
= (current_archive
->__inode_counter
)++;
336 inode
->dev
= current_archive
->rdev
;
337 inode
->archive
= current_archive
;
338 inode
->mode
= hstat
.st_mode
;
340 inode
->rdev
= hstat
.st_rdev
;
344 inode
->uid
= hstat
.st_uid
;
345 inode
->gid
= hstat
.st_gid
;
346 inode
->size
= hstat
.st_size
;
347 inode
->mtime
= hstat
.st_mtime
;
348 inode
->atime
= hstat
.st_atime
;
349 inode
->ctime
= hstat
.st_ctime
;
350 if (current_link_name
!= NULL
&& S_ISLNK (hstat
.st_mode
)) {
351 inode
->linkname
= current_link_name
;
352 current_link_name
= NULL
;
354 if (S_ISLNK( hstat
.st_mode
))
355 inode
->mode
&= ~S_IFLNK
; /* You *DON'T* want to do this always */
356 inode
->linkname
= NULL
;
358 if (S_ISDIR (hstat
.st_mode
))
359 make_dot_doubledot (entry
);
363 g_free (current_file_name
);
364 if (current_link_name
!= NULL
)
365 g_free (current_link_name
);
370 waitpid(-1,NULL
,WNOHANG
);
371 #endif /* SCO_FLAVOR */
372 *pparc
= current_archive
;
377 static char *get_path (char *inname
, struct archive
**archive
, int is_dir
,
380 /* Returns path inside argument. Returned char* is inside inname, which is mangled
381 * by this operation (so you must not free it's return value)
383 static char *get_path_mangle (char *inname
, struct archive
**archive
, int is_dir
,
386 char *local
, *archive_name
, *op
;
388 struct archive
*parc
;
389 struct vfs_stamping
*parent
;
393 archive_name
= inname
;
394 vfs_split( inname
, &local
, &op
);
395 fstype
= extfs_which( NULL
, op
); /* FIXME: we really should pass
396 self pointer. But as we know that extfs_which does not touch vfs
397 *me, it does not matter for now */
403 /* All filesystems should have some local archive, at least
406 * Actually, we should implement an alias mechanism that would
407 * translate: "a:" to "dos:a.
410 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
412 if (!strcmp (parc
->name
, archive_name
)) {
413 struct stat
*s
=&(parc
->extfsstat
);
414 if (vfs_uid
&& (!(s
->st_mode
& 0004)))
415 if ((s
->st_gid
!= vfs_gid
) || !(s
->st_mode
& 0040))
416 if ((s
->st_uid
!= vfs_uid
) || !(s
->st_mode
& 0400))
418 /* This is not too secure - in some cases (/#mtools) files created
419 under user a are probably visible to everyone else since / usually
420 has permissions 755 */
421 vfs_stamp (&vfs_extfs_ops
, (vfsid
) parc
);
426 result
= do_not_open
? -1 : read_archive (fstype
, archive_name
, &parc
);
427 if (result
== -1) ERRNOR (EIO
, NULL
);
430 v
= vfs_type (archive_name
);
431 if (v
== &vfs_local_ops
) {
434 parent
= g_new (struct vfs_stamping
, 1);
437 parent
->id
= (*v
->getid
) (v
, archive_name
, &(parent
->parent
));
439 vfs_add_noncurrent_stamps (&vfs_extfs_ops
, (vfsid
) parc
, parent
);
440 vfs_rm_parents (parent
);
447 /* Returns allocated path (without leading slash) inside the archive */
448 static char *get_path_from_entry (struct entry
*entry
)
457 for (len
= 0, head
= 0; entry
->dir
; entry
= entry
->dir
) {
458 p
= g_new (struct list
, 1);
460 p
->name
= entry
->name
;
462 len
+= strlen (entry
->name
) + 1;
466 return g_strdup ("");
468 localpath
= g_malloc (len
);
471 strcat (localpath
, head
->name
);
473 strcat (localpath
, "/");
482 struct loop_protect
{
484 struct loop_protect
*next
;
489 static struct entry
*
490 __find_entry (struct entry
*dir
, char *name
,
491 struct loop_protect
*list
, int make_dirs
, int make_file
);
493 static struct entry
*
494 __resolve_symlinks (struct entry
*entry
,
495 struct loop_protect
*list
)
498 struct loop_protect
*looping
;
500 if (!S_ISLNK (entry
->inode
->mode
))
502 for (looping
= list
; looping
!= NULL
; looping
= looping
->next
)
503 if (entry
== looping
->entry
) { /* Here we protect us against symlink looping */
507 looping
= g_new (struct loop_protect
, 1);
508 looping
->entry
= entry
;
509 looping
->next
= list
;
510 pent
= __find_entry (entry
->dir
, entry
->inode
->linkname
, looping
, 0, 0);
517 static struct entry
*my_resolve_symlinks (struct entry
*entry
)
523 res
= __resolve_symlinks (entry
, NULL
);
534 struct archive
*archive
;
535 unsigned int has_changed
:1;
540 static char *get_archive_name (struct archive
*archive
)
544 if (archive
->local_name
)
545 archive_name
= archive
->local_name
;
547 archive_name
= archive
->name
;
549 if (!archive_name
|| !*archive_name
)
550 return "no_archive_name";
555 /* FIXME: we really should not have non-static procedures - it
556 * pollutes namespace. */
558 void extfs_run (char *file
)
560 struct archive
*archive
;
561 char *p
, *q
, *archive_name
, *mc_extfsdir
;
564 if ((p
= get_path (file
, &archive
, 0, 0)) == NULL
)
566 q
= name_quote (p
, 0);
568 archive_name
= name_quote (get_archive_name(archive
), 0);
569 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
570 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
571 " run ", archive_name
, " ", q
, NULL
);
572 g_free (mc_extfsdir
);
573 g_free (archive_name
);
575 #ifndef VFS_STANDALONE
576 shell_execute(cmd
, 0);
578 vfs_die( "shell_execute: implement me!" );
584 static void *extfs_open (vfs
*me
, char *file
, int flags
, int mode
)
586 struct pseudofile
*extfs_info
;
587 struct archive
*archive
;
592 const int do_create
= (flags
& O_ACCMODE
) != O_RDONLY
;
594 if ((q
= get_path_mangle (file
, &archive
, 0, 0)) == NULL
)
596 entry
= find_entry (archive
->root_entry
, q
, 0, do_create
);
599 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
601 if (S_ISDIR (entry
->inode
->mode
)) ERRNOR (EISDIR
, NULL
);
602 if (entry
->inode
->local_filename
== NULL
) {
604 char *archive_name
, *p
;
606 entry
->inode
->local_filename
= tempnam (NULL
, "extfs");
610 handle
= open(entry
->inode
->local_filename
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
615 p
= get_path_from_entry (entry
);
616 q
= name_quote (p
, 0);
618 archive_name
= name_quote (get_archive_name (archive
), 0);
620 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
621 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
624 " ", q
, " ", entry
->inode
->local_filename
, NULL
);
626 g_free (mc_extfsdir
);
627 g_free (archive_name
);
628 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
) && !do_create
){
629 free (entry
->inode
->local_filename
);
630 entry
->inode
->local_filename
= NULL
;
638 local_handle
= open (entry
->inode
->local_filename
, flags
, mode
);
639 if (local_handle
== -1) ERRNOR (EIO
, NULL
);
641 extfs_info
= g_new (struct pseudofile
, 1);
642 extfs_info
->archive
= archive
;
643 extfs_info
->entry
= entry
;
644 extfs_info
->has_changed
= 0;
645 extfs_info
->local_handle
= local_handle
;
647 /* i.e. we had no open files and now we have one */
648 vfs_rmstamp (&vfs_extfs_ops
, (vfsid
) archive
, 1);
653 static int extfs_read (void *data
, char *buffer
, int count
)
655 struct pseudofile
*file
= (struct pseudofile
*)data
;
657 return read (file
->local_handle
, buffer
, count
);
660 static int extfs_close (void *data
)
662 struct pseudofile
*file
;
664 file
= (struct pseudofile
*)data
;
666 close (file
->local_handle
);
668 /* Commit the file if it has changed */
669 if (file
->has_changed
){
670 struct archive
*archive
;
671 char *archive_name
, *file_name
;
676 archive
= file
->archive
;
677 archive_name
= name_quote (get_archive_name (archive
), 0);
678 p
= get_path_from_entry (file
->entry
);
679 file_name
= name_quote (p
, 0);
682 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
683 cmd
= g_strconcat (mc_extfsdir
,
684 extfs_prefixes
[archive
->fstype
],
685 " copyin ", archive_name
, " ",
687 file
->entry
->inode
->local_filename
, NULL
);
688 g_free (archive_name
);
690 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
))
693 g_free (mc_extfsdir
);
695 struct stat file_status
;
696 if( stat(file
->entry
->inode
->local_filename
,&file_status
) != 0 )
698 else file
->entry
->inode
->size
= file_status
.st_size
;
701 file
->entry
->inode
->mtime
= time (NULL
);
704 file
->archive
->fd_usage
--;
705 if (!file
->archive
->fd_usage
) {
706 struct vfs_stamping
*parent
;
709 if (!file
->archive
->name
|| !*file
->archive
->name
|| (v
= vfs_type (file
->archive
->name
)) == &vfs_local_ops
) {
712 parent
= g_new (struct vfs_stamping
, 1);
715 parent
->id
= (*v
->getid
) (v
, file
->archive
->name
, &(parent
->parent
));
717 vfs_add_noncurrent_stamps (&vfs_extfs_ops
, (vfsid
) (file
->archive
), parent
);
718 vfs_rm_parents (parent
);
722 if (errno_code
) ERRNOR (EIO
, -1);
726 #define RECORDSIZE 512
727 #include "shared_tar_ext.c"
729 static int extfs_chmod (vfs
*me
, char *path
, int mode
)
734 static int extfs_write (void *data
, char *buf
, int nbyte
)
736 struct pseudofile
*file
= (struct pseudofile
*)data
;
738 file
->has_changed
= 1;
739 return write (file
->local_handle
, buf
, nbyte
);
742 static int extfs_unlink (vfs
*me
, char *file
)
744 struct archive
*archive
;
749 char *archive_name
, *p
;
751 if ((q
= get_path_mangle (file
, &archive
, 0, 0)) == NULL
)
753 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
756 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
758 if (S_ISDIR (entry
->inode
->mode
)) ERRNOR (EISDIR
, -1);
760 p
= get_path_from_entry (entry
);
761 q
= name_quote (p
, 0);
763 archive_name
= name_quote (get_archive_name (archive
), 0);
765 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
766 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
767 " rm ", archive_name
, " ", q
, NULL
);
769 g_free (mc_extfsdir
);
770 g_free (archive_name
);
771 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
)){
777 remove_entry (entry
);
782 static int extfs_mkdir (vfs
*me
, char *path
, mode_t mode
)
784 struct archive
*archive
;
789 char *archive_name
, *p
;
791 if ((q
= get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
793 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
794 if (entry
!= NULL
) ERRNOR (EEXIST
, -1);
795 entry
= find_entry (archive
->root_entry
, q
, 1, 0);
798 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
800 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, -1);
802 p
= get_path_from_entry (entry
);
803 q
= name_quote (p
, 0);
805 archive_name
= name_quote (get_archive_name (archive
), 0);
807 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
808 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
809 " mkdir ", archive_name
, " ", q
, NULL
);
811 g_free (mc_extfsdir
);
812 g_free (archive_name
);
813 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
)){
816 remove_entry (entry
);
824 static int extfs_rmdir (vfs
*me
, char *path
)
826 struct archive
*archive
;
831 char *archive_name
, *p
;
833 if ((q
= get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
835 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
838 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
840 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, -1);
842 p
= get_path_from_entry (entry
);
843 q
= name_quote (p
, 0);
845 archive_name
= name_quote (get_archive_name (archive
), 0);
847 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
848 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
849 " rmdir ", archive_name
, " ", q
, NULL
);
851 g_free (mc_extfsdir
);
852 g_free (archive_name
);
853 if (my_system (EXECUTE_AS_SHELL
| EXECUTE_SETUID
| EXECUTE_WAIT
, shell
, cmd
)){
859 remove_entry (entry
);
864 static int extfs_chdir (vfs
*me
, char *path
)
866 struct archive
*archive
;
871 if ((q
= get_path_mangle (path
, &archive
, 1, 0)) == NULL
)
873 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
876 entry
= my_resolve_symlinks (entry
);
877 if ((!entry
) || (!S_ISDIR (entry
->inode
->mode
)))
879 entry
->inode
->archive
->current_dir
= entry
;
881 entry
->inode
->archive
->name
, "#", extfs_prefixes
[entry
->inode
->archive
->fstype
],
887 static int extfs_lseek (void *data
, off_t offset
, int whence
)
889 struct pseudofile
*file
= (struct pseudofile
*) data
;
891 return lseek (file
->local_handle
, offset
, whence
);
894 static vfsid
extfs_getid (vfs
*me
, char *path
, struct vfs_stamping
**parent
)
896 struct archive
*archive
;
899 struct vfs_stamping
*par
;
903 if (!(p
= get_path (path
, &archive
, 1, 1)))
907 v
= vfs_type (archive
->name
);
908 id
= (*v
->getid
) (v
, archive
->name
, &par
);
909 if (id
!= (vfsid
)-1) {
910 *parent
= g_new (struct vfs_stamping
, 1);
913 (*parent
)->parent
= par
;
914 (*parent
)->next
= NULL
;
917 return (vfsid
) archive
;
920 static int extfs_nothingisopen (vfsid id
)
922 if (((struct archive
*)id
)->fd_usage
<= 0)
928 static void remove_entry (struct entry
*e
)
930 int i
= --(e
->inode
->nlink
);
931 struct entry
*pe
, *ent
, *prev
;
933 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
934 struct entry
*f
= e
->inode
->first_in_subdir
;
935 e
->inode
->first_in_subdir
= NULL
;
939 if (e
== pe
->inode
->first_in_subdir
)
940 pe
->inode
->first_in_subdir
= e
->next_in_dir
;
943 for (ent
= pe
->inode
->first_in_subdir
; ent
&& ent
->next_in_dir
;
944 ent
= ent
->next_in_dir
)
945 if (e
== ent
->next_in_dir
) {
950 prev
->next_in_dir
= e
->next_in_dir
;
951 if (e
== pe
->inode
->last_in_subdir
)
952 pe
->inode
->last_in_subdir
= prev
;
955 if (e
->inode
->local_filename
!= NULL
) {
956 unlink (e
->inode
->local_filename
);
957 free (e
->inode
->local_filename
);
959 if (e
->inode
->linkname
!= NULL
)
960 g_free (e
->inode
->linkname
);
968 static void free_entry (struct entry
*e
)
970 int i
= --(e
->inode
->nlink
);
971 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
972 struct entry
*f
= e
->inode
->first_in_subdir
;
974 e
->inode
->first_in_subdir
= NULL
;
978 if (e
->inode
->local_filename
!= NULL
) {
979 unlink (e
->inode
->local_filename
);
980 free (e
->inode
->local_filename
);
982 if (e
->inode
->linkname
!= NULL
)
983 g_free (e
->inode
->linkname
);
986 if (e
->next_in_dir
!= NULL
)
987 free_entry (e
->next_in_dir
);
992 static void extfs_free (vfsid id
)
994 struct archive
*parc
;
995 struct archive
*archive
= (struct archive
*)id
;
997 free_entry (archive
->root_entry
);
998 if (archive
== first_archive
) {
999 first_archive
= archive
->next
;
1001 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
1002 if (parc
->next
== archive
)
1005 parc
->next
= archive
->next
;
1007 free_archive (archive
);
1010 static char *extfs_getlocalcopy (vfs
*me
, char *path
)
1012 struct pseudofile
*fp
=
1013 (struct pseudofile
*) extfs_open (me
, path
, O_RDONLY
, 0);
1018 if (fp
->entry
->inode
->local_filename
== NULL
) {
1019 extfs_close ((void *) fp
);
1022 p
= g_strdup (fp
->entry
->inode
->local_filename
);
1023 fp
->archive
->fd_usage
++;
1024 extfs_close ((void *) fp
);
1028 static void extfs_ungetlocalcopy (vfs
*me
, char *path
, char *local
, int has_changed
)
1030 struct pseudofile
*fp
=
1031 (struct pseudofile
*) extfs_open (me
, path
, O_WRONLY
, 0);
1035 if (!strcmp (fp
->entry
->inode
->local_filename
, local
)) {
1036 fp
->entry
->inode
->has_changed
= has_changed
;
1037 fp
->archive
->fd_usage
--;
1038 extfs_close ((void *) fp
);
1041 /* Should not happen */
1042 extfs_close ((void *) fp
);
1043 mc_def_ungetlocalcopy (me
, path
, local
, has_changed
);
1048 #include "../src/profile.h"
1049 static int extfs_init (vfs
*me
)
1054 mc_extfsini
= concat_dir_and_file (mc_home
, "extfs/extfs.ini");
1055 cfg
= fopen (mc_extfsini
, "r");
1056 g_free (mc_extfsini
);
1059 fprintf( stderr
, "Warning: " LIBDIR
"extfs/extfs.ini not found\n" );
1064 while ( extfs_no
< MAXEXTFS
) {
1068 if (!fgets( key
, sizeof (key
)-1, cfg
))
1071 /* Handle those with a trailing ':', those flag that the
1072 * file system does not require an archive to work
1076 /* We may not use vfs_die() message or message_1s or similar,
1077 * UI is not initialized at this time and message would not
1078 * appear on screen. */
1079 fprintf( stderr
, "Warning: You need to update your " LIBDIR
"extfs/extfs.ini file.\n" );
1086 if ((c
= strchr (key
, '\n'))){
1088 c
= &key
[strlen (key
) - 1];
1092 extfs_need_archive
[extfs_no
] = !(*c
== ':');
1098 extfs_prefixes
[extfs_no
] = g_strdup (key
);
1105 /* Do NOT use me argument in this function */
1106 static int extfs_which (vfs
*me
, char *path
)
1110 for (i
= 0; i
< extfs_no
; i
++)
1111 if (!strcmp (path
, extfs_prefixes
[i
]))
1116 static void extfs_done (vfs
*me
)
1120 for (i
= 0; i
< extfs_no
; i
++ )
1121 g_free (extfs_prefixes
[i
]);
1125 static int extfs_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
1127 if (ctlop
== MCCTL_EXTFS_RUN
) {
1134 vfs vfs_extfs_ops
= {
1135 NULL
, /* This is place of next pointer */
1136 "Extended filesystems",
1161 extfs_chmod
, /* chmod ... strange, returns success? */
1178 extfs_nothingisopen
,
1182 extfs_ungetlocalcopy
,
1184 extfs_mkdir
, /* mkdir */