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