Remove last trailing comma
[apps/livebox/data-provider-master.git] / src / util.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <sys/time.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <sys/vfs.h>
24 #include <sys/types.h>
25 #include <dirent.h>
26 #include <ctype.h>
27
28 #include <dlog.h>
29 #include <Eina.h>
30 #include <Ecore.h>
31 #include <livebox-errno.h>
32
33 #include "util.h"
34 #include "debug.h"
35 #include "conf.h"
36
37 int errno;
38
39 HAPI unsigned long util_string_hash(const char *str)
40 {
41         unsigned long ret = 0;
42
43         while (*str)
44                 ret += (unsigned long)(*str++);
45
46         ret %= 371773;
47         return ret;
48 }
49
50 HAPI double util_timestamp(void)
51 {
52         struct timeval tv;
53
54         if (gettimeofday(&tv, NULL) < 0) {
55                 static unsigned long internal_count = 0;
56                 ErrPrint("failed to get time of day: %s\n", strerror(errno));
57                 tv.tv_sec = internal_count++;
58                 tv.tv_usec = 0;
59         }
60
61         return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
62 }
63
64 HAPI int util_check_ext(const char *filename, const char *check_ptr)
65 {
66         int name_len;
67
68         name_len = strlen(filename);
69         while (--name_len >= 0 && *check_ptr) {
70                 if (filename[name_len] != *check_ptr)
71                         return LB_STATUS_ERROR_INVALID;
72
73                 check_ptr ++;
74         }
75
76         return LB_STATUS_SUCCESS;
77 }
78
79 static inline int check_native_livebox(const char *pkgname)
80 {
81         int len;
82         char *path;
83
84         len = strlen(pkgname) * 2;
85         len += strlen(ROOT_PATH);
86         len += strlen("%s/libexec/liblive-%s.so");
87
88         path = malloc(len + 1);
89         if (!path) {
90                 ErrPrint("Heap: %s\n", strerror(errno));
91                 return LB_STATUS_ERROR_MEMORY;
92         }
93
94         snprintf(path, len, "%s%s/libexec/liblive-%s.so", ROOT_PATH, pkgname, pkgname);
95         if (access(path, F_OK | R_OK) != 0) {
96                 ErrPrint("%s is not a valid package\n", pkgname);
97                 DbgFree(path);
98                 return LB_STATUS_ERROR_INVALID;
99         }
100
101         DbgFree(path);
102         return LB_STATUS_SUCCESS;
103 }
104
105 static inline int check_web_livebox(const char *pkgname)
106 {
107         int len;
108         char *path;
109
110         len = strlen(pkgname) * 2;
111         len += strlen("/opt/usr/apps/%s/res/wgt/livebox/index.html");
112
113         path = malloc(len + 1);
114         if (!path) {
115                 ErrPrint("Heap: %s\n", strerror(errno));
116                 return LB_STATUS_ERROR_MEMORY;
117         }
118
119         snprintf(path, len, "/opt/usr/apps/%s/res/wgt/livebox/index.html", pkgname);
120         if (access(path, F_OK | R_OK) != 0) {
121                 ErrPrint("%s is not a valid package\n", pkgname);
122                 DbgFree(path);
123                 return LB_STATUS_ERROR_INVALID;
124         }
125
126         DbgFree(path);
127         return LB_STATUS_SUCCESS;
128 }
129
130 HAPI int util_validate_livebox_package(const char *pkgname)
131 {
132         if (!pkgname) {
133                 ErrPrint("Invalid argument\n");
134                 return LB_STATUS_ERROR_INVALID;
135         }
136
137         if (!check_native_livebox(pkgname) || !check_web_livebox(pkgname))
138                 return LB_STATUS_SUCCESS;
139
140         return LB_STATUS_ERROR_INVALID;
141 }
142
143 HAPI int util_unlink(const char *filename)
144 {
145         char *descfile;
146         int desclen;
147         int ret;
148
149         if (!filename)
150                 return LB_STATUS_ERROR_INVALID;
151
152         desclen = strlen(filename) + 6; /* .desc */
153         descfile = malloc(desclen);
154         if (!descfile) {
155                 ErrPrint("Heap: %s\n", strerror(errno));
156                 return LB_STATUS_ERROR_MEMORY;
157         }
158
159         ret = snprintf(descfile, desclen, "%s.desc", filename);
160         if (ret < 0) {
161                 ErrPrint("Error: %s\n", strerror(errno));
162                 DbgFree(descfile);
163                 return LB_STATUS_ERROR_FAULT;
164         }
165
166         (void)unlink(descfile);
167         DbgFree(descfile);
168         (void)unlink(filename);
169
170         return LB_STATUS_SUCCESS;
171 }
172
173 HAPI char *util_slavename(void)
174 {
175         char slavename[BUFSIZ];
176         static unsigned long idx = 0;
177
178         snprintf(slavename, sizeof(slavename), "%lu_%lf", idx++, util_timestamp());
179         return strdup(slavename);
180 }
181
182 HAPI const char *util_basename(const char *name)
183 {
184         int length;
185         length = name ? strlen(name) : 0;
186         if (!length)
187                 return ".";
188
189         while (--length > 0 && name[length] != '/');
190
191         return length <= 0 ? name : (name + length + (name[length] == '/'));
192 }
193
194 /*!
195  * Return size of stroage in MegaBytes unit.
196  */
197 HAPI unsigned long long util_free_space(const char *path)
198 {
199         struct statfs st;
200         unsigned long long space;
201
202         if (statfs(path, &st) < 0) {
203                 ErrPrint("statvfs: %s\n", strerror(errno));
204                 return 0lu;
205         }
206
207         space = (unsigned long long)st.f_bsize * (unsigned long long)st.f_bavail;
208         DbgPrint("Available size: %llu, f_bsize: %lu, f_bavail: %lu\n", space, st.f_bsize, st.f_bavail);
209         /*!
210          * \note
211          * Must have to check the overflow
212          */
213         return space;
214 }
215
216 static inline char *extend_heap(char *buffer, int *sz, int incsz)
217 {
218         char *tmp;
219
220         *sz += incsz;
221         tmp = realloc(buffer, *sz);
222         if (!tmp) {
223                 ErrPrint("Heap: %s\n", strerror(errno));
224                 return NULL;
225         }
226
227         return tmp;
228 }
229
230
231 HAPI char *util_replace_string(const char *src, const char *pattern, const char *replace)
232 {
233         const char *ptr;
234         char *tmp;
235         char *ret = NULL;
236         int idx;
237         int out_idx;
238         int out_sz;
239         enum {
240                 STATE_START,
241                 STATE_FIND,
242                 STATE_CHECK,
243                 STATE_END
244         } state;
245
246         if (!src || !pattern)
247                 return NULL;
248
249         out_sz = strlen(src);
250         ret = strdup(src);
251         if (!ret) {
252                 ErrPrint("Heap: %s\n", strerror(errno));
253                 return NULL;
254         }
255
256         out_idx = 0;
257         for (state = STATE_START, ptr = src; state != STATE_END; ptr++) {
258                 switch (state) {
259                 case STATE_START:
260                         if (*ptr == '\0') {
261                                 state = STATE_END;
262                         } else if (!isblank(*ptr)) {
263                                 state = STATE_FIND;
264                                 ptr--;
265                         }
266                         break;
267                 case STATE_FIND:
268                         if (*ptr == '\0') {
269                                 state = STATE_END;
270                         } else if (*ptr == *pattern) {
271                                 state = STATE_CHECK;
272                                 ptr--;
273                                 idx = 0;
274                         } else {
275                                 ret[out_idx] = *ptr;
276                                 out_idx++;
277                                 if (out_idx == out_sz) {
278                                         tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
279                                         if (!tmp) {
280                                                 free(ret);
281                                                 return NULL;
282                                         }
283                                         ret = tmp;
284                                 }
285                         }
286                         break;
287                 case STATE_CHECK:
288                         if (!pattern[idx]) {
289                                 /*!
290                                  * If there is no space for copying the replacement,
291                                  * Extend size of the return buffer.
292                                  */
293                                 if (out_sz - out_idx < strlen(replace) + 1) {
294                                         tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
295                                         if (!tmp) {
296                                                 free(ret);
297                                                 return NULL;
298                                         }
299                                         ret = tmp;
300                                 }
301
302                                 strcpy(ret + out_idx, replace);
303                                 out_idx += strlen(replace);
304
305                                 state = STATE_FIND;
306                                 ptr--;
307                         } else if (*ptr != pattern[idx]) {
308                                 ptr -= idx;
309
310                                 /* Copy the first matched character */
311                                 ret[out_idx] = *ptr;
312                                 out_idx++;
313                                 if (out_idx == out_sz) {
314                                         tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
315                                         if (!tmp) {
316                                                 free(ret);
317                                                 return NULL;
318                                         }
319
320                                         ret = tmp;
321                                 }
322
323                                 state = STATE_FIND;
324                         } else {
325                                 idx++;
326                         }
327                         break;
328                 default:
329                         break;
330                 }
331         }
332
333         return ret;
334 }
335
336
337 HAPI const char *util_uri_to_path(const char *uri)
338 {
339         int len;
340
341         len = strlen(SCHEMA_FILE);
342         if (strncasecmp(uri, SCHEMA_FILE, len))
343                 return NULL;
344
345         return uri + len;
346 }
347
348 HAPI double util_time_delay_for_compensation(double period)
349 {
350         struct timeval tv;
351         unsigned long long curtime;
352         unsigned long long _period;
353         unsigned long long remain;
354         double ret;
355
356         if (period == 0.0f) {
357                 DbgPrint("Period is ZERO\n");
358                 return 0.0f;
359         }
360
361         if (gettimeofday(&tv, NULL) < 0){
362                 ErrPrint("gettimeofday: %s\n", strerror(errno));
363                 return period;
364         }
365
366         curtime = (unsigned long long)tv.tv_sec * 1000000llu + (unsigned long long)tv.tv_usec;
367         _period = (unsigned long long)(period * (double)1000000);
368         if (_period == 0llu) {
369                 ErrPrint("%lf <> %llu\n", period, _period);
370                 return period;
371         }
372
373         remain = curtime % _period;
374
375         ret = (double)remain / (double)1000000;
376         return period - ret;
377 }
378
379 HAPI void *util_timer_add(double interval, Eina_Bool (*cb)(void *data), void *data)
380 {
381         Ecore_Timer *timer;
382         double delay;
383
384         timer = ecore_timer_add(interval, cb, data);
385         if (!timer)
386                 return NULL;
387
388         delay = util_time_delay_for_compensation(interval) - interval;
389         ecore_timer_delay(timer, delay);
390         DbgPrint("Compensate timer: %lf\n", delay);
391
392         return timer;
393 }
394
395 HAPI void util_timer_interval_set(void *timer, double interval)
396 {
397         double delay;
398         ecore_timer_interval_set(timer, interval);
399
400         delay = util_time_delay_for_compensation(interval) - interval;
401         ecore_timer_delay(timer, delay);
402 }
403
404 HAPI char *util_get_file_kept_in_safe(const char *id)
405 {
406         const char *path;
407         char *new_path;
408         int len;
409         int base_idx;
410
411         path = util_uri_to_path(id);
412         if (!path) {
413                 ErrPrint("Invalid URI(%s)\n", id);
414                 return NULL;
415         }
416
417         /*!
418          * TODO: Remove me
419          */
420         if (OVERWRITE_CONTENT)
421                 return strdup(path);
422
423         len = strlen(path);
424         base_idx = len - 1;
425
426         while (base_idx > 0 && path[base_idx] != '/') base_idx--;
427         base_idx += (path[base_idx] == '/');
428
429         new_path = malloc(len + 10);
430         if (!new_path) {
431                 ErrPrint("Heap: %s\n", strerror(errno));
432                 return NULL;
433         }
434
435         strncpy(new_path, path, base_idx);
436         snprintf(new_path + base_idx, len + 10 - base_idx, "reader/%s", path + base_idx);
437         return new_path;
438 }
439
440 HAPI int util_unlink_files(const char *folder)
441 {
442         struct stat info;
443         DIR *handle;
444         struct dirent *entry;
445         char *abspath;
446         int len;
447
448         if (lstat(folder, &info) < 0) {
449                 ErrPrint("Error: %s\n", strerror(errno));
450                 return LB_STATUS_ERROR_IO;
451         }
452
453         if (!S_ISDIR(info.st_mode)) {
454                 ErrPrint("Error: %s is not a folder", folder);
455                 return LB_STATUS_ERROR_INVALID;
456         }
457
458         handle = opendir(folder);
459         if (!handle) {
460                 ErrPrint("Error: %s\n", strerror(errno));
461                 return LB_STATUS_ERROR_IO;
462         }
463
464         while ((entry = readdir(handle))) {
465                 if (!strcmp(entry->d_name, "."))
466                         continue;
467
468                 if (!strcmp(entry->d_name, ".."))
469                         continue;
470
471                 len = strlen(folder) + strlen(entry->d_name) + 3;
472                 abspath = calloc(1, len);
473                 if (!abspath) {
474                         ErrPrint("Heap: %s\n", strerror(errno));
475                         continue;
476                 }
477                 snprintf(abspath, len - 1, "%s/%s", folder, entry->d_name);
478
479                 if (unlink(abspath) < 0)
480                         DbgPrint("unlink: %s\n", strerror(errno));
481
482                 free(abspath);
483         }
484
485         closedir(handle);
486         return LB_STATUS_SUCCESS;
487 }
488
489 /* End of a file */