Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package seadrive-fuse for openSUSE:Factory checked in at 2026-08-04 23:28:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/seadrive-fuse (Old) and /work/SRC/openSUSE:Factory/.seadrive-fuse.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "seadrive-fuse" Tue Aug 4 23:28:30 2026 rev:12 rq:1369443 version:3.0.24 Changes: -------- --- /work/SRC/openSUSE:Factory/seadrive-fuse/seadrive-fuse.changes 2026-06-08 14:28:24.384739166 +0200 +++ /work/SRC/openSUSE:Factory/.seadrive-fuse.new.16738/seadrive-fuse.changes 2026-08-04 23:28:33.782097302 +0200 @@ -1,0 +2,12 @@ +Tue Aug 4 08:32:21 UTC 2026 - Paolo Stivanin <[email protected]> + +- update to 3.0.24: + * Skip lock file when flock is not implemented (#40) + * fuse-ops.c: populate st_blocks (#41) + * Use queue to update mount path xattr (#38) + * Set proxy to websockets (#42) + * Fix set ca path error (#43) +- add lws-socks5.patch: only use the lws SOCKS5 proxy fields when + libwebsockets is built with LWS_WITH_SOCKS5. + +------------------------------------------------------------------- Old: ---- seadrive-fuse-3.0.23.tar.gz New: ---- lws-socks5.patch seadrive-fuse-3.0.24.tar.gz ----------(New B)---------- New: * Fix set ca path error (#43) - add lws-socks5.patch: only use the lws SOCKS5 proxy fields when libwebsockets is built with LWS_WITH_SOCKS5. ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ seadrive-fuse.spec ++++++ --- /var/tmp/diff_new_pack.uqSrkn/_old 2026-08-04 23:28:34.746131391 +0200 +++ /var/tmp/diff_new_pack.uqSrkn/_new 2026-08-04 23:28:34.746131391 +0200 @@ -17,13 +17,14 @@ Name: seadrive-fuse -Version: 3.0.23 +Version: 3.0.24 Release: 0 Summary: SeaDrive daemon with FUSE interface License: GPL-2.0-only URL: https://github.com/haiwen/seadrive-fuse/ Source0: https://github.com/haiwen/seadrive-fuse/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz Patch0: fuse3.patch +Patch1: lws-socks5.patch BuildRequires: argon2-devel BuildRequires: autoconf BuildRequires: automake ++++++ fuse3.patch ++++++ --- /var/tmp/diff_new_pack.uqSrkn/_old 2026-08-04 23:28:34.778132523 +0200 +++ /var/tmp/diff_new_pack.uqSrkn/_new 2026-08-04 23:28:34.782132665 +0200 @@ -4,10 +4,10 @@ Port to fuse3 -Index: seadrive-fuse-3.0.21/README.md +Index: seadrive-fuse-3.0.24/README.md =================================================================== ---- seadrive-fuse-3.0.21.orig/README.md -+++ seadrive-fuse-3.0.21/README.md +--- seadrive-fuse-3.0.24.orig/README.md ++++ seadrive-fuse-3.0.24/README.md @@ -4,7 +4,7 @@ SeaDrive daemon with FUSE interface # Building ## Ubuntu Linux @@ -17,10 +17,10 @@ ``` First, you shoud get the latest source of [libsearpc](https://github.com/haiwen/libsearpc) with `v3.2-latest` tag and [seadrive-fuse](https://github.com/haiwen/seadrive-fuse). -Index: seadrive-fuse-3.0.21/configure.ac +Index: seadrive-fuse-3.0.24/configure.ac =================================================================== ---- seadrive-fuse-3.0.21.orig/configure.ac -+++ seadrive-fuse-3.0.21/configure.ac +--- seadrive-fuse-3.0.24.orig/configure.ac ++++ seadrive-fuse-3.0.24/configure.ac @@ -154,7 +154,7 @@ GLIB_REQUIRED=2.16.0 SEARPC_REQUIRED=1.0 JANSSON_REQUIRED=2.2.1 @@ -39,10 +39,10 @@ AC_SUBST(FUSE_CFLAGS) AC_SUBST(FUSE_LIBS) fi -Index: seadrive-fuse-3.0.21/src/fuse-ops.c +Index: seadrive-fuse-3.0.24/src/fuse-ops.c =================================================================== ---- seadrive-fuse-3.0.21.orig/src/fuse-ops.c -+++ seadrive-fuse-3.0.21/src/fuse-ops.c +--- seadrive-fuse-3.0.24.orig/src/fuse-ops.c ++++ seadrive-fuse-3.0.24/src/fuse-ops.c @@ -2,8 +2,8 @@ #if defined __linux__ || defined __APPLE__ @@ -74,7 +74,7 @@ FusePathComps comps; int ret = 0; uid_t uid; -@@ -441,7 +442,7 @@ readdir_root_accounts (void *buf, fuse_f +@@ -446,7 +447,7 @@ readdir_root_accounts (void *buf, fuse_f } for (ptr = accounts; ptr; ptr = ptr->next) { account = ptr->data; @@ -83,7 +83,7 @@ } g_list_free_full (accounts, (GDestroyNotify)seaf_account_free); -@@ -462,10 +463,10 @@ readdir_root (AccountInfo *account, void +@@ -467,10 +468,10 @@ readdir_root (AccountInfo *account, void type_str = ptr->data; #ifdef __APPLE__ dname_nfd = g_utf8_normalize (type_str, -1, G_NORMALIZE_NFD); @@ -96,7 +96,7 @@ #endif } -@@ -501,10 +502,10 @@ readdir_category (AccountInfo *account, +@@ -506,10 +507,10 @@ readdir_category (AccountInfo *account, dname = g_path_get_basename (info->display_name); #ifdef __APPLE__ dname_nfd = g_utf8_normalize (dname, -1, G_NORMALIZE_NFD); @@ -109,7 +109,7 @@ #endif g_free (dname); -@@ -553,7 +554,7 @@ readdir_repo (const char *repo_id, const +@@ -558,7 +559,7 @@ readdir_repo (const char *repo_id, const if (seaf_repo_manager_is_path_invisible (seaf->repo_mgr, repo_id, dname)) { continue; } @@ -118,7 +118,7 @@ } g_hash_table_destroy (dirents); -@@ -565,8 +566,10 @@ out: +@@ -570,8 +571,10 @@ out: int seadrive_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, @@ -130,7 +130,7 @@ FusePathComps comps; int ret = 0; -@@ -575,8 +578,8 @@ seadrive_fuse_readdir(const char *path, +@@ -580,8 +583,8 @@ seadrive_fuse_readdir(const char *path, if (!seaf->started) return 0; @@ -141,7 +141,7 @@ memset (&comps, 0, sizeof(comps)); -@@ -1228,8 +1231,11 @@ out: +@@ -1233,8 +1236,11 @@ out: return ret; } @@ -154,7 +154,7 @@ FusePathComps comps1, comps2; int ret = 0; -@@ -1559,8 +1565,9 @@ int seadrive_fuse_release (const char *p +@@ -1564,8 +1570,9 @@ int seadrive_fuse_release (const char *p } int @@ -165,7 +165,7 @@ FusePathComps comps; char *repo_id, *file_path; FileCacheStat st; -@@ -1700,8 +1707,9 @@ seadrive_fuse_statfs (const char *path, +@@ -1705,8 +1712,9 @@ seadrive_fuse_statfs (const char *path, } int @@ -176,7 +176,7 @@ RepoTreeStat tree_st; char *repo_id = NULL, *file_path = NULL; SeafRepo *repo = NULL; -@@ -1766,8 +1774,9 @@ out: +@@ -1776,8 +1784,9 @@ out: } int @@ -187,10 +187,10 @@ RepoTreeStat tree_st; char *repo_id = NULL, *file_path = NULL; SeafRepo *repo = NULL; -Index: seadrive-fuse-3.0.21/src/fuse-ops.h +Index: seadrive-fuse-3.0.24/src/fuse-ops.h =================================================================== ---- seadrive-fuse-3.0.21.orig/src/fuse-ops.h -+++ seadrive-fuse-3.0.21/src/fuse-ops.h +--- seadrive-fuse-3.0.24.orig/src/fuse-ops.h ++++ seadrive-fuse-3.0.24/src/fuse-ops.h @@ -3,13 +3,17 @@ #if defined __linux__ || defined __APPLE__ @@ -238,10 +238,10 @@ int seadrive_fuse_symlink (const char *from, const char *to); -Index: seadrive-fuse-3.0.21/src/seadrive.c +Index: seadrive-fuse-3.0.24/src/seadrive.c =================================================================== ---- seadrive-fuse-3.0.21.orig/src/seadrive.c -+++ seadrive-fuse-3.0.21/src/seadrive.c +--- seadrive-fuse-3.0.24.orig/src/seadrive.c ++++ seadrive-fuse-3.0.24/src/seadrive.c @@ -41,9 +41,9 @@ static void print_version () #include <fcntl.h> #include <sys/file.h> ++++++ lws-socks5.patch ++++++ Author: Paolo Stivanin <[email protected]> Subject: Only use the lws SOCKS5 proxy fields when libwebsockets provides them struct lws_context_creation_info only has the socks_proxy_address and socks_proxy_port members when libwebsockets is built with LWS_WITH_SOCKS5. openSUSE's libwebsockets is built without it, so compilation fails with: notif-mgr.c:901:22: error: 'struct lws_context_creation_info' has no member named 'socks_proxy_address'; did you mean 'ss_proxy_address'? Guard the SOCKS branch with the macro (defined by the installed lws_config.h, which libwebsockets.h includes) and warn at runtime instead. The HTTP proxy branch is unaffected. Index: seadrive-fuse-3.0.24/src/notif-mgr.c =================================================================== --- seadrive-fuse-3.0.24.orig/src/notif-mgr.c +++ seadrive-fuse-3.0.24/src/notif-mgr.c @@ -896,12 +896,17 @@ lws_context_new (gboolean use_ssl) info.http_proxy_port = has_auth ? 0 : (seaf->http_proxy_port > 0 ? seaf->http_proxy_port : 80); } else if (g_strcmp0 (seaf->http_proxy_type, PROXY_TYPE_SOCKS) == 0) { +#if defined(LWS_WITH_SOCKS5) if (seaf->http_proxy_port >= 0) { socks_proxy_addr = has_auth ? build_proxy_address (1080) : g_strdup (seaf->http_proxy_addr); info.socks_proxy_address = socks_proxy_addr; info.socks_proxy_port = has_auth ? 0 : (seaf->http_proxy_port > 0 ? seaf->http_proxy_port : 1080); } +#else + seaf_warning ("libwebsockets was built without SOCKS5 support, " + "not using SOCKS proxy for notifications.\n"); +#endif } } ++++++ seadrive-fuse-3.0.23.tar.gz -> seadrive-fuse-3.0.24.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/configure.ac new/seadrive-fuse-3.0.24/configure.ac --- old/seadrive-fuse-3.0.23/configure.ac 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/configure.ac 2026-07-29 05:48:24.000000000 +0200 @@ -2,7 +2,7 @@ AC_PREREQ(2.61) -AC_INIT([seadrive], [3.0.23], [[email protected]]) +AC_INIT([seadrive], [3.0.24], [[email protected]]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/debian/changelog new/seadrive-fuse-3.0.24/debian/changelog --- old/seadrive-fuse-3.0.23/debian/changelog 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/debian/changelog 2026-07-29 05:48:24.000000000 +0200 @@ -1,3 +1,9 @@ +seadrive-daemon (3.0.24) unstable; urgency=low + + * new upstream release + + -- Jonathan Xu <[email protected]> Wed, 29 Jul 2026 10:30:00 +0800 + seadrive-daemon (3.0.23) unstable; urgency=low * new upstream release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/fuse-ops.c new/seadrive-fuse-3.0.24/src/fuse-ops.c --- old/seadrive-fuse-3.0.23/src/fuse-ops.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/fuse-ops.c 2026-07-29 05:48:24.000000000 +0200 @@ -362,6 +362,7 @@ stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; stbuf->st_size = 4096; + stbuf->st_blocks = 8; stbuf->st_uid = uid; stbuf->st_gid = gid; if (comps.multi_account && comps.account_info) @@ -372,6 +373,7 @@ stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; stbuf->st_size = 4096; + stbuf->st_blocks = 8; stbuf->st_uid = uid; stbuf->st_gid = gid; stbuf->st_mtime = get_category_dir_mtime (comps.account_info->server, comps.account_info->username, comps.repo_type); @@ -380,6 +382,7 @@ stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; stbuf->st_size = 4096; + stbuf->st_blocks = 8; stbuf->st_mtime = comps.repo_info->mtime; stbuf->st_uid = uid; stbuf->st_gid = gid; @@ -404,12 +407,14 @@ comps.repo_path)); if (S_ISDIR(st.mode)) { stbuf->st_size = 4096; + stbuf->st_blocks = 8; if (is_writable) stbuf->st_mode = S_IFDIR | 0755; else stbuf->st_mode = S_IFDIR | 0555; } else { stbuf->st_size = st.size; + stbuf->st_blocks = (st.size + 511) / 512; if (is_writable) stbuf->st_mode = S_IFREG | 0644; else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/http-tx-mgr.c new/seadrive-fuse-3.0.24/src/http-tx-mgr.c --- old/seadrive-fuse-3.0.23/src/http-tx-mgr.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/http-tx-mgr.c 2026-07-29 05:48:24.000000000 +0200 @@ -385,30 +385,14 @@ #ifndef USE_GPL_CRYPTO -char *ca_paths[] = { - "/etc/ssl/certs/ca-certificates.crt", - "/etc/ssl/certs/ca-bundle.crt", - "/etc/pki/tls/certs/ca-bundle.crt", - "/usr/share/ssl/certs/ca-bundle.crt", - "/usr/local/share/certs/ca-root-nss.crt", - "/etc/ssl/cert.pem", -}; - static void load_ca_bundle(CURL *curl) { const char *env_ca_path = seaf->http_tx_mgr->priv->env_ca_bundle_path; int i; const char *ca_path; - gboolean found = FALSE; - for (i = 0; i < sizeof(ca_paths) / sizeof(ca_paths[0]); i++) { - ca_path = ca_paths[i]; - if (seaf_util_exists (ca_path)) { - found = TRUE; - break; - } - } + ca_path = load_ca_bundle_path (); if (env_ca_path) { if (seaf_util_exists (env_ca_path)) { @@ -417,7 +401,7 @@ } } - if (found) + if (ca_path) curl_easy_setopt (curl, CURLOPT_CAINFO, ca_path); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/notif-mgr.c new/seadrive-fuse-3.0.24/src/notif-mgr.c --- old/seadrive-fuse-3.0.23/src/notif-mgr.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/notif-mgr.c 2026-07-29 05:48:24.000000000 +0200 @@ -6,6 +6,7 @@ #include <glib.h> #include "seafile-session.h" +#include "seafile-config.h" #include "notif-mgr.h" #include "sync-mgr.h" @@ -19,7 +20,6 @@ #define STATUS_DISCONNECTED 0 #define STATUS_CONNECTED 1 #define STATUS_ERROR 2 -#define STATUS_CANCELLED 3 typedef struct NotifServer { struct lws_context *context; @@ -28,8 +28,7 @@ // status of the notification server. int status; - // whether to close the connection to the server. - gboolean close; + gboolean reconnect; GHashTable *subscriptions; pthread_mutex_t sub_lock; @@ -47,6 +46,8 @@ struct _SeafNotifManagerPriv { pthread_mutex_t server_lock; GHashTable *servers; + + char *ca_bundle_path; }; // The Message structure is used to send messages to the server. @@ -97,6 +98,17 @@ mgr->priv->servers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + const char *ca_path = NULL; +#ifndef USE_GPL_CRYPTO + ca_path = load_ca_bundle_path (); +#endif + const char *env_ca_path = g_getenv("SEAFILE_SSL_CA_PATH"); + if (env_ca_path && seaf_util_exists (env_ca_path)) { + mgr->priv->ca_bundle_path = g_strdup (env_ca_path); + } else if (ca_path) { + mgr->priv->ca_bundle_path = g_strdup (ca_path); + } + return mgr; } @@ -158,13 +170,62 @@ notif_server_ref (NotifServer *server); static struct lws_context * -lws_context_new (int port); +lws_context_new (gboolean use_ssl); + +static void +init_client_connect_info (NotifServer *server); + +static gboolean +proxy_has_auth (void) +{ + return seaf->http_proxy_username && seaf->http_proxy_password && + seaf->http_proxy_username[0] != '\0' && + seaf->http_proxy_password[0] != '\0'; +} + +static char * +build_proxy_address (int default_port) +{ + char *escaped_user = NULL; + char *escaped_pass = NULL; + char *proxy = NULL; + int port = seaf->http_proxy_port > 0 ? seaf->http_proxy_port : default_port; + + escaped_user = g_uri_escape_string (seaf->http_proxy_username, NULL, FALSE); + escaped_pass = g_uri_escape_string (seaf->http_proxy_password, NULL, FALSE); + proxy = g_strdup_printf ("%s:%s@%s:%d", + escaped_user, + escaped_pass, + seaf->http_proxy_addr, + port); + g_free (escaped_user); + g_free (escaped_pass); + + return proxy; +} + +static int +reset_lws_context (NotifServer *server) +{ + if (server->context) { + lws_context_destroy (server->context); + server->context = NULL; + } + + server->wsi = NULL; + + server->context = lws_context_new (server->use_ssl); + if (!server->context) + return -1; + + init_client_connect_info (server); + return 0; +} static NotifServer* notif_new_server (const char *server_url, gboolean use_notif_server_port) { NotifServer *server = NULL; - static struct lws_context *context; URI *uri = NULL; int port = NOTIF_PORT; gboolean use_ssl = FALSE; @@ -186,20 +247,10 @@ } - context = lws_context_new (use_ssl); - if (!context) { - g_free (uri->scheme); - g_free (uri->host); - g_free (uri); - seaf_warning ("failed to create libwebsockets context\n"); - return NULL; - } - server = g_new0 (NotifServer, 1); server->messages = g_async_queue_new (); - server->context = context; server->server_url = g_strdup (server_url); server->addr = g_strdup (uri->host); server->use_ssl = use_ssl; @@ -225,6 +276,10 @@ { NotifServer *server = NULL; + if (!url) { + return NULL; + } + pthread_mutex_lock (&mgr->priv->server_lock); server = g_hash_table_lookup (mgr->priv->servers, url); if (!server) { @@ -277,9 +332,6 @@ notif_server_free (server); } -static void -init_client_connect_info (NotifServer *server); - static void * notification_worker (void *vdata); @@ -305,8 +357,6 @@ if (!server) return; - init_client_connect_info (server); - rc = pthread_create (&tid, NULL, notification_worker, server); if (rc != 0) { seaf_warning ("Failed to create event notification new thread: %s.\n", strerror(rc)); @@ -321,12 +371,30 @@ return; } -static void -disconnect_server (NotifServer *server) +void +seaf_notif_manager_reconnect_servers (SeafNotifManager *mgr) { - // lws_cancel_service will produce a cancel event to break out of lws_service loop. - lws_cancel_service (server->context); - server->close = TRUE; + GHashTableIter iter; + gpointer key, value; + + if (!mgr->priv) + return; + + pthread_mutex_lock (&mgr->priv->server_lock); + g_hash_table_iter_init (&iter, mgr->priv->servers); + while (g_hash_table_iter_next (&iter, &key, &value)) { + NotifServer *server = value; + + if (!server || !server->context) + continue; + + server->reconnect = TRUE; + + // Call lws_cancel_service() to wake up lws_service() and make it process events immediately. + if (server->context) + lws_cancel_service (server->context); + } + pthread_mutex_unlock (&mgr->priv->server_lock); } // This policy will send a ping packet to the server per second. @@ -382,6 +450,7 @@ switch (reason) { case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: { + // this callback happens when a client handshake is being compiled. unsigned char **p = (unsigned char **)in, *end = (*p) + len; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_USER_AGENT, @@ -390,15 +459,24 @@ break; } case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + // the request client connection has been unable to complete a handshake with the remote server. server->status = STATUS_ERROR; seaf_debug ("websocket connection error: %s\n", in ? (char *)in : "(null)"); ret = -1; break; case LWS_CALLBACK_CLIENT_RECEIVE: + // data has appeared from the server for the client connection. handle_messages (in, len); break; case LWS_CALLBACK_CLIENT_WRITEABLE: + // If it already was able to take another packet without blocking, + // you'll get this callback at the next call to the service loop function. + + // Return -1 to close the current connection and exit lws_service loop. + if (server->reconnect) { + return -1; + } msg = g_async_queue_try_pop (server->messages); if (!msg) { break; @@ -417,22 +495,21 @@ notif_message_free (msg); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: + // after your client connection completed the websocket upgrade handshake with the remote server. seaf_sync_manager_check_locks_and_folder_perms (seaf->sync_mgr, server->server_url); server->status = STATUS_CONNECTED; - seaf_debug ("Successfully connected to the server: %s\n", server->server_url); + seaf_message ("Successfully connected to the server: %s\n", server->server_url); break; case LWS_CALLBACK_CLIENT_CLOSED: + // when a client websocket session ends. ret = -1; server->status = STATUS_ERROR; + server->wsi = NULL; // When the client is closed, cancel the context to prevent the socket from blocking in poll after the operating system wakes from sleep. // After calling lws_cancel_service, a LWS_CALLBACK_EVENT_WAIT_CANCELLED callback is sent to every protocol on every vhost, - // notification_worker will exit loop. + // lws_service() will return. lws_cancel_service (server->context); break; - case LWS_CALLBACK_EVENT_WAIT_CANCELLED: - ret = -1; - server->status = STATUS_CANCELLED; - break; default: break; } @@ -797,6 +874,11 @@ { struct lws_context_creation_info info; struct lws_context *context = NULL; + char *http_proxy_addr = NULL; + char *socks_proxy_addr = NULL; + gboolean has_auth = proxy_has_auth (); + + SeafNotifManagerPriv *priv = seaf->notif_mgr->priv; memset(&info, 0, sizeof info); info.port = CONTEXT_PORT_NO_LISTEN; @@ -806,20 +888,38 @@ // have to use the default allocations for fd tables up to ulimit -n. // It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we will use. info.fd_limit_per_thread = 1 + 1 + 1; - char *ca_path = g_build_filename (seaf->seaf_dir, "ca-bundle.pem", NULL); + + if (seaf->use_http_proxy && seaf->http_proxy_type && seaf->http_proxy_addr) { + if (g_strcmp0 (seaf->http_proxy_type, PROXY_TYPE_HTTP) == 0) { + http_proxy_addr = has_auth ? build_proxy_address (80) : g_strdup (seaf->http_proxy_addr); + info.http_proxy_address = http_proxy_addr; + info.http_proxy_port = has_auth ? 0 : + (seaf->http_proxy_port > 0 ? seaf->http_proxy_port : 80); + } else if (g_strcmp0 (seaf->http_proxy_type, PROXY_TYPE_SOCKS) == 0) { + if (seaf->http_proxy_port >= 0) { + socks_proxy_addr = has_auth ? build_proxy_address (1080) : g_strdup (seaf->http_proxy_addr); + info.socks_proxy_address = socks_proxy_addr; + info.socks_proxy_port = has_auth ? 0 : + (seaf->http_proxy_port > 0 ? seaf->http_proxy_port : 1080); + } + } + } + if (use_ssl) { info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; - info.client_ssl_ca_filepath = ca_path; + info.client_ssl_ca_filepath = priv->ca_bundle_path; } context = lws_create_context(&info); if (!context) { - g_free (ca_path); + g_free (http_proxy_addr); + g_free (socks_proxy_addr); seaf_warning ("failed to create libwebsockets context\n"); return NULL; } - g_free (ca_path); + g_free (http_proxy_addr); + g_free (socks_proxy_addr); return context; } @@ -871,21 +971,31 @@ struct lws_client_connect_info *i = &server->i; int n = 0; - while (!server->close) { + while (1) { + if (reset_lws_context (server) < 0) { + g_usleep (RECONNECT_INTERVAL * G_USEC_PER_SEC); + server->status = STATUS_DISCONNECTED; + continue; + } + // We don't need to check the return value of this function, the connection will be processed in the event loop. lws_client_connect_via_info(i); - while (n >= 0 && !server->close && - server->status != STATUS_ERROR && - server->status != STATUS_CANCELLED) { - n = lws_service(server->context, 0); + while (n >= 0 && server->status != STATUS_ERROR) { + // Wait for events for up to 1000 ms, lws_service() will return when the timeout expires. + n = lws_service(server->context, 1000); } delete_subscribed_repos (server); delete_unsent_messages (server); - if (server->status == STATUS_CANCELLED) - break; + if (server->reconnect) { + server->reconnect = FALSE; + n = 0; + server->status = STATUS_DISCONNECTED; + seaf_message ("Reconnecting to the notification server: %s.\n", server->server_url); + continue; + } // Wait a minute to reconnect to the notification server. seaf_sleep (RECONNECT_INTERVAL); @@ -893,12 +1003,6 @@ server->status = STATUS_DISCONNECTED; } - seaf_message ("Notification worker for server %s exiting.\n", server->server_url); - pthread_mutex_lock (&seaf->notif_mgr->priv->server_lock); - g_hash_table_remove (seaf->notif_mgr->priv->servers, server->server_url); - pthread_mutex_unlock (&seaf->notif_mgr->priv->server_lock); - notif_server_unref (server); - return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/notif-mgr.h new/seadrive-fuse-3.0.24/src/notif-mgr.h --- old/seadrive-fuse-3.0.23/src/notif-mgr.h 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/notif-mgr.h 2026-07-29 05:48:24.000000000 +0200 @@ -21,6 +21,9 @@ gboolean use_notif_server_port); void +seaf_notif_manager_reconnect_servers (SeafNotifManager *mgr); + +void seaf_notif_manager_subscribe_repo (SeafNotifManager *mgr, SeafRepo *repo); void diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/seadrive.c new/seadrive-fuse-3.0.24/src/seadrive.c --- old/seadrive-fuse-3.0.23/src/seadrive.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/seadrive.c 2026-07-29 05:48:24.000000000 +0200 @@ -383,7 +383,7 @@ return -1; } - if (flock (fd, LOCK_EX | LOCK_NB) < 0) { + if (flock (fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS) { seaf_warning ("Failed to lock pidfile %s: %s\n", pidfile, strerror(errno)); close (fd); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/seafile-config.c new/seadrive-fuse-3.0.24/src/seafile-config.c --- old/seadrive-fuse-3.0.23/src/seafile-config.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/seafile-config.c 2026-07-29 05:48:24.000000000 +0200 @@ -148,8 +148,13 @@ if (g_strcmp0(key, KEY_USE_PROXY) == 0) { if (g_strcmp0(value, "true") == 0) session->use_http_proxy = TRUE; - else + else { session->use_http_proxy = FALSE; + // Disabling proxy completes with KEY_USE_PROXY=false, + // so reconnect notification server here to drop the old proxied connection. + if (session->notif_mgr) + seaf_notif_manager_reconnect_servers (session->notif_mgr); + } } if (g_strcmp0(key, KEY_PROXY_TYPE) == 0) { @@ -167,6 +172,10 @@ if (g_strcmp0(key, KEY_PROXY_PASSWORD) == 0) { session->http_proxy_password = g_strdup(value); + // The RPC caller updates proxy settings key by key and writes KEY_PROXY_PASSWORD last when proxy is enabled, + // so reconnect notifications here to pick up the complete new proxy settings. + if (session->notif_mgr) + seaf_notif_manager_reconnect_servers (session->notif_mgr); } if (g_strcmp0 (key, KEY_ENABLE_AUTO_LOCK) == 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/sync-mgr.c new/seadrive-fuse-3.0.24/src/sync-mgr.c --- old/seadrive-fuse-3.0.23/src/sync-mgr.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/sync-mgr.c 2026-07-29 05:48:24.000000000 +0200 @@ -184,6 +184,7 @@ struct SeafTimer *update_sync_status_timer; GHashTable *active_paths; pthread_mutex_t paths_lock; + GAsyncQueue *update_path_xattr_queue; GAsyncQueue *lock_file_job_queue; @@ -201,6 +202,14 @@ GHashTable *del_confirmation_tasks; }; +struct _UpdatePathXattrTask { + char *mount_path; + char *key; + char *value; + gsize size; +}; +typedef struct _UpdatePathXattrTask UpdatePathXattrTask; + struct _ActivePathsInfo { struct SyncStatusTree *syncing_tree; struct SyncStatusTree *synced_tree; @@ -1032,6 +1041,9 @@ static void active_paths_info_free (ActivePathsInfo *info); +static void * +update_path_xattr_worker (void *data); + SeafSyncManager* seaf_sync_manager_new (SeafileSession *seaf) { @@ -1093,6 +1105,7 @@ pthread_mutex_init (&mgr->priv->errors_lock, NULL); mgr->priv->cache_file_task_queue = g_async_queue_new (); + mgr->priv->update_path_xattr_queue = g_async_queue_new (); mgr->priv->auto_sync_enabled = TRUE; @@ -1161,6 +1174,7 @@ static void* check_space_usage_thread (void *data); static void* lock_file_worker (void *data); static void* cache_file_task_worker (void *data); +static void* update_path_xattr_worker (void *data); int seaf_sync_manager_start (SeafSyncManager *mgr) @@ -1198,6 +1212,11 @@ seaf_warning ("Failed to create cache file task worker thread: %s.\n", strerror(rc)); } + rc = pthread_create (&tid, &attr, update_path_xattr_worker, mgr->priv->update_path_xattr_queue); + if (rc != 0) { + seaf_warning ("Failed to create update path xattr worker thread: %s.\n", strerror(rc)); + } + return 0; } @@ -4510,6 +4529,62 @@ /* Path sync status. */ +static void +update_path_xattr_task_free (UpdatePathXattrTask *task) +{ + if (!task) + return; + + g_free (task->mount_path); + g_free (task->key); + g_free (task->value); + g_free (task); +} + +// Update mount-path xattrs asynchronously to avoid blocking sync status updates. +static void * +update_path_xattr_worker (void *data) +{ + GAsyncQueue *queue = data; + UpdatePathXattrTask *task; + + while (1) { + task = g_async_queue_pop (queue); + if (!task) + break; + + seaf_setxattr (task->mount_path, task->key, task->value, task->size); + update_path_xattr_task_free (task); + } + + return NULL; +} + +// seadrive-fuse updates xattrs to notify Nautilus to refresh file sync status. +// Such xattr updates are triggered during file download and file upload. +// When downloading a file, the fuse read callback function will block waiting for the file from being cached. +// The file fetch worker tries to update xattr for the file (via mount path) when it fetches a file, which in turn calls into seadrive-fuse. +// Fuse dosesn't seem to allow concurrent operations on the same file path. So the fuse call to update xattr is in turn waiting for fuse read to finish, +// which causes deadlock between the tow fuse calls. +// Moving the xattr update fuse calls out of the file fetch worker code path will avoid the deadlock. So it's executed asynchronously. +static void +update_path_xattr (SeafSyncManager *mgr, + char *mount_path, + const char *key, + const char *value, + gsize size) +{ + UpdatePathXattrTask *task = NULL; + + task = g_new0 (UpdatePathXattrTask, 1); + task->mount_path = g_strdup (mount_path); + task->key = g_strdup (key); + task->value = g_strdup (value); + task->size = size; + + g_async_queue_push (mgr->priv->update_path_xattr_queue, task); +} + static ActivePathsInfo * active_paths_info_new (SeafRepo *repo) { @@ -4579,9 +4654,9 @@ if (mount_path) { if (status == SYNC_STATUS_SYNCING) - seaf_setxattr (mount_path, "user.seafile-status", "syncing", 8); + update_path_xattr (mgr, mount_path, "user.seafile-status", "syncing", 8); else - seaf_setxattr (mount_path, "user.seafile-status", "cached", 7); + update_path_xattr (mgr, mount_path, "user.seafile-status", "cached", 7); } seaf_repo_unref (repo); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/utils.c new/seadrive-fuse-3.0.24/src/utils.c --- old/seadrive-fuse-3.0.23/src/utils.c 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/utils.c 2026-07-29 05:48:24.000000000 +0200 @@ -774,3 +774,28 @@ return g_strndup (server_addr, sep - server_addr); } } + +char *ca_paths[] = { + "/etc/ssl/certs/ca-certificates.crt", + "/etc/ssl/certs/ca-bundle.crt", + "/etc/pki/tls/certs/ca-bundle.crt", + "/usr/share/ssl/certs/ca-bundle.crt", + "/usr/local/share/certs/ca-root-nss.crt", + "/etc/ssl/cert.pem", +}; + +const char * +load_ca_bundle_path () +{ + int i; + const char *ca_path = NULL; + + for (i = 0; i < sizeof(ca_paths) / sizeof(ca_paths[0]); i++) { + ca_path = ca_paths[i]; + if (seaf_util_exists (ca_path)) { + return ca_path; + } + } + + return NULL; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seadrive-fuse-3.0.23/src/utils.h new/seadrive-fuse-3.0.24/src/utils.h --- old/seadrive-fuse-3.0.23/src/utils.h 2026-06-04 04:55:24.000000000 +0200 +++ new/seadrive-fuse-3.0.24/src/utils.h 2026-07-29 05:48:24.000000000 +0200 @@ -264,4 +264,7 @@ char * parse_fileserver_addr (const char *server_addr); + +const char * +load_ca_bundle_path (); #endif
