mc/vfs/vfs.c

1884 lines
42 KiB
C
Raw Normal View History

1998-02-27 07:54:42 +03:00
/* Virtual File System switch code
Copyright (C) 1995 The Free Software Foundation
Written by: 1995 Miguel de Icaza
1995 Jakub Jelinek
1998 Pavel Machek
1998-02-27 07:54:42 +03:00
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
1998-02-27 07:54:42 +03:00
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 Library General Public License for more details.
1998-02-27 07:54:42 +03:00
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1998-02-27 07:54:42 +03:00
/* Warning: funtions like extfs_lstat() have right to destroy any
* strings you pass to them. This is acutally ok as you g_strdup what
* you are passing to them, anyway; still, beware. */
1998-10-13 02:07:53 +04:00
/* Namespace: exports *many* functions with vfs_ prefix; exports
parse_ls_lga and friends which do not have that prefix. */
1998-02-27 07:54:42 +03:00
#include <config.h>
1999-02-14 00:39:18 +03:00
#ifndef NO_SYSLOG_H
# include <syslog.h>
#endif
1998-02-27 07:54:42 +03:00
#include <stdio.h>
#include <stdlib.h> /* For atol() */
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <signal.h>
#include "utilvfs.h"
#include "../src/panel.h" /* get_current_panel() */
#include "../src/layout.h" /* get_current_type() */
#include "../src/wtools.h" /* input_dialog() */
#include "xdirentry.h"
1998-02-27 07:54:42 +03:00
#include "vfs.h"
1998-10-13 02:07:53 +04:00
#include "extfs.h" /* FIXME: we should not know anything about our modules */
1998-02-27 07:54:42 +03:00
#include "names.h"
#ifdef USE_NETCODE
# include "tcputil.h"
#endif
int vfs_timeout = 60; /* VFS timeout in seconds */
static int vfs_flags = 0; /* Flags */
1998-02-27 07:54:42 +03:00
/* They keep track of the current directory */
1998-10-13 02:07:53 +04:00
static vfs *current_vfs = &vfs_local_ops;
static char *current_dir = NULL;
1998-02-27 07:54:42 +03:00
/*
* FIXME: this is broken. It depends on mc not crossing border on month!
*/
static int current_mday;
1998-02-27 07:54:42 +03:00
static int current_mon;
static int current_year;
/* FIXME: Open files managed by the vfs layer, should be dynamical */
1998-02-27 07:54:42 +03:00
#define MAX_VFS_FILES 100
1998-02-27 07:54:42 +03:00
static struct {
void *fs_info;
vfs *operations;
} vfs_file_table [MAX_VFS_FILES];
static int
get_bucket (void)
1998-02-27 07:54:42 +03:00
{
int i;
/* 0, 1, 2 are reserved file descriptors, while (DIR *) 0 means error */
for (i = 3; i < MAX_VFS_FILES; i++){
if (!vfs_file_table [i].fs_info)
return i;
}
vfs_die ("No more virtual file handles");
return 0;
1998-02-27 07:54:42 +03:00
}
/* vfs_local_ops needs to be the first one */
static vfs *vfs_list = &vfs_local_ops;
static int
vfs_register (vfs *vfs)
1998-02-27 07:54:42 +03:00
{
if (!vfs)
2002-12-26 05:21:37 +03:00
vfs_die("You cannot register NULL.");
if (vfs->init) /* vfs has own initialization function */
if (!(*vfs->init)(vfs)) /* but it failed */
return 0;
vfs->next = vfs_list;
vfs_list = vfs;
return 1;
}
static vfs *
vfs_type_from_op (char *path)
{
vfs *vfs;
if (!path)
vfs_die ("vfs_type_from_op got NULL: impossible");
for (vfs = vfs_list; vfs != &vfs_local_ops; vfs = vfs->next){
if (vfs->which) {
if ((*vfs->which) (vfs, path) == -1)
continue;
return vfs;
}
if (!strncmp (path, vfs->prefix, strlen (vfs->prefix)))
return vfs;
}
return NULL; /* shut up stupid gcc */
1998-02-27 07:54:42 +03:00
}
/* Strip known vfs suffixes from a filename (possible improvement: strip
suffix from last path component).
Returns a malloced string which has to be freed. */
char *
vfs_strip_suffix_from_filename (const char *filename)
{
vfs *vfs;
char *semi;
char *p;
if (!filename)
vfs_die("vfs_strip_suffix_from_path got NULL: impossible");
p = g_strdup (filename);
if (!(semi = strrchr (p, '#')))
return p;
for (vfs = vfs_list; vfs != &vfs_local_ops; vfs = vfs->next){
if (vfs->which){
if ((*vfs->which) (vfs, semi + 1) == -1)
continue;
Rerun configure when you have problems with missing slang.h. Sun Jan 31 20:04:13 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * vfs/vfs.c (vfs_strip_suffix_from_filename): Whoever replaces every occurance of 0 with NULL should stop this stupidy. And replacing '\0' with NULL is plain wrong!!. Reverted this replacement. * vfs/ftpfs.c (load_no_proxy_list): ditto Fri Jan 29 22:55:56 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * slang/slang.h: renamed to slang-mc.h * slang/Makefile.in: delete slang.h on "make clean" * configure.in: link slang/slang-mc.h to slang/slang.h when the included slang is used. Problem was that MC's slang.h was used when we compiled with an already installed SLang and the systems header file were included with <slang/slang.h>. Unfortunatly I can't use AC_LINK_FILES to make the links because if we needn't make any links AC_LINK_FILES makes a link from srcdir to top_builddir (builddir != srcdir). Temporary add $LGPM to $LIBS when checking for the resizeterm and keyok functions (ncurses might be linked against GPM). Substitude PACKAGE (intl/Makefile makes use of it) Sun Jan 31 19:42:47 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * gnome/Makefile.in (install_mx): make it work with srcdir != builddir (gmc.gnorba is located in $srcdir) * src/hotlist.c (add_new_entry_input, add_new_group_input): Make the quick_widget arrays static and various changes needed because they are now static. add_widgets_i18n recalculates button positions which get lost when the quick_widget arrays are non static. * src/screen.c (to_buffer): nul terminate string when using strncpy * src/setup.c: Save and restore new option ftpfs_first_cd_then_ls. Sun Jan 31 19:57:24 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * vfs/ftpfs.c (insert_dot): New function. Insert a "." into the linked list. Stat'ing the root directory of a ftpfs fails if the dot is missing. (retrieve_dir): insert "." into the linked list if the ftp server haven't send it. Sun Jan 31 19:50:24 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * The following changes make ftpfs work with a remote AmiTCP server are the result of somehow longish EMail debugging session. I don't know any public server of this kind but I was told the combination Unix/Amiga boxes are often used in intranets. * vfs/ftpfs.c (translate_path): New function. Translate a Unix path, i.e. MC's internal path representation (e.g. /somedir/somefile) to a path valid for the remote server. Every path transfered to the remote server has to be mangled by this function right prior to sending it. Currently only Amiga ftp servers are handled in a special manner. * vfs/ftpfs.c (various places): use translate_path * vfs/ftpfs.c (login_server): Assume we have to mangle pathnames if the greatings string from the server contains the word Amiga. If this assumption is wrong I have to find another way to turn on path translation. * vfs/ftpfs.c (ftpfs_get_current_directory): Prepend a leading slash if it is missing. MC needs it as seperator between hostname and path in its internal url representation.
1999-01-31 23:28:13 +03:00
*semi = '\0'; /* Found valid suffix */
return p;
}
if (!strncmp (semi + 1, vfs->prefix, strlen (vfs->prefix))) {
Rerun configure when you have problems with missing slang.h. Sun Jan 31 20:04:13 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * vfs/vfs.c (vfs_strip_suffix_from_filename): Whoever replaces every occurance of 0 with NULL should stop this stupidy. And replacing '\0' with NULL is plain wrong!!. Reverted this replacement. * vfs/ftpfs.c (load_no_proxy_list): ditto Fri Jan 29 22:55:56 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * slang/slang.h: renamed to slang-mc.h * slang/Makefile.in: delete slang.h on "make clean" * configure.in: link slang/slang-mc.h to slang/slang.h when the included slang is used. Problem was that MC's slang.h was used when we compiled with an already installed SLang and the systems header file were included with <slang/slang.h>. Unfortunatly I can't use AC_LINK_FILES to make the links because if we needn't make any links AC_LINK_FILES makes a link from srcdir to top_builddir (builddir != srcdir). Temporary add $LGPM to $LIBS when checking for the resizeterm and keyok functions (ncurses might be linked against GPM). Substitude PACKAGE (intl/Makefile makes use of it) Sun Jan 31 19:42:47 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * gnome/Makefile.in (install_mx): make it work with srcdir != builddir (gmc.gnorba is located in $srcdir) * src/hotlist.c (add_new_entry_input, add_new_group_input): Make the quick_widget arrays static and various changes needed because they are now static. add_widgets_i18n recalculates button positions which get lost when the quick_widget arrays are non static. * src/screen.c (to_buffer): nul terminate string when using strncpy * src/setup.c: Save and restore new option ftpfs_first_cd_then_ls. Sun Jan 31 19:57:24 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * vfs/ftpfs.c (insert_dot): New function. Insert a "." into the linked list. Stat'ing the root directory of a ftpfs fails if the dot is missing. (retrieve_dir): insert "." into the linked list if the ftp server haven't send it. Sun Jan 31 19:50:24 1999 Norbert Warmuth <nwarmuth@privat.circular.de> * The following changes make ftpfs work with a remote AmiTCP server are the result of somehow longish EMail debugging session. I don't know any public server of this kind but I was told the combination Unix/Amiga boxes are often used in intranets. * vfs/ftpfs.c (translate_path): New function. Translate a Unix path, i.e. MC's internal path representation (e.g. /somedir/somefile) to a path valid for the remote server. Every path transfered to the remote server has to be mangled by this function right prior to sending it. Currently only Amiga ftp servers are handled in a special manner. * vfs/ftpfs.c (various places): use translate_path * vfs/ftpfs.c (login_server): Assume we have to mangle pathnames if the greatings string from the server contains the word Amiga. If this assumption is wrong I have to find another way to turn on path translation. * vfs/ftpfs.c (ftpfs_get_current_directory): Prepend a leading slash if it is missing. MC needs it as seperator between hostname and path in its internal url representation.
1999-01-31 23:28:13 +03:00
*semi = '\0'; /* Found valid suffix */
return p;
}
}
return p;
}
static int
path_magic (const char *path)
{
struct stat buf;
if (vfs_flags & FL_ALWAYS_MAGIC)
return 1;
if (!stat(path, &buf))
return 0;
return 1;
}
/*
* Splits path '/p1#op/inpath' into inpath,op; returns which vfs it is.
* What is left in path is p1. You still want to g_free(path), you DON'T
* want to free neither *inpath nor *op
*/
vfs *
vfs_split (char *path, char **inpath, char **op)
1998-02-27 07:54:42 +03:00
{
char *semi;
char *slash;
vfs *ret;
if (!path)
2002-12-26 05:21:37 +03:00
vfs_die("Cannot split NULL");
1998-02-27 07:54:42 +03:00
semi = strrchr (path, '#');
if (!semi || !path_magic(path))
return NULL;
slash = strchr (semi, PATH_SEP);
*semi = 0;
if (op)
*op = NULL;
if (inpath)
*inpath = NULL;
if (slash)
*slash = 0;
if ((ret = vfs_type_from_op (semi+1))){
if (op)
*op = semi + 1;
if (inpath)
*inpath = slash ? slash + 1 : NULL;
return ret;
}
if (slash)
*slash = PATH_SEP;
ret = vfs_split (path, inpath, op);
*semi = '#';
return ret;
}
static vfs *
vfs_rosplit (char *path)
{
char *semi;
char *slash;
vfs *ret;
g_return_val_if_fail(path, NULL);
semi = strrchr (path, '#');
if (!semi || !path_magic (path))
return NULL;
slash = strchr (semi, PATH_SEP);
*semi = 0;
if (slash)
*slash = 0;
ret = vfs_type_from_op (semi+1);
if (!ret && (vfs_flags & FL_NO_LOCALHASH))
return &vfs_nil_ops;
if (slash)
*slash = PATH_SEP;
if (!ret)
ret = vfs_rosplit (path);
*semi = '#';
return ret;
}
1998-02-27 07:54:42 +03:00
vfs *
vfs_type (char *path)
{
vfs *vfs;
vfs = vfs_rosplit(path);
if (!vfs)
vfs = &vfs_local_ops;
return vfs;
1998-02-27 07:54:42 +03:00
}
static struct vfs_stamping *stamps;
/*
* Returns the number of seconds remaining to the vfs timeout
1998-02-27 07:54:42 +03:00
*
* FIXME: currently this is set to 10 seconds. We should compute this.
*/
int
vfs_timeouts ()
1998-02-27 07:54:42 +03:00
{
return stamps ? 10 : 0;
}
static void
vfs_addstamp (vfs *v, vfsid id, struct vfs_stamping *parent)
1998-02-27 07:54:42 +03:00
{
1998-10-13 02:07:53 +04:00
if (v != &vfs_local_ops && id != (vfsid)-1){
struct vfs_stamping *stamp;
struct vfs_stamping *last_stamp = NULL;
1998-02-27 07:54:42 +03:00
for (stamp = stamps; stamp != NULL; stamp = stamp->next) {
if (stamp->v == v && stamp->id == id){
1998-02-27 07:54:42 +03:00
gettimeofday(&(stamp->time), NULL);
return;
}
last_stamp = stamp;
}
stamp = g_new (struct vfs_stamping, 1);
1998-02-27 07:54:42 +03:00
stamp->v = v;
stamp->id = id;
if (parent){
1998-02-27 07:54:42 +03:00
struct vfs_stamping *st = stamp;
while (parent){
st->parent = g_new (struct vfs_stamping, 1);
1998-02-27 07:54:42 +03:00
*st->parent = *parent;
parent = parent->parent;
st = st->parent;
}
st->parent = 0;
}
else
stamp->parent = 0;
1998-02-27 07:54:42 +03:00
gettimeofday (&(stamp->time), NULL);
stamp->next = 0;
if (stamps) {
/* Add to the end */
last_stamp->next = stamp;
} else {
/* Add first element */
1998-02-27 07:54:42 +03:00
stamps = stamp;
}
1998-02-27 07:54:42 +03:00
}
}
void
vfs_stamp (vfs *v, vfsid id)
1998-02-27 07:54:42 +03:00
{
struct vfs_stamping *stamp;
1998-02-27 07:54:42 +03:00
for (stamp = stamps; stamp != NULL; stamp = stamp->next)
if (stamp->v == v && stamp->id == id){
1998-02-27 07:54:42 +03:00
gettimeofday (&(stamp->time), NULL);
if (stamp->parent != NULL)
vfs_stamp (stamp->parent->v, stamp->parent->id);
1998-02-27 07:54:42 +03:00
return;
}
}
void
vfs_rm_parents (struct vfs_stamping *stamp)
1998-02-27 07:54:42 +03:00
{
struct vfs_stamping *parent;
while (stamp) {
parent = stamp->parent;
g_free (stamp);
stamp = parent;
1998-02-27 07:54:42 +03:00
}
}
void
vfs_rmstamp (vfs *v, vfsid id, int removeparents)
1998-02-27 07:54:42 +03:00
{
struct vfs_stamping *stamp, *st1;
for (stamp = stamps, st1 = NULL; stamp != NULL; st1 = stamp, stamp = stamp->next)
if (stamp->v == v && stamp->id == id){
if (stamp->parent != NULL){
1998-02-27 07:54:42 +03:00
if (removeparents)
vfs_rmstamp (stamp->parent->v, stamp->parent->id, 1);
vfs_rm_parents (stamp->parent);
}
if (st1 == NULL){
1998-02-27 07:54:42 +03:00
stamps = stamp->next;
} else {
st1->next = stamp->next;
}
g_free (stamp);
1998-02-27 07:54:42 +03:00
return;
}
}
static int
ferrno (vfs *vfs)
{
return vfs->ferrno ? (*vfs->ferrno)(vfs) : E_UNKNOWN;
/* Hope that error message is obscure enough ;-) */
}
int
mc_open (const char *filename, int flags, ...)
1998-02-27 07:54:42 +03:00
{
int handle;
int mode;
void *info;
va_list ap;
char *file = vfs_canon (filename);
vfs *vfs = vfs_type (file);
1998-02-27 07:54:42 +03:00
/* Get the mode flag */ /* FIXME: should look if O_CREAT is present */
1998-02-27 07:54:42 +03:00
va_start (ap, flags);
mode = va_arg (ap, int);
va_end (ap);
if (!vfs->open) {
errno = -EOPNOTSUPP;
return -1;
}
info = (*vfs->open) (vfs, file, flags, mode); /* open must be supported */
g_free (file);
1998-02-27 07:54:42 +03:00
if (!info){
errno = ferrno (vfs);
1998-02-27 07:54:42 +03:00
return -1;
}
handle = get_bucket ();
vfs_file_table [handle].fs_info = info;
vfs_file_table [handle].operations = vfs;
return handle;
}
#define vfs_op(handle) vfs_file_table [handle].operations
#define vfs_info(handle) vfs_file_table [handle].fs_info
#define vfs_free_bucket(handle) vfs_info(handle) = 0;
#define MC_OP(name, inarg, callarg, pre, post) \
int mc_##name inarg \
{ \
vfs *vfs; \
int result; \
\
pre \
result = vfs->name ? (*vfs->name)callarg : -1; \
post \
if (result == -1) \
errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
return result; \
}
1998-02-27 07:54:42 +03:00
1998-08-31 14:02:52 +04:00
#define MC_NAMEOP(name, inarg, callarg) \
MC_OP (name, inarg, callarg, path = vfs_canon (path); vfs = vfs_type (path);, g_free (path); )
1998-08-31 14:02:52 +04:00
#define MC_HANDLEOP(name, inarg, callarg) \
MC_OP (name, inarg, callarg, if (handle == -1) return -1; vfs = vfs_op (handle);, ;)
MC_HANDLEOP(read, (int handle, char *buffer, int count), (vfs_info (handle), buffer, count) )
1998-02-27 07:54:42 +03:00
int
mc_ctl (int handle, int ctlop, int arg)
1998-02-27 07:54:42 +03:00
{
vfs *vfs = vfs_op (handle);
1998-02-27 07:54:42 +03:00
return vfs->ctl ? (*vfs->ctl)(vfs_info (handle), ctlop, arg) : 0;
1998-02-27 07:54:42 +03:00
}
int
mc_setctl (char *path, int ctlop, char *arg)
1998-02-27 07:54:42 +03:00
{
vfs *vfs;
int result;
if (!path)
vfs_die("You don't want to pass NULL to mc_setctl.");
1998-02-27 07:54:42 +03:00
path = vfs_canon (path);
vfs = vfs_type (path);
result = vfs->setctl ? (*vfs->setctl)(vfs, path, ctlop, arg) : 0;
g_free (path);
1998-02-27 07:54:42 +03:00
return result;
}
int
mc_close (int handle)
1998-02-27 07:54:42 +03:00
{
vfs *vfs;
int result;
if (handle == -1 || !vfs_info (handle))
return -1;
vfs = vfs_op (handle);
if (handle < 3)
return close (handle);
1998-08-31 14:02:52 +04:00
if (!vfs->close)
vfs_die ("VFS must support close.\n");
1998-08-31 14:02:52 +04:00
result = (*vfs->close)(vfs_info (handle));
1998-02-27 07:54:42 +03:00
vfs_free_bucket (handle);
if (result == -1)
errno = ferrno (vfs);
1998-02-27 07:54:42 +03:00
return result;
}
DIR *
mc_opendir (char *dirname)
1998-02-27 07:54:42 +03:00
{
int handle, *handlep;
void *info;
vfs *vfs;
dirname = vfs_canon (dirname);
vfs = vfs_type (dirname);
info = vfs->opendir ? (*vfs->opendir)(vfs, dirname) : NULL;
g_free (dirname);
1998-02-27 07:54:42 +03:00
if (!info){
errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP;
1998-02-27 07:54:42 +03:00
return NULL;
}
handle = get_bucket ();
vfs_file_table [handle].fs_info = info;
vfs_file_table [handle].operations = vfs;
handlep = g_new (int, 1);
1998-02-27 07:54:42 +03:00
*handlep = handle;
return (DIR *) handlep;
}
void
mc_seekdir (DIR *dirp, int offset)
1998-08-31 14:02:52 +04:00
{
int handle;
vfs *vfs;
if (!dirp){
errno = EFAULT;
return;
}
handle = *(int *) dirp;
vfs = vfs_op (handle);
if (vfs->seekdir)
(*vfs->seekdir) (vfs_info (handle), offset);
else
errno = E_NOTSUPP;
}
1998-08-31 14:02:52 +04:00
#define MC_DIROP(name, type, onerr ) \
type mc_##name (DIR *dirp) \
{ \
int handle; \
vfs *vfs; \
1998-08-31 14:02:52 +04:00
type result; \
\
if (!dirp){ \
errno = EFAULT; \
1998-08-31 14:02:52 +04:00
return onerr; \
} \
handle = *(int *) dirp; \
vfs = vfs_op (handle); \
1998-08-31 14:02:52 +04:00
result = vfs->name ? (*vfs->name) (vfs_info (handle)) : onerr; \
if (result == onerr) \
errno = vfs->name ? ferrno(vfs) : E_NOTSUPP; \
1998-08-31 14:02:52 +04:00
return result; \
}
1998-08-31 14:02:52 +04:00
MC_DIROP (readdir, struct dirent *, NULL)
MC_DIROP (telldir, int, -1)
1998-02-27 07:54:42 +03:00
int
mc_closedir (DIR *dirp)
1998-02-27 07:54:42 +03:00
{
int handle = *(int *) dirp;
vfs *vfs = vfs_op (handle);
int result;
result = vfs->closedir ? (*vfs->closedir)(vfs_info (handle)) : -1;
1998-02-27 07:54:42 +03:00
vfs_free_bucket (handle);
g_free (dirp);
1998-02-27 07:54:42 +03:00
return result;
}
int mc_stat (const char *filename, struct stat *buf) {
vfs *vfs;
int result;
char *path;
path = vfs_canon (filename); vfs = vfs_type (path);
result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1;
g_free (path);
if (result == -1)
errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
return result;
}
int mc_lstat (const char *filename, struct stat *buf) {
vfs *vfs;
int result;
char *path;
path = vfs_canon (filename); vfs = vfs_type (path);
result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1;
g_free (path);
if (result == -1)
errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
return result;
}
int mc_fstat (int handle, struct stat *buf) {
vfs *vfs;
int result;
if (handle == -1)
return -1;
vfs = vfs_op (handle);
result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1;
if (result == -1)
errno = vfs->name ? ferrno (vfs) : E_NOTSUPP;
return result;
}
1998-02-27 07:54:42 +03:00
/*
* You must g_strdup whatever this function returns.
*/
1998-02-27 07:54:42 +03:00
static const char *
mc_return_cwd (void)
1998-02-27 07:54:42 +03:00
{
char *p;
struct stat my_stat, my_stat2;
if (!vfs_rosplit (current_dir)){
p = g_get_current_dir ();
if (!p) /* One of the directories in the path is not readable */
return current_dir;
1998-02-27 07:54:42 +03:00
/* Otherwise check if it is O.K. to use the current_dir */
if (!cd_symlinks ||
mc_stat (p, &my_stat) ||
mc_stat (current_dir, &my_stat2) ||
my_stat.st_ino != my_stat2.st_ino ||
my_stat.st_dev != my_stat2.st_dev){
g_free (current_dir);
current_dir = p;
1998-02-27 07:54:42 +03:00
return p;
} /* Otherwise we return current_dir below */
g_free (p);
1998-02-27 07:54:42 +03:00
}
return current_dir;
1998-02-27 07:54:42 +03:00
}
char *
mc_get_current_wd (char *buffer, int size)
1998-02-27 07:54:42 +03:00
{
const char *cwd = mc_return_cwd();
strncpy (buffer, cwd, size - 1);
buffer [size - 1] = 0;
return buffer;
1998-02-27 07:54:42 +03:00
}
MC_NAMEOP (chmod, (char *path, int mode), (vfs, path, mode))
MC_NAMEOP (chown, (char *path, int owner, int group), (vfs, path, owner, group))
MC_NAMEOP (utime, (char *path, struct utimbuf *times), (vfs, path, times))
MC_NAMEOP (readlink, (char *path, char *buf, int bufsiz), (vfs, path, buf, bufsiz))
MC_NAMEOP (unlink, (char *path), (vfs, path))
MC_NAMEOP (symlink, (char *name1, char *path), (vfs, name1, path))
1998-02-27 07:54:42 +03:00
1998-08-31 14:02:52 +04:00
#define MC_RENAMEOP(name) \
int mc_##name (const char *fname1, const char *fname2) \
1998-08-31 14:02:52 +04:00
{ \
vfs *vfs; \
int result; \
\
char *name2, *name1 = vfs_canon (fname1); \
1998-08-31 14:02:52 +04:00
vfs = vfs_type (name1); \
name2 = vfs_canon (fname2); \
1998-08-31 14:02:52 +04:00
if (vfs != vfs_type (name2)){ \
errno = EXDEV; \
g_free (name1); \
g_free (name2); \
1998-08-31 14:02:52 +04:00
return -1; \
} \
\
result = vfs->name ? (*vfs->name)(vfs, name1, name2) : -1; \
g_free (name1); \
g_free (name2); \
1998-08-31 14:02:52 +04:00
if (result == -1) \
errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \
1998-08-31 14:02:52 +04:00
return result; \
1998-02-27 07:54:42 +03:00
}
MC_RENAMEOP (link)
MC_RENAMEOP (rename)
1998-02-27 07:54:42 +03:00
MC_HANDLEOP (write, (int handle, char *buf, int nbyte), (vfs_info (handle), buf, nbyte))
1998-02-27 07:54:42 +03:00
off_t mc_lseek (int fd, off_t offset, int whence)
{
vfs *vfs;
1998-08-31 14:02:52 +04:00
int result;
1998-02-27 07:54:42 +03:00
if (fd == -1)
return -1;
vfs = vfs_op (fd);
1998-08-31 14:02:52 +04:00
result = vfs->lseek ? (*vfs->lseek)(vfs_info (fd), offset, whence) : -1;
if (result == -1)
errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP;
1998-08-31 14:02:52 +04:00
return result;
1998-02-27 07:54:42 +03:00
}
/*
* remove //, /./ and /../, local should point to big enough buffer
*/
#define ISSLASH(a) (!a || (a == '/'))
char *
vfs_canon (const char *path)
1998-02-27 07:54:42 +03:00
{
if (!path)
vfs_die("Cannot canonicalize NULL");
/* Tilde expansion */
if (*path == '~'){
1998-02-27 07:54:42 +03:00
char *local, *result;
local = tilde_expand (path);
if (local){
result = vfs_canon (local);
g_free (local);
1998-02-27 07:54:42 +03:00
return result;
}
}
/* Relative to current directory */
if (*path != PATH_SEP){
1998-02-27 07:54:42 +03:00
char *local, *result;
local = concat_dir_and_file (current_dir, path);
1998-02-27 07:54:42 +03:00
result = vfs_canon (local);
g_free (local);
1998-02-27 07:54:42 +03:00
return result;
}
/*
* So we have path of following form:
* /p1/p2#op/.././././p3#op/p4. Good luck.
*/
{
char *result = g_strdup (path);
canonicalize_pathname (result);
return result;
}
1998-02-27 07:54:42 +03:00
}
vfsid
vfs_ncs_getid (vfs *nvfs, char *dir, struct vfs_stamping **par)
1998-02-27 07:54:42 +03:00
{
vfsid nvfsid;
dir = concat_dir_and_file (dir, "");
nvfsid = (*nvfs->getid)(nvfs, dir, par);
g_free (dir);
1998-02-27 07:54:42 +03:00
return nvfsid;
}
static int
is_parent (vfs * nvfs, vfsid nvfsid, struct vfs_stamping *parent)
1998-02-27 07:54:42 +03:00
{
struct vfs_stamping *stamp;
1998-02-27 07:54:42 +03:00
for (stamp = parent; stamp; stamp = stamp->parent)
if (stamp->v == nvfs && stamp->id == nvfsid)
break;
1998-02-27 07:54:42 +03:00
return (stamp ? 1 : 0);
}
void
vfs_add_noncurrent_stamps (vfs * oldvfs, vfsid oldvfsid, struct vfs_stamping *parent)
1998-02-27 07:54:42 +03:00
{
vfs *nvfs, *n2vfs, *n3vfs;
vfsid nvfsid, n2vfsid, n3vfsid;
struct vfs_stamping *par, *stamp;
int f;
/* FIXME: As soon as we convert to multiple panels, this stuff
has to change. It works like this: We do not time out the
vfs's which are current in any panel and on the other
side we add the old directory with all its parents which
are not in any panel (if we find such one, we stop adding
parents to the time-outing structure. */
/* There are three directories we have to take care of: current_dir,
cpanel->cwd and opanel->cwd. Athough most of the time either
current_dir and cpanel->cwd or current_dir and opanel->cwd are the
same, it's possible that all three are different -- Norbert */
if (!cpanel)
return;
nvfs = vfs_type (current_dir);
nvfsid = vfs_ncs_getid (nvfs, current_dir, &par);
vfs_rmstamp (nvfs, nvfsid, 1);
f = is_parent (oldvfs, oldvfsid, par);
vfs_rm_parents (par);
1998-10-13 20:45:00 +04:00
if ((nvfs == oldvfs && nvfsid == oldvfsid) || oldvfsid == (vfsid *)-1 || f){
1998-02-27 07:54:42 +03:00
return;
}
if (get_current_type () == view_listing){
1998-02-27 07:54:42 +03:00
n2vfs = vfs_type (cpanel->cwd);
n2vfsid = vfs_ncs_getid (n2vfs, cpanel->cwd, &par);
f = is_parent (oldvfs, oldvfsid, par);
vfs_rm_parents (par);
if ((n2vfs == oldvfs && n2vfsid == oldvfsid) || f)
return;
} else {
n2vfs = (vfs *) -1;
n2vfsid = (vfs *) -1;
}
if (get_other_type () == view_listing){
1998-02-27 07:54:42 +03:00
n3vfs = vfs_type (opanel->cwd);
n3vfsid = vfs_ncs_getid (n3vfs, opanel->cwd, &par);
f = is_parent (oldvfs, oldvfsid, par);
vfs_rm_parents (par);
if ((n3vfs == oldvfs && n3vfsid == oldvfsid) || f)
return;
} else {
n3vfs = (vfs *)-1;
n3vfsid = (vfs *)-1;
}
if ((*oldvfs->nothingisopen) (oldvfsid)){
1998-10-13 02:07:53 +04:00
if (oldvfs == &vfs_extfs_ops && ((extfs_archive *) oldvfsid)->name == 0){
1998-02-27 07:54:42 +03:00
/* Free the resources immediatly when we leave a mtools fs
('cd a:') instead of waiting for the vfs-timeout */
(oldvfs->free) (oldvfsid);
} else
vfs_addstamp (oldvfs, oldvfsid, parent);
for (stamp = parent; stamp != NULL; stamp = stamp->parent){
1998-02-27 07:54:42 +03:00
if ((stamp->v == nvfs && stamp->id == nvfsid) ||
(stamp->v == n2vfs && stamp->id == n2vfsid) ||
(stamp->v == n3vfs && stamp->id == n3vfsid) ||
stamp->id == (vfsid) - 1 ||
!(*stamp->v->nothingisopen) (stamp->id))
break;
1998-10-13 02:07:53 +04:00
if (stamp->v == &vfs_extfs_ops && ((extfs_archive *) stamp->id)->name == 0){
1998-02-27 07:54:42 +03:00
(stamp->v->free) (stamp->id);
vfs_rmstamp (stamp->v, stamp->id, 0);
} else
vfs_addstamp (stamp->v, stamp->id, stamp->parent);
}
}
}
static void
vfs_stamp_path (char *path)
1998-02-27 07:54:42 +03:00
{
vfs *vfs;
vfsid id;
struct vfs_stamping *par, *stamp;
vfs = vfs_type (path);
id = vfs_ncs_getid (vfs, path, &par);
vfs_addstamp (vfs, id, par);
for (stamp = par; stamp != NULL; stamp = stamp->parent)
vfs_addstamp (stamp->v, stamp->id, stamp->parent);
vfs_rm_parents (par);
}
void
vfs_add_current_stamps (void)
1998-02-27 07:54:42 +03:00
{
vfs_stamp_path (current_dir);
These are a bunch of changes to fix CORBA and session management. They are almost complete (i.e. to handle all nitty gritty cases), but they seem to be working OK right now. SM should be much more stable now. Please tell me if you find any weird behavior - Federico 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * gdesktop-icon.c (desktop_icon_realize): Remove the WM_CLIENT_LEADER property from icon windows so that window managers will not store SM information for them. * gnome-open-dialog.c: Added missing #includes. * gdesktop-init.c (desktop_init_at): Removed an unused variable. * gdesktop.h: Added some missing prototypes. * gmain.h: Added some missing prototypes. * Makefile.in: Added gsession.[ch] to the list of sources. * gmain.c (create_panels): Consider whether we have a CORBA server and session management. * gdesktop.c: #include "gdesktop-init.h" * gdesktop.c: Added a missing cast to GNOME_DIALOG. * gmain.c (create_panels): Removed the run_desktop global variable. * glayout.c (create_container): Set the wmclass of the panel to include its unique ID. * gsession.[ch]: New file with the functions that deal with session management. * glayout.c (gnome_exit): Use session_set_restart(). * gcorba.c (corba_init): Now returns an int with an error value. (corba_init_server): Initialize the server properly. Fixed all the object implementation code. (corba_create_window): New function used to create a window with the CORBA server. * gmain.c (gnome_check_super_user): Now the check for running as root is done here. There should be no GUI code in src/. 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * dlg.c (dlg_run_done): Do not call the callback of a NULL current widget. * setup.h: Added missing prototype for setup_init(). * filegui.c (check_progress_buttons): Added a missing return value. * dlg.c (remove_widget): Added a missing return value. * main.c: Removed the global directory_list variable. Removed the main_corba_register_server() function. * main.h: Removed the global run_desktop variable. * panel.h: Now the panel structure has a unique numerical ID used for session management. * screen.c (panel_new): Maintain a unique ID for each panel. * main.c (maybe_display_linksdir): Handle display of the desktop init dir here. (main): Call gnome_check_super_user(). (init_corba_with_args): Call corba_init_server(). * main.c (init_corba_with_args): Do CORBA initialization here. Also removed the global force_activation option. 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * vfs.c (vfs_add_current_stamps): Only do stamping of the panels if they exist. * mcserv.c: #include <sys/wait.h> (get_client): Put `#ifdef __EMX__' around an otherwise-unused variable. * utilvfs.c (vfs_split_url): Fix NULL <-> 0 confusion when comparing characters. * ftpfs.c (retrieve_dir): Removed unused variable dot_dot_found. * extfs.c (extfs_init): Assign `key' to c, not `&key'.
1999-03-30 10:09:56 +04:00
if (cpanel) {
if (get_current_type () == view_listing)
vfs_stamp_path (cpanel->cwd);
}
if (opanel) {
if (get_other_type () == view_listing)
vfs_stamp_path (opanel->cwd);
}
1998-02-27 07:54:42 +03:00
}
/*
* VFS chdir.
* Return 0 on success, -1 on failure.
*/
int
mc_chdir (char *path)
1998-02-27 07:54:42 +03:00
{
char *new_dir, *new_dir_copy;
vfs *old_vfs, *new_vfs;
vfsid old_vfsid;
1998-02-27 07:54:42 +03:00
struct vfs_stamping *parent;
int result;
1998-02-27 07:54:42 +03:00
new_dir = vfs_canon (path);
new_vfs = vfs_type (new_dir);
if (!new_vfs->chdir)
vfs_die ("No chdir function defined");
/* new_vfs->chdir can write to the second argument, use a copy */
new_dir_copy = g_strdup (new_dir);
result = (*new_vfs->chdir) (new_vfs, new_dir_copy);
g_free (new_dir_copy);
if (result == -1) {
errno = ferrno (new_vfs);
g_free (new_dir);
return -1;
1998-02-27 07:54:42 +03:00
}
old_vfsid = vfs_ncs_getid (current_vfs, current_dir, &parent);
old_vfs = current_vfs;
/* Actually change directory */
g_free (current_dir);
current_dir = new_dir;
current_vfs = new_vfs;
/* This function uses the new current_dir implicitly */
vfs_add_noncurrent_stamps (old_vfs, old_vfsid, parent);
vfs_rm_parents (parent);
/* Sometimes we assume no trailing slash on cwd */
if (*current_dir) {
char *p;
1998-02-27 07:54:42 +03:00
p = strchr (current_dir, 0) - 1;
if (*p == PATH_SEP && p > current_dir)
*p = 0;
1998-02-27 07:54:42 +03:00
}
return 0;
1998-02-27 07:54:42 +03:00
}
int
vfs_current_is_local (void)
1998-02-27 07:54:42 +03:00
{
1998-10-13 02:07:53 +04:00
return current_vfs == &vfs_local_ops;
1998-02-27 07:54:42 +03:00
}
int
vfs_file_is_local (const char *file)
1998-02-27 07:54:42 +03:00
{
char *filename = vfs_canon (file);
vfs *vfs = vfs_type (filename);
1998-02-27 07:54:42 +03:00
g_free (filename);
1998-10-13 02:07:53 +04:00
return vfs == &vfs_local_ops;
1998-02-27 07:54:42 +03:00
}
int
vfs_file_is_ftp (char *filename)
1998-02-27 07:54:42 +03:00
{
#ifdef USE_NETCODE
vfs *vfs;
filename = vfs_canon (filename);
vfs = vfs_type (filename);
g_free (filename);
1998-10-13 02:07:53 +04:00
return vfs == &vfs_ftpfs_ops;
1998-02-27 07:54:42 +03:00
#else
return 0;
#endif
}
int
vfs_file_is_smb (char *filename)
{
#ifdef WITH_SMBFS
#ifdef USE_NETCODE
vfs *vfs;
filename = vfs_canon (filename);
vfs = vfs_type (filename);
g_free (filename);
return vfs == &vfs_smbfs_ops;
#endif /* USE_NETCODE */
#endif /* WITH_SMBFS */
return 0;
}
1998-02-27 07:54:42 +03:00
char *vfs_get_current_dir (void)
{
return current_dir;
}
1998-10-13 02:07:53 +04:00
static void vfs_setup_wd (void)
1998-02-27 07:54:42 +03:00
{
current_dir = g_strdup (PATH_SEP_STR);
if (!(vfs_flags & FL_NO_CWDSETUP))
mc_return_cwd();
1998-02-27 07:54:42 +03:00
if (strlen(current_dir)>MC_MAXPATHLEN-2)
1998-08-31 14:02:52 +04:00
vfs_die ("Current dir too long.\n");
1998-02-27 07:54:42 +03:00
}
MC_NAMEOP (mkdir, (char *path, mode_t mode), (vfs, path, mode))
MC_NAMEOP (rmdir, (char *path), (vfs, path))
MC_NAMEOP (mknod, (char *path, int mode, int dev), (vfs, path, mode, dev))
1998-02-27 07:54:42 +03:00
#ifdef HAVE_MMAP
1998-10-13 02:07:53 +04:00
static struct mc_mmapping {
1998-02-27 07:54:42 +03:00
caddr_t addr;
void *vfs_info;
vfs *vfs;
struct mc_mmapping *next;
} *mc_mmaparray = NULL;
caddr_t
mc_mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
1998-02-27 07:54:42 +03:00
{
vfs *vfs;
caddr_t result;
struct mc_mmapping *mcm;
if (fd == -1)
return (caddr_t) -1;
vfs = vfs_op (fd);
result = vfs->mmap ? (*vfs->mmap)(vfs, addr, len, prot, flags, vfs_info (fd), offset) : (caddr_t)-1;
1998-02-27 07:54:42 +03:00
if (result == (caddr_t)-1){
1998-08-31 14:02:52 +04:00
errno = ferrno (vfs);
1998-02-27 07:54:42 +03:00
return (caddr_t)-1;
}
mcm =g_new (struct mc_mmapping, 1);
1998-02-27 07:54:42 +03:00
mcm->addr = result;
mcm->vfs_info = vfs_info (fd);
mcm->vfs = vfs;
mcm->next = mc_mmaparray;
mc_mmaparray = mcm;
return result;
}
int
mc_munmap (caddr_t addr, size_t len)
1998-02-27 07:54:42 +03:00
{
struct mc_mmapping *mcm, *mcm2 = NULL;
for (mcm = mc_mmaparray; mcm != NULL; mcm2 = mcm, mcm = mcm->next){
if (mcm->addr == addr){
1998-02-27 07:54:42 +03:00
if (mcm2 == NULL)
mc_mmaparray = mcm->next;
else
mcm2->next = mcm->next;
if (mcm->vfs->munmap)
(*mcm->vfs->munmap)(mcm->vfs, addr, len, mcm->vfs_info);
g_free (mcm);
1998-02-27 07:54:42 +03:00
return 0;
}
}
return -1;
}
#endif
char *
mc_def_getlocalcopy (vfs *vfs, char *filename)
1998-02-27 07:54:42 +03:00
{
char *tmp, *suffix, *basename;
1998-02-27 07:54:42 +03:00
int fdin, fdout, i;
char buffer[8192];
struct stat mystat;
fdin = mc_open (filename, O_RDONLY);
if (fdin == -1)
return NULL;
/* retain original filename as a suffix for a temporary filename */
basename = strrchr (filename, PATH_SEP);
if (!basename)
basename = filename;
else
basename++;
suffix = g_strconcat ("-", basename, NULL);
if ((fdout = mc_mkstemps (&tmp, "vfs", suffix)) == -1) {
/* fallback for the case if the filename is too long */
fdout = mc_mkstemps (&tmp, "vfs", NULL);
}
g_free (suffix);
if (fdout == -1)
goto fail;
while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0) {
if (write (fdout, buffer, i) != i)
goto fail;
}
if (i == -1)
goto fail;
i = mc_close (fdin);
fdin = -1;
if (i == -1)
goto fail;
if (close (fdout) == -1)
goto fail;
if (mc_stat (filename, &mystat) != -1) {
chmod (tmp, mystat.st_mode);
1998-02-27 07:54:42 +03:00
}
return tmp;
fail:
if (fdout)
close (fdout);
if (fdin)
mc_close (fdin);
g_free (tmp);
return NULL;
1998-02-27 07:54:42 +03:00
}
char *
mc_getlocalcopy (const char *pathname)
1998-02-27 07:54:42 +03:00
{
char *result;
char *path = vfs_canon (pathname);
vfs *vfs = vfs_type (path);
1998-02-27 07:54:42 +03:00
result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, path) :
mc_def_getlocalcopy (vfs, path);
g_free (path);
1998-08-31 14:02:52 +04:00
if (!result)
errno = ferrno (vfs);
1998-02-27 07:54:42 +03:00
return result;
}
int
mc_def_ungetlocalcopy (vfs *vfs, char *filename, char *local, int has_changed)
{ /* Dijkstra probably hates me... But he should teach me how to do this nicely. */
int fdin = -1, fdout = -1, i;
if (has_changed){
char buffer [8192];
1998-02-27 07:54:42 +03:00
fdin = open (local, O_RDONLY);
if (fdin == -1)
goto failed;
1998-02-27 07:54:42 +03:00
fdout = mc_open (filename, O_WRONLY | O_TRUNC);
if (fdout == -1)
goto failed;
while ((i = read (fdin, buffer, sizeof (buffer))) > 0){
if (mc_write (fdout, buffer, i) != i)
goto failed;
}
if (i == -1)
goto failed;
if (close (fdin)==-1) {
fdin = -1;
goto failed;
}
fdin = -1;
if (mc_close (fdout)==-1) {
fdout = -1;
goto failed;
}
1998-02-27 07:54:42 +03:00
}
unlink (local);
g_free (local);
return 0;
failed:
message_1s (1, _("Changes to file lost"), filename);
if (fdout!=-1) mc_close(fdout);
if (fdin!=-1) close(fdin);
unlink (local);
g_free (local);
return -1;
1998-02-27 07:54:42 +03:00
}
int
mc_ungetlocalcopy (const char *pathname, char *local, int has_changed)
1998-02-27 07:54:42 +03:00
{
int return_value = 0;
char *path = vfs_canon (pathname);
vfs *vfs = vfs_type (path);
1998-02-27 07:54:42 +03:00
return_value = vfs->ungetlocalcopy ?
(*vfs->ungetlocalcopy)(vfs, path, local, has_changed) :
mc_def_ungetlocalcopy (vfs, path, local, has_changed);
g_free (path);
return return_value;
1998-02-27 07:54:42 +03:00
}
/*
* Hmm, as timeout is minute or so, do we need to care about usecs?
*/
static inline int
timeoutcmp (struct timeval *t1, struct timeval *t2)
1998-02-27 07:54:42 +03:00
{
return ((t1->tv_sec < t2->tv_sec)
|| ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec <= t2->tv_usec)));
}
/* This is called from timeout handler with now = 0, or can be called
with now = 1 to force freeing all filesystems that are not in use */
void
vfs_expire (int now)
1998-02-27 07:54:42 +03:00
{
static int locked = 0;
1998-02-27 07:54:42 +03:00
struct timeval time;
struct vfs_stamping *stamp, *st;
/* Avoid recursive invocation, e.g. when one of the free functions
calls message_1s */
if (locked)
return;
locked = 1;
1998-02-27 07:54:42 +03:00
gettimeofday (&time, NULL);
time.tv_sec -= vfs_timeout;
for (stamp = stamps; stamp != NULL;){
if (now || (timeoutcmp (&stamp->time, &time))){
1998-02-27 07:54:42 +03:00
st = stamp->next;
(*stamp->v->free) (stamp->id);
vfs_rmstamp (stamp->v, stamp->id, 0);
stamp = st;
} else
stamp = stamp->next;
}
locked = 0;
1998-02-27 07:54:42 +03:00
}
void
vfs_timeout_handler (void)
{
vfs_expire (0);
}
void
vfs_init (void)
1998-02-27 07:54:42 +03:00
{
time_t current_time;
struct tm *t;
memset (vfs_file_table, 0, sizeof (vfs_file_table));
1998-02-27 07:54:42 +03:00
current_time = time (NULL);
t = localtime (&current_time);
current_mday = t->tm_mday;
current_mon = t->tm_mon;
1998-02-27 07:54:42 +03:00
current_year = t->tm_year;
1998-10-13 02:07:53 +04:00
/* We do not want to register vfs_local_ops */
1998-02-27 07:54:42 +03:00
#ifdef USE_NETCODE
tcp_init();
1998-10-13 02:07:53 +04:00
vfs_register (&vfs_ftpfs_ops);
vfs_register (&vfs_fish_ops);
#ifdef WITH_SMBFS
vfs_register (&vfs_smbfs_ops);
#endif /* WITH_SMBFS */
#ifdef WITH_MCFS
1998-10-13 02:07:53 +04:00
vfs_register (&vfs_mcfs_ops);
#endif /* WITH_SMBFS */
#endif /* USE_NETCODE */
1998-10-13 02:07:53 +04:00
vfs_register (&vfs_extfs_ops);
vfs_register (&vfs_sfs_ops);
vfs_register (&vfs_tarfs_ops);
vfs_register (&vfs_cpiofs_ops);
#ifdef USE_EXT2FSLIB
1998-10-13 02:07:53 +04:00
vfs_register (&vfs_undelfs_ops);
#endif /* USE_EXT2FSLIB */
1998-02-27 07:54:42 +03:00
vfs_setup_wd ();
}
void
vfs_shut (void)
1998-02-27 07:54:42 +03:00
{
struct vfs_stamping *stamp, *st;
vfs *vfs;
1998-02-27 07:54:42 +03:00
for (stamp = stamps, stamps = 0; stamp != NULL;){
1998-02-27 07:54:42 +03:00
(*stamp->v->free)(stamp->id);
st = stamp->next;
g_free (stamp);
1998-02-27 07:54:42 +03:00
stamp = st;
}
if (stamps)
vfs_rmstamp (stamps->v, stamps->id, 1);
if (current_dir)
g_free (current_dir);
1998-02-27 07:54:42 +03:00
for (vfs=vfs_list; vfs; vfs=vfs->next)
if (vfs->done)
(*vfs->done) (vfs);
1998-02-27 07:54:42 +03:00
}
/*
* These ones grab information from the VFS
1998-02-27 07:54:42 +03:00
* and handles them to an upper layer
*/
void
vfs_fill_names (void (*func)(char *))
1998-02-27 07:54:42 +03:00
{
vfs *vfs;
for (vfs=vfs_list; vfs; vfs=vfs->next)
if (vfs->fill_names)
(*vfs->fill_names) (vfs, func);
1998-02-27 07:54:42 +03:00
}
/* Following stuff (parse_ls_lga) is used by ftpfs and extfs */
#define MAXCOLS 30
1998-02-27 07:54:42 +03:00
static char *columns [MAXCOLS]; /* Points to the string in column n */
static int column_ptr [MAXCOLS]; /* Index from 0 to the starting positions of the columns */
int
vfs_split_text (char *p)
1998-02-27 07:54:42 +03:00
{
char *original = p;
int numcols;
memset (columns, 0, sizeof (columns));
1998-02-27 07:54:42 +03:00
for (numcols = 0; *p && numcols < MAXCOLS; numcols++){
while (*p == ' ' || *p == '\r' || *p == '\n'){
*p = 0;
p++;
}
columns [numcols] = p;
column_ptr [numcols] = p - original;
while (*p && *p != ' ' && *p != '\r' && *p != '\n')
p++;
}
return numcols;
}
static int
is_num (int idx)
1998-02-27 07:54:42 +03:00
{
char *column = columns[idx];
if (!column || column[0] < '0' || column[0] > '9')
1998-02-27 07:54:42 +03:00
return 0;
1998-02-27 07:54:42 +03:00
return 1;
}
/* Return 1 for MM-DD-YY and MM-DD-YYYY */
static int
is_dos_date (const char *str)
{
int len;
if (!str)
return 0;
len = strlen (str);
if (len != 8 && len != 10)
return 0;
if (str[2] != str[5])
return 0;
if (!strchr ("\\-/", (int) str[2]))
return 0;
return 1;
}
static int
is_week (const char *str, struct tm *tim)
{
static const char *week = "SunMonTueWedThuFriSat";
char *pos;
if (!str)
return 0;
if ((pos = strstr (week, str)) != NULL) {
if (tim != NULL)
tim->tm_wday = (pos - week) / 3;
return 1;
}
return 0;
}
static int
is_month (const char *str, struct tm *tim)
{
static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
char *pos;
if (!str)
return 0;
if ((pos = strstr (month, str)) != NULL) {
if (tim != NULL)
tim->tm_mon = (pos - month) / 3;
return 1;
}
return 0;
}
/*
* Check for possible locale's abbreviated month name (Jan..Dec).
* Any 3 bytes long string without digit and control characters.
* isalpha() is locale specific, so it cannot be used if current
* locale is "C" and ftp server use Cyrillic.
* TODO: Punctuation characters also cannot be part of month name.
* NB: It is assumed there are no whitespaces in month.
*/
static int
is_localized_month (const unsigned char *month)
{
int i = 0;
while ((i < 3) && *month && !isdigit (*month) && !iscntrl (*month)) {
i++;
month++;
}
return ((i == 3) && (*month == 0));
}
static int
is_time (const char *str, struct tm *tim)
{
char *p, *p2;
if (!str)
return 0;
if ((p = strchr (str, ':')) && (p2 = strrchr (str, ':'))) {
if (p != p2) {
if (sscanf
(str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min,
&tim->tm_sec) != 3)
return 0;
} else {
if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
return 0;
}
} else
return 0;
return 1;
}
static int is_year (char *str, struct tm *tim)
{
long year;
if (!str)
return 0;
if (strchr (str, ':'))
return 0;
if (strlen (str) != 4)
return 0;
if (sscanf (str, "%ld", &year) != 1)
return 0;
1998-08-31 14:02:52 +04:00
if (year < 1900 || year > 3000)
return 0;
1998-08-31 14:02:52 +04:00
tim->tm_year = (int) (year - 1900);
return 1;
}
1998-08-31 14:02:52 +04:00
/*
* FIXME: this is broken. Consider following entry:
* -rwx------ 1 root root 1 Aug 31 10:04 2904 1234
* where "2904 1234" is filename. Well, this code decodes it as year :-(.
1998-08-31 14:02:52 +04:00
*/
int
vfs_parse_filetype (char c)
1998-02-27 07:54:42 +03:00
{
switch (c) {
case 'd': return S_IFDIR;
case 'b': return S_IFBLK;
case 'c': return S_IFCHR;
case 'l': return S_IFLNK;
case 's': /* Socket */
#ifdef S_IFSOCK
return S_IFSOCK;
#else
/* If not supported, we fall through to IFIFO */
return S_IFIFO;
#endif
case 'D': /* Solaris door */
#ifdef S_IFDOOR
return S_IFDOOR;
#else
return S_IFIFO;
#endif
case 'p': return S_IFIFO;
case 'm': case 'n': /* Don't know what these are :-) */
case '-': case '?': return S_IFREG;
default: return -1;
}
}
int vfs_parse_filemode (const char *p)
{ /* converts rw-rw-rw- into 0666 */
int res = 0;
switch (*(p++)){
case 'r': res |= 0400; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'w': res |= 0200; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'x': res |= 0100; break;
case 's': res |= 0100 | S_ISUID; break;
case 'S': res |= S_ISUID; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'r': res |= 0040; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'w': res |= 0020; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'x': res |= 0010; break;
case 's': res |= 0010 | S_ISGID; break;
case 'l': /* Solaris produces these */
case 'S': res |= S_ISGID; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'r': res |= 0004; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'w': res |= 0002; break;
case '-': break;
default: return -1;
}
switch (*(p++)){
case 'x': res |= 0001; break;
case 't': res |= 0001 | S_ISVTX; break;
case 'T': res |= S_ISVTX; break;
case '-': break;
default: return -1;
}
return res;
}
/* This function parses from idx in the columns[] array */
int
vfs_parse_filedate (int idx, time_t *t)
{
char *p;
struct tm tim;
int d[3];
int got_year = 0;
int l10n = 0; /* Locale's abbreviated month name */
/* Let's setup default time values */
tim.tm_year = current_year;
tim.tm_mon = current_mon;
tim.tm_mday = current_mday;
tim.tm_hour = 0;
tim.tm_min = 0;
tim.tm_sec = 0;
tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
p = columns[idx++];
/* We eat weekday name in case of extfs */
if (is_week (p, &tim))
p = columns[idx++];
/* Month name */
if (is_month (p, &tim)) {
/* And we expect, it followed by day number */
if (is_num (idx))
tim.tm_mday = (int) atol (columns[idx++]);
else
return 0; /* No day */
} else {
/* We usually expect:
Mon DD hh:mm
Mon DD YYYY
But in case of extfs we allow these date formats:
Mon DD YYYY hh:mm
Mon DD hh:mm YYYY
Wek Mon DD hh:mm:ss YYYY
MM-DD-YY hh:mm
where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
/* Special case with MM-DD-YY or MM-DD-YYYY */
if (is_dos_date (p)) {
p[2] = p[5] = '-';
if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) == 3) {
/* Months are zero based */
if (d[0] > 0)
d[0]--;
if (d[2] > 1900) {
d[2] -= 1900;
} else {
/* Y2K madness */
if (d[2] < 70)
d[2] += 100;
}
tim.tm_mon = d[0];
tim.tm_mday = d[1];
tim.tm_year = d[2];
got_year = 1;
} else
return 0; /* sscanf failed */
} else {
/* Locale's abbreviated month name followed by day number */
if (is_localized_month (p) && (is_num (idx++)))
l10n = 1;
else
return 0; /* unsupported format */
}
}
/* Here we expect to find time and/or year */
if (is_num (idx)) {
if (is_time (columns[idx], &tim)
|| (got_year = is_year (columns[idx], &tim))) {
idx++;
/* This is a special case for ctime() or Mon DD YYYY hh:mm */
if (is_num (idx) && (columns[idx + 1][0])) {
if (got_year) {
if (is_time (columns[idx], &tim))
idx++; /* time also */
} else {
if ((got_year = is_year (columns[idx], &tim)))
idx++; /* year also */
}
}
} /* only time or date */
} else
return 0; /* Nor time or date */
/*
* If the date is less than 6 months in the past, it is shown without year
* other dates in the past or future are shown with year but without time
* This does not check for years before 1900 ... I don't know, how
* to represent them at all
*/
if (!got_year && current_mon < 6 && current_mon < tim.tm_mon
&& tim.tm_mon - current_mon >= 6)
tim.tm_year--;
if (l10n || (*t = mktime (&tim)) < 0)
*t = 0;
return idx;
}
int
vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, char **linkname)
{
int idx, idx2, num_cols;
1998-02-27 07:54:42 +03:00
int i;
char *p_copy = NULL;
char *t = NULL;
const char *line = p;
if (strncmp (p, "total", 5) == 0)
1998-02-27 07:54:42 +03:00
return 0;
1998-10-13 02:07:53 +04:00
if ((i = vfs_parse_filetype(*(p++))) == -1)
1998-11-16 18:52:27 +03:00
goto error;
s->st_mode = i;
if (*p == ' ') /* Notwell 4 */
p++;
if (*p == '['){
1998-02-27 07:54:42 +03:00
if (strlen (p) <= 8 || p [8] != ']')
1998-11-16 18:52:27 +03:00
goto error;
1998-02-27 07:54:42 +03:00
/* Should parse here the Notwell permissions :) */
if (S_ISDIR (s->st_mode))
s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
else
s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
p += 9;
} else {
if ((i = vfs_parse_filemode(p)) == -1)
1998-11-16 18:52:27 +03:00
goto error;
s->st_mode |= i;
p += 9;
/* This is for an extra ACL attribute (HP-UX) */
if (*p == '+')
p++;
1998-02-27 07:54:42 +03:00
}
p_copy = g_strdup(p);
num_cols = vfs_split_text (p_copy);
1998-02-27 07:54:42 +03:00
s->st_nlink = atol (columns [0]);
if (s->st_nlink <= 0)
1998-11-16 18:52:27 +03:00
goto error;
1998-02-27 07:54:42 +03:00
if (!is_num (1))
s->st_uid = finduid (columns [1]);
else
s->st_uid = (uid_t) atol (columns [1]);
/* Mhm, the ls -lg did not produce a group field */
for (idx = 3; idx <= 5; idx++)
if (is_month (columns[idx], NULL) || is_week (columns[idx], NULL)
|| is_dos_date (columns[idx]) || is_localized_month (columns[idx]))
break;
1998-02-27 07:54:42 +03:00
if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
goto error;
/* We don't have gid */
if (idx == 3 || (idx == 4 && (S_ISCHR(s->st_mode) || S_ISBLK (s->st_mode))))
1998-02-27 07:54:42 +03:00
idx2 = 2;
else {
/* We have gid field */
1998-02-27 07:54:42 +03:00
if (is_num (2))
s->st_gid = (gid_t) atol (columns [2]);
else
s->st_gid = findgid (columns [2]);
idx2 = 3;
}
/* This is device */
if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)){
int maj, min;
if (!is_num (idx2) || sscanf(columns [idx2], " %d,", &maj) != 1)
goto error;
if (!is_num (++idx2) || sscanf(columns [idx2], " %d", &min) != 1)
1998-11-16 18:52:27 +03:00
goto error;
1998-02-27 07:54:42 +03:00
#ifdef HAVE_ST_RDEV
s->st_rdev = ((maj & 0xff) << 8) | (min & 0xffff00ff);
1998-02-27 07:54:42 +03:00
#endif
s->st_size = 0;
1998-02-27 07:54:42 +03:00
} else {
/* Common file size */
1998-02-27 07:54:42 +03:00
if (!is_num (idx2))
1998-11-16 18:52:27 +03:00
goto error;
1998-02-27 07:54:42 +03:00
s->st_size = (size_t) atol (columns [idx2]);
#ifdef HAVE_ST_RDEV
s->st_rdev = 0;
#endif
}
idx = vfs_parse_filedate (idx, &s->st_mtime);
if (!idx)
1998-11-16 18:52:27 +03:00
goto error;
/* Use resulting time value */
s->st_atime = s->st_ctime = s->st_mtime;
/* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */
1998-02-27 07:54:42 +03:00
#ifdef HAVE_ST_BLKSIZE
s->st_blksize = 512;
#endif
#ifdef HAVE_ST_BLOCKS
s->st_blocks = (s->st_size + 511) / 512;
#endif
for (i = idx + 1, idx2 = 0; i < num_cols; i++ )
if (strcmp (columns [i], "->") == 0){
1998-02-27 07:54:42 +03:00
idx2 = i;
break;
}
if (((S_ISLNK (s->st_mode) ||
1998-02-27 07:54:42 +03:00
(num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
&& idx2){
if (filename){
*filename = g_strndup (p + column_ptr [idx], column_ptr [idx2] - column_ptr [idx] - 1);
1998-02-27 07:54:42 +03:00
}
if (linkname){
t = g_strdup (p + column_ptr [idx2+1]);
*linkname = t;
1998-02-27 07:54:42 +03:00
}
} else {
/* Extract the filename from the string copy, not from the columns
* this way we have a chance of entering hidden directories like ". ."
*/
if (filename){
/*
* filename = g_strdup (columns [idx++]);
*/
t = g_strdup (p + column_ptr [idx]);
*filename = t;
1998-02-27 07:54:42 +03:00
}
if (linkname)
*linkname = NULL;
}
if (t) {
int p = strlen (t);
if ((--p > 0) && (t [p] == '\r' || t [p] == '\n'))
t [p] = 0;
if ((--p > 0) && (t [p] == '\r' || t [p] == '\n'))
t [p] = 0;
}
g_free (p_copy);
1998-11-16 18:52:27 +03:00
return 1;
error:
{
static int errorcount = 0;
if (++errorcount < 5) {
2002-12-08 04:12:18 +03:00
message_1s (1, _("Cannot parse:"), (p_copy && *p_copy) ? p_copy : line);
} else if (errorcount == 5)
message_1s (1, _("Error"), _("More parsing errors will be ignored."));
}
g_free (p_copy);
1998-11-16 18:52:27 +03:00
return 0;
1998-02-27 07:54:42 +03:00
}
void
2002-11-15 09:38:55 +03:00
vfs_die (const char *m)
{
message_1s (1, _("Internal error:"), m);
exit (1);
}
void
vfs_print_stats (const char *fs_name, const char *action, const char *file_name, off_t have, off_t need)
{
static char *i18n_percent_transf_format = NULL, *i18n_transf_format = NULL;
if (i18n_percent_transf_format == NULL) {
i18n_percent_transf_format = _("%s: %s: %s %3d%% (%lu bytes transferred)");
i18n_transf_format = _("%s: %s: %s %lu bytes transferred");
}
if (need)
print_vfs_message (i18n_percent_transf_format, fs_name, action,
file_name, (int)((double)have*100/need), (unsigned long) have);
else
print_vfs_message (i18n_transf_format,
fs_name, action, file_name, (unsigned long) have);
}
char *
vfs_get_password (char *msg)
{
return (char *) input_dialog (msg, _("Password:"), INPUT_PASSWORD);
}
1998-10-13 02:07:53 +04:00
/*
* Returns vfs path corresponding to given url. If passed string is
* not recognized as url, g_strdup(url) is returned.
*/
1998-10-13 02:07:53 +04:00
char *
vfs_translate_url (char *url)
{
if (strncmp (url, "ftp://", 6) == 0)
return g_strconcat ("/#ftp:", url + 6, NULL);
2000-09-15 00:53:57 +04:00
else if (strncmp (url, "a:", 2) == 0)
return g_strdup ("/#a");
1998-10-13 02:07:53 +04:00
else
return g_strdup (url);
1998-10-13 02:07:53 +04:00
}