int block_tx_client_start (BlockTxInfo *info, BlockTxClientDoneCB cb) { BlockTxClient *client = g_new0 (BlockTxClient, 1); int ret = 0; client->info = info; client->cb = cb; ret = ccnet_job_manager_schedule_job (seaf->job_mgr, block_tx_client_thread, block_tx_client_thread_done, client); if (ret < 0) { seaf_warning ("Failed to start block tx client thread.\n"); return -1; } return 0; }
static void command_read_cb (CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) { SeafWTMonitorPriv *priv = (SeafWTMonitorPriv *)info; WatchCommand cmd; int n; n = pipereadn (priv->cmd_pipe[0], &cmd, sizeof(cmd)); if (n != sizeof(cmd)) { seaf_warning ("[wt mon] failed to read command.\n"); CFFileDescriptorEnableCallBacks (fdref, kCFFileDescriptorReadCallBack); return; } seaf_debug ("[wt mon] %ld receive command type=%d, repo=%s\n", (long)CFRunLoopGetCurrent(), cmd.type, cmd.repo_id); handle_watch_command (priv, &cmd); CFFileDescriptorEnableCallBacks (fdref, kCFFileDescriptorReadCallBack); }
static void on_fs_write (OSAsyncResult *res, void *cb_data) { CcnetProcessor *processor = cb_data; USE_PRIV; if (!res->success) { seaf_warning ("[recvfs] Failed to write %s.\n", res->obj_id); ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, NULL, 0); ccnet_processor_done (processor, FALSE); return; } --priv->pending_objects; #ifdef DEBUG seaf_debug ("[recvfs] Wrote fs object %s.\n", res->obj_id); #endif }
GList * seaf_share_manager_list_shared_to (SeafShareManager *mgr, const char *owner, const char *repo_id) { char *sql; GList *ret = NULL; sql = "SELECT to_email FROM SharedRepo WHERE " "from_email=? AND repo_id=?"; if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, collect_shared_to, &ret, 2, "string", owner, "string", repo_id) < 0) { seaf_warning ("[share mgr] DB error when list shared to.\n"); string_list_free (ret); return NULL; } return ret; }
static gboolean case_conflict_exists (const char *dir_path, const char *new_dname, char **conflict_dname) { GDir *dir; const char *dname; gboolean is_case_conflict = FALSE; GError *error = NULL; dir = g_dir_open (dir_path, 0, &error); if (!dir && error) { seaf_warning ("Failed to open dir %s: %s.\n", dir_path, error->message); g_error_free (error); return FALSE; } while (1) { dname = g_dir_read_name (dir); if (!dname) break; #ifdef __APPLE__ char *norm_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC); if (case_conflict_utf8 (norm_dname, new_dname)) { is_case_conflict = TRUE; *conflict_dname = norm_dname; break; } g_free (norm_dname); #else if (case_conflict_utf8 (dname, new_dname)) { is_case_conflict = TRUE; *conflict_dname = g_strdup(dname); break; } #endif } g_dir_close (dir); return is_case_conflict; }
static int start (CcnetProcessor *processor, int argc, char **argv) { USE_PRIV; GString *buf; SeafileGetfsV2Proc *proc = (SeafileGetfsV2Proc *)processor; TransferTask *task = proc->tx_task; buf = g_string_new (NULL); if (!task->is_clone) { SeafBranch *master = seaf_branch_manager_get_branch (seaf->branch_mgr, task->repo_id, "master"); if (!master) { seaf_warning ("Master branch not found for repo %s.\n", task->repo_id); g_string_free (buf, TRUE); ccnet_processor_done (processor, FALSE); return -1; } g_string_printf (buf, "remote %s seafile-putfs-v2 %s %s %s", processor->peer_id, task->session_token, task->head, master->commit_id); seaf_branch_unref (master); } else g_string_printf (buf, "remote %s seafile-putfs-v2 %s %s", processor->peer_id, task->session_token, task->head); ccnet_processor_send_request (processor, buf->str); g_string_free (buf, TRUE); priv->registered = TRUE; priv->writer_id = seaf_obj_store_register_async_write (seaf->fs_mgr->obj_store, task->repo_id, task->repo_version, on_fs_write, processor); return 0; }
static void handle_response (CcnetProcessor *processor, char *code, char *code_msg, char *content, int clen) { SeafileGetcommitV3Proc *proc = (SeafileGetcommitV3Proc *)processor; if (proc->tx_task->state != TASK_STATE_NORMAL) { ccnet_processor_done (processor, TRUE); return; } if (strncmp(code, SC_OK, 3) == 0) { receive_commit (processor, content, clen); return; } seaf_warning ("Bad response: %s %s.\n", code, code_msg); if (memcmp (code, SC_ACCESS_DENIED, 3) == 0) transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED); ccnet_processor_done (processor, FALSE); }
static int check_fs_tree_from (CcnetProcessor *processor, const char *root_id) { USE_PRIV; memcpy (priv->root_id, root_id, 40); priv->fetch_objs = NULL; int rc = ccnet_processor_thread_create (processor, seaf->job_mgr, check_objects_thread, check_objects_done, processor); if (rc < 0) { seaf_warning ("Failed to start worker thread.\n"); return -1; } priv->worker_running = TRUE; return 0; }
static gint64 repo_share_usage (const char *user, const char *repo_id) { gint n_shared_to = get_num_shared_to (user, repo_id); if (n_shared_to < 0) { return -1; } else if (n_shared_to == 0) { return 0; } gint64 size = seaf_repo_manager_get_repo_size (seaf->repo_mgr, repo_id); if (size < 0) { seaf_warning ("Cannot get size of repo %s.\n", repo_id); return -1; } /* share_usage = repo_size * n_shared_to */ gint64 usage = size * n_shared_to; return usage; }
static void load_repo_commit (SeafRepoManager *manager, SeafRepo *repo, SeafBranch *branch) { SeafCommit *commit; commit = seaf_commit_manager_get_commit_compatible (manager->seaf->commit_mgr, repo->id, branch->commit_id); if (!commit) { seaf_warning ("Commit %s is missing\n", branch->commit_id); repo->is_corrupted = TRUE; return; } set_head_common (repo, branch); seaf_repo_from_commit (repo, commit); seaf_commit_unref (commit); }
static BMetadata * block_backend_fs_stat_block (BlockBackend *bend, const char *store_id, int version, const char *block_id) { char path[SEAF_PATH_MAX]; SeafStat st; BMetadata *block_md; get_block_path (bend, block_id, path, store_id, version); if (seaf_stat (path, &st) < 0) { seaf_warning ("[block bend] Failed to stat block %s.\n", block_id); return NULL; } block_md = g_new0(BMetadata, 1); memcpy (block_md->id, block_id, 40); block_md->size = (uint32_t) st.st_size; return block_md; }
static void handle_update (CcnetProcessor *processor, char *code, char *code_msg, char *content, int clen) { switch (processor->state) { case PREPARE: if (memcmp (code, SC_BLOCKLIST, 3) == 0) { process_block_list (processor, content, clen); return; } else if (memcmp (code, SC_GET_PORT, 3) == 0) { send_port (processor); return; } break; } seaf_warning ("Bad code: %s %s\n", code, code_msg); ccnet_processor_send_response (processor, SC_BAD_UPDATE_CODE, SS_BAD_UPDATE_CODE, NULL, 0); ccnet_processor_done (processor, FALSE); }
static void init_seafile_path () { GError *error = NULL; char *binary = g_file_read_link ("/proc/self/exe", &error); char *tmp = NULL; if (error != NULL) { seaf_warning ("failed to readlink: %s\n", error->message); return; } bin_dir = g_path_get_dirname (binary); tmp = g_path_get_dirname (bin_dir); installpath = g_path_get_dirname (tmp); topdir = g_path_get_dirname (installpath); g_free (binary); g_free (tmp); }
static void start_upload_if_necessary (SyncTask *task) { GError *error = NULL; const char *repo_id = task->repo->id; char *tx_id = seaf_transfer_manager_add_upload (seaf->transfer_mgr, repo_id, task->dest_id, "local", "master", task->token, &error); if (error != NULL) { seaf_warning ("Failed to start upload: %s\n", error->message); seaf_sync_manager_set_task_error (task, SYNC_ERROR_START_UPLOAD); return; } task->tx_id = tx_id; transition_sync_state (task, SYNC_STATE_UPLOAD); }
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; }
int seafile_update_random_key (const char *old_passwd, const char *old_random_key, const char *new_passwd, char *new_random_key) { unsigned char key[32], iv[16]; unsigned char random_key_raw[48], *secret_key, *new_random_key_raw; int secret_key_len, random_key_len; SeafileCrypt *crypt; /* First, use old_passwd to decrypt secret key from old_random_key. */ seafile_derive_key (old_passwd, strlen(old_passwd), 2, key, iv); hex_to_rawdata (old_random_key, random_key_raw, 48); crypt = seafile_crypt_new (2, key, iv); if (seafile_decrypt ((char **)&secret_key, &secret_key_len, (char *)random_key_raw, 48, crypt) < 0) { seaf_warning ("Failed to decrypt random key.\n"); g_free (crypt); return -1; } g_free (crypt); /* Second, use new_passwd to encrypt secret key. */ seafile_derive_key (new_passwd, strlen(new_passwd), 2, key, iv); crypt = seafile_crypt_new (2, key, iv); seafile_encrypt ((char **)&new_random_key_raw, &random_key_len, (char *)secret_key, secret_key_len, crypt); rawdata_to_hex (new_random_key_raw, new_random_key, 48); g_free (secret_key); g_free (new_random_key_raw); g_free (crypt); return 0; }
/* Add a specific HANDLE to an I/O Completion Port. If it's the cmd pipe * handle, call ReadFile() on it; If it's a dir handle, call * ReadDirectoryChangesW() on it. */ static BOOL add_handle_to_iocp (SeafWTMonitor *monitor, HANDLE hAdd) { SeafWTMonitorPriv *priv = monitor->priv; if (!priv || !hAdd) return FALSE; /* CreateIoCompletionPort() will add the handle to an I/O Completion Port if the iocp handle is not NULL. Otherwise it will create a new IOCP handle. The `key' parameter is used by th IOCP to tell us which handle watched by the I/O Completion Port triggeed a return of the GetQueuedCompletionStatus() function. Here we use the value of the handle itself as the key for this handle in the I/O Completion Port. */ priv->iocp_handle = CreateIoCompletionPort (hAdd, /* handle to add */ priv->iocp_handle, /* iocp handle */ (ULONG_PTR)hAdd, /* key for this handle */ 1); /* Num of concurrent threads */ if (!priv->iocp_handle) { seaf_warning ("failed to create/add iocp, error code %lu", GetLastError()); return FALSE; } if (hAdd == (HANDLE)monitor->cmd_pipe[0]) { /* HANDLE is cmd_pipe */ return start_watch_cmd_pipe (monitor, NULL); } else { /* HANDLE is a dir handle */ return start_watch_dir_change (priv, hAdd); } }
static void on_fs_write (OSAsyncResult *res, void *cb_data) { CcnetProcessor *processor = cb_data; USE_PRIV; if (!res->success) { seaf_warning ("[recvfs] Failed to write %s.\n", res->obj_id); ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, NULL, 0); ccnet_processor_done (processor, FALSE); return; } seaf_debug ("[recvfs] Wrote fs object %s.\n", res->obj_id); if (++(priv->n_saved) == priv->total_needed) { seaf_debug ("All objects saved. Done.\n"); ccnet_processor_send_response (processor, SC_END, SS_END, NULL, 0); ccnet_processor_done (processor, TRUE); } }
static gboolean fs_callback (SeafFSManager *mgr, const char *store_id, int version, const char *obj_id, int type, void *user_data, gboolean *stop) { MigrationData *data = user_data; SeafRepo *repo = data->repo; if (data->visited != NULL) { if (g_hash_table_lookup (data->visited, obj_id) != NULL) { *stop = TRUE; return TRUE; } char *key = g_strdup(obj_id); g_hash_table_insert (data->visited, key, key); } if (seaf_obj_store_copy_obj (seaf->fs_mgr->obj_store, repo->store_id, repo->version, repo->store_id, 1, obj_id) < 0) { seaf_warning ("Failed to copy fs object %s.\n", obj_id); return FALSE; } if (data->stop_copy_blocks) return TRUE; if (type == SEAF_METADATA_TYPE_FILE && migrate_file_blocks (mgr, data, obj_id) < 0) return FALSE; return TRUE; }
GList * seaf_repo_get_commits (SeafRepo *repo) { GList *branches; GList *ptr; SeafBranch *branch; GList *commits = NULL; branches = seaf_branch_manager_get_branch_list (seaf->branch_mgr, repo->id); if (branches == NULL) { seaf_warning ("Failed to get branch list of repo %s.\n", repo->id); return NULL; } for (ptr = branches; ptr != NULL; ptr = ptr->next) { branch = ptr->data; gboolean res = seaf_commit_manager_traverse_commit_tree (seaf->commit_mgr, repo->id, repo->version, branch->commit_id, collect_commit, &commits, FALSE); if (!res) { for (ptr = commits; ptr != NULL; ptr = ptr->next) seaf_commit_unref ((SeafCommit *)(ptr->data)); g_list_free (commits); goto out; } } commits = g_list_reverse (commits); out: for (ptr = branches; ptr != NULL; ptr = ptr->next) { seaf_branch_unref ((SeafBranch *)ptr->data); } return commits; }
void export_repo_files (const char *repo_id, const char *init_path, GHashTable *enc_repos) { SeafCommit *commit = get_available_commit (repo_id); if (!commit) { return; } if (commit->encrypted) { g_hash_table_insert (enc_repos, g_strdup (repo_id), g_strdup (commit->repo_name)); seaf_commit_unref (commit); return; } seaf_message ("Start to export files for repo %.8s(%s).\n", repo_id, commit->repo_name); char *dir_name = g_strdup_printf ("%.8s_%s_%s", repo_id, commit->repo_name, commit->creator_name); char * export_path = g_build_filename (init_path, dir_name, NULL); g_free (dir_name); if (g_mkdir (export_path, 0777) < 0) { seaf_warning ("Failed to create export dir %s: %s, export failed.\n", export_path, strerror (errno)); g_free (export_path); seaf_commit_unref (commit); return; } export_repo_files_recursive (repo_id, commit->root_id, export_path); seaf_message ("Finish exporting files for repo %.8s.\n\n", repo_id); g_free (export_path); seaf_commit_unref (commit); }
static int check_blocks (SeafFSManager *mgr, const char *file_id) { Seafile *seafile; int i; seafile = seaf_fs_manager_get_seafile (mgr, file_id); if (!seafile) { seaf_warning ("Failed to find file %s.\n", file_id); return -1; } for (i = 0; i < seafile->n_blocks; ++i) { if (!seaf_block_manager_block_exists (seaf->block_mgr, seafile->blk_sha1s[i])) g_message ("Block %s is missing.\n", seafile->blk_sha1s[i]); } seafile_unref (seafile); return 0; }
static int send_block_content (BlockTxServer *server, int block_size) { BlockHandle *handle = NULL; int ret = 0; handle = seaf_block_manager_open_block (seaf->block_mgr, server->store_id, server->repo_version, server->curr_block_id, BLOCK_READ); if (!handle) { seaf_warning ("Failed to open block %s.\n", server->curr_block_id); return -1; } ret = send_encrypted_block (server, handle, server->curr_block_id, block_size); seaf_block_manager_close_block (seaf->block_mgr, handle); seaf_block_manager_block_handle_free (seaf->block_mgr, handle); return ret; }
static SeafBranch * real_get_branch (SeafBranchManager *mgr, const char *repo_id, const char *name) { char commit_id[41]; char *sql; commit_id[0] = 0; sql = "SELECT commit_id FROM Branch WHERE name=? AND repo_id=?"; if (seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_branch, commit_id, 2, "string", name, "string", repo_id) < 0) { seaf_warning ("[branch mgr] DB error when get branch %s.\n", name); return NULL; } if (commit_id[0] == 0) return NULL; return seaf_branch_new (name, repo_id, commit_id); }
static void on_repo_fetched (SeafileSession *seaf, TransferTask *tx_task, SeafCloneManager *mgr) { CloneTask *task; /* Only handle clone task. */ if (!tx_task->is_clone) return; task = g_hash_table_lookup (mgr->tasks, tx_task->repo_id); g_assert (task != NULL); if (tx_task->state == TASK_STATE_CANCELED) { /* g_assert (task->state == CLONE_STATE_CANCEL_PENDING); */ transition_state (task, CLONE_STATE_CANCELED); return; } else if (tx_task->state == TASK_STATE_ERROR) { transition_to_error (task, CLONE_ERROR_FETCH); return; } SeafRepo *repo = seaf_repo_manager_get_repo (seaf->repo_mgr, tx_task->repo_id); if (repo == NULL) { seaf_warning ("[Clone mgr] cannot find repo %s after fetched.\n", tx_task->repo_id); transition_to_error (task, CLONE_ERROR_INTERNAL); return; } seaf_repo_manager_set_repo_token (seaf->repo_mgr, repo, task->token); seaf_repo_manager_set_repo_email (seaf->repo_mgr, repo, task->email); seaf_repo_manager_set_repo_relay_info (seaf->repo_mgr, repo->id, task->peer_addr, task->peer_port); start_checkout (repo, task); }
static void handle_response (CcnetProcessor *processor, char *code, char *code_msg, char *content, int clen) { SeafileGetblockV2Proc *proc = (SeafileGetblockV2Proc *)processor; USE_PRIV; if (proc->tx_task->state != TASK_STATE_NORMAL) { g_debug ("Task not running, get-block proc exits.\n"); ccnet_processor_done (processor, TRUE); return; } switch (priv->tdata->state) { case REQUEST_SENT: if (memcmp (code, SC_OK, 3) == 0) { send_block_list (processor); priv->tdata->state = BLOCKLIST_SENT; return; } break; case BLOCKLIST_SENT: if (memcmp (code, SC_BBITMAP, 3) == 0) { process_block_bitmap (processor, content, clen); return; } break; case GET_PORT: if (memcmp (code, SC_SEND_PORT, 3) == 0) { get_port (processor, content, clen); return; } } seaf_warning ("Bad response: %s %s.\n", code, code_msg); if (memcmp (code, SC_ACCESS_DENIED, 3) == 0) transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED); ccnet_processor_done (processor, FALSE); }
static gboolean traverse_commit (SeafCommit *commit, void *vdata, gboolean *stop) { MigrationData *data = vdata; SeafRepo *repo = data->repo; int ret; if (data->truncate_time > 0 && (gint64)(commit->ctime) < data->truncate_time && data->traversed_head && !data->stop_copy_blocks) { data->stop_copy_blocks = TRUE; } if (!data->traversed_head) data->traversed_head = TRUE; if (seaf_obj_store_copy_obj (seaf->commit_mgr->obj_store, repo->id, repo->version, repo->id, 1, commit->commit_id) < 0) { seaf_warning ("Failed to copy commit %s.\n", commit->commit_id); return FALSE; } ret = seaf_fs_manager_traverse_tree (seaf->fs_mgr, data->repo->store_id, data->repo->version, commit->root_id, fs_callback, data, FALSE); if (ret < 0) return FALSE; if (data->truncate_time == 0 && !data->stop_copy_blocks) { data->stop_copy_blocks = TRUE; /* Stop after traversing the head commit. */ } return TRUE; }
static int init_syslog_config () { char *seafile_conf = g_build_filename (ctl->central_config_dir, "seafile.conf", NULL); GKeyFile *key_file = g_key_file_new (); int ret = 0; if (!g_key_file_load_from_file (key_file, seafile_conf, G_KEY_FILE_KEEP_COMMENTS, NULL)) { seaf_warning("Failed to load seafile.conf.\n"); ret = -1; goto out; } set_syslog_config (key_file); out: g_key_file_free (key_file); g_free (seafile_conf); return ret; }
int seaf_clone_manager_cancel_task (SeafCloneManager *mgr, const char *repo_id) { CloneTask *task; task = g_hash_table_lookup (mgr->tasks, repo_id); if (!task) return -1; switch (task->state) { case CLONE_STATE_INIT: case CLONE_STATE_CONNECT: transition_state (task, CLONE_STATE_CANCELED); break; case CLONE_STATE_FETCH: seaf_transfer_manager_cancel_task (seaf->transfer_mgr, task->tx_id, TASK_TYPE_DOWNLOAD); transition_state (task, CLONE_STATE_CANCEL_PENDING); break; case CLONE_STATE_INDEX: case CLONE_STATE_CHECKOUT: case CLONE_STATE_MERGE: /* We cannot cancel an in-progress checkout, just * wait until it finishes. */ transition_state (task, CLONE_STATE_CANCEL_PENDING); break; case CLONE_STATE_CANCEL_PENDING: break; default: seaf_warning ("[Clone mgr] cannot cancel a not-running task.\n"); return -1; } return 0; }
/** * @return * - pid if successfully opened and read the file * - PID_ERROR_ENOENT if file not exists, * - PID_ERROR_OTHER if other errors */ static int read_pid_from_pidfile (const char *pidfile) { FILE *pf = g_fopen (pidfile, "r"); if (!pf) { if (errno == ENOENT) { return PID_ERROR_ENOENT; } else { return PID_ERROR_OTHER; } } int pid = PID_ERROR_OTHER; if (fscanf (pf, "%d", &pid) < 0) { seaf_warning ("bad pidfile format: %s\n", pidfile); fclose(pf); return PID_ERROR_OTHER; } fclose(pf); return pid; }