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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 /* Namespace: exports only vfs_extfs_ops */
29 #include <sys/types.h>
33 #ifdef HAVE_SYS_WAIT_H
38 #include "../src/dialog.h"
39 #include "../src/main.h" /* For shell_execute */
40 #include "xdirentry.h"
45 #define ERRNOR(x,y) do { my_errno = x; return y; } while(0)
49 struct entry
*first_in_subdir
; /* only used if this is a directory */
50 struct entry
*last_in_subdir
;
51 ino_t inode
; /* This is inode # */
52 dev_t dev
; /* This is an internal identification of the extfs archive */
53 struct archive
*archive
; /* And this is an archive structure */
68 struct entry
*next_in_dir
;
75 struct archive
*archive
;
76 unsigned int has_changed
:1;
82 find_entry (struct entry
*dir
, char *name
, int make_dirs
, int make_file
);
83 static int extfs_which (vfs
*me
, char *path
);
84 static void remove_entry (struct entry
*e
);
86 static struct archive
*first_archive
= NULL
;
87 static int my_errno
= 0;
88 static struct stat hstat
; /* Stat struct corresponding */
91 static char *extfs_prefixes
[MAXEXTFS
];
92 static char extfs_need_archive
[MAXEXTFS
];
93 static int extfs_no
= 0;
95 static void extfs_fill_names (vfs
*me
, void (*func
)(char *))
97 struct archive
*a
= first_archive
;
101 name
= g_strconcat (a
->name
? a
->name
: "",
102 "#", extfs_prefixes
[a
->fstype
],
103 PATH_SEP_STR
, a
->current_dir
->name
, NULL
);
110 static void make_dot_doubledot (struct entry
*ent
)
112 struct entry
*entry
= g_new (struct entry
, 1);
113 struct entry
*parentry
= ent
->dir
;
114 struct inode
*inode
= ent
->inode
, *parent
;
116 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
117 entry
->name
= g_strdup (".");
118 entry
->inode
= inode
;
120 inode
->local_filename
= NULL
;
121 inode
->first_in_subdir
= entry
;
122 inode
->last_in_subdir
= entry
;
124 entry
->next_in_dir
= g_new (struct entry
, 1);
125 entry
=entry
->next_in_dir
;
126 entry
->name
= g_strdup ("..");
127 inode
->last_in_subdir
= entry
;
128 entry
->next_in_dir
= NULL
;
129 if (parent
!= NULL
) {
130 entry
->inode
= parent
;
131 entry
->dir
= parentry
;
134 entry
->inode
= inode
;
140 static struct entry
*generate_entry (struct archive
*archive
,
141 char *name
, struct entry
*parentry
, mode_t mode
)
144 struct inode
*inode
, *parent
;
147 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
148 entry
= g_new (struct entry
, 1);
150 entry
->name
= g_strdup (name
);
151 entry
->next_in_dir
= NULL
;
152 entry
->dir
= parentry
;
153 if (parent
!= NULL
) {
154 parent
->last_in_subdir
->next_in_dir
= entry
;
155 parent
->last_in_subdir
= entry
;
157 inode
= g_new (struct inode
, 1);
158 entry
->inode
= inode
;
159 inode
->local_filename
= NULL
;
161 inode
->inode
= (archive
->__inode_counter
)++;
162 inode
->dev
= archive
->rdev
;
163 inode
->archive
= archive
;
164 myumask
= umask (022);
166 inode
->mode
= mode
& ~myumask
;
169 inode
->uid
= getuid ();
170 inode
->gid
= getgid ();
172 inode
->mtime
= time (NULL
);
173 inode
->atime
= inode
->mtime
;
174 inode
->ctime
= inode
->mtime
;
177 make_dot_doubledot (entry
);
181 static void free_entries (struct entry
*entry
)
186 static void free_archive (struct archive
*archive
)
188 free_entries (archive
->root_entry
);
189 if (archive
->local_name
!= NULL
) {
192 mc_stat (archive
->local_name
, &my
);
193 mc_ungetlocalcopy (archive
->name
, archive
->local_name
,
194 archive
->local_stat
.st_mtime
!= my
.st_mtime
);
195 /* ungetlocalcopy frees local_name for us */
198 g_free (archive
->name
);
202 static FILE *open_archive (int fstype
, char *name
, struct archive
**pparc
)
204 static dev_t __extfs_no
= 0;
210 struct archive
*current_archive
;
211 struct entry
*root_entry
;
212 char *local_name
= NULL
, *tmp
= 0;
213 int uses_archive
= extfs_need_archive
[fstype
];
216 if (mc_stat (name
, &mystat
) == -1)
218 if (!vfs_file_is_local (name
)) {
219 local_name
= mc_getlocalcopy (name
);
220 if (local_name
== NULL
)
223 tmp
= name_quote (name
, 0);
226 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
227 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[fstype
],
228 " list ", local_name
? local_name
: tmp
, NULL
);
231 g_free (mc_extfsdir
);
232 result
= popen (cmd
, "r");
234 if (result
== NULL
) {
235 if (local_name
!= NULL
&& uses_archive
)
236 mc_ungetlocalcopy (name
, local_name
, 0);
240 current_archive
= g_new (struct archive
, 1);
241 current_archive
->fstype
= fstype
;
242 current_archive
->name
= name
? g_strdup (name
): name
;
243 current_archive
->local_name
= local_name
;
245 if (local_name
!= NULL
)
246 mc_stat (local_name
, ¤t_archive
->local_stat
);
247 current_archive
->__inode_counter
= 0;
248 current_archive
->fd_usage
= 0;
249 current_archive
->extfsstat
= mystat
;
250 current_archive
->rdev
= __extfs_no
++;
251 current_archive
->next
= first_archive
;
252 first_archive
= current_archive
;
253 mode
= current_archive
->extfsstat
.st_mode
& 07777;
261 root_entry
= generate_entry (current_archive
, "/", NULL
, mode
);
262 root_entry
->inode
->uid
= current_archive
->extfsstat
.st_uid
;
263 root_entry
->inode
->gid
= current_archive
->extfsstat
.st_gid
;
264 root_entry
->inode
->atime
= current_archive
->extfsstat
.st_atime
;
265 root_entry
->inode
->ctime
= current_archive
->extfsstat
.st_ctime
;
266 root_entry
->inode
->mtime
= current_archive
->extfsstat
.st_mtime
;
267 current_archive
->root_entry
= root_entry
;
268 current_archive
->current_dir
= root_entry
;
270 *pparc
= current_archive
;
276 * Main loop for reading an archive.
277 * Returns 0 on success, -1 on error.
279 static int read_archive (int fstype
, char *name
, struct archive
**pparc
)
283 struct archive
*current_archive
;
284 char *current_file_name
, *current_link_name
;
287 if ((extfsd
= open_archive (fstype
, name
, ¤t_archive
)) == NULL
) {
288 message_3s (1, MSG_ERROR
, _("Couldn't open %s archive\n%s"),
289 extfs_prefixes
[fstype
], name
);
293 buffer
= g_malloc (4096);
294 while (fgets (buffer
, 4096, extfsd
) != NULL
) {
295 current_link_name
= NULL
;
296 if (vfs_parse_ls_lga (buffer
, &hstat
, ¤t_file_name
, ¤t_link_name
)) {
297 struct entry
*entry
, *pent
;
299 char *p
, *q
, *cfn
= current_file_name
;
305 if (p
!= cfn
&& *(p
- 1) == '/')
307 p
= strrchr (cfn
, '/');
315 if (S_ISDIR (hstat
.st_mode
) &&
316 (!strcmp (p
, ".") || !strcmp (p
, "..")))
317 goto read_extfs_continue
;
318 pent
= find_entry (current_archive
->root_entry
, q
, 1, 0) ;
320 message_1s (1, MSG_ERROR
, _("Inconsistent extfs archive"));
321 /* FIXME: Should clean everything one day */
326 entry
= g_new (struct entry
, 1);
327 entry
->name
= g_strdup (p
);
328 entry
->next_in_dir
= NULL
;
331 if (pent
->inode
->last_in_subdir
){
332 pent
->inode
->last_in_subdir
->next_in_dir
= entry
;
333 pent
->inode
->last_in_subdir
= entry
;
336 if (!S_ISLNK (hstat
.st_mode
) && current_link_name
!= NULL
) {
337 pent
= find_entry (current_archive
->root_entry
, current_link_name
, 0, 0);
339 message_1s (1, MSG_ERROR
, _("Inconsistent extfs archive"));
340 /* FIXME: Should clean everything one day */
345 entry
->inode
= pent
->inode
;
346 pent
->inode
->nlink
++;
349 inode
= g_new (struct inode
, 1);
350 entry
->inode
= inode
;
351 inode
->local_filename
= NULL
;
352 inode
->inode
= (current_archive
->__inode_counter
)++;
354 inode
->dev
= current_archive
->rdev
;
355 inode
->archive
= current_archive
;
356 inode
->mode
= hstat
.st_mode
;
358 inode
->rdev
= hstat
.st_rdev
;
362 inode
->uid
= hstat
.st_uid
;
363 inode
->gid
= hstat
.st_gid
;
364 inode
->size
= hstat
.st_size
;
365 inode
->mtime
= hstat
.st_mtime
;
366 inode
->atime
= hstat
.st_atime
;
367 inode
->ctime
= hstat
.st_ctime
;
368 if (current_link_name
!= NULL
&& S_ISLNK (hstat
.st_mode
)) {
369 inode
->linkname
= current_link_name
;
370 current_link_name
= NULL
;
372 if (S_ISLNK( hstat
.st_mode
))
373 inode
->mode
&= ~S_IFLNK
; /* You *DON'T* want to do this always */
374 inode
->linkname
= NULL
;
376 if (S_ISDIR (hstat
.st_mode
))
377 make_dot_doubledot (entry
);
381 g_free (current_file_name
);
382 if (current_link_name
!= NULL
)
383 g_free (current_link_name
);
388 waitpid(-1,NULL
,WNOHANG
);
389 #endif /* SCO_FLAVOR */
390 *pparc
= current_archive
;
395 static char *get_path (char *inname
, struct archive
**archive
, int is_dir
,
398 /* Returns path inside argument. Returned char* is inside inname, which is mangled
399 * by this operation (so you must not free it's return value)
401 static char *get_path_mangle (char *inname
, struct archive
**archive
, int is_dir
,
404 char *local
, *archive_name
, *op
;
406 struct archive
*parc
;
407 struct vfs_stamping
*parent
;
411 archive_name
= inname
;
412 vfs_split( inname
, &local
, &op
);
413 fstype
= extfs_which( NULL
, op
); /* FIXME: we really should pass
414 self pointer. But as we know that extfs_which does not touch vfs
415 *me, it does not matter for now */
421 /* All filesystems should have some local archive, at least
424 * Actually, we should implement an alias mechanism that would
425 * translate: "a:" to "dos:a.
428 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
430 if (!strcmp (parc
->name
, archive_name
)) {
431 struct stat
*s
=&(parc
->extfsstat
);
432 if (vfs_uid
&& (!(s
->st_mode
& 0004)))
433 if ((s
->st_gid
!= vfs_gid
) || !(s
->st_mode
& 0040))
434 if ((s
->st_uid
!= vfs_uid
) || !(s
->st_mode
& 0400))
436 /* This is not too secure - in some cases (/#mtools) files created
437 under user a are probably visible to everyone else since / usually
438 has permissions 755 */
439 vfs_stamp (&vfs_extfs_ops
, (vfsid
) parc
);
444 result
= do_not_open
? -1 : read_archive (fstype
, archive_name
, &parc
);
445 if (result
== -1) ERRNOR (EIO
, NULL
);
448 v
= vfs_type (archive_name
);
449 if (v
== &vfs_local_ops
) {
452 parent
= g_new (struct vfs_stamping
, 1);
455 parent
->id
= (*v
->getid
) (v
, archive_name
, &(parent
->parent
));
457 vfs_add_noncurrent_stamps (&vfs_extfs_ops
, (vfsid
) parc
, parent
);
458 vfs_rm_parents (parent
);
465 /* Returns allocated path (without leading slash) inside the archive */
466 static char *get_path_from_entry (struct entry
*entry
)
475 for (len
= 0, head
= 0; entry
->dir
; entry
= entry
->dir
) {
476 p
= g_new (struct list
, 1);
478 p
->name
= entry
->name
;
480 len
+= strlen (entry
->name
) + 1;
484 return g_strdup ("");
486 localpath
= g_malloc (len
);
489 strcat (localpath
, head
->name
);
491 strcat (localpath
, "/");
500 struct loop_protect
{
502 struct loop_protect
*next
;
507 static struct entry
*
508 __find_entry (struct entry
*dir
, char *name
,
509 struct loop_protect
*list
, int make_dirs
, int make_file
);
511 static struct entry
*
512 __resolve_symlinks (struct entry
*entry
,
513 struct loop_protect
*list
)
516 struct loop_protect
*looping
;
518 if (!S_ISLNK (entry
->inode
->mode
))
520 for (looping
= list
; looping
!= NULL
; looping
= looping
->next
)
521 if (entry
== looping
->entry
) { /* Here we protect us against symlink looping */
525 looping
= g_new (struct loop_protect
, 1);
526 looping
->entry
= entry
;
527 looping
->next
= list
;
528 pent
= __find_entry (entry
->dir
, entry
->inode
->linkname
, looping
, 0, 0);
535 static struct entry
*my_resolve_symlinks (struct entry
*entry
)
541 res
= __resolve_symlinks (entry
, NULL
);
551 static char *get_archive_name (struct archive
*archive
)
555 if (archive
->local_name
)
556 archive_name
= archive
->local_name
;
558 archive_name
= archive
->name
;
560 if (!archive_name
|| !*archive_name
)
561 return "no_archive_name";
566 static void extfs_run (char *file
)
568 struct archive
*archive
;
569 char *p
, *q
, *archive_name
, *mc_extfsdir
;
572 if ((p
= get_path (file
, &archive
, 0, 0)) == NULL
)
574 q
= name_quote (p
, 0);
577 archive_name
= name_quote (get_archive_name(archive
), 0);
578 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
579 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
580 " run ", archive_name
, " ", q
, NULL
);
581 g_free (mc_extfsdir
);
582 g_free (archive_name
);
584 shell_execute(cmd
, 0);
588 static void *extfs_open (vfs
*me
, char *file
, int flags
, int mode
)
590 struct pseudofile
*extfs_info
;
591 struct archive
*archive
;
598 if ((q
= get_path_mangle (file
, &archive
, 0, 0)) == NULL
)
600 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
601 if (entry
== NULL
&& (flags
& O_CREAT
)) {
602 /* Create new entry */
603 entry
= find_entry (archive
->root_entry
, q
, 0, 1);
604 created
= (entry
!= NULL
);
608 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
610 if (S_ISDIR (entry
->inode
->mode
)) ERRNOR (EISDIR
, NULL
);
611 if (entry
->inode
->local_filename
== NULL
) {
613 char *archive_name
, *p
;
617 handle
= mc_mkstemps (&entry
->inode
->local_filename
, "extfs", NULL
);
623 p
= get_path_from_entry (entry
);
624 q
= name_quote (p
, 0);
626 archive_name
= name_quote (get_archive_name (archive
), 0);
628 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
629 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
632 " ", q
, " ", entry
->inode
->local_filename
, NULL
);
634 g_free (mc_extfsdir
);
635 g_free (archive_name
);
636 if (my_system (EXECUTE_AS_SHELL
, shell
, cmd
) && !created
){
637 free (entry
->inode
->local_filename
);
638 entry
->inode
->local_filename
= NULL
;
646 local_handle
= open (entry
->inode
->local_filename
, NO_LINEAR(flags
),
648 if (local_handle
== -1) ERRNOR (EIO
, NULL
);
650 extfs_info
= g_new (struct pseudofile
, 1);
651 extfs_info
->archive
= archive
;
652 extfs_info
->entry
= entry
;
653 extfs_info
->has_changed
= created
;
654 extfs_info
->local_handle
= local_handle
;
656 /* i.e. we had no open files and now we have one */
657 vfs_rmstamp (&vfs_extfs_ops
, (vfsid
) archive
, 1);
662 static int extfs_read (void *data
, char *buffer
, int count
)
664 struct pseudofile
*file
= (struct pseudofile
*)data
;
666 return read (file
->local_handle
, buffer
, count
);
669 static int extfs_close (void *data
)
671 struct pseudofile
*file
;
673 file
= (struct pseudofile
*)data
;
675 close (file
->local_handle
);
677 /* Commit the file if it has changed */
678 if (file
->has_changed
){
679 struct archive
*archive
;
680 char *archive_name
, *file_name
;
685 archive
= file
->archive
;
686 archive_name
= name_quote (get_archive_name (archive
), 0);
687 p
= get_path_from_entry (file
->entry
);
688 file_name
= name_quote (p
, 0);
691 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
692 cmd
= g_strconcat (mc_extfsdir
,
693 extfs_prefixes
[archive
->fstype
],
694 " copyin ", archive_name
, " ",
696 file
->entry
->inode
->local_filename
, NULL
);
697 g_free (archive_name
);
699 g_free (mc_extfsdir
);
700 if (my_system (EXECUTE_AS_SHELL
, shell
, cmd
))
704 struct stat file_status
;
705 if (stat(file
->entry
->inode
->local_filename
,&file_status
) != 0)
708 file
->entry
->inode
->size
= file_status
.st_size
;
711 file
->entry
->inode
->mtime
= time (NULL
);
714 file
->archive
->fd_usage
--;
715 if (!file
->archive
->fd_usage
) {
716 struct vfs_stamping
*parent
;
719 if (!file
->archive
->name
|| !*file
->archive
->name
|| (v
= vfs_type (file
->archive
->name
)) == &vfs_local_ops
) {
722 parent
= g_new (struct vfs_stamping
, 1);
725 parent
->id
= (*v
->getid
) (v
, file
->archive
->name
, &(parent
->parent
));
727 vfs_add_noncurrent_stamps (&vfs_extfs_ops
, (vfsid
) (file
->archive
), parent
);
728 vfs_rm_parents (parent
);
732 if (errno_code
) ERRNOR (EIO
, -1);
736 #define RECORDSIZE 512
738 static char *get_path (char *inname
, struct archive
**archive
, int is_dir
,
741 char *buf
= g_strdup (inname
);
742 char *res
= get_path_mangle( buf
, archive
, is_dir
, do_not_open
);
745 res2
= g_strdup(res
);
751 __find_entry (struct entry
*dir
, char *name
,
752 struct loop_protect
*list
, int make_dirs
, int make_file
)
754 struct entry
*pent
, *pdir
;
755 char *p
, *q
, *name_end
;
758 if (*name
== '/') { /* Handle absolute paths */
760 dir
= dir
->inode
->archive
->root_entry
;
765 name_end
= name
+ strlen (name
);
771 for (; pent
!= NULL
&& c
&& *p
; ){
775 if (strcmp (p
, ".")){
776 if (!strcmp (p
, ".."))
779 if ((pent
= __resolve_symlinks (pent
, list
))==NULL
){
783 if (!S_ISDIR (pent
->inode
->mode
)){
789 for (pent
= pent
->inode
->first_in_subdir
; pent
; pent
= pent
->next_in_dir
)
790 /* Hack: I keep the original semanthic unless
791 q+1 would break in the strchr */
792 if (!strcmp (pent
->name
, p
)){
793 if (q
+ 1 > name_end
){
795 notadir
= !S_ISDIR (pent
->inode
->mode
);
801 /* When we load archive, we create automagically
802 * non-existant directories
804 if (pent
== NULL
&& make_dirs
) {
805 pent
= generate_entry (dir
->inode
->archive
, p
, pdir
, S_IFDIR
| 0777);
807 if (pent
== NULL
&& make_file
) {
808 pent
= generate_entry (dir
->inode
->archive
, p
, pdir
, 0777);
824 static struct entry
*find_entry (struct entry
*dir
, char *name
, int make_dirs
, int make_file
)
830 res
= __find_entry (dir
, name
, NULL
, make_dirs
, make_file
);
841 static int s_errno (vfs
*me
)
846 static void * s_opendir (vfs
*me
, char *dirname
)
848 struct archive
*archive
;
853 if ((q
= get_path_mangle (dirname
, &archive
, 1, 0)) == NULL
)
855 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
858 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
860 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, NULL
);
862 info
= g_new (struct entry
*, 2);
863 info
[0] = entry
->inode
->first_in_subdir
;
864 info
[1] = entry
->inode
->first_in_subdir
;
869 static void * s_readdir(void *data
)
871 static union vfs_dirent dir
;
872 struct entry
**info
= (struct entry
**) data
;
877 strncpy(dir
.dent
.d_name
, (*info
)->name
, MC_MAXPATHLEN
);
878 dir
.dent
.d_name
[MC_MAXPATHLEN
] = 0;
880 compute_namelen(&dir
.dent
);
881 *info
= (*info
)->next_in_dir
;
883 return (void *) &dir
;
886 static int s_telldir (void *data
)
888 struct entry
**info
= (struct entry
**) data
;
894 if (cur
== info
[0]) return num
;
896 cur
= cur
->next_in_dir
;
901 static void s_seekdir (void *data
, int offset
)
903 struct entry
**info
= (struct entry
**) data
;
906 for (i
=0; i
<offset
; i
++)
910 static int s_closedir (void *data
)
916 static void stat_move( struct stat
*buf
, struct inode
*inode
)
918 buf
->st_dev
= inode
->dev
;
919 buf
->st_ino
= inode
->inode
;
920 buf
->st_mode
= inode
->mode
;
921 buf
->st_nlink
= inode
->nlink
;
922 buf
->st_uid
= inode
->uid
;
923 buf
->st_gid
= inode
->gid
;
925 buf
->st_rdev
= inode
->rdev
;
927 buf
->st_size
= inode
->size
;
928 #ifdef HAVE_ST_BLKSIZE
929 buf
->st_blksize
= RECORDSIZE
;
931 #ifdef HAVE_ST_BLOCKS
932 buf
->st_blocks
= (inode
->size
+ RECORDSIZE
- 1) / RECORDSIZE
;
934 buf
->st_atime
= inode
->atime
;
935 buf
->st_mtime
= inode
->mtime
;
936 buf
->st_ctime
= inode
->ctime
;
939 static int s_internal_stat (char *path
, struct stat
*buf
, int resolve
)
941 struct archive
*archive
;
946 if ((q
= get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
948 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
951 if (resolve
&& (entry
= my_resolve_symlinks (entry
)) == NULL
)
953 inode
= entry
->inode
;
954 stat_move( buf
, inode
);
958 static int s_stat (vfs
*me
, char *path
, struct stat
*buf
)
960 return s_internal_stat (path
, buf
, 1);
963 static int s_lstat (vfs
*me
, char *path
, struct stat
*buf
)
965 return s_internal_stat (path
, buf
, 0);
968 static int s_fstat (void *data
, struct stat
*buf
)
970 struct pseudofile
*file
= (struct pseudofile
*)data
;
973 inode
= file
->entry
->inode
;
974 stat_move( buf
, inode
);
978 static int s_readlink (vfs
*me
, char *path
, char *buf
, int size
)
980 struct archive
*archive
;
985 if ((q
= get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
987 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
990 if (!S_ISLNK (entry
->inode
->mode
)) ERRNOR (EINVAL
, -1);
991 if (size
> (i
= strlen (entry
->inode
->linkname
))) {
994 strncpy (buf
, entry
->inode
->linkname
, i
);
998 static int extfs_chmod (vfs
*me
, char *path
, int mode
)
1003 static int extfs_write (void *data
, char *buf
, int nbyte
)
1005 struct pseudofile
*file
= (struct pseudofile
*)data
;
1007 file
->has_changed
= 1;
1008 return write (file
->local_handle
, buf
, nbyte
);
1011 static int extfs_unlink (vfs
*me
, char *file
)
1013 struct archive
*archive
;
1016 struct entry
*entry
;
1018 char *archive_name
, *p
;
1020 if ((q
= get_path_mangle (file
, &archive
, 0, 0)) == NULL
)
1022 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
1025 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
1027 if (S_ISDIR (entry
->inode
->mode
)) ERRNOR (EISDIR
, -1);
1029 p
= get_path_from_entry (entry
);
1030 q
= name_quote (p
, 0);
1032 archive_name
= name_quote (get_archive_name (archive
), 0);
1034 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
1035 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
1036 " rm ", archive_name
, " ", q
, NULL
);
1038 g_free (mc_extfsdir
);
1039 g_free (archive_name
);
1040 if (my_system (EXECUTE_AS_SHELL
, shell
, cmd
)){
1046 remove_entry (entry
);
1051 static int extfs_mkdir (vfs
*me
, char *path
, mode_t mode
)
1053 struct archive
*archive
;
1056 struct entry
*entry
;
1058 char *archive_name
, *p
;
1060 if ((q
= get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
1062 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
1063 if (entry
!= NULL
) ERRNOR (EEXIST
, -1);
1064 entry
= find_entry (archive
->root_entry
, q
, 1, 0);
1067 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
1069 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, -1);
1071 p
= get_path_from_entry (entry
);
1072 q
= name_quote (p
, 0);
1074 archive_name
= name_quote (get_archive_name (archive
), 0);
1076 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
1077 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
1078 " mkdir ", archive_name
, " ", q
, NULL
);
1080 g_free (mc_extfsdir
);
1081 g_free (archive_name
);
1082 if (my_system (EXECUTE_AS_SHELL
, shell
, cmd
)){
1085 remove_entry (entry
);
1093 static int extfs_rmdir (vfs
*me
, char *path
)
1095 struct archive
*archive
;
1098 struct entry
*entry
;
1100 char *archive_name
, *p
;
1102 if ((q
= get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
1104 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
1107 if ((entry
= my_resolve_symlinks (entry
)) == NULL
)
1109 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, -1);
1111 p
= get_path_from_entry (entry
);
1112 q
= name_quote (p
, 0);
1114 archive_name
= name_quote (get_archive_name (archive
), 0);
1116 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs/");
1117 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
1118 " rmdir ", archive_name
, " ", q
, NULL
);
1120 g_free (mc_extfsdir
);
1121 g_free (archive_name
);
1122 if (my_system (EXECUTE_AS_SHELL
, shell
, cmd
)){
1128 remove_entry (entry
);
1133 static int extfs_chdir (vfs
*me
, char *path
)
1135 struct archive
*archive
;
1137 struct entry
*entry
;
1140 if ((q
= get_path_mangle (path
, &archive
, 1, 0)) == NULL
)
1142 entry
= find_entry (archive
->root_entry
, q
, 0, 0);
1145 entry
= my_resolve_symlinks (entry
);
1146 if ((!entry
) || (!S_ISDIR (entry
->inode
->mode
)))
1148 entry
->inode
->archive
->current_dir
= entry
;
1153 static int extfs_lseek (void *data
, off_t offset
, int whence
)
1155 struct pseudofile
*file
= (struct pseudofile
*) data
;
1157 return lseek (file
->local_handle
, offset
, whence
);
1160 static vfsid
extfs_getid (vfs
*me
, char *path
, struct vfs_stamping
**parent
)
1162 struct archive
*archive
;
1165 struct vfs_stamping
*par
;
1169 if (!(p
= get_path (path
, &archive
, 1, 1)))
1173 v
= vfs_type (archive
->name
);
1174 id
= (*v
->getid
) (v
, archive
->name
, &par
);
1175 if (id
!= (vfsid
)-1) {
1176 *parent
= g_new (struct vfs_stamping
, 1);
1179 (*parent
)->parent
= par
;
1180 (*parent
)->next
= NULL
;
1183 return (vfsid
) archive
;
1186 static int extfs_nothingisopen (vfsid id
)
1188 if (((struct archive
*)id
)->fd_usage
<= 0)
1193 static void remove_entry (struct entry
*e
)
1195 int i
= --(e
->inode
->nlink
);
1196 struct entry
*pe
, *ent
, *prev
;
1198 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
1199 struct entry
*f
= e
->inode
->first_in_subdir
;
1200 e
->inode
->first_in_subdir
= NULL
;
1204 if (e
== pe
->inode
->first_in_subdir
)
1205 pe
->inode
->first_in_subdir
= e
->next_in_dir
;
1208 for (ent
= pe
->inode
->first_in_subdir
; ent
&& ent
->next_in_dir
;
1209 ent
= ent
->next_in_dir
)
1210 if (e
== ent
->next_in_dir
) {
1215 prev
->next_in_dir
= e
->next_in_dir
;
1216 if (e
== pe
->inode
->last_in_subdir
)
1217 pe
->inode
->last_in_subdir
= prev
;
1220 if (e
->inode
->local_filename
!= NULL
) {
1221 unlink (e
->inode
->local_filename
);
1222 free (e
->inode
->local_filename
);
1224 if (e
->inode
->linkname
!= NULL
)
1225 g_free (e
->inode
->linkname
);
1233 static void free_entry (struct entry
*e
)
1235 int i
= --(e
->inode
->nlink
);
1236 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
1237 struct entry
*f
= e
->inode
->first_in_subdir
;
1239 e
->inode
->first_in_subdir
= NULL
;
1243 if (e
->inode
->local_filename
!= NULL
) {
1244 unlink (e
->inode
->local_filename
);
1245 free (e
->inode
->local_filename
);
1247 if (e
->inode
->linkname
!= NULL
)
1248 g_free (e
->inode
->linkname
);
1251 if (e
->next_in_dir
!= NULL
)
1252 free_entry (e
->next_in_dir
);
1257 static void extfs_free (vfsid id
)
1259 struct archive
*parc
;
1260 struct archive
*archive
= (struct archive
*)id
;
1262 free_entry (archive
->root_entry
);
1263 if (archive
== first_archive
) {
1264 first_archive
= archive
->next
;
1266 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
1267 if (parc
->next
== archive
)
1270 parc
->next
= archive
->next
;
1272 free_archive (archive
);
1275 static char *extfs_getlocalcopy (vfs
*me
, char *path
)
1277 struct pseudofile
*fp
=
1278 (struct pseudofile
*) extfs_open (me
, path
, O_RDONLY
, 0);
1283 if (fp
->entry
->inode
->local_filename
== NULL
) {
1284 extfs_close ((void *) fp
);
1287 p
= g_strdup (fp
->entry
->inode
->local_filename
);
1288 fp
->archive
->fd_usage
++;
1289 extfs_close ((void *) fp
);
1293 static int extfs_ungetlocalcopy (vfs
*me
, char *path
, char *local
, int has_changed
)
1295 struct pseudofile
*fp
=
1296 (struct pseudofile
*) extfs_open (me
, path
, O_RDONLY
, 0);
1300 if (!strcmp (fp
->entry
->inode
->local_filename
, local
)) {
1301 fp
->archive
->fd_usage
--;
1302 fp
->has_changed
|= has_changed
;
1303 extfs_close ((void *) fp
);
1306 /* Should not happen */
1307 extfs_close ((void *) fp
);
1308 return mc_def_ungetlocalcopy (me
, path
, local
, has_changed
);
1313 #include "../src/profile.h"
1314 static int extfs_init (vfs
*me
)
1319 mc_extfsini
= concat_dir_and_file (mc_home
, "extfs/extfs.ini");
1320 cfg
= fopen (mc_extfsini
, "r");
1323 fprintf(stderr
, _("Warning: file %s not found\n"), mc_extfsini
);
1324 g_free (mc_extfsini
);
1329 while ( extfs_no
< MAXEXTFS
) {
1333 if (!fgets( key
, sizeof (key
)-1, cfg
))
1336 /* Handle those with a trailing ':', those flag that the
1337 * file system does not require an archive to work
1341 /* We may not use vfs_die() message or message_1s or similar,
1342 * UI is not initialized at this time and message would not
1343 * appear on screen. */
1344 fprintf(stderr
, "Warning: You need to update your %s file.\n",
1347 g_free (mc_extfsini
);
1353 if ((c
= strchr (key
, '\n'))){
1355 c
= &key
[strlen (key
) - 1];
1359 extfs_need_archive
[extfs_no
] = !(*c
== ':');
1365 extfs_prefixes
[extfs_no
] = g_strdup (key
);
1369 g_free (mc_extfsini
);
1373 /* Do NOT use me argument in this function */
1374 static int extfs_which (vfs
*me
, char *path
)
1378 for (i
= 0; i
< extfs_no
; i
++)
1379 if (!strcmp (path
, extfs_prefixes
[i
]))
1384 static void extfs_done (vfs
*me
)
1388 for (i
= 0; i
< extfs_no
; i
++ )
1389 g_free (extfs_prefixes
[i
]);
1393 static int extfs_setctl (vfs
*me
, char *path
, int ctlop
, char *arg
)
1395 if (ctlop
== MCCTL_EXTFS_RUN
) {
1402 vfs vfs_extfs_ops
= {
1403 NULL
, /* This is place of next pointer */
1429 extfs_chmod
, /* chmod ... strange, returns success? */
1446 extfs_nothingisopen
,
1450 extfs_ungetlocalcopy
,
1452 extfs_mkdir
, /* mkdir */