/* * Comprehensive repo access permission checker. * * Returns read/write permission. */ char * seaf_repo_manager_check_permission (SeafRepoManager *mgr, const char *repo_id, const char *user, GError **error) { SeafVirtRepo *vinfo; char *owner = NULL; char *permission = NULL; /* This is a virtual repo.*/ vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); if (vinfo) { permission = check_virtual_repo_permission (mgr, repo_id, vinfo->origin_repo_id, user, error); goto out; } owner = seaf_repo_manager_get_repo_owner (mgr, repo_id); if (owner != NULL) { if (strcmp (owner, user) == 0) permission = g_strdup("rw"); else permission = check_repo_share_permission (mgr, repo_id, user); } out: seaf_virtual_repo_info_free (vinfo); g_free (owner); return permission; }
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; }
int seaf_quota_manager_check_quota_with_delta (SeafQuotaManager *mgr, const char *repo_id, gint64 delta) { SeafVirtRepo *vinfo; const char *r_repo_id = repo_id; char *user = NULL; gint64 quota, usage; int ret = 0; /* If it's a virtual repo, check quota to origin repo. */ vinfo = seaf_repo_manager_get_virtual_repo_info (seaf->repo_mgr, repo_id); if (vinfo) r_repo_id = vinfo->origin_repo_id; user = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, r_repo_id); if (user != NULL) { quota = seaf_quota_manager_get_user_quota (mgr, user); } else { seaf_warning ("Repo %s has no owner.\n", r_repo_id); ret = -1; goto out; } if (quota == INFINITE_QUOTA) goto out; usage = seaf_quota_manager_get_user_usage (mgr, user); if (usage < 0) { ret = -1; goto out; } if (delta != 0) { usage += delta; } if (usage >= quota) { ret = 1; } out: seaf_virtual_repo_info_free (vinfo); g_free (user); return ret; }
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; }
int seaf_repo_manager_set_repo_history_limit (SeafRepoManager *mgr, const char *repo_id, int days) { SeafVirtRepo *vinfo; SeafDB *db = mgr->seaf->db; char sql[256]; vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); if (vinfo) { seaf_virtual_repo_info_free (vinfo); return 0; } if (seaf_db_type(db) == SEAF_DB_TYPE_PGSQL) { gboolean err; snprintf(sql, sizeof(sql), "SELECT repo_id FROM RepoHistoryLimit " "WHERE repo_id='%s'", repo_id); if (seaf_db_check_for_existence(db, sql, &err)) snprintf(sql, sizeof(sql), "UPDATE RepoHistoryLimit SET days=%d" "WHERE repo_id='%s'", days, repo_id); else snprintf(sql, sizeof(sql), "INSERT INTO RepoHistoryLimit VALUES " "('%s', %d)", repo_id, days); if (err) return -1; return seaf_db_query(db, sql); } else { snprintf (sql, sizeof(sql), "REPLACE INTO RepoHistoryLimit VALUES ('%s', %d)", repo_id, days); if (seaf_db_query (db, sql) < 0) return -1; } return 0; }
int seaf_repo_manager_get_repo_history_limit (SeafRepoManager *mgr, const char *repo_id) { SeafVirtRepo *vinfo; const char *r_repo_id = repo_id; char sql[256]; int per_repo_days = -1; vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); if (vinfo) r_repo_id = vinfo->origin_repo_id; snprintf (sql, sizeof(sql), "SELECT days FROM RepoHistoryLimit WHERE repo_id='%s'", r_repo_id); seaf_virtual_repo_info_free (vinfo); /* We don't use seaf_db_get_int() because we need to differ DB error * from not exist. * We can't just return global config value if DB error occured, * since the global value may be smaller than per repo one. * This can lead to data lose in GC. */ if (seaf_db_foreach_selected_row (mgr->seaf->db, sql, get_limit, &per_repo_days) < 0) { seaf_warning ("DB error.\n"); return -1; } /* If per repo value is not set, return the global one. */ if (per_repo_days < 0) return mgr->seaf->keep_history_days; return per_repo_days; }
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; }
int seaf_quota_manager_check_quota (SeafQuotaManager *mgr, const char *repo_id) { SeafVirtRepo *vinfo; const char *r_repo_id = repo_id; char *user = NULL; int org_id; gint64 quota, usage; int ret = 0; /* If it's a virtual repo, check quota to origin repo. */ vinfo = seaf_repo_manager_get_virtual_repo_info (seaf->repo_mgr, repo_id); if (vinfo) r_repo_id = vinfo->origin_repo_id; user = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, r_repo_id); if (user != NULL) { quota = seaf_quota_manager_get_user_quota (mgr, user); } else if (seaf->cloud_mode) { org_id = seaf_repo_manager_get_repo_org (seaf->repo_mgr, r_repo_id); if (org_id < 0) { seaf_warning ("Repo %s has no owner.\n", r_repo_id); ret = -1; goto out; } quota = seaf_quota_manager_get_org_quota (mgr, org_id); } else { seaf_warning ("Repo %s has no owner.\n", r_repo_id); ret = -1; goto out; } if (quota == INFINITE_QUOTA) goto out; if (user) { if (!mgr->calc_share_usage) { usage = seaf_quota_manager_get_user_usage (mgr, user); } else { gint64 my_usage, share_usage; share_usage = seaf_quota_manager_get_user_share_usage (mgr, user); if (share_usage < 0) { ret = -1; goto out; } my_usage = seaf_quota_manager_get_user_usage (mgr, user); if (my_usage < 0) { ret = -1; goto out; } usage = my_usage + share_usage; } } else usage = seaf_quota_manager_get_org_usage (mgr, org_id); if (usage < 0 || usage >= quota) ret = -1; out: seaf_virtual_repo_info_free (vinfo); g_free (user); return ret; }
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; }