Ticket #4145: file names longer than 255 bytes are not supported.

Avoid limitation of file name length.

(vfs_dirent): redefined to use instead of standard "struct direct"
to hold file name of any length.
(vfs_class::readdir): return newly allocated vfs_dirent structure.
Related changes.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Andrew Borodin 2020-11-16 10:09:09 +03:00
parent 3566727870
commit 4c7223e9f2
16 changed files with 130 additions and 74 deletions

View File

@ -453,10 +453,10 @@ vfs_s_opendir (const vfs_path_t * vpath)
/* --------------------------------------------------------------------------------------------- */
static void *
static struct vfs_dirent *
vfs_s_readdir (void *data)
{
static union vfs_dirent dir;
struct vfs_dirent *dir = NULL;
struct dirhandle *info = (struct dirhandle *) data;
const char *name;
@ -465,13 +465,13 @@ vfs_s_readdir (void *data)
name = VFS_ENTRY (info->cur->data)->name;
if (name != NULL)
g_strlcpy (dir.dent.d_name, name, MC_MAXPATHLEN);
dir = vfs_dirent_init (NULL, name, 0);
else
vfs_die ("Null in structure-cannot happen");
info->cur = g_list_next (info->cur);
return (void *) &dir;
return dir;
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -62,12 +62,10 @@
/* TODO: move it to separate private .h */
extern GString *vfs_str_buffer;
extern vfs_class *current_vfs;
extern struct dirent *mc_readdir_result;
extern struct vfs_dirent *mc_readdir_result;
/*** global variables ****************************************************************************/
struct dirent *mc_readdir_result = NULL;
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
@ -458,30 +456,15 @@ mc_opendir (const vfs_path_t * vpath)
/* --------------------------------------------------------------------------------------------- */
struct dirent *
struct vfs_dirent *
mc_readdir (DIR * dirp)
{
int handle;
struct vfs_class *vfs;
void *fsinfo = NULL;
struct dirent *entry = NULL;
struct vfs_dirent *entry = NULL;
vfs_path_element_t *vfs_path_element;
if (mc_readdir_result == NULL)
{
/* 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 == NULL)
{
errno = EFAULT;
@ -507,8 +490,8 @@ mc_readdir (DIR * dirp)
#else
g_string_assign (vfs_str_buffer, entry->d_name);
#endif
mc_readdir_result->d_ino = entry->d_ino;
g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, MAXNAMLEN + 1);
vfs_dirent_assign (mc_readdir_result, vfs_str_buffer->str, entry->d_ino);
vfs_dirent_free (entry);
}
if (entry == NULL)
errno = vfs->readdir ? vfs_ferrno (vfs) : E_NOTSUPP;

View File

@ -69,13 +69,14 @@
#include "gc.h"
/* TODO: move it to the separate .h */
extern struct dirent *mc_readdir_result;
extern struct vfs_dirent *mc_readdir_result;
extern GPtrArray *vfs__classes_list;
extern GString *vfs_str_buffer;
extern vfs_class *current_vfs;
/*** global variables ****************************************************************************/
struct vfs_dirent *mc_readdir_result = NULL;
GPtrArray *vfs__classes_list = NULL;
GString *vfs_str_buffer = NULL;
vfs_class *current_vfs = NULL;
@ -469,6 +470,7 @@ vfs_init (void)
vfs_str_buffer = g_string_new ("");
mc_readdir_result = vfs_dirent_init (NULL, "", -1);
}
/* --------------------------------------------------------------------------------------------- */
@ -518,10 +520,70 @@ vfs_shut (void)
vfs_str_buffer = NULL;
current_vfs = NULL;
vfs_free_handle_list = -1;
MC_PTR_FREE (mc_readdir_result);
vfs_dirent_free (mc_readdir_result);
mc_readdir_result = NULL;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Init or create vfs_dirent structure
*
* @d vfs_dirent structure to init. If NULL, new structure is created.
* @fname file name
* @ino file inode number
*
* @return pointer to d if d isn't NULL, or pointer to newly created structure.
*/
struct vfs_dirent *
vfs_dirent_init (struct vfs_dirent *d, const char *fname, ino_t ino)
{
struct vfs_dirent *ret = d;
if (ret == NULL)
ret = g_new0 (struct vfs_dirent, 1);
if (ret->d_name_str == NULL)
ret->d_name_str = g_string_sized_new (MC_MAXFILENAMELEN);
vfs_dirent_assign (ret, fname, ino);
return ret;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Assign members of vfs_dirent structure
*
* @d vfs_dirent structure for assignment
* @fname file name
* @ino file inode number
*/
void
vfs_dirent_assign (struct vfs_dirent *d, const char *fname, ino_t ino)
{
g_string_assign (d->d_name_str, fname);
d->d_name = d->d_name_str->str;
d->d_ino = ino;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Destroy vfs_dirent structure
*
* @d vfs_dirent structure to destroy.
*/
void
vfs_dirent_free (struct vfs_dirent *d)
{
g_string_free (d->d_name_str, TRUE);
g_free (d);
}
/* --------------------------------------------------------------------------------------------- */
/**
* These ones grab information from the VFS
* and handles them to an upper layer

View File

@ -9,7 +9,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <dirent.h> /* DIR */
#ifdef HAVE_UTIMENSAT
#include <sys/time.h>
#elif defined (HAVE_UTIME_H)
@ -20,7 +20,6 @@
#include <stddef.h>
#include "lib/global.h"
#include "lib/fs.h" /* MC_MAXPATHLEN */
#include "path.h"
@ -172,7 +171,7 @@ typedef struct vfs_class
ssize_t (*write) (void *vfs_info, const char *buf, size_t count);
void *(*opendir) (const vfs_path_t * vpath);
void *(*readdir) (void *vfs_info);
struct vfs_dirent *(*readdir) (void *vfs_info);
int (*closedir) (void *vfs_info);
int (*stat) (const vfs_path_t * vpath, struct stat * buf);
@ -211,13 +210,17 @@ typedef struct vfs_class
} vfs_class;
/*
* This union is used to ensure that there is enough space for the
* filename (d_name) when the dirent structure is created.
* This struct is used instead of standard dirent to hold file name of any length
* (not limited to NAME_MAX).
*/
union vfs_dirent
struct vfs_dirent
{
struct dirent dent;
char _extra_buffer[offsetof (struct dirent, d_name) + MC_MAXPATHLEN + 1];
/* private */
GString *d_name_str;
/* public */
ino_t d_ino;
char *d_name; /* Alias of d_name_str->str */
};
/*** global variables defined in .c file *********************************************************/
@ -278,6 +281,10 @@ void vfs_stamp_path (const vfs_path_t * path);
void vfs_release_path (const vfs_path_t * vpath);
struct vfs_dirent *vfs_dirent_init (struct vfs_dirent *d, const char *fname, ino_t ino);
void vfs_dirent_assign (struct vfs_dirent *d, const char *fname, ino_t ino);
void vfs_dirent_free (struct vfs_dirent *d);
void vfs_fill_names (fill_names_f);
/* *INDENT-OFF* */
@ -309,7 +316,7 @@ int mc_readlink (const vfs_path_t * vpath, 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 vfs_path_t * vpath);
struct dirent *mc_readdir (DIR * dirp);
struct vfs_dirent *mc_readdir (DIR * dirp);
int mc_closedir (DIR * dir);
int mc_stat (const vfs_path_t * vpath, struct stat *buf);
int mc_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev);

View File

@ -139,7 +139,7 @@ filename_completion_function (const char *text, int state, input_complete_t flag
static vfs_path_t *dirname_vpath = NULL;
gboolean isdir = TRUE, isexec = FALSE;
struct dirent *entry = NULL;
struct vfs_dirent *entry = NULL;
SHOW_C_CTX ("filename_completion_function");

View File

@ -145,7 +145,7 @@ clean_sort_keys (dir_list * list, int start, int count)
*/
static gboolean
handle_dirent (struct dirent *dp, const char *fltr, struct stat *buf1, gboolean * link_to_dir,
handle_dirent (struct vfs_dirent *dp, const char *fltr, struct stat *buf1, gboolean * link_to_dir,
gboolean * stale_link)
{
vfs_path_t *vpath;
@ -624,7 +624,7 @@ dir_list_load (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort,
const dir_sort_options_t * sort_op, const char *fltr)
{
DIR *dirp;
struct dirent *dp;
struct vfs_dirent *dp;
struct stat st;
file_entry_t *fentry;
const char *vpath_str;
@ -697,7 +697,7 @@ dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort,
const dir_sort_options_t * sort_op, const char *fltr)
{
DIR *dirp;
struct dirent *dp;
struct vfs_dirent *dp;
int i;
struct stat st;
int marked_cnt;

View File

@ -624,7 +624,7 @@ do_compute_dir_size (const vfs_path_t * dirname_vpath, dirsize_status_msg_t * ds
int res;
struct stat s;
DIR *dir;
struct dirent *dirent;
struct vfs_dirent *dirent;
FileProgressStatus ret = FILE_CONT;
(*dir_count)++;
@ -1403,7 +1403,7 @@ try_erase_dir (file_op_context_t * ctx, const char *dir)
static FileProgressStatus
recursive_erase (file_op_total_context_t * tctx, file_op_context_t * ctx, const vfs_path_t * vpath)
{
struct dirent *next;
struct vfs_dirent *next;
DIR *reading;
const char *s;
FileProgressStatus return_status = FILE_CONT;
@ -1458,7 +1458,7 @@ static int
check_dir_is_empty (const vfs_path_t * vpath)
{
DIR *dir;
struct dirent *d;
struct vfs_dirent *d;
int i = 1;
dir = mc_opendir (vpath);
@ -2766,7 +2766,7 @@ FileProgressStatus
copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const char *s, const char *d,
gboolean toplevel, gboolean move_over, gboolean do_delete, GSList * parent_dirs)
{
struct dirent *next;
struct vfs_dirent *next;
struct stat dst_stat, src_stat;
DIR *reading;
FileProgressStatus return_status = FILE_CONT;

View File

@ -1247,7 +1247,7 @@ find_rotate_dash (const WDialog * h, gboolean show)
static int
do_search (WDialog * h)
{
static struct dirent *dp = NULL;
static struct vfs_dirent *dp = NULL;
static DIR *dirp = NULL;
static char *directory = NULL;
struct stat tmp_stat;

View File

@ -909,7 +909,7 @@ tree_store_rescan (const vfs_path_t * vpath)
dirp = mc_opendir (vpath);
if (dirp != NULL)
{
struct dirent *dp;
struct vfs_dirent *dp;
for (dp = mc_readdir (dirp); dp != NULL; dp = mc_readdir (dirp))
if (!DIR_IS_DOT (dp->d_name) && !DIR_IS_DOTDOT (dp->d_name))

View File

@ -1047,20 +1047,20 @@ extfs_opendir (const vfs_path_t * vpath)
/* --------------------------------------------------------------------------------------------- */
static void *
static struct vfs_dirent *
extfs_readdir (void *data)
{
static union vfs_dirent dir;
struct vfs_dirent *dir;
GList **info = (GList **) data;
if (*info == NULL)
return NULL;
g_strlcpy (dir.dent.d_name, VFS_ENTRY ((*info)->data)->name, MC_MAXPATHLEN);
dir = vfs_dirent_init (NULL, VFS_ENTRY ((*info)->data)->name, 0); /* FIXME: inode */
*info = g_list_next (*info);
return (void *) &dir;
return dir;
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -103,10 +103,14 @@ local_opendir (const vfs_path_t * vpath)
/* --------------------------------------------------------------------------------------------- */
static void *
static struct vfs_dirent *
local_readdir (void *data)
{
return readdir (*(DIR **) data);
struct dirent *d;
d = readdir (*(DIR **) data);
return (d != NULL ? vfs_dirent_init (NULL, d->d_name, d->d_ino) : NULL);
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -115,13 +115,12 @@ sftpfs_opendir (const vfs_path_t * vpath, GError ** mcerror)
* @return information about direntry if success, NULL otherwise
*/
void *
struct vfs_dirent *
sftpfs_readdir (void *data, GError ** mcerror)
{
char mem[BUF_MEDIUM];
LIBSSH2_SFTP_ATTRIBUTES attrs;
sftpfs_dir_data_t *sftpfs_dir = (sftpfs_dir_data_t *) data;
static union vfs_dirent sftpfs_dirent;
int rc;
mc_return_val_if_error (mcerror, NULL);
@ -137,11 +136,7 @@ sftpfs_readdir (void *data, GError ** mcerror)
}
while (rc == LIBSSH2_ERROR_EAGAIN);
if (rc == 0)
return NULL;
g_strlcpy (sftpfs_dirent.dent.d_name, mem, BUF_MEDIUM);
return &sftpfs_dirent;
return (rc != 0 ? vfs_dirent_init (NULL, mem, 0) : NULL); /* FIXME: inode */
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -91,7 +91,7 @@ void sftpfs_close_connection (struct vfs_s_super *super, const char *shutdown_me
vfs_file_handler_t *sftpfs_fh_new (struct vfs_s_inode *ino, gboolean changed);
void *sftpfs_opendir (const vfs_path_t * vpath, GError ** mcerror);
void *sftpfs_readdir (void *data, GError ** mcerror);
struct vfs_dirent *sftpfs_readdir (void *data, GError ** mcerror);
int sftpfs_closedir (void *data, GError ** mcerror);
int sftpfs_mkdir (const vfs_path_t * vpath, mode_t mode, GError ** mcerror);
int sftpfs_rmdir (const vfs_path_t * vpath, GError ** mcerror);

View File

@ -188,11 +188,11 @@ sftpfs_cb_opendir (const vfs_path_t * vpath)
* @return information about direntry if success, NULL otherwise
*/
static void *
static struct vfs_dirent *
sftpfs_cb_readdir (void *data)
{
GError *mcerror = NULL;
union vfs_dirent *sftpfs_dirent;
struct vfs_dirent *sftpfs_dirent;
if (tty_got_interrupt ())
{
@ -204,7 +204,7 @@ sftpfs_cb_readdir (void *data)
if (!mc_error_message (&mcerror, NULL))
{
if (sftpfs_dirent != NULL)
vfs_print_message (_("sftp: (Ctrl-G break) Listing... %s"), sftpfs_dirent->dent.d_name);
vfs_print_message (_("sftp: (Ctrl-G break) Listing... %s"), sftpfs_dirent->d_name);
else
vfs_print_message ("%s", _("sftp: Listing done."));
}

View File

@ -915,11 +915,10 @@ smbfs_free_dir (dir_entry * de)
/* It's too slow to ask the server each time */
/* It now also sends the complete lstat information for each file */
static void *
static struct vfs_dirent *
smbfs_readdir (void *info)
{
static union vfs_dirent smbfs_readdir_data;
static char *const dirent_dest = smbfs_readdir_data.dent.d_name;
struct vfs_dirent *dirent;
opendir_info *smbfs_info = (opendir_info *) info;
DEBUG (4, ("smbfs_readdir(%s)\n", smbfs_info->dirname));
@ -937,10 +936,12 @@ smbfs_readdir (void *info)
#endif
return NULL;
}
g_strlcpy (dirent_dest, smbfs_info->current->text, MC_MAXPATHLEN);
dirent = vfs_dirent_init (NULL, smbfs_info->current->text, 0); /* FIXME: inode */
smbfs_info->current = smbfs_info->current->next;
return &smbfs_readdir_data;
return dirent;
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -400,11 +400,10 @@ undelfs_opendir (const vfs_path_t * vpath)
/* --------------------------------------------------------------------------------------------- */
static void *
static struct vfs_dirent *
undelfs_readdir (void *vfs_info)
{
static union vfs_dirent undelfs_readdir_data;
static char *const dirent_dest = undelfs_readdir_data.dent.d_name;
struct vfs_dirent *dirent;
if (vfs_info != fs)
{
@ -414,13 +413,18 @@ undelfs_readdir (void *vfs_info)
if (readdir_ptr == num_delarray)
return NULL;
if (readdir_ptr < 0)
strcpy (dirent_dest, readdir_ptr == -2 ? "." : "..");
dirent = vfs_dirent_init (NULL, readdir_ptr == -2 ? "." : "..", 0); /* FIXME: inode */
else
{
char dirent_dest[MC_MAXPATHLEN];
g_snprintf (dirent_dest, MC_MAXPATHLEN, "%ld:%d",
(long) delarray[readdir_ptr].ino, delarray[readdir_ptr].num_blocks);
dirent = vfs_dirent_init (NULL, dirent_dest, 0); /* FIXME: inode */
}
readdir_ptr++;
return &undelfs_readdir_data;
return dirent;
}
/* --------------------------------------------------------------------------------------------- */