1 /* Copyright (C) 2016-2018 Shengyu Zhang <i@silverrainz.me>
2  *
3  * This file is part of Srain.
4  *
5  * Srain is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file path.c
21  * @brief Get application data files' path
22  * @author Shengyu Zhang <i@silverrainz.me>
23  * @version 0.06.2
24  * @date 2018-12-15
25  */
26 
27 
28 #include <sys/stat.h>
29 #include <glib.h>
30 #include <glib/gstdio.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 
34 #include "meta.h"
35 #include "log.h"
36 #include "i18n.h"
37 
38 #define DEFAULT_FILE_MODE   (S_IRUSR | S_IWUSR)
39 #define DEFAULT_DIR_MODE    (S_IRWXU)
40 
41 static SrnRet create_file_if_not_exist(const char *path);
42 static SrnRet create_dir_if_not_exist(const char *path);
43 
44 /**
45  * @brief srn_get_theme_file returns the path of theme file with specified name.
46  *  If the file is not found, returns NULL.
47  *
48  * @param fname
49  *
50  * @return NULL or path to the theme file, must be freed by g_free.
51  */
srn_get_theme_file(const char * name)52 char *srn_get_theme_file(const char *name){
53     char *path;
54 
55     path = g_build_filename(PACKAGE_DATA_DIR, PACKAGE, "themes", name, NULL);
56 
57     if (g_file_test(path, G_FILE_TEST_EXISTS)){
58         return path;
59     }
60 
61     g_free(path);
62     return NULL;
63 }
64 
srn_get_user_config_file()65 char *srn_get_user_config_file(){
66     char *path;
67     SrnRet ret;
68 
69     path = g_build_filename(g_get_user_config_dir(), PACKAGE, "srain.cfg", NULL);
70 
71     ret = create_file_if_not_exist(path);
72     if (!RET_IS_OK(ret)){
73         WARN_FR("Failed to create user configuration file: %1$s", RET_MSG(ret));
74 
75         g_free(path);
76         return NULL;
77     }
78 
79     return path;
80 }
81 
srn_get_system_config_file()82 char *srn_get_system_config_file(){
83     char *path;
84 
85     path = g_build_filename(PACKAGE_CONFIG_DIR, PACKAGE, "builtin.cfg", NULL);
86 
87     if (g_file_test(path, G_FILE_TEST_EXISTS)){
88         return path;
89     }
90 
91     // System configuration file should always exist
92     WARN_FR("'%s' not found", path);
93 
94     g_free(path);
95     return NULL;
96 }
97 
98 // FIXME: actually it only create the dir.
srn_create_log_file(const char * srv_name,const char * fname)99 char *srn_create_log_file(const char *srv_name, const char *fname){
100     char *path;
101     SrnRet ret;
102 
103     // $XDG_DATA_HOME/srain/logs/<srv_name>/<fname>
104     path = g_build_filename(g_get_user_data_dir(),
105             PACKAGE, "logs", srv_name, fname, NULL);
106 
107     ret = create_file_if_not_exist(path);
108     if (!RET_IS_OK(ret)){
109         WARN_FR("Failed to create log file: %1$s", RET_MSG(ret));
110 
111         g_free(path);
112         return NULL;
113     }
114 
115     return path;
116 }
117 
118 /**
119  * @brief srn_create_user_files creates users files which required for
120  *  running of Srain
121  *
122  * @return SRN_OK if all required files are created or already existent
123  *
124  * User fils including:
125  *
126  *  - $XDG_CONFIG_HOME/srain/
127  *  - $XDG_CONFIG_HOME/srain/srain.cfg
128  *  - $XDG_CACHE_HOME/srain/
129  *  - $XDG_DATA_HOME/srain/logs
130  *
131  *  FIXME: not in use
132  */
srn_create_user_files()133 SrnRet srn_create_user_files(){
134     SrnRet ret;
135     char *path;
136 
137     path = g_build_filename( // $XDG_CONFIG_HOME/srain/
138             g_get_user_config_dir(),
139             PACKAGE,
140             NULL);
141     ret = create_dir_if_not_exist(path);
142     g_free(path);
143     if (!RET_IS_OK(ret)){
144         ret = RET_ERR(_("Failed to create user configuration directory: %1$s"),
145                 RET_MSG(ret));
146         goto FIN;
147     }
148 
149     // $XDG_CONFIG_HOME/srain/srain.cfg
150     path = g_build_filename(g_get_user_config_dir(), PACKAGE, "srain.cfg", NULL);
151     ret = create_file_if_not_exist(path);
152     g_free(path);
153     if (!RET_IS_OK(ret)){
154         ret = RET_ERR(_("Failed to create user configuration file: %1$s"),
155                 RET_MSG(ret));
156         goto FIN;
157     }
158 
159     // $XDG_CACHE_HOME/srain/
160     path = g_build_filename(g_get_user_cache_dir(), PACKAGE, NULL);
161     ret = create_dir_if_not_exist(path);
162     g_free(path);
163     if (!RET_IS_OK(ret)){
164         ret = RET_ERR(_("Failed to create user cache directory: %1$s"),
165                 RET_MSG(ret));
166         goto FIN;
167     }
168 
169     // $XDG_DATA_HOME/srain/
170     path = g_build_filename(g_get_user_data_dir(), PACKAGE, NULL);
171     ret = create_dir_if_not_exist(path);
172     g_free(path);
173     if (!RET_IS_OK(ret)){
174         ret = RET_ERR(_("Failed to create user data directory: %1$s"),
175                 RET_MSG(ret));
176         goto FIN;
177     }
178 
179     // $XDG_DATA_HOME/srain/logs
180     path = g_build_filename(g_get_user_data_dir(), PACKAGE, "logs", NULL);
181     ret = create_dir_if_not_exist(path);
182     g_free(path);
183     if (!RET_IS_OK(ret)){
184         ret = RET_ERR(_("Failed to create chat logs directory: %1$s"),
185                 RET_MSG(ret));
186         goto FIN;
187     }
188 
189     ret = SRN_OK;
190 FIN:
191     return ret;
192 }
193 
create_dir_if_not_exist(const char * path)194 SrnRet create_dir_if_not_exist(const char *path) {
195     if (g_file_test(path, G_FILE_TEST_IS_DIR)){
196         return SRN_OK;
197     }
198     if (g_file_test(path, G_FILE_TEST_EXISTS)){
199         return RET_ERR(_("Not a directory"));
200     }
201 
202     if (g_mkdir_with_parents(path, DEFAULT_DIR_MODE) == -1) {
203         return RET_ERR("%s", g_strerror(errno));
204     }
205 
206     return SRN_OK;
207 }
208 
create_file_if_not_exist(const char * path)209 SrnRet create_file_if_not_exist(const char *path) {
210     int fd;
211     char *dir;
212     SrnRet ret;
213 
214     if (g_file_test(path, G_FILE_TEST_IS_REGULAR)){
215         return SRN_OK;
216     }
217     if (g_file_test(path, G_FILE_TEST_EXISTS)){
218         return RET_ERR(_("Not a regular file"));
219     }
220 
221     dir = g_path_get_dirname(path);
222     ret = create_dir_if_not_exist(dir);
223     g_free(dir);
224     if (!RET_IS_OK(ret)){
225         return ret;
226     }
227 
228     if ((fd = g_creat(path, DEFAULT_FILE_MODE)) == -1) {
229         return RET_ERR("%s", g_strerror(errno));
230     }
231     g_close(fd, NULL);
232 
233     return SRN_OK;
234 }
235