Improve coverage and add notification unittest
[platform/core/api/notification.git] / notification / src / notification_shared_file.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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 #ifndef _GNU_SOURCE
17 #define _GNU_SOURCE
18 #endif
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include <gio/gio.h>
26 #include <glib/gstdio.h>
27
28 #include <tzplatform_config.h>
29 #include <security-manager.h>
30 #include <sys/smack.h>
31 #include <sys/stat.h>
32 #include <linux/xattr.h>
33 #include <sys/types.h>
34 #include <utime.h>
35 #include <sys/time.h>
36 #include <package_manager.h>
37
38 #include "notification.h"
39 #include "notification_debug.h"
40 #include "notification_shared_file.h"
41 #include <notification_private.h>
42
43 #define NOTI_PRIV_DATA_DIR "data/.notification"
44 #define MAX_TIMEOUT 5000
45 #define MAX_RETRY_CNT 3
46 #define ERR_BUFFER_SIZE 1024
47
48 #define DUMMY_PARAM
49 #define __OOM_CHECK(value, ret_value, free_fun) \
50 do { \
51         if (value == NULL) { \
52                 ERR("out of memory"); \
53                 free_fun; \
54                 return ret_value; \
55         } \
56 } while (0)
57
58 GList *__uid_list;
59 typedef struct uid_info {
60         uid_t uid;
61         GList *sharing_req_list;
62         GList *target_app_list;
63 } uid_info_s;
64
65 typedef struct sharing_req_data {
66         char *app_id;
67         char *dir;
68         guint timer;
69         int drop_retry_count;
70         uid_t uid;
71         GList *priv_id_list;
72         GList *shared_file_list;
73         GList *target_app_table;
74 } sharing_req_data_s;
75
76 typedef struct sharing_file_info {
77         char *src_path;
78         char *dst_path;
79         time_t modification_time;
80 } sharing_file_info_s;
81
82 typedef struct target_app_info {
83         char *app_id;
84         char *dbus_sender_name;
85 } target_app_info_s;
86
87 /* LCOV_EXCL_START */
88 static const char *__last_index_of(const char *path, const char *search);
89 static bool __make_sharing_dir(const char *dir)
90 {
91         GFile *noti_dir = NULL;
92         GError *g_err = NULL;
93
94         if (access(dir, R_OK) == 0)
95                 return true;
96
97         noti_dir = g_file_new_for_path(dir);
98         if (noti_dir == NULL)
99                 return false;
100
101         if (g_file_make_directory(noti_dir, NULL, &g_err) == false) {
102                 if (g_err) {
103                         ERR("Failed to make sharing dir[%s]", g_err->message);
104                         g_error_free(g_err);
105                 }
106                 g_object_unref(noti_dir);
107                 return false;
108         }
109
110         g_object_unref(noti_dir);
111         return true;
112 }
113 /* LCOV_EXCL_STOP */
114
115 /* LCOV_EXCL_START */
116 static char *__get_data_path_by_pkg_id(const char *pkg_id,
117                                         const char *file_path, uid_t uid)
118 {
119         const char *path;
120         char dir[PATH_MAX * 2];
121         char rel_file_path[PATH_MAX];
122         const char *pkg_path;
123
124         if (pkg_id == NULL)
125                 return NULL;
126
127         tzplatform_set_user(uid);
128         path = tzplatform_getenv(TZ_USER_APP);
129         tzplatform_reset_user();
130
131         if (path == NULL)
132                 return NULL;
133
134         pkg_path = __last_index_of(file_path, pkg_id);
135         if (pkg_path == NULL) {
136                 ERR("Wrong file path : cannot find pkgid");
137                 return NULL;
138         }
139
140         snprintf(rel_file_path, sizeof(rel_file_path), "%s",
141                         pkg_path + strlen(pkg_id));
142
143         for (int i = 0; i < strlen(rel_file_path); i++) {
144                 if (rel_file_path[i] == '/')
145                   rel_file_path[i] = '_';
146         }
147
148         snprintf(dir, sizeof(dir), "%s/%s/%s",
149                         path, pkg_id, NOTI_PRIV_DATA_DIR);
150         if (__make_sharing_dir(dir) == false)
151                 return NULL;
152
153         snprintf(dir, sizeof(dir), "%s/%s/%s/%s", path, pkg_id,
154                                         NOTI_PRIV_DATA_DIR, rel_file_path);
155
156         return strdup(dir);
157 }
158
159 static const char *__last_index_of(const char *path, const char *search)
160 {
161         int i;
162         int search_len;
163         const char *index;
164
165         if (path == NULL || search == NULL)
166                 return NULL;
167
168         search_len = strlen(search);
169         index = path + strlen(path) - search_len;
170
171         while (index >= path) {
172                 for (i = 0; i < search_len; i++) {
173                         if (index[i] != search[i])
174                                 break;
175                 }
176
177                 if (i == search_len)
178                         return index;
179
180                 index--;
181         }
182
183         return NULL;
184 }
185 /* LCOV_EXCL_STOP */
186
187 /* Check path that include res directory */
188 /* LCOV_EXCL_START */
189 static bool __is_private_file(const char *smack_label, const char *pkg_id)
190 {
191         const char *smack_index;
192         bool ret = false;
193
194         if (smack_label == NULL || pkg_id == NULL)
195                 return ret;
196
197         smack_index = __last_index_of(smack_label, pkg_id);
198         if (smack_index != NULL && (strlen(smack_index) == strlen(pkg_id)))
199                 ret = true;
200
201         return ret;
202 }
203 /* LCOV_EXCL_STOP */
204
205 /* LCOV_EXCL_START */
206 static bool __is_RO_file(const char *smack_label)
207 {
208 #define CHECK_LABEL "::RO"
209
210         const char *smack_index;
211         bool ret = false;
212
213         smack_index = __last_index_of(smack_label, CHECK_LABEL);
214         if (smack_index != NULL && (strlen(smack_index) == strlen(CHECK_LABEL)))
215                 ret = true;
216
217         return ret;
218 }
219 /* LCOV_EXCL_STOP */
220
221 /* file copy from /res to /data */
222 /* LCOV_EXCL_START */
223 int notification_copy_private_file(const char *src_path,
224                                         const char *dst_path)
225 {
226         int ret = NOTIFICATION_ERROR_NONE;
227         GFile *src = NULL;
228         GFile *dst = NULL;
229         GError *g_err = NULL;
230         struct utimbuf ut = {0,};
231
232         dst = g_file_new_for_path(dst_path);
233         if (dst == NULL) {
234                 ERR("dst path is wrong [%s]", dst_path);
235                 ret = NOTIFICATION_ERROR_IO_ERROR;
236                 goto out;
237         }
238
239         if (g_file_query_exists(dst, NULL) == true) {
240                 ret = NOTIFICATION_ERROR_ALREADY_EXIST_ID;
241                 INFO("dst path existed [%s]", dst_path);
242                 goto out;
243         }
244
245         src = g_file_new_for_path(src_path);
246         if (src == NULL) {
247                 ERR("src path is wrong [%s]", src_path);
248                 ret = NOTIFICATION_ERROR_IO_ERROR;
249                 goto out;
250         }
251
252         if (!g_file_copy(src, dst, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, NULL,
253                         NULL, &g_err)) {
254                 if (g_err) {
255                         ERR("Copying file from [%s] to [%s] is failed [%s]",
256                                 src_path, dst_path, g_err->message);
257                         g_error_free(g_err);
258                 }
259                 ret = NOTIFICATION_ERROR_IO_ERROR;
260                 goto out;
261         }
262
263         ut.modtime = time(NULL);
264         if (g_utime(dst_path, &ut) != 0)
265                 DBG("Failed to set g_utime %d ", errno);
266
267 out:
268         if (src)
269                 g_object_unref(src);
270         if (dst)
271                 g_object_unref(dst);
272
273         return ret;
274 }
275 /* LCOV_EXCL_STOP */
276
277 /* LCOV_EXCL_START */
278 static void __free_file_info(gpointer data)
279 {
280         sharing_file_info_s *info = (sharing_file_info_s *)data;
281
282         if (info != NULL) {
283                 if (info->src_path)
284                         free(info->src_path);
285                 if (info->dst_path)
286                         free(info->dst_path);
287                 free(info);
288         }
289 }
290 /* LCOV_EXCL_STOP */
291
292 /* LCOV_EXCL_START */
293 static void __free_req_info(gpointer data)
294 {
295         sharing_req_data_s *info = (sharing_req_data_s *)data;
296
297         if (info == NULL)
298                 return;
299         if (info->app_id)
300                 free(info->app_id);
301         if (info->dir)
302                 free(info->dir);
303         if (info->shared_file_list)
304                 g_list_free_full(info->shared_file_list, __free_file_info);
305         if (info->target_app_table)
306                 g_list_free_full(info->target_app_table, free);
307
308         free(info);
309 }
310 /* LCOV_EXCL_STOP */
311
312 /* LCOV_EXCL_START */
313 static char **__convert_list_to_array(GList *list, int *length)
314 {
315         int len, i;
316         char **array;
317         GList *iter;
318
319         if (list == NULL)
320                 return NULL;
321
322         len = g_list_length(list);
323         if (len == 0)
324                 return NULL;
325
326         array = (char **)calloc(len + 1, sizeof(char *));
327         __OOM_CHECK(array, NULL, DUMMY_PARAM);
328
329         for (i = 0, iter = list; iter != NULL; i++, iter = g_list_next(iter))
330                 array[i] = ((sharing_file_info_s *)iter->data)->dst_path;
331
332         *length = len;
333
334         return array;
335 }
336
337 static gint __comp_str(gconstpointer a, gconstpointer b)
338 {
339         char *new_file = (char *)a;
340         char *file = (char *)b;
341
342         if (new_file == NULL || file == NULL)
343                 return -1;
344
345         return strcmp(new_file, file);
346 }
347 /* LCOV_EXCL_STOP */
348
349 /* LCOV_EXCL_START */
350 static gint __comp_file_info(gconstpointer a, gconstpointer b)
351 {
352         sharing_file_info_s *file = (sharing_file_info_s *)a;
353         sharing_file_info_s *new_file = (sharing_file_info_s *)b;
354
355         if (!file || !new_file || !new_file->dst_path || !file->dst_path)
356                 return -1;
357
358         return strcmp(new_file->dst_path, file->dst_path);
359 }
360 /* LCOV_EXCL_STOP */
361
362 /* LCOV_EXCL_START */
363 static gint __comp_dst_path(gconstpointer a, gconstpointer b)
364 {
365         sharing_file_info_s *info = (sharing_file_info_s *)a;
366         char *path = (char *)b;
367
368         if (!info || !path || !info->dst_path)
369                 return -1;
370
371         return strcmp(info->dst_path, path);
372 }
373 /* LCOV_EXCL_STOP */
374
375 /* LCOV_EXCL_START */
376 static sharing_file_info_s *__dup_file_info(sharing_file_info_s *src)
377 {
378         sharing_file_info_s *file_info;
379
380         file_info = (sharing_file_info_s *)calloc(1, sizeof(sharing_file_info_s));
381         __OOM_CHECK(file_info, NULL, DUMMY_PARAM);
382
383         file_info->dst_path = strdup(src->dst_path);
384         __OOM_CHECK(file_info->dst_path, NULL, __free_file_info(file_info));
385
386         file_info->src_path = strdup(src->src_path);
387         __OOM_CHECK(file_info->src_path, NULL, __free_file_info(file_info));
388
389         file_info->modification_time = src->modification_time;
390
391         return file_info;
392
393 }
394
395 static void __make_file_info(char *src_path, char *dst_path,
396         GList **new_file_list, GList *shared_file_list, bool *is_overlapping)
397 {
398         int ret;
399         GList *tmp;
400         sharing_file_info_s *file_info;
401         sharing_file_info_s *dup_file_info;
402         struct stat stat_buf = {0,};
403
404         /*
405         * If the file copy is successful,
406         * ignore the shared_file_list check for private sharing
407         */
408         ret = notification_copy_private_file(src_path, dst_path);
409         if (ret == NOTIFICATION_ERROR_ALREADY_EXIST_ID) {
410                 tmp = g_list_find_custom(shared_file_list, dst_path,
411                                 __comp_dst_path);
412                 if (tmp == NULL) {
413                         file_info = (sharing_file_info_s *)calloc(1,
414                                         sizeof(sharing_file_info_s));
415                         __OOM_CHECK(file_info, DUMMY_PARAM, DUMMY_PARAM);
416
417                         file_info->dst_path = strdup(dst_path);
418                         __OOM_CHECK(file_info->dst_path, DUMMY_PARAM,
419                                 __free_file_info(file_info));
420
421                         file_info->src_path = strdup(src_path);
422                         __OOM_CHECK(file_info->src_path, DUMMY_PARAM,
423                                 __free_file_info(file_info));
424
425                         if (stat(dst_path, &stat_buf) != 0)
426                                 ERR("Failed to get stat info");
427                         file_info->modification_time = stat_buf.st_mtime;
428
429                         *new_file_list = g_list_append(*new_file_list, file_info);
430                 } else {
431                         file_info = (sharing_file_info_s *)tmp->data;
432
433                         if (stat(file_info->dst_path, &stat_buf) != 0)
434                                 ERR("Failed to get stat info");
435
436                         if (file_info->modification_time != stat_buf.st_mtime) {
437                                 dup_file_info = __dup_file_info(file_info);
438                                 __OOM_CHECK(dup_file_info, DUMMY_PARAM, DUMMY_PARAM);
439
440                                 *new_file_list =  g_list_append(*new_file_list,
441                                                 dup_file_info);
442                                 *is_overlapping = true;
443                         }
444                 }
445         } else if (ret == NOTIFICATION_ERROR_NONE) {
446                 *is_overlapping = true;
447         }
448
449 }
450
451 static GList *__get_new_file_list(notification_h noti,
452                                 GList *shared_file_list,
453                                 bool *is_overlapping)
454 {
455         GList *new_file_list = NULL;
456         char *src_path, *dst_path, *dup_str;
457         char buf_key[32] = { 0, };
458         int i = NOTIFICATION_IMAGE_TYPE_ICON;
459
460
461         if (noti->priv_sound_path != NULL &&  noti->sound_path != NULL) {
462                 dst_path = noti->priv_sound_path;
463                 src_path = noti->sound_path;
464
465                 dup_str = strdup(dst_path);
466                 __OOM_CHECK(dup_str, NULL, DUMMY_PARAM);
467
468                 __make_file_info(src_path, dst_path, &new_file_list,
469                                 shared_file_list, is_overlapping);
470
471                 free(noti->sound_path);
472                 noti->sound_path = dup_str;
473         }
474
475         if (noti->priv_vibration_path != NULL && noti->vibration_path != NULL) {
476                 dst_path = noti->priv_vibration_path;
477                 src_path = noti->vibration_path;
478
479                 dup_str = strdup(dst_path);
480                 __OOM_CHECK(dup_str, NULL,
481                         g_list_free_full(new_file_list, __free_file_info));
482
483                 __make_file_info(src_path, dst_path, &new_file_list,
484                                                 shared_file_list, is_overlapping);
485
486                 free(noti->vibration_path);
487                 noti->vibration_path = dup_str;
488         }
489
490         if (noti->b_priv_image_path == NULL)
491                 return new_file_list;
492
493         for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) {
494                 src_path = NULL;
495                 dst_path = NULL;
496                 snprintf(buf_key, sizeof(buf_key), "%d", i);
497                 bundle_get_str(noti->b_priv_image_path, buf_key, &dst_path);
498                 bundle_get_str(noti->b_image_path, buf_key, &src_path);
499                 if (dst_path != NULL && src_path != NULL) {
500                         __make_file_info(src_path, dst_path, &new_file_list,
501                                         shared_file_list, is_overlapping);
502
503                         bundle_del(noti->b_image_path, buf_key);
504                         bundle_add_str(noti->b_image_path, buf_key, dst_path);
505                 }
506         }
507
508         return new_file_list;
509 }
510
511 static char *__get_shared_dir(notification_h noti)
512 {
513         char *path;
514         char *dir;
515         char *shared_path = NULL;
516         const char *index;
517         char buf_key[32] = { 0, };
518         int ret;
519         int i = NOTIFICATION_IMAGE_TYPE_ICON, dir_len;
520
521         if (noti->b_priv_image_path != NULL) {
522                 for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) {
523                         snprintf(buf_key, sizeof(buf_key), "%d", i);
524                         ret = bundle_get_str(noti->b_priv_image_path, buf_key, &path);
525                         if (ret == BUNDLE_ERROR_NONE
526                                         && __last_index_of(path, NOTI_PRIV_DATA_DIR) != NULL) {
527                                 shared_path = path;
528                                 break;
529                         }
530                 }
531         }
532
533         if (shared_path == NULL && noti->priv_sound_path != NULL
534                         && __last_index_of(noti->priv_sound_path, NOTI_PRIV_DATA_DIR) != NULL)
535                 shared_path = noti->priv_sound_path;
536         else if (shared_path == NULL && noti->priv_vibration_path != NULL
537                         && __last_index_of(noti->priv_vibration_path, NOTI_PRIV_DATA_DIR) != NULL)
538                 shared_path = noti->priv_vibration_path;
539
540         if (shared_path == NULL) {
541                 DBG("No private resource");
542                 return NULL;
543         }
544
545         index =  __last_index_of(shared_path, "/");
546         if (index == NULL) {
547                 ERR("Failed to find directory separator");
548                 return NULL;
549         }
550
551         dir_len = index - shared_path + 1;
552         if (dir_len <= 0 || dir_len > PATH_MAX)
553                 return NULL;
554
555         dir = (char *)calloc(dir_len, sizeof(char));
556         __OOM_CHECK(dir, NULL, DUMMY_PARAM);
557
558         snprintf(dir, dir_len, "%s", shared_path);
559
560         return dir;
561 }
562
563 static gint __comp_sharing_req_list(gconstpointer a, gconstpointer b)
564 {
565         sharing_req_data_s *req_data = (sharing_req_data_s *)a;
566         char *app_id = (char *)b;
567
568         if (!req_data || !app_id || !req_data->app_id)
569                 return -1;
570
571         if (!strcmp(app_id, req_data->app_id))
572                 return 0;
573
574         return -1;
575 }
576
577 static gint __comp_uid_info_list(gconstpointer a, gconstpointer b)
578 {
579         uid_info_s *uid_info = (uid_info_s *)a;
580
581         if (!a || !b)
582                 return -1;
583
584         if (uid_info->uid == GPOINTER_TO_INT(b))
585                 return 0;
586
587         return -1;
588 }
589
590 static gint __comp_priv_id(gconstpointer a, gconstpointer b)
591 {
592         if (!a || !b)
593                 return -1;
594
595         if (GPOINTER_TO_INT(a) == GPOINTER_TO_INT(b))
596                 return 0;
597
598         return 1;
599 }
600
601 static gint __comp_target_app(gconstpointer a, gconstpointer b)
602 {
603         target_app_info_s *target = (target_app_info_s *)a;
604         char *sender = (char *)b;
605
606         if (!target || !sender || !target->dbus_sender_name)
607                 return -1;
608
609         return strcmp(sender, target->dbus_sender_name);
610 }
611
612 EXPORT_API void notification_remove_private_sharing_target_id(
613                                 const char *sender, uid_t uid)
614 {
615         target_app_info_s *target_info;
616         uid_info_s *uid_info;
617         GList *sharing_req_list, *target_app;
618
619         sharing_req_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid),
620                                                 __comp_uid_info_list);
621         if (sharing_req_list == NULL)
622                 return;
623
624         uid_info = sharing_req_list->data;
625         target_app = g_list_find_custom(uid_info->target_app_list, sender,
626                                                 __comp_target_app);
627
628         if (target_app != NULL) {
629                 target_info = target_app->data;
630                 if (target_info) {
631                         uid_info->target_app_list = g_list_remove(
632                                         uid_info->target_app_list, target_info);
633
634                         free(target_info->app_id);
635                         free(target_info->dbus_sender_name);
636                         free(target_info);
637                         target_info = NULL;
638                 }
639         }
640 }
641
642 EXPORT_API void notification_add_private_sharing_target_id(pid_t pid,
643                                         const char *sender, uid_t uid)
644 {
645         char *app_id;
646         target_app_info_s *target_info;
647         uid_info_s *uid_info;
648         GList *sharing_req_list, *target_app;
649
650         sharing_req_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid),
651                                                 __comp_uid_info_list);
652         if (sharing_req_list == NULL) {
653                 uid_info = (uid_info_s *)calloc(1, sizeof(uid_info_s));
654                 __OOM_CHECK(uid_info, DUMMY_PARAM, DUMMY_PARAM);
655                 uid_info->uid = uid;
656
657                 __uid_list = g_list_append(__uid_list, uid_info);
658         } else {
659                 uid_info = sharing_req_list->data;
660         }
661
662         target_app = g_list_find_custom(uid_info->target_app_list, sender,
663                                                 __comp_target_app);
664         if (target_app == NULL) {
665                 app_id = notification_get_app_id_by_pid((int)pid);
666                 if (app_id == NULL) {
667                         ERR("Failed to get app id by pid");
668                         return;
669                 }
670
671                 target_info = (target_app_info_s *)calloc(1, sizeof(target_app_info_s));
672                 if (target_info == NULL) {
673                         ERR("Failed to alloc memory");
674                         free(app_id);
675                         return;
676                 }
677
678                 target_info->app_id = app_id;
679                 target_info->dbus_sender_name = strdup(sender);
680                 if (target_info->dbus_sender_name == NULL) {
681                         ERR("Failed to alloc memory");
682                         free(target_info);
683                         free(app_id);
684                         return;
685                 }
686
687                 uid_info->target_app_list = g_list_append(
688                         uid_info->target_app_list, target_info);
689         }
690 }
691
692 char *notification_check_file_path_is_private(const char *pkg_id,
693                                                         const char *file_path)
694 {
695         char *smack_label = NULL;
696         char *dst_path = NULL;
697         int size;
698         uid_t uid = getuid();
699         char err_buf[ERR_BUFFER_SIZE];
700         char *err_str;
701
702         errno = 0;
703         size = smack_new_label_from_path(file_path, XATTR_NAME_SMACK,
704                                                         TRUE, &smack_label);
705         if (size <= 0) {
706                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
707                 ERR("Failed to get smack info : %d [%s][%s]", errno, err_str,
708                         file_path);
709                 return NULL;
710         }
711
712         if (__is_RO_file(smack_label))
713                 dst_path = __get_data_path_by_pkg_id(pkg_id, file_path, uid);
714
715         if (dst_path == NULL && __is_private_file(smack_label, pkg_id)) {
716                 dst_path = strdup(file_path);
717                 if (dst_path == NULL)
718                         ERR("Failed to strdup");
719         }
720
721         free(smack_label);
722         return dst_path;
723 }
724
725 EXPORT_API bool notification_validate_private_sharing(
726                                                 notification_h updated_noti)
727 {
728         char *updated_path = NULL;
729         char *private_path = NULL;
730         char buf_key[32] = { 0, };
731         int i = NOTIFICATION_IMAGE_TYPE_ICON;
732
733         if (updated_noti->b_image_path && updated_noti->b_priv_image_path) {
734                 for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) {
735                         updated_path = NULL;
736                         private_path = NULL;
737
738                         snprintf(buf_key, sizeof(buf_key), "%d", i);
739                         bundle_get_str(updated_noti->b_image_path, buf_key,
740                                                         &updated_path);
741                         if (updated_path == NULL)
742                                 continue;
743
744                         bundle_get_str(updated_noti->b_priv_image_path,
745                                                         buf_key, &private_path);
746                         if (private_path == NULL)
747                                 continue;
748
749                         if (strcmp(updated_path, private_path) == 0)
750                                 return false;
751                 }
752         }
753
754         if (updated_noti->sound_path && updated_noti->priv_sound_path) {
755                 if (strcmp(updated_noti->sound_path,
756                                         updated_noti->priv_sound_path) == 0)
757                         return false;
758         }
759
760         if (updated_noti->vibration_path && updated_noti->priv_vibration_path) {
761                 if (strcmp(updated_noti->vibration_path,
762                                         updated_noti->priv_vibration_path) == 0)
763                         return false;
764         }
765
766         return true;
767 }
768
769 EXPORT_API void notification_calibrate_private_sharing(
770                         notification_h updated_noti, notification_h source_noti)
771 {
772         char *updated_path = NULL;
773         char *source_path = NULL;
774         char *private_path = NULL;
775         char buf_key[32] = { 0, };
776         int i = NOTIFICATION_IMAGE_TYPE_ICON;
777
778         if (updated_noti->b_image_path && updated_noti->b_priv_image_path) {
779                 for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) {
780                         source_path = NULL;
781                         updated_path = NULL;
782                         private_path = NULL;
783
784                         snprintf(buf_key, sizeof(buf_key), "%d", i);
785                         bundle_get_str(updated_noti->b_image_path, buf_key,
786                                                 &updated_path);
787                         if (updated_path == NULL)
788                                 continue;
789
790                         bundle_get_str(updated_noti->b_priv_image_path,
791                                                 buf_key, &private_path);
792                         if (private_path == NULL)
793                                 continue;
794
795                         if (strcmp(updated_path, private_path) == 0) {
796                                 if (bundle_get_str(source_noti->b_image_path,
797                                         buf_key, &source_path) == BUNDLE_ERROR_NONE) {
798                                         bundle_del(updated_noti->b_image_path,
799                                                 buf_key);
800                                         bundle_add_str(updated_noti->b_image_path,
801                                                 buf_key, source_path);
802                                 }
803                         }
804                 }
805         }
806
807         if (updated_noti->sound_path && updated_noti->priv_sound_path) {
808                 if (strcmp(updated_noti->sound_path,
809                                 updated_noti->priv_sound_path) == 0) {
810                         free(updated_noti->sound_path);
811                         updated_noti->sound_path = NULL;
812
813                         if (source_noti->sound_path) {
814                                 updated_noti->sound_path = strdup(source_noti->sound_path);
815                                 if (updated_noti->sound_path == NULL)
816                                         ERR("out of memory");
817                         }
818                 }
819         }
820
821         if (updated_noti->vibration_path && updated_noti->priv_vibration_path) {
822                 if (strcmp(updated_noti->vibration_path,
823                                 updated_noti->priv_vibration_path) == 0) {
824                         free(updated_noti->vibration_path);
825                         updated_noti->vibration_path = NULL;
826
827                         if (source_noti->priv_vibration_path) {
828                                 updated_noti->vibration_path =
829                                         strdup(source_noti->priv_vibration_path);
830                                 if (updated_noti->vibration_path == NULL)
831                                         ERR("out of memory");
832                         }
833                 }
834         }
835 }
836
837
838 int __set_sharing_for_new_target(sharing_req_data_s *req_data,
839                                         GList *target_app_list)
840 {
841         char **path_array = NULL;
842         int ret = NOTIFICATION_ERROR_NONE;
843         int len;
844         private_sharing_req *handle = NULL;
845         GList *iter, *tmp;
846         target_app_info_s *target_info;
847         char *app_info = NULL;
848
849         iter = target_app_list;
850         for (; iter != NULL; iter = g_list_next(iter)) {
851                 target_info = (target_app_info_s *)iter->data;
852                 tmp = g_list_find_custom(req_data->target_app_table,
853                                         target_info->app_id, __comp_str);
854                 if (tmp != NULL)
855                         continue;
856
857                 app_info = strdup(target_info->app_id);
858                 if (app_info == NULL) {
859                         ERR("out of memory");
860                         ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
861                         goto out;
862                 }
863
864                 if (handle == NULL) {
865                         ret = security_manager_private_sharing_req_new(&handle);
866                         if (ret != SECURITY_MANAGER_SUCCESS) {
867                                 ret = NOTIFICATION_ERROR_IO_ERROR;
868                                 ERR("Failed to create PS handle");
869                                 goto out;
870                         }
871
872                         ret = security_manager_private_sharing_req_set_owner_appid(
873                                                 handle, req_data->app_id);
874                         if (ret != SECURITY_MANAGER_SUCCESS) {
875                                 ret = NOTIFICATION_ERROR_IO_ERROR;
876                                 ERR("Failed to set owner appid(%s) %d",
877                                                 req_data->app_id, ret);
878                                 goto out;
879                         }
880                         path_array = __convert_list_to_array(
881                                         req_data->shared_file_list, &len);
882                         if (path_array == NULL) {
883                                 ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
884                                 goto out;
885                         }
886
887                         ret = security_manager_private_sharing_req_add_paths(
888                                         handle, (const char **)path_array, len);
889                         if (ret != SECURITY_MANAGER_SUCCESS) {
890                                 ret = NOTIFICATION_ERROR_IO_ERROR;
891                                 ERR("Failed to add paths %d", ret);
892                                 goto out;
893                         }
894                 }
895
896                 ret = security_manager_private_sharing_req_set_target_appid(
897                                         handle, target_info->app_id);
898                 if (ret != SECURITY_MANAGER_SUCCESS) {
899                         ret = NOTIFICATION_ERROR_IO_ERROR;
900                         ERR("Failed to set target appid(%s)",
901                                 (const char *)iter->data);
902                         goto out;
903                 }
904
905                 ret = security_manager_private_sharing_apply(handle);
906                 if (ret != SECURITY_MANAGER_SUCCESS) {
907                         ret = NOTIFICATION_ERROR_IO_ERROR;
908                         ERR("Failed to apply PS %d", ret);
909                         goto out;
910                 }
911
912                 req_data->target_app_table = g_list_append(
913                                 req_data->target_app_table, app_info);
914         }
915
916 out:
917         if (ret != NOTIFICATION_ERROR_NONE && app_info)
918                 free(app_info);
919
920         if (handle != NULL)
921                 security_manager_private_sharing_req_free(handle);
922
923         if (path_array != NULL)
924                 free(path_array);
925
926         return ret;
927 }
928 /* LCOV_EXCL_STOP */
929
930 /* LCOV_EXCL_START */
931 int __set_sharing_for_new_file(sharing_req_data_s *req_data,
932                                 GList *new_file_list, bool is_overlapping)
933 {
934         char **path_array = NULL;
935         int ret = NOTIFICATION_ERROR_NONE;
936         int len;
937         private_sharing_req *handle = NULL;
938         GList *iter;
939
940         path_array = __convert_list_to_array(new_file_list, &len);
941         if (path_array == NULL) {
942                 ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
943                 goto out;
944         }
945
946         ret = security_manager_private_sharing_req_new(&handle);
947         if (ret != SECURITY_MANAGER_SUCCESS) {
948                 ERR("Failed to create private sharing request handle[%d]", ret);
949                 ret = NOTIFICATION_ERROR_IO_ERROR;
950                 goto out;
951         }
952
953         ret = security_manager_private_sharing_req_set_owner_appid(handle,
954                                         req_data->app_id);
955         if (ret != SECURITY_MANAGER_SUCCESS) {
956                 ERR("Failed to set owner appid[%s][%d]", req_data->app_id, ret);
957                 ret = NOTIFICATION_ERROR_IO_ERROR;
958                 goto out;
959         }
960
961         ret = security_manager_private_sharing_req_add_paths(handle,
962                                                 (const char **)path_array, len);
963         if (ret != SECURITY_MANAGER_SUCCESS) {
964                 ERR("Failed to add paths [%d]", ret);
965                 ret = NOTIFICATION_ERROR_IO_ERROR;
966                 goto out;
967         }
968
969         if (is_overlapping == true) {
970                 iter = req_data->target_app_table;
971                 for (; iter != NULL; iter = g_list_next(iter)) {
972                         ret = security_manager_private_sharing_req_set_target_appid(
973                                                         handle, (const char *)iter->data);
974                         if (ret != SECURITY_MANAGER_SUCCESS) {
975                                 ERR("Failed to set target appid [%s]",
976                                         (const char *)iter->data);
977                                 ret = NOTIFICATION_ERROR_IO_ERROR;
978                                 goto out;
979                         }
980
981                         ret = security_manager_private_sharing_drop(handle);
982                         if (ret != SECURITY_MANAGER_SUCCESS) {
983                                 ERR("Failed to drop [%d]", ret);
984                                 ret = NOTIFICATION_ERROR_IO_ERROR;
985                                 goto out;
986                         }
987                 }
988         }
989
990         iter = req_data->target_app_table;
991         for (; iter != NULL; iter = g_list_next(iter)) {
992                 ret = security_manager_private_sharing_req_set_target_appid(handle,
993                                                         (const char *)iter->data);
994                 if (ret != SECURITY_MANAGER_SUCCESS) {
995                         ERR("Failed to set target appid [%s]",
996                                 (const char *)iter->data);
997                         ret = NOTIFICATION_ERROR_IO_ERROR;
998                         goto out;
999                 }
1000
1001                 ret = security_manager_private_sharing_apply(handle);
1002                 if (ret != SECURITY_MANAGER_SUCCESS) {
1003                         ERR("Failed to apply PS [%d]", ret);
1004                         ret = NOTIFICATION_ERROR_IO_ERROR;
1005                         goto out;
1006                 }
1007         }
1008
1009 out:
1010         if (handle != NULL)
1011                 security_manager_private_sharing_req_free(handle);
1012
1013         if (path_array != NULL)
1014                 free(path_array);
1015
1016         return ret;
1017 }
1018 /* LCOV_EXCL_STOP */
1019
1020 /* LCOV_EXCL_START */
1021 EXPORT_API int notification_set_private_sharing(notification_h noti,
1022                                                 uid_t uid)
1023 {
1024         int ret = NOTIFICATION_ERROR_NONE;
1025         bool is_overlapping = false;
1026         sharing_req_data_s *req_data;
1027         sharing_file_info_s *file_info, *dup_file_info;
1028         uid_info_s *uid_info;
1029         GList *req_list, *iter, *tmp;
1030         GList *new_file_list = NULL;
1031
1032         if (noti == NULL || noti->caller_app_id == NULL)
1033                 return NOTIFICATION_ERROR_INVALID_PARAMETER;
1034
1035         tmp = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid),
1036                                                 __comp_uid_info_list);
1037         if (tmp == NULL) {
1038                 uid_info = (uid_info_s *)calloc(1, sizeof(uid_info_s));
1039                 __OOM_CHECK(uid_info, NOTIFICATION_ERROR_OUT_OF_MEMORY, DUMMY_PARAM);
1040
1041                 uid_info->uid = uid;
1042                 __uid_list = g_list_append(__uid_list, uid_info);
1043         } else {
1044                 uid_info = tmp->data;
1045         }
1046
1047         req_list = g_list_find_custom(uid_info->sharing_req_list,
1048                                 noti->caller_app_id, __comp_sharing_req_list);
1049         if (req_list == NULL) {
1050                 req_data = (sharing_req_data_s *)calloc(1, sizeof(sharing_req_data_s));
1051                 __OOM_CHECK(req_data, NOTIFICATION_ERROR_OUT_OF_MEMORY, DUMMY_PARAM);
1052
1053                 req_data->app_id = strdup(noti->caller_app_id);
1054                 __OOM_CHECK(req_data->app_id, NOTIFICATION_ERROR_OUT_OF_MEMORY,
1055                                                 __free_req_info(req_data));
1056
1057                 req_data->dir = __get_shared_dir(noti);
1058                 req_data->uid = uid;
1059
1060                 uid_info->sharing_req_list = g_list_append(
1061                         uid_info->sharing_req_list, req_data);
1062         } else {
1063                 req_data = (sharing_req_data_s *)req_list->data;
1064                 if (req_data->dir == NULL)
1065                         req_data->dir = __get_shared_dir(noti);
1066
1067                 if (req_data->timer > 0) {
1068                         g_source_remove(req_data->timer);
1069                         req_data->timer = 0;
1070                 }
1071         }
1072
1073         if (req_data->dir != NULL)
1074                 __make_sharing_dir(req_data->dir);
1075
1076         tmp = g_list_find_custom(req_data->priv_id_list,
1077                                 GINT_TO_POINTER(noti->priv_id), __comp_priv_id);
1078         if (tmp == NULL)
1079                 req_data->priv_id_list = g_list_append(req_data->priv_id_list,
1080                                                 GINT_TO_POINTER(noti->priv_id));
1081
1082         new_file_list = __get_new_file_list(noti, req_data->shared_file_list,
1083                                                         &is_overlapping);
1084         if (new_file_list != NULL) {
1085                 if (__set_sharing_for_new_file(req_data, new_file_list,
1086                                 is_overlapping) != NOTIFICATION_ERROR_NONE) {
1087                         ret = NOTIFICATION_ERROR_IO_ERROR;
1088                         goto out;
1089                 }
1090         }
1091
1092         for (iter = new_file_list; iter != NULL; iter = g_list_next(iter)) {
1093                 tmp = NULL;
1094                 file_info = iter->data;
1095                 if (is_overlapping) {
1096                         tmp = g_list_find_custom(req_data->shared_file_list,
1097                                 file_info, __comp_file_info);
1098                 }
1099
1100                 if (tmp == NULL) {
1101                         dup_file_info = __dup_file_info(file_info);
1102                         req_data->shared_file_list = g_list_append(
1103                                 req_data->shared_file_list, dup_file_info);
1104                 }
1105         }
1106
1107         if (__set_sharing_for_new_target(req_data, uid_info->target_app_list)
1108                                                 != NOTIFICATION_ERROR_NONE) {
1109                 ret = NOTIFICATION_ERROR_IO_ERROR;
1110                 goto out;
1111         }
1112         INFO("PS success priv id[%d] shared file count[%d] target app count[%d]",
1113                                 noti->priv_id,
1114                                 g_list_length(req_data->shared_file_list),
1115                                 g_list_length(req_data->target_app_table));
1116
1117 out:
1118         if (new_file_list != NULL)
1119                 g_list_free_full(new_file_list, __free_file_info);
1120
1121         if (ret != NOTIFICATION_ERROR_NONE)
1122                 req_data->priv_id_list = g_list_remove(req_data->priv_id_list,
1123                                                 GINT_TO_POINTER(noti->priv_id));
1124         return ret;
1125 }
1126
1127 static gboolean __timeout_handler(void *data)
1128 {
1129         char **path_array = NULL;
1130         char *dst_path;
1131         char *target_appid;
1132         sharing_req_data_s *req_data;
1133         private_sharing_req *handle = NULL;
1134         GList *iter;
1135         GList *tmp_list;
1136         uid_info_s *uid_info;
1137         int ret = SECURITY_MANAGER_SUCCESS;
1138         int len;
1139
1140         req_data = (sharing_req_data_s *)data;
1141         if (g_list_length(req_data->priv_id_list) > 0) {
1142                 req_data->timer = 0;
1143                 return FALSE;
1144         }
1145
1146         req_data->drop_retry_count++;
1147
1148         /* If there is no shared file, the private sharing is not dropped. */
1149         if (req_data->dir != NULL) {
1150                 __make_sharing_dir(req_data->dir);
1151                 iter = req_data->shared_file_list;
1152                 for (; iter != NULL; iter = g_list_next(iter)) {
1153                         notification_copy_private_file(
1154                                 ((sharing_file_info_s *)(iter->data))->src_path,
1155                                 ((sharing_file_info_s *)(iter->data))->dst_path);
1156                 }
1157         }
1158
1159         if (g_list_length(req_data->target_app_table) > 0) {
1160                 ret = security_manager_private_sharing_req_new(&handle);
1161                 if (ret != SECURITY_MANAGER_SUCCESS) {
1162                         ERR("Failed to create PS request handle");
1163                         goto out;
1164                 }
1165
1166                 ret = security_manager_private_sharing_req_set_owner_appid(
1167                                 handle, req_data->app_id);
1168                 if (ret != SECURITY_MANAGER_SUCCESS) {
1169                         ERR("Failed to set owner appid(%s) %d",
1170                                         req_data->app_id, ret);
1171                         goto out;
1172                 }
1173
1174                 path_array = __convert_list_to_array(req_data->shared_file_list, &len);
1175                 if (path_array == NULL) {
1176                         ERR("path_array is null %d",
1177                                 g_list_length(req_data->shared_file_list));
1178                         ret = SECURITY_MANAGER_ERROR_MEMORY;
1179                         goto out;
1180                 }
1181
1182                 ret = security_manager_private_sharing_req_add_paths(handle,
1183                                                 (const char **)path_array, len);
1184                 if (ret != SECURITY_MANAGER_SUCCESS) {
1185                         ERR("Failed to add paths %d", ret);
1186                         goto out;
1187                 }
1188
1189                 iter = req_data->target_app_table;
1190                 while(iter != NULL) {
1191                         target_appid = (char *)iter->data;
1192                         iter = g_list_next(iter);
1193
1194                         ret = security_manager_private_sharing_req_set_target_appid(
1195                                                 handle, target_appid);
1196                         if (ret != SECURITY_MANAGER_SUCCESS) {
1197                                 ERR("Failed to set target appid(%s)", target_appid);
1198                                 goto out;
1199                         }
1200
1201                         ret = security_manager_private_sharing_drop(handle);
1202                         if (ret != SECURITY_MANAGER_SUCCESS) {
1203                                 ERR("Failed to drop %d", ret);
1204                                 goto out;
1205                         }
1206
1207                         req_data->target_app_table = g_list_remove(
1208                                         req_data->target_app_table, target_appid);
1209                         free(target_appid);
1210                 }
1211         }
1212
1213 out:
1214         if (handle != NULL)
1215                 security_manager_private_sharing_req_free(handle);
1216
1217         if (path_array)
1218                 free(path_array);
1219
1220         if (ret != SECURITY_MANAGER_SUCCESS && req_data->drop_retry_count < MAX_RETRY_CNT) {
1221                 ERR("drop_retry_count %d", req_data->drop_retry_count);
1222                 return TRUE;
1223         }
1224
1225         if (req_data->dir != NULL) {
1226                 iter = req_data->shared_file_list;
1227                 for (; iter != NULL; iter = g_list_next(iter)) {
1228                         dst_path = ((sharing_file_info_s *)(iter->data))->dst_path;
1229                         if (strncmp(req_data->dir, dst_path, strlen(req_data->dir)) != 0)
1230                                 continue;
1231
1232                         if (g_remove(dst_path) != 0)
1233                                 ERR("Failed [%s] [%d]", dst_path, errno);
1234                 }
1235                 g_rmdir(req_data->dir);
1236         }
1237
1238         tmp_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(req_data->uid),
1239                         __comp_uid_info_list);
1240
1241         if (tmp_list != NULL) {
1242                 uid_info = tmp_list->data;
1243                 uid_info->sharing_req_list = g_list_remove(
1244                                 uid_info->sharing_req_list, req_data);
1245         }
1246         __free_req_info(req_data);
1247
1248         return FALSE;
1249 }
1250
1251 EXPORT_API void notification_remove_private_sharing(
1252                 const char *src_app_id, int priv_id, uid_t uid)
1253 {
1254         sharing_req_data_s *req_data;
1255         uid_info_s *uid_info;
1256         GList *req_list;
1257         GList *priv_id_info = NULL;
1258         GList *tmp_list = NULL;
1259         int len;
1260
1261         tmp_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid),
1262                         __comp_uid_info_list);
1263         if (tmp_list == NULL)
1264                 return;
1265
1266         uid_info = tmp_list->data;
1267
1268         req_list = g_list_find_custom(uid_info->sharing_req_list, src_app_id,
1269                         __comp_sharing_req_list);
1270         if (req_list == NULL)
1271                 return;
1272
1273         req_data = (sharing_req_data_s *)req_list->data;
1274
1275         priv_id_info = g_list_find_custom(req_data->priv_id_list,
1276                         GINT_TO_POINTER(priv_id), __comp_priv_id);
1277         if (priv_id_info == NULL)
1278                 return;
1279
1280         req_data->priv_id_list = g_list_remove(req_data->priv_id_list,
1281                         priv_id_info->data);
1282         len = g_list_length(req_data->priv_id_list);
1283         if (len > 0)
1284                 return;
1285
1286         if (req_data->timer > 0)
1287                 g_source_remove(req_data->timer);
1288
1289         req_data->timer = g_timeout_add(MAX_TIMEOUT, __timeout_handler, req_data);
1290         req_data->drop_retry_count = 0;
1291         if (req_data->timer == 0) {
1292                 ERR("Failed to add timer");
1293                 __timeout_handler(req_data);
1294         }
1295
1296 }
1297 /* LCOV_EXCL_STOP */