1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-09-03 00:14:23 +00:00

Add verify blocks after sync (#715)

Co-authored-by: 杨赫然 <heran.yang@seafile.com>
This commit is contained in:
feiniks
2024-11-18 11:34:38 +08:00
committed by GitHub
parent 2cf6b99f40
commit 665d0083bd
4 changed files with 203 additions and 0 deletions

View File

@@ -152,6 +152,7 @@ load_http_config (HttpServerStruct *htp_server, SeafileSession *session)
int worker_threads;
char *encoding;
char *cluster_shared_temp_file_mode = NULL;
gboolean verify_client_blocks;
host = fileserver_config_get_string (session->config, HOST, &error);
if (!error) {
@@ -194,6 +195,18 @@ load_http_config (HttpServerStruct *htp_server, SeafileSession *session)
}
seaf_message ("fileserver: worker_threads = %d\n", htp_server->worker_threads);
verify_client_blocks = fileserver_config_get_boolean (session->config,
"verify_client_blocks_after_sync",
&error);
if (error) {
htp_server->verify_client_blocks = TRUE;
g_clear_error(&error);
} else {
htp_server->verify_client_blocks = verify_client_blocks;
}
seaf_message ("fileserver: verify_client_blocks = %d\n",
htp_server->verify_client_blocks);
cluster_shared_temp_file_mode = fileserver_config_get_string (session->config,
"cluster_shared_temp_file_mode",
&error);
@@ -1090,6 +1103,95 @@ out:
return ret;
}
typedef struct CheckBlockAux {
GList *file_list;
const char *store_id;
int version;
} CheckBlockAux;
static int
check_file_blocks (int n, const char *basedir, SeafDirent *files[], void *data)
{
Seafile *file = NULL;
char *block_id;
int i = 0;
SeafDirent *file1 = files[0];
SeafDirent *file2 = files[1];
CheckBlockAux *aux = (CheckBlockAux*)data;
if (!file2 || strcmp (file2->id, EMPTY_SHA1) == 0 || (file1 && strcmp (file1->id, file2->id) == 0)) {
return 0;
}
file = seaf_fs_manager_get_seafile (seaf->fs_mgr, aux->store_id, aux->version, file2->id);
if (!file) {
return -1;
}
for (i = 0; i < file->n_blocks; ++i) {
block_id = file->blk_sha1s[i];
if (!seaf_block_manager_block_exists (seaf->block_mgr, aux->store_id, aux->version, block_id)) {
aux->file_list = g_list_prepend (aux->file_list, g_strdup (file2->name));
goto out;
}
}
out:
seafile_unref (file);
return 0;
}
static int
check_dir_cb (int n, const char *basedir, SeafDirent *dirs[], void *data,
gboolean *recurse)
{
return 0;
}
static int
check_blocks (SeafRepo *repo, SeafCommit *base, SeafCommit *remote, char **ret_body) {
DiffOptions opts;
memset (&opts, 0, sizeof(opts));
memcpy (opts.store_id, repo->store_id, 36);
opts.version = repo->version;
opts.file_cb = check_file_blocks;
opts.dir_cb = check_dir_cb;
CheckBlockAux aux;
memset (&aux, 0, sizeof(aux));
aux.store_id = repo->store_id;
aux.version = repo->version;
opts.data = &aux;
const char *trees[2];
trees[0] = base->root_id;
trees[1] = remote->root_id;
if (diff_trees (2, trees, &opts) < 0) {
seaf_warning ("Failed to diff base and remote head for repo %.8s.\n",
repo->id);
return -1;
}
if (!aux.file_list) {
return 0;
}
json_t *obj_array = json_array ();
GList *ptr;
for (ptr = aux.file_list; ptr; ptr = ptr->next) {
json_array_append_new (obj_array, json_string (ptr->data));
g_free (ptr->data);
}
g_list_free (aux.file_list);
*ret_body = json_dumps (obj_array, JSON_COMPACT);
json_decref (obj_array);
return -1;
}
static void
put_update_branch_cb (evhtp_request_t *req, void *arg)
{
@@ -1154,6 +1256,19 @@ put_update_branch_cb (evhtp_request_t *req, void *arg)
token = get_auth_token (req);
if (seaf->http_server->verify_client_blocks) {
char *ret_body = NULL;
int rc = check_blocks(repo, base, new_commit, &ret_body);
if (rc < 0) {
if (ret_body) {
evbuffer_add (req->buffer_out, ret_body, strlen (ret_body));
}
evhtp_send_reply (req, SEAF_HTTP_RES_BLOCK_MISSING);
g_free (ret_body);
goto out;
}
}
if (fast_forward_or_merge (repo_id, base, new_commit, token) < 0) {
seaf_warning ("Fast forward merge for repo %s is failed.\n", repo_id);
evhtp_send_reply (req, EVHTP_RES_SERVERR);