4 Copyright (C) 1998-2017
5 Free Software Foundation, Inc.
8 Slava Zanko <slavazanko@gmail.com>, 2013
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * \brief Source: Single File fileSystem
30 * This defines whole class of filesystems which contain single file
31 * inside. It is somehow similar to extfs, except that extfs makes
32 * whole virtual trees and we do only single virtual files.
34 * If you want to gunzip something, you should open it with \verbatim #ugz \endverbatim
35 * suffix, DON'T try to gunzip it yourself.
37 * Namespace: exports vfs_sfs_ops
42 #include <sys/types.h>
47 #include "lib/global.h"
49 #include "lib/widget.h" /* D_ERROR, D_NORMAL */
51 #include "src/execute.h" /* EXECUTE_AS_SHELL */
53 #include "lib/vfs/vfs.h"
54 #include "lib/vfs/utilvfs.h"
55 #include "src/vfs/local/local.h"
56 #include "lib/vfs/gc.h" /* vfs_stamp_create */
60 /*** global variables ****************************************************************************/
62 /*** file scope macro definitions ****************************************************************/
68 #define F_NOLOCALCOPY 4
72 if ((size_t) (t - pad) > sizeof(pad)) \
80 #define COPY_STRING(a) \
81 if ((t - pad) + strlen(a) > sizeof(pad)) \
92 /*** file scope type declarations ****************************************************************/
94 typedef struct cachedfile
100 /*** file scope variables ************************************************************************/
103 static struct vfs_class vfs_sfs_ops
;
105 static int sfs_no
= 0;
106 static char *sfs_prefix
[MAXFS
];
107 static char *sfs_command
[MAXFS
];
108 static int sfs_flags
[MAXFS
];
110 /*** file scope functions ************************************************************************/
113 cachedfile_compare (const void *a
, const void *b
)
115 const cachedfile
*cf
= (const cachedfile
*) a
;
116 const char *name
= (const char *) b
;
118 return strcmp (name
, cf
->name
);
121 /* --------------------------------------------------------------------------------------------- */
124 sfs_vfmake (const vfs_path_t
* vpath
, vfs_path_t
* cache_vpath
)
128 char *s_iter
, *t
= pad
;
130 vfs_path_t
*pname
; /* name of parent archive */
131 char *pqname
; /* name of parent archive, quoted */
132 const vfs_path_element_t
*path_element
;
134 path_element
= vfs_path_get_by_index (vpath
, -1);
135 pname
= vfs_path_clone (vpath
);
136 vfs_path_remove_element_by_index (pname
, -1);
138 w
= (*path_element
->class->which
) (path_element
->class, path_element
->vfs_prefix
);
140 vfs_die ("This cannot happen... Hopefully.\n");
142 if ((sfs_flags
[w
] & F_1
) == 0 && strcmp (vfs_path_get_last_path_str (pname
), PATH_SEP_STR
) != 0)
144 vfs_path_free (pname
);
148 /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */
149 if ((sfs_flags
[w
] & F_NOLOCALCOPY
) == 0)
153 s
= mc_getlocalcopy (pname
);
156 vfs_path_free (pname
);
159 pqname
= name_quote (vfs_path_get_last_path_str (s
), FALSE
);
163 pqname
= name_quote (vfs_path_as_str (pname
), FALSE
);
165 vfs_path_free (pname
);
168 for (s_iter
= sfs_command
[w
]; *s_iter
!= '\0'; s_iter
++)
172 const char *ptr
= NULL
;
182 ptr
= path_element
->path
;
185 ptr
= vfs_path_get_by_index (cache_vpath
, -1)->path
;
209 if (my_system (EXECUTE_AS_SHELL
, "/bin/sh", pad
))
211 close_error_pipe (D_ERROR
, NULL
);
215 close_error_pipe (D_NORMAL
, NULL
);
219 /* --------------------------------------------------------------------------------------------- */
222 sfs_redirect (const vfs_path_t
* vpath
)
226 vfs_path_t
*cache_vpath
;
228 const vfs_path_element_t
*path_element
;
230 path_element
= vfs_path_get_by_index (vpath
, -1);
231 cur
= g_slist_find_custom (head
, vfs_path_as_str (vpath
), cachedfile_compare
);
235 cf
= (cachedfile
*) cur
->data
;
236 vfs_stamp (&vfs_sfs_ops
, cf
);
240 handle
= vfs_mkstemps (&cache_vpath
, "sfs", path_element
->path
);
243 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
247 if (sfs_vfmake (vpath
, cache_vpath
) == 0)
249 cf
= g_new (cachedfile
, 1);
250 cf
->name
= g_strdup (vfs_path_as_str (vpath
));
251 cf
->cache
= g_strdup (vfs_path_as_str (cache_vpath
));
252 head
= g_slist_prepend (head
, cf
);
253 vfs_path_free (cache_vpath
);
255 vfs_stamp_create (&vfs_sfs_ops
, (cachedfile
*) head
->data
);
259 mc_unlink (cache_vpath
);
260 vfs_path_free (cache_vpath
);
261 return "/I_MUST_NOT_EXIST";
264 /* --------------------------------------------------------------------------------------------- */
267 sfs_open (const vfs_path_t
* vpath
/*struct vfs_class *me, const char *path */ , int flags
,
273 fd
= open (sfs_redirect (vpath
), NO_LINEAR (flags
), mode
);
277 sfs_info
= g_new (int, 1);
283 /* --------------------------------------------------------------------------------------------- */
286 sfs_stat (const vfs_path_t
* vpath
, struct stat
*buf
)
288 return stat (sfs_redirect (vpath
), buf
);
291 /* --------------------------------------------------------------------------------------------- */
294 sfs_lstat (const vfs_path_t
* vpath
, struct stat
*buf
)
296 #ifndef HAVE_STATLSTAT
297 return lstat (sfs_redirect (vpath
), buf
);
299 return statlstat (sfs_redirect (vpath
), buf
);
303 /* --------------------------------------------------------------------------------------------- */
306 sfs_chmod (const vfs_path_t
* vpath
, mode_t mode
)
308 return chmod (sfs_redirect (vpath
), mode
);
311 /* --------------------------------------------------------------------------------------------- */
314 sfs_chown (const vfs_path_t
* vpath
, uid_t owner
, gid_t group
)
316 return chown (sfs_redirect (vpath
), owner
, group
);
319 /* --------------------------------------------------------------------------------------------- */
322 sfs_utime (const vfs_path_t
* vpath
, mc_timesbuf_t
* times
)
326 #ifdef HAVE_UTIMENSAT
327 ret
= utimensat (AT_FDCWD
, sfs_redirect (vpath
), *times
, 0);
329 ret
= utime (sfs_redirect (vpath
), times
);
334 /* --------------------------------------------------------------------------------------------- */
337 sfs_readlink (const vfs_path_t
* vpath
, char *buf
, size_t size
)
339 return readlink (sfs_redirect (vpath
), buf
, size
);
342 /* --------------------------------------------------------------------------------------------- */
345 sfs_getid (const vfs_path_t
* vpath
)
349 cur
= g_slist_find_custom (head
, vfs_path_as_str (vpath
), cachedfile_compare
);
351 return (vfsid
) (cur
!= NULL
? cur
->data
: NULL
);
354 /* --------------------------------------------------------------------------------------------- */
359 struct cachedfile
*which
;
362 which
= (struct cachedfile
*) id
;
363 cur
= g_slist_find (head
, which
);
365 vfs_die ("Free of thing which is unknown to me\n");
367 which
= (struct cachedfile
*) cur
->data
;
368 unlink (which
->cache
);
369 g_free (which
->cache
);
370 g_free (which
->name
);
373 head
= g_slist_delete_link (head
, cur
);
376 /* --------------------------------------------------------------------------------------------- */
379 sfs_fill_names (struct vfs_class
*me
, fill_names_f func
)
385 for (cur
= head
; cur
!= NULL
; cur
= g_slist_next (cur
))
386 func (((cachedfile
*) cur
->data
)->name
);
389 /* --------------------------------------------------------------------------------------------- */
392 sfs_nothingisopen (vfsid id
)
394 /* FIXME: Investigate whether have to guard this like in
395 the other VFSs (see fd_usage in extfs) -- Norbert */
400 /* --------------------------------------------------------------------------------------------- */
403 sfs_getlocalcopy (const vfs_path_t
* vpath
)
405 return vfs_path_from_str (sfs_redirect (vpath
));
408 /* --------------------------------------------------------------------------------------------- */
411 sfs_ungetlocalcopy (const vfs_path_t
* vpath
, const vfs_path_t
* local
, gboolean has_changed
)
419 /* --------------------------------------------------------------------------------------------- */
422 sfs_init (struct vfs_class
*me
)
430 mc_sfsini
= g_build_filename (mc_global
.sysconfig_dir
, "sfs.ini", (char *) NULL
);
431 cfg
= fopen (mc_sfsini
, "r");
435 fprintf (stderr
, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini
);
442 while (sfs_no
< MAXFS
&& fgets (key
, sizeof (key
), cfg
))
444 char *c
, *semi
= NULL
, flags
= 0;
446 if (*key
== '#' || *key
== '\n')
449 for (c
= key
; *c
; c
++)
450 if (*c
== ':' || IS_PATH_SEP (*c
))
453 if (IS_PATH_SEP (*c
))
456 flags
|= F_FULLMATCH
;
464 fprintf (stderr
, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key
);
469 while (*c
!= '\0' && !whitespace (*c
))
480 flags
|= F_NOLOCALCOPY
;
483 fprintf (stderr
, _("Warning: Invalid flag %c in %s:\n%s\n"), *c
, "sfs.ini", key
);
492 semi
= strchr (c
, '\n');
496 sfs_prefix
[sfs_no
] = g_strdup (key
);
497 sfs_command
[sfs_no
] = g_strdup (c
);
498 sfs_flags
[sfs_no
] = flags
;
505 /* --------------------------------------------------------------------------------------------- */
508 sfs_done (struct vfs_class
*me
)
514 for (i
= 0; i
< sfs_no
; i
++)
516 MC_PTR_FREE (sfs_prefix
[i
]);
517 MC_PTR_FREE (sfs_command
[i
]);
522 /* --------------------------------------------------------------------------------------------- */
525 sfs_which (struct vfs_class
*me
, const char *path
)
531 for (i
= 0; i
< sfs_no
; i
++)
532 if (sfs_flags
[i
] & F_FULLMATCH
)
534 if (!strcmp (path
, sfs_prefix
[i
]))
537 else if (!strncmp (path
, sfs_prefix
[i
], strlen (sfs_prefix
[i
])))
543 /* --------------------------------------------------------------------------------------------- */
544 /*** public functions ****************************************************************************/
545 /* --------------------------------------------------------------------------------------------- */
550 vfs_sfs_ops
.name
= "sfs";
551 vfs_sfs_ops
.init
= sfs_init
;
552 vfs_sfs_ops
.done
= sfs_done
;
553 vfs_sfs_ops
.fill_names
= sfs_fill_names
;
554 vfs_sfs_ops
.which
= sfs_which
;
555 vfs_sfs_ops
.open
= sfs_open
;
556 vfs_sfs_ops
.close
= local_close
;
557 vfs_sfs_ops
.read
= local_read
;
558 vfs_sfs_ops
.stat
= sfs_stat
;
559 vfs_sfs_ops
.lstat
= sfs_lstat
;
560 vfs_sfs_ops
.fstat
= local_fstat
;
561 vfs_sfs_ops
.chmod
= sfs_chmod
;
562 vfs_sfs_ops
.chown
= sfs_chown
;
563 vfs_sfs_ops
.utime
= sfs_utime
;
564 vfs_sfs_ops
.readlink
= sfs_readlink
;
565 vfs_sfs_ops
.ferrno
= local_errno
;
566 vfs_sfs_ops
.lseek
= local_lseek
;
567 vfs_sfs_ops
.getid
= sfs_getid
;
568 vfs_sfs_ops
.nothingisopen
= sfs_nothingisopen
;
569 vfs_sfs_ops
.free
= sfs_free
;
570 vfs_sfs_ops
.getlocalcopy
= sfs_getlocalcopy
;
571 vfs_sfs_ops
.ungetlocalcopy
= sfs_ungetlocalcopy
;
572 vfs_register_class (&vfs_sfs_ops
);
575 /* --------------------------------------------------------------------------------------------- */