summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <marcel@osg.samsung.com>2018-02-18 22:12:58 +0100
committerMarcel Hollerbach <marcel@osg.samsung.com>2018-02-22 09:26:55 +0100
commit7165003bc60177818a491db0d6a557dd0767554b (patch)
treef90eeb3bf587b8f5322ea2a935f80ab2fde68fe3
parent0a6697804154f450df0466b029c8bbbf0b149c78 (diff)
introduce eina_vpath!
Its the successor of efl.vpath, the api is synchronous, and supports addtional vpath paths, new apis cal always be added to use them.
Diffstat (limited to '')
-rw-r--r--src/Makefile_Eina.am9
-rw-r--r--src/lib/eina/Eina.h1
-rw-r--r--src/lib/eina/eina_main.c3
-rw-r--r--src/lib/eina/eina_vpath.c349
-rw-r--r--src/lib/eina/eina_vpath.h74
-rw-r--r--src/tests/eina/eina_suite.c1
-rw-r--r--src/tests/eina/eina_suite.h1
-rw-r--r--src/tests/eina/eina_test_vpath.c53
8 files changed, 488 insertions, 3 deletions
diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am
index 186bd1e8e1..33c7c660c2 100644
--- a/src/Makefile_Eina.am
+++ b/src/Makefile_Eina.am
@@ -107,7 +107,8 @@ lib/eina/eina_slice.h \
107lib/eina/eina_inline_slice.x \ 107lib/eina/eina_inline_slice.x \
108lib/eina/eina_inline_modinfo.x \ 108lib/eina/eina_inline_modinfo.x \
109lib/eina/eina_freeq.h \ 109lib/eina/eina_freeq.h \
110lib/eina/eina_slstr.h 110lib/eina/eina_slstr.h \
111lib/eina/eina_vpath.h
111 112
112 113
113lib_eina_libeina_la_SOURCES = \ 114lib_eina_libeina_la_SOURCES = \
@@ -183,7 +184,8 @@ lib/eina/eina_quaternion.c \
183lib/eina/eina_bezier.c \ 184lib/eina/eina_bezier.c \
184lib/eina/eina_safepointer.c \ 185lib/eina/eina_safepointer.c \
185lib/eina/eina_freeq.c \ 186lib/eina/eina_freeq.c \
186lib/eina/eina_slstr.c 187lib/eina/eina_slstr.c \
188lib/eina/eina_vpath.c
187 189
188 190
189if HAVE_WIN32 191if HAVE_WIN32
@@ -356,7 +358,8 @@ tests/eina/eina_test_bezier.c \
356tests/eina/eina_test_safepointer.c \ 358tests/eina/eina_test_safepointer.c \
357tests/eina/eina_test_slice.c \ 359tests/eina/eina_test_slice.c \
358tests/eina/eina_test_freeq.c \ 360tests/eina/eina_test_freeq.c \
359tests/eina/eina_test_slstr.c 361tests/eina/eina_test_slstr.c \
362tests/eina/eina_test_vpath.c
360 363
361tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ 364tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
362-DTESTS_WD=\"`pwd`\" \ 365-DTESTS_WD=\"`pwd`\" \
diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h
index 256de025bc..b403d308f8 100644
--- a/src/lib/eina/Eina.h
+++ b/src/lib/eina/Eina.h
@@ -274,6 +274,7 @@ extern "C" {
274#include <eina_slstr.h> 274#include <eina_slstr.h>
275#include <eina_debug.h> 275#include <eina_debug.h>
276#include <eina_promise.h> 276#include <eina_promise.h>
277#include <eina_vpath.h>
277 278
278#undef EAPI 279#undef EAPI
279#define EAPI 280#define EAPI
diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c
index 1a152d0da7..275e4a0baa 100644
--- a/src/lib/eina/eina_main.c
+++ b/src/lib/eina/eina_main.c
@@ -68,6 +68,7 @@
68#include "eina_evlog.h" 68#include "eina_evlog.h"
69#include "eina_freeq.h" 69#include "eina_freeq.h"
70#include "eina_slstr.h" 70#include "eina_slstr.h"
71#include "eina_vpath.h"
71 72
72/*============================================================================* 73/*============================================================================*
73* Local * 74* Local *
@@ -155,6 +156,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL;
155 S(safepointer); 156 S(safepointer);
156 S(slstr); 157 S(slstr);
157 S(promise); 158 S(promise);
159 S(vpath);
158#undef S 160#undef S
159 161
160struct eina_desc_setup 162struct eina_desc_setup
@@ -202,6 +204,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
202 S(safepointer), 204 S(safepointer),
203 S(slstr), 205 S(slstr),
204 S(promise), 206 S(promise),
207 S(vpath),
205#undef S 208#undef S
206}; 209};
207static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / 210static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
diff --git a/src/lib/eina/eina_vpath.c b/src/lib/eina/eina_vpath.c
new file mode 100644
index 0000000000..af57afae97
--- /dev/null
+++ b/src/lib/eina/eina_vpath.c
@@ -0,0 +1,349 @@
1#include <Eina.h>
2
3#include "eina_private.h"
4
5static Eina_Hash *vpath_data = NULL;
6
7#ifdef CRI
8#undef CRI
9#endif
10#define CRI(...) EINA_LOG_DOM_CRIT(_eina_vpath_log_dom, __VA_ARGS__)
11
12#ifdef ERR
13#undef ERR
14#endif
15#define ERR(...) EINA_LOG_DOM_ERR(_eina_vpath_log_dom, __VA_ARGS__)
16
17#ifdef DBG
18#undef DBG
19#endif
20#define DBG(...) EINA_LOG_DOM_DBG(_eina_vpath_log_dom, __VA_ARGS__)
21
22static int _eina_vpath_log_dom = -1;
23
24static inline void
25_eina_vpath_data_add(const char *key, const char *value)
26{
27 eina_hash_add(vpath_data, key, eina_stringshare_add(value));
28}
29
30static inline Eina_Stringshare*
31_eina_vpath_data_get(const char *key)
32{
33 return eina_hash_find(vpath_data, key);
34}
35
36
37static char*
38_fallback_runtime_dir(const char *home)
39{
40 char buf[PATH_MAX];
41 struct stat st;
42
43#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
44 if (setuid(geteuid()) != 0)
45 {
46 fprintf(stderr,
47 "FATAL: Cannot setuid - errno=%i\n",
48 errno);
49 abort();
50 }
51#endif
52 // fallback - make ~/.run
53 snprintf(buf, sizeof(buf), "%s/.run", home);
54 if (!!mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR))
55 {
56 if (errno == EEXIST)
57 {
58 if (stat(buf, &st) == 0)
59 {
60 // some sanity checks - but not for security
61 if (!(st.st_mode & S_IFDIR))
62 {
63 // fatal - exists but is not a dir
64 fprintf(stderr,
65 "FATAL: run dir '%s' exists but not a dir\n",
66 buf);
67 abort();
68 }
69#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
70 if (st.st_uid != geteuid())
71 {
72 // fatal - run dir doesn't belong to user
73 fprintf(stderr,
74 "FATAL: run dir '%s' not owned by uid %i\n",
75 buf, (int)geteuid());
76 abort();
77 }
78#endif
79 }
80 else
81 {
82 // fatal - we cant create our run dir in ~/
83 fprintf(stderr,
84 "FATAL: Cannot verify run dir '%s' errno=%i\n",
85 buf, errno);
86 abort();
87 }
88 }
89 else
90 {
91 // fatal - we cant create our run dir in ~/
92 fprintf(stderr,
93 "FATAL: Cannot create run dir '%s' - errno=%i\n",
94 buf, errno);
95 abort();
96 }
97 }
98#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
99 if (setreuid(uid, geteuid()) != 0)
100 {
101 fprintf(stderr,
102 "FATAL: Cannot setreuid - errno=%i\n",
103 errno);
104 abort();
105 }
106#endif
107
108 return strdup(buf);
109}
110
111static char*
112_fallback_home_dir()
113{
114 char buf[PATH_MAX];
115 /* Windows does not have getuid(), but home can't be NULL */
116#ifdef HAVE_GETEUID
117 uid_t uid = geteuid();
118 struct stat st;
119
120 snprintf(buf, sizeof(buf), "/tmp/%i", (int)uid);
121 if (mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
122 {
123 if (errno != EEXIST)
124 {
125 if (stat("/tmp", &st) == 0)
126 snprintf(buf, sizeof(buf), "/tmp");
127 else
128 snprintf(buf, sizeof(buf), "/");
129 }
130 }
131 if (stat(buf, &st) != 0)
132 {
133 if (stat("/tmp", &st) == 0)
134 snprintf(buf, sizeof(buf), "/tmp");
135 else
136 snprintf(buf, sizeof(buf), "/");
137 }
138#else
139 snprintf(buf, sizeof(buf), "/");
140#endif
141 return strdup(buf);
142}
143
144static void
145_eina_vpath_interface_sys_init(void)
146{
147 const char *home, *tmp;
148
149 // $HOME / ~/ etc.
150 home = eina_environment_home_get();
151 if (!home)
152 home = _fallback_home_dir();
153
154 // tmp dir - system wide
155 tmp = eina_environment_tmp_get();
156
157 _eina_vpath_data_add("home", home);
158 _eina_vpath_data_add("tmp", tmp);
159}
160
161Eina_Bool
162eina_vpath_init(void)
163{
164 vpath_data = eina_hash_string_superfast_new((Eina_Free_Cb)eina_stringshare_del);
165
166 _eina_vpath_interface_sys_init();
167
168 _eina_vpath_log_dom = eina_log_domain_register("vpath", "cyan");
169 return EINA_TRUE;
170}
171
172Eina_Bool
173eina_vpath_shutdown(void)
174{
175 eina_log_domain_unregister(_eina_vpath_log_dom);
176 _eina_vpath_log_dom = -1;
177 return EINA_TRUE;
178}
179
180EAPI char*
181eina_vpath_resolve(const char* path)
182{
183 // XXX: implement parse of path then look up in hash if not just create
184 // object where path and result are the same and return that with
185 // path set and result set to resolved path - return obj handler calls
186 // "do" on object to get the result inside fetched or failed callback.
187 // if it's a url then we need a new classs that overrides the do and
188 // begins a fetch and on finish calls the event cb or when wait is called
189 /* FIXME: not working for WIndows */
190 // /* <- full path
191
192 if (!path) return NULL;
193
194 if (path[0] == '~')
195 {
196 // ~/ <- home directory
197 if (path[1] == '/')
198 {
199 char buf[PATH_MAX];
200 const char *home = eina_hash_find(vpath_data, "home");
201
202 if (home)
203 {
204 snprintf(buf, sizeof(buf), "%s%s", home, path + 1);
205 return strdup(buf);
206 }
207 }
208#ifdef HAVE_GETPWENT
209 // ~username/ <- homedir of user "username"
210 else
211 {
212 const char *p;
213 struct passwd pwent, *pwent2 = NULL;
214 char *name, buf[PATH_MAX], pwbuf[8129];
215
216 for (p = path + 1; *p; p++)
217 {
218 if (*p =='/') break;
219 }
220 name = alloca(p - path);
221 strncpy(name, path + 1, p - path - 1);
222 name[p - path - 1] = 0;
223 if (!getpwnam_r(name, &pwent, pwbuf, sizeof(pwbuf), &pwent2))
224 {
225 if ((pwent2) && (pwent.pw_dir))
226 {
227 return strdup(buf);
228 }
229 }
230 }
231#endif /* HAVE_GETPWENT */
232 return NULL;
233 }
234 // (:xxx:)/* ... <- meta hash table
235 else if ((path[0] == '(') && (path[1] == ':'))
236 {
237 const char *p, *end, *meta;
238 char *name, buf[PATH_MAX];
239 int max_len = strlen(path);
240 Eina_Bool found = EINA_FALSE;
241
242 for (p = path + 2; p <= path + max_len - 2; p++)
243 {
244 if ((p[0] ==':') && (p[1] == ')'))
245 {
246 end = p;
247 found = EINA_TRUE;
248 break;
249 }
250 }
251 p += 2;
252
253 if (!found)
254 {
255 ERR("(: Needs to have a matching ':)'\nThe string was: %s", path);
256 return NULL;
257 }
258
259 if (*p != '/')
260 {
261 ERR("A / is expected after :)\nThe string was: %s", path);
262 return NULL;
263 }
264
265 if (found)
266 {
267 name = alloca(end - path);
268 strncpy(name, path + 2, end - path - 2);
269 name[end - path - 2] = 0;
270 meta = _eina_vpath_data_get(name);
271 if (meta)
272 {
273 snprintf(buf, sizeof(buf), "%s%s", meta, end + 2);
274 return strdup(buf);
275 }
276 else
277 {
278 ERR("Meta key '%s' was not registered!\nThe string was: %s", name, path);
279 return NULL;
280 }
281 }
282 }
283 //just return the path, since we assume that this is a normal path
284 else
285 {
286 return strdup(path);
287 }
288
289 ERR("The path has to start with either '~/' or '(:NAME:)/' or be a normal path \nThe string was: %s", path);
290
291 return NULL;
292}
293
294EAPI void
295eina_vpath_interface_app_set(const char *app_domain, Eina_Prefix *app_pfx)
296{
297 char buf[PATH_MAX];
298
299 EINA_SAFETY_ON_NULL_RETURN(app_domain);
300 EINA_SAFETY_ON_NULL_RETURN(app_pfx);
301
302 _eina_vpath_data_add("app.dir", eina_prefix_get(app_pfx));
303 _eina_vpath_data_add("app.bin", eina_prefix_bin_get(app_pfx));
304 _eina_vpath_data_add("app.lib", eina_prefix_lib_get(app_pfx));
305 _eina_vpath_data_add("app.data", eina_prefix_data_get(app_pfx));
306 _eina_vpath_data_add("app.locale", eina_prefix_locale_get(app_pfx));
307 snprintf(buf, sizeof(buf), "%s/%s",
308 _eina_vpath_data_get("config"), app_domain);
309 _eina_vpath_data_add("app.config", buf);
310 snprintf(buf, sizeof(buf), "%s/%s",
311 _eina_vpath_data_get("cache"), app_domain);
312 _eina_vpath_data_add("app.cache", buf);
313 snprintf(buf, sizeof(buf), "%s/%s",
314 _eina_vpath_data_get("data"), app_domain);
315 _eina_vpath_data_add("app.local", buf);
316}
317
318EAPI void
319eina_vpath_interface_user_set(Eina_Vpath_Interface_User *user)
320{
321 char buf[PATH_MAX];
322 Eina_Bool free_run = EINA_FALSE;
323
324 EINA_SAFETY_ON_NULL_RETURN(user);
325
326 if (!user->run)
327 {
328 user->run = _fallback_runtime_dir(_eina_vpath_data_get("home"));
329 free_run = EINA_TRUE;
330 }
331
332#define ADD(a) _eina_vpath_data_add("usr." #a , user->a)
333 ADD(desktop);
334 ADD(documents);
335 ADD(downloads);
336 ADD(music);
337 ADD(pictures);
338 ADD(pub);
339 ADD(templates);
340 ADD(videos);
341 ADD(data);
342 ADD(config);
343 ADD(cache);
344 ADD(run);
345#undef ADD
346
347 if (free_run)
348 free((char*)user->run);
349}
diff --git a/src/lib/eina/eina_vpath.h b/src/lib/eina/eina_vpath.h
new file mode 100644
index 0000000000..40adffeca1
--- /dev/null
+++ b/src/lib/eina/eina_vpath.h
@@ -0,0 +1,74 @@
1#ifndef EINA_VPATH_H
2#define EINA_VPATH_H
3
4#include "eina_prefix.h"
5
6/*
7 * Eina_vpath
8 * eina vpath is a path that can be prefixed with a virtual path.
9 *
10 * A virutla path can either start with (:XXXXXXXX:) that indicates a virtual path, OR normal with / or ./ or ../ or ~
11 * The char sequence in between (: and :) are used as key to lookup the real value.
12 * The key has to be set by a interface before, otherwise you will get a error.
13 *
14 * The symbol ~ is interpretated as the home directory of the running user, and will be replaced.
15 * Additional infos: https://phab.enlightenment.org/w/eina_vpath/
16 */
17
18/**
19 * This datatype is a vpath, this means you can use the syntax described above.
20 */
21typedef const char* Eina_Vpath;
22
23
24typedef struct
25{
26 const char *desktop;
27 const char *documents;
28 const char *downloads;
29 const char *music;
30 const char *pictures;
31 const char *pub;
32 const char *templates;
33 const char *videos;
34 const char *data;
35 const char *config;
36 const char *cache;
37 const char *run;
38} Eina_Vpath_Interface_User;
39
40/**
41 * Make the app specific paths accessable as virtual path
42 *
43 * This will create :
44 * - app.dir
45 * - app.bin
46 * - app.lib
47 * - app.data
48 * - app.locale
49 * - app.config
50 * - app.cache
51 * - app.local
52 *
53 * If you do NOT call this api the virtual paths for app.* will be unset
54 */
55EAPI void eina_vpath_interface_app_set(const char *app_name, Eina_Prefix *p);
56
57/**
58 * Create the desktop specific vpaths
59 *
60 * The virtual paths will be named usr.<field-name-of-struct>
61 *
62 * If you do NOT call this api the virtual paths for usr.* will be unset.
63 */
64EAPI void eina_vpath_interface_user_set(Eina_Vpath_Interface_User *user);
65
66/*
67 * Translate a virtual path into a normal path.
68 *
69 * @return a string that is not virtual anymore
70 *
71 */
72EAPI char* eina_vpath_resolve(Eina_Vpath path);
73
74#endif
diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c
index 8e833356f3..bd3bf42a4e 100644
--- a/src/tests/eina/eina_suite.c
+++ b/src/tests/eina/eina_suite.c
@@ -87,6 +87,7 @@ static const Efl_Test_Case etc[] = {
87 { "Free Queue", eina_test_freeq }, 87 { "Free Queue", eina_test_freeq },
88 { "Util", eina_test_util }, 88 { "Util", eina_test_util },
89 { "Short Lived Strings", eina_test_slstr }, 89 { "Short Lived Strings", eina_test_slstr },
90 { "Vpath", eina_test_vpath },
90 { NULL, NULL } 91 { NULL, NULL }
91}; 92};
92 93
diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h
index 7bf643e478..9b8351bd25 100644
--- a/src/tests/eina/eina_suite.h
+++ b/src/tests/eina/eina_suite.h
@@ -74,5 +74,6 @@ void eina_test_safepointer(TCase *tc);
74void eina_test_slice(TCase *tc); 74void eina_test_slice(TCase *tc);
75void eina_test_freeq(TCase *tc); 75void eina_test_freeq(TCase *tc);
76void eina_test_slstr(TCase *tc); 76void eina_test_slstr(TCase *tc);
77void eina_test_vpath(TCase *tc);
77 78
78#endif /* EINA_SUITE_H_ */ 79#endif /* EINA_SUITE_H_ */
diff --git a/src/tests/eina/eina_test_vpath.c b/src/tests/eina/eina_test_vpath.c
new file mode 100644
index 0000000000..b09d2d5c9a
--- /dev/null
+++ b/src/tests/eina/eina_test_vpath.c
@@ -0,0 +1,53 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <Eina.h>
6#include <check.h>
7
8
9START_TEST(eina_test_vpath_valid)
10{
11 int ret;
12 char test[PATH_MAX];
13
14 ret = eina_init();
15 ck_assert_int_ne(ret, 0);
16
17 ck_assert_str_eq(eina_vpath_resolve("/"), "/");
18 ck_assert_str_eq(eina_vpath_resolve("./"), "./");
19 ck_assert_str_eq(eina_vpath_resolve("..bla"), "..bla");
20 ck_assert_str_eq(eina_vpath_resolve(".bla"), ".bla");
21
22 snprintf(test, sizeof(test), "%s/", eina_environment_home_get());
23 ck_assert_str_eq(eina_vpath_resolve("~/"), test);
24
25 snprintf(test, sizeof(test), "%s/bla", eina_environment_home_get());
26 ck_assert_str_eq(eina_vpath_resolve("(:home:)/bla"), test);
27
28 ret = eina_shutdown();
29}
30END_TEST
31
32START_TEST(eina_test_vpath_invalid)
33{
34 int ret;
35
36 ret = eina_init();
37 ck_assert_int_ne(ret, 0);
38
39 ck_assert_ptr_null(eina_vpath_resolve("(:asdfasdfafasdf"));
40 ck_assert_ptr_null(eina_vpath_resolve("(:missing_slash:)"));
41 ck_assert_ptr_null(eina_vpath_resolve("(:"));
42 ck_assert_ptr_null(eina_vpath_resolve("(:home:)"));
43 ck_assert_ptr_null(eina_vpath_resolve("(:wrong_meta_key:)/"));
44
45 ret = eina_shutdown();
46}
47END_TEST
48
49void eina_test_vpath(TCase *tc)
50{
51 tcase_add_test(tc, eina_test_vpath_invalid);
52 tcase_add_test(tc, eina_test_vpath_valid);
53}