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>