mirror of
https://github.com/haiwen/seafile-server.git
synced 2025-06-28 07:56:52 +00:00
161 lines
4.3 KiB
C
161 lines
4.3 KiB
C
#include "seafile-session.h"
|
|
#include "log.h"
|
|
|
|
typedef struct VerifyData {
|
|
SeafRepo *repo;
|
|
gint64 truncate_time;
|
|
gboolean traversed_head;
|
|
} VerifyData;
|
|
|
|
static int
|
|
check_blocks (VerifyData *data, const char *file_id)
|
|
{
|
|
SeafRepo *repo = data->repo;
|
|
Seafile *seafile;
|
|
int i;
|
|
|
|
seafile = seaf_fs_manager_get_seafile (seaf->fs_mgr,
|
|
repo->store_id,
|
|
repo->version,
|
|
file_id);
|
|
if (!seafile) {
|
|
seaf_warning ("Failed to find file %s.\n", file_id);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < seafile->n_blocks; ++i) {
|
|
if (!seaf_block_manager_block_exists (seaf->block_mgr,
|
|
repo->store_id,
|
|
repo->version,
|
|
seafile->blk_sha1s[i]))
|
|
g_message ("Block %s is missing.\n", seafile->blk_sha1s[i]);
|
|
}
|
|
|
|
seafile_unref (seafile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gboolean
|
|
fs_callback (SeafFSManager *mgr,
|
|
const char *store_id,
|
|
int version,
|
|
const char *obj_id,
|
|
int type,
|
|
void *user_data,
|
|
gboolean *stop)
|
|
{
|
|
VerifyData *data = user_data;
|
|
|
|
if (type == SEAF_METADATA_TYPE_FILE && check_blocks (data, obj_id) < 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
traverse_commit (SeafCommit *commit, void *vdata, gboolean *stop)
|
|
{
|
|
VerifyData *data = vdata;
|
|
SeafRepo *repo = data->repo;
|
|
int ret;
|
|
|
|
if (data->truncate_time == 0)
|
|
{
|
|
*stop = TRUE;
|
|
/* Stop after traversing the head commit. */
|
|
}
|
|
else if (data->truncate_time > 0 &&
|
|
(gint64)(commit->ctime) < data->truncate_time &&
|
|
data->traversed_head)
|
|
{
|
|
*stop = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!data->traversed_head)
|
|
data->traversed_head = TRUE;
|
|
|
|
ret = seaf_fs_manager_traverse_tree (seaf->fs_mgr,
|
|
repo->store_id,
|
|
repo->version,
|
|
commit->root_id,
|
|
fs_callback,
|
|
vdata, FALSE);
|
|
if (ret < 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
verify_repo (SeafRepo *repo)
|
|
{
|
|
GList *branches, *ptr;
|
|
SeafBranch *branch;
|
|
int ret = 0;
|
|
VerifyData data = {0};
|
|
|
|
data.repo = repo;
|
|
data.truncate_time = seaf_repo_manager_get_repo_truncate_time (repo->manager,
|
|
repo->id);
|
|
|
|
branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id);
|
|
if (branches == NULL) {
|
|
seaf_warning ("[GC] Failed to get branch list of repo %s.\n", repo->id);
|
|
return -1;
|
|
}
|
|
|
|
for (ptr = branches; ptr != NULL; ptr = ptr->next) {
|
|
branch = ptr->data;
|
|
gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr,
|
|
repo->id,
|
|
repo->version,
|
|
branch->commit_id,
|
|
traverse_commit,
|
|
&data, FALSE);
|
|
seaf_branch_unref (branch);
|
|
if (!res) {
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_list_free (branches);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
verify_repos (GList *repo_id_list)
|
|
{
|
|
if (repo_id_list == NULL)
|
|
repo_id_list = seaf_repo_manager_get_repo_id_list (seaf->repo_mgr);
|
|
|
|
GList *ptr;
|
|
SeafRepo *repo;
|
|
int ret = 0;
|
|
|
|
for (ptr = repo_id_list; ptr != NULL; ptr = ptr->next) {
|
|
repo = seaf_repo_manager_get_repo_ex (seaf->repo_mgr, (const gchar *)ptr->data);
|
|
|
|
g_free (ptr->data);
|
|
|
|
if (!repo)
|
|
continue;
|
|
|
|
if (repo->is_corrupted) {
|
|
seaf_warning ("Repo %s is corrupted.\n", repo->id);
|
|
} else {
|
|
ret = verify_repo (repo);
|
|
seaf_repo_unref (repo);
|
|
if (ret < 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_list_free (repo_id_list);
|
|
|
|
return ret;
|
|
}
|