Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
0
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);
}
Exemple #4
0
static void
start_connect_task_relay (CloneTask *task, GError **error)
{
    CcnetPeer *peer = ccnet_get_peer (seaf->ccnetrpc_client, task->peer_id);
    if (!peer) {
        /* clone from a new relay */
        GString *buf = NULL; 
        seaf_message ("add relay before clone, %s:%s\n",
                      task->peer_addr, task->peer_port);
        buf = g_string_new(NULL);
        g_string_append_printf (buf, "add-relay --id %s --addr %s:%s",
                                task->peer_id, task->peer_addr, task->peer_port);
        ccnet_send_command (seaf->session, buf->str, NULL, NULL);
        transition_state (task, CLONE_STATE_CONNECT);
        g_string_free (buf, TRUE);
    } else {
        /* The peer is added to ccnet already and will be connected,
         * only need to transition the state
         */
        transition_state (task, CLONE_STATE_CONNECT);
    }

    if (peer)
        g_object_unref (peer);
}
Exemple #5
0
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);
}
Exemple #6
0
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);
    }
}
Exemple #7
0
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);
}
Exemple #8
0
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));
    }
}
Exemple #9
0
int
seaf_clone_manager_cancel_task (SeafCloneManager *mgr,
                                const char *repo_id)
{
    CloneTask *task;

    if (!seaf->started) {
        seaf_message ("System not started, skip canceling clone task.\n");
        return -1;
    }

    task = g_hash_table_lookup (mgr->tasks, repo_id);
    if (!task)
        return -1;

    switch (task->state) {
    case CLONE_STATE_INIT:
    case CLONE_STATE_CONNECT:
    case CLONE_STATE_ERROR:
        transition_state (task, CLONE_STATE_CANCELED);
        break;
    case CLONE_STATE_CHECK_SERVER:
        transition_state (task, CLONE_STATE_CANCEL_PENDING);
    case CLONE_STATE_FETCH:
        http_tx_manager_cancel_task (seaf->http_tx_mgr,
                                     task->repo_id,
                                     HTTP_TASK_TYPE_DOWNLOAD);
        transition_state (task, CLONE_STATE_CANCEL_PENDING);
        break;
    case CLONE_STATE_INDEX:
    case CLONE_STATE_CHECKOUT:
    case CLONE_STATE_MERGE:
    case CLONE_STATE_CHECK_PROTOCOL:
        /* We cannot cancel an in-progress checkout, just
         * wait until it finishes.
         */
        transition_state (task, CLONE_STATE_CANCEL_PENDING);
        break;
    case CLONE_STATE_CANCEL_PENDING:
        break;
    default:
        seaf_warning ("[Clone mgr] cannot cancel a not-running task.\n");
        return -1;
    }

    return 0;
}
Exemple #10
0
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;
}
Exemple #11
0
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);
}
Exemple #12
0
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;

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
    if (repo != NULL) {
        if (repo->head != NULL) {
            /* If repo exists and its head is set, we are done actually.
             * The task will be removed from db but still left in memory.
             */
            transition_state (task, CLONE_STATE_DONE);
            g_hash_table_insert (mgr->tasks, g_strdup(task->repo_id), task);
        } else {
            /* If head is not set, we haven't finished checkout.
             */
            g_hash_table_insert (mgr->tasks, g_strdup(task->repo_id), task);
            start_checkout (repo, task);
        }
    } else {
        /* Repo was not created last time. In this case, we just
         * restart from the very beginning.
         */
        if (!ccnet_peer_is_ready (seaf->ccnetrpc_client, task->peer_id)) {
            /* the relay is not ready yet */
            start_connect_task_relay (task, NULL);
        } else {
            start_index_or_transfer (mgr, task, NULL);
        }
        g_hash_table_insert (mgr->tasks, g_strdup(task->repo_id), task);
    }

    return TRUE;
}
Exemple #13
0
int
seaf_clone_manager_cancel_task (SeafCloneManager *mgr,
                                const char *repo_id)
{
    CloneTask *task;

    task = g_hash_table_lookup (mgr->tasks, repo_id);
    if (!task)
        return -1;

    switch (task->state) {
    case CLONE_STATE_INIT:
    case CLONE_STATE_CONNECT:
        transition_state (task, CLONE_STATE_CANCELED);
        break;
    case CLONE_STATE_FETCH:
        seaf_transfer_manager_cancel_task (seaf->transfer_mgr,
                                           task->tx_id,
                                           TASK_TYPE_DOWNLOAD);
        transition_state (task, CLONE_STATE_CANCEL_PENDING);
        break;
    case CLONE_STATE_INDEX:
    case CLONE_STATE_CHECKOUT:
    case CLONE_STATE_MERGE:
        /* We cannot cancel an in-progress checkout, just
         * wait until it finishes.
         */
        transition_state (task, CLONE_STATE_CANCEL_PENDING);
        break;
    case CLONE_STATE_CANCEL_PENDING:
        break;
    default:
        seaf_warning ("[Clone mgr] cannot cancel a not-running task.\n");
        return -1;
    }

    return 0;
}
Exemple #14
0
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);
}
Exemple #15
0
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);
}
Exemple #16
0
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);
}
Exemple #17
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));
    }
}
Exemple #18
0
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);
}
Exemple #19
0
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));
    }
}
Exemple #20
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);
}