Exemple #1
0
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;
}
Exemple #2
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);
    }
}
Exemple #3
0
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;
}
Exemple #4
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;
}
Exemple #5
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;
}
Exemple #6
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;
}
Exemple #7
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);
}
Exemple #8
0
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;
}
Exemple #9
0
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;
}
Exemple #10
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;
}
Exemple #11
0
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;
}
Exemple #12
0
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;
}
Exemple #13
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;
}
Exemple #14
0
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;
}
Exemple #15
0
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;
}
Exemple #16
0
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;
}
Exemple #17
0
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;    
}
Exemple #19
0
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;
}
Exemple #20
0
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;
}
Exemple #21
0
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;
}
Exemple #22
0
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;
}
Exemple #23
0
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;
}
Exemple #24
0
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;    
}
Exemple #25
0
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);
}
Exemple #26
0
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;
}
Exemple #29
0
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;
}
Exemple #30
0
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);
    }
}