2011-10-15 14:56:47 +04:00
|
|
|
/*
|
|
|
|
Directory cache support
|
|
|
|
|
2024-01-01 09:46:17 +03:00
|
|
|
Copyright (C) 1998-2024
|
2014-02-12 10:33:10 +04:00
|
|
|
Free Software Foundation, Inc.
|
2011-10-15 14:56:47 +04:00
|
|
|
|
|
|
|
Written by:
|
|
|
|
Pavel Machek <pavel@ucw.cz>, 1998
|
2022-05-07 11:23:42 +03:00
|
|
|
Slava Zanko <slavazanko@gmail.com>, 2010-2013
|
|
|
|
Andrew Borodin <aborodin@vmail.ru> 2010-2022
|
2011-10-15 14:56:47 +04:00
|
|
|
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
\warning Paths here do _not_ begin with '/', so root directory of
|
|
|
|
archive/site is simply "".
|
|
|
|
*/
|
|
|
|
|
2009-02-07 15:54:58 +03:00
|
|
|
/** \file
|
|
|
|
* \brief Source: directory cache support
|
|
|
|
*
|
|
|
|
* So that you do not have copy of this in each and every filesystem.
|
1998-10-23 12:26:25 +04:00
|
|
|
*
|
2009-02-07 15:54:58 +03:00
|
|
|
* Very loosely based on tar.c from midnight and archives.[ch] from
|
|
|
|
* avfs by Miklos Szeredi (mszeredi@inf.bme.hu)
|
1998-10-23 12:26:25 +04:00
|
|
|
*
|
2009-02-07 15:54:58 +03:00
|
|
|
* Unfortunately, I was unable to keep all filesystems
|
|
|
|
* uniform. tar-like filesystems use tree structure where each
|
|
|
|
* directory has pointers to its subdirectories. We can do this
|
|
|
|
* because we have full information about our archive.
|
1998-11-21 22:36:01 +03:00
|
|
|
*
|
2009-02-07 15:54:58 +03:00
|
|
|
* At ftp-like filesystems, situation is a little bit different. When
|
|
|
|
* you cd /usr/src/linux/drivers/char, you do _not_ want /usr,
|
|
|
|
* /usr/src, /usr/src/linux and /usr/src/linux/drivers to be
|
|
|
|
* listed. That means that we do not have complete information, and if
|
|
|
|
* /usr is symlink to /4, we will not know. Also we have to time out
|
|
|
|
* entries and things would get messy with tree-like approach. So we
|
|
|
|
* do different trick: root directory is completely special and
|
|
|
|
* completely fake, it contains entries such as 'usr', 'usr/src', ...,
|
|
|
|
* and we'll try to use custom find_entry function.
|
1998-11-21 22:36:01 +03:00
|
|
|
*
|
2011-10-15 14:56:47 +04:00
|
|
|
* \author Pavel Machek <pavel@ucw.cz>
|
2009-02-07 15:54:58 +03:00
|
|
|
* \date 1998
|
1998-11-21 22:36:01 +03:00
|
|
|
*
|
2009-02-07 15:54:58 +03:00
|
|
|
*/
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2001-06-26 01:34:46 +04:00
|
|
|
#include <config.h>
|
2009-01-30 22:10:40 +03:00
|
|
|
|
2003-10-16 12:47:33 +04:00
|
|
|
#include <errno.h>
|
2010-11-26 11:31:18 +03:00
|
|
|
#include <inttypes.h> /* uintmax_t */
|
2011-02-16 14:26:59 +03:00
|
|
|
#include <stdarg.h>
|
2019-09-22 17:29:50 +03:00
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
|
|
#include <sys/select.h>
|
|
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-01-20 18:11:52 +03:00
|
|
|
#include "lib/global.h"
|
2009-05-08 14:01:05 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
#include "lib/tty/tty.h" /* enable/disable interrupt key */
|
2022-05-07 11:23:42 +03:00
|
|
|
#include "lib/util.h" /* canonicalize_pathname_custom() */
|
2010-11-12 11:03:57 +03:00
|
|
|
#if 0
|
|
|
|
#include "lib/widget.h" /* message() */
|
|
|
|
#endif
|
2010-01-07 02:57:27 +03:00
|
|
|
|
2011-02-15 16:44:17 +03:00
|
|
|
#include "vfs.h"
|
2010-07-22 12:07:07 +04:00
|
|
|
#include "utilvfs.h"
|
1998-10-24 00:18:48 +04:00
|
|
|
#include "xdirentry.h"
|
2010-07-22 12:07:07 +04:00
|
|
|
#include "gc.h" /* vfs_rmstamp */
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/*** global variables ****************************************************************************/
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/*** file scope macro definitions ****************************************************************/
|
2009-12-12 13:54:22 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
#define CALL(x) \
|
|
|
|
if (VFS_SUBCLASS (me)->x != NULL) \
|
|
|
|
VFS_SUBCLASS (me)->x
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/*** file scope type declarations ****************************************************************/
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
struct dirhandle
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2011-03-28 16:17:45 +04:00
|
|
|
GList *cur;
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_inode *dir;
|
|
|
|
};
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/*** file scope variables ************************************************************************/
|
2000-04-28 11:43:13 +04:00
|
|
|
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/*** forward declarations (file scope functions) *************************************************/
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2018-03-02 15:02:55 +03:00
|
|
|
/*** file scope functions ************************************************************************/
|
2011-03-28 16:17:45 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1998-11-21 22:36:01 +03:00
|
|
|
/* We were asked to create entries automagically */
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2003-10-12 05:00:44 +04:00
|
|
|
static struct vfs_s_entry *
|
|
|
|
vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
|
|
|
struct vfs_s_entry *res;
|
2011-03-28 16:17:45 +04:00
|
|
|
char *sep;
|
|
|
|
|
|
|
|
sep = strchr (path, PATH_SEP);
|
|
|
|
if (sep != NULL)
|
|
|
|
*sep = '\0';
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2016-04-24 20:30:37 +03:00
|
|
|
res = vfs_s_generate_entry (me, path, dir, (flags & FL_MKDIR) != 0 ? (0777 | S_IFDIR) : 0777);
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_insert_entry (me, dir, res);
|
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
if (sep != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
*sep = PATH_SEP;
|
1999-01-18 02:10:05 +03:00
|
|
|
|
1998-10-23 12:26:25 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2003-10-17 03:58:43 +04:00
|
|
|
/* If the entry is a symlink, find the entry for its target */
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2003-10-17 03:58:43 +04:00
|
|
|
static struct vfs_s_entry *
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry, int follow)
|
2003-10-17 03:58:43 +04:00
|
|
|
{
|
|
|
|
char *linkname;
|
|
|
|
char *fullname = NULL;
|
|
|
|
struct vfs_s_entry *target;
|
|
|
|
|
|
|
|
if (follow == LINK_NO_FOLLOW)
|
2010-03-30 12:10:25 +04:00
|
|
|
return entry;
|
2003-10-17 03:58:43 +04:00
|
|
|
if (follow == 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
ERRNOR (ELOOP, NULL);
|
2018-01-08 11:20:55 +03:00
|
|
|
if (entry == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
ERRNOR (ENOENT, NULL);
|
2003-10-17 03:58:43 +04:00
|
|
|
if (!S_ISLNK (entry->ino->st.st_mode))
|
2010-03-30 12:10:25 +04:00
|
|
|
return entry;
|
2003-10-17 03:58:43 +04:00
|
|
|
|
|
|
|
linkname = entry->ino->linkname;
|
|
|
|
if (linkname == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
ERRNOR (EFAULT, NULL);
|
2003-10-17 03:58:43 +04:00
|
|
|
|
|
|
|
/* make full path from relative */
|
2015-01-07 11:34:53 +03:00
|
|
|
if (!IS_PATH_SEP (*linkname))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2015-01-07 11:34:53 +03:00
|
|
|
char *fullpath;
|
|
|
|
|
|
|
|
fullpath = vfs_s_fullpath (me, entry->dir);
|
|
|
|
if (fullpath != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2015-01-07 11:34:53 +03:00
|
|
|
fullname = g_strconcat (fullpath, PATH_SEP_STR, linkname, (char *) NULL);
|
2010-03-30 12:10:25 +04:00
|
|
|
linkname = fullname;
|
|
|
|
g_free (fullpath);
|
|
|
|
}
|
2003-10-17 03:58:43 +04:00
|
|
|
}
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
target =
|
|
|
|
VFS_SUBCLASS (me)->find_entry (me, entry->dir->super->root, linkname, follow - 1, FL_NONE);
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (fullname);
|
2003-10-17 03:58:43 +04:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1999-01-18 02:10:05 +03:00
|
|
|
/*
|
|
|
|
* Follow > 0: follow links, serves as loop protect,
|
|
|
|
* == -1: do not follow links
|
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2003-10-28 10:09:39 +03:00
|
|
|
static struct vfs_s_entry *
|
2003-10-17 03:58:43 +04:00
|
|
|
vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
|
2010-03-30 12:10:25 +04:00
|
|
|
const char *a_path, int follow, int flags)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2004-09-04 01:23:05 +04:00
|
|
|
size_t pseg;
|
2003-10-12 05:00:44 +04:00
|
|
|
struct vfs_s_entry *ent = NULL;
|
2010-03-30 12:10:25 +04:00
|
|
|
char *const pathref = g_strdup (a_path);
|
2004-09-22 15:28:14 +04:00
|
|
|
char *path = pathref;
|
2003-10-17 03:58:43 +04:00
|
|
|
|
2009-11-23 11:45:46 +03:00
|
|
|
/* canonicalize as well, but don't remove '../' from path */
|
2022-05-07 11:23:42 +03:00
|
|
|
canonicalize_pathname_custom (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
|
2003-10-17 07:25:43 +04:00
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
while (root != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2011-03-28 16:17:45 +04:00
|
|
|
GList *iter;
|
|
|
|
|
2015-01-07 11:34:53 +03:00
|
|
|
while (IS_PATH_SEP (*path)) /* Strip leading '/' */
|
2010-03-30 12:10:25 +04:00
|
|
|
path++;
|
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
if (path[0] == '\0')
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
g_free (pathref);
|
|
|
|
return ent;
|
|
|
|
}
|
|
|
|
|
2015-01-07 11:34:53 +03:00
|
|
|
for (pseg = 0; path[pseg] != '\0' && !IS_PATH_SEP (path[pseg]); pseg++)
|
2011-03-28 16:17:45 +04:00
|
|
|
;
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2015-01-16 10:56:08 +03:00
|
|
|
for (iter = g_queue_peek_head_link (root->subdir); iter != NULL; iter = g_list_next (iter))
|
2011-03-28 16:17:45 +04:00
|
|
|
{
|
2018-03-02 15:02:55 +03:00
|
|
|
ent = VFS_ENTRY (iter->data);
|
2011-03-28 16:17:45 +04:00
|
|
|
if (strlen (ent->name) == pseg && strncmp (ent->name, path, pseg) == 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
/* FOUND! */
|
|
|
|
break;
|
2011-03-28 16:17:45 +04:00
|
|
|
}
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2018-03-02 15:02:55 +03:00
|
|
|
ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
|
2011-03-28 16:17:45 +04:00
|
|
|
|
|
|
|
if (ent == NULL && (flags & (FL_MKFILE | FL_MKDIR)) != 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
ent = vfs_s_automake (me, root, path, flags);
|
2011-03-28 16:17:45 +04:00
|
|
|
if (ent == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
me->verrno = ENOENT;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-03-28 16:17:45 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
path += pseg;
|
|
|
|
/* here we must follow leading directories always;
|
|
|
|
only the actual file is optional */
|
2011-03-28 16:17:45 +04:00
|
|
|
ent = vfs_s_resolve_symlink (me, ent,
|
|
|
|
strchr (path, PATH_SEP) != NULL ? LINK_FOLLOW : follow);
|
|
|
|
if (ent == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
goto cleanup;
|
|
|
|
root = ent->ino;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
2010-03-30 12:10:25 +04:00
|
|
|
cleanup:
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (pathref);
|
2000-04-28 11:43:13 +04:00
|
|
|
return NULL;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-28 10:09:39 +03:00
|
|
|
static struct vfs_s_entry *
|
|
|
|
vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
|
2010-03-30 12:10:25 +04:00
|
|
|
const char *a_path, int follow, int flags)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2003-10-28 10:09:39 +03:00
|
|
|
struct vfs_s_entry *ent = NULL;
|
2010-03-30 12:10:25 +04:00
|
|
|
char *const path = g_strdup (a_path);
|
2011-03-28 16:17:45 +04:00
|
|
|
GList *iter;
|
1998-11-21 22:36:01 +03:00
|
|
|
|
1999-11-03 17:51:22 +03:00
|
|
|
if (root->super->root != root)
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_die ("We have to use _real_ root. Always. Sorry.");
|
1999-11-03 17:51:22 +03:00
|
|
|
|
2009-11-23 11:45:46 +03:00
|
|
|
/* canonicalize as well, but don't remove '../' from path */
|
2022-05-07 11:23:42 +03:00
|
|
|
canonicalize_pathname_custom (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
|
2002-07-27 01:58:43 +04:00
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
if ((flags & FL_DIR) == 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2011-07-20 22:20:41 +04:00
|
|
|
char *dirname, *name;
|
2010-03-30 12:10:25 +04:00
|
|
|
struct vfs_s_inode *ino;
|
2011-07-20 22:20:41 +04:00
|
|
|
|
|
|
|
dirname = g_path_get_dirname (path);
|
|
|
|
name = g_path_get_basename (path);
|
2010-03-30 12:10:25 +04:00
|
|
|
ino = vfs_s_find_inode (me, root->super, dirname, follow, flags | FL_DIR);
|
2013-10-10 16:21:26 +04:00
|
|
|
ent = vfs_s_find_entry_tree (me, ino, name, follow, flags);
|
2011-07-20 22:20:41 +04:00
|
|
|
g_free (dirname);
|
|
|
|
g_free (name);
|
2010-03-30 12:10:25 +04:00
|
|
|
g_free (path);
|
2013-10-10 16:21:26 +04:00
|
|
|
return ent;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
|
2015-01-16 10:56:08 +03:00
|
|
|
iter = g_queue_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
|
2018-03-02 15:02:55 +03:00
|
|
|
ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (ent != NULL && !VFS_SUBCLASS (me)->dir_uptodate (me, ent->ino))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
1998-12-09 23:22:53 +03:00
|
|
|
#if 1
|
2011-02-16 14:26:59 +03:00
|
|
|
vfs_print_message (_("Directory cache expired for %s"), path);
|
1998-11-21 22:36:01 +03:00
|
|
|
#endif
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_s_free_entry (me, ent);
|
|
|
|
ent = NULL;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
if (ent == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
struct vfs_s_inode *ino;
|
|
|
|
|
|
|
|
ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
|
|
|
|
ent = vfs_s_new_entry (me, path, ino);
|
2018-09-12 14:01:28 +03:00
|
|
|
if (VFS_SUBCLASS (me)->dir_load (me, ino, path) == -1)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
vfs_s_free_entry (me, ent);
|
|
|
|
g_free (path);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-03-28 16:17:45 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_s_insert_entry (me, root, ent);
|
|
|
|
|
2015-01-16 10:56:08 +03:00
|
|
|
iter = g_queue_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
|
2018-03-02 15:02:55 +03:00
|
|
|
ent = iter != NULL ? VFS_ENTRY (iter->data) : NULL;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
2011-03-28 16:17:45 +04:00
|
|
|
if (ent == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_die ("find_linear: success but directory is not there\n");
|
1998-11-21 22:36:01 +03:00
|
|
|
|
|
|
|
#if 0
|
2018-01-08 11:20:55 +03:00
|
|
|
if (vfs_s_resolve_symlink (me, ent, follow) == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
g_free (path);
|
|
|
|
return NULL;
|
2004-09-22 15:28:14 +04:00
|
|
|
}
|
1998-11-21 22:36:01 +03:00
|
|
|
#endif
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (path);
|
1998-11-21 22:36:01 +03:00
|
|
|
return ent;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2002-03-06 11:46:35 +03:00
|
|
|
/* Ook, these were functions around directory entries / inodes */
|
1998-10-23 12:26:25 +04:00
|
|
|
/* -------------------------------- superblock games -------------------------- */
|
|
|
|
|
2003-10-12 05:00:44 +04:00
|
|
|
static struct vfs_s_super *
|
2003-10-12 04:24:00 +04:00
|
|
|
vfs_s_new_super (struct vfs_class *me)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2003-10-12 05:00:44 +04:00
|
|
|
struct vfs_s_super *super;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
1999-01-21 01:01:11 +03:00
|
|
|
super = g_new0 (struct vfs_s_super, 1);
|
1998-10-23 12:26:25 +04:00
|
|
|
super->me = me;
|
1998-12-02 08:11:48 +03:00
|
|
|
return super;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2011-03-28 15:18:21 +04:00
|
|
|
static inline void
|
2003-10-12 05:00:44 +04:00
|
|
|
vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
VFS_SUBCLASS (me)->supers = g_list_prepend (VFS_SUBCLASS (me)->supers, super);
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-08 02:38:28 +04:00
|
|
|
static void
|
2003-10-12 05:00:44 +04:00
|
|
|
vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2011-03-28 16:17:45 +04:00
|
|
|
if (super->root != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
vfs_s_free_inode (me, super->root);
|
|
|
|
super->root = NULL;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
1998-10-23 12:26:25 +04:00
|
|
|
|
1999-12-08 14:39:14 +03:00
|
|
|
#if 0
|
Fix various typos in the source code (closes MidnightCommander/mc#177).
Found via `codespell -S
po,doc,./misc/syntax,./src/vfs/extfs/helpers/README.it -L
parm,rouge,sav,ect,vie,te,dum,clen,wee,dynamc,childs,ths,fo,nin,unx,nd,iif,iterm,ser,makrs,wil`
Co-authored-by: Yury V. Zaytsev <yury@shurup.com>
Signed-off-by: Kian-Meng Ang <kianmeng@cpan.org>
Signed-off-by: Yury V. Zaytsev <yury@shurup.com>
2023-01-10 06:02:52 +03:00
|
|
|
/* FIXME: We currently leak small amount of memory, sometimes. Fix it if you can. */
|
2018-01-08 11:20:55 +03:00
|
|
|
if (super->ino_usage != 0)
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, "Direntry warning",
|
2010-03-30 12:10:25 +04:00
|
|
|
"Super ino_usage is %d, memory leak", super->ino_usage);
|
1998-12-09 23:22:53 +03:00
|
|
|
|
|
|
|
if (super->want_stale)
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, "Direntry warning", "%s", "Super has want_stale set");
|
1998-11-21 22:36:01 +03:00
|
|
|
#endif
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
VFS_SUBCLASS (me)->supers = g_list_remove (VFS_SUBCLASS (me)->supers, super);
|
1998-10-23 12:26:25 +04:00
|
|
|
|
1999-01-18 02:10:05 +03:00
|
|
|
CALL (free_archive) (me, super);
|
2011-03-29 11:20:34 +04:00
|
|
|
#ifdef ENABLE_VFS_NET
|
2011-06-07 14:18:08 +04:00
|
|
|
vfs_path_element_free (super->path_element);
|
2011-03-29 11:20:34 +04:00
|
|
|
#endif
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (super->name);
|
2010-03-30 12:10:25 +04:00
|
|
|
g_free (super);
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2016-08-17 14:34:37 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static vfs_file_handler_t *
|
|
|
|
vfs_s_new_fh (struct vfs_s_inode *ino, gboolean changed)
|
|
|
|
{
|
|
|
|
vfs_file_handler_t *fh;
|
|
|
|
|
|
|
|
fh = g_new0 (vfs_file_handler_t, 1);
|
|
|
|
vfs_s_init_fh (fh, ino, changed);
|
|
|
|
|
|
|
|
return fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_free_fh (struct vfs_s_subclass *s, vfs_file_handler_t *fh)
|
2016-08-17 14:34:37 +03:00
|
|
|
{
|
|
|
|
if (s->fh_free != NULL)
|
|
|
|
s->fh_free (fh);
|
|
|
|
|
|
|
|
g_free (fh);
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-10-23 12:26:25 +04:00
|
|
|
/* Support of archives */
|
1998-11-21 22:36:01 +03:00
|
|
|
/* ------------------------ readdir & friends ----------------------------- */
|
|
|
|
|
2003-10-12 05:00:44 +04:00
|
|
|
static struct vfs_s_inode *
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_inode_from_path (const vfs_path_t *vpath, int flags)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
|
|
|
struct vfs_s_super *super;
|
2000-05-03 23:10:52 +04:00
|
|
|
struct vfs_s_inode *ino;
|
2011-06-19 14:32:07 +04:00
|
|
|
const char *q;
|
2023-07-16 11:18:59 +03:00
|
|
|
struct vfs_class *me;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2011-04-28 15:39:59 +04:00
|
|
|
q = vfs_s_get_path (vpath, &super, 0);
|
|
|
|
if (q == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
return NULL;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
|
2011-04-26 17:29:34 +04:00
|
|
|
|
2003-10-27 06:09:40 +03:00
|
|
|
ino =
|
2023-07-16 11:18:59 +03:00
|
|
|
vfs_s_find_inode (me, super, q,
|
2016-04-24 20:30:37 +03:00
|
|
|
(flags & FL_FOLLOW) != 0 ? LINK_FOLLOW : LINK_NO_FOLLOW,
|
|
|
|
flags & ~FL_FOLLOW);
|
2018-01-08 11:20:55 +03:00
|
|
|
if (ino == NULL && *q == '\0')
|
2010-03-30 12:10:25 +04:00
|
|
|
/* We are asking about / directory of ftp server: assume it exists */
|
|
|
|
ino =
|
2023-07-16 11:18:59 +03:00
|
|
|
vfs_s_find_inode (me, super, q,
|
2016-04-24 20:30:37 +03:00
|
|
|
(flags & FL_FOLLOW) != 0 ? LINK_FOLLOW : LINK_NO_FOLLOW,
|
|
|
|
FL_DIR | (flags & ~FL_FOLLOW));
|
2000-05-03 23:10:52 +04:00
|
|
|
return ino;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static void *
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_opendir (const vfs_path_t *vpath)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
1998-11-21 22:36:01 +03:00
|
|
|
struct vfs_s_inode *dir;
|
|
|
|
struct dirhandle *info;
|
2023-07-16 11:18:59 +03:00
|
|
|
struct vfs_class *me;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2011-04-26 17:29:34 +04:00
|
|
|
dir = vfs_s_inode_from_path (vpath, FL_DIR | FL_FOLLOW);
|
2011-03-28 16:17:45 +04:00
|
|
|
if (dir == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
return NULL;
|
2019-05-20 13:47:43 +03:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
|
2019-05-20 13:47:43 +03:00
|
|
|
|
1999-01-11 03:48:23 +03:00
|
|
|
if (!S_ISDIR (dir->st.st_mode))
|
2011-04-20 16:59:06 +04:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = ENOTDIR;
|
2011-04-20 16:59:06 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
1998-10-23 12:26:25 +04:00
|
|
|
|
1998-11-21 22:36:01 +03:00
|
|
|
dir->st.st_nlink++;
|
|
|
|
#if 0
|
2011-03-28 16:17:45 +04:00
|
|
|
if (dir->subdir == NULL) /* This can actually happen if we allow empty directories */
|
2011-04-20 16:59:06 +04:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = EAGAIN;
|
2011-04-20 16:59:06 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
1998-11-21 22:36:01 +03:00
|
|
|
#endif
|
1999-01-21 01:01:11 +03:00
|
|
|
info = g_new (struct dirhandle, 1);
|
2015-01-16 10:56:08 +03:00
|
|
|
info->cur = g_queue_peek_head_link (dir->subdir);
|
1998-11-21 22:36:01 +03:00
|
|
|
info->dir = dir;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2020-11-16 10:09:09 +03:00
|
|
|
static struct vfs_dirent *
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_s_readdir (void *data)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2020-11-16 10:09:09 +03:00
|
|
|
struct vfs_dirent *dir = NULL;
|
1998-11-21 22:36:01 +03:00
|
|
|
struct dirhandle *info = (struct dirhandle *) data;
|
2011-03-28 16:17:45 +04:00
|
|
|
const char *name;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
if (info->cur == NULL || info->cur->data == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
return NULL;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2018-03-02 15:02:55 +03:00
|
|
|
name = VFS_ENTRY (info->cur->data)->name;
|
2011-03-28 16:17:45 +04:00
|
|
|
if (name != NULL)
|
2020-11-16 10:09:09 +03:00
|
|
|
dir = vfs_dirent_init (NULL, name, 0);
|
2010-03-30 12:10:25 +04:00
|
|
|
else
|
|
|
|
vfs_die ("Null in structure-cannot happen");
|
1999-01-11 03:48:23 +03:00
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
info->cur = g_list_next (info->cur);
|
2002-08-16 01:15:17 +04:00
|
|
|
|
2020-11-16 10:09:09 +03:00
|
|
|
return dir;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static int
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_closedir (void *data)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
1998-11-21 22:36:01 +03:00
|
|
|
struct dirhandle *info = (struct dirhandle *) data;
|
|
|
|
struct vfs_s_inode *dir = info->dir;
|
|
|
|
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_free_inode (dir->super->me, dir);
|
2009-02-06 01:27:37 +03:00
|
|
|
g_free (data);
|
1998-10-23 12:26:25 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_chdir (const vfs_path_t *vpath)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
|
|
|
void *data;
|
2010-03-30 22:59:41 +04:00
|
|
|
|
2011-04-20 16:59:06 +04:00
|
|
|
data = vfs_s_opendir (vpath);
|
2010-03-30 22:59:41 +04:00
|
|
|
if (data == NULL)
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_closedir (data);
|
1998-10-23 12:26:25 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-11-21 22:36:01 +03:00
|
|
|
/* --------------------------- stat and friends ---------------------------- */
|
1998-10-23 12:26:25 +04:00
|
|
|
|
1999-01-18 02:10:05 +03:00
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_internal_stat (const vfs_path_t *vpath, struct stat *buf, int flag)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
|
|
|
struct vfs_s_inode *ino;
|
|
|
|
|
2011-04-26 17:29:34 +04:00
|
|
|
ino = vfs_s_inode_from_path (vpath, flag);
|
2010-03-30 22:59:41 +04:00
|
|
|
if (ino == NULL)
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
1998-10-23 12:26:25 +04:00
|
|
|
*buf = ino->st;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_readlink (const vfs_path_t *vpath, char *buf, size_t size)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
|
|
|
struct vfs_s_inode *ino;
|
2004-09-02 18:12:21 +04:00
|
|
|
size_t len;
|
2023-07-16 11:18:59 +03:00
|
|
|
struct vfs_class *me;
|
2011-04-21 11:46:20 +04:00
|
|
|
|
2011-04-26 17:29:34 +04:00
|
|
|
ino = vfs_s_inode_from_path (vpath, 0);
|
2018-01-08 11:20:55 +03:00
|
|
|
if (ino == NULL)
|
|
|
|
return (-1);
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
|
2019-05-20 13:47:43 +03:00
|
|
|
|
1999-01-11 03:48:23 +03:00
|
|
|
if (!S_ISLNK (ino->st.st_mode))
|
2011-04-21 11:46:20 +04:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = EINVAL;
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
2011-04-21 11:46:20 +04:00
|
|
|
}
|
2000-01-31 16:48:00 +03:00
|
|
|
|
|
|
|
if (ino->linkname == NULL)
|
2011-04-21 11:46:20 +04:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = EFAULT;
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
2011-04-21 11:46:20 +04:00
|
|
|
}
|
2000-01-31 16:48:00 +03:00
|
|
|
|
2004-11-29 21:44:49 +03:00
|
|
|
len = strlen (ino->linkname);
|
2004-09-02 18:12:21 +04:00
|
|
|
if (size < len)
|
2010-03-30 12:10:25 +04:00
|
|
|
len = size;
|
2004-09-02 18:12:21 +04:00
|
|
|
/* readlink() does not append a NUL character to buf */
|
|
|
|
memcpy (buf, ino->linkname, len);
|
|
|
|
return len;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2009-01-13 21:00:25 +03:00
|
|
|
static ssize_t
|
2010-07-18 17:46:59 +04:00
|
|
|
vfs_s_read (void *fh, char *buffer, size_t count)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
|
|
|
|
struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->linear == LS_LINEAR_PREOPEN)
|
|
|
|
if (VFS_SUBCLASS (me)->linear_start (me, file, file->pos) == 0)
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
2006-01-25 17:04:27 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->linear == LS_LINEAR_CLOSED)
|
1998-11-21 22:36:01 +03:00
|
|
|
vfs_die ("linear_start() did not set linear_state!");
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->linear == LS_LINEAR_OPEN)
|
|
|
|
return VFS_SUBCLASS (me)->linear_read (me, file, buffer, count);
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->handle != -1)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2012-11-18 14:11:30 +04:00
|
|
|
ssize_t n;
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
n = read (file->handle, buffer, count);
|
2010-03-30 12:10:25 +04:00
|
|
|
if (n < 0)
|
|
|
|
me->verrno = errno;
|
|
|
|
return n;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_die ("vfs_s_read: This should not happen\n");
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-04-23 23:14:11 +04:00
|
|
|
static ssize_t
|
2010-07-18 17:46:59 +04:00
|
|
|
vfs_s_write (void *fh, const char *buffer, size_t count)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
|
|
|
|
struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->linear != LS_NOT_LINEAR)
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_die ("no writing to linear files, please");
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
file->changed = TRUE;
|
|
|
|
if (file->handle != -1)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2012-11-18 14:11:30 +04:00
|
|
|
ssize_t n;
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
n = write (file->handle, buffer, count);
|
2010-03-30 12:10:25 +04:00
|
|
|
if (n < 0)
|
|
|
|
me->verrno = errno;
|
|
|
|
return n;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_die ("vfs_s_write: This should not happen\n");
|
1999-01-02 10:46:20 +03:00
|
|
|
return 0;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-01-13 21:00:25 +03:00
|
|
|
static off_t
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_lseek (void *fh, off_t offset, int whence)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
|
|
|
|
off_t size = file->ino->st.st_size;
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->linear == LS_LINEAR_OPEN)
|
2006-01-25 17:04:27 +03:00
|
|
|
vfs_die ("cannot lseek() after linear_read!");
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->handle != -1)
|
2010-03-30 12:10:25 +04:00
|
|
|
{ /* If we have local file opened, we want to work with it */
|
2018-01-08 11:20:55 +03:00
|
|
|
off_t retval;
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
retval = lseek (file->handle, offset, whence);
|
2010-03-30 12:10:25 +04:00
|
|
|
if (retval == -1)
|
2018-09-12 14:01:28 +03:00
|
|
|
VFS_FILE_HANDLER_SUPER (fh)->me->verrno = errno;
|
2010-03-30 12:10:25 +04:00
|
|
|
return retval;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
switch (whence)
|
|
|
|
{
|
|
|
|
case SEEK_CUR:
|
2018-09-12 14:01:28 +03:00
|
|
|
offset += file->pos;
|
2010-03-30 12:10:25 +04:00
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
offset += size;
|
|
|
|
break;
|
2015-04-19 13:57:38 +03:00
|
|
|
default:
|
|
|
|
break;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
if (offset < 0)
|
2018-09-12 14:01:28 +03:00
|
|
|
file->pos = 0;
|
1998-10-23 12:26:25 +04:00
|
|
|
else if (offset < size)
|
2018-09-12 14:01:28 +03:00
|
|
|
file->pos = offset;
|
1998-10-23 12:26:25 +04:00
|
|
|
else
|
2018-09-12 14:01:28 +03:00
|
|
|
file->pos = size;
|
|
|
|
return file->pos;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static int
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_close (void *fh)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
|
|
|
|
struct vfs_s_super *super = VFS_FILE_HANDLER_SUPER (fh);
|
|
|
|
struct vfs_class *me = super->me;
|
2018-09-12 14:01:28 +03:00
|
|
|
struct vfs_s_subclass *sub = VFS_SUBCLASS (me);
|
2018-09-12 14:01:28 +03:00
|
|
|
int res = 0;
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2013-12-03 12:09:28 +04:00
|
|
|
if (me == NULL)
|
|
|
|
return (-1);
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
super->fd_usage--;
|
|
|
|
if (super->fd_usage == 0)
|
|
|
|
vfs_stamp_create (me, VFS_FILE_HANDLER_SUPER (fh));
|
2003-11-13 11:03:03 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->linear == LS_LINEAR_OPEN)
|
2018-09-12 14:01:28 +03:00
|
|
|
sub->linear_close (me, fh);
|
|
|
|
if (sub->fh_close != NULL)
|
|
|
|
res = sub->fh_close (me, fh);
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((me->flags & VFSF_USETMP) != 0 && file->changed && sub->file_store != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2018-01-08 11:20:55 +03:00
|
|
|
char *s;
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
s = vfs_s_fullpath (me, file->ino);
|
2018-01-08 11:20:55 +03:00
|
|
|
|
|
|
|
if (s == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
res = -1;
|
|
|
|
else
|
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
res = sub->file_store (me, fh, s, file->ino->localname);
|
2010-03-30 12:10:25 +04:00
|
|
|
g_free (s);
|
|
|
|
}
|
2018-09-12 14:01:28 +03:00
|
|
|
vfs_s_invalidate (me, super);
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
2019-05-11 11:15:59 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
if (file->handle != -1)
|
2019-05-11 11:15:59 +03:00
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
close (file->handle);
|
2019-05-11 11:15:59 +03:00
|
|
|
file->handle = -1;
|
|
|
|
}
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
vfs_s_free_inode (me, file->ino);
|
2016-08-17 14:34:37 +03:00
|
|
|
vfs_s_free_fh (sub, fh);
|
|
|
|
|
1998-11-21 22:36:01 +03:00
|
|
|
return res;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-11-05 09:08:16 +03:00
|
|
|
static void
|
|
|
|
vfs_s_print_stats (const char *fs_name, const char *action,
|
2010-03-30 12:10:25 +04:00
|
|
|
const char *file_name, off_t have, off_t need)
|
2003-11-05 09:08:16 +03:00
|
|
|
{
|
2015-11-21 18:23:45 +03:00
|
|
|
if (need != 0)
|
|
|
|
vfs_print_message (_("%s: %s: %s %3d%% (%lld) bytes transferred"), fs_name, action,
|
|
|
|
file_name, (int) ((double) have * 100 / need), (long long) have);
|
2003-11-05 09:08:16 +03:00
|
|
|
else
|
2016-01-03 15:39:57 +03:00
|
|
|
vfs_print_message (_("%s: %s: %s %lld bytes transferred"), fs_name, action, file_name,
|
2015-11-21 18:23:45 +03:00
|
|
|
(long long) have);
|
2003-11-05 09:08:16 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-10-23 12:26:25 +04:00
|
|
|
/* ------------------------------- mc support ---------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static void
|
2004-08-16 20:34:11 +04:00
|
|
|
vfs_s_fill_names (struct vfs_class *me, fill_names_f func)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2011-03-28 15:18:21 +04:00
|
|
|
GList *iter;
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
for (iter = VFS_SUBCLASS (me)->supers; iter != NULL; iter = g_list_next (iter))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2011-03-28 15:18:21 +04:00
|
|
|
const struct vfs_s_super *super = (const struct vfs_s_super *) iter->data;
|
|
|
|
char *name;
|
|
|
|
|
2015-01-07 11:34:53 +03:00
|
|
|
name = g_strconcat (super->name, PATH_SEP_STR, me->prefix, VFS_PATH_URL_DELIMITER,
|
2011-03-28 15:18:21 +04:00
|
|
|
/* super->current_dir->name, */ (char *) NULL);
|
|
|
|
func (name);
|
2010-03-30 12:10:25 +04:00
|
|
|
g_free (name);
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static int
|
2003-10-12 04:24:00 +04:00
|
|
|
vfs_s_ferrno (struct vfs_class *me)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
|
|
|
return me->verrno;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
2003-10-28 11:20:30 +03:00
|
|
|
* Get local copy of the given file. We reuse the existing file cache
|
|
|
|
* for remote filesystems. Archives use standard VFS facilities.
|
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2011-07-24 16:27:48 +04:00
|
|
|
static vfs_path_t *
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_getlocalcopy (const vfs_path_t *vpath)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2011-02-09 14:34:13 +03:00
|
|
|
vfs_file_handler_t *fh;
|
2011-07-24 16:27:48 +04:00
|
|
|
vfs_path_t *local = NULL;
|
2003-10-28 10:09:39 +03:00
|
|
|
|
2011-07-23 14:25:00 +04:00
|
|
|
if (vpath == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2011-04-18 18:08:55 +04:00
|
|
|
fh = vfs_s_open (vpath, O_RDONLY, 0);
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
if (fh != NULL)
|
|
|
|
{
|
2012-01-03 13:35:57 +04:00
|
|
|
const struct vfs_class *me;
|
2011-07-23 14:25:00 +04:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = vfs_path_get_last_path_vfs (vpath);
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((me->flags & VFSF_USETMP) != 0 && fh->ino != NULL)
|
2011-07-24 16:27:48 +04:00
|
|
|
local = vfs_path_from_str_flags (fh->ino->localname, VPF_NO_CANON);
|
2010-03-05 21:37:09 +03:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
vfs_s_close (fh);
|
2010-03-05 21:37:09 +03:00
|
|
|
}
|
|
|
|
|
2003-10-28 10:09:39 +03:00
|
|
|
return local;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
2003-10-28 10:09:39 +03:00
|
|
|
* Return the local copy. Since we are using our cache, we do nothing -
|
|
|
|
* the cache will be removed when the archive is closed.
|
|
|
|
*/
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2003-10-28 10:09:39 +03:00
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_ungetlocalcopy (const vfs_path_t *vpath, const vfs_path_t *local, gboolean has_changed)
|
2003-10-28 10:09:39 +03:00
|
|
|
{
|
2011-04-18 18:08:55 +04:00
|
|
|
(void) vpath;
|
2005-02-22 21:35:22 +03:00
|
|
|
(void) local;
|
|
|
|
(void) has_changed;
|
2003-10-28 10:09:39 +03:00
|
|
|
return 0;
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-16 20:12:19 +04:00
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_setctl (const vfs_path_t *vpath, int ctlop, void *arg)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
struct vfs_class *me;
|
2011-04-21 14:27:56 +04:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
|
2012-01-03 13:35:57 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
switch (ctlop)
|
|
|
|
{
|
2003-10-16 20:12:19 +04:00
|
|
|
case VFS_SETCTL_STALE_DATA:
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2012-01-03 13:35:57 +04:00
|
|
|
struct vfs_s_inode *ino;
|
2010-03-30 12:10:25 +04:00
|
|
|
|
2012-01-03 13:35:57 +04:00
|
|
|
ino = vfs_s_inode_from_path (vpath, 0);
|
2010-03-30 22:59:41 +04:00
|
|
|
if (ino == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
return 0;
|
2018-01-08 11:20:55 +03:00
|
|
|
if (arg != NULL)
|
2018-01-08 11:23:10 +03:00
|
|
|
ino->super->want_stale = TRUE;
|
2010-03-30 12:10:25 +04:00
|
|
|
else
|
|
|
|
{
|
2018-01-08 11:23:10 +03:00
|
|
|
ino->super->want_stale = FALSE;
|
2023-07-16 11:18:59 +03:00
|
|
|
vfs_s_invalidate (me, ino->super);
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2003-10-16 21:08:38 +04:00
|
|
|
case VFS_SETCTL_LOGFILE:
|
2023-07-16 11:18:59 +03:00
|
|
|
me->logfile = fopen ((char *) arg, "w");
|
2010-03-30 12:10:25 +04:00
|
|
|
return 1;
|
2003-10-16 22:51:41 +04:00
|
|
|
case VFS_SETCTL_FLUSH:
|
2023-07-16 11:18:59 +03:00
|
|
|
me->flush = TRUE;
|
2010-03-30 12:10:25 +04:00
|
|
|
return 1;
|
2015-04-19 13:57:38 +03:00
|
|
|
default:
|
|
|
|
return 0;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-11-21 22:36:01 +03:00
|
|
|
/* ----------------------------- Stamping support -------------------------- */
|
1998-10-23 12:26:25 +04:00
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static vfsid
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_getid (const vfs_path_t *vpath)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2010-03-30 22:59:41 +04:00
|
|
|
struct vfs_s_super *archive = NULL;
|
2011-06-19 14:32:07 +04:00
|
|
|
const char *p;
|
2011-04-21 14:27:56 +04:00
|
|
|
|
2011-04-26 17:29:34 +04:00
|
|
|
p = vfs_s_get_path (vpath, &archive, FL_NO_OPEN);
|
2024-09-12 10:15:43 +03:00
|
|
|
return (p == NULL ? NULL : (vfsid) archive);
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2019-05-14 15:56:24 +03:00
|
|
|
static gboolean
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_nothingisopen (vfsid id)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2019-05-18 18:19:00 +03:00
|
|
|
return (VFS_SUPER (id)->fd_usage <= 0);
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-11 14:13:36 +04:00
|
|
|
static void
|
1999-01-18 02:10:05 +03:00
|
|
|
vfs_s_free (vfsid id)
|
1998-10-23 12:26:25 +04:00
|
|
|
{
|
2016-08-17 13:54:08 +03:00
|
|
|
vfs_s_free_super (VFS_SUPER (id)->me, VFS_SUPER (id));
|
1998-10-23 12:26:25 +04:00
|
|
|
}
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2020-03-08 20:36:26 +03:00
|
|
|
static gboolean
|
2006-02-23 13:46:29 +03:00
|
|
|
vfs_s_dir_uptodate (struct vfs_class *me, struct vfs_s_inode *ino)
|
|
|
|
{
|
2020-11-22 15:06:29 +03:00
|
|
|
gint64 tim;
|
2006-02-23 13:46:29 +03:00
|
|
|
|
2019-05-20 07:54:51 +03:00
|
|
|
if (me->flush)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2019-05-20 07:54:51 +03:00
|
|
|
me->flush = FALSE;
|
2010-03-30 12:10:25 +04:00
|
|
|
return 0;
|
2006-02-23 13:46:29 +03:00
|
|
|
}
|
|
|
|
|
2021-10-03 17:12:42 +03:00
|
|
|
tim = g_get_monotonic_time ();
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2020-03-08 20:36:26 +03:00
|
|
|
return (tim < ino->timestamp);
|
2006-02-23 13:46:29 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** public functions ****************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
struct vfs_s_inode *
|
|
|
|
vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat)
|
2010-07-22 15:55:23 +04:00
|
|
|
{
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_inode *ino;
|
2010-07-22 15:55:23 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
ino = g_try_new0 (struct vfs_s_inode, 1);
|
|
|
|
if (ino == NULL)
|
|
|
|
return NULL;
|
2010-07-22 15:55:23 +04:00
|
|
|
|
2018-01-08 11:20:55 +03:00
|
|
|
if (initstat != NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
ino->st = *initstat;
|
|
|
|
ino->super = super;
|
2015-01-16 10:56:08 +03:00
|
|
|
ino->subdir = g_queue_new ();
|
2010-11-08 13:21:45 +03:00
|
|
|
ino->st.st_nlink = 0;
|
2018-09-12 14:01:28 +03:00
|
|
|
ino->st.st_ino = VFS_SUBCLASS (me)->inode_counter++;
|
|
|
|
ino->st.st_dev = VFS_SUBCLASS (me)->rdev;
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
super->ino_usage++;
|
|
|
|
|
|
|
|
CALL (init_inode) (me, ino);
|
|
|
|
|
|
|
|
return ino;
|
2010-07-22 15:55:23 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2011-07-20 01:36:05 +04:00
|
|
|
void
|
|
|
|
vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
|
|
|
|
{
|
|
|
|
if (ino == NULL)
|
|
|
|
vfs_die ("Don't pass NULL to me");
|
|
|
|
|
|
|
|
/* ==0 can happen if freshly created entry is deleted */
|
|
|
|
if (ino->st.st_nlink > 1)
|
|
|
|
{
|
|
|
|
ino->st.st_nlink--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-16 10:56:08 +03:00
|
|
|
while (g_queue_get_length (ino->subdir) != 0)
|
|
|
|
{
|
|
|
|
struct vfs_s_entry *entry;
|
|
|
|
|
|
|
|
entry = VFS_ENTRY (g_queue_peek_head (ino->subdir));
|
|
|
|
vfs_s_free_entry (me, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_queue_free (ino->subdir);
|
|
|
|
ino->subdir = NULL;
|
2011-07-20 01:36:05 +04:00
|
|
|
|
|
|
|
CALL (free_inode) (me, ino);
|
|
|
|
g_free (ino->linkname);
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((me->flags & VFSF_USETMP) != 0 && ino->localname != NULL)
|
2011-07-20 01:36:05 +04:00
|
|
|
{
|
|
|
|
unlink (ino->localname);
|
|
|
|
g_free (ino->localname);
|
|
|
|
}
|
|
|
|
ino->super->ino_usage--;
|
|
|
|
g_free (ino);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_entry *
|
|
|
|
vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *inode)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_entry *entry;
|
|
|
|
|
|
|
|
entry = g_new0 (struct vfs_s_entry, 1);
|
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
entry->name = g_strdup (name);
|
2010-11-08 13:21:45 +03:00
|
|
|
entry->ino = inode;
|
|
|
|
entry->ino->ent = entry;
|
|
|
|
CALL (init_entry) (me, entry);
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
|
|
|
|
{
|
2011-03-28 16:17:45 +04:00
|
|
|
if (ent->dir != NULL)
|
2015-01-16 10:56:08 +03:00
|
|
|
g_queue_remove (ent->dir->subdir, ent);
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2014-08-05 11:18:30 +04:00
|
|
|
MC_PTR_FREE (ent->name);
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2011-03-28 16:17:45 +04:00
|
|
|
if (ent->ino != NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
|
|
|
ent->ino->ent = NULL;
|
|
|
|
vfs_s_free_inode (me, ent->ino);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
|
|
|
|
{
|
|
|
|
(void) me;
|
|
|
|
|
|
|
|
ent->dir = dir;
|
|
|
|
|
|
|
|
ent->ino->st.st_nlink++;
|
2015-01-16 10:56:08 +03:00
|
|
|
g_queue_push_tail (dir->subdir, ent);
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2018-03-02 15:02:55 +03:00
|
|
|
int
|
|
|
|
vfs_s_entry_compare (const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const struct vfs_s_entry *e = (const struct vfs_s_entry *) a;
|
|
|
|
const char *name = (const char *) b;
|
|
|
|
|
|
|
|
return strcmp (e->name, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
struct stat *
|
|
|
|
vfs_s_default_stat (struct vfs_class *me, mode_t mode)
|
|
|
|
{
|
|
|
|
static struct stat st;
|
2015-11-21 17:21:23 +03:00
|
|
|
mode_t myumask;
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
(void) me;
|
|
|
|
|
|
|
|
myumask = umask (022);
|
|
|
|
umask (myumask);
|
|
|
|
mode &= ~myumask;
|
|
|
|
|
|
|
|
st.st_mode = mode;
|
|
|
|
st.st_ino = 0;
|
|
|
|
st.st_dev = 0;
|
2017-01-02 10:55:26 +03:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_RDEV
|
2010-11-08 13:21:45 +03:00
|
|
|
st.st_rdev = 0;
|
2017-01-02 10:55:26 +03:00
|
|
|
#endif
|
2010-11-08 13:21:45 +03:00
|
|
|
st.st_uid = getuid ();
|
|
|
|
st.st_gid = getgid ();
|
2016-12-30 11:28:19 +03:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
|
|
|
st.st_blksize = 512;
|
|
|
|
#endif
|
2010-11-08 13:21:45 +03:00
|
|
|
st.st_size = 0;
|
2017-05-06 21:57:59 +03:00
|
|
|
|
2024-06-01 18:44:28 +03:00
|
|
|
vfs_zero_stat_times (&st);
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2017-01-04 11:27:19 +03:00
|
|
|
vfs_adjust_stat (&st);
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
return &st;
|
|
|
|
}
|
|
|
|
|
2017-01-04 11:27:19 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Calculate number of st_blocks using st_size and st_blksize.
|
|
|
|
* In according to stat(2), st_blocks is the size in 512-byte units.
|
|
|
|
*
|
|
|
|
* @param s stat info
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_adjust_stat (struct stat *s)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
|
|
|
|
if (s->st_size == 0)
|
|
|
|
s->st_blocks = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
|
|
|
blkcnt_t ioblocks;
|
|
|
|
blksize_t ioblock_size;
|
|
|
|
|
|
|
|
/* 1. Calculate how many IO blocks are occupied */
|
|
|
|
ioblocks = 1 + (s->st_size - 1) / s->st_blksize;
|
|
|
|
/* 2. Calculate size of st_blksize in 512-byte units */
|
|
|
|
ioblock_size = 1 + (s->st_blksize - 1) / 512;
|
|
|
|
/* 3. Calculate number of blocks */
|
|
|
|
s->st_blocks = ioblocks * ioblock_size;
|
|
|
|
#else
|
|
|
|
/* Let IO block size is 512 bytes */
|
|
|
|
s->st_blocks = 1 + (s->st_size - 1) / 512;
|
|
|
|
#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
|
|
|
|
}
|
|
|
|
#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
struct vfs_s_entry *
|
|
|
|
vfs_s_generate_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *parent,
|
|
|
|
mode_t mode)
|
|
|
|
{
|
|
|
|
struct vfs_s_inode *inode;
|
|
|
|
struct stat *st;
|
|
|
|
|
|
|
|
st = vfs_s_default_stat (me, mode);
|
|
|
|
inode = vfs_s_new_inode (me, parent->super, st);
|
|
|
|
|
|
|
|
return vfs_s_new_entry (me, name, inode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
struct vfs_s_inode *
|
|
|
|
vfs_s_find_inode (struct vfs_class *me, const struct vfs_s_super *super,
|
|
|
|
const char *path, int follow, int flags)
|
|
|
|
{
|
|
|
|
struct vfs_s_entry *ent;
|
|
|
|
|
2019-11-18 21:24:13 +03:00
|
|
|
if (((me->flags & VFSF_REMOTE) == 0) && (*path == '\0'))
|
2010-11-08 13:21:45 +03:00
|
|
|
return super->root;
|
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
ent = VFS_SUBCLASS (me)->find_entry (me, super->root, path, follow, flags);
|
2018-01-08 11:20:55 +03:00
|
|
|
return (ent != NULL ? ent->ino : NULL);
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/* Ook, these were functions around directory entries / inodes */
|
|
|
|
/* -------------------------------- superblock games -------------------------- */
|
2011-06-19 14:32:07 +04:00
|
|
|
/**
|
2012-05-02 16:37:06 +04:00
|
|
|
* get superlock object by vpath
|
2011-06-19 14:32:07 +04:00
|
|
|
*
|
2012-05-02 16:37:06 +04:00
|
|
|
* @param vpath path
|
|
|
|
* @return superlock object or NULL if not found
|
2010-11-08 13:21:45 +03:00
|
|
|
*/
|
2012-05-02 16:37:06 +04:00
|
|
|
|
|
|
|
struct vfs_s_super *
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_get_super_by_vpath (const vfs_path_t *vpath)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2011-03-28 15:18:21 +04:00
|
|
|
GList *iter;
|
2010-11-08 13:21:45 +03:00
|
|
|
void *cookie = NULL;
|
2012-01-03 13:35:57 +04:00
|
|
|
const vfs_path_element_t *path_element;
|
2011-04-28 15:39:59 +04:00
|
|
|
struct vfs_s_subclass *subclass;
|
2012-05-02 16:37:06 +04:00
|
|
|
struct vfs_s_super *super = NULL;
|
|
|
|
vfs_path_t *vpath_archive;
|
2011-04-28 15:39:59 +04:00
|
|
|
|
|
|
|
path_element = vfs_path_get_by_index (vpath, -1);
|
2018-09-12 14:01:28 +03:00
|
|
|
subclass = VFS_SUBCLASS (path_element->class);
|
2012-04-20 15:03:53 +04:00
|
|
|
|
2011-06-08 17:40:36 +04:00
|
|
|
vpath_archive = vfs_path_clone (vpath);
|
|
|
|
vfs_path_remove_element_by_index (vpath_archive, -1);
|
|
|
|
|
2011-04-28 15:39:59 +04:00
|
|
|
if (subclass->archive_check != NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2011-06-13 15:44:25 +04:00
|
|
|
cookie = subclass->archive_check (vpath_archive);
|
2010-11-08 13:21:45 +03:00
|
|
|
if (cookie == NULL)
|
2012-05-02 16:37:06 +04:00
|
|
|
goto ret;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
2016-08-17 11:27:57 +03:00
|
|
|
if (subclass->archive_same == NULL)
|
|
|
|
goto ret;
|
|
|
|
|
2011-04-28 15:39:59 +04:00
|
|
|
for (iter = subclass->supers; iter != NULL; iter = g_list_next (iter))
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2011-03-28 15:18:21 +04:00
|
|
|
int i;
|
|
|
|
|
2016-08-17 13:54:08 +03:00
|
|
|
super = VFS_SUPER (iter->data);
|
2011-03-28 15:18:21 +04:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* 0 == other, 1 == same, return it, 2 == other but stop scanning */
|
2011-06-13 15:44:25 +04:00
|
|
|
i = subclass->archive_same (path_element, super, vpath_archive, cookie);
|
2012-05-02 16:37:06 +04:00
|
|
|
if (i == 1)
|
|
|
|
goto ret;
|
2010-11-08 13:21:45 +03:00
|
|
|
if (i != 0)
|
2011-03-28 15:18:21 +04:00
|
|
|
break;
|
2012-06-04 18:00:03 +04:00
|
|
|
|
|
|
|
super = NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
2012-05-02 16:37:06 +04:00
|
|
|
ret:
|
2021-02-21 19:30:18 +03:00
|
|
|
vfs_path_free (vpath_archive, TRUE);
|
2012-05-02 16:37:06 +04:00
|
|
|
return super;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* get path from last VFS-element and create corresponding superblock
|
|
|
|
*
|
|
|
|
* @param vpath source path object
|
|
|
|
* @param archive pointer to object for store newly created superblock
|
|
|
|
* @param flags flags
|
|
|
|
*
|
|
|
|
* @return path from last VFS-element
|
|
|
|
*/
|
|
|
|
const char *
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_get_path (const vfs_path_t *vpath, struct vfs_s_super **archive, int flags)
|
2012-05-02 16:37:06 +04:00
|
|
|
{
|
|
|
|
const char *retval = "";
|
|
|
|
int result = -1;
|
|
|
|
struct vfs_s_super *super;
|
|
|
|
const vfs_path_element_t *path_element;
|
|
|
|
struct vfs_s_subclass *subclass;
|
|
|
|
|
|
|
|
path_element = vfs_path_get_by_index (vpath, -1);
|
|
|
|
|
|
|
|
if (path_element->path != NULL)
|
|
|
|
retval = path_element->path;
|
|
|
|
|
2012-06-04 18:00:03 +04:00
|
|
|
super = vfs_get_super_by_vpath (vpath);
|
2012-05-02 16:37:06 +04:00
|
|
|
if (super != NULL)
|
|
|
|
goto return_success;
|
|
|
|
|
2018-01-08 11:20:55 +03:00
|
|
|
if ((flags & FL_NO_OPEN) != 0)
|
2011-04-28 15:39:59 +04:00
|
|
|
{
|
|
|
|
path_element->class->verrno = EIO;
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2018-09-12 14:01:28 +03:00
|
|
|
subclass = VFS_SUBCLASS (path_element->class);
|
2012-05-02 16:37:06 +04:00
|
|
|
|
2016-08-17 13:54:08 +03:00
|
|
|
super = subclass->new_archive != NULL ?
|
|
|
|
subclass->new_archive (path_element->class) : vfs_s_new_super (path_element->class);
|
|
|
|
|
2011-04-28 15:39:59 +04:00
|
|
|
if (subclass->open_archive != NULL)
|
2012-05-02 16:37:06 +04:00
|
|
|
{
|
|
|
|
vfs_path_t *vpath_archive;
|
|
|
|
|
|
|
|
vpath_archive = vfs_path_clone (vpath);
|
|
|
|
vfs_path_remove_element_by_index (vpath_archive, -1);
|
|
|
|
|
2011-06-13 15:44:25 +04:00
|
|
|
result = subclass->open_archive (super, vpath_archive, path_element);
|
2021-02-21 19:30:18 +03:00
|
|
|
vfs_path_free (vpath_archive, TRUE);
|
2012-05-02 16:37:06 +04:00
|
|
|
}
|
2010-11-08 13:21:45 +03:00
|
|
|
if (result == -1)
|
|
|
|
{
|
2011-04-28 15:39:59 +04:00
|
|
|
vfs_s_free_super (path_element->class, super);
|
|
|
|
path_element->class->verrno = EIO;
|
|
|
|
return NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
2018-01-08 11:20:55 +03:00
|
|
|
if (super->name == NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
vfs_die ("You have to fill name\n");
|
2018-01-08 11:20:55 +03:00
|
|
|
if (super->root == NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
vfs_die ("You have to fill root inode\n");
|
|
|
|
|
2011-04-28 15:39:59 +04:00
|
|
|
vfs_s_insert_super (path_element->class, super);
|
|
|
|
vfs_stamp_create (path_element->class, super);
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
return_success:
|
|
|
|
*archive = super;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_s_invalidate (struct vfs_class *me, struct vfs_s_super *super)
|
|
|
|
{
|
|
|
|
if (!super->want_stale)
|
|
|
|
{
|
|
|
|
vfs_s_free_inode (me, super->root);
|
|
|
|
super->root = vfs_s_new_inode (me, super, vfs_s_default_stat (me, S_IFDIR | 0755));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
char *
|
|
|
|
vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
|
|
|
|
{
|
2018-01-08 11:20:55 +03:00
|
|
|
if (ino->ent == NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
ERRNOR (EAGAIN, NULL);
|
|
|
|
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((me->flags & VFSF_USETMP) == 0)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
|
|
|
/* archives */
|
2018-01-08 11:20:55 +03:00
|
|
|
char *path;
|
|
|
|
|
|
|
|
path = g_strdup (ino->ent->name);
|
|
|
|
|
|
|
|
while (TRUE)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2018-01-08 11:20:55 +03:00
|
|
|
char *newpath;
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
ino = ino->ent->dir;
|
|
|
|
if (ino == ino->super->root)
|
|
|
|
break;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2015-01-07 11:34:53 +03:00
|
|
|
newpath = g_strconcat (ino->ent->name, PATH_SEP_STR, path, (char *) NULL);
|
2010-11-08 13:21:45 +03:00
|
|
|
g_free (path);
|
|
|
|
path = newpath;
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remote systems */
|
2018-01-08 11:20:55 +03:00
|
|
|
if (ino->ent->dir == NULL || ino->ent->dir->ent == NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
return g_strdup (ino->ent->name);
|
|
|
|
|
|
|
|
return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, ino->ent->name, (char *) NULL);
|
|
|
|
}
|
|
|
|
|
2016-08-17 14:34:37 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_init_fh (vfs_file_handler_t *fh, struct vfs_s_inode *ino, gboolean changed)
|
2016-08-17 14:34:37 +03:00
|
|
|
{
|
|
|
|
fh->ino = ino;
|
|
|
|
fh->handle = -1;
|
|
|
|
fh->changed = changed;
|
|
|
|
fh->linear = LS_NOT_LINEAR;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/* --------------------------- stat and friends ---------------------------- */
|
|
|
|
|
|
|
|
void *
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_open (const vfs_path_t *vpath, int flags, mode_t mode)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2018-01-08 11:27:09 +03:00
|
|
|
gboolean was_changed = FALSE;
|
2011-02-09 14:34:13 +03:00
|
|
|
vfs_file_handler_t *fh;
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_super *super;
|
2011-06-19 14:32:07 +04:00
|
|
|
const char *q;
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_inode *ino;
|
2023-07-16 11:18:59 +03:00
|
|
|
struct vfs_class *me;
|
2016-08-17 11:27:57 +03:00
|
|
|
struct vfs_s_subclass *s;
|
2011-04-18 18:08:55 +04:00
|
|
|
|
2011-04-26 17:29:34 +04:00
|
|
|
q = vfs_s_get_path (vpath, &super, 0);
|
2010-11-08 13:21:45 +03:00
|
|
|
if (q == NULL)
|
|
|
|
return NULL;
|
2019-05-20 13:47:43 +03:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
|
2019-05-20 13:47:43 +03:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
ino = vfs_s_find_inode (me, super, q, LINK_FOLLOW, FL_NONE);
|
2018-01-08 11:20:55 +03:00
|
|
|
if (ino != NULL && (flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = EEXIST;
|
2011-04-18 18:08:55 +04:00
|
|
|
return NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
s = VFS_SUBCLASS (me);
|
2016-08-17 11:27:57 +03:00
|
|
|
|
2018-01-08 11:20:55 +03:00
|
|
|
if (ino == NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2023-01-03 09:30:39 +03:00
|
|
|
char *name;
|
2010-11-08 13:21:45 +03:00
|
|
|
struct vfs_s_entry *ent;
|
|
|
|
struct vfs_s_inode *dir;
|
|
|
|
|
|
|
|
/* If the filesystem is read-only, disable file creation */
|
2023-07-16 11:18:59 +03:00
|
|
|
if ((flags & O_CREAT) == 0 || me->write == NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
return NULL;
|
|
|
|
|
2023-01-03 09:30:39 +03:00
|
|
|
name = g_path_get_dirname (q);
|
2023-07-16 11:18:59 +03:00
|
|
|
dir = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_DIR);
|
2023-01-03 09:30:39 +03:00
|
|
|
g_free (name);
|
2010-12-09 11:40:12 +03:00
|
|
|
if (dir == NULL)
|
|
|
|
return NULL;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2022-06-07 22:03:53 +03:00
|
|
|
name = g_path_get_basename (q);
|
2023-07-16 11:18:59 +03:00
|
|
|
ent = vfs_s_generate_entry (me, name, dir, 0755);
|
2010-11-08 13:21:45 +03:00
|
|
|
ino = ent->ino;
|
2023-07-16 11:18:59 +03:00
|
|
|
vfs_s_insert_entry (me, dir, ent);
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0)
|
2011-07-23 14:25:00 +04:00
|
|
|
{
|
2013-10-15 10:34:04 +04:00
|
|
|
int tmp_handle;
|
2012-01-04 16:34:05 +04:00
|
|
|
vfs_path_t *tmp_vpath;
|
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
tmp_handle = vfs_mkstemps (&tmp_vpath, me->name, name);
|
2021-02-21 19:30:18 +03:00
|
|
|
ino->localname = vfs_path_free (tmp_vpath, FALSE);
|
2011-07-23 14:25:00 +04:00
|
|
|
if (tmp_handle == -1)
|
2011-07-20 22:20:41 +04:00
|
|
|
{
|
|
|
|
g_free (name);
|
2011-07-23 14:25:00 +04:00
|
|
|
return NULL;
|
2011-07-20 22:20:41 +04:00
|
|
|
}
|
2011-06-19 14:32:07 +04:00
|
|
|
|
2011-07-23 14:25:00 +04:00
|
|
|
close (tmp_handle);
|
|
|
|
}
|
2022-06-07 22:03:53 +03:00
|
|
|
|
2011-07-20 22:20:41 +04:00
|
|
|
g_free (name);
|
2018-01-08 11:27:09 +03:00
|
|
|
was_changed = TRUE;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (S_ISDIR (ino->st.st_mode))
|
2011-04-18 18:08:55 +04:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = EISDIR;
|
2011-04-18 18:08:55 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2016-08-17 14:34:37 +03:00
|
|
|
fh = s->fh_new != NULL ? s->fh_new (ino, was_changed) : vfs_s_new_fh (ino, was_changed);
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
if (IS_LINEAR (flags))
|
|
|
|
{
|
2016-08-17 11:27:57 +03:00
|
|
|
if (s->linear_start != NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2015-08-25 13:56:56 +03:00
|
|
|
vfs_print_message ("%s", _("Starting linear transfer..."));
|
2010-11-08 13:21:45 +03:00
|
|
|
fh->linear = LS_LINEAR_PREOPEN;
|
|
|
|
}
|
|
|
|
}
|
2011-10-19 12:45:28 +04:00
|
|
|
else
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
if (s->fh_open != NULL && s->fh_open (me, fh, flags, mode) != 0)
|
2011-10-19 12:45:28 +04:00
|
|
|
{
|
2016-08-17 14:34:37 +03:00
|
|
|
vfs_s_free_fh (s, fh);
|
2011-10-19 12:45:28 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((VFS_CLASS (s)->flags & VFSF_USETMP) != 0 && fh->ino->localname != NULL)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
|
|
|
fh->handle = open (fh->ino->localname, NO_LINEAR (flags), mode);
|
|
|
|
if (fh->handle == -1)
|
|
|
|
{
|
2016-08-17 14:34:37 +03:00
|
|
|
vfs_s_free_fh (s, fh);
|
2023-07-16 11:18:59 +03:00
|
|
|
me->verrno = errno;
|
2011-04-18 18:08:55 +04:00
|
|
|
return NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* i.e. we had no open files and now we have one */
|
2023-07-16 11:18:59 +03:00
|
|
|
vfs_rmstamp (me, (vfsid) super);
|
2010-11-08 13:21:45 +03:00
|
|
|
super->fd_usage++;
|
|
|
|
fh->ino->st.st_nlink++;
|
|
|
|
return fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2017-01-02 11:58:49 +03:00
|
|
|
int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_stat (const vfs_path_t *vpath, struct stat *buf)
|
2017-01-02 11:58:49 +03:00
|
|
|
{
|
|
|
|
return vfs_s_internal_stat (vpath, buf, FL_FOLLOW);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
int
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_s_lstat (const vfs_path_t *vpath, struct stat *buf)
|
2017-01-02 11:58:49 +03:00
|
|
|
{
|
|
|
|
return vfs_s_internal_stat (vpath, buf, FL_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
int
|
|
|
|
vfs_s_fstat (void *fh, struct stat *buf)
|
|
|
|
{
|
2018-09-12 14:01:28 +03:00
|
|
|
*buf = VFS_FILE_HANDLER (fh)->ino->st;
|
2017-01-02 11:58:49 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
int
|
|
|
|
vfs_s_retrieve_file (struct vfs_class *me, struct vfs_s_inode *ino)
|
|
|
|
{
|
|
|
|
/* If you want reget, you'll have to open file with O_LINEAR */
|
|
|
|
off_t total = 0;
|
2022-11-27 19:42:40 +03:00
|
|
|
char buffer[BUF_8K];
|
2012-11-18 14:31:04 +04:00
|
|
|
int handle;
|
|
|
|
ssize_t n;
|
2010-11-08 13:21:45 +03:00
|
|
|
off_t stat_size = ino->st.st_size;
|
2016-08-17 14:34:37 +03:00
|
|
|
vfs_file_handler_t *fh = NULL;
|
2012-01-04 16:34:05 +04:00
|
|
|
vfs_path_t *tmp_vpath;
|
2018-09-12 14:01:28 +03:00
|
|
|
struct vfs_s_subclass *s = VFS_SUBCLASS (me);
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((me->flags & VFSF_USETMP) == 0)
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
2011-07-23 14:25:00 +04:00
|
|
|
|
2012-01-04 16:34:05 +04:00
|
|
|
handle = vfs_mkstemps (&tmp_vpath, me->name, ino->ent->name);
|
2021-02-21 19:30:18 +03:00
|
|
|
ino->localname = vfs_path_free (tmp_vpath, FALSE);
|
2010-11-08 13:21:45 +03:00
|
|
|
if (handle == -1)
|
|
|
|
{
|
|
|
|
me->verrno = errno;
|
|
|
|
goto error_4;
|
|
|
|
}
|
|
|
|
|
2016-08-17 14:34:37 +03:00
|
|
|
fh = s->fh_new != NULL ? s->fh_new (ino, FALSE) : vfs_s_new_fh (ino, FALSE);
|
|
|
|
|
|
|
|
if (s->linear_start (me, fh, 0) == 0)
|
2010-11-08 13:21:45 +03:00
|
|
|
goto error_3;
|
|
|
|
|
|
|
|
/* Clear the interrupt status */
|
|
|
|
tty_got_interrupt ();
|
|
|
|
tty_enable_interrupt_key ();
|
|
|
|
|
2016-08-17 14:34:37 +03:00
|
|
|
while ((n = s->linear_read (me, fh, buffer, sizeof (buffer))) != 0)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
|
|
|
int t;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
if (n < 0)
|
|
|
|
goto error_1;
|
|
|
|
|
|
|
|
total += n;
|
|
|
|
vfs_s_print_stats (me->name, _("Getting file"), ino->ent->name, total, stat_size);
|
|
|
|
|
|
|
|
if (tty_got_interrupt ())
|
|
|
|
goto error_1;
|
|
|
|
|
|
|
|
t = write (handle, buffer, n);
|
|
|
|
if (t != n)
|
|
|
|
{
|
|
|
|
if (t == -1)
|
|
|
|
me->verrno = errno;
|
|
|
|
goto error_1;
|
|
|
|
}
|
|
|
|
}
|
2016-08-17 14:34:37 +03:00
|
|
|
s->linear_close (me, fh);
|
2010-11-08 13:21:45 +03:00
|
|
|
close (handle);
|
|
|
|
|
|
|
|
tty_disable_interrupt_key ();
|
2016-08-17 14:34:37 +03:00
|
|
|
vfs_s_free_fh (s, fh);
|
2010-11-08 13:21:45 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_1:
|
2016-08-17 14:34:37 +03:00
|
|
|
s->linear_close (me, fh);
|
2010-11-08 13:21:45 +03:00
|
|
|
error_3:
|
|
|
|
tty_disable_interrupt_key ();
|
|
|
|
close (handle);
|
|
|
|
unlink (ino->localname);
|
|
|
|
error_4:
|
2014-08-05 11:18:30 +04:00
|
|
|
MC_PTR_FREE (ino->localname);
|
2016-08-17 14:34:37 +03:00
|
|
|
if (fh != NULL)
|
|
|
|
vfs_s_free_fh (s, fh);
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/* ----------------------------- Stamping support -------------------------- */
|
|
|
|
|
|
|
|
/* Initialize one of our subclasses - fill common functions */
|
|
|
|
void
|
2018-09-14 13:24:17 +03:00
|
|
|
vfs_init_class (struct vfs_class *vclass, const char *name, vfs_flags_t flags, const char *prefix)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2018-09-14 13:24:17 +03:00
|
|
|
memset (vclass, 0, sizeof (struct vfs_class));
|
|
|
|
|
|
|
|
vclass->name = name;
|
|
|
|
vclass->flags = flags;
|
|
|
|
vclass->prefix = prefix;
|
2016-08-17 11:27:57 +03:00
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
vclass->fill_names = vfs_s_fill_names;
|
|
|
|
vclass->open = vfs_s_open;
|
|
|
|
vclass->close = vfs_s_close;
|
|
|
|
vclass->read = vfs_s_read;
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((vclass->flags & VFSF_READONLY) == 0)
|
2010-11-08 13:21:45 +03:00
|
|
|
vclass->write = vfs_s_write;
|
|
|
|
vclass->opendir = vfs_s_opendir;
|
|
|
|
vclass->readdir = vfs_s_readdir;
|
|
|
|
vclass->closedir = vfs_s_closedir;
|
|
|
|
vclass->stat = vfs_s_stat;
|
|
|
|
vclass->lstat = vfs_s_lstat;
|
|
|
|
vclass->fstat = vfs_s_fstat;
|
|
|
|
vclass->readlink = vfs_s_readlink;
|
|
|
|
vclass->chdir = vfs_s_chdir;
|
|
|
|
vclass->ferrno = vfs_s_ferrno;
|
|
|
|
vclass->lseek = vfs_s_lseek;
|
|
|
|
vclass->getid = vfs_s_getid;
|
|
|
|
vclass->nothingisopen = vfs_s_nothingisopen;
|
|
|
|
vclass->free = vfs_s_free;
|
2018-09-14 13:24:17 +03:00
|
|
|
vclass->setctl = vfs_s_setctl;
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((vclass->flags & VFSF_USETMP) != 0)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
|
|
|
vclass->getlocalcopy = vfs_s_getlocalcopy;
|
|
|
|
vclass->ungetlocalcopy = vfs_s_ungetlocalcopy;
|
|
|
|
}
|
2018-09-14 13:24:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
vfs_init_subclass (struct vfs_s_subclass *sub, const char *name, vfs_flags_t flags,
|
|
|
|
const char *prefix)
|
|
|
|
{
|
|
|
|
struct vfs_class *vclass = VFS_CLASS (sub);
|
|
|
|
size_t len;
|
|
|
|
char *start;
|
|
|
|
|
|
|
|
vfs_init_class (vclass, name, flags, prefix);
|
|
|
|
|
|
|
|
len = sizeof (struct vfs_s_subclass) - sizeof (struct vfs_class);
|
|
|
|
start = (char *) sub + sizeof (struct vfs_class);
|
|
|
|
memset (start, 0, len);
|
|
|
|
|
2019-11-18 21:24:13 +03:00
|
|
|
if ((vclass->flags & VFSF_USETMP) != 0)
|
2018-09-14 13:24:17 +03:00
|
|
|
sub->find_entry = vfs_s_find_entry_linear;
|
2019-11-18 21:24:13 +03:00
|
|
|
else if ((vclass->flags & VFSF_REMOTE) != 0)
|
2011-07-23 14:25:00 +04:00
|
|
|
sub->find_entry = vfs_s_find_entry_linear;
|
2010-11-08 13:21:45 +03:00
|
|
|
else
|
|
|
|
sub->find_entry = vfs_s_find_entry_tree;
|
|
|
|
sub->dir_uptodate = vfs_s_dir_uptodate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/** Find VFS id for given directory name */
|
|
|
|
|
|
|
|
vfsid
|
2024-06-01 21:12:14 +03:00
|
|
|
vfs_getid (const vfs_path_t *vpath)
|
2010-11-08 13:21:45 +03:00
|
|
|
{
|
2023-07-16 11:18:59 +03:00
|
|
|
const struct vfs_class *me;
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
me = vfs_path_get_last_path_vfs (vpath);
|
|
|
|
if (me == NULL || me->getid == NULL)
|
2011-04-21 14:27:56 +04:00
|
|
|
return NULL;
|
2010-11-08 13:21:45 +03:00
|
|
|
|
2023-07-16 11:18:59 +03:00
|
|
|
return me->getid (vpath);
|
2010-11-08 13:21:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/* ----------- Utility functions for networked filesystems -------------- */
|
|
|
|
|
|
|
|
#ifdef ENABLE_VFS_NET
|
|
|
|
int
|
|
|
|
vfs_s_select_on_two (int fd1, int fd2)
|
|
|
|
{
|
2024-09-12 10:15:43 +03:00
|
|
|
struct timeval time_out = {
|
|
|
|
.tv_sec = 1,
|
|
|
|
.tv_usec = 0
|
|
|
|
};
|
2010-11-08 13:21:45 +03:00
|
|
|
fd_set set;
|
2024-09-12 10:15:43 +03:00
|
|
|
int maxfd;
|
2010-11-08 13:21:45 +03:00
|
|
|
int v;
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2024-09-12 10:15:43 +03:00
|
|
|
maxfd = MAX (fd1, fd2) + 1;
|
|
|
|
|
1999-01-18 02:10:05 +03:00
|
|
|
FD_ZERO (&set);
|
|
|
|
FD_SET (fd1, &set);
|
|
|
|
FD_SET (fd2, &set);
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2010-02-02 13:48:08 +03:00
|
|
|
v = select (maxfd, &set, 0, 0, &time_out);
|
1998-11-21 22:36:01 +03:00
|
|
|
if (v <= 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
return v;
|
1998-11-21 22:36:01 +03:00
|
|
|
if (FD_ISSET (fd1, &set))
|
2010-03-30 12:10:25 +04:00
|
|
|
return 1;
|
1998-11-21 22:36:01 +03:00
|
|
|
if (FD_ISSET (fd2, &set))
|
2010-03-30 12:10:25 +04:00
|
|
|
return 2;
|
2018-01-08 11:20:55 +03:00
|
|
|
return (-1);
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1998-11-21 22:36:01 +03:00
|
|
|
int
|
2003-10-12 04:24:00 +04:00
|
|
|
vfs_s_get_line (struct vfs_class *me, int sock, char *buf, int buf_len, char term)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2019-05-20 07:50:09 +03:00
|
|
|
FILE *logfile = me->logfile;
|
2005-08-16 01:25:02 +04:00
|
|
|
int i;
|
1998-11-21 22:36:01 +03:00
|
|
|
char c;
|
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
for (i = 0; i < buf_len - 1; i++, buf++)
|
|
|
|
{
|
|
|
|
if (read (sock, buf, sizeof (char)) <= 0)
|
|
|
|
return 0;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
|
|
|
if (logfile != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-12-29 01:53:09 +03:00
|
|
|
size_t ret1;
|
|
|
|
int ret2;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2009-12-29 01:53:09 +03:00
|
|
|
ret1 = fwrite (buf, 1, 1, logfile);
|
|
|
|
ret2 = fflush (logfile);
|
2013-01-17 16:21:35 +04:00
|
|
|
(void) ret1;
|
|
|
|
(void) ret2;
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
if (*buf == term)
|
|
|
|
{
|
2018-01-08 11:20:55 +03:00
|
|
|
*buf = '\0';
|
2010-03-30 12:10:25 +04:00
|
|
|
return 1;
|
|
|
|
}
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
2002-08-20 05:08:34 +04:00
|
|
|
|
|
|
|
/* Line is too long - terminate buffer and discard the rest of line */
|
2018-01-08 11:20:55 +03:00
|
|
|
*buf = '\0';
|
2010-03-30 12:10:25 +04:00
|
|
|
while (read (sock, &c, sizeof (c)) > 0)
|
|
|
|
{
|
2018-01-08 11:20:55 +03:00
|
|
|
if (logfile != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2012-07-18 09:41:00 +04:00
|
|
|
size_t ret1;
|
|
|
|
int ret2;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2012-07-18 09:41:00 +04:00
|
|
|
ret1 = fwrite (&c, 1, 1, logfile);
|
|
|
|
ret2 = fflush (logfile);
|
2013-01-17 16:21:35 +04:00
|
|
|
(void) ret1;
|
|
|
|
(void) ret2;
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
|
|
|
if (c == '\n')
|
|
|
|
return 1;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-08 13:21:45 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1998-11-21 22:36:01 +03:00
|
|
|
int
|
2003-10-12 04:24:00 +04:00
|
|
|
vfs_s_get_line_interruptible (struct vfs_class *me, char *buffer, int size, int fd)
|
1998-11-21 22:36:01 +03:00
|
|
|
{
|
2000-01-31 16:48:00 +03:00
|
|
|
int i;
|
2014-04-20 18:03:07 +04:00
|
|
|
int res = 0;
|
1998-11-21 22:36:01 +03:00
|
|
|
|
2005-02-22 21:35:22 +03:00
|
|
|
(void) me;
|
|
|
|
|
2009-05-19 17:42:37 +04:00
|
|
|
tty_enable_interrupt_key ();
|
2014-04-20 18:03:07 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
for (i = 0; i < size - 1; i++)
|
|
|
|
{
|
2014-04-20 18:03:07 +04:00
|
|
|
ssize_t n;
|
2013-10-15 10:34:04 +04:00
|
|
|
|
2014-04-20 18:03:07 +04:00
|
|
|
n = read (fd, &buffer[i], 1);
|
2010-03-30 12:10:25 +04:00
|
|
|
if (n == -1 && errno == EINTR)
|
|
|
|
{
|
2014-04-20 18:03:07 +04:00
|
|
|
buffer[i] = '\0';
|
|
|
|
res = EINTR;
|
|
|
|
goto ret;
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
|
|
|
if (n == 0)
|
|
|
|
{
|
2014-04-20 18:03:07 +04:00
|
|
|
buffer[i] = '\0';
|
|
|
|
goto ret;
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
|
|
|
if (buffer[i] == '\n')
|
|
|
|
{
|
2014-04-20 18:03:07 +04:00
|
|
|
buffer[i] = '\0';
|
|
|
|
res = 1;
|
|
|
|
goto ret;
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
2014-04-20 18:03:07 +04:00
|
|
|
|
|
|
|
buffer[size - 1] = '\0';
|
|
|
|
|
|
|
|
ret:
|
|
|
|
tty_disable_interrupt_key ();
|
|
|
|
|
|
|
|
return res;
|
1998-11-21 22:36:01 +03:00
|
|
|
}
|
2010-07-18 12:42:28 +04:00
|
|
|
#endif /* ENABLE_VFS_NET */
|
2010-11-08 13:21:45 +03:00
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2011-06-24 22:09:12 +04:00
|
|
|
/**
|
|
|
|
* Normalize filenames start position
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2011-08-27 21:22:41 +04:00
|
|
|
vfs_s_normalize_filename_leading_spaces (struct vfs_s_inode *root_inode, size_t final_num_spaces)
|
2011-06-24 22:09:12 +04:00
|
|
|
{
|
|
|
|
GList *iter;
|
|
|
|
|
2015-01-16 10:56:08 +03:00
|
|
|
for (iter = g_queue_peek_head_link (root_inode->subdir); iter != NULL;
|
|
|
|
iter = g_list_next (iter))
|
2011-06-24 22:09:12 +04:00
|
|
|
{
|
2018-03-02 15:02:55 +03:00
|
|
|
struct vfs_s_entry *entry = VFS_ENTRY (iter->data);
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2022-06-18 09:30:25 +03:00
|
|
|
if ((size_t) entry->leading_spaces > final_num_spaces)
|
2011-06-24 22:09:12 +04:00
|
|
|
{
|
2015-01-16 10:36:08 +03:00
|
|
|
char *source_name, *spacer;
|
2018-01-08 11:20:55 +03:00
|
|
|
|
2015-01-16 10:36:08 +03:00
|
|
|
source_name = entry->name;
|
2022-06-18 09:30:25 +03:00
|
|
|
spacer = g_strnfill ((size_t) entry->leading_spaces - final_num_spaces, ' ');
|
2015-01-16 10:36:08 +03:00
|
|
|
entry->name = g_strconcat (spacer, source_name, (char *) NULL);
|
2011-06-24 22:09:12 +04:00
|
|
|
g_free (spacer);
|
|
|
|
g_free (source_name);
|
|
|
|
}
|
2015-01-16 10:36:08 +03:00
|
|
|
|
2022-06-18 09:30:25 +03:00
|
|
|
entry->leading_spaces = -1;
|
2011-06-24 22:09:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|