[packages/sshfs-fuse] add patches for memleak and missing stat in cached readdir; rel 2

atler atler at pld-linux.org
Mon Jun 17 15:36:00 CEST 2024


commit b2e7b15978917d7d8ef5d097a256275b183feb57
Author: Jan Palus <atler at pld-linux.org>
Date:   Mon Jun 17 15:33:50 2024 +0200

    add patches for memleak and missing stat in cached readdir; rel 2
    
    from:
    - https://github.com/libfuse/sshfs/pull/305
    - https://github.com/libfuse/sshfs/pull/306

 readlink-memleak.patch       |  21 +++++++
 sshfs-fuse.spec              |   6 +-
 stat-in-cached-readdir.patch | 146 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 172 insertions(+), 1 deletion(-)
---
diff --git a/sshfs-fuse.spec b/sshfs-fuse.spec
index 787c235..0748b5d 100644
--- a/sshfs-fuse.spec
+++ b/sshfs-fuse.spec
@@ -2,12 +2,14 @@ Summary:	Filesystem based on the SSH File Transfer Protocol
 Summary(pl.UTF-8):	System plików oparty na protokole SSH File Transfer Protocol
 Name:		sshfs-fuse
 Version:	3.7.3
-Release:	1
+Release:	2
 License:	GPL v2
 Group:		Applications/System
 #Source0Download: https://github.com/libfuse/sshfs/releases
 Source0:	https://github.com/libfuse/sshfs/releases/download/sshfs-%{version}/sshfs-%{version}.tar.xz
 # Source0-md5:	f704f0d1800bdb5214030a1603e8c6d6
+Patch0:		readlink-memleak.patch
+Patch1:		stat-in-cached-readdir.patch
 URL:		https://github.com/libfuse/sshfs
 BuildRequires:	docutils
 BuildRequires:	glib2-devel >= 2.0
@@ -29,6 +31,8 @@ System plików oparty na protokole SSH File Transfer Protocol.
 
 %prep
 %setup -q -n sshfs-%{version}
+%patch0 -p1
+%patch1 -p1
 
 %build
 %meson build
diff --git a/readlink-memleak.patch b/readlink-memleak.patch
new file mode 100644
index 0000000..2c5278a
--- /dev/null
+++ b/readlink-memleak.patch
@@ -0,0 +1,21 @@
+From 8bb9d33d16f6004cc0420592b0dcf78571cdc746 Mon Sep 17 00:00:00 2001
+From: Jan Palus <jpalus at fastmail.com>
+Date: Mon, 17 Jun 2024 00:08:34 +0200
+Subject: [PATCH] Fix memleak in cache after readlink
+
+---
+ cache.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/cache.c b/cache.c
+index 9436c5a7..70dc35b4 100644
+--- a/cache.c
++++ b/cache.c
+@@ -67,6 +67,7 @@ static void free_node(gpointer node_)
+ {
+ 	struct node *node = (struct node *) node_;
+ 	g_strfreev(node->dir);
++	g_free(node->link);
+ 	g_free(node);
+ }
+ 
diff --git a/stat-in-cached-readdir.patch b/stat-in-cached-readdir.patch
new file mode 100644
index 0000000..f667a2f
--- /dev/null
+++ b/stat-in-cached-readdir.patch
@@ -0,0 +1,146 @@
+From 5f767dec5b3fc07f665fdd4fbd9eb728a790f35f Mon Sep 17 00:00:00 2001
+From: Jan Palus <jpalus at fastmail.com>
+Date: Mon, 17 Jun 2024 11:48:44 +0200
+Subject: [PATCH] Fill stat info when returning cached data for readdir
+
+Uncached and cached results for readdir were inconsistent -- the former
+returned correct stat info for directory entries while the latter
+didn't. That's because only names of entries were saved in cache without
+stat info. In turn this leads to issues like
+https://github.com/junegunn/fzf/issues/3832 since directory traversal
+library (https://github.com/charlievieth/fastwalk in this case) relies
+on proper stat info returned by readdir. Hence when unchached result was
+returned it gave proper outcome, while with cached result it was wrong.
+
+Cache stat info next to entry name to fix the issue. While file
+attributes are saved in cache already, they use full path as key. To
+avoid potentially plenty of allocations, string copying and cache
+lookups to get each attr, let's keep a copy of stat struct independently
+to be on the fast path.
+---
+ cache.c | 43 +++++++++++++++++++++++++++++++------------
+ 1 file changed, 31 insertions(+), 12 deletions(-)
+
+diff --git a/cache.c b/cache.c
+index 9436c5a7..c57829dc 100644
+--- a/cache.c
++++ b/cache.c
+@@ -14,6 +14,7 @@
+ #include <errno.h>
+ #include <glib.h>
+ #include <pthread.h>
++#include <sys/stat.h>
+ 
+ #define DEFAULT_CACHE_TIMEOUT_SECS 20
+ #define DEFAULT_MAX_CACHE_SIZE 10000
+@@ -40,7 +41,7 @@ static struct cache cache;
+ struct node {
+ 	struct stat stat;
+ 	time_t stat_valid;
+-	char **dir;
++	GPtrArray *dir;
+ 	time_t dir_valid;
+ 	char *link;
+ 	time_t link_valid;
+@@ -63,14 +64,28 @@ struct file_handle {
+ 	unsigned long fs_fh;
+ };
+ 
++struct cache_dirent {
++	char *name;
++	struct stat stat;
++};
++
+ static void free_node(gpointer node_)
+ {
+ 	struct node *node = (struct node *) node_;
+-	g_strfreev(node->dir);
++	if (node->dir != NULL)
++		g_ptr_array_free(node->dir, TRUE);
+ 	g_free(node->link);
+ 	g_free(node);
+ }
+ 
++static void free_cache_dirent(gpointer data) {
++	struct cache_dirent *cache_dirent = (struct cache_dirent *) data;
++	if (cache_dirent != NULL) {
++		g_free(cache_dirent->name);
++		g_free(cache_dirent);
++	}
++}
++
+ static int cache_clean_entry(void *key_, struct node *node, time_t *now)
+ {
+ 	(void) key_;
+@@ -186,13 +201,14 @@ void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr)
+ 	pthread_mutex_unlock(&cache.lock);
+ }
+ 
+-static void cache_add_dir(const char *path, char **dir)
++static void cache_add_dir(const char *path, GPtrArray *dir)
+ {
+ 	struct node *node;
+ 
+ 	pthread_mutex_lock(&cache.lock);
+ 	node = cache_get(path);
+-	g_strfreev(node->dir);
++	if (node->dir != NULL)
++		g_ptr_array_free(node->dir, TRUE);
+ 	node->dir = dir;
+ 	node->dir_valid = time(NULL) + cache.dir_timeout_secs;
+ 	if (node->dir_valid > node->valid)
+@@ -341,7 +357,10 @@ static int cache_dirfill (void *buf, const char *name,
+ 	ch = (struct readdir_handle*) buf;
+ 	err = ch->filler(ch->buf, name, stbuf, off, flags);
+ 	if (!err) {
+-		g_ptr_array_add(ch->dir, g_strdup(name));
++		struct cache_dirent *cdent = g_malloc(sizeof(struct cache_dirent));
++		cdent->name = g_strdup(name);
++		cdent->stat = *stbuf;
++		g_ptr_array_add(ch->dir, cdent);
+ 		if (stbuf->st_mode & S_IFMT) {
+ 			char *fullpath;
+ 			const char *basepath = !ch->path[1] ? "" : ch->path;
+@@ -361,8 +380,9 @@ static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ 	struct readdir_handle ch;
+ 	struct file_handle *cfi;
+ 	int err;
+-	char **dir;
++	GPtrArray *dir;
+ 	struct node *node;
++	struct cache_dirent **cdent;
+ 
+ 	assert(offset == 0);
+ 
+@@ -371,9 +391,8 @@ static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ 	if (node != NULL && node->dir != NULL) {
+ 		time_t now = time(NULL);
+ 		if (node->dir_valid - now >= 0) {
+-			for(dir = node->dir; *dir != NULL; dir++)
+-				// FIXME: What about st_mode?
+-				filler(buf, *dir, NULL, 0, 0);
++			for(cdent = (struct cache_dirent**)node->dir->pdata; *cdent != NULL; cdent++)
++				filler(buf, (*cdent)->name, &(*cdent)->stat, 0, 0);
+ 			pthread_mutex_unlock(&cache.lock);
+ 			return 0;
+ 		}
+@@ -397,16 +416,16 @@ static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ 	ch.buf = buf;
+ 	ch.filler = filler;
+ 	ch.dir = g_ptr_array_new();
++	g_ptr_array_set_free_func(ch.dir, free_cache_dirent);
+ 	ch.wrctr = cache_get_write_ctr();
+ 	err = cache.next_oper->readdir(path, &ch, cache_dirfill, offset, fi, flags);
+ 	g_ptr_array_add(ch.dir, NULL);
+-	dir = (char **) ch.dir->pdata;
++	dir = ch.dir;
+ 	if (!err) {
+ 		cache_add_dir(path, dir);
+ 	} else {
+-		g_strfreev(dir);
++		g_ptr_array_free(dir, TRUE);
+ 	}
+-	g_ptr_array_free(ch.dir, FALSE);
+ 
+ 	return err;
+ }
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/sshfs-fuse.git/commitdiff/b2e7b15978917d7d8ef5d097a256275b183feb57



More information about the pld-cvs-commit mailing list