mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 12:56:51 +03:00
097fe43280
Now in wrap mode the End key and cursor up key behave much better (e.g. when viewing binary files with lots of wrapped lines). It's not perfekt but it's better than it used to be. Tue Apr 28 06:52:24 1998 Norbert Warmuth <k3190@fh-sw.de> * gnome/gcmd.c (gnome_open_terminal): Changed my_system(1,...) to my_system(EXECUTE_AS_SHELL,...) Tue Apr 28 06:06:03 1998 Norbert Warmuth <k3190@fh-sw.de> * vfs/extfs.c (extfs_open, extfs_close): Changed my_system(1,...) to my_system(EXECUTE_AS_SHELL,...), this fixes the broken copyin and copyout in 4.1.32. Tue Apr 28 06:11:08 1998 Norbert Warmuth <k3190@fh-sw.de> * view.c (toggle_wrap_mode, toggle_hex_mode): Force recalculation of bottom_first (we mustn't use an already calculated and cached value because it is invalid for the new mode and the End key would not move to the end of the file). * configure.in: Renamed the option `--with-our-slang' to `--with-included-slang' (this one looks better because we also have an `--with-included-gettext'). Make the option `--with-ext2undel' recognice a given path. * cmd.c (view_file_at_line): In plain view (F13) set the default magic flag to zero in order to view the file content unprocessed (esp. don't uncompress files if they are compressed). The view_simple_cmd got broken when the default magic flag in view.c was changed from 0 to 1. * view.c (do_view_init, goto_line): Set wrap mode temporary off to make goto line number work, i.e. `line number' now always means line number in file and not line number on screen (in wrap mode one long line wrapped once is displayed in two lines on the screen). That's important when the viewer is invoked from the find file dialog to display even in wrap mode approxiamtly the part of the file where we found the content we searched for. (move_forward2): In wrap mode lines were sometimes counted wrong causing cursor up to move more than one line. (move_backward2): Fixed the movement in wrap mode. (change_viewer): Always re-init viewer when we have a filename, i. e. if the viewer is invoked with simple_view_cmd then we can switch with the F8 key between unprocessed file content und uncompressed file content. (view_init): re-init view also when magic flag was altered
1378 lines
36 KiB
C
1378 lines
36 KiB
C
/* Virtual File System: External file system.
|
|
Copyright (C) 1995 The Free Software Foundation
|
|
|
|
Written by: 1995 Jakub Jelinek
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
#include <sys/wait.h>
|
|
#endif
|
|
#include <errno.h>
|
|
#ifdef SCO_FLAVOR
|
|
#include <sys/timeb.h> /* alex: for struct timeb definition */
|
|
#endif /* SCO_FLAVOR */
|
|
#include <time.h>
|
|
#include "../src/fs.h"
|
|
#include "../src/util.h"
|
|
#include "../src/mem.h"
|
|
#include "../src/mad.h"
|
|
#include "../src/main.h" /* For shell_execute */
|
|
#define WANT_PARSE_LS_LGA
|
|
#include "vfs.h"
|
|
#include "extfs.h"
|
|
|
|
static struct extfs_entry *
|
|
extfs_find_entry (struct extfs_entry *dir, char *name, int make_dirs, int make_file);
|
|
|
|
static struct extfs_archive *first_archive = NULL;;
|
|
static int extfserrno = 0;
|
|
static struct stat hstat; /* Stat struct corresponding */
|
|
static char *current_file_name, *current_link_name;
|
|
static char *extfs_current_dir;
|
|
|
|
enum {
|
|
EFS_ARG_EMPTY,
|
|
EFS_NEED_FILE,
|
|
EFS_NEED_ARG
|
|
};
|
|
|
|
#define MAXEXTFS 32
|
|
static char *extfs_prefixes [MAXEXTFS];
|
|
static char extfs_need_archive [MAXEXTFS];
|
|
static int extfs_no = 0;
|
|
|
|
struct extfs_ext {
|
|
char *ext;
|
|
struct extfs_ext *next;
|
|
};
|
|
|
|
static struct extfs_ext *extfs_extensions [MAXEXTFS];
|
|
|
|
void extfs_fill_names (void (*func)(char *))
|
|
{
|
|
struct extfs_archive *a = first_archive;
|
|
char *name;
|
|
|
|
while (a){
|
|
name = copy_strings (extfs_prefixes [a->fstype], ":",
|
|
(a->name ? a->name : ""), "/",
|
|
a->current_dir->name, 0);
|
|
(*func)(name);
|
|
free (name);
|
|
a = a->next;
|
|
}
|
|
}
|
|
|
|
static void make_dot_doubledot (struct extfs_entry *ent)
|
|
{
|
|
struct extfs_entry *entry = (struct extfs_entry *)
|
|
xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
|
struct extfs_entry *parentry = ent->dir;
|
|
struct extfs_inode *inode = ent->inode, *parent;
|
|
|
|
parent = (parentry != NULL) ? parentry->inode : NULL;
|
|
entry->name = strdup (".");
|
|
entry->has_changed = 0;
|
|
entry->inode = inode;
|
|
entry->dir = ent;
|
|
inode->local_filename = NULL;
|
|
inode->first_in_subdir = entry;
|
|
inode->last_in_subdir = entry;
|
|
inode->nlink++;
|
|
entry->next_in_dir = (struct extfs_entry *)
|
|
xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
|
entry=entry->next_in_dir;
|
|
entry->name = strdup ("..");
|
|
entry->has_changed = 0;
|
|
inode->last_in_subdir = entry;
|
|
entry->next_in_dir = NULL;
|
|
if (parent != NULL) {
|
|
entry->inode = parent;
|
|
entry->dir = parentry;
|
|
parent->nlink++;
|
|
} else {
|
|
entry->inode = inode;
|
|
entry->dir = ent;
|
|
inode->nlink++;
|
|
}
|
|
}
|
|
|
|
static struct extfs_entry *generate_entry (struct extfs_archive *archive,
|
|
char *name, struct extfs_entry *parentry, mode_t mode)
|
|
{
|
|
mode_t myumask;
|
|
struct extfs_inode *inode, *parent;
|
|
struct extfs_entry *entry;
|
|
|
|
parent = (parentry != NULL) ? parentry->inode : NULL;
|
|
entry = (struct extfs_entry *)
|
|
xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
|
|
|
entry->name = strdup (name);
|
|
entry->has_changed = 0;
|
|
entry->next_in_dir = NULL;
|
|
entry->dir = parentry;
|
|
if (parent != NULL) {
|
|
parent->last_in_subdir->next_in_dir = entry;
|
|
parent->last_in_subdir = entry;
|
|
}
|
|
inode = (struct extfs_inode *)
|
|
xmalloc (sizeof (struct extfs_inode), "Extfs: extfs_inode");
|
|
entry->inode = inode;
|
|
inode->has_changed = 0;
|
|
inode->local_filename = NULL;
|
|
inode->linkname = 0;
|
|
inode->inode = (archive->__inode_counter)++;
|
|
inode->dev = archive->rdev;
|
|
inode->archive = archive;
|
|
myumask = umask (022);
|
|
umask (myumask);
|
|
inode->mode = mode & ~myumask;
|
|
mode = inode->mode;
|
|
inode->rdev = 0;
|
|
inode->uid = getuid ();
|
|
inode->gid = getgid ();
|
|
inode->size = 0;
|
|
inode->mtime = time (NULL);
|
|
inode->atime = inode->mtime;
|
|
inode->ctime = inode->mtime;
|
|
inode->nlink = 1;
|
|
if (S_ISDIR (mode))
|
|
make_dot_doubledot (entry);
|
|
return entry;
|
|
}
|
|
|
|
static void free_entries (struct extfs_entry *entry)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void free_archive (struct extfs_archive *archive)
|
|
{
|
|
free_entries (archive->root_entry);
|
|
if (archive->local_name != NULL) {
|
|
struct stat my;
|
|
|
|
mc_stat (archive->local_name, &my);
|
|
mc_ungetlocalcopy (archive->name, archive->local_name,
|
|
archive->local_stat.st_mtime != my.st_mtime);
|
|
/* ungetlocalcopy frees local_name for us */
|
|
}
|
|
if (archive->name)
|
|
free (archive->name);
|
|
free (archive);
|
|
}
|
|
|
|
static FILE *open_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
|
{
|
|
static dev_t __extfs_no = 0;
|
|
FILE *result;
|
|
mode_t mode;
|
|
char *cmd;
|
|
struct stat mystat;
|
|
struct extfs_archive *current_archive;
|
|
struct extfs_entry *root_entry;
|
|
char *local_name = NULL, *tmp = 0;
|
|
const int uses_archive = extfs_need_archive [fstype];
|
|
|
|
if (uses_archive == EFS_NEED_FILE){
|
|
if (mc_stat (name, &mystat) == -1)
|
|
return NULL;
|
|
if (!vfs_file_is_local (name)) {
|
|
local_name = mc_getlocalcopy (name);
|
|
if (local_name == NULL)
|
|
return NULL;
|
|
}
|
|
tmp = name_quote (name, 0);
|
|
}
|
|
|
|
if (uses_archive == EFS_NEED_ARG){
|
|
tmp = name_quote (name, 0);
|
|
}
|
|
|
|
cmd = copy_strings (LIBDIR "extfs/", extfs_prefixes [fstype],
|
|
" list ", local_name ? local_name : tmp, 0);
|
|
if (tmp)
|
|
free (tmp);
|
|
result = popen (cmd, "r");
|
|
free (cmd);
|
|
if (result == NULL) {
|
|
if (local_name != NULL && uses_archive)
|
|
mc_ungetlocalcopy (name, local_name, 0);
|
|
return NULL;
|
|
}
|
|
|
|
current_archive = (struct extfs_archive *)
|
|
xmalloc (sizeof (struct extfs_archive), "Tar archive");
|
|
current_archive->fstype = fstype;
|
|
current_archive->name = name ? strdup (name): name;
|
|
current_archive->local_name = local_name;
|
|
|
|
if (local_name != NULL)
|
|
mc_stat (local_name, ¤t_archive->local_stat);
|
|
current_archive->__inode_counter = 0;
|
|
current_archive->fd_usage = 0;
|
|
current_archive->extfsstat = mystat;
|
|
current_archive->rdev = __extfs_no++;
|
|
current_archive->next = first_archive;
|
|
first_archive = current_archive;
|
|
mode = current_archive->extfsstat.st_mode & 07777;
|
|
if (mode & 0400)
|
|
mode |= 0100;
|
|
if (mode & 0040)
|
|
mode |= 0010;
|
|
if (mode & 0004)
|
|
mode |= 0001;
|
|
mode |= S_IFDIR;
|
|
root_entry = generate_entry (current_archive, "/", NULL, mode);
|
|
root_entry->inode->uid = current_archive->extfsstat.st_uid;
|
|
root_entry->inode->gid = current_archive->extfsstat.st_gid;
|
|
root_entry->inode->atime = current_archive->extfsstat.st_atime;
|
|
root_entry->inode->ctime = current_archive->extfsstat.st_ctime;
|
|
root_entry->inode->mtime = current_archive->extfsstat.st_mtime;
|
|
current_archive->root_entry = root_entry;
|
|
current_archive->current_dir = root_entry;
|
|
|
|
*pparc = current_archive;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Main loop for reading an archive.
|
|
* Returns 0 on success, -1 on error.
|
|
*/
|
|
int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
|
{
|
|
FILE *extfsd;
|
|
char *buffer;
|
|
struct extfs_archive *current_archive;
|
|
|
|
if ((extfsd = open_extfs_archive (fstype, name, ¤t_archive)) == NULL) {
|
|
message_3s (1, " Error ", "Couldn't open %s archive\n%s",
|
|
extfs_prefixes [fstype], name);
|
|
return -1;
|
|
}
|
|
|
|
buffer = xmalloc (4096, "Extfs: buffer");
|
|
while (fgets (buffer, 4096, extfsd) != NULL) {
|
|
current_link_name = NULL;
|
|
if (parse_ls_lga (buffer, &hstat, ¤t_file_name, ¤t_link_name)) {
|
|
struct extfs_entry *entry, *pent;
|
|
struct extfs_inode *inode;
|
|
char *p, *q, *cfn = current_file_name;
|
|
|
|
if (*cfn) {
|
|
if (*cfn == '/')
|
|
cfn++;
|
|
p = strchr (cfn, 0);
|
|
if (p != NULL && p != cfn && *(p - 1) == '/')
|
|
*(p - 1) = 0;
|
|
p = strrchr (cfn, '/');
|
|
if (p == NULL) {
|
|
p = cfn;
|
|
q = strchr (cfn, 0);
|
|
} else {
|
|
*(p++) = 0;
|
|
q = cfn;
|
|
}
|
|
if (S_ISDIR (hstat.st_mode) &&
|
|
(!strcmp (p, ".") || !strcmp (p, "..")))
|
|
goto read_extfs_continue;
|
|
pent = extfs_find_entry (current_archive->root_entry, q, 1, 0) ;
|
|
if (pent == NULL) {
|
|
message_1s (1, " Error ", "Inconsistent extfs archive");
|
|
/* FIXME: Should clean everything one day */
|
|
free (buffer);
|
|
pclose (extfsd);
|
|
return -1;
|
|
}
|
|
entry = (struct extfs_entry *) xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
|
entry->name = strdup (p);
|
|
entry->has_changed = 0;
|
|
entry->next_in_dir = NULL;
|
|
entry->dir = pent;
|
|
if (pent != NULL) {
|
|
if (pent->inode->last_in_subdir){
|
|
pent->inode->last_in_subdir->next_in_dir = entry;
|
|
pent->inode->last_in_subdir = entry;
|
|
}
|
|
}
|
|
if (!S_ISLNK (hstat.st_mode) && current_link_name != NULL) {
|
|
pent = extfs_find_entry (current_archive->root_entry, current_link_name, 0, 0);
|
|
if (pent == NULL) {
|
|
message_1s (1, " Error ", "Inconsistent extfs archive");
|
|
/* FIXME: Should clean everything one day */
|
|
free (buffer);
|
|
pclose (extfsd);
|
|
return -1;
|
|
} else {
|
|
entry->inode = pent->inode;
|
|
pent->inode->nlink++;
|
|
}
|
|
} else {
|
|
inode = (struct extfs_inode *) xmalloc (sizeof (struct extfs_inode), "Extfs: extfs_inode");
|
|
entry->inode = inode;
|
|
inode->local_filename = NULL;
|
|
inode->has_changed = 0;
|
|
inode->inode = (current_archive->__inode_counter)++;
|
|
inode->nlink = 1;
|
|
inode->dev = current_archive->rdev;
|
|
inode->archive = current_archive;
|
|
inode->mode = hstat.st_mode;
|
|
#ifdef HAVE_ST_RDEV
|
|
inode->rdev = hstat.st_rdev;
|
|
#else
|
|
inode->rdev = 0;
|
|
#endif
|
|
inode->uid = hstat.st_uid;
|
|
inode->gid = hstat.st_gid;
|
|
inode->size = hstat.st_size;
|
|
inode->mtime = hstat.st_mtime;
|
|
inode->atime = hstat.st_atime;
|
|
inode->ctime = hstat.st_ctime;
|
|
if (current_link_name != NULL && S_ISLNK (hstat.st_mode)) {
|
|
inode->linkname = current_link_name;
|
|
current_link_name = NULL;
|
|
} else {
|
|
inode->mode &= ~S_IFLNK;
|
|
inode->linkname = NULL;
|
|
}
|
|
if (S_ISDIR (hstat.st_mode))
|
|
make_dot_doubledot (entry);
|
|
}
|
|
}
|
|
read_extfs_continue:
|
|
free (current_file_name);
|
|
if (current_link_name != NULL)
|
|
free (current_link_name);
|
|
}
|
|
}
|
|
pclose (extfsd);
|
|
#ifdef SCO_FLAVOR
|
|
waitpid(-1,NULL,WNOHANG);
|
|
#endif /* SCO_FLAVOR */
|
|
*pparc = current_archive;
|
|
free (buffer);
|
|
return 0;
|
|
}
|
|
|
|
char *extfs_analysis (char *name, char **archive, int *fstype, int is_dir)
|
|
{
|
|
char *p, *local;
|
|
int j;
|
|
char *archive_name = NULL;
|
|
struct extfs_ext *ext;
|
|
/* | this is len of prefix plus some minimum
|
|
* v space needed for the extension */
|
|
*fstype = extfs_prefix_to_type (name);
|
|
if (*fstype == -1) {
|
|
extfserrno = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
if (extfs_need_archive [*fstype] == EFS_ARG_EMPTY){
|
|
*archive = 0;
|
|
return strdup (name + strlen(extfs_prefixes [*fstype]) + 1);
|
|
}
|
|
|
|
if (extfs_need_archive [*fstype] == EFS_NEED_ARG){
|
|
char c;
|
|
p = strchr (name + strlen (extfs_prefixes [*fstype]) + 1, '/');
|
|
if (p){
|
|
c = *p;
|
|
*p = 0;
|
|
}
|
|
archive_name = strdup (name + strlen (extfs_prefixes [*fstype]) + 1);
|
|
if (p)
|
|
*p = c;
|
|
*archive = archive_name;
|
|
return p ? strdup (p+1) : NULL;
|
|
}
|
|
for (p = name + strlen (name); p > name; p--)
|
|
if (*p == '/' || (is_dir && !*p))
|
|
for (ext = extfs_extensions [*fstype]; ext; ext = ext->next) {
|
|
j = strlen (ext->ext);
|
|
if (p - j < name + 1)
|
|
continue;
|
|
if (!strncmp (p - j, ext->ext, j)) {
|
|
char c = *p;
|
|
|
|
*p = 0;
|
|
archive_name =
|
|
vfs_canon (name + strlen (extfs_prefixes [*fstype]) + 1);
|
|
*archive = archive_name;
|
|
*p = c;
|
|
local = strdup (p);
|
|
return local;
|
|
}
|
|
}
|
|
extfserrno = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
/* Returns allocated path inside the archive or NULL */
|
|
static char *extfs_get_path (char *inname, struct extfs_archive **archive, int is_dir,
|
|
int do_not_open)
|
|
{
|
|
char *local, *archive_name;
|
|
int result = -1;
|
|
struct extfs_archive *parc;
|
|
struct vfs_stamping *parent;
|
|
vfs *v;
|
|
int fstype;
|
|
|
|
local = extfs_analysis (inname, &archive_name, &fstype, is_dir);
|
|
if (local == NULL) {
|
|
extfserrno = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
/* In the case of the file systems that do not require a local
|
|
* archive, we compare the fstype instead of the archive name,
|
|
* of course, this has the drawback that we can't have more than
|
|
* one external file system for each prefix.
|
|
*
|
|
* Actually, we should implement an alias mechanism that would
|
|
* translate: "a:" to "dos:a.
|
|
*
|
|
*/
|
|
for (parc = first_archive; parc != NULL; parc = parc->next)
|
|
if (archive_name){
|
|
if (parc->name) {
|
|
if (!strcmp (parc->name, archive_name)) {
|
|
vfs_stamp (&extfs_vfs_ops, (vfsid) parc);
|
|
goto return_success;
|
|
}
|
|
}
|
|
} else {
|
|
if (parc->fstype == fstype){
|
|
vfs_stamp (&extfs_vfs_ops, (vfsid) parc);
|
|
goto return_success;
|
|
}
|
|
}
|
|
|
|
if (do_not_open)
|
|
result = -1;
|
|
else
|
|
result = read_extfs_archive (fstype, archive_name, &parc);
|
|
if (result == -1) {
|
|
extfserrno = EIO;
|
|
free(local);
|
|
if (archive_name)
|
|
free(archive_name);
|
|
return NULL;
|
|
}
|
|
if (archive_name){
|
|
v = vfs_type (archive_name);
|
|
if (v == &local_vfs_ops) {
|
|
parent = NULL;
|
|
} else {
|
|
parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
|
|
parent->v = v;
|
|
parent->next = 0;
|
|
parent->id = (*v->getid) (archive_name, &(parent->parent));
|
|
}
|
|
vfs_add_noncurrent_stamps (&extfs_vfs_ops, (vfsid) parc, parent);
|
|
vfs_rm_parents (parent);
|
|
}
|
|
return_success:
|
|
*archive = parc;
|
|
if (archive_name)
|
|
free (archive_name);
|
|
return local;
|
|
}
|
|
|
|
/* Returns allocated path (without leading slash) inside the archive */
|
|
static char *extfs_get_path_from_entry (struct extfs_entry *entry)
|
|
{
|
|
struct list {
|
|
struct list *next;
|
|
char *name;
|
|
} *head, *p;
|
|
char *localpath;
|
|
size_t len;
|
|
|
|
for (len = 0, head = 0; entry->dir; entry = entry->dir) {
|
|
p = xmalloc (sizeof (struct list), "Extfs: list");
|
|
p->next = head;
|
|
p->name = entry->name;
|
|
head = p;
|
|
len += strlen (entry->name) + 1;
|
|
}
|
|
|
|
localpath = xmalloc (len, "Extfs: localpath");
|
|
*localpath = '\0';
|
|
for ( ; head; ) {
|
|
strcat (localpath, head->name);
|
|
if (head->next)
|
|
strcat (localpath, "/");
|
|
p = head;
|
|
head = head->next;
|
|
free (p);
|
|
}
|
|
return (localpath);
|
|
}
|
|
|
|
|
|
struct extfs_loop_protect {
|
|
struct extfs_entry *entry;
|
|
struct extfs_loop_protect *next;
|
|
};
|
|
static int errloop;
|
|
static int notadir;
|
|
|
|
static struct extfs_entry *
|
|
__extfs_find_entry (struct extfs_entry *dir, char *name,
|
|
struct extfs_loop_protect *list, int make_dirs, int make_file);
|
|
|
|
static struct extfs_entry *
|
|
__extfs_resolve_symlinks (struct extfs_entry *entry,
|
|
struct extfs_loop_protect *list)
|
|
{
|
|
struct extfs_entry *pent;
|
|
struct extfs_loop_protect *looping;
|
|
|
|
if (!S_ISLNK (entry->inode->mode))
|
|
return entry;
|
|
for (looping = list; looping != NULL; looping = looping->next)
|
|
if (entry == looping->entry) { /* Here we protect us against symlink looping */
|
|
errloop = 1;
|
|
return NULL;
|
|
}
|
|
looping = (struct extfs_loop_protect *)
|
|
xmalloc (sizeof (struct extfs_loop_protect),
|
|
"Extfs: symlink looping protection");
|
|
looping->entry = entry;
|
|
looping->next = list;
|
|
pent = __extfs_find_entry (entry->dir, entry->inode->linkname, looping, 0, 0);
|
|
free (looping);
|
|
if (pent == NULL)
|
|
extfserrno = ENOENT;
|
|
return pent;
|
|
}
|
|
|
|
static struct extfs_entry *extfs_resolve_symlinks (struct extfs_entry *entry)
|
|
{
|
|
struct extfs_entry *res;
|
|
|
|
errloop = 0;
|
|
notadir = 0;
|
|
res = __extfs_resolve_symlinks (entry, NULL);
|
|
if (res == NULL) {
|
|
if (errloop)
|
|
extfserrno = ELOOP;
|
|
else if (notadir)
|
|
extfserrno = ENOTDIR;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static struct extfs_entry*
|
|
__extfs_find_entry (struct extfs_entry *dir, char *name,
|
|
struct extfs_loop_protect *list, int make_dirs, int make_file)
|
|
{
|
|
struct extfs_entry *pent, *pdir;
|
|
char *p, *q, *name_end;
|
|
char c;
|
|
|
|
if (*name == '/') { /* Handle absolute paths */
|
|
name++;
|
|
dir = dir->inode->archive->root_entry;
|
|
}
|
|
|
|
pent = dir;
|
|
p = name;
|
|
name_end = name + strlen (name);
|
|
q = strchr (p, '/');
|
|
c = '/';
|
|
if (!q)
|
|
q = strchr (p, 0);
|
|
|
|
for (; pent != NULL && c && *p; ){
|
|
c = *q;
|
|
*q = 0;
|
|
|
|
if (strcmp (p, ".")){
|
|
if (!strcmp (p, ".."))
|
|
pent = pent->dir;
|
|
else {
|
|
if ((pent = __extfs_resolve_symlinks (pent, list))==NULL){
|
|
*q = c;
|
|
return NULL;
|
|
}
|
|
if (c == '/' && !S_ISDIR (pent->inode->mode)){
|
|
*q = c;
|
|
notadir = 1;
|
|
return NULL;
|
|
}
|
|
pdir = pent;
|
|
for (pent = pent->inode->first_in_subdir; pent; pent = pent->next_in_dir)
|
|
/* Hack: I keep the original semanthic unless
|
|
q+1 would break in the strchr */
|
|
if (!strcmp (pent->name, p)){
|
|
if (q + 1 > name_end){
|
|
*q = c;
|
|
notadir = !S_ISDIR (pent->inode->mode);
|
|
return pent;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* When we load archive, we create automagically
|
|
* non-existant directories
|
|
*/
|
|
if (pent == NULL && make_dirs) {
|
|
pent = generate_entry (dir->inode->archive, p, pdir, S_IFDIR | 0777);
|
|
}
|
|
if (pent == NULL && make_file) {
|
|
pent = generate_entry (dir->inode->archive, p, pdir, 0777);
|
|
}
|
|
}
|
|
}
|
|
/* Next iteration */
|
|
*q = c;
|
|
p = q + 1;
|
|
q = strchr (p, '/');
|
|
if (!q)
|
|
q = strchr (p, 0);
|
|
}
|
|
if (pent == NULL)
|
|
extfserrno = ENOENT;
|
|
return pent;
|
|
}
|
|
|
|
static struct extfs_entry *extfs_find_entry (struct extfs_entry *dir, char *name, int make_dirs, int make_file)
|
|
{
|
|
struct extfs_entry *res;
|
|
|
|
errloop = 0;
|
|
notadir = 0;
|
|
res = __extfs_find_entry (dir, name, NULL, make_dirs, make_file);
|
|
if (res == NULL) {
|
|
if (errloop)
|
|
extfserrno = ELOOP;
|
|
else if (notadir)
|
|
extfserrno = ENOTDIR;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
struct extfs_pseudofile {
|
|
struct extfs_archive *archive;
|
|
unsigned int has_changed:1;
|
|
int local_handle;
|
|
struct extfs_entry *entry;
|
|
};
|
|
|
|
static char *get_archive_name (struct extfs_archive *archive)
|
|
{
|
|
char *archive_name;
|
|
|
|
if (archive->local_name)
|
|
archive_name = archive->local_name;
|
|
else
|
|
archive_name = archive->name;
|
|
|
|
if (!archive_name || !*archive_name)
|
|
return "no_archive_name";
|
|
else
|
|
return archive_name;
|
|
}
|
|
|
|
void extfs_run (char *file)
|
|
{
|
|
struct extfs_archive *archive;
|
|
char *p, *q, *cmd, *archive_name;
|
|
|
|
if ((p = extfs_get_path (file, &archive, 0, 0)) == NULL)
|
|
return;
|
|
q = name_quote (((*p == '/') ? p + 1 : p), 0);
|
|
|
|
archive_name = name_quote (get_archive_name(archive), 0);
|
|
cmd = copy_strings (LIBDIR "extfs/", extfs_prefixes [archive->fstype],
|
|
" run ", archive_name, " ", q, 0);
|
|
free (archive_name);
|
|
free (q);
|
|
shell_execute(cmd, 0);
|
|
free(cmd);
|
|
free(p);
|
|
}
|
|
|
|
static void *extfs_open (char *file, int flags, int mode)
|
|
{
|
|
struct extfs_pseudofile *extfs_info;
|
|
struct extfs_archive *archive;
|
|
char *p, *q;
|
|
struct extfs_entry *entry;
|
|
int local_handle;
|
|
const int do_create = (flags & O_ACCMODE) != O_RDONLY;
|
|
|
|
if ((p = extfs_get_path (file, &archive, 0, 0)) == NULL)
|
|
return NULL;
|
|
q = (*p == '/') ? p + 1 : p;
|
|
entry = extfs_find_entry (archive->root_entry, q, 0, do_create);
|
|
free (p);
|
|
if (entry == NULL) {
|
|
return NULL;
|
|
}
|
|
if ((entry = extfs_resolve_symlinks (entry)) == NULL) {
|
|
return NULL;
|
|
}
|
|
if (S_ISDIR (entry->inode->mode)) {
|
|
extfserrno = EISDIR;
|
|
return NULL;
|
|
}
|
|
if (entry->inode->local_filename == NULL) {
|
|
char *cmd, *archive_name;
|
|
|
|
entry->inode->local_filename = strdup (tmpnam (NULL));
|
|
p = extfs_get_path_from_entry (entry);
|
|
q = name_quote (p, 0);
|
|
free (p);
|
|
archive_name = name_quote (get_archive_name (archive), 0);
|
|
cmd = copy_strings (LIBDIR "extfs/", extfs_prefixes [archive->fstype],
|
|
" copyout ",
|
|
archive_name,
|
|
" ", q, " ", entry->inode->local_filename, 0);
|
|
free (q);
|
|
free (archive_name);
|
|
if (my_system (EXECUTE_AS_SHELL, shell, cmd) && !do_create){
|
|
free (entry->inode->local_filename);
|
|
entry->inode->local_filename = NULL;
|
|
free (cmd);
|
|
extfserrno = EIO;
|
|
return NULL;
|
|
}
|
|
free (cmd);
|
|
}
|
|
|
|
local_handle = open (entry->inode->local_filename, flags, mode);
|
|
if (local_handle == -1) {
|
|
extfserrno = EIO;
|
|
return NULL;
|
|
}
|
|
|
|
extfs_info = (struct extfs_pseudofile *) xmalloc (sizeof (struct extfs_pseudofile), "Extfs: extfs_open");
|
|
extfs_info->archive = archive;
|
|
extfs_info->entry = entry;
|
|
extfs_info->has_changed = 0;
|
|
extfs_info->local_handle = local_handle;
|
|
|
|
/* i.e. we had no open files and now we have one */
|
|
vfs_rmstamp (&extfs_vfs_ops, (vfsid) archive, 1);
|
|
archive->fd_usage++;
|
|
return extfs_info;
|
|
}
|
|
|
|
static int extfs_read (void *data, char *buffer, int count)
|
|
{
|
|
struct extfs_pseudofile *file = (struct extfs_pseudofile *)data;
|
|
|
|
return read (file->local_handle, buffer, count);
|
|
}
|
|
|
|
static int extfs_close (void *data)
|
|
{
|
|
struct extfs_pseudofile *file;
|
|
int errno_code = 0;
|
|
file = (struct extfs_pseudofile *)data;
|
|
|
|
close (file->local_handle);
|
|
|
|
/* Commit the file if it has changed */
|
|
if (file->has_changed){
|
|
struct extfs_archive *archive;
|
|
char *archive_name, *file_name;
|
|
char *cmd;
|
|
char *p;
|
|
|
|
archive = file->archive;
|
|
archive_name = name_quote (get_archive_name (archive), 0);
|
|
p = extfs_get_path_from_entry (file->entry);
|
|
file_name = name_quote (p, 0);
|
|
free (p);
|
|
|
|
cmd = copy_strings (LIBDIR "extfs/",
|
|
extfs_prefixes [archive->fstype],
|
|
" copyin ", archive_name, " ",
|
|
file_name, " ",
|
|
file->entry->inode->local_filename, 0);
|
|
free (archive_name);
|
|
free (file_name);
|
|
if (my_system (EXECUTE_AS_SHELL, shell, cmd))
|
|
errno_code = EIO;
|
|
free (cmd);
|
|
{
|
|
struct stat file_status;
|
|
if( stat(file->entry->inode->local_filename,&file_status) != 0 )
|
|
errno_code = EIO;
|
|
else file->entry->inode->size = file_status.st_size;
|
|
}
|
|
|
|
file->entry->inode->mtime = time (NULL);
|
|
}
|
|
|
|
file->archive->fd_usage--;
|
|
if (!file->archive->fd_usage) {
|
|
struct vfs_stamping *parent;
|
|
vfs *v;
|
|
|
|
if (!file->archive->name || !*file->archive->name || (v = vfs_type (file->archive->name)) == &local_vfs_ops) {
|
|
parent = NULL;
|
|
} else {
|
|
parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
|
|
parent->v = v;
|
|
parent->next = 0;
|
|
parent->id = (*v->getid) (file->archive->name, &(parent->parent));
|
|
}
|
|
vfs_add_noncurrent_stamps (&extfs_vfs_ops, (vfsid) (file->archive), parent);
|
|
vfs_rm_parents (parent);
|
|
}
|
|
|
|
free (data);
|
|
if (errno_code){
|
|
extfserrno = EIO; /* Non standard, but who cares? */
|
|
return -1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
static int extfs_errno (void)
|
|
{
|
|
return extfserrno;
|
|
}
|
|
|
|
static void *extfs_opendir (char *dirname)
|
|
{
|
|
struct extfs_archive *archive;
|
|
char *p, *q;
|
|
struct extfs_entry *entry;
|
|
struct extfs_entry **extfs_info;
|
|
|
|
if ((p = extfs_get_path (dirname, &archive, 1, 0)) == NULL)
|
|
return NULL;
|
|
q = (*p == '/') ? p + 1 : p;
|
|
entry = extfs_find_entry (archive->root_entry, q, 0, 0);
|
|
free (p);
|
|
if (entry == NULL)
|
|
return NULL;
|
|
if ((entry = extfs_resolve_symlinks (entry)) == NULL)
|
|
return NULL;
|
|
if (!S_ISDIR (entry->inode->mode)) {
|
|
extfserrno = ENOTDIR;
|
|
return NULL;
|
|
}
|
|
|
|
extfs_info = (struct extfs_entry **) xmalloc (sizeof (struct extfs_entry *), "Extfs: extfs_opendir");
|
|
*extfs_info = entry->inode->first_in_subdir;
|
|
|
|
return extfs_info;
|
|
}
|
|
|
|
static void *extfs_readdir (void *data)
|
|
{
|
|
static struct {
|
|
struct dirent dir;
|
|
#ifdef NEED_EXTRA_DIRENT_BUFFER
|
|
char extra_buffer [MC_MAXPATHLEN];
|
|
#endif
|
|
} dir;
|
|
|
|
struct extfs_entry **extfs_info = (struct extfs_entry **) data;
|
|
|
|
if (*extfs_info == NULL)
|
|
return NULL;
|
|
|
|
strcpy (&(dir.dir.d_name [0]), (*extfs_info)->name);
|
|
|
|
#ifndef DIRENT_LENGTH_COMPUTED
|
|
dir.d_namlen = strlen (dir.dir.d_name);
|
|
#endif
|
|
*extfs_info = (*extfs_info)->next_in_dir;
|
|
|
|
return (void *)&dir;
|
|
}
|
|
|
|
static int extfs_closedir (void *data)
|
|
{
|
|
free (data);
|
|
return 0;
|
|
}
|
|
|
|
static int _extfs_stat (char *path, struct stat *buf, int resolve)
|
|
{
|
|
struct extfs_archive *archive;
|
|
char *p, *q;
|
|
struct extfs_entry *entry;
|
|
struct extfs_inode *inode;
|
|
|
|
if ((p = extfs_get_path (path, &archive, 0, 0)) == NULL)
|
|
return -1;
|
|
q = (*p == '/') ? p + 1 : p;
|
|
entry = extfs_find_entry (archive->root_entry, q, 0, 0);
|
|
free (p);
|
|
if (entry == NULL)
|
|
return -1;
|
|
if (resolve && (entry = extfs_resolve_symlinks (entry)) == NULL)
|
|
return -1;
|
|
inode = entry->inode;
|
|
buf->st_dev = inode->dev;
|
|
buf->st_ino = inode->inode;
|
|
buf->st_mode = inode->mode;
|
|
buf->st_nlink = inode->nlink;
|
|
buf->st_uid = inode->uid;
|
|
buf->st_gid = inode->gid;
|
|
#ifdef HAVE_ST_RDEV
|
|
buf->st_rdev = inode->rdev;
|
|
#endif
|
|
buf->st_size = inode->size;
|
|
#ifdef HAVE_ST_BLKSIZE
|
|
buf->st_blksize = 512;
|
|
#endif
|
|
#ifdef HAVE_ST_BLOCKS
|
|
buf->st_blocks = (inode->size + 512 - 1) / 512;
|
|
#endif
|
|
buf->st_atime = inode->atime;
|
|
buf->st_mtime = inode->mtime;
|
|
buf->st_ctime = inode->ctime;
|
|
return 0;
|
|
}
|
|
|
|
static int extfs_stat (char *path, struct stat *buf)
|
|
{
|
|
return _extfs_stat (path, buf, 1);
|
|
}
|
|
|
|
static int extfs_lstat (char *path, struct stat *buf)
|
|
{
|
|
return _extfs_stat (path, buf, 0);
|
|
}
|
|
|
|
static int extfs_fstat (void *data, struct stat *buf)
|
|
{
|
|
struct extfs_pseudofile *file = (struct extfs_pseudofile *)data;
|
|
struct extfs_inode *inode;
|
|
|
|
inode = file->entry->inode;
|
|
buf->st_dev = inode->dev;
|
|
buf->st_ino = inode->inode;
|
|
buf->st_mode = inode->mode;
|
|
buf->st_nlink = inode->nlink;
|
|
buf->st_uid = inode->uid;
|
|
buf->st_gid = inode->gid;
|
|
#ifdef HAVE_ST_RDEV
|
|
buf->st_rdev = inode->rdev;
|
|
#endif
|
|
buf->st_size = inode->size;
|
|
#ifdef HAVE_ST_BLKSIZE
|
|
buf->st_blksize = 512;
|
|
#endif
|
|
#ifdef HAVE_ST_BLOCKS
|
|
buf->st_blocks = (inode->size + 512 - 1) / 512;
|
|
#endif
|
|
buf->st_atime = inode->atime;
|
|
buf->st_mtime = inode->mtime;
|
|
buf->st_ctime = inode->ctime;
|
|
return 0;
|
|
}
|
|
|
|
static int extfs_chmod (char *path, int mode)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int extfs_chown (char *path, int owner, int group)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_readlink (char *path, char *buf, int size)
|
|
{
|
|
struct extfs_archive *archive;
|
|
char *p, *q;
|
|
int i;
|
|
struct extfs_entry *entry;
|
|
|
|
if ((p = extfs_get_path (path, &archive, 0, 0)) == NULL)
|
|
return -1;
|
|
q = (*p == '/') ? p + 1 : p;
|
|
entry = extfs_find_entry (archive->root_entry, q, 0, 0);
|
|
free (p);
|
|
if (entry == NULL)
|
|
return -1;
|
|
if (!S_ISLNK (entry->inode->mode)) {
|
|
extfserrno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (size > (i = strlen (entry->inode->linkname))) {
|
|
size = i;
|
|
}
|
|
strncpy (buf, entry->inode->linkname, i);
|
|
return i;
|
|
}
|
|
|
|
static int extfs_unlink (char *path)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_symlink (char *n1, char *n2)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_write (void *data, char *buf, int nbyte)
|
|
{
|
|
struct extfs_pseudofile *file = (struct extfs_pseudofile *)data;
|
|
|
|
file->has_changed = 1;
|
|
return write (file->local_handle, buf, nbyte);
|
|
}
|
|
|
|
static int extfs_rename (char *a, char *b)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_chdir (char *path)
|
|
{
|
|
struct extfs_archive *archive;
|
|
char *p, *q, *res;
|
|
struct extfs_entry *entry;
|
|
|
|
extfserrno = ENOTDIR;
|
|
if ((p = extfs_get_path (path, &archive, 1, 0)) == NULL)
|
|
return -1;
|
|
q = (*p == '/') ? p + 1 : p;
|
|
entry = extfs_find_entry (archive->root_entry, q, 0, 0);
|
|
if (entry == NULL) {
|
|
free (p);
|
|
return -1;
|
|
}
|
|
entry = extfs_resolve_symlinks (entry);
|
|
if (entry == NULL) {
|
|
free (p);
|
|
return -1;
|
|
}
|
|
if (!S_ISDIR (entry->inode->mode)) {
|
|
free (p);
|
|
return -1;
|
|
}
|
|
entry->inode->archive->current_dir = entry;
|
|
res = copy_strings (extfs_prefixes [entry->inode->archive->fstype], ":",
|
|
entry->inode->archive->name, p, NULL);
|
|
free (p);
|
|
extfserrno = 0;
|
|
if (extfs_current_dir)
|
|
free (extfs_current_dir);
|
|
extfs_current_dir = res;
|
|
return 0;
|
|
}
|
|
|
|
static int extfs_lseek (void *data, off_t offset, int whence)
|
|
{
|
|
struct extfs_pseudofile *file = (struct extfs_pseudofile *) data;
|
|
|
|
return lseek (file->local_handle, offset, whence);
|
|
}
|
|
|
|
static int extfs_mknod (char *path, int mode, int dev)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_link (char *p1, char *p2)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_mkdir (char *path, mode_t mode)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static int extfs_rmdir (char *path)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static vfsid extfs_getid (char *path, struct vfs_stamping **parent)
|
|
{
|
|
struct extfs_archive *archive;
|
|
vfs *v;
|
|
vfsid id;
|
|
char *p;
|
|
struct vfs_stamping *par;
|
|
|
|
*parent = NULL;
|
|
if ((p = extfs_get_path (path, &archive, 1, 1)) == NULL) {
|
|
return (vfsid) -1;
|
|
}
|
|
free (p);
|
|
if (archive->name){
|
|
v = vfs_type (archive->name);
|
|
id = (*v->getid) (archive->name, &par);
|
|
if (id != (vfsid)-1) {
|
|
*parent = xmalloc (sizeof (struct vfs_stamping), "vfs stamping");
|
|
(*parent)->v = v;
|
|
(*parent)->id = id;
|
|
(*parent)->parent = par;
|
|
(*parent)->next = NULL;
|
|
}
|
|
}
|
|
return (vfsid) archive;
|
|
}
|
|
|
|
static int extfs_nothingisopen (vfsid id)
|
|
{
|
|
if (((struct extfs_archive *)id)->fd_usage <= 0)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void free_entry (struct extfs_entry *e)
|
|
{
|
|
int i = --(e->inode->nlink);
|
|
if (S_ISDIR (e->inode->mode) && e->inode->first_in_subdir != NULL) {
|
|
struct extfs_entry *f = e->inode->first_in_subdir;
|
|
|
|
e->inode->first_in_subdir = NULL;
|
|
free_entry (f);
|
|
}
|
|
if (i <= 0) {
|
|
if (e->inode->local_filename != NULL) {
|
|
unlink (e->inode->local_filename);
|
|
free (e->inode->local_filename);
|
|
}
|
|
if (e->inode->linkname != NULL)
|
|
free (e->inode->linkname);
|
|
free (e->inode);
|
|
}
|
|
if (e->next_in_dir != NULL)
|
|
free_entry (e->next_in_dir);
|
|
free (e->name);
|
|
free (e);
|
|
}
|
|
|
|
static void extfs_free (vfsid id)
|
|
{
|
|
struct extfs_archive *parc;
|
|
struct extfs_archive *archive = (struct extfs_archive *)id;
|
|
|
|
free_entry (archive->root_entry);
|
|
if (archive == first_archive) {
|
|
first_archive = archive->next;
|
|
} else {
|
|
for (parc = first_archive; parc != NULL; parc = parc->next)
|
|
if (parc->next == archive)
|
|
break;
|
|
if (parc != NULL)
|
|
parc->next = archive->next;
|
|
}
|
|
free_archive (archive);
|
|
}
|
|
|
|
static char *extfs_getlocalcopy (char *path)
|
|
{
|
|
struct extfs_pseudofile *fp =
|
|
(struct extfs_pseudofile *) extfs_open (path, O_RDONLY, 0);
|
|
char *p;
|
|
|
|
if (fp == NULL)
|
|
return NULL;
|
|
if (fp->entry->inode->local_filename == NULL) {
|
|
extfs_close ((void *) fp);
|
|
return NULL;
|
|
}
|
|
p = strdup (fp->entry->inode->local_filename);
|
|
fp->archive->fd_usage++;
|
|
extfs_close ((void *) fp);
|
|
return p;
|
|
}
|
|
|
|
static void extfs_ungetlocalcopy (char *path, char *local, int has_changed)
|
|
{
|
|
struct extfs_pseudofile *fp =
|
|
(struct extfs_pseudofile *) extfs_open (path, O_WRONLY, 0);
|
|
|
|
if (fp == NULL)
|
|
return;
|
|
if (!strcmp (fp->entry->inode->local_filename, local)) {
|
|
fp->entry->inode->has_changed = has_changed;
|
|
fp->archive->fd_usage--;
|
|
extfs_close ((void *) fp);
|
|
return;
|
|
} else {
|
|
/* Should not happen */
|
|
extfs_close ((void *) fp);
|
|
mc_def_ungetlocalcopy (path, local, has_changed);
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_MMAP
|
|
caddr_t extfs_mmap (caddr_t addr, size_t len, int prot, int flags, void *data, off_t offset)
|
|
{
|
|
return (caddr_t)-1;
|
|
}
|
|
|
|
int extfs_munmap (caddr_t addr, size_t len, void *data)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
vfs extfs_vfs_ops =
|
|
{
|
|
extfs_open,
|
|
extfs_close,
|
|
extfs_read,
|
|
extfs_write,
|
|
|
|
extfs_opendir,
|
|
extfs_readdir,
|
|
extfs_closedir,
|
|
|
|
extfs_stat,
|
|
extfs_lstat,
|
|
extfs_fstat,
|
|
|
|
extfs_chmod, /* unimplemented */
|
|
extfs_chown, /* unimplemented */
|
|
NULL,
|
|
|
|
extfs_readlink,
|
|
|
|
extfs_symlink, /* unimplemented */
|
|
extfs_link, /* unimplemented */
|
|
extfs_unlink, /* unimplemented */
|
|
|
|
extfs_rename, /* unimplemented */
|
|
extfs_chdir,
|
|
extfs_errno,
|
|
extfs_lseek,
|
|
extfs_mknod, /* unimplemented */
|
|
|
|
extfs_getid,
|
|
extfs_nothingisopen,
|
|
extfs_free,
|
|
|
|
extfs_getlocalcopy,
|
|
extfs_ungetlocalcopy,
|
|
|
|
extfs_mkdir, /* unimplemented */
|
|
extfs_rmdir, /* unimplemented */
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
#ifdef HAVE_MMAP
|
|
, extfs_mmap,
|
|
extfs_munmap
|
|
#endif
|
|
};
|
|
|
|
#include "../src/profile.h"
|
|
void extfs_init (void)
|
|
{
|
|
void *keys = profile_init_iterator ("extfs", LIBDIR "extfs/extfs.ini");
|
|
char *key, *value;
|
|
char *p, *q, c;
|
|
|
|
extfs_no = 0;
|
|
for (extfs_no = 0; keys != NULL && extfs_no < MAXEXTFS; extfs_no++) {
|
|
keys = profile_iterator_next (keys, &key, &value);
|
|
|
|
/* Handle those with a trailing ':', those flag that the
|
|
* file system does not require an archive to work
|
|
*/
|
|
|
|
c = key [strlen (key)-1];
|
|
if (c == ':'){
|
|
key [strlen (key)-1] = 0;
|
|
extfs_need_archive [extfs_no] = EFS_ARG_EMPTY;
|
|
} else if (c == '*'){
|
|
key [strlen (key)-1] = 0;
|
|
extfs_need_archive [extfs_no] = EFS_NEED_ARG;
|
|
} else
|
|
extfs_need_archive [extfs_no] = EFS_NEED_FILE;
|
|
|
|
extfs_prefixes [extfs_no] = strdup (key);
|
|
|
|
value = strdup (value);
|
|
for (q = value; (p = strtok (q, " \t")) != NULL; ){
|
|
struct extfs_ext *newn;
|
|
|
|
q = NULL;
|
|
newn = xmalloc (sizeof (struct extfs_ext), "prefixes");
|
|
newn->next = extfs_extensions [extfs_no];
|
|
newn->ext = strdup (p);
|
|
extfs_extensions [extfs_no] = newn;
|
|
}
|
|
free (value);
|
|
}
|
|
free_profile_name (LIBDIR "extfs/extfs.ini");
|
|
}
|
|
|
|
int extfs_prefix_to_type (char *path)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < extfs_no; i++) {
|
|
j = strlen (extfs_prefixes [i]);
|
|
if (!strncmp (path, extfs_prefixes [i], j) && path [j] == ':')
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
char *extfs_get_prefix (int idx)
|
|
{
|
|
return extfs_prefixes [idx];
|
|
}
|
|
|
|
void extfs_done (void)
|
|
{
|
|
struct extfs_ext *current, *old;
|
|
int i;
|
|
|
|
for (i = 0; i < extfs_no; i++ ){
|
|
free (extfs_prefixes [i]);
|
|
current = extfs_extensions [i];
|
|
while (current){
|
|
old = current;
|
|
current = current->next;
|
|
free (old->ext);
|
|
free (old);
|
|
}
|
|
}
|
|
extfs_no = 0;
|
|
if (extfs_current_dir)
|
|
free (extfs_current_dir);
|
|
extfs_current_dir = 0;
|
|
}
|
|
|