1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 #include "common.h"
4 #include <glib/gstdio.h>
5 #include <ctype.h>
6
7 #include <sys/stat.h>
8 #include <dirent.h>
9 #include "utils.h"
10
11 #include "seafile-session.h"
12 #include "fs-mgr.h"
13 #include "repo-mgr.h"
14 #include "seafile-error.h"
15 #include "seafile-rpc.h"
16 #include "common/mq-mgr.h"
17 #include "seafile-config.h"
18 #include "seafile-object.h"
19 #include "seafile-error-impl.h"
20 #define DEBUG_FLAG SEAFILE_DEBUG_OTHER
21 #include "log.h"
22
23 #include "../daemon/vc-utils.h"
24
25
26 /* -------- Utilities -------- */
27 static GObject*
convert_repo(SeafRepo * r)28 convert_repo (SeafRepo *r)
29 {
30 SeafileRepo *repo = NULL;
31
32 if (r->head == NULL)
33 return NULL;
34
35 if (r->worktree_invalid && !seafile_session_config_get_allow_invalid_worktree(seaf))
36 return NULL;
37
38 repo = seafile_repo_new ();
39 if (!repo)
40 return NULL;
41
42 g_object_set (repo, "id", r->id, "name", r->name,
43 "desc", r->desc, "encrypted", r->encrypted,
44 "magic", r->magic, "enc_version", r->enc_version,
45 "head_cmmt_id", r->head ? r->head->commit_id : NULL,
46 "root", r->root_id,
47 "version", r->version, "last_modify", (int)r->last_modify,
48 NULL);
49 g_object_set (repo,
50 "repo_id", r->id, "repo_name", r->name,
51 "repo_desc", r->desc, "last_modified", (int)r->last_modify,
52 NULL);
53
54 g_object_set (repo, "worktree", r->worktree,
55 "relay-id", r->relay_id,
56 "worktree-invalid", r->worktree_invalid,
57 "last-sync-time", r->last_sync_time,
58 "auto-sync", r->auto_sync,
59 NULL);
60
61 return (GObject *)repo;
62 }
63
64 static void
free_repo_obj(gpointer repo)65 free_repo_obj (gpointer repo)
66 {
67 if (!repo)
68 return;
69 g_object_unref ((GObject *)repo);
70 }
71
72 static GList *
convert_repo_list(GList * inner_repos)73 convert_repo_list (GList *inner_repos)
74 {
75 GList *ret = NULL, *ptr;
76 GObject *repo = NULL;
77
78 for (ptr = inner_repos; ptr; ptr=ptr->next) {
79 SeafRepo *r = ptr->data;
80 repo = convert_repo (r);
81 if (!repo) {
82 g_list_free_full (ret, free_repo_obj);
83 return NULL;
84 }
85
86 ret = g_list_prepend (ret, repo);
87 }
88
89 return g_list_reverse (ret);
90 }
91
92 /*
93 * RPC functions only available for clients.
94 */
95
96 #include "sync-mgr.h"
97
98 int
seafile_set_config(const char * key,const char * value,GError ** error)99 seafile_set_config (const char *key, const char *value, GError **error)
100 {
101 return seafile_session_config_set_string(seaf, key, value);
102 }
103
104 char *
seafile_get_config(const char * key,GError ** error)105 seafile_get_config (const char *key, GError **error)
106 {
107 return seafile_session_config_get_string(seaf, key);
108 }
109
110 int
seafile_set_config_int(const char * key,int value,GError ** error)111 seafile_set_config_int (const char *key, int value, GError **error)
112 {
113 return seafile_session_config_set_int(seaf, key, value);
114 }
115
116 int
seafile_get_config_int(const char * key,GError ** error)117 seafile_get_config_int (const char *key, GError **error)
118 {
119 gboolean exists = TRUE;
120
121 int ret = seafile_session_config_get_int(seaf, key, &exists);
122
123 if (!exists) {
124 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Config not exists");
125 return -1;
126 }
127
128 return ret;
129 }
130
131 int
seafile_set_upload_rate_limit(int limit,GError ** error)132 seafile_set_upload_rate_limit (int limit, GError **error)
133 {
134 if (limit < 0)
135 limit = 0;
136
137 seaf->sync_mgr->upload_limit = limit;
138
139 return seafile_session_config_set_int (seaf, KEY_UPLOAD_LIMIT, limit);
140 }
141
142 int
seafile_set_download_rate_limit(int limit,GError ** error)143 seafile_set_download_rate_limit (int limit, GError **error)
144 {
145 if (limit < 0)
146 limit = 0;
147
148 seaf->sync_mgr->download_limit = limit;
149
150 return seafile_session_config_set_int (seaf, KEY_DOWNLOAD_LIMIT, limit);
151 }
152
153 char *
seafile_gen_default_worktree(const char * worktree_parent,const char * repo_name,GError ** error)154 seafile_gen_default_worktree (const char *worktree_parent,
155 const char *repo_name,
156 GError **error)
157 {
158 if (!worktree_parent || !repo_name) {
159 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Empty args");
160 return NULL;
161 }
162
163 return seaf_clone_manager_gen_default_worktree (seaf->clone_mgr,
164 worktree_parent,
165 repo_name);
166 }
167
168 int
seafile_check_path_for_clone(const char * path,GError ** error)169 seafile_check_path_for_clone (const char *path, GError **error)
170 {
171 if (!seaf_clone_manager_check_worktree_path(seaf->clone_mgr, path, error)) {
172 return -1;
173 }
174
175 return 0;
176 }
177
178 char *
seafile_clone(const char * repo_id,int repo_version,const char * repo_name,const char * worktree,const char * token,const char * passwd,const char * magic,const char * email,const char * random_key,int enc_version,const char * more_info,GError ** error)179 seafile_clone (const char *repo_id,
180 int repo_version,
181 const char *repo_name,
182 const char *worktree,
183 const char *token,
184 const char *passwd,
185 const char *magic,
186 const char *email,
187 const char *random_key,
188 int enc_version,
189 const char *more_info,
190 GError **error)
191 {
192 if (!repo_id || strlen(repo_id) != 36) {
193 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo id");
194 return NULL;
195 }
196
197 if (!worktree) {
198 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
199 "Worktre must be specified");
200 return NULL;
201 }
202
203 if (!token || !email ) {
204 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
205 "Argument can't be NULL");
206 return NULL;
207 }
208
209 return seaf_clone_manager_add_task (seaf->clone_mgr,
210 repo_id, repo_version,
211 repo_name, token,
212 passwd, magic,
213 enc_version,
214 random_key,
215 worktree,
216 email, more_info,
217 error);
218 }
219
220 char *
seafile_download(const char * repo_id,int repo_version,const char * repo_name,const char * wt_parent,const char * token,const char * passwd,const char * magic,const char * email,const char * random_key,int enc_version,const char * more_info,GError ** error)221 seafile_download (const char *repo_id,
222 int repo_version,
223 const char *repo_name,
224 const char *wt_parent,
225 const char *token,
226 const char *passwd,
227 const char *magic,
228 const char *email,
229 const char *random_key,
230 int enc_version,
231 const char *more_info,
232 GError **error)
233 {
234 if (!repo_id || strlen(repo_id) != 36) {
235 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo id");
236 return NULL;
237 }
238
239 if (!wt_parent) {
240 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
241 "Worktre must be specified");
242 return NULL;
243 }
244
245 if (!token || !email ) {
246 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
247 "Argument can't be NULL");
248 return NULL;
249 }
250
251 return seaf_clone_manager_add_download_task (seaf->clone_mgr,
252 repo_id, repo_version,
253 repo_name, token,
254 passwd, magic,
255 enc_version, random_key,
256 wt_parent,
257 email, more_info,
258 error);
259 }
260
261 int
seafile_cancel_clone_task(const char * repo_id,GError ** error)262 seafile_cancel_clone_task (const char *repo_id, GError **error)
263 {
264 return seaf_clone_manager_cancel_task (seaf->clone_mgr, repo_id);
265 }
266
267 GList *
seafile_get_clone_tasks(GError ** error)268 seafile_get_clone_tasks (GError **error)
269 {
270 GList *tasks, *ptr;
271 GList *ret = NULL;
272 CloneTask *task;
273 SeafileCloneTask *t;
274
275 tasks = seaf_clone_manager_get_tasks (seaf->clone_mgr);
276 for (ptr = tasks; ptr != NULL; ptr = ptr->next) {
277 task = ptr->data;
278 t = g_object_new (SEAFILE_TYPE_CLONE_TASK,
279 "state", clone_task_state_to_str(task->state),
280 "error", task->error,
281 "repo_id", task->repo_id,
282 "repo_name", task->repo_name,
283 "worktree", task->worktree,
284 NULL);
285 ret = g_list_prepend (ret, t);
286 }
287
288 g_list_free (tasks);
289 return ret;
290 }
291
292 int
seafile_sync(const char * repo_id,const char * peer_id,GError ** error)293 seafile_sync (const char *repo_id, const char *peer_id, GError **error)
294 {
295 if (!repo_id) {
296 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Repo ID should not be null");
297 return -1;
298 }
299
300 return seaf_sync_manager_add_sync_task (seaf->sync_mgr, repo_id, error);
301 }
302
303 static SeafileTask *
convert_http_task(HttpTxTask * task)304 convert_http_task (HttpTxTask *task)
305 {
306 SeafileTask *t = seafile_task_new();
307
308 g_object_set (t,
309 "repo_id", task->repo_id,
310 "state", http_task_state_to_str(task->state),
311 "rt_state", http_task_rt_state_to_str(task->runtime_state),
312 NULL);
313
314 if (task->type == HTTP_TASK_TYPE_DOWNLOAD) {
315 g_object_set (t, "ttype", "download", NULL);
316 if (task->runtime_state == HTTP_TASK_RT_STATE_BLOCK) {
317 g_object_set (t, "block_total", task->total_download,
318 "block_done", task->done_download,
319 NULL);
320 g_object_set (t, "rate", http_tx_task_get_rate(task), NULL);
321 } else if (task->runtime_state == HTTP_TASK_RT_STATE_FS) {
322 g_object_set (t, "fs_objects_total", task->n_fs_objs,
323 "fs_objects_done", task->done_fs_objs,
324 NULL);
325 }
326 } else {
327 g_object_set (t, "ttype", "upload", NULL);
328 if (task->runtime_state == HTTP_TASK_RT_STATE_BLOCK) {
329 SyncInfo *info = seaf_sync_manager_get_sync_info (seaf->sync_mgr, task->repo_id);
330 if (info && info->multipart_upload) {
331 g_object_set (t, "block_total", info->total_bytes,
332 "block_done", info->uploaded_bytes,
333 NULL);
334 } else {
335 g_object_set (t, "block_total", (gint64)task->n_blocks,
336 "block_done", (gint64)task->done_blocks,
337 NULL);
338 }
339 g_object_set (t, "rate", http_tx_task_get_rate(task), NULL);
340 }
341 }
342
343 return t;
344 }
345
346 GObject *
seafile_find_transfer_task(const char * repo_id,GError * error)347 seafile_find_transfer_task (const char *repo_id, GError *error)
348 {
349 HttpTxTask *http_task;
350
351 http_task = http_tx_manager_find_task (seaf->http_tx_mgr, repo_id);
352 if (http_task)
353 return (GObject *)convert_http_task (http_task);
354
355 return NULL;
356 }
357
358 int
seafile_get_upload_rate(GError ** error)359 seafile_get_upload_rate(GError **error)
360 {
361 return seaf->sync_mgr->last_sent_bytes;
362 }
363
364 int
seafile_get_download_rate(GError ** error)365 seafile_get_download_rate(GError **error)
366 {
367 return seaf->sync_mgr->last_recv_bytes;
368 }
369
370 GObject *
seafile_get_repo_sync_task(const char * repo_id,GError ** error)371 seafile_get_repo_sync_task (const char *repo_id, GError **error)
372 {
373 SeafRepo *repo;
374 repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
375
376 if (!repo) {
377 return NULL;
378 }
379
380 SyncInfo *info = seaf_sync_manager_get_sync_info (seaf->sync_mgr, repo_id);
381 if (!info || !info->current_task)
382 return NULL;
383
384 SyncTask *task = info->current_task;
385 const char *sync_state;
386 char allzeros[41] = {0};
387
388 if (!info->in_sync && memcmp(allzeros, info->head_commit, 41) == 0) {
389 sync_state = "waiting for sync";
390 } else {
391 sync_state = sync_state_to_str(task->state);
392 }
393
394 SeafileSyncTask *s_task;
395 s_task = g_object_new (SEAFILE_TYPE_SYNC_TASK,
396 "force_upload", task->is_manual_sync,
397 "state", sync_state,
398 "error", task->error,
399 "repo_id", info->repo_id,
400 NULL);
401
402 return (GObject *)s_task;
403 }
404
405 int
seafile_set_repo_property(const char * repo_id,const char * key,const char * value,GError ** error)406 seafile_set_repo_property (const char *repo_id,
407 const char *key,
408 const char *value,
409 GError **error)
410 {
411 int ret;
412
413 if (repo_id == NULL || key == NULL || value == NULL) {
414 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Arguments should not be empty");
415 return -1;
416 }
417
418 SeafRepo *repo;
419 repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
420 if (!repo) {
421 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_REPO, "Can't find Repo %s", repo_id);
422 return -1;
423 }
424
425 ret = seaf_repo_manager_set_repo_property (seaf->repo_mgr,
426 repo->id, key, value);
427 if (ret < 0) {
428 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL,
429 "Failed to set key for repo %s", repo_id);
430 return -1;
431 }
432
433 return 0;
434 }
435
436 gchar *
seafile_get_repo_property(const char * repo_id,const char * key,GError ** error)437 seafile_get_repo_property (const char *repo_id,
438 const char *key,
439 GError **error)
440 {
441 char *value = NULL;
442
443 if (!repo_id || !key) {
444 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Arguments should not be empty");
445 return NULL;
446 }
447
448 SeafRepo *repo;
449 repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
450 if (!repo) {
451 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_REPO, "Can't find Repo %s", repo_id);
452 return NULL;
453 }
454
455 value = seaf_repo_manager_get_repo_property (seaf->repo_mgr, repo->id, key);
456 return value;
457 }
458
459 int
seafile_update_repos_server_host(const char * old_server_url,const char * new_server_url,GError ** error)460 seafile_update_repos_server_host (const char *old_server_url,
461 const char *new_server_url,
462 GError **error)
463 {
464 if (!old_server_url || !new_server_url) {
465 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
466 return -1;
467 }
468
469 return seaf_repo_manager_update_repos_server_host(
470 seaf->repo_mgr, old_server_url, new_server_url);
471 }
472
473 int
seafile_calc_dir_size(const char * path,GError ** error)474 seafile_calc_dir_size (const char *path, GError **error)
475 {
476 if (!path) {
477 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
478 return -1;
479 }
480
481 gint64 size_64 = ccnet_calc_directory_size(path, error);
482 if (size_64 < 0) {
483 seaf_warning ("failed to calculate dir size for %s\n", path);
484 return -1;
485 }
486
487 /* get the size in MB */
488 int size = (int) (size_64 >> 20);
489 return size;
490 }
491
492 int
seafile_disable_auto_sync(GError ** error)493 seafile_disable_auto_sync (GError **error)
494 {
495 return seaf_sync_manager_disable_auto_sync (seaf->sync_mgr);
496 }
497
498 int
seafile_enable_auto_sync(GError ** error)499 seafile_enable_auto_sync (GError **error)
500 {
501 return seaf_sync_manager_enable_auto_sync (seaf->sync_mgr);
502 }
503
seafile_is_auto_sync_enabled(GError ** error)504 int seafile_is_auto_sync_enabled (GError **error)
505 {
506 return seaf_sync_manager_is_auto_sync_enabled (seaf->sync_mgr);
507 }
508
509 char *
seafile_get_path_sync_status(const char * repo_id,const char * path,int is_dir,GError ** error)510 seafile_get_path_sync_status (const char *repo_id,
511 const char *path,
512 int is_dir,
513 GError **error)
514 {
515 char *canon_path = NULL;
516 int len;
517 char *status;
518
519 if (!repo_id || !path) {
520 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
521 return NULL;
522 }
523
524 /* Empty path means to get status of the worktree folder. */
525 if (strcmp (path, "") != 0) {
526 if (*path == '/')
527 ++path;
528 canon_path = g_strdup(path);
529 len = strlen(canon_path);
530 if (canon_path[len-1] == '/')
531 canon_path[len-1] = 0;
532 } else {
533 canon_path = g_strdup(path);
534 }
535
536 status = seaf_sync_manager_get_path_sync_status (seaf->sync_mgr,
537 repo_id,
538 canon_path,
539 is_dir);
540 g_free (canon_path);
541 return status;
542 }
543
544 int
seafile_mark_file_locked(const char * repo_id,const char * path,GError ** error)545 seafile_mark_file_locked (const char *repo_id, const char *path, GError **error)
546 {
547 char *canon_path = NULL;
548 int len;
549 int ret;
550
551 if (!repo_id || !path) {
552 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
553 return -1;
554 }
555
556 if (*path == '/')
557 ++path;
558
559 if (path[0] == 0) {
560 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid path");
561 return -1;
562 }
563
564 canon_path = g_strdup(path);
565 len = strlen(canon_path);
566 if (canon_path[len-1] == '/')
567 canon_path[len-1] = 0;
568
569 ret = seaf_filelock_manager_mark_file_locked (seaf->filelock_mgr,
570 repo_id, path, FALSE);
571
572 g_free (canon_path);
573 return ret;
574 }
575
576 int
seafile_mark_file_unlocked(const char * repo_id,const char * path,GError ** error)577 seafile_mark_file_unlocked (const char *repo_id, const char *path, GError **error)
578 {
579 char *canon_path = NULL;
580 int len;
581 int ret;
582
583 if (!repo_id || !path) {
584 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
585 return -1;
586 }
587
588 if (*path == '/')
589 ++path;
590
591 if (path[0] == 0) {
592 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid path");
593 return -1;
594 }
595
596 canon_path = g_strdup(path);
597 len = strlen(canon_path);
598 if (canon_path[len-1] == '/')
599 canon_path[len-1] = 0;
600
601 ret = seaf_filelock_manager_mark_file_unlocked (seaf->filelock_mgr,
602 repo_id, path);
603
604 g_free (canon_path);
605 return ret;
606 }
607
608 json_t *
seafile_get_sync_notification(GError ** error)609 seafile_get_sync_notification (GError **error)
610 {
611 return seaf_mq_manager_pop_message (seaf->mq_mgr);
612 }
613
614 char *
seafile_get_server_property(const char * server_url,const char * key,GError ** error)615 seafile_get_server_property (const char *server_url, const char *key, GError **error)
616 {
617 if (!server_url || !key) {
618 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
619 "Argument should not be null");
620 return NULL;
621 }
622
623 return seaf_repo_manager_get_server_property (seaf->repo_mgr,
624 server_url,
625 key);
626 }
627
628 int
seafile_set_server_property(const char * server_url,const char * key,const char * value,GError ** error)629 seafile_set_server_property (const char *server_url,
630 const char *key,
631 const char *value,
632 GError **error)
633 {
634 if (!server_url || !key || !value) {
635 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
636 "Argument should not be null");
637 return -1;
638 }
639
640 return seaf_repo_manager_set_server_property (seaf->repo_mgr,
641 server_url,
642 key, value);
643 }
644
645 GList *
seafile_get_file_sync_errors(int offset,int limit,GError ** error)646 seafile_get_file_sync_errors (int offset, int limit, GError **error)
647 {
648 return seaf_repo_manager_get_file_sync_errors (seaf->repo_mgr, offset, limit);
649 }
650
651 int
seafile_del_file_sync_error_by_id(int id,GError ** error)652 seafile_del_file_sync_error_by_id (int id, GError **error)
653 {
654 return seaf_repo_manager_del_file_sync_error_by_id (seaf->repo_mgr, id);
655 }
656
657 GList*
seafile_get_repo_list(int start,int limit,GError ** error)658 seafile_get_repo_list (int start, int limit, GError **error)
659 {
660 GList *repos = seaf_repo_manager_get_repo_list(seaf->repo_mgr, start, limit);
661 GList *ret = NULL;
662
663 ret = convert_repo_list (repos);
664
665 g_list_free (repos);
666
667 return ret;
668 }
669
670 GObject*
seafile_get_repo(const char * repo_id,GError ** error)671 seafile_get_repo (const char *repo_id, GError **error)
672 {
673 SeafRepo *r;
674
675 if (!repo_id) {
676 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
677 return NULL;
678 }
679 if (!is_uuid_valid (repo_id)) {
680 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo id");
681 return NULL;
682 }
683
684 r = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
685 /* Don't return repo that's not checked out. */
686 if (r == NULL)
687 return NULL;
688
689 GObject *repo = convert_repo (r);
690
691 return repo;
692 }
693
694 static
do_unsync_repo(SeafRepo * repo)695 int do_unsync_repo(SeafRepo *repo)
696 {
697 if (!seaf->started) {
698 seaf_message ("System not started, skip removing repo.\n");
699 return -1;
700 }
701
702 if (repo->auto_sync && (repo->sync_interval == 0))
703 seaf_wt_monitor_unwatch_repo (seaf->wt_monitor, repo->id);
704
705 seaf_sync_manager_cancel_sync_task (seaf->sync_mgr, repo->id);
706
707 SyncInfo *info = seaf_sync_manager_get_sync_info (seaf->sync_mgr, repo->id);
708
709 /* If we are syncing the repo,
710 * we just mark the repo as deleted and let sync-mgr actually delete it.
711 * Otherwise we are safe to delete the repo.
712 */
713 char *worktree = g_strdup (repo->worktree);
714 if (info != NULL && info->in_sync) {
715 seaf_repo_manager_mark_repo_deleted (seaf->repo_mgr, repo);
716 } else {
717 seaf_repo_manager_del_repo (seaf->repo_mgr, repo);
718 }
719
720 g_free (worktree);
721
722 return 0;
723 }
724
725 static void
cancel_clone_tasks_by_account(const char * account_server_url,const char * account_email)726 cancel_clone_tasks_by_account (const char *account_server_url, const char *account_email)
727 {
728 GList *ptr, *tasks;
729 CloneTask *task;
730
731 tasks = seaf_clone_manager_get_tasks (seaf->clone_mgr);
732 for (ptr = tasks; ptr != NULL; ptr = ptr->next) {
733 task = ptr->data;
734
735 if (g_strcmp0(account_server_url, task->server_url) == 0
736 && g_strcmp0(account_email, task->email) == 0) {
737 seaf_clone_manager_cancel_task (seaf->clone_mgr, task->repo_id);
738 }
739 }
740
741 g_list_free (tasks);
742 }
743
744 int
seafile_unsync_repos_by_account(const char * server_url,const char * email,GError ** error)745 seafile_unsync_repos_by_account (const char *server_url, const char *email, GError **error)
746 {
747 if (!server_url || !email) {
748 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
749 return -1;
750 }
751 char *canon_server_url = canonical_server_url (server_url);
752
753 GList *ptr, *repos = seaf_repo_manager_get_repo_list(seaf->repo_mgr, -1, -1);
754 if (!repos) {
755 return 0;
756 }
757
758 for (ptr = repos; ptr; ptr = ptr->next) {
759 SeafRepo *repo = (SeafRepo*)ptr->data;
760 if (g_strcmp0(repo->server_url, canon_server_url) == 0 && g_strcmp0(repo->email, email) == 0) {
761 if (do_unsync_repo(repo) < 0) {
762 return -1;
763 }
764 }
765 }
766
767 g_list_free (repos);
768 g_free (canon_server_url);
769
770 cancel_clone_tasks_by_account (server_url, email);
771
772 return 0;
773 }
774
775 int
seafile_remove_repo_tokens_by_account(const char * server_url,const char * email,GError ** error)776 seafile_remove_repo_tokens_by_account (const char *server_url, const char *email, GError **error)
777 {
778 if (!server_url || !email) {
779 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
780 return -1;
781 }
782 char *canon_server_url = canonical_server_url (server_url);
783
784 GList *ptr, *repos = seaf_repo_manager_get_repo_list(seaf->repo_mgr, -1, -1);
785 if (!repos) {
786 return 0;
787 }
788
789 for (ptr = repos; ptr; ptr = ptr->next) {
790 SeafRepo *repo = (SeafRepo*)ptr->data;
791 if (g_strcmp0(repo->server_url, canon_server_url) == 0 && g_strcmp0(repo->email, email) == 0) {
792 if (seaf_repo_manager_remove_repo_token(seaf->repo_mgr, repo) < 0) {
793 return -1;
794 }
795 }
796 }
797
798 g_list_free (repos);
799 g_free (canon_server_url);
800
801 cancel_clone_tasks_by_account (server_url, email);
802
803 return 0;
804 }
805
806 int
seafile_set_repo_token(const char * repo_id,const char * token,GError ** error)807 seafile_set_repo_token (const char *repo_id,
808 const char *token,
809 GError **error)
810 {
811 int ret;
812
813 if (repo_id == NULL || token == NULL) {
814 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Arguments should not be empty");
815 return -1;
816 }
817
818 SeafRepo *repo;
819 repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
820 if (!repo) {
821 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_REPO, "Can't find Repo %s", repo_id);
822 return -1;
823 }
824
825 ret = seaf_repo_manager_set_repo_token (seaf->repo_mgr,
826 repo, token);
827 if (ret < 0) {
828 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_INTERNAL,
829 "Failed to set token for repo %s", repo_id);
830 return -1;
831 }
832
833 return 0;
834 }
835
836 int
seafile_destroy_repo(const char * repo_id,GError ** error)837 seafile_destroy_repo (const char *repo_id, GError **error)
838 {
839 if (!repo_id) {
840 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
841 return -1;
842 }
843 if (!is_uuid_valid (repo_id)) {
844 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo id");
845 return -1;
846 }
847
848 SeafRepo *repo;
849
850 repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
851 if (!repo) {
852 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "No such repository");
853 return -1;
854 }
855
856 return do_unsync_repo(repo);
857 }
858
859
860 GObject *
seafile_generate_magic_and_random_key(int enc_version,const char * repo_id,const char * passwd,GError ** error)861 seafile_generate_magic_and_random_key(int enc_version,
862 const char* repo_id,
863 const char *passwd,
864 GError **error)
865 {
866 if (!repo_id || !passwd) {
867 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
868 return NULL;
869 }
870
871 gchar salt[65] = {0};
872 gchar magic[65] = {0};
873 gchar random_key[97] = {0};
874
875 if (enc_version >= 3 && seafile_generate_repo_salt (salt) < 0) {
876 return NULL;
877 }
878
879 seafile_generate_magic (enc_version, repo_id, passwd, salt, magic);
880 if (seafile_generate_random_key (passwd, enc_version, salt, random_key) < 0) {
881 return NULL;
882 }
883
884 SeafileEncryptionInfo *sinfo;
885 sinfo = g_object_new (SEAFILE_TYPE_ENCRYPTION_INFO,
886 "repo_id", repo_id,
887 "passwd", passwd,
888 "enc_version", enc_version,
889 "magic", magic,
890 "random_key", random_key,
891 NULL);
892
893 if (enc_version >= 3)
894 g_object_set (sinfo, "salt", salt, NULL);
895
896 return (GObject *)sinfo;
897
898 }
899
900 #include "diff-simple.h"
901
902 inline static const char*
get_diff_status_str(char status)903 get_diff_status_str(char status)
904 {
905 if (status == DIFF_STATUS_ADDED)
906 return "add";
907 if (status == DIFF_STATUS_DELETED)
908 return "del";
909 if (status == DIFF_STATUS_MODIFIED)
910 return "mod";
911 if (status == DIFF_STATUS_RENAMED)
912 return "mov";
913 if (status == DIFF_STATUS_DIR_ADDED)
914 return "newdir";
915 if (status == DIFF_STATUS_DIR_DELETED)
916 return "deldir";
917 return NULL;
918 }
919
920 GList *
seafile_diff(const char * repo_id,const char * arg1,const char * arg2,int fold_dir_diff,GError ** error)921 seafile_diff (const char *repo_id, const char *arg1, const char *arg2, int fold_dir_diff, GError **error)
922 {
923 SeafRepo *repo;
924 char *err_msgs = NULL;
925 GList *diff_entries, *p;
926 GList *ret = NULL;
927
928 if (!repo_id || !arg1 || !arg2) {
929 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Argument should not be null");
930 return NULL;
931 }
932
933 if (!is_uuid_valid (repo_id)) {
934 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid repo id");
935 return NULL;
936 }
937
938 if ((arg1[0] != 0 && !is_object_id_valid (arg1)) || !is_object_id_valid(arg2)) {
939 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Invalid commit id");
940 return NULL;
941 }
942
943 repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
944 if (!repo) {
945 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "No such repository");
946 return NULL;
947 }
948
949 diff_entries = seaf_repo_diff (repo, arg1, arg2, fold_dir_diff, &err_msgs);
950 if (err_msgs) {
951 g_set_error (error, SEAFILE_DOMAIN, -1, "%s", err_msgs);
952 g_free (err_msgs);
953 return NULL;
954 }
955
956 for (p = diff_entries; p != NULL; p = p->next) {
957 DiffEntry *de = p->data;
958 SeafileDiffEntry *entry = g_object_new (
959 SEAFILE_TYPE_DIFF_ENTRY,
960 "status", get_diff_status_str(de->status),
961 "name", de->name,
962 "new_name", de->new_name,
963 NULL);
964 ret = g_list_prepend (ret, entry);
965 }
966
967 for (p = diff_entries; p != NULL; p = p->next) {
968 DiffEntry *de = p->data;
969 diff_entry_free (de);
970 }
971 g_list_free (diff_entries);
972
973 return g_list_reverse (ret);
974 }
975
976 int
seafile_shutdown(GError ** error)977 seafile_shutdown (GError **error)
978 {
979 seaf_warning ("Got an exit command. Now exiting\n");
980 exit(0);
981 return 0;
982 }
983
984 char*
seafile_sync_error_id_to_str(int error_id,GError ** error)985 seafile_sync_error_id_to_str (int error_id, GError **error)
986 {
987 return g_strdup(sync_error_id_to_str (error_id));
988 }
989