1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 #include "common.h"
4
5 #include <stdint.h>
6 #include <dirent.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <errno.h>
16
17 #include <glib.h>
18
19 #include "utils.h"
20
21 #include "seafile-session.h"
22
23 #include "mq-mgr.h"
24 #include "seaf-db.h"
25 #include "seaf-utils.h"
26
27 #include "log.h"
28
29 #define CONNECT_INTERVAL_MSEC 10 * 1000
30
31 #define DEFAULT_THREAD_POOL_SIZE 500
32
33 SeafileSession *
seafile_session_new(const char * central_config_dir,const char * seafile_dir,const char * ccnet_dir)34 seafile_session_new(const char *central_config_dir,
35 const char *seafile_dir,
36 const char *ccnet_dir)
37 {
38 char *abs_central_config_dir = NULL;
39 char *abs_seafile_dir;
40 char *abs_ccnet_dir = NULL;
41 char *tmp_file_dir;
42 char *config_file_path;
43 char *config_file_ccnet;
44 GKeyFile *config;
45 GKeyFile *ccnet_config;
46 SeafileSession *session = NULL;
47
48 abs_ccnet_dir = ccnet_expand_path (ccnet_dir);
49 abs_seafile_dir = ccnet_expand_path (seafile_dir);
50 tmp_file_dir = g_build_filename (abs_seafile_dir, "tmpfiles", NULL);
51 if (central_config_dir) {
52 abs_central_config_dir = ccnet_expand_path (central_config_dir);
53 }
54
55 if (checkdir_with_mkdir (abs_seafile_dir) < 0) {
56 seaf_warning ("Config dir %s does not exist and is unable to create\n",
57 abs_seafile_dir);
58 goto onerror;
59 }
60
61 if (checkdir_with_mkdir (tmp_file_dir) < 0) {
62 seaf_warning ("Temp file dir %s does not exist and is unable to create\n",
63 tmp_file_dir);
64 goto onerror;
65 }
66
67 if (checkdir_with_mkdir (abs_ccnet_dir) < 0) {
68 seaf_warning ("Ccnet config dir %s does not exist and is unable to create\n",
69 abs_ccnet_dir);
70 goto onerror;
71 }
72
73 config_file_path = g_build_filename(
74 abs_central_config_dir ? abs_central_config_dir : abs_seafile_dir,
75 "seafile.conf", NULL);
76
77 config_file_ccnet = g_build_filename(
78 abs_central_config_dir ? abs_central_config_dir : abs_ccnet_dir,
79 "ccnet.conf", NULL);
80
81 GError *error = NULL;
82 config = g_key_file_new ();
83 if (!g_key_file_load_from_file (config, config_file_path,
84 G_KEY_FILE_NONE, &error)) {
85 seaf_warning ("Failed to load config file.\n");
86 g_key_file_free (config);
87 g_free (config_file_path);
88 goto onerror;
89 }
90 ccnet_config = g_key_file_new ();
91 g_key_file_set_list_separator (ccnet_config, ',');
92 if (!g_key_file_load_from_file (ccnet_config, config_file_ccnet,
93 G_KEY_FILE_KEEP_COMMENTS, NULL))
94 {
95 seaf_warning ("Can't load ccnet config file %s.\n", config_file_ccnet);
96 g_key_file_free (ccnet_config);
97 g_free (config_file_ccnet);
98 goto onerror;
99 }
100 g_free (config_file_path);
101 g_free (config_file_ccnet);
102
103 session = g_new0(SeafileSession, 1);
104 session->seaf_dir = abs_seafile_dir;
105 session->ccnet_dir = abs_ccnet_dir;
106 session->tmp_file_dir = tmp_file_dir;
107 session->config = config;
108 session->ccnet_config = ccnet_config;
109
110 session->cloud_mode = g_key_file_get_boolean (config,
111 "general", "cloud_mode",
112 NULL);
113
114 if (load_database_config (session) < 0) {
115 seaf_warning ("Failed to load database config.\n");
116 goto onerror;
117 }
118
119 if (load_ccnet_database_config (session) < 0) {
120 seaf_warning ("Failed to load ccnet database config.\n");
121 goto onerror;
122 }
123
124 session->cfg_mgr = seaf_cfg_manager_new (session);
125 if (!session->cfg_mgr)
126 goto onerror;
127 session->fs_mgr = seaf_fs_manager_new (session, abs_seafile_dir);
128 if (!session->fs_mgr)
129 goto onerror;
130 session->block_mgr = seaf_block_manager_new (session, abs_seafile_dir);
131 if (!session->block_mgr)
132 goto onerror;
133 session->commit_mgr = seaf_commit_manager_new (session);
134 if (!session->commit_mgr)
135 goto onerror;
136 session->repo_mgr = seaf_repo_manager_new (session);
137 if (!session->repo_mgr)
138 goto onerror;
139 session->branch_mgr = seaf_branch_manager_new (session);
140 if (!session->branch_mgr)
141 goto onerror;
142
143 session->share_mgr = seaf_share_manager_new (session);
144 if (!session->share_mgr)
145 goto onerror;
146
147 session->web_at_mgr = seaf_web_at_manager_new (session);
148 if (!session->web_at_mgr)
149 goto onerror;
150
151 session->passwd_mgr = seaf_passwd_manager_new (session);
152 if (!session->passwd_mgr)
153 goto onerror;
154
155 session->quota_mgr = seaf_quota_manager_new (session);
156 if (!session->quota_mgr)
157 goto onerror;
158
159 session->copy_mgr = seaf_copy_manager_new (session);
160 if (!session->copy_mgr)
161 goto onerror;
162
163 session->job_mgr = ccnet_job_manager_new (DEFAULT_THREAD_POOL_SIZE);
164
165 session->size_sched = size_scheduler_new (session);
166
167 session->mq_mgr = seaf_mq_manager_new ();
168 if (!session->mq_mgr)
169 goto onerror;
170
171 session->http_server = seaf_http_server_new (session);
172 if (!session->http_server)
173 goto onerror;
174
175 session->zip_download_mgr = zip_download_mgr_new ();
176 if (!session->zip_download_mgr)
177 goto onerror;
178
179 session->index_blocks_mgr = index_blocks_mgr_new (session);
180 if (!session->index_blocks_mgr)
181 goto onerror;
182
183 session->user_mgr = ccnet_user_manager_new (session);
184 if (!session->user_mgr)
185 goto onerror;
186
187 session->group_mgr = ccnet_group_manager_new (session);
188 if (!session->group_mgr)
189 goto onerror;
190
191 session->org_mgr = ccnet_org_manager_new (session);
192 if (!session->org_mgr)
193 goto onerror;
194
195 return session;
196
197 onerror:
198 free (abs_seafile_dir);
199 free (abs_ccnet_dir);
200 g_free (tmp_file_dir);
201 g_free (session);
202 return NULL;
203 }
204
205 int
seafile_session_init(SeafileSession * session)206 seafile_session_init (SeafileSession *session)
207 {
208 if (seaf_commit_manager_init (session->commit_mgr) < 0)
209 return -1;
210
211 if (seaf_fs_manager_init (session->fs_mgr) < 0)
212 return -1;
213
214 if (seaf_branch_manager_init (session->branch_mgr) < 0) {
215 seaf_warning ("Failed to init branch manager.\n");
216 return -1;
217 }
218
219 if (seaf_repo_manager_init (session->repo_mgr) < 0) {
220 seaf_warning ("Failed to init repo manager.\n");
221 return -1;
222 }
223
224 if (seaf_quota_manager_init (session->quota_mgr) < 0) {
225 seaf_warning ("Failed to init quota manager.\n");
226 return -1;
227 }
228
229 if (ccnet_user_manager_prepare (session->user_mgr) < 0) {
230 seaf_warning ("Failed to init user manager.\n");
231 return -1;
232 }
233
234 if (ccnet_group_manager_prepare (session->group_mgr) < 0) {
235 seaf_warning ("Failed to init group manager.\n");
236 return -1;
237 }
238
239 if (ccnet_org_manager_prepare (session->org_mgr) < 0) {
240 seaf_warning ("Failed to init org manager.\n");
241 return -1;
242 }
243
244 if ((session->create_tables || seaf_db_type(session->db) == SEAF_DB_TYPE_PGSQL)
245 && seaf_cfg_manager_init (session->cfg_mgr) < 0) {
246 seaf_warning ("Failed to init config manager.\n");
247 return -1;
248 }
249
250 return 0;
251 }
252
253 int
seafile_session_start(SeafileSession * session)254 seafile_session_start (SeafileSession *session)
255 {
256 if (seaf_share_manager_start (session->share_mgr) < 0) {
257 seaf_warning ("Failed to start share manager.\n");
258 return -1;
259 }
260
261 if (seaf_web_at_manager_start (session->web_at_mgr) < 0) {
262 seaf_warning ("Failed to start web access check manager.\n");
263 return -1;
264 }
265
266 if (seaf_passwd_manager_start (session->passwd_mgr) < 0) {
267 seaf_warning ("Failed to start password manager.\n");
268 return -1;
269 }
270
271 if (size_scheduler_start (session->size_sched) < 0) {
272 seaf_warning ("Failed to start size scheduler.\n");
273 return -1;
274 }
275
276 if (seaf_copy_manager_start (session->copy_mgr) < 0) {
277 seaf_warning ("Failed to start copy manager.\n");
278 return -1;
279 }
280
281 if (seaf_http_server_start (session->http_server) < 0) {
282 seaf_warning ("Failed to start http server thread.\n");
283 return -1;
284 }
285
286 return 0;
287 }
288
289 char *
get_system_default_repo_id(SeafileSession * session)290 get_system_default_repo_id (SeafileSession *session)
291 {
292 char *sql = "SELECT info_value FROM SystemInfo WHERE info_key='default_repo_id'";
293 return seaf_db_get_string (session->db, sql);
294 }
295
296 int
set_system_default_repo_id(SeafileSession * session,const char * repo_id)297 set_system_default_repo_id (SeafileSession *session, const char *repo_id)
298 {
299 char sql[256];
300 snprintf (sql, sizeof(sql),
301 "INSERT INTO SystemInfo (info_key, info_value) VALUES ('default_repo_id', '%s')",
302 repo_id);
303 return seaf_db_query (session->db, sql);
304 }
305
306 static int
del_system_default_repo_id(SeafileSession * session)307 del_system_default_repo_id (SeafileSession *session)
308 {
309 const char *sql = "DELETE FROM SystemInfo WHERE info_key='default_repo_id'";
310 return seaf_db_query (session->db, sql);
311 }
312
313 #define DEFAULT_TEMPLATE_DIR "library-template"
314
315 static void
copy_template_files_recursive(SeafileSession * session,const char * repo_id,const char * repo_dir_path,const char * dir_path)316 copy_template_files_recursive (SeafileSession *session,
317 const char *repo_id,
318 const char *repo_dir_path,
319 const char *dir_path)
320 {
321 GDir *dir;
322 const char *name;
323 char *sub_path, *repo_sub_path;
324 SeafStat st;
325 GError *error = NULL;
326 int rc;
327
328 dir = g_dir_open (dir_path, 0, &error);
329 if (!dir) {
330 seaf_warning ("Failed to open template dir %s: %s.\n",
331 dir_path, error->message);
332 return;
333 }
334
335 while ((name = g_dir_read_name(dir)) != NULL) {
336 sub_path = g_build_filename (dir_path, name, NULL);
337 if (seaf_stat (sub_path, &st) < 0) {
338 seaf_warning ("Failed to stat %s: %s.\n", sub_path, strerror(errno));
339 g_free (sub_path);
340 continue;
341 }
342
343 if (S_ISREG(st.st_mode)) {
344 rc = seaf_repo_manager_post_file (session->repo_mgr,
345 repo_id,
346 sub_path,
347 repo_dir_path,
348 name,
349 "System",
350 NULL);
351 if (rc < 0)
352 seaf_warning ("Failed to add template file %s.\n", sub_path);
353 } else if (S_ISDIR(st.st_mode)) {
354 rc = seaf_repo_manager_post_dir (session->repo_mgr,
355 repo_id,
356 repo_dir_path,
357 name,
358 "System",
359 NULL);
360 if (rc < 0) {
361 seaf_warning ("Failed to add template dir %s.\n", sub_path);
362 g_free (sub_path);
363 continue;
364 }
365
366 repo_sub_path = g_build_path ("/", repo_dir_path, name, NULL);
367 copy_template_files_recursive (session, repo_id,
368 repo_sub_path, sub_path);
369 g_free (repo_sub_path);
370 }
371 g_free (sub_path);
372 }
373 g_dir_close (dir);
374 }
375
376 static void *
create_system_default_repo(void * data)377 create_system_default_repo (void *data)
378 {
379 SeafileSession *session = data;
380 char *repo_id;
381 char *template_path;
382
383 /* If default repo is not set or doesn't exist, create a new one. */
384 repo_id = get_system_default_repo_id (session);
385 if (repo_id != NULL) {
386 SeafRepo *repo;
387 repo = seaf_repo_manager_get_repo (session->repo_mgr, repo_id);
388 if (!repo) {
389 seaf_warning ("Failed to get system default repo. Create a new one.\n");
390 del_system_default_repo_id (session);
391 seaf_repo_manager_del_repo (session->repo_mgr, repo_id, NULL);
392 g_free (repo_id);
393 } else {
394 seaf_repo_unref (repo);
395 g_free (repo_id);
396 return data;
397 }
398 }
399
400 repo_id = seaf_repo_manager_create_new_repo (session->repo_mgr,
401 "My Library Template",
402 "Template for creating 'My Library' for users",
403 "System",
404 NULL, -1, NULL);
405 if (!repo_id) {
406 seaf_warning ("Failed to create system default repo.\n");
407 return data;
408 }
409
410 set_system_default_repo_id (session, repo_id);
411
412 template_path = g_build_filename (session->seaf_dir, DEFAULT_TEMPLATE_DIR, NULL);
413 copy_template_files_recursive (session, repo_id, "/", template_path);
414
415 g_free (repo_id);
416 g_free (template_path);
417 return data;
418 }
419
420 void
schedule_create_system_default_repo(SeafileSession * session)421 schedule_create_system_default_repo (SeafileSession *session)
422 {
423 int db_type = seaf_db_type (session->db);
424 char *sql;
425
426 if (db_type == SEAF_DB_TYPE_MYSQL)
427 sql = "CREATE TABLE IF NOT EXISTS SystemInfo "
428 "(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, "
429 "info_key VARCHAR(256), info_value VARCHAR(1024))";
430 else
431 sql = "CREATE TABLE IF NOT EXISTS SystemInfo( "
432 "info_key VARCHAR(256), info_value VARCHAR(1024))";
433
434 if ((session->create_tables || db_type == SEAF_DB_TYPE_PGSQL)
435 && seaf_db_query (session->db, sql) < 0)
436 return;
437
438 ccnet_job_manager_schedule_job (session->job_mgr,
439 create_system_default_repo,
440 NULL, session);
441 }
442