static int get_commit_start (CcnetProcessor *processor, int argc, char **argv) { USE_PRIV; GString *buf = g_string_new (NULL); TransferTask *task = ((SeafileGetcommitV3Proc *)processor)->tx_task; SeafBranch *master = NULL; g_return_val_if_fail (task->session_token, -1); /* fs_roots can be non-NULL if transfer is resumed from NET_DOWN. */ if (task->fs_roots != NULL) object_list_free (task->fs_roots); task->fs_roots = object_list_new (); priv->writer_id = seaf_obj_store_register_async_write (seaf->commit_mgr->obj_store, task->repo_id, task->repo_version, commit_write_cb, processor); g_string_printf (buf, "remote %s seafile-putcommit-v3 %s %s", processor->peer_id, task->head, task->session_token); ccnet_processor_send_request (processor, buf->str); g_string_free (buf, TRUE); seaf_branch_unref (master); return 0; }
static int verify_repo (SeafRepo *repo) { GList *branches, *ptr; SeafBranch *branch; int ret = 0; VerifyData data = {0}; 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, branch->commit_id, traverse_commit, &data); seaf_branch_unref (branch); if (!res) { ret = -1; break; } } g_list_free (branches); return ret; }
static void * merge_job (void *data) { MergeAux *aux = data; CloneTask *task = aux->task; SeafRepo *repo = aux->repo; SeafBranch *local = NULL; SeafCommit *head = NULL; /* If we haven't indexed files in the worktree, index them now. */ if (task->root_id[0] == 0) { if (seaf_repo_index_worktree_files (task->repo_id, task->worktree, task->passwd, task->root_id) < 0) return aux; } local = seaf_branch_manager_get_branch (seaf->branch_mgr, repo->id, "local"); if (!local) { aux->success = FALSE; goto out; } head = seaf_commit_manager_get_commit (seaf->commit_mgr, local->commit_id); if (!head) { aux->success = FALSE; goto out; } if (check_fast_forward (head, task->root_id)) { seaf_debug ("[clone mgr] Fast forward.\n"); if (fast_forward_checkout (repo, head, task) < 0) goto out; } else { if (real_merge (repo, head, task) < 0) goto out; /* Commit the result of merge. */ GError *error = NULL; /* XXX: the commit code assumes repo->head is set. */ repo->head = local; seaf_repo_index_commit (repo, "", &error); if (error) { seaf_warning ("Failed to commit after merge.\n"); goto out; } repo->head = NULL; } /* Set repo head to mark checkout done. */ seaf_repo_set_head (repo, local); aux->success = TRUE; out: seaf_branch_unref (local); seaf_commit_unref (head); return aux; }
static int send_repo_branch_info (CcnetProcessor *processor, const char *repo_id, const char *branch) { SeafRepo *repo; SeafBranch *seaf_branch; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { ccnet_processor_send_response (processor, SC_NO_REPO, SS_NO_REPO, NULL, 0); return 0; } seaf_branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, branch); if (seaf_branch == NULL) { ccnet_processor_send_response (processor, SC_NO_BRANCH, SS_NO_BRANCH, NULL, 0); return -1; } ccnet_processor_send_response (processor, SC_COMMIT_ID, SS_COMMIT_ID, seaf_branch->commit_id, 41); seaf_branch_unref (seaf_branch); return 0; }
static void set_head_common (SeafRepo *repo, SeafBranch *branch) { if (repo->head) seaf_branch_unref (repo->head); repo->head = branch; seaf_branch_ref(branch); }
void seaf_repo_free (SeafRepo *repo) { if (repo->name) g_free (repo->name); if (repo->desc) g_free (repo->desc); if (repo->category) g_free (repo->category); if (repo->head) seaf_branch_unref (repo->head); g_free (repo); }
void seaf_branch_list_free (GList *blist) { GList *ptr; for (ptr = blist; ptr; ptr = ptr->next) { seaf_branch_unref (ptr->data); } g_list_free (blist); }
static SeafRepo * load_repo (SeafRepoManager *manager, const char *repo_id) { SeafRepo *repo; SeafBranch *branch; SeafVirtRepo *vinfo = NULL; repo = seaf_repo_new(repo_id, NULL, NULL); if (!repo) { g_warning ("[repo mgr] failed to alloc repo.\n"); return NULL; } repo->manager = manager; branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master"); if (!branch) { g_warning ("Failed to get master branch of repo %.8s.\n", repo_id); repo->is_corrupted = TRUE; } else { load_repo_commit (manager, repo, branch); seaf_branch_unref (branch); } if (repo->is_corrupted) { g_warning ("Repo %.8s is corrupted.\n", repo->id); seaf_repo_free (repo); return NULL; } vinfo = seaf_repo_manager_get_virtual_repo_info (manager, repo_id); if (vinfo) { repo->is_virtual = TRUE; memcpy (repo->store_id, vinfo->origin_repo_id, 36); } else { repo->is_virtual = FALSE; memcpy (repo->store_id, repo->id, 36); } seaf_virtual_repo_info_free (vinfo); #if 0 if (pthread_rwlock_wrlock (&manager->priv->lock) < 0) { g_warning ("[repo mgr] failed to lock repo cache.\n"); seaf_repo_free (repo); return NULL; } avl_insert (manager->priv->repo_tree, repo); /* Don't need to increase ref count, since the ref count of * a new repo object is already 1. */ pthread_rwlock_unlock (&manager->priv->lock); #endif return repo; }
static SeafRepo * load_repo (SeafRepoManager *manager, const char *repo_id, gboolean ret_corrupt) { SeafRepo *repo; SeafBranch *branch; SeafVirtRepo *vinfo = NULL; repo = seaf_repo_new(repo_id, NULL, NULL); if (!repo) { seaf_warning ("[repo mgr] failed to alloc repo.\n"); return NULL; } repo->manager = manager; branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master"); if (!branch) { g_warning ("Failed to get master branch of repo %.8s.\n", repo_id); repo->is_corrupted = TRUE; } else { load_repo_commit (manager, repo, branch); seaf_branch_unref (branch); } if (repo->is_corrupted) { if (!ret_corrupt) { seaf_repo_free (repo); return NULL; } return repo; } vinfo = seaf_repo_manager_get_virtual_repo_info (manager, repo_id); if (vinfo) { repo->is_virtual = TRUE; memcpy (repo->store_id, vinfo->origin_repo_id, 36); } else { repo->is_virtual = FALSE; memcpy (repo->store_id, repo->id, 36); } seaf_virtual_repo_info_free (vinfo); return repo; }
static int start (CcnetProcessor *processor, int argc, char **argv) { USE_PRIV; GString *buf; SeafileGetfsV2Proc *proc = (SeafileGetfsV2Proc *)processor; TransferTask *task = proc->tx_task; buf = g_string_new (NULL); if (!task->is_clone) { SeafBranch *master = seaf_branch_manager_get_branch (seaf->branch_mgr, task->repo_id, "master"); if (!master) { seaf_warning ("Master branch not found for repo %s.\n", task->repo_id); g_string_free (buf, TRUE); ccnet_processor_done (processor, FALSE); return -1; } g_string_printf (buf, "remote %s seafile-putfs-v2 %s %s %s", processor->peer_id, task->session_token, task->head, master->commit_id); seaf_branch_unref (master); } else g_string_printf (buf, "remote %s seafile-putfs-v2 %s %s", processor->peer_id, task->session_token, task->head); ccnet_processor_send_request (processor, buf->str); g_string_free (buf, TRUE); priv->registered = TRUE; priv->writer_id = seaf_obj_store_register_async_write (seaf->fs_mgr->obj_store, task->repo_id, task->repo_version, on_fs_write, processor); return 0; }
static gboolean load_branch_cb (SeafDBRow *row, void *vrepo) { SeafRepo *repo = vrepo; SeafRepoManager *manager = repo->manager; const char *branch_name = seaf_db_row_get_column_text (row, 0); SeafBranch *branch = seaf_branch_manager_get_branch (manager->seaf->branch_mgr, repo->id, branch_name); if (branch == NULL) { g_warning ("Broken branch name for repo %s\n", repo->id); repo->is_corrupted = TRUE; return FALSE; } load_repo_commit (manager, repo, branch); seaf_branch_unref (branch); /* Only one result. */ return FALSE; }
GList * seaf_repo_get_commits (SeafRepo *repo) { GList *branches; GList *ptr; SeafBranch *branch; GList *commits = NULL; branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); if (branches == NULL) { g_warning ("Failed to get branch list of repo %s.\n", repo->id); return NULL; } 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, collect_commit, &commits, FALSE); if (!res) { for (ptr = commits; ptr != NULL; ptr = ptr->next) seaf_commit_unref ((SeafCommit *)(ptr->data)); g_list_free (commits); goto out; } } commits = g_list_reverse (commits); out: for (ptr = branches; ptr != NULL; ptr = ptr->next) { seaf_branch_unref ((SeafBranch *)ptr->data); } return commits; }
static void handle_upload_ok (CcnetProcessor *processor, TransferTask *task, char *content, int clen) { if (clen == 0) { ccnet_processor_send_update (processor, SC_GET_TOKEN, SS_GET_TOKEN, NULL, 0); return; } if (clen != 41 || content[clen-1] != '\0') { seaf_warning ("Bad response content.\n"); transfer_task_set_error (task, TASK_ERR_UNKNOWN); ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0); ccnet_processor_done (processor, FALSE); return; } /* Ignore the returned remote head id, just use the head of master branch. * For protocol version >= 6, the complete hitstory is not downloaded, so * there is no way to check fast forward on the client. For protocol version * < 6, the server will check fast forward anyway. */ SeafBranch *master = seaf_branch_manager_get_branch (seaf->branch_mgr, task->repo_id, "master"); if (!master) { seaf_warning ("Cannot find branch master for repo %s.\n", task->repo_id); ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0); ccnet_processor_done (processor, FALSE); return; } memcpy (task->remote_head, master->commit_id, 40); seaf_branch_unref (master); ccnet_processor_send_update (processor, SC_GET_TOKEN, SS_GET_TOKEN, NULL, 0); }
static SeafRepo * load_repo (SeafRepoManager *manager, const char *repo_id) { SeafRepo *repo; SeafBranch *branch; repo = seaf_repo_new(repo_id, NULL, NULL); if (!repo) { seaf_warning ("[repo mgr] failed to alloc repo.\n"); return NULL; } repo->manager = manager; branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, "master"); if (!branch) { seaf_warning ("Failed to get master branch of repo %.8s.\n", repo_id); repo->is_corrupted = TRUE; } else { load_repo_commit (manager, repo, branch); seaf_branch_unref (branch); } if (repo->is_corrupted) { seaf_warning ("Repo %.8s is corrupted.\n", repo->id); seaf_repo_free (repo); return NULL; } char *origin_repo_id = get_origin_repo_id (manager, repo->id); if (origin_repo_id) memcpy (repo->store_id, origin_repo_id, 36); else memcpy (repo->store_id, repo->id, 36); g_free (origin_repo_id); return repo; }
static int get_commit_start (CcnetProcessor *processor, int argc, char **argv) { GString *buf = g_string_new (NULL); TransferTask *task = ((SeafileGetcommitV2Proc *)processor)->tx_task; SeafBranch *master = NULL; char *end_commit_id = NULL; g_return_val_if_fail (task->session_token, -1); if (!task->is_clone) { master = seaf_branch_manager_get_branch (seaf->branch_mgr, task->repo_id, "master"); if (master != NULL) end_commit_id = master->commit_id; } /* fs_roots can be non-NULL if transfer is resumed from NET_DOWN. */ if (task->fs_roots != NULL) object_list_free (task->fs_roots); task->fs_roots = object_list_new (); if (end_commit_id != NULL) g_string_printf (buf, "remote %s seafile-putcommit-v2 %s %s %s", processor->peer_id, task->head, end_commit_id, task->session_token); else g_string_printf (buf, "remote %s seafile-putcommit-v2 %s %s", processor->peer_id, task->head, task->session_token); ccnet_processor_send_request (processor, buf->str); g_string_free (buf, TRUE); seaf_branch_unref (master); return 0; }
static void * send_repo_branch_info (void *vprocessor) { CcnetProcessor *processor = vprocessor; SeafRepo *repo; SeafBranch *seaf_branch; USE_PRIV; repo = seaf_repo_manager_get_repo_ex (seaf->repo_mgr, priv->repo_id); if (!repo) { priv->rsp_code = g_strdup (SC_NO_REPO); priv->rsp_msg = g_strdup (SS_NO_REPO); return vprocessor; } else if (repo->is_corrupted) { priv->rsp_code = g_strdup (SC_REPO_CORRUPT); priv->rsp_msg = g_strdup (SS_REPO_CORRUPT); return vprocessor; } seaf_branch = seaf_branch_manager_get_branch (seaf->branch_mgr, priv->repo_id, priv->branch_name); if (!seaf_branch) { seaf_repo_unref (repo); priv->rsp_code = g_strdup (SC_NO_BRANCH); priv->rsp_msg = g_strdup (SS_NO_BRANCH); return vprocessor; } priv->rsp_code = g_strdup (SC_COMMIT_ID); priv->rsp_msg = g_strdup (SS_COMMIT_ID); memcpy (priv->commit_id, seaf_branch->commit_id, 41); seaf_repo_unref (repo); seaf_branch_unref (seaf_branch); return vprocessor; }
static void get_branch_head (CcnetProcessor *processor) { SeafBranch *branch; USE_PRIV; branch = seaf_branch_manager_get_branch (seaf->branch_mgr, priv->repo_id, priv->branch_name); if (branch != NULL) { priv->has_branch = 1; memcpy (priv->head_id, branch->commit_id, 41); seaf_branch_unref (branch); priv->rsp_code = g_strdup(SC_OK); priv->rsp_msg = g_strdup(SS_OK); } else if (priv->type == CHECK_TX_TYPE_UPLOAD) { priv->rsp_code = g_strdup(SC_OK); priv->rsp_msg = g_strdup(SS_OK); } else { priv->rsp_code = g_strdup(SC_NO_BRANCH); priv->rsp_msg = g_strdup(SS_NO_BRANCH); } }
static int recover_corrupted_repo_head (char *repo_id) { GList *commit_list = NULL; GList *temp_list = NULL; SeafCommit *temp_commit = NULL; SeafBranch *branch = NULL; SeafRepo *repo = NULL; SeafVirtRepo *vinfo = NULL; FsckRes res; int rc = -1; seaf_message ("Recovering corrupt head commit for repo %.8s.\n", repo_id); seaf_obj_store_foreach_obj (seaf->commit_mgr->obj_store, repo_id, 1, fsck_get_repo_commit, &commit_list); if (commit_list == NULL) return rc; commit_list = g_list_sort (commit_list, compare_commit_by_ctime); memset (&res, 0, sizeof(res)); res.existing_blocks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (temp_list = commit_list; temp_list; temp_list = temp_list->next) { temp_commit = temp_list->data; branch = seaf_branch_new ("master", repo_id, temp_commit->commit_id); if (branch == NULL) { continue; } repo = seaf_repo_new (repo_id, NULL, NULL); if (repo == NULL) { seaf_branch_unref (branch); continue; } repo->head = branch; seaf_repo_from_commit (repo, temp_commit); vinfo = seaf_repo_manager_get_virtual_repo_info (seaf->repo_mgr, repo_id); if (vinfo) { repo->is_virtual = TRUE; memcpy (repo->store_id, vinfo->origin_repo_id, 36); } else { repo->is_virtual = FALSE; memcpy (repo->store_id, repo->id, 36); } seaf_virtual_repo_info_free (vinfo); res.repo = repo; rc = seaf_fs_manager_traverse_tree (seaf->fs_mgr, repo->store_id, repo->version, temp_commit->root_id, fs_callback, &res, FALSE); if (rc < 0) { seaf_repo_unref (repo); } else { break; } } if (rc < 0) { seaf_warning ("Failed to fix head commit of repo %.8s.\n", repo_id); } else { // create new head commit, and set it's parent commit as latest avaliable commit temp_commit = cre_commit_from_parent (repo_id, temp_commit); if (temp_commit) { seaf_branch_set_commit (repo->head, temp_commit->commit_id); // in case of branch col miss, using add_branch instead of update_branch if (seaf_branch_manager_add_branch (seaf->branch_mgr, repo->head) < 0) { seaf_warning ("Failed to fix head commit of repo %.8s.\n", repo_id); rc = -1; } else { seaf_commit_manager_add_commit (seaf->commit_mgr, temp_commit); seaf_message ("Head commit of repo %.8s has been fixed to commit %.8s.\n", repo_id, temp_commit->commit_id); } seaf_commit_unref (temp_commit); } else { seaf_warning ("Failed to fix head commit of repo %.8s.\n", repo_id); rc = -1; } } g_hash_table_destroy (res.existing_blocks); seaf_repo_unref (repo); for (temp_list = commit_list; temp_list; temp_list = temp_list->next) { temp_commit = temp_list->data; seaf_commit_unref (temp_commit); } g_list_free (commit_list); return rc; }
static void * update_repo (void *vprocessor) { CcnetProcessor *processor = vprocessor; USE_PRIV; char *repo_id, *branch_name, *new_head; SeafRepo *repo = NULL; SeafBranch *branch = NULL; SeafCommit *commit = NULL; char old_commit_id[41]; repo_id = priv->repo_id; branch_name = priv->branch_name; new_head = priv->new_head; /* Since this is the last step of upload procedure, commit should exist. */ commit = seaf_commit_manager_get_commit (seaf->commit_mgr, new_head); if (!commit) { priv->rsp_code = g_strdup (SC_BAD_COMMIT); priv->rsp_msg = g_strdup (SS_BAD_COMMIT); goto out; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { /* repo is deleted on server */ priv->rsp_code = g_strdup (SC_BAD_REPO); priv->rsp_msg = g_strdup (SC_BAD_REPO); goto out; } if (seaf_quota_manager_check_quota (seaf->quota_mgr, repo_id) < 0) { priv->rsp_code = g_strdup(SC_QUOTA_FULL); priv->rsp_msg = g_strdup(SS_QUOTA_FULL); goto out; } branch = seaf_branch_manager_get_branch (seaf->branch_mgr, repo_id, branch_name); if (!branch) { priv->rsp_code = g_strdup (SC_BAD_BRANCH); priv->rsp_msg = g_strdup (SS_BAD_BRANCH); goto out; } /* If branch exists, check fast forward. */ if (strcmp (new_head, branch->commit_id) != 0 && !is_fast_forward (new_head, branch->commit_id)) { g_warning ("Upload is not fast forward. Refusing.\n"); seaf_repo_unref (repo); seaf_commit_unref (commit); seaf_branch_unref (branch); priv->rsp_code = g_strdup (SC_NOT_FF); priv->rsp_msg = g_strdup (SS_NOT_FF); return vprocessor; } /* Update branch. In case of concurrent update, we must ensure atomicity. */ memcpy (old_commit_id, branch->commit_id, 41); seaf_branch_set_commit (branch, commit->commit_id); if (seaf_branch_manager_test_and_update_branch (seaf->branch_mgr, branch, old_commit_id) < 0) { g_warning ("Upload is not fast forward, concurrent update.\n"); priv->rsp_code = g_strdup (SC_NOT_FF); priv->rsp_msg = g_strdup (SS_NOT_FF); goto out; } out: if (repo) seaf_repo_unref (repo); if (commit) seaf_commit_unref (commit); if (branch) seaf_branch_unref (branch); if (!priv->rsp_code) { priv->rsp_code = g_strdup (SC_OK); priv->rsp_msg = g_strdup (SS_OK); } return vprocessor; }
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); }
static int do_create_virtual_repo (SeafRepoManager *mgr, SeafRepo *origin_repo, const char *repo_id, const char *repo_name, const char *repo_desc, const char *root_id, const char *user, const char *passwd, GError **error) { SeafRepo *repo = NULL; SeafCommit *commit = NULL; SeafBranch *master = NULL; int ret = 0; repo = seaf_repo_new (repo_id, repo_name, repo_desc); repo->no_local_history = TRUE; if (passwd != NULL && passwd[0] != '\0') { repo->encrypted = TRUE; repo->enc_version = origin_repo->enc_version; seafile_generate_magic (repo->enc_version, repo_id, passwd, repo->magic); if (repo->enc_version == 2) memcpy (repo->random_key, origin_repo->random_key, 96); } /* Virtual repos share fs and block store with origin repo and * have the same version as the origin. */ repo->version = origin_repo->version; memcpy (repo->store_id, origin_repo->id, 36); commit = seaf_commit_new (NULL, repo->id, root_id, /* root id */ user, /* creator */ EMPTY_SHA1, /* creator id */ repo_desc, /* description */ 0); /* ctime */ seaf_repo_to_commit (repo, commit); if (seaf_commit_manager_add_commit (seaf->commit_mgr, commit) < 0) { seaf_warning ("Failed to add commit.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to add commit"); ret = -1; goto out; } master = seaf_branch_new ("master", repo->id, commit->commit_id); if (seaf_branch_manager_add_branch (seaf->branch_mgr, master) < 0) { seaf_warning ("Failed to add branch.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to add branch"); ret = -1; goto out; } if (seaf_repo_set_head (repo, master) < 0) { seaf_warning ("Failed to set repo head.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to set repo head."); ret = -1; goto out; } if (seaf_repo_manager_add_repo (mgr, repo) < 0) { seaf_warning ("Failed to add repo.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to add repo."); ret = -1; goto out; } out: if (repo) seaf_repo_unref (repo); if (commit) seaf_commit_unref (commit); if (master) seaf_branch_unref (master); return ret; }