Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package seafile for openSUSE:Factory checked 
in at 2022-11-09 12:56:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/seafile (Old)
 and      /work/SRC/openSUSE:Factory/.seafile.new.1597 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "seafile"

Wed Nov  9 12:56:45 2022 rev:14 rq:1034482 version:8.0.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/seafile/seafile.changes  2022-07-21 
11:35:12.143054746 +0200
+++ /work/SRC/openSUSE:Factory/.seafile.new.1597/seafile.changes        
2022-11-09 12:57:03.080217993 +0100
@@ -1,0 +2,7 @@
+Mon Nov  7 15:56:08 UTC 2022 - Paolo Stivanin <i...@paolostivanin.com>
+
+- Update to 8.0.9:
+  * Add confirmation when deleting more than 500 files.
+  * Don't create commit from index and don't write duplicate name cache to 
index.
+
+-------------------------------------------------------------------

Old:
----
  v8.0.8.tar.gz

New:
----
  v8.0.9.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ seafile.spec ++++++
--- /var/tmp/diff_new_pack.iQBLNg/_old  2022-11-09 12:57:03.832222233 +0100
+++ /var/tmp/diff_new_pack.iQBLNg/_new  2022-11-09 12:57:03.836222255 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           seafile
-Version:        8.0.8
+Version:        8.0.9
 Release:        0
 Summary:        Cloud storage client
 License:        GPL-2.0-only

++++++ v8.0.8.tar.gz -> v8.0.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/common/index/index.c 
new/seafile-8.0.9/common/index/index.c
--- old/seafile-8.0.8/common/index/index.c      2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/common/index/index.c      2022-10-30 03:54:58.000000000 
+0100
@@ -1974,6 +1974,7 @@
     struct cache_entry **cache = istate->cache;
     int entries = istate->cache_nr;
     SeafStat st;
+    const char *prev_name = NULL;
     int ret = 0;
 
     memset (&info, 0, sizeof(info));
@@ -2005,6 +2006,11 @@
         struct cache_entry *ce = cache[i];
         if (ce->ce_flags & CE_REMOVE)
             continue;
+        // skip duplicate cache.
+        if (prev_name && g_strcmp0 (ce->name, prev_name) ==0) {
+            continue;
+        }
+        prev_name = ce->name;
         /* if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) */
         /*     ce_smudge_racily_clean_entry(ce); */
         if (ce_write_entry2(&info, newfd, ce) < 0) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/common/log.c 
new/seafile-8.0.9/common/log.c
--- old/seafile-8.0.8/common/log.c      2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/common/log.c      2022-10-30 03:54:58.000000000 +0100
@@ -4,6 +4,7 @@
 
 #include <stdio.h>
 #include <glib/gstdio.h>
+#include <pthread.h>
 
 #ifndef WIN32
 #ifdef SEAFILE_SERVER
@@ -241,3 +242,57 @@
 {
     return logfp;
 }
+
+// seafile event log
+#define MAX_EVENT_LOG_SISE  300 * 1024 * 1024
+static FILE *eventfp;
+static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER;
+
+int
+seafile_event_log_init (const char *_logfile)
+{
+    char *eventfile = ccnet_expand_path(_logfile);
+    char *dirname;
+    char *eventfile_old;
+    SeafStat st;
+    
+    if (seaf_stat (eventfile, &st) >= 0) {
+        if (st.st_size >= MAX_EVENT_LOG_SISE) {
+            dirname = g_path_get_dirname (eventfile);
+            eventfile_old  = g_build_filename (dirname, "events-old.log", 
NULL);
+            seaf_util_rename (eventfile, eventfile_old);
+            g_free (dirname);
+            g_free (eventfile_old);
+        }
+    }
+
+    if ((eventfp = g_fopen (eventfile, "a+")) == NULL) {
+        g_free (eventfile);
+        seaf_message ("Failed to open event file %s\n", eventfile);
+        return -1;
+    }
+
+    g_free (eventfile);
+    return 0;
+}
+
+void 
+seafile_event_message(const char *message)
+{
+    time_t t;
+    struct tm *tm;
+    char buf[1024];
+    int len;
+
+    t = time(NULL);
+    tm = localtime(&t);
+    len = strftime (buf, 1024, "[%x %X] ", tm);
+    g_return_if_fail (len < 1024);
+    pthread_mutex_lock (&event_lock);
+    if (eventfp != NULL) {    
+        fputs (buf, eventfp);
+        fputs (message, eventfp);
+        fflush (eventfp);
+    }
+    pthread_mutex_unlock (&event_lock);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/common/log.h 
new/seafile-8.0.9/common/log.h
--- old/seafile-8.0.8/common/log.h      2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/common/log.h      2022-10-30 03:54:58.000000000 +0100
@@ -61,3 +61,9 @@
 #endif
 
 FILE *seafile_get_log_fp ();
+
+// seafile event log
+int
+seafile_event_log_init (const char *_logfile);
+
+void seafile_event_message (const char *msg);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/common/rpc-service.c 
new/seafile-8.0.9/common/rpc-service.c
--- old/seafile-8.0.8/common/rpc-service.c      2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/common/rpc-service.c      2022-10-30 03:54:58.000000000 
+0100
@@ -988,3 +988,9 @@
 {
     return g_strdup(sync_error_id_to_str (error_id));
 }
+
+int
+seafile_add_del_confirmation (const char *confirmation_id, int resync, GError 
**error)
+{
+    return seaf_sync_manager_add_del_confirmation (seaf->sync_mgr, 
confirmation_id, resync);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/configure.ac 
new/seafile-8.0.9/configure.ac
--- old/seafile-8.0.8/configure.ac      2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/configure.ac      2022-10-30 03:54:58.000000000 +0100
@@ -2,7 +2,7 @@
 
 
 AC_PREREQ(2.61)
-AC_INIT([seafile], [8.0.8], [i...@seafile.com])
+AC_INIT([seafile], [8.0.9], [i...@seafile.com])
 AC_CONFIG_HEADER([config.h])
 
 AC_CONFIG_MACRO_DIR([m4])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/repo-mgr.c 
new/seafile-8.0.9/daemon/repo-mgr.c
--- old/seafile-8.0.8/daemon/repo-mgr.c 2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/daemon/repo-mgr.c 2022-10-30 03:54:58.000000000 +0100
@@ -3752,7 +3752,7 @@
 static int
 apply_worktree_changes_to_index (SeafRepo *repo, struct index_state *istate,
                                  SeafileCrypt *crypt, GList *ignore_list,
-                                 LockedFileSet *fset)
+                                 LockedFileSet *fset, GList **event_list)
 {
     WTStatus *status;
     WTEvent *event, *next_event;
@@ -3794,6 +3794,9 @@
         if (!event)
             break;
 
+        WTEvent *copy = wt_event_new (event->ev_type, event->path, 
event->new_path);
+        *event_list = g_list_prepend (*event_list, copy);
+
         /* Scanned dirs list is used to avoid redundant scan of consecutive
            CREATE_OR_UPDATE events. When we see other events, we should
            clear the list. Otherwise in some cases we'll get wrong result.
@@ -3959,7 +3962,8 @@
 }
 
 static int
-index_add (SeafRepo *repo, struct index_state *istate, gboolean 
is_force_commit)
+index_add (SeafRepo *repo, struct index_state *istate,
+           gboolean is_force_commit, GList **event_list)
 {
     SeafileCrypt *crypt = NULL;
     LockedFileSet *fset = NULL;
@@ -3978,7 +3982,7 @@
     ignore_list = seaf_repo_load_ignore_files (repo->worktree);
 
     if (!is_force_commit) {
-        if (apply_worktree_changes_to_index (repo, istate, crypt, ignore_list, 
fset) < 0) {
+        if (apply_worktree_changes_to_index (repo, istate, crypt, ignore_list, 
fset, event_list) < 0) {
             seaf_warning ("Failed to apply worktree changes to index.\n");
             ret = -1;
         }
@@ -4074,6 +4078,48 @@
 }
 #endif
 
+static void
+print_event_log (const char *repo_name, const char *repo_id,
+                 const char *commit_id, GList *event_list)
+{
+    GList *ptr;
+    WTEvent *event;
+    char *name;
+    int i = 0;
+    GString *msg = g_string_new ("");
+
+    g_string_append_printf (msg, "%s %s %s\n", repo_name, repo_id, commit_id);
+
+    for (ptr = event_list; ptr; ptr = ptr->next) {
+        event = ptr->data;
+        i++;
+        switch (event->ev_type) {
+        case WT_EVENT_CREATE_OR_UPDATE:
+            name = "create/update";
+            break;
+        case WT_EVENT_SCAN_DIR:
+            name = "scan dir";
+            break;
+        case WT_EVENT_DELETE:
+            name = "delete";
+            break;
+        case WT_EVENT_RENAME:
+            name = "rename";
+            break;
+        case WT_EVENT_OVERFLOW:
+            name = "overflow";
+            break;
+        default:
+            name = "unknown";
+        }
+        g_string_append_printf (msg, "[event %d] %s, %s %s\n", i, name, 
event->path, event->new_path?event->new_path:"");
+    }
+
+    seafile_event_message (msg->str);
+
+    g_string_free (msg, TRUE);
+}
+
 char *
 seaf_repo_index_commit (SeafRepo *repo,
                         gboolean is_force_commit,
@@ -4090,6 +4136,7 @@
     GList *diff_results = NULL;
     char *desc = NULL;
     char *ret = NULL;
+    GList *event_list = NULL;
 
     if (!check_worktree_common (repo))
         return NULL;
@@ -4110,7 +4157,7 @@
 
     repo->changeset = changeset;
 
-    if (index_add (repo, &istate, is_force_commit) < 0) {
+    if (index_add (repo, &istate, is_force_commit, &event_list) < 0) {
         g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to add");
         goto out;
     }
@@ -4118,30 +4165,12 @@
     if (!istate.cache_changed)
         goto out;
 
-    if (!is_initial_commit && !is_force_commit) {
-        new_root_id = commit_tree_from_changeset (changeset);
-        if (!new_root_id) {
-            seaf_warning ("Create commit tree failed for repo %s\n", repo->id);
-            g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
-                         "Failed to generate commit");
-            goto out;
-        }
-    } else {
-        char hex[41];
-        struct cache_tree *it = cache_tree ();
-        if (cache_tree_update (repo->id, repo->version,
-                               repo->worktree,
-                               it, istate.cache,
-                               istate.cache_nr, 0, 0, commit_trees_cb) < 0) {
-            seaf_warning ("Failed to build cache tree");
-            g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL,
-                         "Internal data structure error");
-            cache_tree_free (&it);
-            goto out;
-        }
-        rawdata_to_hex (it->sha1, hex, 20);
-        new_root_id = g_strdup(hex);
-        cache_tree_free (&it);
+    new_root_id = commit_tree_from_changeset (changeset);
+    if (!new_root_id) {
+        seaf_warning ("Create commit tree failed for repo %s\n", repo->id);
+        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
+                     "Failed to generate commit");
+        goto out;
     }
 
     head = seaf_commit_manager_get_commit (seaf->commit_mgr,
@@ -4177,6 +4206,11 @@
         goto out;
     }
 
+    if (event_list) {
+        event_list = g_list_reverse (event_list);
+        print_event_log (repo->name, repo->id, commit_id, event_list);
+    }
+
     if (update_index (&istate, index_path) < 0) {
         g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "Internal 
error");
         goto out;
@@ -4187,6 +4221,9 @@
     ret = g_strdup(commit_id);
 
 out:
+    if (event_list) {
+        g_list_free_full (event_list, (GDestroyNotify)wt_event_free);
+    }
     g_free (desc);
     seaf_commit_unref (head);
     g_free (new_root_id);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/seaf-daemon.c 
new/seafile-8.0.9/daemon/seaf-daemon.c
--- old/seafile-8.0.8/daemon/seaf-daemon.c      2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/daemon/seaf-daemon.c      2022-10-30 03:54:58.000000000 
+0100
@@ -93,6 +93,11 @@
                                      searpc_signature_string__int());
 
     searpc_server_register_function ("seafile-rpcserver",
+                                     seafile_add_del_confirmation,
+                                     "seafile_add_del_confirmation",
+                                     searpc_signature_int__string_int());
+
+    searpc_server_register_function ("seafile-rpcserver",
                                      seafile_get_config,
                                      "seafile_get_config",
                                      searpc_signature_string__string());
@@ -389,6 +394,7 @@
     char *seafile_dir = NULL;
     char *worktree_dir = NULL;
     char *logfile = NULL;
+    char *eventfile = NULL;
     const char *debug_str = NULL;
     int daemon_mode = 0;
     char *ccnet_debug_level_str = "info";
@@ -496,6 +502,14 @@
         exit (1);
     }
 
+    eventfile = g_build_filename (config_dir, "logs", "events.log", NULL);
+    if (seafile_event_log_init (eventfile) < 0) {
+        seaf_warning ("Failed to init event log.\n");
+        exit (1);
+    }
+
+    seafile_event_message("Starting record seafile events.\n");
+
     /* init seafile */
     if (seafile_dir == NULL)
         seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
@@ -516,6 +530,7 @@
     g_free (seafile_dir);
     g_free (worktree_dir);
     g_free (logfile);
+    g_free (eventfile);
 
 #ifndef WIN32
     set_signal_handlers (seaf);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/seafile-config.c 
new/seafile-8.0.9/daemon/seafile-config.c
--- old/seafile-8.0.8/daemon/seafile-config.c   2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/daemon/seafile-config.c   2022-10-30 03:54:58.000000000 
+0100
@@ -168,6 +168,9 @@
     if (g_strcmp0(key, KEY_PROXY_PORT) == 0) {
         session->http_proxy_port = value;
     }
+    if (g_strcmp0(key, KEY_DELETE_CONFIRM_THRESHOLD) == 0) {
+        session->delete_confirm_threshold = value;
+    }
 
     return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/seafile-config.h 
new/seafile-8.0.9/daemon/seafile-config.h
--- old/seafile-8.0.8/daemon/seafile-config.h   2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/daemon/seafile-config.h   2022-10-30 03:54:58.000000000 
+0100
@@ -37,6 +37,7 @@
 #define KEY_PROXY_PASSWORD "proxy_password"
 #define PROXY_TYPE_HTTP "http"
 #define PROXY_TYPE_SOCKS "socks"
+#define KEY_DELETE_CONFIRM_THRESHOLD "delete_confirm_threshold"
 
 gboolean
 seafile_session_config_exists (SeafileSession *session, const char *key);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/seafile-error.c 
new/seafile-8.0.9/daemon/seafile-error.c
--- old/seafile-8.0.8/daemon/seafile-error.c    2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/daemon/seafile-error.c    2022-10-30 03:54:58.000000000 
+0100
@@ -174,6 +174,11 @@
         SYNC_ERROR_LEVEL_REPO,
         "Library is too large to sync"
     },
+    {
+        SYNC_ERROR_ID_DEL_CONFIRMATION_PENDING,
+        SYNC_ERROR_LEVEL_REPO,
+        "Waiting for confirmation to delete files"
+    },
 };
 
 const char *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/seafile-session.c 
new/seafile-8.0.9/daemon/seafile-session.c
--- old/seafile-8.0.8/daemon/seafile-session.c  2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/daemon/seafile-session.c  2022-10-30 03:54:58.000000000 
+0100
@@ -348,6 +348,8 @@
     g_key_file_free (key_file);
 }
 
+#define MAX_DELETED_FILES_NUM 500
+
 void
 seafile_session_prepare (SeafileSession *session)
 {
@@ -415,6 +417,10 @@
             seafile_session_config_get_string(session, KEY_PROXY_PASSWORD);
     }
 
+    session->delete_confirm_threshold = seafile_session_config_get_int 
(session, KEY_DELETE_CONFIRM_THRESHOLD, NULL);
+    if (session->delete_confirm_threshold <= 0)
+        session->delete_confirm_threshold = MAX_DELETED_FILES_NUM;
+
     int block_size = seafile_session_config_get_int(session, 
KEY_CDC_AVERAGE_BLOCK_SIZE, NULL);
     if (block_size >= 1024) {
         session->cdc_average_block_size = block_size;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/seafile-session.h 
new/seafile-8.0.9/daemon/seafile-session.h
--- old/seafile-8.0.8/daemon/seafile-session.h  2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/daemon/seafile-session.h  2022-10-30 03:54:58.000000000 
+0100
@@ -88,6 +88,7 @@
     int                  http_proxy_port;
     char                *http_proxy_username;
     char                *http_proxy_password;
+    int                 delete_confirm_threshold;
 };
 
 struct _SeafileSessionClass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/sync-mgr.c 
new/seafile-8.0.9/daemon/sync-mgr.c
--- old/seafile-8.0.8/daemon/sync-mgr.c 2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/daemon/sync-mgr.c 2022-10-30 03:54:58.000000000 +0100
@@ -15,6 +15,7 @@
 #include "vc-utils.h"
 
 #include "sync-status-tree.h"
+#include "diff-simple.h"
 
 #ifdef WIN32
 #include <shlobj.h>
@@ -62,6 +63,10 @@
 };
 typedef struct _HttpServerState HttpServerState;
 
+typedef struct DelConfirmationResult {
+    gboolean resync;
+} DelConfirmationResult;
+
 struct _SeafSyncManagerPriv {
     struct SeafTimer *check_sync_timer;
     struct SeafTimer *update_tx_state_timer;
@@ -77,6 +82,9 @@
     GAsyncQueue *refresh_paths;
     struct SeafTimer *refresh_windows_timer;
 #endif
+
+    pthread_mutex_t del_confirmation_lock;
+    GHashTable *del_confirmation_tasks;
 };
 
 struct _ActivePathsInfo {
@@ -165,6 +173,11 @@
     mgr->priv->refresh_paths = g_async_queue_new ();
 #endif
 
+    mgr->priv->del_confirmation_tasks = g_hash_table_new_full (g_str_hash, 
g_str_equal,
+                                                           g_free,
+                                                           g_free);
+    pthread_mutex_init (&mgr->priv->del_confirmation_lock, NULL);
+
     return mgr;
 }
 
@@ -970,6 +983,11 @@
     return res;
 }
 
+static char *
+exceed_max_deleted_files (SeafRepo *repo);
+static void
+notify_delete_confirmation (const char *repo_name, const char *desc, const 
char *confirmation_id);
+
 static void
 commit_job_done (void *vres)
 {
@@ -998,8 +1016,20 @@
         return;
     }
 
-    if (res->changed)
+    if (res->changed) {
+        char *desc = NULL;
+        desc = exceed_max_deleted_files (repo);
+        if (desc) {
+            notify_delete_confirmation (repo->name, desc, 
repo->head->commit_id);
+            seaf_warning ("Delete more than %d files, add delete 
confirmation.\n", seaf->delete_confirm_threshold);
+            task->info->del_confirmation_pending = TRUE;
+            set_task_error (res->task, SYNC_ERROR_ID_DEL_CONFIRMATION_PENDING);
+            g_free (desc);
+            g_free (res);
+            return;
+        }
         start_upload_if_necessary (res->task);
+    }
     else if (task->is_manual_sync || task->is_initial_commit)
         check_head_commit_http (task);
     else
@@ -1186,6 +1216,194 @@
     return ret;
 }
 
+#define MAX_DELETED_FILES_NUM 100
+
+inline static char *
+get_basename (char *path)
+{
+    char *slash;
+    slash = strrchr (path, '/');
+    if (!slash)
+        return path;
+    return (slash + 1);
+}
+
+static char *
+exceed_max_deleted_files (SeafRepo *repo)
+{
+    SeafBranch *master = NULL, *local = NULL;
+    SeafCommit *local_head = NULL, *master_head = NULL;
+    GList *diff_results = NULL;
+    char *deleted_file = NULL;
+    GString *desc = NULL;
+    char *ret = NULL;
+
+    local = seaf_branch_manager_get_branch (seaf->branch_mgr, repo->id, 
"local");
+    if (!local) {
+        seaf_warning ("No local branch found for repo %s(%.8s).\n",
+                      repo->name, repo->id);
+        goto out;
+    }
+
+    master = seaf_branch_manager_get_branch (seaf->branch_mgr, repo->id, 
"master");
+    if (!master) {
+        seaf_warning ("No master branch found for repo %s(%.8s).\n",
+                      repo->name, repo->id);
+        goto out;
+    }
+
+    local_head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, 
repo->version,
+                                                 local->commit_id);
+    if (!local_head) {
+        seaf_warning ("Failed to get head of local branch for repo %s.\n", 
repo->id);
+        goto out;
+    }
+
+    master_head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, 
repo->version,
+                                                  master->commit_id);
+    if (!master_head) {
+        seaf_warning ("Failed to get head of master branch for repo %s.\n", 
repo->id);
+        goto out;
+    }
+
+    diff_commit_roots (repo->id, repo->version, master_head->root_id, 
local_head->root_id, &diff_results, TRUE);
+    if (!diff_results) {
+        goto out;
+    }
+    GList *p;
+    DiffEntry *de;
+    int n_deleted = 0;
+
+    for (p = diff_results; p != NULL; p = p->next) {
+        de = p->data;
+        switch (de->status) {
+        case DIFF_STATUS_DELETED:
+            if (n_deleted == 0)
+                deleted_file = get_basename(de->name);
+            n_deleted++;
+            break;
+        }
+    }
+
+    if (n_deleted >= seaf->delete_confirm_threshold) {
+        desc = g_string_new ("");
+        g_string_append_printf (desc, "Deleted \"%s\" and %d more files.\n",
+                                deleted_file, n_deleted - 1);
+        ret = g_string_free (desc, FALSE);
+    }
+
+out:
+    seaf_branch_unref (local);
+    seaf_branch_unref (master);
+    seaf_commit_unref (local_head);
+    seaf_commit_unref (master_head);
+    g_list_free_full (diff_results, (GDestroyNotify)diff_entry_free);
+
+    return ret;
+}
+
+static void
+notify_delete_confirmation (const char *repo_name, const char *desc, const 
char *confirmation_id)
+{
+    json_t *obj = json_object ();
+    json_object_set_string_member (obj, "repo_name", repo_name);
+    json_object_set_string_member (obj, "delete_files", desc);
+    json_object_set_string_member (obj, "confirmation_id", confirmation_id);
+
+    char *msg = json_dumps (obj, JSON_COMPACT);
+
+    seaf_mq_manager_publish_notification (seaf->mq_mgr, 
"sync.del_confirmation", msg);
+
+    json_decref (obj);
+    g_free (msg);
+}
+
+int
+seaf_sync_manager_add_del_confirmation (SeafSyncManager *mgr,
+                                        const char *confirmation_id,
+                                        gboolean resync)
+{
+    SeafSyncManagerPriv *priv = seaf->sync_mgr->priv;
+    DelConfirmationResult *result = NULL;
+
+    result = g_new0 (DelConfirmationResult, 1);
+    result->resync = resync;
+
+    pthread_mutex_lock (&priv->del_confirmation_lock);
+    g_hash_table_insert (priv->del_confirmation_tasks, g_strdup 
(confirmation_id), result);
+    pthread_mutex_unlock (&priv->del_confirmation_lock);
+
+    return 0;
+}
+
+static DelConfirmationResult *
+get_del_confirmation_result (const char *confirmation_id)
+{
+    SeafSyncManagerPriv *priv = seaf->sync_mgr->priv;
+    DelConfirmationResult *result, *copy = NULL;
+
+
+    pthread_mutex_lock (&priv->del_confirmation_lock);
+    result = g_hash_table_lookup (priv->del_confirmation_tasks, 
confirmation_id);
+    if (result) {
+        copy = g_new0 (DelConfirmationResult, 1);
+        copy->resync = result->resync;
+        g_hash_table_remove (priv->del_confirmation_tasks, confirmation_id);
+    }
+    pthread_mutex_unlock (&priv->del_confirmation_lock);
+
+    return copy;
+}
+
+static void
+resync_repo (SeafRepo *repo)
+{
+    GError *error = NULL;
+    char *repo_id = g_strdup (repo->id);
+    int repo_version = repo->version;
+    char *repo_name = g_strdup (repo->name);
+    char *token = g_strdup (repo->token);
+    char *magic = g_strdup (repo->magic);
+    int enc_version = repo->enc_version;
+    char *random_key = g_strdup (repo->random_key);
+    char *worktree = g_strdup (repo->worktree);
+    char *email = g_strdup (repo->email);
+    char *more_info = NULL;
+    json_t *obj = json_object ();
+
+    json_object_set_int_member (obj, "is_readonly", repo->is_readonly);
+    json_object_set_string_member (obj, "repo_salt", repo->salt);
+    json_object_set_string_member (obj, "server_url", repo->server_url);
+
+    more_info = json_dumps (obj, 0);
+
+    if (repo->auto_sync && (repo->sync_interval == 0))
+        seaf_wt_monitor_unwatch_repo (seaf->wt_monitor, repo->id);
+
+    seaf_repo_manager_del_repo (seaf->repo_mgr, repo);
+
+    char *ret = seaf_clone_manager_add_task (seaf->clone_mgr, repo_id,
+                                             repo_version, repo_name,
+                                             token, NULL,
+                                             magic, enc_version,
+                                             random_key, worktree,
+                                             email, more_info, &error);
+    if (error) {
+        seaf_warning ("Failed to clone repo %s: %s\n", repo_id, 
error->message);
+        g_clear_error (&error);
+    }
+    g_free (ret);
+    g_free (repo_id);
+    g_free (repo_name);
+    g_free (token);
+    g_free (magic);
+    g_free (random_key);
+    g_free (worktree);
+    g_free (email);
+    json_decref (obj);
+    g_free (more_info);
+}
+
 static int
 sync_repo_v2 (SeafSyncManager *manager, SeafRepo *repo, gboolean 
is_manual_sync)
 {
@@ -1224,6 +1442,36 @@
     if (strcmp (master->commit_id, local->commit_id) != 0) {
         if (is_manual_sync || can_schedule_repo (manager, repo)) {
             task = create_sync_task_v2 (manager, repo, is_manual_sync, FALSE);
+            if (!task->info->del_confirmation_pending) {
+                char *desc = NULL;
+                desc = exceed_max_deleted_files (repo);
+                if (desc) {
+                    notify_delete_confirmation (repo->name, desc, 
local->commit_id);
+                    seaf_warning ("Delete more than %d files, add delete 
confirmation.\n", seaf->delete_confirm_threshold);
+                    task->info->del_confirmation_pending = TRUE;
+                    set_task_error (task, 
SYNC_ERROR_ID_DEL_CONFIRMATION_PENDING);
+                    g_free (desc);
+                    goto out;
+                }
+            } else {
+                DelConfirmationResult *result = get_del_confirmation_result 
(local->commit_id);
+                if (!result) {
+                    // User has not confirmed whether to continue syncing.
+                    set_task_error (task, 
SYNC_ERROR_ID_DEL_CONFIRMATION_PENDING);
+                    goto out;
+                } else if (result->resync) {
+                    // User chooses to resync.
+                    g_free (result);
+                    task->info->del_confirmation_pending = FALSE;
+                    set_task_error (task, 
SYNC_ERROR_ID_DEL_CONFIRMATION_PENDING);
+                    // Delete this repo and resync this repo by adding clone 
task.
+                    resync_repo (repo);
+                    goto out;
+                }
+                // User chooes to continue syncing.
+                g_free (result);
+                task->info->del_confirmation_pending = FALSE;
+            }
             start_upload_if_necessary (task);
         }
         /* Do nothing if the client still has something to upload
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/daemon/sync-mgr.h 
new/seafile-8.0.9/daemon/sync-mgr.h
--- old/seafile-8.0.8/daemon/sync-mgr.h 2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/daemon/sync-mgr.h 2022-10-30 03:54:58.000000000 +0100
@@ -35,6 +35,7 @@
     gboolean   end_multipart_upload;
 
     gint       sync_perm_err_cnt;
+    gboolean   del_confirmation_pending;
 };
 
 enum {
@@ -130,6 +131,11 @@
                                  const char *repo_id);
 
 int
+seaf_sync_manager_add_del_confirmation (SeafSyncManager *mgr,
+                                        const char *confirmation_id,
+                                        gboolean resync);
+
+int
 seaf_sync_manager_disable_auto_sync (SeafSyncManager *mgr);
 
 int
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/debian/changelog 
new/seafile-8.0.9/debian/changelog
--- old/seafile-8.0.8/debian/changelog  2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/debian/changelog  2022-10-30 03:54:58.000000000 +0100
@@ -1,16 +1,21 @@
+seafile-daemon (8.0.9) unstable; urgency=low
+
+  * new upstream release
+
+ -- Jonathan Xu <jonathan...@seafile.com>  Thu, 27 Oct  2022 11:35:08 +0800
 seafile-daemon (8.0.8) unstable; urgency=low
 
-  * new upstream relase
+  * new upstream release
 
  -- Jonathan Xu <jonathan...@seafile.com>  Thu, 30 Jun  2022 10:31:41 +0800
 seafile-daemon (8.0.7) unstable; urgency=low
 
-  * new upstream relase
+  * new upstream release
 
  -- Jonathan Xu <jonathan...@seafile.com>  Sun, 24 Apr  2022 10:34:42 +0800
 seafile-daemon (8.0.6) unstable; urgency=low
 
-  * new upstream relase
+  * new upstream release
 
  -- Jonathan Xu <jonathan...@seafile.com>  Wed, 23 Feb  2022 17:21:27 +0800
 seafile-daemon (8.0.5) unstable; urgency=low
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/include/seafile-error.h 
new/seafile-8.0.9/include/seafile-error.h
--- old/seafile-8.0.8/include/seafile-error.h   2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/include/seafile-error.h   2022-10-30 03:54:58.000000000 
+0100
@@ -62,6 +62,7 @@
 #define SYNC_ERROR_ID_REMOVE_UNCOMMITTED_FOLDER 30
 #define SYNC_ERROR_ID_INVALID_PATH_ON_WINDOWS   31
 #define SYNC_ERROR_ID_LIBRARY_TOO_LARGE         32
-#define N_SYNC_ERROR_ID                         33
+#define SYNC_ERROR_ID_DEL_CONFIRMATION_PENDING  33
+#define N_SYNC_ERROR_ID                         34
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/include/seafile-rpc.h 
new/seafile-8.0.9/include/seafile-rpc.h
--- old/seafile-8.0.8/include/seafile-rpc.h     2022-06-30 04:35:44.000000000 
+0200
+++ new/seafile-8.0.9/include/seafile-rpc.h     2022-10-30 03:54:58.000000000 
+0100
@@ -216,4 +216,7 @@
 
 char*
 seafile_sync_error_id_to_str (int error_id, GError **error);
+
+int
+seafile_add_del_confirmation (const char *confirmation_id, int resync, GError 
**error);
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/msi/Includes.wxi 
new/seafile-8.0.9/msi/Includes.wxi
--- old/seafile-8.0.8/msi/Includes.wxi  2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/msi/Includes.wxi  2022-10-30 03:54:58.000000000 +0100
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Include Id="SeafileInclude">
-  <?define CurrentSeafileVersion="8.0.8" ?>
+  <?define CurrentSeafileVersion="8.0.9" ?>
 
   <!-- Update Guid ????????? -->
   <?define CurrentUpdateGuid="65DED1C8-A5F1-4C49-8E7E-B0A8A5A6535C" ?>
@@ -151,7 +151,8 @@
   <!-- <?define ProductGuid="02E0FA9C-6C8A-4F87-924B-D33EF51EB9DE" ?> (8.0.5) 
-->
   <!-- <?define ProductGuid="7EB8EE37-06D5-4119-84B4-5369AAF20041" ?> (8.0.6) 
-->
   <!-- <?define ProductGuid="A1210D1B-4DE1-4A01-85DF-779BE1C10790" ?> (8.0.7) 
-->
-  <?define ProductGuid="B9B16F5B-BA57-4ABF-B9AC-F40C90D9C03D" ?>
+  <!-- <?define ProductGuid="B9B16F5B-BA57-4ABF-B9AC-F40C90D9C03D" ?> (8.0.8) 
-->
+  <?define ProductGuid="614CE64F-16AE-46B3-9A3F-AA8AD5FCB7A3" ?>
 
   <?define GuidOfCustomComponent="AD201805-3CBD-4834-9097-5D934F7E0000" ?>
   <?define GuidOfAutoStartComponent="AD201805-3CBD-4834-9097-5D934F7E0001" ?>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/python/seafile/rpcclient.py 
new/seafile-8.0.9/python/seafile/rpcclient.py
--- old/seafile-8.0.8/python/seafile/rpcclient.py       2022-06-30 
04:35:44.000000000 +0200
+++ new/seafile-8.0.9/python/seafile/rpcclient.py       2022-10-30 
03:54:58.000000000 +0100
@@ -211,3 +211,8 @@
     def seafile_shutdown():
         pass
     shutdown = seafile_shutdown
+
+    @searpc_func("int", ["string", "int"])
+    def seafile_add_del_confirmation(key, value):
+        pass
+    add_del_confirmation = seafile_add_del_confirmation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/seafile-8.0.8/seafile.vcxproj 
new/seafile-8.0.9/seafile.vcxproj
--- old/seafile-8.0.8/seafile.vcxproj   2022-06-30 04:35:44.000000000 +0200
+++ new/seafile-8.0.9/seafile.vcxproj   2022-10-30 03:54:58.000000000 +0100
@@ -92,7 +92,7 @@
       <WarningLevel>Level3</WarningLevel>
       <SDLCheck>
       </SDLCheck>
-      
<PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.8";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.9";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>false</ConformanceMode>
       <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
       
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir)common;$(ProjectDir)lib;$(ProjectDir)include;$(ProjectDir)daemon;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -110,7 +110,7 @@
       <WarningLevel>Level1</WarningLevel>
       <SDLCheck>
       </SDLCheck>
-      
<PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.8";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.9";%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>false</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
       
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir)common;$(ProjectDir)include;$(ProjectDir)daemon;$(ProjectDir)lib;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -131,7 +131,7 @@
       <IntrinsicFunctions>false</IntrinsicFunctions>
       <SDLCheck>
       </SDLCheck>
-      
<PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.8";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.9";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>false</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
       
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir);$(ProjectDir)daemon;$(ProjectDir)include;$(ProjectDir)lib;$(ProjectDir)common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -158,7 +158,7 @@
       <IntrinsicFunctions>false</IntrinsicFunctions>
       <SDLCheck>
       </SDLCheck>
-     
<PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.8";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;ENABLE_BREAKPAD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+     
<PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.9";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;ENABLE_BREAKPAD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>false</ConformanceMode>
       <LanguageStandard>stdcpp17</LanguageStandard>
       
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir);$(ProjectDir)common;$(ProjectDir)lib;$(ProjectDir)include;$(ProjectDir)daemon;$(ProjectDir)..\breakpad\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

Reply via email to