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: init_extfs */
29 #include <sys/types.h>
33 #ifdef HAVE_SYS_WAIT_H
38 #include "../src/execute.h" /* For shell_execute */
40 #include "gc.h" /* vfs_rmstamp */
43 #define ERRNOR(x,y) do { my_errno = x; return y; } while(0)
47 struct entry
*first_in_subdir
; /* only used if this is a directory */
48 struct entry
*last_in_subdir
;
49 ino_t inode
; /* This is inode # */
50 dev_t dev
; /* This is an internal identification of the extfs archive */
51 struct archive
*archive
; /* And this is an archive structure */
66 struct entry
*next_in_dir
;
73 struct archive
*archive
;
74 unsigned int has_changed
:1;
83 struct stat local_stat
;
87 struct entry
*root_entry
;
91 static struct entry
*extfs_find_entry (struct entry
*dir
, char *name
,
92 int make_dirs
, int make_file
);
93 static int extfs_which (struct vfs_class
*me
, char *path
);
94 static void extfs_remove_entry (struct entry
*e
);
95 static void extfs_free (vfsid id
);
97 static struct vfs_class vfs_extfs_ops
;
98 static struct archive
*first_archive
= NULL
;
99 static int my_errno
= 0;
102 static char *extfs_prefixes
[MAXEXTFS
];
103 static char extfs_need_archive
[MAXEXTFS
];
104 static int extfs_no
= 0;
107 extfs_fill_names (struct vfs_class
*me
, void (*func
) (char *))
109 struct archive
*a
= first_archive
;
114 g_strconcat (a
->name
? a
->name
: "", "#",
115 extfs_prefixes
[a
->fstype
], NULL
);
122 static void extfs_make_dots (struct entry
*ent
)
124 struct entry
*entry
= g_new (struct entry
, 1);
125 struct entry
*parentry
= ent
->dir
;
126 struct inode
*inode
= ent
->inode
, *parent
;
128 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
129 entry
->name
= g_strdup (".");
130 entry
->inode
= inode
;
132 inode
->local_filename
= NULL
;
133 inode
->first_in_subdir
= entry
;
134 inode
->last_in_subdir
= entry
;
136 entry
->next_in_dir
= g_new (struct entry
, 1);
137 entry
=entry
->next_in_dir
;
138 entry
->name
= g_strdup ("..");
139 inode
->last_in_subdir
= entry
;
140 entry
->next_in_dir
= NULL
;
141 if (parent
!= NULL
) {
142 entry
->inode
= parent
;
143 entry
->dir
= parentry
;
146 entry
->inode
= inode
;
152 static struct entry
*extfs_generate_entry (struct archive
*archive
,
153 char *name
, struct entry
*parentry
, mode_t mode
)
156 struct inode
*inode
, *parent
;
159 parent
= (parentry
!= NULL
) ? parentry
->inode
: NULL
;
160 entry
= g_new (struct entry
, 1);
162 entry
->name
= g_strdup (name
);
163 entry
->next_in_dir
= NULL
;
164 entry
->dir
= parentry
;
165 if (parent
!= NULL
) {
166 parent
->last_in_subdir
->next_in_dir
= entry
;
167 parent
->last_in_subdir
= entry
;
169 inode
= g_new (struct inode
, 1);
170 entry
->inode
= inode
;
171 inode
->local_filename
= NULL
;
173 inode
->inode
= (archive
->inode_counter
)++;
174 inode
->dev
= archive
->rdev
;
175 inode
->archive
= archive
;
176 myumask
= umask (022);
178 inode
->mode
= mode
& ~myumask
;
181 inode
->uid
= getuid ();
182 inode
->gid
= getgid ();
184 inode
->mtime
= time (NULL
);
185 inode
->atime
= inode
->mtime
;
186 inode
->ctime
= inode
->mtime
;
189 extfs_make_dots (entry
);
193 static void extfs_free_entries (struct entry
*entry
)
198 static void extfs_free_archive (struct archive
*archive
)
200 extfs_free_entries (archive
->root_entry
);
201 if (archive
->local_name
!= NULL
) {
204 mc_stat (archive
->local_name
, &my
);
205 mc_ungetlocalcopy (archive
->name
, archive
->local_name
,
206 archive
->local_stat
.st_mtime
!= my
.st_mtime
);
207 /* mc_ungetlocalcopy() frees local_name for us */
210 g_free (archive
->name
);
215 extfs_open_archive (int fstype
, const char *name
, struct archive
**pparc
)
217 static dev_t archive_counter
= 0;
223 struct archive
*current_archive
;
224 struct entry
*root_entry
;
225 char *local_name
= NULL
, *tmp
= 0;
226 int uses_archive
= extfs_need_archive
[fstype
];
229 if (mc_stat (name
, &mystat
) == -1)
231 if (!vfs_file_is_local (name
)) {
232 local_name
= mc_getlocalcopy (name
);
233 if (local_name
== NULL
)
236 tmp
= name_quote (name
, 0);
239 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs" PATH_SEP_STR
);
241 g_strconcat (mc_extfsdir
, extfs_prefixes
[fstype
], " list ",
242 local_name
? local_name
: tmp
, NULL
);
245 g_free (mc_extfsdir
);
247 result
= popen (cmd
, "r");
249 if (result
== NULL
) {
250 close_error_pipe (1, NULL
);
252 mc_ungetlocalcopy (name
, local_name
, 0);
256 current_archive
= g_new (struct archive
, 1);
257 current_archive
->fstype
= fstype
;
258 current_archive
->name
= name
? g_strdup (name
) : NULL
;
259 current_archive
->local_name
= local_name
;
261 if (local_name
!= NULL
)
262 mc_stat (local_name
, ¤t_archive
->local_stat
);
263 current_archive
->inode_counter
= 0;
264 current_archive
->fd_usage
= 0;
265 current_archive
->rdev
= archive_counter
++;
266 current_archive
->next
= first_archive
;
267 first_archive
= current_archive
;
268 mode
= mystat
.st_mode
& 07777;
276 root_entry
= extfs_generate_entry (current_archive
, "/", NULL
, mode
);
277 root_entry
->inode
->uid
= mystat
.st_uid
;
278 root_entry
->inode
->gid
= mystat
.st_gid
;
279 root_entry
->inode
->atime
= mystat
.st_atime
;
280 root_entry
->inode
->ctime
= mystat
.st_ctime
;
281 root_entry
->inode
->mtime
= mystat
.st_mtime
;
282 current_archive
->root_entry
= root_entry
;
284 *pparc
= current_archive
;
290 * Main loop for reading an archive.
291 * Return 0 on success, -1 on error.
294 extfs_read_archive (int fstype
, const char *name
, struct archive
**pparc
)
298 struct archive
*current_archive
;
299 char *current_file_name
, *current_link_name
;
302 extfs_open_archive (fstype
, name
, ¤t_archive
)) == NULL
) {
303 message (1, MSG_ERROR
, _("Cannot open %s archive\n%s"),
304 extfs_prefixes
[fstype
], name
);
308 buffer
= g_malloc (4096);
309 while (fgets (buffer
, 4096, extfsd
) != NULL
) {
312 current_link_name
= NULL
;
314 (buffer
, &hstat
, ¤t_file_name
, ¤t_link_name
)) {
315 struct entry
*entry
, *pent
;
317 char *p
, *q
, *cfn
= current_file_name
;
323 if (p
!= cfn
&& *(p
- 1) == '/')
325 p
= strrchr (cfn
, '/');
333 if (S_ISDIR (hstat
.st_mode
)
334 && (!strcmp (p
, ".") || !strcmp (p
, "..")))
335 goto read_extfs_continue
;
337 extfs_find_entry (current_archive
->root_entry
, q
, 1,
340 /* FIXME: Should clean everything one day */
343 close_error_pipe (1, _("Inconsistent extfs archive"));
346 entry
= g_new (struct entry
, 1);
347 entry
->name
= g_strdup (p
);
348 entry
->next_in_dir
= NULL
;
351 if (pent
->inode
->last_in_subdir
) {
352 pent
->inode
->last_in_subdir
->next_in_dir
= entry
;
353 pent
->inode
->last_in_subdir
= entry
;
356 if (!S_ISLNK (hstat
.st_mode
) && current_link_name
!= NULL
) {
358 extfs_find_entry (current_archive
->root_entry
,
359 current_link_name
, 0, 0);
361 /* FIXME: Should clean everything one day */
365 _("Inconsistent extfs archive"));
368 entry
->inode
= pent
->inode
;
369 pent
->inode
->nlink
++;
372 inode
= g_new (struct inode
, 1);
373 entry
->inode
= inode
;
374 inode
->local_filename
= NULL
;
375 inode
->inode
= (current_archive
->inode_counter
)++;
377 inode
->dev
= current_archive
->rdev
;
378 inode
->archive
= current_archive
;
379 inode
->mode
= hstat
.st_mode
;
380 #ifdef HAVE_STRUCT_STAT_ST_RDEV
381 inode
->rdev
= hstat
.st_rdev
;
385 inode
->uid
= hstat
.st_uid
;
386 inode
->gid
= hstat
.st_gid
;
387 inode
->size
= hstat
.st_size
;
388 inode
->mtime
= hstat
.st_mtime
;
389 inode
->atime
= hstat
.st_atime
;
390 inode
->ctime
= hstat
.st_ctime
;
391 if (current_link_name
!= NULL
392 && S_ISLNK (hstat
.st_mode
)) {
393 inode
->linkname
= current_link_name
;
394 current_link_name
= NULL
;
396 if (S_ISLNK (hstat
.st_mode
))
397 inode
->mode
&= ~S_IFLNK
; /* You *DON'T* want to do this always */
398 inode
->linkname
= NULL
;
400 if (S_ISDIR (hstat
.st_mode
))
401 extfs_make_dots (entry
);
405 g_free (current_file_name
);
406 if (current_link_name
!= NULL
)
407 g_free (current_link_name
);
411 /* Check if extfs 'list' returned 0 */
412 if (pclose (extfsd
) != 0) {
414 extfs_free (current_archive
);
415 close_error_pipe (1, _("Inconsistent extfs archive"));
419 close_error_pipe (1, NULL
);
420 *pparc
= current_archive
;
426 * Dissect the path and create corresponding superblock. Note that inname
427 * can be changed and the result may point inside the original string.
430 extfs_get_path_mangle (char *inname
, struct archive
**archive
, int is_dir
,
434 const char *archive_name
;
436 struct archive
*parc
;
439 archive_name
= inname
;
440 vfs_split (inname
, &local
, &op
);
443 * FIXME: we really should pass self pointer. But as we know that
444 * extfs_which does not touch struct vfs_class *me, it does not matter for now
446 fstype
= extfs_which (NULL
, op
);
454 * All filesystems should have some local archive, at least
457 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
459 if (!strcmp (parc
->name
, archive_name
)) {
460 vfs_stamp (&vfs_extfs_ops
, (vfsid
) parc
);
466 do_not_open
? -1 : extfs_read_archive (fstype
, archive_name
,
478 * Dissect the path and create corresponding superblock.
479 * The result should be freed.
482 extfs_get_path (const char *inname
, struct archive
**archive
, int is_dir
,
485 char *buf
= g_strdup (inname
);
486 char *res
= extfs_get_path_mangle (buf
, archive
, is_dir
, do_not_open
);
489 res2
= g_strdup (res
);
495 /* Return allocated path (without leading slash) inside the archive */
496 static char *extfs_get_path_from_entry (struct entry
*entry
)
505 for (len
= 0, head
= 0; entry
->dir
; entry
= entry
->dir
) {
506 p
= g_new (struct list
, 1);
508 p
->name
= entry
->name
;
510 len
+= strlen (entry
->name
) + 1;
514 return g_strdup ("");
516 localpath
= g_malloc (len
);
519 strcat (localpath
, head
->name
);
521 strcat (localpath
, "/");
530 struct loop_protect
{
532 struct loop_protect
*next
;
537 static struct entry
*
538 extfs_find_entry_int (struct entry
*dir
, char *name
,
539 struct loop_protect
*list
, int make_dirs
, int make_file
);
541 static struct entry
*
542 extfs_resolve_symlinks_int (struct entry
*entry
,
543 struct loop_protect
*list
)
546 struct loop_protect
*looping
;
548 if (!S_ISLNK (entry
->inode
->mode
))
550 for (looping
= list
; looping
!= NULL
; looping
= looping
->next
)
551 if (entry
== looping
->entry
) { /* Here we protect us against symlink looping */
555 looping
= g_new (struct loop_protect
, 1);
556 looping
->entry
= entry
;
557 looping
->next
= list
;
558 pent
= extfs_find_entry_int (entry
->dir
, entry
->inode
->linkname
, looping
, 0, 0);
565 static struct entry
*extfs_resolve_symlinks (struct entry
*entry
)
571 res
= extfs_resolve_symlinks_int (entry
, NULL
);
581 static char *extfs_get_archive_name (struct archive
*archive
)
585 if (archive
->local_name
)
586 archive_name
= archive
->local_name
;
588 archive_name
= archive
->name
;
590 if (!archive_name
|| !*archive_name
)
591 return "no_archive_name";
596 /* Don't pass localname as NULL */
598 extfs_cmd (const char *extfs_cmd
, struct archive
*archive
,
599 struct entry
*entry
, const char *localname
)
603 char *quoted_localname
;
609 file
= extfs_get_path_from_entry (entry
);
610 quoted_file
= name_quote (file
, 0);
612 archive_name
= name_quote (extfs_get_archive_name (archive
), 0);
613 quoted_localname
= name_quote (localname
, 0);
615 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs" PATH_SEP_STR
);
616 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
617 extfs_cmd
, archive_name
, " ", quoted_file
, " ",
618 quoted_localname
, NULL
);
619 g_free (quoted_file
);
620 g_free (quoted_localname
);
621 g_free (mc_extfsdir
);
622 g_free (archive_name
);
625 retval
= my_system (EXECUTE_AS_SHELL
, shell
, cmd
);
627 close_error_pipe (1, NULL
);
632 extfs_run (char *file
)
634 struct archive
*archive
;
635 char *p
, *q
, *archive_name
, *mc_extfsdir
;
638 if ((p
= extfs_get_path (file
, &archive
, 0, 0)) == NULL
)
640 q
= name_quote (p
, 0);
643 archive_name
= name_quote (extfs_get_archive_name (archive
), 0);
644 mc_extfsdir
= concat_dir_and_file (mc_home
, "extfs" PATH_SEP_STR
);
645 cmd
= g_strconcat (mc_extfsdir
, extfs_prefixes
[archive
->fstype
],
646 " run ", archive_name
, " ", q
, NULL
);
647 g_free (mc_extfsdir
);
648 g_free (archive_name
);
650 shell_execute (cmd
, 0);
655 extfs_open (struct vfs_class
*me
, const char *file
, int flags
, int mode
)
657 struct pseudofile
*extfs_info
;
658 struct archive
*archive
;
664 if ((q
= extfs_get_path (file
, &archive
, 0, 0)) == NULL
)
666 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
667 if (entry
== NULL
&& (flags
& O_CREAT
)) {
668 /* Create new entry */
669 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 1);
670 created
= (entry
!= NULL
);
676 if ((entry
= extfs_resolve_symlinks (entry
)) == NULL
)
679 if (S_ISDIR (entry
->inode
->mode
))
680 ERRNOR (EISDIR
, NULL
);
682 if (entry
->inode
->local_filename
== NULL
) {
683 char *local_filename
;
685 local_handle
= vfs_mkstemps (&local_filename
, "extfs", entry
->name
);
687 if (local_handle
== -1)
689 close (local_handle
);
691 if (!created
&& !(flags
& O_TRUNC
)
692 && extfs_cmd (" copyout ", archive
, entry
, local_filename
)) {
693 unlink (local_filename
);
694 free (local_filename
);
698 entry
->inode
->local_filename
= local_filename
;
702 open (entry
->inode
->local_filename
, NO_LINEAR (flags
), mode
);
703 if (local_handle
== -1)
706 extfs_info
= g_new (struct pseudofile
, 1);
707 extfs_info
->archive
= archive
;
708 extfs_info
->entry
= entry
;
709 extfs_info
->has_changed
= created
;
710 extfs_info
->local_handle
= local_handle
;
712 /* i.e. we had no open files and now we have one */
713 vfs_rmstamp (&vfs_extfs_ops
, (vfsid
) archive
);
718 static int extfs_read (void *data
, char *buffer
, int count
)
720 struct pseudofile
*file
= (struct pseudofile
*)data
;
722 return read (file
->local_handle
, buffer
, count
);
726 extfs_close (void *data
)
728 struct pseudofile
*file
;
730 file
= (struct pseudofile
*) data
;
732 close (file
->local_handle
);
734 /* Commit the file if it has changed */
735 if (file
->has_changed
) {
737 (" copyin ", file
->archive
, file
->entry
,
738 file
->entry
->inode
->local_filename
))
741 struct stat file_status
;
742 if (stat (file
->entry
->inode
->local_filename
, &file_status
) !=
746 file
->entry
->inode
->size
= file_status
.st_size
;
749 file
->entry
->inode
->mtime
= time (NULL
);
752 file
->archive
->fd_usage
--;
753 if (!file
->archive
->fd_usage
)
754 vfs_stamp_create (&vfs_extfs_ops
, file
->archive
);
762 #define RECORDSIZE 512
765 extfs_find_entry_int (struct entry
*dir
, char *name
,
766 struct loop_protect
*list
, int make_dirs
, int make_file
)
768 struct entry
*pent
, *pdir
;
769 char *p
, *q
, *name_end
;
772 if (*name
== '/') { /* Handle absolute paths */
774 dir
= dir
->inode
->archive
->root_entry
;
779 name_end
= name
+ strlen (name
);
785 for (; pent
!= NULL
&& c
&& *p
; ){
789 if (strcmp (p
, ".")){
790 if (!strcmp (p
, ".."))
793 if ((pent
= extfs_resolve_symlinks_int (pent
, list
))==NULL
){
797 if (!S_ISDIR (pent
->inode
->mode
)){
803 for (pent
= pent
->inode
->first_in_subdir
; pent
; pent
= pent
->next_in_dir
)
804 /* Hack: I keep the original semanthic unless
805 q+1 would break in the strchr */
806 if (!strcmp (pent
->name
, p
)){
807 if (q
+ 1 > name_end
){
809 notadir
= !S_ISDIR (pent
->inode
->mode
);
815 /* When we load archive, we create automagically
816 * non-existant directories
818 if (pent
== NULL
&& make_dirs
) {
819 pent
= extfs_generate_entry (dir
->inode
->archive
, p
, pdir
, S_IFDIR
| 0777);
821 if (pent
== NULL
&& make_file
) {
822 pent
= extfs_generate_entry (dir
->inode
->archive
, p
, pdir
, S_IFREG
| 0666);
838 static struct entry
*extfs_find_entry (struct entry
*dir
, char *name
, int make_dirs
, int make_file
)
844 res
= extfs_find_entry_int (dir
, name
, NULL
, make_dirs
, make_file
);
855 static int extfs_errno (struct vfs_class
*me
)
860 static void * extfs_opendir (struct vfs_class
*me
, const char *dirname
)
862 struct archive
*archive
;
867 if ((q
= extfs_get_path (dirname
, &archive
, 1, 0)) == NULL
)
869 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
873 if ((entry
= extfs_resolve_symlinks (entry
)) == NULL
)
875 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, NULL
);
877 info
= g_new (struct entry
*, 2);
878 info
[0] = entry
->inode
->first_in_subdir
;
879 info
[1] = entry
->inode
->first_in_subdir
;
884 static void * extfs_readdir(void *data
)
886 static union vfs_dirent dir
;
887 struct entry
**info
= (struct entry
**) data
;
892 strncpy(dir
.dent
.d_name
, (*info
)->name
, MC_MAXPATHLEN
);
893 dir
.dent
.d_name
[MC_MAXPATHLEN
] = 0;
895 compute_namelen(&dir
.dent
);
896 *info
= (*info
)->next_in_dir
;
898 return (void *) &dir
;
901 static int extfs_closedir (void *data
)
907 static void extfs_stat_move( struct stat
*buf
, struct inode
*inode
)
909 buf
->st_dev
= inode
->dev
;
910 buf
->st_ino
= inode
->inode
;
911 buf
->st_mode
= inode
->mode
;
912 buf
->st_nlink
= inode
->nlink
;
913 buf
->st_uid
= inode
->uid
;
914 buf
->st_gid
= inode
->gid
;
915 #ifdef HAVE_STRUCT_STAT_ST_RDEV
916 buf
->st_rdev
= inode
->rdev
;
918 buf
->st_size
= inode
->size
;
919 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
920 buf
->st_blksize
= RECORDSIZE
;
922 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
923 buf
->st_blocks
= (inode
->size
+ RECORDSIZE
- 1) / RECORDSIZE
;
925 buf
->st_atime
= inode
->atime
;
926 buf
->st_mtime
= inode
->mtime
;
927 buf
->st_ctime
= inode
->ctime
;
930 static int extfs_internal_stat (char *path
, struct stat
*buf
, int resolve
)
932 struct archive
*archive
;
937 if ((q
= extfs_get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
939 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
942 if (resolve
&& (entry
= extfs_resolve_symlinks (entry
)) == NULL
)
944 inode
= entry
->inode
;
945 extfs_stat_move( buf
, inode
);
949 static int extfs_stat (struct vfs_class
*me
, char *path
, struct stat
*buf
)
951 return extfs_internal_stat (path
, buf
, 1);
954 static int extfs_lstat (struct vfs_class
*me
, char *path
, struct stat
*buf
)
956 return extfs_internal_stat (path
, buf
, 0);
959 static int extfs_fstat (void *data
, struct stat
*buf
)
961 struct pseudofile
*file
= (struct pseudofile
*)data
;
964 inode
= file
->entry
->inode
;
965 extfs_stat_move( buf
, inode
);
970 extfs_readlink (struct vfs_class
*me
, char *path
, char *buf
, int size
)
972 struct archive
*archive
;
977 if ((q
= extfs_get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
979 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
982 if (!S_ISLNK (entry
->inode
->mode
))
984 if (size
< (i
= strlen (entry
->inode
->linkname
))) {
987 strncpy (buf
, entry
->inode
->linkname
, i
);
991 static int extfs_chmod (struct vfs_class
*me
, char *path
, int mode
)
996 static int extfs_write (void *data
, char *buf
, int nbyte
)
998 struct pseudofile
*file
= (struct pseudofile
*)data
;
1000 file
->has_changed
= 1;
1001 return write (file
->local_handle
, buf
, nbyte
);
1004 static int extfs_unlink (struct vfs_class
*me
, char *file
)
1006 struct archive
*archive
;
1008 struct entry
*entry
;
1010 if ((q
= extfs_get_path_mangle (file
, &archive
, 0, 0)) == NULL
)
1012 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
1015 if ((entry
= extfs_resolve_symlinks (entry
)) == NULL
)
1017 if (S_ISDIR (entry
->inode
->mode
)) ERRNOR (EISDIR
, -1);
1019 if (extfs_cmd (" rm ", archive
, entry
, "")){
1023 extfs_remove_entry (entry
);
1028 static int extfs_mkdir (struct vfs_class
*me
, char *path
, mode_t mode
)
1030 struct archive
*archive
;
1032 struct entry
*entry
;
1034 if ((q
= extfs_get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
1036 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
1037 if (entry
!= NULL
) ERRNOR (EEXIST
, -1);
1038 entry
= extfs_find_entry (archive
->root_entry
, q
, 1, 0);
1041 if ((entry
= extfs_resolve_symlinks (entry
)) == NULL
)
1043 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, -1);
1045 if (extfs_cmd (" mkdir ", archive
, entry
, "")){
1047 extfs_remove_entry (entry
);
1054 static int extfs_rmdir (struct vfs_class
*me
, char *path
)
1056 struct archive
*archive
;
1058 struct entry
*entry
;
1060 if ((q
= extfs_get_path_mangle (path
, &archive
, 0, 0)) == NULL
)
1062 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
1065 if ((entry
= extfs_resolve_symlinks (entry
)) == NULL
)
1067 if (!S_ISDIR (entry
->inode
->mode
)) ERRNOR (ENOTDIR
, -1);
1069 if (extfs_cmd (" rmdir ", archive
, entry
, "")){
1073 extfs_remove_entry (entry
);
1079 extfs_chdir (struct vfs_class
*me
, const char *path
)
1081 struct archive
*archive
;
1083 struct entry
*entry
;
1086 if ((q
= extfs_get_path (path
, &archive
, 1, 0)) == NULL
)
1088 entry
= extfs_find_entry (archive
->root_entry
, q
, 0, 0);
1092 entry
= extfs_resolve_symlinks (entry
);
1093 if ((!entry
) || (!S_ISDIR (entry
->inode
->mode
)))
1099 static int extfs_lseek (void *data
, off_t offset
, int whence
)
1101 struct pseudofile
*file
= (struct pseudofile
*) data
;
1103 return lseek (file
->local_handle
, offset
, whence
);
1107 extfs_getid (struct vfs_class
*me
, const char *path
)
1109 struct archive
*archive
;
1112 if (!(p
= extfs_get_path (path
, &archive
, 1, 1)))
1115 return (vfsid
) archive
;
1118 static int extfs_nothingisopen (vfsid id
)
1120 if (((struct archive
*)id
)->fd_usage
<= 0)
1125 static void extfs_remove_entry (struct entry
*e
)
1127 int i
= --(e
->inode
->nlink
);
1128 struct entry
*pe
, *ent
, *prev
;
1130 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
1131 struct entry
*f
= e
->inode
->first_in_subdir
;
1132 e
->inode
->first_in_subdir
= NULL
;
1133 extfs_remove_entry (f
);
1136 if (e
== pe
->inode
->first_in_subdir
)
1137 pe
->inode
->first_in_subdir
= e
->next_in_dir
;
1140 for (ent
= pe
->inode
->first_in_subdir
; ent
&& ent
->next_in_dir
;
1141 ent
= ent
->next_in_dir
)
1142 if (e
== ent
->next_in_dir
) {
1147 prev
->next_in_dir
= e
->next_in_dir
;
1148 if (e
== pe
->inode
->last_in_subdir
)
1149 pe
->inode
->last_in_subdir
= prev
;
1152 if (e
->inode
->local_filename
!= NULL
) {
1153 unlink (e
->inode
->local_filename
);
1154 free (e
->inode
->local_filename
);
1156 if (e
->inode
->linkname
!= NULL
)
1157 g_free (e
->inode
->linkname
);
1165 static void extfs_free_entry (struct entry
*e
)
1167 int i
= --(e
->inode
->nlink
);
1168 if (S_ISDIR (e
->inode
->mode
) && e
->inode
->first_in_subdir
!= NULL
) {
1169 struct entry
*f
= e
->inode
->first_in_subdir
;
1171 e
->inode
->first_in_subdir
= NULL
;
1172 extfs_free_entry (f
);
1175 if (e
->inode
->local_filename
!= NULL
) {
1176 unlink (e
->inode
->local_filename
);
1177 free (e
->inode
->local_filename
);
1179 if (e
->inode
->linkname
!= NULL
)
1180 g_free (e
->inode
->linkname
);
1183 if (e
->next_in_dir
!= NULL
)
1184 extfs_free_entry (e
->next_in_dir
);
1189 static void extfs_free (vfsid id
)
1191 struct archive
*parc
;
1192 struct archive
*archive
= (struct archive
*)id
;
1194 extfs_free_entry (archive
->root_entry
);
1195 if (archive
== first_archive
) {
1196 first_archive
= archive
->next
;
1198 for (parc
= first_archive
; parc
!= NULL
; parc
= parc
->next
)
1199 if (parc
->next
== archive
)
1202 parc
->next
= archive
->next
;
1204 extfs_free_archive (archive
);
1208 extfs_getlocalcopy (struct vfs_class
*me
, const char *path
)
1210 struct pseudofile
*fp
=
1211 (struct pseudofile
*) extfs_open (me
, path
, O_RDONLY
, 0);
1216 if (fp
->entry
->inode
->local_filename
== NULL
) {
1217 extfs_close ((void *) fp
);
1220 p
= g_strdup (fp
->entry
->inode
->local_filename
);
1221 fp
->archive
->fd_usage
++;
1222 extfs_close ((void *) fp
);
1227 extfs_ungetlocalcopy (struct vfs_class
*me
, const char *path
,
1228 const char *local
, int has_changed
)
1230 struct pseudofile
*fp
=
1231 (struct pseudofile
*) extfs_open (me
, path
, O_RDONLY
, 0);
1235 if (!strcmp (fp
->entry
->inode
->local_filename
, local
)) {
1236 fp
->archive
->fd_usage
--;
1237 fp
->has_changed
|= has_changed
;
1238 extfs_close ((void *) fp
);
1241 /* Should not happen */
1242 extfs_close ((void *) fp
);
1248 static int extfs_init (struct vfs_class
*me
)
1254 mc_extfsini
= concat_dir_and_file (mc_home
, "extfs" PATH_SEP_STR
"extfs.ini");
1255 cfg
= fopen (mc_extfsini
, "r");
1257 /* We may not use vfs_die() message or message or similar,
1258 * UI is not initialized at this time and message would not
1259 * appear on screen. */
1261 fprintf (stderr
, _("Warning: file %s not found\n"), mc_extfsini
);
1262 g_free (mc_extfsini
);
1267 while (extfs_no
< MAXEXTFS
&& fgets (key
, sizeof (key
), cfg
)) {
1270 /* Handle those with a trailing ':', those flag that the
1271 * file system does not require an archive to work
1275 fprintf(stderr
, "Warning: You need to update your %s file.\n",
1278 g_free (mc_extfsini
);
1281 if (*key
== '#' || *key
== '\n')
1284 if ((c
= strchr (key
, '\n'))){
1286 } else { /* Last line without newline or strlen (key) > 255 */
1287 c
= &key
[strlen (key
) - 1];
1289 extfs_need_archive
[extfs_no
] = !(*c
== ':');
1295 extfs_prefixes
[extfs_no
++] = g_strdup (key
);
1298 g_free (mc_extfsini
);
1302 /* Do NOT use me argument in this function */
1303 static int extfs_which (struct vfs_class
*me
, char *path
)
1307 for (i
= 0; i
< extfs_no
; i
++)
1308 if (!strcmp (path
, extfs_prefixes
[i
]))
1313 static void extfs_done (struct vfs_class
*me
)
1317 for (i
= 0; i
< extfs_no
; i
++ )
1318 g_free (extfs_prefixes
[i
]);
1323 extfs_setctl (struct vfs_class
*me
, char *path
, int ctlop
, void *arg
)
1325 if (ctlop
== VFS_SETCTL_RUN
) {
1335 vfs_extfs_ops
.name
= "extfs";
1336 vfs_extfs_ops
.init
= extfs_init
;
1337 vfs_extfs_ops
.done
= extfs_done
;
1338 vfs_extfs_ops
.fill_names
= extfs_fill_names
;
1339 vfs_extfs_ops
.which
= extfs_which
;
1340 vfs_extfs_ops
.open
= extfs_open
;
1341 vfs_extfs_ops
.close
= extfs_close
;
1342 vfs_extfs_ops
.read
= extfs_read
;
1343 vfs_extfs_ops
.write
= extfs_write
;
1344 vfs_extfs_ops
.opendir
= extfs_opendir
;
1345 vfs_extfs_ops
.readdir
= extfs_readdir
;
1346 vfs_extfs_ops
.closedir
= extfs_closedir
;
1347 vfs_extfs_ops
.stat
= extfs_stat
;
1348 vfs_extfs_ops
.lstat
= extfs_lstat
;
1349 vfs_extfs_ops
.fstat
= extfs_fstat
;
1350 vfs_extfs_ops
.chmod
= extfs_chmod
;
1351 vfs_extfs_ops
.readlink
= extfs_readlink
;
1352 vfs_extfs_ops
.unlink
= extfs_unlink
;
1353 vfs_extfs_ops
.chdir
= extfs_chdir
;
1354 vfs_extfs_ops
.ferrno
= extfs_errno
;
1355 vfs_extfs_ops
.lseek
= extfs_lseek
;
1356 vfs_extfs_ops
.getid
= extfs_getid
;
1357 vfs_extfs_ops
.nothingisopen
= extfs_nothingisopen
;
1358 vfs_extfs_ops
.free
= extfs_free
;
1359 vfs_extfs_ops
.getlocalcopy
= extfs_getlocalcopy
;
1360 vfs_extfs_ops
.ungetlocalcopy
= extfs_ungetlocalcopy
;
1361 vfs_extfs_ops
.mkdir
= extfs_mkdir
;
1362 vfs_extfs_ops
.rmdir
= extfs_rmdir
;
1363 vfs_extfs_ops
.setctl
= extfs_setctl
;
1364 vfs_register_class (&vfs_extfs_ops
);