int seaf_passwd_manager_check_passwd (SeafPasswdManager *mgr, const char *repo_id, const char *magic, GError **error) { SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo"); return -1; } if (!repo->encrypted) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Repo is not encrypted"); return -1; } if (strcmp (magic, repo->magic) != 0) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); return -1; } seaf_repo_unref (repo); return 0; }
static void fill_in_repo_info (GList *shared_repos) { SeafileSharedRepo *srepo; GList *ptr; SeafRepo *repo = NULL; SeafCommit *commit = NULL; for (ptr = shared_repos; ptr; ptr = ptr->next) { srepo = ptr->data; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, seafile_shared_repo_get_repo_id(srepo)); if (!repo) continue; commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->head->commit_id); if (!commit) { seaf_repo_unref (repo); continue; } g_object_set (srepo, "repo_name", repo->name, "repo_desc", repo->desc, "encrypted", repo->encrypted, "last_modified", commit->ctime, NULL); seaf_repo_unref (repo); seaf_commit_unref (commit); } }
static int readdir_user(SeafileSession *seaf, const char *user, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) { SearpcClient *client; CcnetEmailUser *emailuser; GList *list = NULL, *p; GString *name; client = ccnet_create_pooled_rpc_client (seaf->client_pool, NULL, "ccnet-threaded-rpcserver"); if (!client) { seaf_warning ("Failed to alloc rpc client.\n"); return -ENOMEM; } emailuser = get_user_from_ccnet (client, user); if (!emailuser) { ccnet_rpc_client_free (client); return -ENOENT; } g_object_unref (emailuser); ccnet_rpc_client_free (client); list = seaf_repo_manager_get_repos_by_owner (seaf->repo_mgr, user); if (!list) return 0; for (p = list; p; p = p->next) { SeafRepo *repo = (SeafRepo *)p->data; /* Don't list virtual repos. */ if (seaf_repo_manager_is_virtual_repo(seaf->repo_mgr, repo->id)) { seaf_repo_unref (repo); continue; } //skip the encrypted repo if(repo -> encrypted) continue; char *clean_repo_name = replace_slash (repo->name); name = g_string_new (""); g_string_printf (name, "%s_%s", repo->id, clean_repo_name); filler(buf, name->str, NULL, 0); g_string_free (name, TRUE); g_free (clean_repo_name); seaf_repo_unref (repo); } g_list_free (list); return 0; }
int seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, const char *repo_id, const char *user, const char *passwd, GError **error) { SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); DecryptKey *crypt_key; GString *hash_key; if (!repo) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo"); return -1; } if (!repo->encrypted) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Repo is not encrypted"); return -1; } if (seaf_repo_verify_passwd (repo, passwd) < 0) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); return -1; } crypt_key = g_new0 (DecryptKey, 1); if (!crypt_key) { g_warning ("Failed to alloc crypt key struct.\n"); seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL, "Internal server error"); return -1; } seafile_generate_enc_key (passwd, strlen(passwd), repo->enc_version, crypt_key->key, crypt_key->iv); crypt_key->passwd = g_strdup(passwd); crypt_key->expire_time = (guint64)time(NULL) + REAP_THRESHOLD; hash_key = g_string_new (NULL); g_string_printf (hash_key, "%s.%s", repo_id, user); /* g_debug ("[passwd mgr] Set passwd for %s\n", hash_key->str); */ g_hash_table_insert (mgr->priv->decrypt_keys, g_string_free (hash_key, FALSE), crypt_key); seaf_repo_unref (repo); return 0; }
int seaf_fsck (GList *repo_id_list) { if (!repo_id_list) repo_id_list = seaf_repo_manager_get_repo_id_list (seaf->repo_mgr); GList *ptr; char *repo_id; SeafRepo *repo; for (ptr = repo_id_list; ptr; ptr = ptr->next) { repo_id = ptr->data; seaf_message ("Running fsck for repo %.8s.\n", repo_id); repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { if (recover_corrupted_repo_head (repo_id) < 0) { seaf_warning ("Failed to recover repo %.8s.\n\n", repo_id); } else seaf_message ("Fsck finished for repo %.8s.\n\n", repo_id); continue; } check_and_reset_consistent_state (repo); seaf_message ("Fsck finished for repo %.8s.\n\n", repo_id); seaf_repo_unref (repo); } return 0; }
static int handle_auth_req_content_cb (char *content, int clen, void *cbarg) { BlockTxServer *server = cbarg; char *session_token = content; SearpcClient *client = NULL; char repo_id[37]; SeafRepo *repo; if (session_token[clen - 1] != '\0') { seaf_warning ("Invalid session token format.\n"); send_auth_response (server, STATUS_BAD_REQUEST); return -1; } client = ccnet_create_pooled_rpc_client (seaf->client_pool, NULL, "ccnet-rpcserver"); if (!client) { seaf_warning ("Failed to create rpc client.\n"); send_auth_response (server, STATUS_INTERNAL_SERVER_ERROR); return -1; } if (seaf_token_manager_verify_token (seaf->token_mgr, client, NULL, session_token, repo_id) < 0) { seaf_warning ("Session token check failed.\n"); send_auth_response (server, STATUS_ACCESS_DENIED); ccnet_rpc_client_free (client); return -1; } ccnet_rpc_client_free (client); repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("Failed to get repo %.8s.\n", repo_id); return -1; } memcpy (server->store_id, repo->store_id, 36); server->repo_version = repo->version; seaf_repo_unref (repo); if (send_auth_response (server, STATUS_OK) < 0) return -1; seaf_debug ("recv_state set to HEADER.\n"); server->parser.content_cb = handle_block_header_content_cb; server->recv_state = RECV_STATE_HEADER; return 0; }
void seaf_repo_manager_cleanup_virtual_repos (SeafRepoManager *mgr, const char *origin_repo_id) { SeafRepo *repo = NULL; SeafCommit *head = NULL; GList *vinfo_list = NULL, *ptr; SeafVirtRepo *vinfo; SeafDir *dir; GError *error = NULL; repo = seaf_repo_manager_get_repo (mgr, origin_repo_id); if (!repo) { seaf_warning ("Failed to get repo %.10s.\n", origin_repo_id); goto out; } head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!head) { seaf_warning ("Failed to get commit %s:%.8s.\n", repo->id, repo->head->commit_id); goto out; } vinfo_list = seaf_repo_manager_get_virtual_info_by_origin (mgr, origin_repo_id); for (ptr = vinfo_list; ptr; ptr = ptr->next) { vinfo = ptr->data; dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, repo->store_id, repo->version, head->root_id, vinfo->path, &error); if (error) { if (error->code == SEAF_ERR_PATH_NO_EXIST) { handle_missing_virtual_repo (mgr, repo, head, vinfo); } g_clear_error (&error); } else seaf_dir_free (dir); seaf_virtual_repo_info_free (vinfo); } out: seaf_repo_unref (repo); seaf_commit_unref (head); g_list_free (vinfo_list); }
GList * seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit, gboolean ignore_errors, gboolean *error) { char sql[256]; GList *id_list = NULL, *ptr; GList *ret = NULL; SeafRepo *repo; *error = FALSE; if (start == -1 && limit == -1) snprintf (sql, 256, "SELECT repo_id FROM Repo"); else snprintf (sql, 256, "SELECT repo_id FROM Repo LIMIT %d, %d", start, limit); if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, collect_repo_id, &id_list) < 0) goto error; for (ptr = id_list; ptr; ptr = ptr->next) { char *repo_id = ptr->data; repo = seaf_repo_manager_get_repo (mgr, repo_id); if (!repo) { /* In GC, we should be more conservative. * No matter a repo is really corrupted or it's a temp error, * we return error here. */ g_warning ("Failed to get repo %.8s.\n", repo_id); if (!ignore_errors) goto error; else continue; } ret = g_list_prepend (ret, repo); } string_list_free (id_list); return ret; error: *error = TRUE; string_list_free (id_list); for (ptr = ret; ptr; ptr = ptr->next) { repo = ptr->data; seaf_repo_unref (repo); } return NULL; }
static int readdir_repo(SeafileSession *seaf, const char *user, const char *repo_id, const char *repo_path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) { SeafRepo *repo = NULL; SeafBranch *branch; SeafCommit *commit = NULL; SeafDir *dir = NULL; GList *l; int ret = 0; repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("Failed to get repo %s.\n", repo_id); ret = -ENOENT; goto out; } branch = repo->head; commit = seaf_commit_manager_get_commit(seaf->commit_mgr, repo->id, repo->version, branch->commit_id); if (!commit) { seaf_warning ("Failed to get commit %.8s.\n", branch->commit_id); ret = -ENOENT; goto out; } dir = seaf_fs_manager_get_seafdir_by_path(seaf->fs_mgr, repo->store_id, repo->version, commit->root_id, repo_path, NULL); if (!dir) { seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id); ret = -ENOENT; goto out; } for (l = dir->entries; l; l = l->next) { SeafDirent *seaf_dent = (SeafDirent *) l->data; /* FIXME: maybe we need to return stbuf */ filler(buf, seaf_dent->name, NULL, 0); } out: seaf_repo_unref (repo); seaf_commit_unref (commit); seaf_dir_free (dir); return ret; }
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; }
int verify_repos () { GList *repos = NULL, *ptr; int ret = 0; repos = seaf_repo_manager_get_repo_list (seaf->repo_mgr, -1, -1); for (ptr = repos; ptr != NULL; ptr = ptr->next) { ret = verify_repo ((SeafRepo *)ptr->data); seaf_repo_unref ((SeafRepo *)ptr->data); if (ret < 0) break; } return ret; }
static int migrate_v0_repos_to_v1_layout () { GList *repos = NULL, *ptr; SeafRepo *repo; gboolean error = FALSE; repos = seaf_repo_manager_get_repo_list (seaf->repo_mgr, -1, -1, &error); for (ptr = repos; ptr; ptr = ptr->next) { repo = ptr->data; if (!repo->is_corrupted && repo->version == 0) migrate_repo (repo); seaf_repo_unref (repo); } g_list_free (repos); return 0; }
static void * collect_commit_id_thread (void *vprocessor) { CcnetProcessor *processor = vprocessor; USE_PRIV; SeafRepo *repo; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); if (!repo) { seaf_warning ("Failed to get repo %s.\n", priv->repo_id); priv->id_list = NULL; return vprocessor; } priv->repo_version = repo->version; priv->fast_forward = TRUE; if (seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, repo->id, repo->version, priv->head_commit_id, collect_id_fast_forward, processor, FALSE) < 0) { seaf_warning ("[putcommit] Failed to collect commit id.\n"); string_list_free (priv->id_list); priv->id_list = NULL; goto out; } if (priv->fast_forward) { seaf_debug ("Send commits after a fast-forward merge.\n"); goto out; } seaf_debug ("Send commits after a real merge.\n"); compute_delta_commits (processor, priv->head_commit_id); out: seaf_repo_unref (repo); return vprocessor; }
static gboolean collect_repos (SeafDBRow *row, void *data) { GList **p_repos = data; const char *repo_id; const char *email; const char *permission; SeafRepo *repo = NULL; SeafCommit *commit = NULL; SeafileSharedRepo *srepo; repo_id = seaf_db_row_get_column_text (row, 0); repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) goto out; email = seaf_db_row_get_column_text (row, 1); permission = seaf_db_row_get_column_text (row, 2); commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->head->commit_id); if (!commit) goto out; srepo = g_object_new (SEAFILE_TYPE_SHARED_REPO, "share_type", "personal", "repo_id", repo_id, "repo_name", repo->name, "repo_desc", repo->desc, "encrypted", repo->encrypted, "user", email, "permission", permission, "last_modified", commit->ctime, NULL); *p_repos = g_list_prepend (*p_repos, srepo); out: seaf_repo_unref (repo); seaf_commit_unref (commit); return TRUE; }
static void * create_system_default_repo (void *data) { SeafileSession *session = data; char *repo_id; char *template_path; /* If default repo is not set or doesn't exist, create a new one. */ repo_id = get_system_default_repo_id (session); if (repo_id != NULL) { SeafRepo *repo; repo = seaf_repo_manager_get_repo (session->repo_mgr, repo_id); if (!repo) { seaf_warning ("Failed to get system default repo. Create a new one.\n"); del_system_default_repo_id (session); seaf_repo_manager_del_repo (session->repo_mgr, repo_id, NULL); } else { seaf_repo_unref (repo); return data; } } repo_id = seaf_repo_manager_create_new_repo (session->repo_mgr, "My Library Template", "Template for creating 'My Libray' for users", "System", NULL, NULL); if (!repo_id) { seaf_warning ("Failed to create system default repo.\n"); return data; } set_system_default_repo_id (session, repo_id); template_path = g_build_filename (session->seaf_dir, DEFAULT_TEMPLATE_DIR, NULL); copy_template_files_recursive (session, repo_id, "/", template_path); g_free (repo_id); g_free (template_path); return data; }
static void * get_repo_info_thread (void *data) { CcnetProcessor *processor = data; USE_PRIV; SeafRepo *repo; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, priv->repo_id); if (!repo) { seaf_warning ("Failed to get repo %s.\n", priv->repo_id); priv->success = FALSE; return data; } memcpy (priv->store_id, repo->store_id, 36); priv->repo_version = repo->version; priv->success = TRUE; seaf_repo_unref (repo); return data; }
GList * seaf_repo_manager_get_repo_list (SeafRepoManager *mgr, int start, int limit, gboolean *error) { char sql[256]; GList *id_list = NULL, *ptr; GList *ret = NULL; SeafRepo *repo; *error = FALSE; if (start == -1 && limit == -1) snprintf (sql, 256, "SELECT repo_id FROM Repo"); else snprintf (sql, 256, "SELECT repo_id FROM Repo LIMIT %d, %d", start, limit); if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, collect_repo_id, &id_list) < 0) goto error; for (ptr = id_list; ptr; ptr = ptr->next) { char *repo_id = ptr->data; repo = seaf_repo_manager_get_repo_ex (mgr, repo_id); if (repo) ret = g_list_prepend (ret, repo); } string_list_free (id_list); return ret; error: *error = TRUE; string_list_free (id_list); for (ptr = ret; ptr; ptr = ptr->next) { repo = ptr->data; seaf_repo_unref (repo); } return NULL; }
static void * check_tx (void *vprocessor) { CcnetProcessor *processor = vprocessor; USE_PRIV; char *user = NULL; char *repo_id = priv->repo_id; SeafRepo *repo = NULL; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { priv->rsp_code = g_strdup(SC_BAD_REPO); priv->rsp_msg = g_strdup(SS_BAD_REPO); goto out; } if (repo->version > 0 && priv->client_version < 6) { seaf_warning ("Client protocol version is %d, " "cannot sync version %d repo %s.\n", priv->client_version, repo->version, repo_id); priv->rsp_code = g_strdup(SC_PROTOCOL_MISMATCH); priv->rsp_msg = g_strdup(SS_PROTOCOL_MISMATCH); goto out; } if (decrypt_token (processor) < 0) { priv->rsp_code = g_strdup(SC_ACCESS_DENIED); priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); goto out; } user = seaf_repo_manager_get_email_by_token ( seaf->repo_mgr, repo_id, priv->token); if (!user) { priv->rsp_code = g_strdup(SC_ACCESS_DENIED); priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); goto out; } if (priv->type == CHECK_TX_TYPE_UPLOAD && 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; } char *perm = seaf_repo_manager_check_permission (seaf->repo_mgr, repo_id, user, NULL); if (!perm || (strcmp (perm, "r") == 0 && priv->type == CHECK_TX_TYPE_UPLOAD)) { priv->rsp_code = g_strdup(SC_ACCESS_DENIED); priv->rsp_msg = g_strdup(SS_ACCESS_DENIED); g_free (perm); goto out; } g_free (perm); /* Record the (token, email, <peer info>) information, <peer info> may * include peer_id, peer_ip, peer_name, etc. */ if (!seaf_repo_manager_token_peer_info_exists (seaf->repo_mgr, priv->token)) seaf_repo_manager_add_token_peer_info (seaf->repo_mgr, priv->token, processor->peer_id, priv->peer_addr, priv->peer_name, (gint64)time(NULL)); else seaf_repo_manager_update_token_peer_info (seaf->repo_mgr, priv->token, priv->peer_addr, (gint64)time(NULL)); get_branch_head (processor); /* Fill information for sending events. */ priv->user = g_strdup(user); if (repo->virtual_info) { memcpy (priv->orig_repo_id, repo->virtual_info->origin_repo_id, 36); priv->orig_path = g_strdup(repo->virtual_info->path); } else memcpy (priv->orig_repo_id, repo_id, 36); out: seaf_repo_unref (repo); g_free (user); return vprocessor; }
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* compute_repo_size (void *vjob) { RepoSizeJob *job = vjob; Scheduler *sched = job->sched; SeafRepo *repo = NULL; SeafCommit *head = NULL; char *cached_head_id = NULL; BlockList *bl; char *block_id; BlockMetadata *bmd; guint64 size = 0; repo = seaf_repo_manager_get_repo (sched->seaf->repo_mgr, job->repo_id); if (!repo) { g_warning ("[scheduler] failed to get repo %s.\n", job->repo_id); return vjob; } cached_head_id = get_cached_head_id (sched->seaf->db, job->repo_id); if (g_strcmp0 (cached_head_id, repo->head->commit_id) == 0) goto out; head = seaf_commit_manager_get_commit (sched->seaf->commit_mgr, repo->head->commit_id); if (!head) { g_warning ("[scheduler] failed to get head commit %s.\n", repo->head->commit_id); goto out; } /* Load block list first so that we don't need to count duplicate blocks. * We only calculate the size of the head commit. */ bl = block_list_new (); if (seaf_fs_manager_populate_blocklist (seaf->fs_mgr, head->root_id, bl) < 0) { block_list_free (bl); goto out; } int i; for (i = 0; i < bl->n_blocks; ++i) { block_id = g_ptr_array_index (bl->block_ids, i); bmd = seaf_block_manager_stat_block (sched->seaf->block_mgr, block_id); if (bmd) { size += bmd->size; g_free (bmd); } } block_list_free (bl); if (set_repo_size (sched->seaf->db, job->repo_id, repo->head->commit_id, size) < 0) g_warning ("[scheduler] failed to store repo size %s.\n", job->repo_id); out: seaf_repo_unref (repo); seaf_commit_unref (head); g_free (cached_head_id); return vjob; }
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 SeafRepo* get_available_repo (char *repo_id, gboolean repair) { GList *commit_list = NULL; GList *temp_list = NULL; SeafCommit *temp_commit = NULL; SeafBranch *branch = NULL; SeafRepo *repo = NULL; SeafVirtRepo *vinfo = NULL; gboolean io_error; seaf_message ("Scanning available commits...\n"); seaf_obj_store_foreach_obj (seaf->commit_mgr->obj_store, repo_id, 1, fsck_get_repo_commit, &commit_list); if (commit_list == NULL) { seaf_warning ("No available commits for repo %.8s, can't be repaired.\n", repo_id); return NULL; } commit_list = g_list_sort (commit_list, compare_commit_by_ctime); repo = seaf_repo_new (repo_id, NULL, NULL); if (repo == NULL) { seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", repo_id); goto out; } 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); seaf_virtual_repo_info_free (vinfo); } else { repo->is_virtual = FALSE; memcpy (repo->store_id, repo->id, 36); } for (temp_list = commit_list; temp_list; temp_list = temp_list->next) { temp_commit = temp_list->data; io_error = FALSE; if (!fsck_verify_seafobj (repo->store_id, 1, temp_commit->root_id, &io_error, VERIFY_DIR, repair)) { if (io_error) { seaf_repo_unref (repo); repo = NULL; goto out; } // fs object of this commit is corrupted, // continue to verify next continue; } branch = seaf_branch_new ("master", repo_id, temp_commit->commit_id); if (branch == NULL) { seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", repo_id); seaf_repo_unref (repo); repo = NULL; goto out; } repo->head = branch; seaf_repo_from_commit (repo, temp_commit); char time_buf[64]; strftime (time_buf, 64, "%Y-%m-%d %H:%M:%S", localtime((time_t *)&temp_commit->ctime)); seaf_message ("Find available commit %.8s(created at %s) for repo %.8s.\n", temp_commit->commit_id, time_buf, repo_id); break; } out: 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 repo; }
static void *merge_virtual_repo (void *vtask) { MergeTask *task = vtask; SeafRepoManager *mgr = seaf->repo_mgr; char *repo_id = task->repo_id; SeafVirtRepo *vinfo; SeafRepo *repo = NULL, *orig_repo = NULL; SeafCommit *head = NULL, *orig_head = NULL, *base = NULL; char *root = NULL, *orig_root = NULL, *base_root = NULL; char new_base_commit[41] = {0}; int ret = 0; /* repos */ repo = seaf_repo_manager_get_repo (mgr, repo_id); if (!repo) { seaf_warning ("Failed to get virt repo %.10s.\n", repo_id); ret = -1; goto out; } vinfo = repo->virtual_info; orig_repo = seaf_repo_manager_get_repo (mgr, vinfo->origin_repo_id); if (!orig_repo) { seaf_warning ("Failed to get orig repo %.10s.\n", vinfo->origin_repo_id); ret = -1; goto out; } /* commits */ head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!head) { seaf_warning ("Failed to get commit %s:%.8s.\n", repo->id, repo->head->commit_id); ret = -1; goto out; } orig_head = seaf_commit_manager_get_commit (seaf->commit_mgr, orig_repo->id, orig_repo->version, orig_repo->head->commit_id); if (!orig_head) { seaf_warning ("Failed to get commit %s:%.8s.\n", orig_repo->id, orig_repo->head->commit_id); ret = -1; goto out; } base = seaf_commit_manager_get_commit (seaf->commit_mgr, orig_repo->id, orig_repo->version, vinfo->base_commit); if (!base) { seaf_warning ("Failed to get commit %s:%.8s.\n", orig_repo->id, vinfo->base_commit); ret = -1; goto out; } /* fs roots */ root = head->root_id; base_root = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, orig_repo->store_id, orig_repo->version, base->root_id, vinfo->path, NULL); if (!base_root) { seaf_warning ("Cannot find seafdir for repo %.10s path %s.\n", vinfo->origin_repo_id, vinfo->path); ret = -1; goto out; } orig_root = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, orig_repo->store_id, orig_repo->version, orig_head->root_id, vinfo->path, NULL); if (!orig_root) { seaf_warning ("Cannot find seafdir for repo %.10s path %s.\n", vinfo->origin_repo_id, vinfo->path); ret = -1; goto out; } if (strcmp (root, orig_root) == 0) { /* Nothing to merge. */ seaf_debug ("Nothing to merge.\n"); } else if (strcmp (base_root, root) == 0) { /* Origin changed, virtual repo not changed. */ seaf_debug ("Origin changed, virtual repo not changed.\n"); ret = seaf_repo_manager_update_dir (mgr, repo_id, "/", orig_root, orig_head->creator_name, head->commit_id, NULL, NULL); if (ret < 0) { seaf_warning ("Failed to update root of virtual repo %.10s.\n", repo_id); goto out; } set_virtual_repo_base_commit_path (repo->id, orig_repo->head->commit_id, vinfo->path); } else if (strcmp (base_root, orig_root) == 0) { /* Origin not changed, virutal repo changed. */ seaf_debug ("Origin not changed, virutal repo changed.\n"); ret = seaf_repo_manager_update_dir (mgr, vinfo->origin_repo_id, vinfo->path, root, head->creator_name, orig_head->commit_id, new_base_commit, NULL); if (ret < 0) { seaf_warning ("Failed to update origin repo %.10s path %s.\n", vinfo->origin_repo_id, vinfo->path); goto out; } set_virtual_repo_base_commit_path (repo->id, new_base_commit, vinfo->path); /* Since origin repo is updated, we have to merge it with other * virtual repos if necessary. But we don't need to merge with * the current virtual repo again. */ seaf_repo_manager_cleanup_virtual_repos (mgr, vinfo->origin_repo_id); seaf_repo_manager_merge_virtual_repo (mgr, vinfo->origin_repo_id, repo_id); } else { /* Both origin and virtual repo are changed. */ seaf_debug ("Both origin and virtual repo are changed.\n"); MergeOptions opt; const char *roots[3]; memset (&opt, 0, sizeof(opt)); opt.n_ways = 3; memcpy (opt.remote_repo_id, repo_id, 36); memcpy (opt.remote_head, head->commit_id, 40); opt.do_merge = TRUE; roots[0] = base_root; /* base */ roots[1] = orig_root; /* head */ roots[2] = root; /* remote */ /* Merge virtual into origin */ if (seaf_merge_trees (orig_repo->store_id, orig_repo->version, 3, roots, &opt) < 0) { seaf_warning ("Failed to merge virtual repo %.10s.\n", repo_id); ret = -1; goto out; } seaf_debug ("Number of dirs visted in merge: %d.\n", opt.visit_dirs); /* Update virtual repo root. */ ret = seaf_repo_manager_update_dir (mgr, repo_id, "/", opt.merged_tree_root, orig_head->creator_name, head->commit_id, NULL, NULL); if (ret < 0) { seaf_warning ("Failed to update root of virtual repo %.10s.\n", repo_id); goto out; } /* Update origin repo path. */ ret = seaf_repo_manager_update_dir (mgr, vinfo->origin_repo_id, vinfo->path, opt.merged_tree_root, head->creator_name, orig_head->commit_id, new_base_commit, NULL); if (ret < 0) { seaf_warning ("Failed to update origin repo %.10s path %s.\n", vinfo->origin_repo_id, vinfo->path); goto out; } set_virtual_repo_base_commit_path (repo->id, new_base_commit, vinfo->path); seaf_repo_manager_cleanup_virtual_repos (mgr, vinfo->origin_repo_id); seaf_repo_manager_merge_virtual_repo (mgr, vinfo->origin_repo_id, repo_id); } out: seaf_repo_unref (repo); seaf_repo_unref (orig_repo); seaf_commit_unref (head); seaf_commit_unref (orig_head); seaf_commit_unref (base); g_free (base_root); g_free (orig_root); return vtask; }
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; }
static void enable_sync_repo (const char *repo_id) { SeafRepo *repo = NULL; SeafCommit *parent_commit = NULL; SeafCommit *new_commit = NULL; gboolean exists; if (!is_uuid_valid (repo_id)) { seaf_warning ("Invalid repo id %s.\n", repo_id); return; } exists = seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id); if (!exists) { seaf_warning ("Repo %.8s doesn't exist.\n", repo_id); return; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) return; if (!repo->repaired) { seaf_repo_unref (repo); return; } seaf_message ("Enabling sync repo %s.\n", repo_id); parent_commit = seaf_commit_manager_get_commit_compatible (seaf->commit_mgr, repo_id, repo->head->commit_id); if (!parent_commit) { seaf_warning ("Commit %s:%s is missing\n", repo_id, repo->head->commit_id); goto out; } new_commit = seaf_commit_new (NULL, repo_id, parent_commit->root_id, parent_commit->creator_name, parent_commit->creator_id, "Enable sync repo", 0); if (!new_commit) { seaf_warning ("Out of memory when create commit.\n"); goto out; } new_commit->parent_id = g_strdup (parent_commit->commit_id); seaf_repo_to_commit (repo, new_commit); new_commit->repaired = FALSE; if (seaf_commit_manager_add_commit (seaf->commit_mgr, new_commit) < 0) { seaf_warning ("Failed to save commit %.8s for repo %.8s.\n", new_commit->commit_id, repo_id); goto out; } seaf_branch_set_commit (repo->head, new_commit->commit_id); if (seaf_branch_manager_update_branch (seaf->branch_mgr, repo->head) < 0) { seaf_warning ("Failed to update head commit %.8s to repo %.8s.\n", new_commit->commit_id, repo_id); } else { seaf_message ("Enable sync repo %.8s success.\n", repo_id); } out: if (parent_commit) seaf_commit_unref (parent_commit); if (new_commit) seaf_commit_unref (new_commit); if (repo) seaf_repo_unref (repo); }
char * seaf_repo_manager_create_virtual_repo (SeafRepoManager *mgr, const char *origin_repo_id, const char *path, const char *repo_name, const char *repo_desc, const char *owner, const char *passwd, GError **error) { SeafRepo *origin_repo = NULL; SeafCommit *origin_head = NULL; char *repo_id = NULL; char *dir_id = NULL; char *orig_owner = NULL; if (seaf_repo_manager_is_virtual_repo (mgr, origin_repo_id)) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Cannot create sub-library from a sub-library"); return NULL; } repo_id = get_existing_virtual_repo (mgr, origin_repo_id, path); if (repo_id) { return repo_id; } origin_repo = seaf_repo_manager_get_repo (mgr, origin_repo_id); if (!origin_repo) { seaf_warning ("Failed to get origin repo %.10s\n", origin_repo_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Origin library not exists"); return NULL; } if (origin_repo->encrypted) { if (origin_repo->enc_version < 2) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Library encryption version must be higher than 2"); seaf_repo_unref (origin_repo); return NULL; } if (!passwd || passwd[0] == 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Password is not set"); seaf_repo_unref (origin_repo); return NULL; } if (seafile_verify_repo_passwd (origin_repo_id, passwd, origin_repo->magic, origin_repo->enc_version) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); seaf_repo_unref (origin_repo); return NULL; } } origin_head = seaf_commit_manager_get_commit (seaf->commit_mgr, origin_repo->id, origin_repo->version, origin_repo->head->commit_id); if (!origin_head) { seaf_warning ("Failed to get head commit %.8s of repo %s.\n", origin_repo->head->commit_id, origin_repo->id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Bad origin repo head"); goto error; } dir_id = seaf_fs_manager_get_seafdir_id_by_path (seaf->fs_mgr, origin_repo->store_id, origin_repo->version, origin_head->root_id, path, NULL); if (!dir_id) { seaf_warning ("Path %s doesn't exist or is not a dir in repo %.10s.\n", path, origin_repo_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad path"); goto error; } repo_id = gen_uuid(); /* Save virtual repo info before actually create the repo. */ if (save_virtual_repo_info (mgr, repo_id, origin_repo_id, path, origin_head->commit_id) < 0) { seaf_warning ("Failed to save virtual repo info for %.10s:%s", origin_repo_id, path); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Internal error"); goto error; } orig_owner = seaf_repo_manager_get_repo_owner (mgr, origin_repo_id); if (do_create_virtual_repo (mgr, origin_repo, repo_id, repo_name, repo_desc, dir_id, orig_owner, passwd, error) < 0) goto error; if (seaf_repo_manager_set_repo_owner (mgr, repo_id, orig_owner) < 0) { seaf_warning ("Failed to set repo owner for %.10s.\n", repo_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Failed to set repo owner."); goto error; } /* The size of virtual repo is non-zero at the beginning. */ update_repo_size (repo_id); seaf_repo_unref (origin_repo); seaf_commit_unref (origin_head); g_free (dir_id); g_free (orig_owner); return repo_id; error: seaf_repo_unref (origin_repo); seaf_commit_unref (origin_head); g_free (repo_id); g_free (dir_id); g_free (orig_owner); return NULL; }
static void * update_repo (void *vprocessor) { CcnetProcessor *processor = vprocessor; USE_PRIV; char *repo_id, *new_head; SeafRepo *repo = NULL; SeafCommit *new_commit = NULL, *base = NULL; repo_id = priv->repo_id; new_head = priv->new_head; 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; } /* Since this is the last step of upload procedure, commit should exist. */ new_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, new_head); if (!new_commit) { seaf_warning ("Failed to get commit %s for repo %s.\n", new_head, repo->id); priv->rsp_code = g_strdup (SC_BAD_COMMIT); priv->rsp_msg = g_strdup (SS_BAD_COMMIT); goto out; } base = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, new_commit->parent_id); if (!base) { seaf_warning ("Failed to get commit %s for repo %s.\n", new_commit->parent_id, repo->id); priv->rsp_code = g_strdup (SC_BAD_COMMIT); priv->rsp_msg = g_strdup (SS_BAD_COMMIT); 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; } if (fast_forward_or_merge (repo_id, base, new_commit) < 0) { priv->rsp_code = g_strdup(SC_SERVER_ERROR); priv->rsp_msg = g_strdup(SS_SERVER_ERROR); goto out; } seaf_repo_manager_cleanup_virtual_repos (seaf->repo_mgr, repo_id); seaf_repo_manager_merge_virtual_repo (seaf->repo_mgr, repo_id, NULL); out: seaf_repo_unref (repo); seaf_commit_unref (new_commit); seaf_commit_unref (base); if (!priv->rsp_code) { priv->rsp_code = g_strdup (SC_OK); priv->rsp_msg = g_strdup (SS_OK); } return vprocessor; }
static int fast_forward_or_merge (const char *repo_id, SeafCommit *base, SeafCommit *new_commit) { #define MAX_RETRY_COUNT 3 SeafRepo *repo = NULL; SeafCommit *current_head = NULL, *merged_commit = NULL; int retry_cnt = 0; int ret = 0; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("Repo %s doesn't exist.\n", repo_id); ret = -1; goto out; } retry: current_head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!current_head) { seaf_warning ("Failed to find head commit of %s.\n", repo_id); ret = -1; goto out; } /* Merge if base and head are not the same. */ if (strcmp (base->commit_id, current_head->commit_id) != 0) { MergeOptions opt; const char *roots[3]; char *desc = NULL; memset (&opt, 0, sizeof(opt)); opt.n_ways = 3; memcpy (opt.remote_repo_id, repo_id, 36); memcpy (opt.remote_head, new_commit->commit_id, 40); opt.do_merge = TRUE; roots[0] = base->root_id; /* base */ roots[1] = current_head->root_id; /* head */ roots[2] = new_commit->root_id; /* remote */ if (seaf_merge_trees (repo->store_id, repo->version, 3, roots, &opt) < 0) { seaf_warning ("Failed to merge.\n"); ret = -1; goto out; } if (!opt.conflict) desc = g_strdup("Auto merge by system"); else { desc = gen_merge_description (repo, opt.merged_tree_root, current_head->root_id, new_commit->root_id); if (!desc) desc = g_strdup("Auto merge by system"); } merged_commit = seaf_commit_new(NULL, repo->id, opt.merged_tree_root, new_commit->creator_name, EMPTY_SHA1, desc, 0); g_free (desc); merged_commit->parent_id = g_strdup (current_head->commit_id); merged_commit->second_parent_id = g_strdup (new_commit->commit_id); merged_commit->new_merge = TRUE; if (opt.conflict) merged_commit->conflict = TRUE; seaf_repo_to_commit (repo, merged_commit); if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged_commit) < 0) { seaf_warning ("Failed to add commit.\n"); ret = -1; goto out; } } else { seaf_commit_ref (new_commit); merged_commit = new_commit; } seaf_branch_set_commit(repo->head, merged_commit->commit_id); if (seaf_branch_manager_test_and_update_branch(seaf->branch_mgr, repo->head, current_head->commit_id) < 0) { seaf_repo_unref (repo); repo = NULL; seaf_commit_unref (current_head); current_head = NULL; seaf_commit_unref (merged_commit); merged_commit = NULL; repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("Repo %s doesn't exist.\n", repo_id); ret = -1; goto out; } if (++retry_cnt <= MAX_RETRY_COUNT) { seaf_message ("Concurrent branch update, retry.\n"); /* Sleep random time between 100 and 1000 millisecs. */ USLEEP (g_random_int_range(1, 11) * 100 * 1000); goto retry; } else { seaf_warning ("Stop retrying.\n"); ret = -1; goto out; } } out: seaf_commit_unref (current_head); seaf_commit_unref (merged_commit); seaf_repo_unref (repo); return ret; }
GList * seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr, const char *repo_id, const char *dir_path, const char *dir_id, const char *user, int offset, int limit, GError **error) { SeafRepo *repo; char *perm = NULL; SeafDir *dir; SeafDirent *dent; SeafileDirent *d; GList *res = NULL; GList *p; if (!repo_id || !is_uuid_valid(repo_id) || dir_id == NULL || !user) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); return NULL; } perm = seaf_repo_manager_check_permission (mgr, repo_id, user, error); if (!perm) { if (*error == NULL) g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Access denied"); return NULL; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad repo id"); g_free (perm); return NULL; } dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, repo->store_id, repo->version, dir_id); if (!dir) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); seaf_repo_unref (repo); g_free (perm); return NULL; } dir->entries = g_list_sort (dir->entries, comp_dirent_func); if (offset < 0) { offset = 0; } int index = 0; for (p = dir->entries; p != NULL; p = p->next, index++) { if (index < offset) { continue; } if (limit > 0) { if (index >= offset + limit) break; } dent = p->data; d = g_object_new (SEAFILE_TYPE_DIRENT, "obj_id", dent->id, "obj_name", dent->name, "mode", dent->mode, "version", dent->version, "mtime", dent->mtime, "size", dent->size, "permission", perm, NULL); res = g_list_prepend (res, d); } seaf_dir_free (dir); seaf_repo_unref (repo); g_free (perm); res = g_list_reverse (res); return res; }
static void repair_repos (GList *repo_id_list, gboolean repair) { GList *ptr; char *repo_id; SeafRepo *repo; gboolean exists; gboolean reset; gboolean io_error; for (ptr = repo_id_list; ptr; ptr = ptr->next) { reset = FALSE; repo_id = ptr->data; seaf_message ("Running fsck for repo %s.\n", repo_id); if (!is_uuid_valid (repo_id)) { seaf_warning ("Invalid repo id %s.\n", repo_id); goto next; } exists = seaf_repo_manager_repo_exists (seaf->repo_mgr, repo_id); if (!exists) { seaf_warning ("Repo %.8s doesn't exist.\n", repo_id); goto next; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { seaf_message ("Repo %.8s HEAD commit is corrupted, " "need to restore to an old version.\n", repo_id); repo = get_available_repo (repo_id, repair); if (!repo) { goto next; } reset = TRUE; } else { SeafCommit *commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!commit) { seaf_warning ("Failed to get head commit %s of repo %s\n", repo->head->commit_id, repo->id); seaf_repo_unref (repo); goto next; } io_error = FALSE; if (!fsck_verify_seafobj (repo->store_id, repo->version, commit->root_id, &io_error, VERIFY_DIR, repair)) { if (io_error) { seaf_commit_unref (commit); seaf_repo_unref (repo); goto next; } else { // root fs object is corrupted, get available commit seaf_message ("Repo %.8s HEAD commit is corrupted, " "need to restore to an old version.\n", repo_id); seaf_commit_unref (commit); seaf_repo_unref (repo); repo = get_available_repo (repo_id, repair); if (!repo) { goto next; } reset = TRUE; } } else { // head commit is available seaf_commit_unref (commit); } } check_and_recover_repo (repo, reset, repair); seaf_repo_unref (repo); next: seaf_message ("Fsck finished for repo %.8s.\n\n", repo_id); } }