static void start_clone_v2 (CloneTask *task) { GError *error = NULL; if (g_access (task->worktree, F_OK) != 0 && g_mkdir_with_parents (task->worktree, 0777) < 0) { seaf_warning ("[clone mgr] Failed to create worktree %s.\n", task->worktree); transition_to_error (task, CLONE_ERROR_FETCH); return; } SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, task->repo_id); if (repo != NULL) { seaf_repo_manager_set_repo_token (seaf->repo_mgr, repo, task->token); seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email); seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id, task->peer_addr, task->peer_port); if (task->server_url) { seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_PROP_SERVER_URL, task->server_url); } mark_clone_done_v2 (repo, task); return; } if (add_transfer_task (task, &error) == 0) transition_state (task, CLONE_STATE_FETCH); else transition_to_error (task, CLONE_ERROR_FETCH); }
static void check_http_protocol_done (HttpProtocolVersion *result, void *user_data) { CloneTask *task = user_data; if (task->state == CLONE_STATE_CANCEL_PENDING) { transition_state (task, CLONE_STATE_CANCELED); return; } if (result->check_success && !result->not_supported) { task->http_protocol_version = result->version; task->effective_url = g_strdup(task->server_url); http_check_head_commit (task); } else if (strncmp(task->server_url, "https", 5) != 0) { char *host_fileserver = http_fileserver_url(task->server_url); if (http_tx_manager_check_protocol_version (seaf->http_tx_mgr, host_fileserver, TRUE, check_http_fileserver_protocol_done, task) < 0) transition_to_error (task, CLONE_ERROR_CHECK_SERVER); g_free (host_fileserver); } else { /* Wait for periodic retry. */ transition_to_error (task, CLONE_ERROR_CHECK_SERVER); if (result->error_code != 0) task->err_detail = g_strdup(http_task_error_str(result->error_code)); } }
static void index_files_done (void *result) { IndexAux *aux = result; CloneTask *task = aux->task; if (!aux->success) { transition_to_error (task, CLONE_ERROR_INDEX); goto out; } if (task->state == CLONE_STATE_CANCEL_PENDING) { transition_state (task, CLONE_STATE_CANCELED); goto out; } if (add_transfer_task (aux->mgr, task, NULL) < 0) { transition_to_error (task, CLONE_ERROR_FETCH); goto out; } transition_state (task, CLONE_STATE_FETCH); out: g_free (aux); return; }
static void start_checkout (SeafRepo *repo, CloneTask *task) { if (repo->encrypted && task->passwd != NULL) { /* keep this password check to be compatible with old servers. */ if (repo->enc_version >= 1 && seaf_repo_verify_passwd (repo->id, task->passwd, repo->magic) < 0) { seaf_warning ("[Clone mgr] incorrect password.\n"); transition_to_error (task, CLONE_ERROR_PASSWD); return; } if (seaf_repo_manager_set_repo_passwd (seaf->repo_mgr, repo, task->passwd) < 0) { seaf_warning ("[Clone mgr] failed to set passwd for %s.\n", repo->id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } } else if (repo->encrypted) { seaf_warning ("[Clone mgr] Password is empty for encrypted repo %s.\n", repo->id); transition_to_error (task, CLONE_ERROR_PASSWD); return; } if (g_access (task->worktree, F_OK) != 0 && g_mkdir_with_parents (task->worktree, 0777) < 0) { seaf_warning ("[clone mgr] Failed to create worktree %s.\n", task->worktree); transition_to_error (task, CLONE_ERROR_CHECKOUT); return; } if (!is_non_empty_directory (task->worktree)) { transition_state (task, CLONE_STATE_CHECKOUT); seaf_repo_manager_add_checkout_task (seaf->repo_mgr, repo, task->worktree, on_checkout_done, task->manager); } else { MergeAux *aux = g_new0 (MergeAux, 1); aux->task = task; aux->repo = repo; transition_state (task, CLONE_STATE_MERGE); ccnet_job_manager_schedule_job (seaf->job_mgr, merge_job, merge_job_done, aux); } }
static int start_index_or_transfer (SeafCloneManager *mgr, CloneTask *task, GError **error) { IndexAux *aux; int ret = 0; if (is_non_empty_directory (task->worktree)) { transition_state (task, CLONE_STATE_INDEX); aux = g_new0 (IndexAux, 1); aux->mgr = mgr; aux->task = task; ccnet_job_manager_schedule_job (seaf->job_mgr, index_files_job, index_files_done, aux); } else { ret = add_transfer_task (mgr, task, error); if (ret == 0) transition_state (task, CLONE_STATE_FETCH); else transition_to_error (task, CLONE_ERROR_FETCH); } return ret; }
static void merge_job_done (void *data) { MergeAux *aux = data; CloneTask *task = aux->task; SeafRepo *repo = aux->repo; if (!aux->success) { g_free (aux); transition_to_error (task, CLONE_ERROR_MERGE); return; } seaf_repo_manager_set_repo_worktree (aux->repo->manager, aux->repo, task->worktree); if (task->state == CLONE_STATE_CANCEL_PENDING) transition_state (task, CLONE_STATE_CANCELED); else if (task->state == CLONE_STATE_MERGE) { /* Save repo head if for GC. */ seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_REMOTE_HEAD, repo->head->commit_id); transition_state (task, CLONE_STATE_DONE); } else g_assert (0); g_free (aux); }
static void merge_job_done (void *data) { MergeAux *aux = data; CloneTask *task = aux->task; if (!aux->success) { g_free (aux); transition_to_error (task, CLONE_ERROR_MERGE); return; } seaf_repo_manager_set_repo_worktree (aux->repo->manager, aux->repo, task->worktree); if (task->state == CLONE_STATE_CANCEL_PENDING) transition_state (task, CLONE_STATE_CANCELED); else if (task->state == CLONE_STATE_MERGE) transition_state (task, CLONE_STATE_DONE); else g_assert (0); g_free (aux); }
static void on_repo_http_fetched (SeafileSession *seaf, HttpTxTask *tx_task, SeafCloneManager *mgr) { CloneTask *task; /* Only handle clone task. */ if (!tx_task->is_clone) return; task = g_hash_table_lookup (mgr->tasks, tx_task->repo_id); g_return_if_fail (task != NULL); if (tx_task->state == HTTP_TASK_STATE_CANCELED) { /* g_assert (task->state == CLONE_STATE_CANCEL_PENDING); */ transition_state (task, CLONE_STATE_CANCELED); return; } else if (tx_task->state == HTTP_TASK_STATE_ERROR) { transition_to_error (task, CLONE_ERROR_FETCH); task->err_detail = g_strdup(http_task_error_str(tx_task->error)); return; } SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, tx_task->repo_id); if (repo == NULL) { seaf_warning ("[Clone mgr] cannot find repo %s after fetched.\n", tx_task->repo_id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } seaf_repo_manager_set_repo_token (seaf->repo_mgr, repo, task->token); seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email); seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id, task->peer_addr, task->peer_port); if (task->server_url) { seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_PROP_SERVER_URL, task->server_url); } check_folder_permissions (task); }
static gboolean restart_task (sqlite3_stmt *stmt, void *data) { SeafCloneManager *mgr = data; const char *repo_id, *repo_name, *token, *peer_id, *worktree, *passwd; const char *peer_addr, *peer_port, *email; CloneTask *task; SeafRepo *repo; repo_id = (const char *)sqlite3_column_text (stmt, 0); repo_name = (const char *)sqlite3_column_text (stmt, 1); token = (const char *)sqlite3_column_text (stmt, 2); peer_id = (const char *)sqlite3_column_text (stmt, 3); worktree = (const char *)sqlite3_column_text (stmt, 4); passwd = (const char *)sqlite3_column_text (stmt, 5); peer_addr = (const char *)sqlite3_column_text (stmt, 6); peer_port = (const char *)sqlite3_column_text (stmt, 7); email = (const char *)sqlite3_column_text (stmt, 8); task = clone_task_new (repo_id, peer_id, repo_name, token, worktree, passwd, peer_addr, peer_port, email); task->manager = mgr; /* Default to 1. */ task->enc_version = 1; if (passwd && load_clone_enc_info (task) < 0) { clone_task_free (task); return TRUE; } task->repo_version = 0; load_clone_repo_version_info (task); load_clone_more_info (task); repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (repo != NULL && repo->head != NULL) { transition_state (task, CLONE_STATE_DONE); return TRUE; } if (task->repo_version > 0) { if (task->server_url) { check_http_protocol (task); } else { transition_to_error (task, CLONE_ERROR_CHECK_SERVER); return TRUE; } } g_hash_table_insert (mgr->tasks, g_strdup(task->repo_id), task); return TRUE; }
static void on_repo_fetched (SeafileSession *seaf, TransferTask *tx_task, SeafCloneManager *mgr) { CloneTask *task; /* Only handle clone task. */ if (!tx_task->is_clone) return; task = g_hash_table_lookup (mgr->tasks, tx_task->repo_id); g_assert (task != NULL); if (tx_task->state == TASK_STATE_CANCELED) { /* g_assert (task->state == CLONE_STATE_CANCEL_PENDING); */ transition_state (task, CLONE_STATE_CANCELED); return; } else if (tx_task->state == TASK_STATE_ERROR) { transition_to_error (task, CLONE_ERROR_FETCH); return; } SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, tx_task->repo_id); if (repo == NULL) { seaf_warning ("[Clone mgr] cannot find repo %s after fetched.\n", tx_task->repo_id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } seaf_repo_manager_set_repo_token (seaf->repo_mgr, repo, task->token); seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email); seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id, task->peer_addr, task->peer_port); start_checkout (repo, task); }
static void check_http_protocol (CloneTask *task) { if (http_tx_manager_check_protocol_version (seaf->http_tx_mgr, task->server_url, FALSE, check_http_protocol_done, task) < 0) { transition_to_error (task, CLONE_ERROR_CHECK_SERVER); return; } transition_state (task, CLONE_STATE_CHECK_SERVER); }
static void http_check_head_commit (CloneTask *task) { int ret = http_tx_manager_check_head_commit (seaf->http_tx_mgr, task->repo_id, task->repo_version, task->effective_url, task->token, task->use_fileserver_port, check_head_commit_done, task); if (ret < 0) transition_to_error (task, CLONE_ERROR_CHECK_SERVER); }
static void check_folder_permissions (CloneTask *task) { SeafRepo *repo = NULL; HttpFolderPermReq *req; GList *requests = NULL; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, task->repo_id); if (repo == NULL) { seaf_warning ("[Clone mgr] cannot find repo %s after fetched.\n", task->repo_id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } if (!seaf_repo_manager_server_is_pro (seaf->repo_mgr, task->server_url)) { mark_clone_done_v2 (repo, task); return; } req = g_new0 (HttpFolderPermReq, 1); memcpy (req->repo_id, task->repo_id, 36); req->token = g_strdup(task->token); req->timestamp = 0; requests = g_list_append (requests, req); /* The requests list will be freed in http tx manager. */ if (http_tx_manager_get_folder_perms (seaf->http_tx_mgr, task->effective_url, task->use_fileserver_port, requests, check_folder_perms_done, task) < 0) transition_to_error (task, CLONE_ERROR_INTERNAL); }
static void on_checkout_done (CheckoutTask *ctask, SeafRepo *repo, void *data) { SeafCloneManager *mgr = data; CloneTask *task = g_hash_table_lookup (mgr->tasks, repo->id); g_assert (task != NULL); if (!ctask->success) { transition_to_error (task, CLONE_ERROR_CHECKOUT); return; } if (task->state == CLONE_STATE_CANCEL_PENDING) transition_state (task, CLONE_STATE_CANCELED); else if (task->state == CLONE_STATE_CHECKOUT) transition_state (task, CLONE_STATE_DONE); else g_assert (0); }
static void check_head_commit_done (HttpHeadCommit *result, void *user_data) { CloneTask *task = user_data; if (task->state == CLONE_STATE_CANCEL_PENDING) { transition_state (task, CLONE_STATE_CANCELED); return; } if (result->check_success && !result->is_corrupt && !result->is_deleted) { memcpy (task->server_head_id, result->head_commit, 40); start_clone_v2 (task); } else { transition_to_error (task, CLONE_ERROR_CHECK_SERVER); if (result->error_code != 0) task->err_detail = g_strdup(http_task_error_str(result->error_code)); } }
static void check_http_fileserver_protocol_done (HttpProtocolVersion *result, void *user_data) { CloneTask *task = user_data; if (task->state == CLONE_STATE_CANCEL_PENDING) { transition_state (task, CLONE_STATE_CANCELED); return; } if (result->check_success && !result->not_supported) { task->http_protocol_version = result->version; task->effective_url = http_fileserver_url (task->server_url); task->use_fileserver_port = TRUE; http_check_head_commit (task); } else { /* Wait for periodic retry. */ transition_to_error (task, CLONE_ERROR_CHECK_SERVER); if (result->error_code != 0) task->err_detail = g_strdup(http_task_error_str(result->error_code)); } }
static void check_folder_perms_done (HttpFolderPerms *result, void *user_data) { CloneTask *task = user_data; GList *ptr; HttpFolderPermRes *res; SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, task->repo_id); if (repo == NULL) { seaf_warning ("[Clone mgr] cannot find repo %s after fetched.\n", task->repo_id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } if (!result->success) { goto out; } for (ptr = result->results; ptr; ptr = ptr->next) { res = ptr->data; seaf_repo_manager_update_folder_perms (seaf->repo_mgr, res->repo_id, FOLDER_PERM_TYPE_USER, res->user_perms); seaf_repo_manager_update_folder_perms (seaf->repo_mgr, res->repo_id, FOLDER_PERM_TYPE_GROUP, res->group_perms); seaf_repo_manager_update_folder_perm_timestamp (seaf->repo_mgr, res->repo_id, res->timestamp); } out: mark_clone_done_v2 (repo, task); }
static void on_checkout_done (CheckoutTask *ctask, SeafRepo *repo, void *data) { SeafCloneManager *mgr = data; CloneTask *task = g_hash_table_lookup (mgr->tasks, repo->id); g_assert (task != NULL); if (!ctask->success) { transition_to_error (task, CLONE_ERROR_CHECKOUT); return; } if (task->state == CLONE_STATE_CANCEL_PENDING) transition_state (task, CLONE_STATE_CANCELED); else if (task->state == CLONE_STATE_CHECKOUT) { /* Save repo head if for GC. */ seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_REMOTE_HEAD, repo->head->commit_id); transition_state (task, CLONE_STATE_DONE); } else g_assert (0); }
static void mark_clone_done_v2 (SeafRepo *repo, CloneTask *task) { SeafBranch *local = NULL; seaf_repo_manager_set_repo_worktree (repo->manager, repo, task->worktree); local = seaf_branch_manager_get_branch (seaf->branch_mgr, repo->id, "local"); if (!local) { seaf_warning ("Cannot get branch local for repo %s(%.10s).\n", repo->name, repo->id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } /* Set repo head to mark checkout done. */ seaf_repo_set_head (repo, local); seaf_branch_unref (local); if (repo->encrypted) { if (seaf_repo_manager_set_repo_passwd (seaf->repo_mgr, repo, task->passwd) < 0) { seaf_warning ("[Clone mgr] failed to set passwd for %s.\n", repo->id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } } if (task->is_readonly) { seaf_repo_set_readonly (repo); } if (task->sync_wt_name) { seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_SYNC_WORKTREE_NAME, "true"); } if (task->server_url) repo->server_url = g_strdup(task->server_url); if (repo->auto_sync && (repo->sync_interval == 0)) { if (seaf_wt_monitor_watch_repo (seaf->wt_monitor, repo->id, repo->worktree) < 0) { seaf_warning ("failed to watch repo %s(%.10s).\n", repo->name, repo->id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } } /* For compatibility, still set these two properties. * So that if we downgrade to an old version, the syncing can still work. */ seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_REMOTE_HEAD, repo->head->commit_id); seaf_repo_manager_set_repo_property (seaf->repo_mgr, repo->id, REPO_LOCAL_HEAD, repo->head->commit_id); transition_state (task, CLONE_STATE_DONE); }