Пример #1
0
static inline void
transition_sync_state (SyncTask *task, int new_state)
{
    g_assert (new_state >= 0 && new_state < SYNC_STATE_NUM);

    if (task->state != new_state) {
        if (!task->quiet &&
            !(task->state == SYNC_STATE_DONE && new_state == SYNC_STATE_INIT) &&
            !(task->state == SYNC_STATE_INIT && new_state == SYNC_STATE_DONE)) {
            seaf_message ("Repo '%s' sync state transition from '%s' to '%s'.\n",
                          task->repo->name,
                          sync_state_str[task->state],
                          sync_state_str[new_state]);
        }

        if ((task->state == SYNC_STATE_MERGE || task->state == SYNC_STATE_UPLOAD) &&
            new_state == SYNC_STATE_DONE &&
            need_notify_sync(task->repo))
        {
            GString *buf = g_string_new (NULL);
            g_string_append_printf (buf, "%s\t%s",
                                    task->repo->name, task->repo->id);
            seaf_mq_manager_publish_notification (seaf->mq_mgr,
                                                  "sync.done",
                                                  buf->str);
            g_string_free (buf, TRUE);
        }

        task->state = new_state;
        if (new_state == SYNC_STATE_DONE || 
            new_state == SYNC_STATE_CANCELED ||
            new_state == SYNC_STATE_ERROR) {
            task->info->in_sync = FALSE;
            --(task->mgr->n_running_tasks);
            if (new_state == SYNC_STATE_ERROR)
                task->info->err_cnt++;
            else
                task->info->err_cnt = 0;
        }
    }
}
Пример #2
0
static int
start_ccnet_server ()
{
    if (!ctl->config_dir)
        return -1;

    seaf_message ("starting ccnet-server ...\n");

    char *argv[] = {
        "ccnet-server",
        "-c", ctl->config_dir,
        "-d",
        "-P", ctl->pidfile[PID_CCNET],
        NULL};
    
    int pid = spawn_process (argv);
    if (pid <= 0) {
        seaf_warning ("Failed to spawn ccnet-server\n");
        return -1;
    }

    return 0;
}
Пример #3
0
static void
calculate_send_object_list_done (void *vdata)
{
    CcnetProcessor *processor = vdata;
    USE_PRIV;

    if (!priv->calc_success) {
        ccnet_processor_send_response (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    if (priv->send_obj_list == NULL) {
        seaf_message ("No fs objects to put. Done.\n");
        ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0);
        ccnet_processor_done (processor, TRUE);
        return;
    }

    send_object_list_segments (processor);

    processor->state = SEND_OBJECTS;
}
Пример #4
0
static int
start_seaf_monitor ()
{
    if (!ctl->config_dir || !ctl->seafile_dir)
        return -1;

    seaf_message ("starting seaf-mon ...\n");

    char *argv[] = {
        "seaf-mon",
        "-c", ctl->config_dir,
        "-d", ctl->seafile_dir,
        "-P", ctl->pidfile[PID_MONITOR],
        NULL};
    
    int pid = spawn_process (argv);
    if (pid <= 0) {
        seaf_warning ("Failed to spawn seaf-mon\n");
        return -1;
    }

    return 0;
}
Пример #5
0
/*
 * check and recover repo, for curropted file or folder set it empty
 */
static void
check_and_recover_repo (SeafRepo *repo, gboolean reset, gboolean repair)
{
    FsckData fsck_data;
    SeafCommit *rep_commit;

    seaf_message ("Checking file system integrity of repo %s(%.8s)...\n",
                  repo->name, repo->id);

    rep_commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id,
                                                 repo->version, repo->head->commit_id);

    memset (&fsck_data, 0, sizeof(fsck_data));
    fsck_data.repair = repair;
    fsck_data.repo = repo;
    fsck_data.existing_blocks = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                       g_free, NULL);

    char *root_id = fsck_check_dir_recursive (rep_commit->root_id, "/", &fsck_data);
    g_hash_table_destroy (fsck_data.existing_blocks);
    if (root_id == NULL)
        return;

    if (repair) {
        if (strcmp (root_id, rep_commit->root_id) != 0) {
            // some fs objects curropted for the head commit,
            // create new head commit using the new root_id
            reset_commit_to_repair (repo, rep_commit, root_id);
        } else if (reset) {
            // for reset commit but fs objects not curropted, also create a repaired commit
            reset_commit_to_repair (repo, rep_commit, rep_commit->root_id);
        }
    }

    g_free (root_id);
    seaf_commit_unref (rep_commit);
}
Пример #6
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);
    }
}
Пример #7
0
int
main(int argc, char *argv[])
{
    evbase_t *evbase = NULL;
    evhtp_t *htp = NULL;
    int daemon_mode = 1;
    int c;
    char *logfile = NULL;
    char *ccnet_debug_level_str = "info";
    char *http_debug_level_str = "debug";
    const char *debug_str = NULL;

    config_dir = DEFAULT_CONFIG_DIR;

    while ((c = getopt_long(argc, argv,
                short_opts, long_opts, NULL)) != EOF) {
        switch (c) {
        case 'h':
            usage();
            exit(0);
        case 'v':
            exit(-1);
            break;
        case 'c':
            config_dir = strdup(optarg);
            break;
        case 'd':
            seafile_dir = strdup(optarg);
            break;
        case 't':
            num_threads = atoi(optarg);
            break;
        case 'f':
            daemon_mode = 0;
            break;
        case 'l':
            logfile = g_strdup(optarg);
            break;
        case 'g':
            ccnet_debug_level_str = optarg;
            break;
        case 'G':
            http_debug_level_str = optarg;
            break;
        case 'D':
            debug_str = optarg;
            break;
        default:
            usage();
            exit(-1);
        }
    }

#ifndef WIN32
    if (daemon_mode)
        daemon(1, 0);
#endif

    g_type_init();

    ccnet_client = ccnet_client_new();
    if ((ccnet_client_load_confdir(ccnet_client, config_dir)) < 0) {
        g_warning ("Read config dir error\n");
        return -1;
    }

    if (seafile_dir == NULL)
        seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
    if (logfile == NULL)
        logfile = g_build_filename (seafile_dir, "http.log", NULL);

    seaf = seafile_session_new (seafile_dir, ccnet_client);
    if (!seaf) {
        g_warning ("Failed to create seafile session.\n");
        exit (1);
    }
    if (seafile_session_init(seaf) < 0)
        exit (1);

    seaf->client_pool = ccnet_client_pool_new (config_dir);

    if (!debug_str)
        debug_str = g_getenv("SEAFILE_DEBUG");
    seafile_debug_set_flags_string (debug_str);

    if (seafile_log_init (logfile, ccnet_debug_level_str,
                          http_debug_level_str) < 0) {
        g_warning ("Failed to init log.\n");
        exit (1);
    }

    load_httpserver_config (seaf);
    if (use_https) {
        seaf_message ("port = %d, https = true, pemfile = %s, privkey = %s\n",
                      bind_port, pemfile, privkey);
    } else {
        seaf_message ("port = %d, https = false\n", bind_port);
    }

    evbase = event_base_new();
    htp = evhtp_new(evbase, NULL);

    if (pemfile != NULL) {
        evhtp_ssl_cfg_t scfg;

        memset (&scfg, 0, sizeof(scfg));

        scfg.pemfile        = pemfile;
        scfg.privfile       = privkey;
        scfg.scache_type    = evhtp_ssl_scache_type_internal;
        scfg.scache_timeout = 5000;

        evhtp_ssl_init (htp, &scfg);
    }

    if (access_file_init (htp) < 0)
        exit (1);

    if (upload_file_init (htp) < 0)
        exit (1);

    evhtp_set_gencb(htp, default_cb, NULL);

    evhtp_use_threads(htp, NULL, num_threads, NULL);

    if (evhtp_bind_socket(htp, bind_addr, bind_port, 128) < 0) {
        g_warning ("Could not bind socket: %s\n", strerror(errno));
        exit(-1);
    }

    event_base_loop(evbase, 0);

    return 0;
}
Пример #8
0
int
main(int argc, char *argv[])
{
    int c;
    gboolean repair = FALSE;
    gboolean esync = FALSE;
    char *export_path = NULL;

#ifdef WIN32
    argv = get_argv_utf8 (&argc);
#endif

    config_dir = DEFAULT_CONFIG_DIR;

    while ((c = getopt_long(argc, argv,
                short_opts, long_opts, NULL)) != EOF) {
        switch (c) {
        case 'h':
            usage();
            exit(0);
        case 'v':
            exit(-1);
            break;
        case 'r':
            repair = TRUE;
            break;
        case 'e':
            esync = TRUE;
            break;
        case 'E':
            export_path = strdup(optarg);
            break;
        case 'c':
            config_dir = strdup(optarg);
            break;
        case 'd':
            seafile_dir = strdup(optarg);
            break;
        default:
            usage();
            exit(-1);
        }
    }

#if !GLIB_CHECK_VERSION(2, 35, 0)
    g_type_init();
#endif

    if (seafile_log_init ("-", "info", "debug") < 0) {
        seaf_warning ("Failed to init log.\n");
        exit (1);
    }

    ccnet_client = ccnet_client_new();
    if ((ccnet_client_load_confdir(ccnet_client, config_dir)) < 0) {
        seaf_warning ("Read config dir error\n");
        return -1;
    }

    if (seafile_dir == NULL)
        seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);

#ifdef __linux__
    uid_t current_user, seafile_user;
    if (!check_user (seafile_dir, &current_user, &seafile_user)) {
        seaf_message ("Current user (%u) is not the user for running "
                      "seafile server (%u). Unable to run fsck.\n",
                      current_user, seafile_user);
        exit(1);
    }
#endif
    
    seaf = seafile_session_new(seafile_dir, ccnet_client);
    if (!seaf) {
        seaf_warning ("Failed to create seafile session.\n");
        exit (1);
    }

    GList *repo_id_list = NULL;
    int i;
    for (i = optind; i < argc; i++)
        repo_id_list = g_list_append (repo_id_list, g_strdup(argv[i]));

    if (export_path) {
        export_file (repo_id_list, seafile_dir, export_path);
    } else {
        seaf_fsck (repo_id_list, repair, esync);
    }

    return 0;
}
Пример #9
0
char *
seaf_clone_manager_add_download_task (SeafCloneManager *mgr, 
                                      const char *repo_id,
                                      int repo_version,
                                      const char *peer_id,
                                      const char *repo_name,
                                      const char *token,
                                      const char *passwd,
                                      const char *magic,
                                      int enc_version,
                                      const char *random_key,
                                      const char *wt_parent,
                                      const char *peer_addr,
                                      const char *peer_port,
                                      const char *email,
                                      const char *more_info,
                                      GError **error)
{
    SeafRepo *repo;
    char *wt_tmp, *worktree;
    char *ret;

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

#ifdef USE_GPL_CRYPTO
    if (repo_version == 0 || (passwd && enc_version < 2)) {
        seaf_warning ("Don't support syncing old version libraries.\n");
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
                     "Don't support syncing old version libraries");
        return NULL;
    }
#endif

    if (passwd &&
        !check_encryption_args (magic, enc_version, random_key, error))
        return NULL;

    /* After a repo was unsynced, the sync task may still be blocked in the
     * network, so the repo is not actually deleted yet.
     * In this case just return an error to the user.
     */
    SyncInfo *sync_info = seaf_sync_manager_get_sync_info (seaf->sync_mgr,
                                                           repo_id);
    if (sync_info && sync_info->in_sync) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Repo already exists");
        return NULL;
    }

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);

    if (repo != NULL && repo->head != NULL) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Repo already exists");
        return NULL;
    }

    if (is_duplicate_task (mgr, repo_id)) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, 
                     "Task is already in progress");
        return NULL;
    }

    if (passwd &&
        seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version) < 0) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Incorrect password");
        return NULL;
    }

    IgnoreReason reason;
    if (should_ignore_on_checkout (repo_name, &reason)) {
        if (reason == IGNORE_REASON_END_SPACE_PERIOD)
            g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
                         "Library name ends with space or period character");
        else
            g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
                         "Library name contains invalid characters such as ':', '*', '|', '?'");
        return NULL;
    }

    wt_tmp = g_build_filename (wt_parent, repo_name, NULL);

    worktree = make_worktree_for_download (mgr, wt_tmp, error);
    if (!worktree) {
        g_free (wt_tmp);
        return NULL;
    }

    /* If a repo was unsynced and then downloaded again, there may be
     * a garbage record for this repo. We don't want the downloaded blocks
     * be removed by GC.
     */
    if (repo_version > 0)
        seaf_repo_manager_remove_garbage_repo (seaf->repo_mgr, repo_id);

    /* Delete orphan information in the db in case the repo was corrupt. */
    if (!repo)
        seaf_repo_manager_remove_repo_ondisk (seaf->repo_mgr, repo_id, FALSE);

    ret = add_task_common (mgr, repo_id, repo_version,
                           peer_id, repo_name, token, passwd,
                           enc_version, random_key,
                           worktree, peer_addr, peer_port,
                           email, more_info, TRUE, error);
    g_free (worktree);
    g_free (wt_tmp);

    return ret;
}
Пример #10
0
char *
seaf_clone_manager_add_task (SeafCloneManager *mgr, 
                             const char *repo_id,
                             int repo_version,
                             const char *peer_id,
                             const char *repo_name,
                             const char *token,
                             const char *passwd,
                             const char *magic,
                             int enc_version,
                             const char *random_key,
                             const char *worktree_in,
                             const char *peer_addr,
                             const char *peer_port,
                             const char *email,
                             const char *more_info,
                             GError **error)
{
    SeafRepo *repo;
    char *worktree;
    char *ret;
    gboolean sync_wt_name = FALSE;

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

#ifdef USE_GPL_CRYPTO
    if (repo_version == 0 || (passwd && enc_version < 2)) {
        seaf_warning ("Don't support syncing old version libraries.\n");
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
                     "Don't support syncing old version libraries");
        return NULL;
    }
#endif

    if (passwd &&
        !check_encryption_args (magic, enc_version, random_key, error))
        return NULL;

    /* After a repo was unsynced, the sync task may still be blocked in the
     * network, so the repo is not actually deleted yet.
     * In this case just return an error to the user.
     */
    SyncInfo *sync_info = seaf_sync_manager_get_sync_info (seaf->sync_mgr,
                                                           repo_id);
    if (sync_info && sync_info->in_sync) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Repo already exists");
        return NULL;
    }

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);

    if (repo != NULL && repo->head != NULL) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Repo already exists");
        return NULL;
    }   

    if (is_duplicate_task (mgr, repo_id)) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, 
                     "Task is already in progress");
        return NULL;
    }

    if (passwd &&
        seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version) < 0) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Incorrect password");
        return NULL;
    }

    if (!seaf_clone_manager_check_worktree_path (mgr, worktree_in, error))
        return NULL;

    /* Return error if worktree_in conflicts with another repo or
     * is not a directory.
     */
    worktree = make_worktree (mgr, worktree_in, FALSE, error);
    if (!worktree) {
        return NULL;
    }

    /* Don't sync worktree folder name with library name later if they're not the same
     * at the beginning.
     */
    sync_wt_name = is_wt_repo_name_same (worktree, repo_name);

    /* If a repo was unsynced and then downloaded again, there may be
     * a garbage record for this repo. We don't want the downloaded blocks
     * be removed by GC.
     */
    if (repo_version > 0)
        seaf_repo_manager_remove_garbage_repo (seaf->repo_mgr, repo_id);

    /* Delete orphan information in the db in case the repo was corrupt. */
    if (!repo)
        seaf_repo_manager_remove_repo_ondisk (seaf->repo_mgr, repo_id, FALSE);

    ret = add_task_common (mgr, repo_id, repo_version,
                           peer_id, repo_name, token, passwd,
                           enc_version, random_key,
                           worktree, peer_addr, peer_port,
                           email, more_info,
                           sync_wt_name,
                           error);
    g_free (worktree);

    return ret;
}
Пример #11
0
static void
handle_response (CcnetProcessor *processor,
                 char *code, char *code_msg,
                 char *content, int clen)
{
    SeafileCheckTxV3Proc *proc = (SeafileCheckTxV3Proc *)processor;
    TransferTask *task = proc->task;

    if (strncmp(code, SC_OK, 3) == 0) {
        if (proc->type == CHECK_TX_TYPE_UPLOAD)
            handle_upload_ok (processor, task, content, clen);
        else
            handle_download_ok (processor, task, content, clen);
    } else if (strncmp (code, SC_PUT_TOKEN, 3) == 0) {
        /* In LAN sync, we don't use session token. */
        if (clen == 0) {
            ccnet_processor_done (processor, TRUE);
            return;
        }

        if (content[clen-1] != '\0') {
            seaf_warning ("Bad response content.\n");
            transfer_task_set_error (task, TASK_ERR_UNKNOWN);
            ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS,
                                         NULL, 0);
            ccnet_processor_done (processor, FALSE);
            return;
        }
        task->session_token = g_strdup (content);

        ccnet_processor_send_update (processor, SC_GET_VERSION, SS_GET_VERSION,
                                     NULL, 0);
    } else if (strncmp (code, SC_VERSION, 3) == 0) {
        int server_version = atoi(content);
        /* There is a bug in block transfer in version 4, so it's not supported. */
        if (server_version == 4)
            server_version = 3;
        task->protocol_version = MIN (server_version, CURRENT_PROTO_VERSION);

        if (task->protocol_version < 5) {
            seaf_warning ("Deprecated server protocol version %d.\n",
                          task->protocol_version);
            transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
            ccnet_processor_done (processor, FALSE);
            return;
        }

        if (task->repo_version == 0)
            task->protocol_version = 5;
        else if (task->protocol_version == 5) {
            /* Syncing version 1 reop with 2.x server is not supported.
             * Actually version 1 repo can only be created by 3.x servers.
             * If version 1 repos exist on 2.x server, it means a down-grade
             * operation has been performed, which is not supported.
             */
            seaf_warning ("Syncing version %d repo with protocol version %d "
                          "is not supported.\n",
                          task->repo_version, task->protocol_version);
            transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
            ccnet_processor_done (processor, FALSE);
            return;
        }

        if (task->protocol_version >= 7 && !task->server_side_merge)
            task->protocol_version = 6;

        if (task->protocol_version >= 7 && task->type == TASK_TYPE_DOWNLOAD)
            set_download_head_info (task);

        seaf_message ("repo version is %d, protocol version is %d.\n",
                      task->repo_version, task->protocol_version);
        ccnet_processor_done (processor, TRUE);
    } else {
        seaf_warning ("[check tx v3] Bad response: %s %s", code, code_msg);
        if (strncmp(code, SC_ACCESS_DENIED, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
        else if (strncmp(code, SC_QUOTA_ERROR, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_CHECK_QUOTA);
        else if (strncmp(code, SC_QUOTA_FULL, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_QUOTA_FULL);
        else if (strncmp(code, SC_PROTOCOL_MISMATCH, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_PROTOCOL_VERSION);
        else if (strncmp(code, SC_BAD_REPO, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_BAD_REPO_ID);
        else
            transfer_task_set_error (task, TASK_ERR_UNKNOWN);
        ccnet_processor_done (processor, FALSE);
    }
}
Пример #12
0
static int
read_seafdav_config()
{
    int ret = 0;
    char *seafdav_conf = NULL;
    GKeyFile *key_file = NULL;
    GError *error = NULL;

    seafdav_conf = g_build_filename(ctl->central_config_dir, "seafdav.conf", NULL);
    if (!g_file_test(seafdav_conf, G_FILE_TEST_EXISTS)) {
        goto out;
    }

    key_file = g_key_file_new ();
    if (!g_key_file_load_from_file (key_file, seafdav_conf,
                                    G_KEY_FILE_KEEP_COMMENTS, NULL)) {
        seaf_warning("Failed to load seafdav.conf\n");
        ret = -1;
        goto out;
    }

    /* enabled */
    ctl->seafdav_config.enabled = g_key_file_get_boolean(key_file, "WEBDAV", "enabled", &error);
    if (error != NULL) {
        if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
            seaf_message ("Error when reading WEBDAV.enabled, use default value 'false'\n");
        }
        ctl->seafdav_config.enabled = FALSE;
        g_clear_error (&error);
        goto out;
    }

    if (!ctl->seafdav_config.enabled) {
        goto out;
    }

    /* fastcgi */
    ctl->seafdav_config.fastcgi = g_key_file_get_boolean(key_file, "WEBDAV", "fastcgi", &error);
    if (error != NULL) {
        if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
            seaf_message ("Error when reading WEBDAV.fastcgi, use default value 'false'\n");
        }
        ctl->seafdav_config.fastcgi = FALSE;
        g_clear_error (&error);
    }

    /* host */
    char *host = seaf_key_file_get_string (key_file, "WEBDAV", "host", &error);
    if (error != NULL) {
        g_clear_error(&error);
        ctl->seafdav_config.host = g_strdup(ctl->seafdav_config.fastcgi ? "localhost" : "0.0.0.0");
    } else {
        ctl->seafdav_config.host = host;
    }

    /* port */
    ctl->seafdav_config.port = g_key_file_get_integer(key_file, "WEBDAV", "port", &error);
    if (error != NULL) {
        if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
            seaf_message ("Error when reading WEBDAV.port, use deafult value 8080\n");
        }
        ctl->seafdav_config.port = 8080;
        g_clear_error (&error);
    }

    if (ctl->seafdav_config.port <= 0 || ctl->seafdav_config.port > 65535) {
        seaf_warning("Failed to load seafdav config: invalid port %d\n", ctl->seafdav_config.port);
        ret = -1;
        goto out;
    }

out:
    if (key_file) {
        g_key_file_free (key_file);
    }
    g_free (seafdav_conf);

    return ret;
}
Пример #13
0
int
main (int argc, char **argv)
{
    int c;
    char *config_dir = DEFAULT_CONFIG_DIR;
    char *seafile_dir = NULL;
    char *worktree_dir = NULL;
    char *logfile = NULL;
    const char *debug_str = NULL;
    int daemon_mode = 0;
    CcnetClient *client;
    char *ccnet_debug_level_str = "info";
    char *seafile_debug_level_str = "debug";

#ifdef WIN32
    LoadLibraryA ("exchndl.dll");

    argv = get_argv_utf8 (&argc);
#endif

    while ((c = getopt_long (argc, argv, short_options, 
                             long_options, NULL)) != EOF)
    {
        switch (c) {
        case 'h':
            usage();
            exit (1);
            break;
        case 'v':
            exit (1);
            break;
        case 'c':
            config_dir = optarg;
            break;
        case 'd':
            seafile_dir = g_strdup(optarg);
            break;
        case 'b':
            daemon_mode = 1;
            break;
        case 'D':
            debug_str = optarg;
            break;
        case 'w':
            worktree_dir = g_strdup(optarg);
            break;
        case 'l':
            logfile = g_strdup(optarg);
            break;
        case 'g':
            ccnet_debug_level_str = optarg;
            break;
        case 'G':
            seafile_debug_level_str = optarg;
            break;
        default:
            usage ();
            exit (1);
        }
    }

    argc -= optind;
    argv += optind;

#ifndef WIN32
    if (daemon_mode) {
#ifndef __APPLE__
        daemon (1, 0);
#else   /* __APPLE */
        /* daemon is deprecated under APPLE
         * use fork() instead
         * */
        switch (fork ()) {
          case -1:
              seaf_warning ("Failed to daemonize");
              exit (-1);
              break;
          case 0:
              /* all good*/
              break;
          default:
              /* kill origin process */
              exit (0);
        }
#endif  /* __APPLE */
    }
#endif /* !WIN32 */

    cdc_init ();

#if !GLIB_CHECK_VERSION(2, 35, 0)
    g_type_init();
#endif
#if !GLIB_CHECK_VERSION(2, 31, 0)
    g_thread_init(NULL);
#endif

    if (!debug_str)
        debug_str = g_getenv("SEAFILE_DEBUG");
    seafile_debug_set_flags_string (debug_str);

    if (logfile == NULL)
        logfile = g_build_filename (config_dir, "logs", "seafile.log", NULL);
    if (seafile_log_init (logfile, ccnet_debug_level_str,
                          seafile_debug_level_str) < 0) {
        seaf_warning ("Failed to init log.\n");
        exit (1);
    }

    if (!bind_ccnet_service (config_dir)) {
        seaf_warning ("Failed to bind ccnet service\n");
        exit (1);
    }

    /* init ccnet */
    client = ccnet_init (config_dir);
    if (!client)
        exit (1);

    start_rpc_service (client);

    create_sync_rpc_clients (config_dir);
    appletrpc_client = ccnet_create_async_rpc_client (client, NULL, 
                                                      "applet-rpcserver");

    /* init seafile */
    if (seafile_dir == NULL)
        seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
    if (worktree_dir == NULL)
        worktree_dir = g_build_filename (g_get_home_dir(), "seafile", NULL);

    seaf = seafile_session_new (seafile_dir, worktree_dir, client);
    if (!seaf) {
        seaf_warning ("Failed to create seafile session.\n");
        exit (1);
    }
    seaf->ccnetrpc_client = ccnetrpc_client;
    seaf->appletrpc_client = appletrpc_client;

    seaf_message ("starting seafile client "SEAFILE_CLIENT_VERSION"\n");
#if defined(SEAFILE_SOURCE_COMMIT_ID)
    seaf_message ("seafile source code version "SEAFILE_SOURCE_COMMIT_ID"\n");
#endif

    g_free (seafile_dir);
    g_free (worktree_dir);
    g_free (logfile);

    set_signal_handlers (seaf);

    seafile_session_prepare (seaf);
    seafile_session_start (seaf);

    seafile_session_config_set_string (seaf, "wktree", seaf->worktree_dir);
    ccnet_main (client);

    return 0;
}
Пример #14
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);
}
Пример #15
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;
}
Пример #16
0
static char*
fsck_check_dir_recursive (const char *id, const char *parent_dir, FsckData *fsck_data)
{
    SeafDir *dir;
    SeafDir *new_dir;
    GList *p;
    SeafDirent *seaf_dent;
    char *dir_id = NULL;
    char *path = NULL;
    gboolean io_error = FALSE;

    SeafFSManager *mgr = seaf->fs_mgr;
    char *store_id = fsck_data->repo->store_id;
    int version = fsck_data->repo->version;
    gboolean is_corrupted = FALSE;

    dir = seaf_fs_manager_get_seafdir (mgr, store_id, version, id);

    for (p = dir->entries; p; p = p->next) {
        seaf_dent = p->data;
        io_error = FALSE;

        if (S_ISREG(seaf_dent->mode)) {
            path = g_strdup_printf ("%s%s", parent_dir, seaf_dent->name);
            if (!path) {
                seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n",
                              fsck_data->repo->id);
                goto out;
            }
            if (!fsck_verify_seafobj (store_id, version,
                                      seaf_dent->id, &io_error,
                                      VERIFY_FILE, fsck_data->repair)) {
                if (io_error) {
                    g_free (path);
                    goto out;
                }
                is_corrupted = TRUE;
                if (fsck_data->repair) {
                    seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n",
                                  path, seaf_dent->id);
                } else {
                    seaf_message ("File %s(%.8s) is corrupted.\n",
                                  path, seaf_dent->id);
                }
                // file corrupted, set it empty
                memcpy (seaf_dent->id, EMPTY_SHA1, 40);
                seaf_dent->size = 0;
            } else {
                if (check_blocks (seaf_dent->id, fsck_data, &io_error) < 0) {
                    if (io_error) {
                        g_free (path);
                        goto out;
                    }
                    is_corrupted = TRUE;
                    if (fsck_data->repair) {
                        seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n",
                                      path, seaf_dent->id);
                    } else {
                        seaf_message ("File %s(%.8s) is corrupted.\n",
                                      path, seaf_dent->id);
                    }
                    // file corrupted, set it empty
                    memcpy (seaf_dent->id, EMPTY_SHA1, 40);
                    seaf_dent->size = 0;
                }
            }
            g_free (path);
        } else if (S_ISDIR(seaf_dent->mode)) {
            path = g_strdup_printf ("%s%s/", parent_dir, seaf_dent->name);
            if (!path) {
                seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n",
                              fsck_data->repo->id);
                goto out;
            }
            if (!fsck_verify_seafobj (store_id, version,
                                      seaf_dent->id, &io_error,
                                      VERIFY_DIR, fsck_data->repair)) {
                if (io_error) {
                    g_free (path);
                    goto out;
                }
                if (fsck_data->repair) {
                    seaf_message ("Dir %s(%.8s) is corrupted, recreate an empty dir.\n",
                                  path, seaf_dent->id);
                } else {
                    seaf_message ("Dir %s(%.8s) is corrupted.\n",
                                  path, seaf_dent->id);
                }
                is_corrupted = TRUE;
                // dir corrupted, set it empty
                memcpy (seaf_dent->id, EMPTY_SHA1, 40);
            } else {
               dir_id = fsck_check_dir_recursive (seaf_dent->id, path, fsck_data);
               if (dir_id == NULL) {
                   // IO error
                   g_free (path);
                   goto out;
               }
               if (strcmp (dir_id, seaf_dent->id) != 0) {
                   is_corrupted = TRUE;
                   // dir corrupted, set it to new dir_id
                   memcpy (seaf_dent->id, dir_id, 41);
               }
               g_free (dir_id);
           }
           g_free (path);
        }
    }

    if (is_corrupted) {
        new_dir = seaf_dir_new (NULL, dir->entries, version);
        if (fsck_data->repair) {
            if (seaf_dir_save (mgr, store_id, version, new_dir) < 0) {
                seaf_warning ("Failed to save dir\n");
                seaf_dir_free (new_dir);
                goto out;
            }
        }
        dir_id = g_strdup (new_dir->dir_id);
        seaf_dir_free (new_dir);
        dir->entries = NULL;
    } else {
        dir_id = g_strdup (dir->dir_id);
    }

out:
    seaf_dir_free (dir);

    return dir_id;
}
Пример #17
0
static void
print_enc_repo (gpointer key, gpointer value, gpointer user_data)
{
    seaf_message ("%s(%s)\n", (char *)key, (char *)value);
}
Пример #18
0
char *
seaf_clone_manager_add_download_task (SeafCloneManager *mgr, 
                                      const char *repo_id,
                                      const char *peer_id,
                                      const char *repo_name,
                                      const char *token,
                                      const char *passwd,
                                      const char *magic,
                                      const char *wt_parent,
                                      const char *peer_addr,
                                      const char *peer_port,
                                      const char *email,
                                      GError **error)
{
    SeafRepo *repo;
    char *wt_tmp, *worktree;
    char *ret;

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

    g_assert (strlen(repo_id) == 36);

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);

    if (repo != NULL && repo->head != NULL) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Repo already exists");
        return NULL;
    }   

    if (is_duplicate_task (mgr, repo_id)) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, 
                     "Task is already in progress");
        return NULL;
    }

    /* If magic is not given, check password before checkout. */
    if (passwd && magic && seaf_repo_verify_passwd(repo_id, passwd, magic) < 0) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
                     "Incorrect password");
        return NULL;
    }

    wt_tmp = g_build_filename (wt_parent, repo_name, NULL);

    worktree = make_worktree_for_download (mgr, wt_tmp, error);
    if (!worktree) {
        g_free (wt_tmp);
        return NULL;
    }

    ret = add_task_common (mgr, repo, repo_id, peer_id, repo_name, token, passwd,
                           worktree, peer_addr, peer_port, email, error);
    g_free (worktree);
    g_free (wt_tmp);

    return ret;
}
Пример #19
0
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;
}
Пример #20
0
static SeafCommit*
get_available_commit (const char *repo_id)
{
    GList *commit_list = NULL;
    GList *temp_list = NULL;
    GList *next_list = NULL;
    SeafCommit *temp_commit = NULL;
    gboolean io_error;

    seaf_message ("Scanning available commits for repo %s...\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) {
        seaf_warning ("No available commits for repo %.8s, export failed.\n\n",
                      repo_id);
        return NULL;
    }

    commit_list = g_list_sort (commit_list, compare_commit_by_ctime);
    temp_list = commit_list;
    while (temp_list) {
        next_list = temp_list->next;
        temp_commit = temp_list->data;
        io_error = FALSE;

        if (memcmp (temp_commit->root_id, EMPTY_SHA1, 40) == 0) {
            seaf_commit_unref (temp_commit);
            temp_commit = NULL;
            temp_list = next_list;
            continue;
        } else if (!fsck_verify_seafobj (repo_id, 1, temp_commit->root_id,
                                         &io_error, VERIFY_DIR, FALSE)) {
            seaf_commit_unref (temp_commit);
            temp_commit = NULL;
            temp_list = next_list;

            if (io_error) {
                break;
            }
            // fs object of this commit is corrupted,
            // continue to verify next
            continue;
        }

        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), will export files from it.\n",
                      temp_commit->commit_id, time_buf);
        temp_list = next_list;
        break;
    }

    while (temp_list) {
        seaf_commit_unref (temp_list->data);
        temp_list = temp_list->next;
    }
    g_list_free (commit_list);

    if (!temp_commit && !io_error) {
        seaf_warning ("No available commits for repo %.8s, export failed.\n\n",
                      repo_id);
    }

    return temp_commit;
}
Пример #21
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;
}
Пример #22
0
int
main (int argc, char **argv)
{
    int c;
    char *config_dir = DEFAULT_CONFIG_DIR;
    char *seafile_dir = NULL;
    char *worktree_dir = NULL;
    char *logfile = NULL;
    const char *debug_str = NULL;
    int daemon_mode = 0;
    CcnetClient *client;
    char *ccnet_debug_level_str = "info";
    char *seafile_debug_level_str = "debug";

#ifdef WIN32
    argv = get_argv_utf8 (&argc);
#endif

    while ((c = getopt_long (argc, argv, short_options, 
                             long_options, NULL)) != EOF)
    {
        switch (c) {
        case 'h':
            exit (1);
            break;
        case 'v':
            exit (1);
            break;
        case 'c':
            config_dir = optarg;
            break;
        case 'd':
            seafile_dir = g_strdup(optarg);
            break;
        case 'b':
            daemon_mode = 1;
            break;
        case 'D':
            debug_str = optarg;
            break;
        case 'w':
            worktree_dir = g_strdup(optarg);
            break;
        case 'l':
            logfile = g_strdup(optarg);
            break;
        case 'g':
            ccnet_debug_level_str = optarg;
            break;
        case 'G':
            seafile_debug_level_str = optarg;
            break;
        default:
            usage ();
            exit (1);
        }
    }

    argc -= optind;
    argv += optind;

#ifndef WIN32

#ifndef __APPLE__
    if (daemon_mode)
        daemon (1, 0);
#endif

#endif

    g_type_init ();
#if !GLIB_CHECK_VERSION(2,32,0)
    g_thread_init (NULL);
#endif
    if (!debug_str)
        debug_str = g_getenv("SEAFILE_DEBUG");
    seafile_debug_set_flags_string (debug_str);

    /* init ccnet */
    client = ccnet_init (config_dir);
    if (!client)
        exit (1);
    register_processors (client);
    start_rpc_service (client);
    create_sync_rpc_clients (config_dir);
    appletrpc_client = ccnet_create_async_rpc_client (client, NULL, 
                                                      "applet-rpcserver");

    /* init seafile */
    if (seafile_dir == NULL)
        seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
    if (worktree_dir == NULL)
        worktree_dir = g_build_filename (g_get_home_dir(), "seafile", NULL);
    if (logfile == NULL)
        logfile = g_build_filename (config_dir, "logs", "seafile.log", NULL);

    seaf = seafile_session_new (seafile_dir, worktree_dir, client);
    if (!seaf) {
        fprintf (stderr, "Failed to create seafile session.\n");
        exit (1);
    }
    seaf->ccnetrpc_client = ccnetrpc_client;
    seaf->appletrpc_client = appletrpc_client;

    if (seafile_log_init (logfile, ccnet_debug_level_str,
                          seafile_debug_level_str) < 0) {
        fprintf (stderr, "Failed to init log.\n");
        exit (1);
    }

    seaf_message ("starting seaf-daemon "PACKAGE_VERSION"\n");

    g_free (seafile_dir);
    g_free (worktree_dir);
    g_free (logfile);

    set_signal_handlers (seaf);

    seafile_session_prepare (seaf);
    seafile_session_start (seaf);

    seafile_session_config_set_string (seaf, "wktree", seaf->worktree_dir);
    ccnet_main (client);

    return 0;
}