diff --git a/lib/vfs/Makefile.am b/lib/vfs/Makefile.am index 8a1686f87..4d2d51915 100644 --- a/lib/vfs/Makefile.am +++ b/lib/vfs/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libmcvfs.la AM_CFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) libmcvfs_la_SOURCES = \ + interface.c interface.h \ vfs.c vfs.h \ direntry.c xdirentry.h \ utilvfs.c utilvfs.h \ diff --git a/lib/vfs/interface.c b/lib/vfs/interface.c new file mode 100644 index 000000000..5d316ca75 --- /dev/null +++ b/lib/vfs/interface.c @@ -0,0 +1,780 @@ +/* Virtual File System: interface functions + Copyright (C) 2011 Free Software Foundation, Inc. + + Written by: + Slava Zanko , 2011 + + This file is part of the Midnight Commander. + + The Midnight Commander 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. + + The Midnight Commander 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + */ + +/** + * \file + * \brief Source: Virtual File System: path handlers + * \author Slava Zanko + * \date 2011 + */ + + +#include + +#include +#include /* For atol() */ +#include +#include +#include +#include +#include +#include /* is_digit() */ +#include +#include +#include +#include + +#include "lib/global.h" + +#include "lib/widget.h" /* message() */ +#include "lib/strutil.h" /* str_crt_conv_from() */ + +#include "vfs.h" +#include "utilvfs.h" +#include "gc.h" + +extern GString *vfs_str_buffer; +extern struct vfs_class *current_vfs; +extern char *current_dir; + +/*** global variables ****************************************************************************/ + +struct dirent *mc_readdir_result = NULL; + +/*** file scope macro definitions ****************************************************************/ + +/*** file scope type declarations ****************************************************************/ + +struct vfs_dirinfo +{ + DIR *info; + GIConv converter; +}; + +/*** file scope variables ************************************************************************/ + +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +static char * +mc_def_getlocalcopy (const char *filename) +{ + char *tmp; + int fdin, fdout; + ssize_t i; + char buffer[8192]; + struct stat mystat; + + fdin = mc_open (filename, O_RDONLY | O_LINEAR); + if (fdin == -1) + return NULL; + + fdout = vfs_mkstemps (&tmp, "vfs", filename); + + 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) + { + fdout = -1; + goto fail; + } + + if (mc_stat (filename, &mystat) != -1) + chmod (tmp, mystat.st_mode); + + return tmp; + + fail: + if (fdout != -1) + close (fdout); + if (fdin != -1) + mc_close (fdin); + g_free (tmp); + return NULL; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename, + const char *local, int has_changed) +{ + int fdin = -1, fdout = -1; + if (has_changed) + { + char buffer[8192]; + ssize_t i; + + if (!vfs->write) + goto failed; + + fdin = open (local, O_RDONLY); + if (fdin == -1) + goto failed; + 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, (size_t) 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; + } + } + unlink (local); + return 0; + + failed: + message (D_ERROR, _("Changes to file lost"), "%s", filename); + if (fdout != -1) + mc_close (fdout); + if (fdin != -1) + close (fdin); + unlink (local); + return -1; +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +int +mc_open (const char *filename, int flags, ...) +{ + int mode = 0; + void *info; + va_list ap; + char *file; + struct vfs_class *vfs; + + file = vfs_canon_and_translate (filename); + if (file == NULL) + return -1; + + vfs = vfs_get_class (file); + + /* Get the mode flag */ + if (flags & O_CREAT) + { + va_start (ap, flags); + mode = va_arg (ap, int); + va_end (ap); + } + + if (vfs->open == NULL) + { + g_free (file); + errno = -EOPNOTSUPP; + return -1; + } + + info = vfs->open (vfs, file, flags, mode); /* open must be supported */ + g_free (file); + if (info == NULL) + { + errno = vfs_ferrno (vfs); + return -1; + } + + return vfs_new_handle (vfs, info); +} + +/* --------------------------------------------------------------------------------------------- */ + +/* *INDENT-OFF* */ + +#define MC_NAMEOP(name, inarg, callarg) \ +int mc_##name inarg \ +{ \ + struct vfs_class *vfs; \ + int result; \ + char *mpath; \ + mpath = vfs_canon_and_translate (path); \ + if (mpath == NULL) \ + return -1; \ + vfs = vfs_get_class (mpath); \ + if (vfs == NULL) \ + { \ + g_free (mpath); \ + return -1; \ + } \ + result = vfs->name != NULL ? vfs->name callarg : -1; \ + g_free (mpath); \ + if (result == -1) \ + errno = vfs->name != NULL ? vfs_ferrno (vfs) : E_NOTSUPP; \ + return result; \ +} + +MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode)) +MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, owner, group)) +MC_NAMEOP (utime, (const char *path, struct utimbuf * times), (vfs, mpath, times)) +MC_NAMEOP (readlink, (const char *path, char *buf, size_t bufsiz), (vfs, mpath, buf, bufsiz)) +MC_NAMEOP (unlink, (const char *path), (vfs, mpath)) +MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode)) +MC_NAMEOP (rmdir, (const char *path), (vfs, mpath)) +MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev)) + +/* *INDENT-ON* */ + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_symlink (const char *name1, const char *path) +{ + struct vfs_class *vfs; + int result; + char *mpath; + char *lpath; + char *tmp; + + mpath = vfs_canon_and_translate (path); + if (mpath == NULL) + return -1; + + tmp = g_strdup (name1); + lpath = vfs_translate_path_n (tmp); + g_free (tmp); + + if (lpath != NULL) + { + vfs = vfs_get_class (mpath); + result = vfs->symlink != NULL ? vfs->symlink (vfs, lpath, mpath) : -1; + g_free (lpath); + g_free (mpath); + + if (result == -1) + errno = vfs->symlink != NULL ? vfs_ferrno (vfs) : E_NOTSUPP; + return result; + } + + g_free (mpath); + + return -1; +} + +/* --------------------------------------------------------------------------------------------- */ + +/* *INDENT-OFF* */ + +#define MC_HANDLEOP(name, inarg, callarg) \ +ssize_t mc_##name inarg \ +{ \ + struct vfs_class *vfs; \ + int result; \ + if (handle == -1) \ + return -1; \ + vfs = vfs_class_find_by_handle (handle); \ + if (vfs == NULL) \ + return -1; \ + result = vfs->name != NULL ? vfs->name callarg : -1; \ + if (result == -1) \ + errno = vfs->name != NULL ? vfs_ferrno (vfs) : E_NOTSUPP; \ + return result; \ +} + +MC_HANDLEOP (read, (int handle, void *buffer, size_t count), (vfs_class_data_find_by_handle (handle), buffer, count)) +MC_HANDLEOP (write, (int handle, const void *buf, size_t nbyte), (vfs_class_data_find_by_handle (handle), buf, nbyte)) + +/* --------------------------------------------------------------------------------------------- */ + +#define MC_RENAMEOP(name) \ +int mc_##name (const char *fname1, const char *fname2) \ +{ \ + struct vfs_class *vfs; \ + int result; \ + char *name2, *name1; \ + name1 = vfs_canon_and_translate (fname1); \ + if (name1 == NULL) \ + return -1; \ + name2 = vfs_canon_and_translate (fname2); \ + if (name2 == NULL) { \ + g_free (name1); \ + return -1; \ + } \ + vfs = vfs_get_class (name1); \ + if (vfs != vfs_get_class (name2)) \ + { \ + errno = EXDEV; \ + g_free (name1); \ + g_free (name2); \ + return -1; \ + } \ + result = vfs->name != NULL ? vfs->name (vfs, name1, name2) : -1; \ + g_free (name1); \ + g_free (name2); \ + if (result == -1) \ + errno = vfs->name != NULL ? vfs_ferrno (vfs) : E_NOTSUPP; \ + return result; \ +} + +MC_RENAMEOP (link) +MC_RENAMEOP (rename) + +/* *INDENT-ON* */ + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_ctl (int handle, int ctlop, void *arg) +{ + struct vfs_class *vfs = vfs_class_find_by_handle (handle); + + if (vfs == NULL) + return 0; + + return vfs->ctl ? (*vfs->ctl) (vfs_class_data_find_by_handle (handle), ctlop, arg) : 0; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_setctl (const char *path, int ctlop, void *arg) +{ + struct vfs_class *vfs; + int result = -1; + char *mpath; + + if (path == NULL) + vfs_die ("You don't want to pass NULL to mc_setctl."); + + mpath = vfs_canon_and_translate (path); + if (mpath != NULL) + { + vfs = vfs_get_class (mpath); + result = vfs->setctl != NULL ? vfs->setctl (vfs, mpath, ctlop, arg) : 0; + g_free (mpath); + } + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_close (int handle) +{ + struct vfs_class *vfs; + int result; + + if (handle == -1 || !vfs_class_data_find_by_handle (handle)) + return -1; + + vfs = vfs_class_find_by_handle (handle); + if (vfs == NULL) + return -1; + + if (handle < 3) + return close (handle); + + if (!vfs->close) + vfs_die ("VFS must support close.\n"); + result = (*vfs->close) (vfs_class_data_find_by_handle (handle)); + vfs_free_handle (handle); + if (result == -1) + errno = vfs_ferrno (vfs); + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +DIR * +mc_opendir (const char *dirname) +{ + int handle, *handlep; + void *info; + struct vfs_class *vfs; + char *canon; + char *dname; + struct vfs_dirinfo *dirinfo; + const char *encoding; + + canon = vfs_canon (dirname); + dname = vfs_translate_path_n (canon); + + if (dname != NULL) + { + vfs = vfs_get_class (dname); + info = vfs->opendir ? (*vfs->opendir) (vfs, dname) : NULL; + g_free (dname); + + if (info == NULL) + { + errno = vfs->opendir ? vfs_ferrno (vfs) : E_NOTSUPP; + g_free (canon); + return NULL; + } + + dirinfo = g_new (struct vfs_dirinfo, 1); + dirinfo->info = info; + + encoding = vfs_get_encoding (canon); + g_free (canon); + dirinfo->converter = (encoding != NULL) ? str_crt_conv_from (encoding) : str_cnv_from_term; + if (dirinfo->converter == INVALID_CONV) + dirinfo->converter = str_cnv_from_term; + + handle = vfs_new_handle (vfs, dirinfo); + + handlep = g_new (int, 1); + *handlep = handle; + return (DIR *) handlep; + } + else + { + g_free (canon); + return NULL; + } +} + +/* --------------------------------------------------------------------------------------------- */ + +struct dirent * +mc_readdir (DIR * dirp) +{ + int handle; + struct vfs_class *vfs; + struct dirent *entry = NULL; + struct vfs_dirinfo *dirinfo; + estr_t state; + + if (!mc_readdir_result) + { + /* We can't just allocate struct dirent as (see man dirent.h) + * struct dirent has VERY nonnaive semantics of allocating + * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_, + * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy + * heap corrupter. So, allocate longliving dirent with at least + * (MAXNAMLEN + 1) for d_name in it. + * Strictly saying resulting dirent is unusable as we don't adjust internal + * structures, holding dirent size. But we don't use it in libc infrastructure. + * TODO: to make simpler homemade dirent-alike structure. + */ + mc_readdir_result = (struct dirent *) g_malloc (sizeof (struct dirent) + MAXNAMLEN + 1); + } + + if (!dirp) + { + errno = EFAULT; + return NULL; + } + handle = *(int *) dirp; + + vfs = vfs_class_find_by_handle (handle); + if (vfs == NULL) + return NULL; + + dirinfo = vfs_class_data_find_by_handle (handle); + if (vfs->readdir) + { + entry = (*vfs->readdir) (dirinfo->info); + if (entry == NULL) + return NULL; + g_string_set_size (vfs_str_buffer, 0); + state = str_vfs_convert_from (dirinfo->converter, entry->d_name, vfs_str_buffer); + mc_readdir_result->d_ino = entry->d_ino; + g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, MAXNAMLEN + 1); + } + if (entry == NULL) + errno = vfs->readdir ? vfs_ferrno (vfs) : E_NOTSUPP; + return (entry != NULL) ? mc_readdir_result : NULL; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_closedir (DIR * dirp) +{ + int handle = *(int *) dirp; + struct vfs_class *vfs; + int result = -1; + + vfs = vfs_class_find_by_handle (handle); + if (vfs != NULL) + { + struct vfs_dirinfo *dirinfo; + + dirinfo = vfs_class_data_find_by_handle (handle); + if (dirinfo->converter != str_cnv_from_term) + str_close_conv (dirinfo->converter); + + result = vfs->closedir ? (*vfs->closedir) (dirinfo->info) : -1; + vfs_free_handle (handle); + g_free (dirinfo); + } + g_free (dirp); + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_stat (const char *filename, struct stat *buf) +{ + struct vfs_class *vfs; + int result; + char *path; + + path = vfs_canon_and_translate (filename); + + if (path == NULL) + return -1; + + vfs = vfs_get_class (path); + + if (vfs == NULL) + { + g_free (path); + return -1; + } + + result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1; + + g_free (path); + + if (result == -1) + errno = vfs->name ? vfs_ferrno (vfs) : E_NOTSUPP; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_lstat (const char *filename, struct stat *buf) +{ + struct vfs_class *vfs; + int result; + char *path; + + path = vfs_canon_and_translate (filename); + + if (path == NULL) + return -1; + + vfs = vfs_get_class (path); + if (vfs == NULL) + { + g_free (path); + return -1; + } + + result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1; + g_free (path); + if (result == -1) + errno = vfs->name ? vfs_ferrno (vfs) : E_NOTSUPP; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_fstat (int handle, struct stat *buf) +{ + struct vfs_class *vfs; + int result; + + if (handle == -1) + return -1; + + vfs = vfs_class_find_by_handle (handle); + if (vfs == NULL) + return -1; + + result = vfs->fstat ? (*vfs->fstat) (vfs_class_data_find_by_handle (handle), buf) : -1; + if (result == -1) + errno = vfs->name ? vfs_ferrno (vfs) : E_NOTSUPP; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ +/** + * Return current directory. If it's local, reread the current directory + * from the OS. Put directory to the provided buffer. + */ + +char * +mc_get_current_wd (char *buffer, size_t size) +{ + const char *cwd = _vfs_get_cwd (); + + g_strlcpy (buffer, cwd, size); + return buffer; +} + +/* --------------------------------------------------------------------------------------------- */ + +char * +mc_getlocalcopy (const char *pathname) +{ + char *result = NULL; + char *path; + + path = vfs_canon_and_translate (pathname); + if (path != NULL) + { + struct vfs_class *vfs = vfs_get_class (path); + + result = vfs->getlocalcopy != NULL ? + vfs->getlocalcopy (vfs, path) : mc_def_getlocalcopy (path); + g_free (path); + if (result == NULL) + errno = vfs_ferrno (vfs); + } + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed) +{ + int return_value = -1; + char *path; + + path = vfs_canon_and_translate (pathname); + if (path != NULL) + { + struct vfs_class *vfs = vfs_get_class (path); + + return_value = vfs->ungetlocalcopy != NULL ? + vfs->ungetlocalcopy (vfs, path, local, has_changed) : + mc_def_ungetlocalcopy (vfs, path, local, has_changed); + g_free (path); + } + + return return_value; +} + +/* --------------------------------------------------------------------------------------------- */ +/** + * VFS chdir. + * Return 0 on success, -1 on failure. + */ + +int +mc_chdir (const char *path) +{ + char *new_dir; + char *trans_dir; + struct vfs_class *old_vfs, *new_vfs; + vfsid old_vfsid; + int result; + + new_dir = vfs_canon (path); + trans_dir = vfs_translate_path_n (new_dir); + if (trans_dir != NULL) + { + new_vfs = vfs_get_class (trans_dir); + if (!new_vfs->chdir) + { + g_free (new_dir); + g_free (trans_dir); + return -1; + } + + result = (*new_vfs->chdir) (new_vfs, trans_dir); + + if (result == -1) + { + errno = vfs_ferrno (new_vfs); + g_free (new_dir); + g_free (trans_dir); + return -1; + } + + old_vfsid = vfs_getid (current_vfs, current_dir); + 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_stamp_create (old_vfs, old_vfsid); + + /* Sometimes we assume no trailing slash on cwd */ + if (*current_dir) + { + char *p; + p = strchr (current_dir, 0) - 1; + if (*p == PATH_SEP && p > current_dir) + *p = 0; + } + + g_free (trans_dir); + return 0; + } + else + { + g_free (new_dir); + return -1; + } +} + +/* --------------------------------------------------------------------------------------------- */ + +off_t +mc_lseek (int fd, off_t offset, int whence) +{ + struct vfs_class *vfs; + off_t result; + + if (fd == -1) + return -1; + + vfs = vfs_class_find_by_handle (fd); + if (vfs == NULL) + return -1; + + result = vfs->lseek ? (*vfs->lseek) (vfs_class_data_find_by_handle (fd), offset, whence) : -1; + if (result == -1) + errno = vfs->lseek ? vfs_ferrno (vfs) : E_NOTSUPP; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/lib/vfs/interface.h b/lib/vfs/interface.h new file mode 100644 index 000000000..21d987bd1 --- /dev/null +++ b/lib/vfs/interface.h @@ -0,0 +1,45 @@ +#ifndef MC__VFS_INTERFACE_H +#define MC__VFS_INTERFACE_H + +/*** typedefs(not structures) and defined constants **********************************************/ + +/*** enums ***************************************************************************************/ + +/*** structures declarations (and typedefs of structures)*****************************************/ + +/*** global variables defined in .c file *********************************************************/ + +/*** declarations of public functions ************************************************************/ + +ssize_t mc_read (int handle, void *buffer, size_t count); +ssize_t mc_write (int handle, const void *buffer, size_t count); +int mc_utime (const char *path, struct utimbuf *times); +int mc_readlink (const char *path, char *buf, size_t bufsiz); +int mc_close (int handle); +off_t mc_lseek (int fd, off_t offset, int whence); +DIR *mc_opendir (const char *dirname); +struct dirent *mc_readdir (DIR * dirp); +int mc_closedir (DIR * dir); +int mc_stat (const char *path, struct stat *buf); +int mc_mknod (const char *path, mode_t mode, dev_t dev); +int mc_link (const char *name1, const char *name2); +int mc_mkdir (const char *path, mode_t mode); +int mc_rmdir (const char *path); +int mc_fstat (int fd, struct stat *buf); +int mc_lstat (const char *path, struct stat *buf); +int mc_symlink (const char *name1, const char *name2); +int mc_rename (const char *original, const char *target); +int mc_chmod (const char *path, mode_t mode); +int mc_chown (const char *path, uid_t owner, gid_t group); +int mc_chdir (const char *path); +int mc_unlink (const char *path); +int mc_ctl (int fd, int ctlop, void *arg); +int mc_setctl (const char *path, int ctlop, void *arg); +int mc_open (const char *filename, int flags, ...); +char *mc_get_current_wd (char *buffer, size_t bufsize); +char *mc_getlocalcopy (const char *pathname); +int mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed); + +/*** inline functions ****************************************************************************/ + +#endif diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index 25e44b0b6..4ea47aa18 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -37,18 +37,7 @@ #include -#include -#include /* For atol() */ -#include -#include #include -#include -#include -#include /* is_digit() */ -#include -#include -#include -#include #include "lib/global.h" #include "lib/strutil.h" @@ -64,8 +53,15 @@ #include "utilvfs.h" #include "gc.h" +extern struct dirent *mc_readdir_result; /*** global variables ****************************************************************************/ +GString *vfs_str_buffer; +struct vfs_class *current_vfs; + +/** They keep track of the current directory */ +char *current_dir; + /*** file scope macro definitions ****************************************************************/ #if defined(_AIX) && !defined(NAME_MAX) @@ -85,27 +81,14 @@ struct vfs_openfile void *fsinfo; }; -struct vfs_dirinfo -{ - DIR *info; - GIConv converter; -}; - /*** file scope variables ************************************************************************/ -/** They keep track of the current directory */ -static struct vfs_class *current_vfs; -static char *current_dir; static GPtrArray *vfs_openfiles; static long vfs_free_handle_list = -1; -static GString *vfs_str_buffer; - static GPtrArray *vfs_list = NULL; -static struct dirent *mc_readdir_result = NULL; - static const struct { const char *name; @@ -129,98 +112,6 @@ static const struct }; /*** file scope functions ************************************************************************/ -/* --------------------------------------------------------------------------------------------- */ -/** - * Create new VFS handle and put it to the list - */ - -static int -vfs_new_handle (struct vfs_class *vclass, void *fsinfo) -{ - struct vfs_openfile *h; - - h = g_new (struct vfs_openfile, 1); - h->fsinfo = fsinfo; - h->vclass = vclass; - - /* Allocate the first free handle */ - h->handle = vfs_free_handle_list; - if (h->handle == -1) - { - /* No free allocated handles, allocate one */ - h->handle = vfs_openfiles->len; - g_ptr_array_add (vfs_openfiles, h); - } - else - { - vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list); - g_ptr_array_index (vfs_openfiles, h->handle) = h; - } - - h->handle += VFS_FIRST_HANDLE; - return h->handle; -} - -/* --------------------------------------------------------------------------------------------- */ -/** Find VFS class by file handle */ - -static struct vfs_class * -vfs_op (int handle) -{ - struct vfs_openfile *h; - - if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len) - return NULL; - - h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE); - if (!h) - return NULL; - - g_assert (h->handle == handle); - - return h->vclass; -} - -/* --------------------------------------------------------------------------------------------- */ -/** Find private file data by file handle */ - -static void * -vfs_info (int handle) -{ - struct vfs_openfile *h; - - if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len) - return NULL; - - h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE); - if (!h) - return NULL; - - g_assert (h->handle == handle); - - return h->fsinfo; -} - -/* --------------------------------------------------------------------------------------------- */ -/** Free open file data for given file handle */ - -static void -vfs_free_handle (int handle) -{ - const int idx = handle - VFS_FIRST_HANDLE; - - if (handle >= VFS_FIRST_HANDLE && (guint) idx < vfs_openfiles->len) - { - struct vfs_openfile *h; - - h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, idx); - g_free (h); - g_ptr_array_index (vfs_openfiles, idx) = (void *) vfs_free_handle_list; - vfs_free_handle_list = idx; - } -} - - /* --------------------------------------------------------------------------------------------- */ /** Return VFS class for the given prefix */ @@ -369,173 +260,109 @@ _vfs_translate_path (const char *path, int size, GIConv defcnv, GString * buffer } /* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ +/** Free open file data for given file handle */ -static int -ferrno (struct vfs_class *vfs) +void +vfs_free_handle (int handle) +{ + const int idx = handle - VFS_FIRST_HANDLE; + + if (handle >= VFS_FIRST_HANDLE && (guint) idx < vfs_openfiles->len) + { + struct vfs_openfile *h; + + h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, idx); + g_free (h); + g_ptr_array_index (vfs_openfiles, idx) = (void *) vfs_free_handle_list; + vfs_free_handle_list = idx; + } +} + + +/* --------------------------------------------------------------------------------------------- */ +/** Find private file data by file handle */ + +void * +vfs_class_data_find_by_handle (int handle) +{ + struct vfs_openfile *h; + + if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len) + return NULL; + + h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE); + if (!h) + return NULL; + + g_assert (h->handle == handle); + + return h->fsinfo; +} + +/* --------------------------------------------------------------------------------------------- */ +/** Find VFS class by file handle */ + +struct vfs_class * +vfs_class_find_by_handle (int handle) +{ + struct vfs_openfile *h; + + if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len) + return NULL; + + h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE); + if (!h) + return NULL; + + g_assert (h->handle == handle); + + return h->vclass; +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * Create new VFS handle and put it to the list + */ + +int +vfs_new_handle (struct vfs_class *vclass, void *fsinfo) +{ + struct vfs_openfile *h; + + h = g_new (struct vfs_openfile, 1); + h->fsinfo = fsinfo; + h->vclass = vclass; + + /* Allocate the first free handle */ + h->handle = vfs_free_handle_list; + if (h->handle == -1) + { + /* No free allocated handles, allocate one */ + h->handle = vfs_openfiles->len; + g_ptr_array_add (vfs_openfiles, h); + } + else + { + vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list); + g_ptr_array_index (vfs_openfiles, h->handle) = h; + } + + h->handle += VFS_FIRST_HANDLE; + return h->handle; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +vfs_ferrno (struct vfs_class *vfs) { return vfs->ferrno ? (*vfs->ferrno) (vfs) : E_UNKNOWN; /* Hope that error message is obscure enough ;-) */ } -/* --------------------------------------------------------------------------------------------- */ -/** - * Return current directory. If it's local, reread the current directory - * from the OS. You must g_strdup() whatever this function returns. - */ - -static const char * -_vfs_get_cwd (void) -{ - char *trans; - - trans = vfs_translate_path_n (current_dir); - - if (_vfs_get_class (trans) == NULL) - { - const char *encoding = vfs_get_encoding (current_dir); - - if (encoding == NULL) - { - char *tmp; - - tmp = g_get_current_dir (); - if (tmp != NULL) - { /* One of the directories in the path is not readable */ - estr_t state; - char *sys_cwd; - - g_string_set_size (vfs_str_buffer, 0); - state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer); - g_free (tmp); - - sys_cwd = (state == ESTR_SUCCESS) ? g_strdup (vfs_str_buffer->str) : NULL; - if (sys_cwd != NULL) - { - struct stat my_stat, my_stat2; - /* Check if it is O.K. to use the current_dir */ - if (mc_global.vfs.cd_symlinks - && mc_stat (sys_cwd, &my_stat) == 0 - && mc_stat (current_dir, &my_stat2) == 0 - && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev) - g_free (sys_cwd); - else - { - g_free (current_dir); - current_dir = sys_cwd; - } - } - } - } - } - - g_free (trans); - return current_dir; -} - -/* --------------------------------------------------------------------------------------------- */ - -static char * -mc_def_getlocalcopy (const char *filename) -{ - char *tmp; - int fdin, fdout; - ssize_t i; - char buffer[8192]; - struct stat mystat; - - fdin = mc_open (filename, O_RDONLY | O_LINEAR); - if (fdin == -1) - return NULL; - - fdout = vfs_mkstemps (&tmp, "vfs", filename); - - 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) - { - fdout = -1; - goto fail; - } - - if (mc_stat (filename, &mystat) != -1) - chmod (tmp, mystat.st_mode); - - return tmp; - - fail: - if (fdout != -1) - close (fdout); - if (fdin != -1) - mc_close (fdin); - g_free (tmp); - return NULL; -} - -/* --------------------------------------------------------------------------------------------- */ - -static int -mc_def_ungetlocalcopy (struct vfs_class *vfs, const char *filename, - const char *local, int has_changed) -{ - int fdin = -1, fdout = -1; - if (has_changed) - { - char buffer[8192]; - ssize_t i; - - if (!vfs->write) - goto failed; - - fdin = open (local, O_RDONLY); - if (fdin == -1) - goto failed; - 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, (size_t) 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; - } - } - unlink (local); - return 0; - - failed: - message (D_ERROR, _("Changes to file lost"), "%s", filename); - if (fdout != -1) - mc_close (fdout); - if (fdin != -1) - close (fdin); - unlink (local); - return -1; -} - -/* --------------------------------------------------------------------------------------------- */ -/*** public functions ****************************************************************************/ /* --------------------------------------------------------------------------------------------- */ gboolean @@ -746,470 +573,6 @@ vfs_canon_and_translate (const char *path) /* --------------------------------------------------------------------------------------------- */ -int -mc_open (const char *filename, int flags, ...) -{ - int mode = 0; - void *info; - va_list ap; - char *file; - struct vfs_class *vfs; - - file = vfs_canon_and_translate (filename); - if (file == NULL) - return -1; - - vfs = vfs_get_class (file); - - /* Get the mode flag */ - if (flags & O_CREAT) - { - va_start (ap, flags); - mode = va_arg (ap, int); - va_end (ap); - } - - if (vfs->open == NULL) - { - g_free (file); - errno = -EOPNOTSUPP; - return -1; - } - - info = vfs->open (vfs, file, flags, mode); /* open must be supported */ - g_free (file); - if (info == NULL) - { - errno = ferrno (vfs); - return -1; - } - - return vfs_new_handle (vfs, info); -} - -/* --------------------------------------------------------------------------------------------- */ - -/* *INDENT-OFF* */ - -#define MC_NAMEOP(name, inarg, callarg) \ -int mc_##name inarg \ -{ \ - struct vfs_class *vfs; \ - int result; \ - char *mpath; \ - mpath = vfs_canon_and_translate (path); \ - if (mpath == NULL) \ - return -1; \ - vfs = vfs_get_class (mpath); \ - if (vfs == NULL) \ - { \ - g_free (mpath); \ - return -1; \ - } \ - result = vfs->name != NULL ? vfs->name callarg : -1; \ - g_free (mpath); \ - if (result == -1) \ - errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \ - return result; \ -} - -MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode)) -MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, owner, group)) -MC_NAMEOP (utime, (const char *path, struct utimbuf * times), (vfs, mpath, times)) -MC_NAMEOP (readlink, (const char *path, char *buf, size_t bufsiz), (vfs, mpath, buf, bufsiz)) -MC_NAMEOP (unlink, (const char *path), (vfs, mpath)) -MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode)) -MC_NAMEOP (rmdir, (const char *path), (vfs, mpath)) -MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev)) - -/* *INDENT-ON* */ - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_symlink (const char *name1, const char *path) -{ - struct vfs_class *vfs; - int result; - char *mpath; - char *lpath; - char *tmp; - - mpath = vfs_canon_and_translate (path); - if (mpath == NULL) - return -1; - - tmp = g_strdup (name1); - lpath = vfs_translate_path_n (tmp); - g_free (tmp); - - if (lpath != NULL) - { - vfs = vfs_get_class (mpath); - result = vfs->symlink != NULL ? vfs->symlink (vfs, lpath, mpath) : -1; - g_free (lpath); - g_free (mpath); - - if (result == -1) - errno = vfs->symlink != NULL ? ferrno (vfs) : E_NOTSUPP; - return result; - } - - g_free (mpath); - - return -1; -} - -/* --------------------------------------------------------------------------------------------- */ - -/* *INDENT-OFF* */ - -#define MC_HANDLEOP(name, inarg, callarg) \ -ssize_t mc_##name inarg \ -{ \ - struct vfs_class *vfs; \ - int result; \ - if (handle == -1) \ - return -1; \ - vfs = vfs_op (handle); \ - if (vfs == NULL) \ - return -1; \ - result = vfs->name != NULL ? vfs->name callarg : -1; \ - if (result == -1) \ - errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \ - return result; \ -} - -MC_HANDLEOP (read, (int handle, void *buffer, size_t count), (vfs_info (handle), buffer, count)) -MC_HANDLEOP (write, (int handle, const void *buf, size_t nbyte), (vfs_info (handle), buf, nbyte)) - -/* --------------------------------------------------------------------------------------------- */ - -#define MC_RENAMEOP(name) \ -int mc_##name (const char *fname1, const char *fname2) \ -{ \ - struct vfs_class *vfs; \ - int result; \ - char *name2, *name1; \ - name1 = vfs_canon_and_translate (fname1); \ - if (name1 == NULL) \ - return -1; \ - name2 = vfs_canon_and_translate (fname2); \ - if (name2 == NULL) { \ - g_free (name1); \ - return -1; \ - } \ - vfs = vfs_get_class (name1); \ - if (vfs != vfs_get_class (name2)) \ - { \ - errno = EXDEV; \ - g_free (name1); \ - g_free (name2); \ - return -1; \ - } \ - result = vfs->name != NULL ? vfs->name (vfs, name1, name2) : -1; \ - g_free (name1); \ - g_free (name2); \ - if (result == -1) \ - errno = vfs->name != NULL ? ferrno (vfs) : E_NOTSUPP; \ - return result; \ -} - -MC_RENAMEOP (link) -MC_RENAMEOP (rename) - -/* *INDENT-ON* */ - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_ctl (int handle, int ctlop, void *arg) -{ - struct vfs_class *vfs = vfs_op (handle); - - if (vfs == NULL) - return 0; - - return vfs->ctl ? (*vfs->ctl) (vfs_info (handle), ctlop, arg) : 0; -} - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_setctl (const char *path, int ctlop, void *arg) -{ - struct vfs_class *vfs; - int result = -1; - char *mpath; - - if (path == NULL) - vfs_die ("You don't want to pass NULL to mc_setctl."); - - mpath = vfs_canon_and_translate (path); - if (mpath != NULL) - { - vfs = vfs_get_class (mpath); - result = vfs->setctl != NULL ? vfs->setctl (vfs, mpath, ctlop, arg) : 0; - g_free (mpath); - } - - return result; -} - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_close (int handle) -{ - struct vfs_class *vfs; - int result; - - if (handle == -1 || !vfs_info (handle)) - return -1; - - vfs = vfs_op (handle); - if (vfs == NULL) - return -1; - - if (handle < 3) - return close (handle); - - if (!vfs->close) - vfs_die ("VFS must support close.\n"); - result = (*vfs->close) (vfs_info (handle)); - vfs_free_handle (handle); - if (result == -1) - errno = ferrno (vfs); - - return result; -} - -/* --------------------------------------------------------------------------------------------- */ - -DIR * -mc_opendir (const char *dirname) -{ - int handle, *handlep; - void *info; - struct vfs_class *vfs; - char *canon; - char *dname; - struct vfs_dirinfo *dirinfo; - const char *encoding; - - canon = vfs_canon (dirname); - dname = vfs_translate_path_n (canon); - - if (dname != NULL) - { - vfs = vfs_get_class (dname); - info = vfs->opendir ? (*vfs->opendir) (vfs, dname) : NULL; - g_free (dname); - - if (info == NULL) - { - errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP; - g_free (canon); - return NULL; - } - - dirinfo = g_new (struct vfs_dirinfo, 1); - dirinfo->info = info; - - encoding = vfs_get_encoding (canon); - g_free (canon); - dirinfo->converter = (encoding != NULL) ? str_crt_conv_from (encoding) : str_cnv_from_term; - if (dirinfo->converter == INVALID_CONV) - dirinfo->converter = str_cnv_from_term; - - handle = vfs_new_handle (vfs, dirinfo); - - handlep = g_new (int, 1); - *handlep = handle; - return (DIR *) handlep; - } - else - { - g_free (canon); - return NULL; - } -} - -/* --------------------------------------------------------------------------------------------- */ - -struct dirent * -mc_readdir (DIR * dirp) -{ - int handle; - struct vfs_class *vfs; - struct dirent *entry = NULL; - struct vfs_dirinfo *dirinfo; - estr_t state; - - if (!mc_readdir_result) - { - /* We can't just allocate struct dirent as (see man dirent.h) - * struct dirent has VERY nonnaive semantics of allocating - * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_, - * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy - * heap corrupter. So, allocate longliving dirent with at least - * (MAXNAMLEN + 1) for d_name in it. - * Strictly saying resulting dirent is unusable as we don't adjust internal - * structures, holding dirent size. But we don't use it in libc infrastructure. - * TODO: to make simpler homemade dirent-alike structure. - */ - mc_readdir_result = (struct dirent *) g_malloc (sizeof (struct dirent) + MAXNAMLEN + 1); - } - - if (!dirp) - { - errno = EFAULT; - return NULL; - } - handle = *(int *) dirp; - - vfs = vfs_op (handle); - if (vfs == NULL) - return NULL; - - dirinfo = vfs_info (handle); - if (vfs->readdir) - { - entry = (*vfs->readdir) (dirinfo->info); - if (entry == NULL) - return NULL; - g_string_set_size (vfs_str_buffer, 0); - state = str_vfs_convert_from (dirinfo->converter, entry->d_name, vfs_str_buffer); - mc_readdir_result->d_ino = entry->d_ino; - g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, MAXNAMLEN + 1); - } - if (entry == NULL) - errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP; - return (entry != NULL) ? mc_readdir_result : NULL; -} - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_closedir (DIR * dirp) -{ - int handle = *(int *) dirp; - struct vfs_class *vfs; - int result = -1; - - vfs = vfs_op (handle); - if (vfs != NULL) - { - struct vfs_dirinfo *dirinfo; - - dirinfo = vfs_info (handle); - if (dirinfo->converter != str_cnv_from_term) - str_close_conv (dirinfo->converter); - - result = vfs->closedir ? (*vfs->closedir) (dirinfo->info) : -1; - vfs_free_handle (handle); - g_free (dirinfo); - } - g_free (dirp); - return result; -} - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_stat (const char *filename, struct stat *buf) -{ - struct vfs_class *vfs; - int result; - char *path; - - path = vfs_canon_and_translate (filename); - - if (path == NULL) - return -1; - - vfs = vfs_get_class (path); - - if (vfs == NULL) - { - g_free (path); - return -1; - } - - 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) -{ - struct vfs_class *vfs; - int result; - char *path; - - path = vfs_canon_and_translate (filename); - - if (path == NULL) - return -1; - - vfs = vfs_get_class (path); - if (vfs == NULL) - { - g_free (path); - return -1; - } - - 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) -{ - struct vfs_class *vfs; - int result; - - if (handle == -1) - return -1; - - vfs = vfs_op (handle); - if (vfs == NULL) - return -1; - - result = vfs->fstat ? (*vfs->fstat) (vfs_info (handle), buf) : -1; - if (result == -1) - errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; - return result; -} - -/* --------------------------------------------------------------------------------------------- */ -/** - * Return current directory. If it's local, reread the current directory - * from the OS. Put directory to the provided buffer. - */ - -char * -mc_get_current_wd (char *buffer, size_t size) -{ - const char *cwd = _vfs_get_cwd (); - - g_strlcpy (buffer, cwd, size); - return buffer; -} - -/* --------------------------------------------------------------------------------------------- */ /** * Return current directory without any OS calls. */ @@ -1220,27 +583,6 @@ vfs_get_current_dir (void) return current_dir; } -/* --------------------------------------------------------------------------------------------- */ - -off_t -mc_lseek (int fd, off_t offset, int whence) -{ - struct vfs_class *vfs; - off_t result; - - if (fd == -1) - return -1; - - vfs = vfs_op (fd); - if (vfs == NULL) - return -1; - - result = vfs->lseek ? (*vfs->lseek) (vfs_info (fd), offset, whence) : -1; - if (result == -1) - errno = vfs->lseek ? ferrno (vfs) : E_NOTSUPP; - return result; -} - /* --------------------------------------------------------------------------------------------- */ /** * remove //, /./ and /../ @@ -1275,73 +617,6 @@ vfs_canon (const char *path) } } -/* --------------------------------------------------------------------------------------------- */ -/** - * VFS chdir. - * Return 0 on success, -1 on failure. - */ - -int -mc_chdir (const char *path) -{ - char *new_dir; - char *trans_dir; - struct vfs_class *old_vfs, *new_vfs; - vfsid old_vfsid; - int result; - - new_dir = vfs_canon (path); - trans_dir = vfs_translate_path_n (new_dir); - if (trans_dir != NULL) - { - new_vfs = vfs_get_class (trans_dir); - if (!new_vfs->chdir) - { - g_free (new_dir); - g_free (trans_dir); - return -1; - } - - result = (*new_vfs->chdir) (new_vfs, trans_dir); - - if (result == -1) - { - errno = ferrno (new_vfs); - g_free (new_dir); - g_free (trans_dir); - return -1; - } - - old_vfsid = vfs_getid (current_vfs, current_dir); - 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_stamp_create (old_vfs, old_vfsid); - - /* Sometimes we assume no trailing slash on cwd */ - if (*current_dir) - { - char *p; - p = strchr (current_dir, 0) - 1; - if (*p == PATH_SEP && p > current_dir) - *p = 0; - } - - g_free (trans_dir); - return 0; - } - else - { - g_free (new_dir); - return -1; - } -} - /* --------------------------------------------------------------------------------------------- */ /* Return TRUE is the current VFS class is local */ @@ -1371,51 +646,6 @@ vfs_file_class_flags (const char *filename) /* --------------------------------------------------------------------------------------------- */ -char * -mc_getlocalcopy (const char *pathname) -{ - char *result = NULL; - char *path; - - path = vfs_canon_and_translate (pathname); - if (path != NULL) - { - struct vfs_class *vfs = vfs_get_class (path); - - result = vfs->getlocalcopy != NULL ? - vfs->getlocalcopy (vfs, path) : mc_def_getlocalcopy (path); - g_free (path); - if (result == NULL) - errno = ferrno (vfs); - } - - return result; -} - -/* --------------------------------------------------------------------------------------------- */ - -int -mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed) -{ - int return_value = -1; - char *path; - - path = vfs_canon_and_translate (pathname); - if (path != NULL) - { - struct vfs_class *vfs = vfs_get_class (path); - - return_value = vfs->ungetlocalcopy != NULL ? - vfs->ungetlocalcopy (vfs, path, local, has_changed) : - mc_def_ungetlocalcopy (vfs, path, local, has_changed); - g_free (path); - } - - return return_value; -} - -/* --------------------------------------------------------------------------------------------- */ - void vfs_init (void) { @@ -1530,3 +760,58 @@ vfs_print_message (const char *msg, ...) } /* --------------------------------------------------------------------------------------------- */ +/** + * Return current directory. If it's local, reread the current directory + * from the OS. You must g_strdup() whatever this function returns. + */ + +const char * +_vfs_get_cwd (void) +{ + char *trans; + + trans = vfs_translate_path_n (current_dir); + + if (_vfs_get_class (trans) == NULL) + { + const char *encoding = vfs_get_encoding (current_dir); + + if (encoding == NULL) + { + char *tmp; + + tmp = g_get_current_dir (); + if (tmp != NULL) + { /* One of the directories in the path is not readable */ + estr_t state; + char *sys_cwd; + + g_string_set_size (vfs_str_buffer, 0); + state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer); + g_free (tmp); + + sys_cwd = (state == ESTR_SUCCESS) ? g_strdup (vfs_str_buffer->str) : NULL; + if (sys_cwd != NULL) + { + struct stat my_stat, my_stat2; + /* Check if it is O.K. to use the current_dir */ + if (mc_global.vfs.cd_symlinks + && mc_stat (sys_cwd, &my_stat) == 0 + && mc_stat (current_dir, &my_stat2) == 0 + && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev) + g_free (sys_cwd); + else + { + g_free (current_dir); + current_dir = sys_cwd; + } + } + } + } + } + + g_free (trans); + return current_dir; +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index cd6cd974a..aff5ad3ee 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -19,6 +19,8 @@ #include "lib/global.h" #include "lib/fs.h" /* MC_MAXPATHLEN */ +#include "interface.h" + /*** typedefs(not structures) and defined constants **********************************************/ #if defined (ENABLE_VFS_FTP) || defined (ENABLE_VFS_FISH) || defined (ENABLE_VFS_SMB) @@ -231,35 +233,7 @@ char *vfs_get_current_dir (void); gboolean vfs_current_is_local (void); gboolean vfs_file_is_local (const char *filename); -ssize_t mc_read (int handle, void *buffer, size_t count); -ssize_t mc_write (int handle, const void *buffer, size_t count); -int mc_utime (const char *path, struct utimbuf *times); -int mc_readlink (const char *path, char *buf, size_t bufsiz); -int mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed); -int mc_close (int handle); -off_t mc_lseek (int fd, off_t offset, int whence); -DIR *mc_opendir (const char *dirname); -struct dirent *mc_readdir (DIR * dirp); -int mc_closedir (DIR * dir); -int mc_stat (const char *path, struct stat *buf); -int mc_mknod (const char *path, mode_t mode, dev_t dev); -int mc_link (const char *name1, const char *name2); -int mc_mkdir (const char *path, mode_t mode); -int mc_rmdir (const char *path); -int mc_fstat (int fd, struct stat *buf); -int mc_lstat (const char *path, struct stat *buf); -int mc_symlink (const char *name1, const char *name2); -int mc_rename (const char *original, const char *target); -int mc_chmod (const char *path, mode_t mode); -int mc_chown (const char *path, uid_t owner, gid_t group); -int mc_chdir (const char *path); -int mc_unlink (const char *path); -int mc_ctl (int fd, int ctlop, void *arg); -int mc_setctl (const char *path, int ctlop, void *arg); -int mc_open (const char *filename, int flags, ...); -char *mc_get_current_wd (char *buffer, size_t bufsize); char *vfs_canon (const char *path); -char *mc_getlocalcopy (const char *pathname); char *vfs_strip_suffix_from_filename (const char *filename); char *vfs_translate_url (const char *url); @@ -290,5 +264,17 @@ void vfs_fill_names (fill_names_f); void vfs_print_message (const char *msg, ...) __attribute__ ((format (__printf__, 1, 2))); +int vfs_ferrno (struct vfs_class *vfs); + +int vfs_new_handle (struct vfs_class *vclass, void *fsinfo); + +struct vfs_class * vfs_class_find_by_handle (int handle); + +void *vfs_class_data_find_by_handle (int handle); + +void vfs_free_handle (int handle); + +const char *_vfs_get_cwd (void); + /*** inline functions ****************************************************************************/ #endif /* MC_VFS_VFS_H */