Tizen 2.1 base
[apps/home/ug-myfile-efl.git] / src / common / mf-ug-search-internal.c
1 /*
2  * Copyright 2012          Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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://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
18
19
20
21 #include <glib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <dirent.h>
26 #include <pthread.h>
27 #include <Ecore.h>
28
29 #include "mf-ug-main.h"
30 #include "mf-ug-search.h"
31 #include "mf-ug-search-internal.h"
32 #include "mf-ug-fs-util.h"
33
34 #define APPEND_SIZE 2           /* for null and slash */
35 #define MF_ERR_BUF              256
36
37 #define NORMALIZE_OPTION G_NORMALIZE_NFD
38
39 #ifdef CHECK_RESTRICTED_PATH
40 /* TODO
41  *  This code should be revised.
42  *  How to get restricted path information?
43  *  I think this module should not depend on other lib(except glib and stdlib).
44 */
45 #define ROOT_UMS "/opt/usr/media"
46 #define ROOT_MMC "/opt/storage/sdcard"
47 #endif /* CHECK_RESTRICTED_PATH */
48
49 int flagSearchMsg = 1;
50 pthread_mutex_t gLockSearchMsg;
51 pthread_cond_t gCondSearchMsg;
52
53 static void __mf_ug_search_tx_wait();
54 static void __mf_ug_search_result_publish_msg(mf_search_pipe_msg_type type, void *result, void *user_data);
55
56 inline static void __mf_ug_search_cmd_lock(ms_handle_t *handle)
57 {
58         if (handle && handle->cmd_lock) {
59                 g_mutex_lock(handle->cmd_lock);
60         }
61         return;
62 }
63
64 inline static void __mf_ug_search_cmd_unlock(ms_handle_t *handle)
65 {
66         if (handle && handle->cmd_lock) {
67                 g_mutex_unlock(handle->cmd_lock);
68         }
69         return;
70 }
71
72 inline static void __mf_ug_search_thread_lock(ms_handle_t *handle)
73 {
74         if (handle && handle->thread_mutex) {
75                 g_mutex_lock(handle->thread_mutex);
76         }
77         return;
78 }
79
80 inline static void __mf_ug_search_thread_unlock(ms_handle_t *handle)
81 {
82         if (handle && handle->thread_mutex) {
83                 g_mutex_unlock(handle->thread_mutex);
84         }
85         return;
86 }
87
88 inline static void __mf_ug_search_args_free(ms_args_t *args)
89 {
90         if (args) {
91                 if (args->root_path) {
92                         g_list_foreach(args->root_path, (GFunc) g_free, NULL);
93                         g_list_free(args->root_path);
94                         args->root_path = NULL;
95                 }
96
97                 if (args->needle)
98                         g_free(args->needle);
99
100                 g_free(args);
101         }
102         return;
103 }
104
105 inline static void __mf_ug_search_result_free(mf_search_result_t *result)
106 {
107         if (result) {
108                 if (result->current_dir) {
109                         g_free(result->current_dir);
110                         result->current_dir = NULL;
111                 }
112                 if (result->dir_list) {
113                         g_list_foreach(result->dir_list, (GFunc) g_free, NULL);
114                         g_list_free(result->dir_list);
115                         result->dir_list = NULL;
116                 }
117                 if (result->file_list) {
118                         g_list_foreach(result->file_list, (GFunc) g_free, NULL);
119                         g_list_free(result->file_list);
120                         result->file_list = NULL;
121                 }
122                 g_free(result);
123         }
124         return;
125 }
126
127 #ifdef CHECK_RESTRICTED_PATH
128 gboolean __mf_ug_search_check_licet_path(const char *path)
129 {
130         return (gboolean) (strstr(path, ROOT_UMS) || strstr(path, ROOT_MMC));
131 }
132 #endif /*CHECK_RESTRICTED_PATH*/
133
134
135  /*This function is for testing and should be revised for performance before applying*/
136 static inline gboolean __mf_ug_search_has_nonspacing_mark(const char *nstr)
137 {
138         if (nstr) {
139                 const char *p_str = nstr;
140                 while (p_str && *p_str) {
141                         gunichar uc;
142                         uc = g_utf8_get_char(p_str);
143                         if (g_unichar_type(uc) == G_UNICODE_NON_SPACING_MARK) {
144                                 return TRUE;
145                         } else {
146                                 p_str = g_utf8_next_char(p_str);
147                         }
148                 }
149         }
150         return FALSE;
151 }
152
153 static gboolean __mf_ug_search_NFD_ext(const char *str, const char *needle)
154 {
155         int s_len = 0;
156         int n_len = 0;
157         if (!str) {
158                 return FALSE;
159         }
160         s_len = strlen(str);
161
162         if (!needle) {
163                 return FALSE;
164         } else {
165                 n_len = strlen(needle);
166                 if (n_len == 0) {
167                         return FALSE;
168                 }
169         }
170         if (s_len < n_len)
171                 return FALSE;
172         char *pdot = strrchr(str, '.');
173
174         if (!pdot) {
175                 return FALSE;
176         } else if (pdot != str) {
177                 char *ext = NULL;;
178                 ext = g_strdup(pdot+1);
179                 if (g_strcmp0(ext, needle)== 0) {
180                         g_free(ext);
181                         ext = NULL;
182                         return TRUE;
183                 }
184                 else {
185                         g_free(ext);
186                         ext = NULL;
187                         return FALSE;
188                 }
189         } else {
190                 return FALSE;
191         }
192
193 }
194 static gboolean __mf_ug_search_NFD_strstr(const char *str, const char *needle)
195 {
196         int s_len = 0;
197         int n_len = 0;
198
199         if (!str) {
200                 return FALSE;
201         }
202         s_len = strlen(str);
203
204         if (!needle) {
205                 return FALSE;
206         } else {
207                 n_len = strlen(needle);
208                 if (n_len == 0) {
209                         return FALSE;
210                 }
211         }
212
213         if (s_len < n_len)
214                 return FALSE;
215
216         if (__mf_ug_search_has_nonspacing_mark(str)) {
217                 const char *p_str = str;
218                 const char *end = p_str + s_len - n_len;
219
220                 while (p_str && p_str <= end && *p_str) {
221                         const char *s = p_str;
222                         const char *n = needle;
223                         while (n && *n) {
224                                 if (s && *s) {
225                                         gunichar sc, nc;
226                                         sc = g_utf8_get_char(s);
227                                         nc = g_utf8_get_char(n);
228                                         if (g_unichar_type(sc) == G_UNICODE_NON_SPACING_MARK) {
229                                                 if (g_unichar_type(nc) == G_UNICODE_NON_SPACING_MARK) {
230                                                         if (sc != nc) {
231                                                                 goto next;
232                                                         } else {
233                                                                 s = g_utf8_next_char(s);
234                                                                 n = g_utf8_next_char(n);
235                                                         }
236                                                 } else {
237                                                         s = g_utf8_next_char(s);
238                                                 }
239                                         } else if (sc != nc) {
240                                                 goto next;
241                                         } else {
242                                                 s = g_utf8_next_char(s);
243                                                 n = g_utf8_next_char(n);
244                                         }
245                                 } else {
246                                         return FALSE;
247                                 }
248                         }
249
250                         return TRUE;
251 next:
252                         p_str = g_utf8_next_char(p_str);
253                 }
254         } else {
255                 return (gboolean) (!(!strstr(str, needle)));
256         }
257         return FALSE;
258 }
259
260 static GList *__mf_ug_search_do_find(const char *root, const char *needle, mf_search_option option, ms_handle_t *handle)
261 {
262         DIR *directory = NULL;
263         GList *candidate = NULL;
264
265         char *up_needle = NULL;
266         char *up_name = NULL;
267
268         if (!handle) {
269                 ms_error("handle is NULL");
270                 return NULL;
271         }
272
273         if (!handle->result) {
274                 ms_error("handle->result is NULL");
275                 return NULL;
276         }
277
278         if (!root || !needle) {
279                 ms_error("invaild args");
280                 return NULL;
281         }
282
283         if (!g_file_test(root, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
284                 ms_error("invaild root_path : %s", root);
285                 return NULL;
286         }
287
288         directory = opendir(root);
289         if (directory) {
290                 mf_search_result_t *result = NULL;
291                 struct dirent *entry = NULL;
292
293                 result = handle->result;
294                 __mf_ug_search_thread_lock(handle);
295                 if (result->current_dir) {
296                         g_free(result->current_dir);
297                 }
298                 result->current_dir = g_strdup(root);
299                 __mf_ug_search_thread_unlock(handle);
300                 while ((entry = readdir(directory)) != NULL) {
301                         if (!(option & MF_SEARCH_OPT_HIDDEN) && (0 == strncmp(entry->d_name, ".", 1))) {
302                                 ms_debug("[%s] is hidden file. Skip it", entry->d_name);
303                                 continue;
304                         }
305
306                         if (handle->is_stop == TRUE) {
307                                 ms_debug("break from do find");
308                                 break;
309                         }
310
311                         if (entry->d_type & DT_REG) {
312                                 if (option & MF_SEARCH_OPT_FILE) {
313                                         __mf_ug_search_thread_lock(handle);
314                                         result->total_count++;
315                                         __mf_ug_search_thread_unlock(handle);
316
317                                         up_name = g_utf8_strup(entry->d_name, strlen(entry->d_name));
318                                         up_needle = g_utf8_strup(needle, strlen(needle));
319
320                                         /*Todo:*/
321                                         /*      should we check the return value for further use? */
322                                         gchar *nor_str = g_utf8_normalize(up_name, -1, NORMALIZE_OPTION);
323                                         if (__mf_ug_search_NFD_strstr(nor_str, up_needle))
324                                         {
325                                                 gchar *path = NULL;
326                                                 gssize len = strlen(root) + strlen(entry->d_name) + APPEND_SIZE;        /* for null and slash*/
327                                                 path = g_malloc(sizeof(gchar) * len);
328                                                 if (path) {
329                                                         g_snprintf(path, len, "%s/%s", root, entry->d_name);
330
331                                                         __mf_ug_search_thread_lock(handle);
332                                                         result->file_list = g_list_append(result->file_list, (gpointer) path);
333                                                         result->is_end = FALSE;
334                                                         __mf_ug_search_thread_unlock(handle);
335
336                                                         __mf_ug_search_tx_wait();
337                                                         __mf_ug_search_result_publish_msg(MF_SEARCH_PIPE_MSG_RESULT_REPORT, result,
338                                                                                        handle->args->user_data);
339                                                 }
340                                                 /*1  TODO: how can i handle else case?*/
341                                         }
342                                         g_free(nor_str);
343                                         free(up_needle);
344                                         up_needle = NULL;
345                                         free(up_name);
346                                         up_name = NULL;
347                                 }else if (option & MF_SEARCH_OPT_EXT) {
348                                         __mf_ug_search_thread_lock(handle);
349                                         result->total_count++;
350                                         __mf_ug_search_thread_unlock(handle);
351
352                                         up_name = g_utf8_strup(entry->d_name, strlen(entry->d_name));
353                                         up_needle = g_utf8_strup(needle, strlen(needle));
354
355                                         /*Todo:*/
356                                         /*      should we check the return value for further use? */
357                                         gchar *nor_str = g_utf8_normalize(up_name, -1, NORMALIZE_OPTION);
358                                         if (__mf_ug_search_NFD_ext(nor_str, up_needle))
359                                         {
360                                                 gchar *path = NULL;
361                                                 gssize len = strlen(root) + strlen(entry->d_name) + APPEND_SIZE;        /* for null and slash*/
362                                                 path = g_malloc(sizeof(gchar) * len);
363                                                 if (path) {
364                                                         g_snprintf(path, len, "%s/%s", root, entry->d_name);
365
366                                                         __mf_ug_search_thread_lock(handle);
367                                                         result->file_list = g_list_append(result->file_list, (gpointer) path);
368                                                         result->is_end = FALSE;
369                                                         __mf_ug_search_thread_unlock(handle);
370
371                                                         __mf_ug_search_tx_wait();
372                                                         __mf_ug_search_result_publish_msg(MF_SEARCH_PIPE_MSG_RESULT_REPORT, result,
373                                                                                        handle->args->user_data);
374                                                 }
375                                                 /*1  TODO: how can i handle else case?*/
376                                         }
377                                         g_free(nor_str);
378                                         free(up_needle);
379                                         up_needle = NULL;
380                                         free(up_name);
381                                         up_name = NULL;
382
383                                 }
384                         } else if (entry->d_type & DT_DIR) {
385                                 gchar *path = NULL;
386                                 gssize len = 0;
387
388                                 len = strlen(entry->d_name);
389                                 /*skip current and upper directory*/
390                                 if (0 == strncmp(entry->d_name, ".", strlen(".")) || 0 == strncmp(entry->d_name, "..", strlen(".."))) {
391                                         continue;
392                                 }
393                                 /* we are not going to search /opt/media/SLP_Debug folder */
394                                 if ((strlen(result->current_dir) == strlen(PHONE_FOLDER)) && (strcmp(result->current_dir, PHONE_FOLDER) == 0)
395                                     && (strlen(entry->d_name) == strlen(DEBUG_FOLDER)) && (strcmp(entry->d_name, DEBUG_FOLDER) == 0)) {
396                                         ms_debug("[%s] is hidden folder. Skip it", entry->d_name);
397                                         continue;
398                                 }
399
400                                 len = strlen(root) + strlen(entry->d_name) + APPEND_SIZE;       /* for null and slash */
401                                 path = g_malloc(sizeof(gchar) * len);
402                                 if (path) {
403                                         g_snprintf(path, len, "%s/%s", root, entry->d_name);
404                                         candidate = g_list_append(candidate, (gpointer) path);
405                                 }
406                                 /*1  TODO: how can i handle else case?*/
407                                 if (option & MF_SEARCH_OPT_DIR) {
408                                         __mf_ug_search_thread_lock(handle);
409                                         result->total_count++;
410                                         __mf_ug_search_thread_unlock(handle);
411
412                                         up_name = g_utf8_strup(entry->d_name, strlen(entry->d_name));
413                                         if (needle && strlen(needle)) {
414                                                 up_needle = g_utf8_strup(needle, strlen(needle));
415                                                 gchar *nor_str = g_utf8_normalize(up_name, -1, NORMALIZE_OPTION);
416                                                 if (__mf_ug_search_NFD_strstr(nor_str, up_needle))
417                                                 {
418                                                         __mf_ug_search_thread_lock(handle);
419                                                         result->dir_list = g_list_append(result->dir_list, (gpointer) g_strdup(path));
420                                                         result->is_end = FALSE;
421                                                         __mf_ug_search_thread_unlock(handle);
422                                                         __mf_ug_search_tx_wait();
423                                                         __mf_ug_search_result_publish_msg(MF_SEARCH_PIPE_MSG_RESULT_REPORT, result, handle->args->user_data);
424                                                 }
425                                                 g_free(nor_str);
426                                                 free(up_name);
427                                                 up_name = NULL;
428
429                                                 free(up_needle);
430                                                 up_needle = NULL;
431                                         } else {
432                                                 free(up_name);
433                                                 up_name = NULL;
434                                         }
435                                 }
436                         }
437                 }
438                 closedir(directory);
439                 directory = NULL;
440         }
441
442         return candidate;
443 }
444
445 static gpointer __mf_ug_search_find_thread(gpointer data)
446 {
447         ms_handle_t *handle = (ms_handle_t *) data;
448         if (handle) {
449                 ms_args_t *args = NULL;
450                 mf_search_result_t *result = NULL;
451
452                 result = handle->result;
453                 args = handle->args;
454
455                 if (args && result) {
456                         GList *root = NULL;
457                         GList *candidate = NULL;        /*use this list as stack*/
458                         root = args->root_path;
459                         while (root) {
460                                 char *path = (char *)root->data;
461                                 if (path) {
462                                         /*push root paths to stack*/
463                                         candidate = g_list_append(candidate, (gpointer) g_strdup(path));
464                                 }
465                                 root = g_list_next(root);
466                         }
467
468                         while (candidate) {
469                                 GList *new_list = NULL;
470                                 GList *list = NULL;
471                                 gchar *item = NULL;
472
473                                 __mf_ug_search_thread_lock(handle);
474                                 if (handle->is_stop) {
475                                         __mf_ug_search_thread_unlock(handle);
476                                         result->is_end = TRUE;
477                                         goto MF_FIND_THREAD_EXIT;
478                                 }
479                                 __mf_ug_search_thread_unlock(handle);
480
481                                 list = g_list_first(candidate);
482                                 /*pop one path from stack*/
483                                 candidate = g_list_remove_link(candidate, list);
484                                 item = (gchar *) list->data;
485                                 if (item) {
486                                         ms_debug("current : %s", item);
487 #if 0
488                                         __mf_ug_search_thread_lock(handle);
489                                         if (result->current_dir) {
490                                                 g_free(result->current_dir);
491                                         }
492                                         result->current_dir = g_strdup(item);
493                                         __mf_ug_search_thread_unlock(handle);
494 #endif
495                                         /*publish root change message here*/
496                                         __mf_ug_search_tx_wait();
497                                         if (handle->is_stop) {
498                                                 result->is_end = TRUE;
499                                                 goto MF_FIND_THREAD_EXIT;
500                                         }
501                                         __mf_ug_search_result_publish_msg(MF_SEARCH_PIPE_MSG_ROOT_CHANGE, item, args->user_data);
502                                         new_list = __mf_ug_search_do_find(item, args->needle, args->option, handle);
503                                         g_free(item);
504                                         item = NULL;
505                                         g_list_free(list);
506                                         list = NULL;
507                                 }
508                                 /*push new paths to stack*/
509                                 candidate = g_list_concat(new_list, candidate);
510                         }
511
512                         __mf_ug_search_thread_lock(handle);
513                         result->is_end = TRUE;
514                         __mf_ug_search_thread_unlock(handle);
515                         __mf_ug_search_tx_wait();
516                         __mf_ug_search_result_publish_msg(MF_SEARCH_PIPE_MSG_FINISHED, handle->result, args->user_data);
517 MF_FIND_THREAD_EXIT:
518                         if (candidate) {
519                                 g_list_foreach(candidate, (GFunc) g_free, NULL);
520                                 g_list_free(candidate);
521                                 candidate = NULL;
522                         }
523                 } else {
524                         ms_error("args : %p or result : %p is not allocated yet!!", handle->args, handle->result);
525                 }
526         }
527         /*g_thread_exit(NULL);*/
528         return NULL;
529 }
530
531 int _mf_ug_search_init(ms_handle_t **handle)
532 {
533         GMutex *lock = NULL;
534         ms_handle_t *ms_handle = NULL;
535
536         ms_debug("");
537
538         if (!handle) {
539                 return MF_SEARCH_ERROR_INVAL_P;
540         }
541
542         ms_handle = g_malloc0(sizeof(ms_handle_t));
543         if (ms_handle == NULL) {
544                 ms_error("Fail to allocate memory for handle ");
545                 *handle = NULL;
546                 return MF_SEARCH_ERROR_ALLOC;
547         }
548
549         ms_handle->state = MF_SEARCH_STATE_INIT;
550         ms_handle->is_stop = FALSE;
551
552         lock = g_mutex_new();
553         if (!lock) {
554                 ms_error("Fail to create cmd_lock");
555                 g_free(ms_handle);
556                 return MF_SEARCH_ERROR_ALLOC;
557         }
558         ms_handle->cmd_lock = lock;
559
560         *handle = ms_handle;
561
562         ms_info("Success to make search handle : %p", ms_handle);
563         return MF_SEARCH_ERROR_NONE;
564 }
565
566 int _mf_ug_search_start(ms_handle_t *handle, const char **root_path, unsigned int path_num, const char *needle, mf_search_option option, void *user_data)
567 {
568         ms_args_t *args = NULL;
569         mf_search_result_t *result = NULL;
570         mf_search_option l_opt = MF_SEARCH_OPT_NONE;
571         int ret = MF_SEARCH_ERROR_NONE;
572         int i = 0;
573
574         if (!handle) {
575                 ms_error("handle is NULL");
576                 return MF_SEARCH_ERROR_INVAL_P;
577         }
578
579         if (handle->state != MF_SEARCH_STATE_INIT) {
580                 ms_error("invaild state : %d", handle->state);
581                 return MF_SEARCH_ERROR_INVAL_S;
582         }
583
584         if (!root_path || !needle || path_num < 1) {
585                 ms_error("invaild arguments - root[%p], path_num[%d], needle[%p]", root_path, path_num, needle);
586                 return MF_SEARCH_ERROR_INVAL_P;
587         }
588
589         __mf_ug_search_cmd_lock(handle);
590
591         if (handle->args) {
592                 __mf_ug_search_args_free(handle->args);
593                 handle->args = NULL;
594         }
595         handle->args = args = g_malloc0(sizeof(ms_args_t));
596         if (!args) {
597                 ms_error("fail to alloc args");
598                 ret = MF_SEARCH_ERROR_ALLOC;
599                 goto FAIL_FREE_MEM;
600         }
601
602         if (option == MF_SEARCH_OPT_NONE) {
603                 ms_warn("option is MF_SEARCH_OPT_NONE, set all option automatically ");
604                 l_opt = MF_SEARCH_OPT_HIDDEN | MF_SEARCH_OPT_DIR | MF_SEARCH_OPT_FILE;
605         } else {
606                 l_opt = option;
607         }
608
609         for (i = 0; i < path_num; i++) {
610                 const char *path = root_path[i];
611                 ms_debug("%d th root path is %s", i, path);
612 #ifdef CHECK_RESTRICTED_PATH
613                 if (!__mf_ug_search_check_licet_path(path)) {
614                         ms_error("%dth root path[%s] is invaild", i, path);
615                         ret = MF_SEARCH_ERROR_INVAL_P;
616                         goto FAIL_FREE_MEM;
617                 }
618 #endif /*CHECK_RESTRICTED_PATH*/
619                 if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)
620                     && ((l_opt & MF_SEARCH_OPT_HIDDEN) || strncmp(path, ".", 1))
621                     && TRUE) {
622                         gchar *new_path = NULL;
623                         gssize len = strlen(path);
624
625                         if (path[len - 1] == '/') {
626                                 new_path = g_strndup(path, len - 1);
627                         } else {
628                                 new_path = g_strndup(path, len);
629                         }
630                         args->root_path = g_list_append(args->root_path, (gpointer) new_path);
631                 } else {
632                         ms_error("Fail to test %dthe root path[%s]", i, path);
633                         ret = MF_SEARCH_ERROR_INVAL_P;
634                         goto FAIL_FREE_MEM;
635                 }
636         }
637         args->user_data = user_data;
638
639
640         args->needle = g_utf8_normalize(needle, -1, NORMALIZE_OPTION);
641         if (!args->needle) {
642                 ms_error("fail to alloc args->needle");
643                 goto FAIL_FREE_MEM;
644         }
645
646         args->option = l_opt;
647
648         if (handle->result) {
649                 __mf_ug_search_result_free(handle->result);
650                 handle->result = NULL;
651         }
652         handle->result = result = g_malloc0(sizeof(ms_args_t));
653         if (!result) {
654                 ms_error("fail to alloc result");
655                 ret = MF_SEARCH_ERROR_ALLOC;
656                 goto FAIL_FREE_MEM;
657         }
658
659         handle->thread_mutex = g_mutex_new();
660         if (!handle->thread_mutex) {
661                 ms_error("fail to alloc handle->thread_mutex");
662                 ret = MF_SEARCH_ERROR_ALLOC;
663                 goto FAIL_FREE_MEM;
664         }
665
666         handle->is_stop = FALSE;
667         handle->result->is_end = FALSE;
668
669         /*create thread for find item.*/
670         handle->thread_h = g_thread_create(__mf_ug_search_find_thread, handle, TRUE, NULL);
671         if (!handle->thread_h) {
672                 ms_error("fail to create __mf_ug_search_find_thread");
673                 ret = MF_SEARCH_ERROR_INTERNAL;
674                 goto FAIL_FREE_MEM;
675         }
676         /*create idler for reporting find result.*/
677         handle->state = MF_SEARCH_STATE_SEARCH;
678         __mf_ug_search_cmd_unlock(handle);
679         return MF_SEARCH_ERROR_NONE;
680
681 FAIL_FREE_MEM:
682         if (args) {
683                 __mf_ug_search_args_free(args);
684                 handle->args = NULL;
685         }
686
687         if (result) {
688                 __mf_ug_search_result_free(result);
689                 handle->result = NULL;
690         }
691
692         if (handle->thread_mutex) {
693                 g_mutex_free(handle->thread_mutex);
694                 handle->thread_mutex = NULL;
695         }
696
697         if (handle->thread_h) {
698                 __mf_ug_search_thread_lock(handle);
699                 handle->is_stop = TRUE;
700                 __mf_ug_search_thread_unlock(handle);
701                 g_thread_join(handle->thread_h);
702                 handle->thread_h = NULL;
703         }
704         __mf_ug_search_cmd_unlock(handle);
705
706         return ret;
707 }
708
709 int _mf_ug_search_stop(ms_handle_t *handle)
710 {
711         ms_debug("");
712
713         if (!handle) {
714                 ms_error("handle is NULL");
715                 return MF_SEARCH_ERROR_INVAL_P;
716         }
717
718         if (handle->state != MF_SEARCH_STATE_SEARCH) {
719                 ms_error("invaild state : %d", handle->state);
720                 return MF_SEARCH_ERROR_INVAL_S;
721         }
722
723         __mf_ug_search_cmd_lock(handle);
724
725         __mf_ug_search_thread_lock(handle);
726         handle->is_stop = TRUE;
727         __mf_ug_search_thread_unlock(handle);
728
729         pthread_mutex_lock(&gLockSearchMsg);
730         if (flagSearchMsg == 0) {
731                 flagSearchMsg = 1;
732                 pthread_cond_signal(&gCondSearchMsg);
733         }
734         pthread_mutex_unlock(&gLockSearchMsg);
735
736         if (handle->thread_h) {
737                 g_thread_join(handle->thread_h);
738                 handle->thread_h = NULL;
739         }
740
741         if (handle->thread_mutex) {
742                 g_mutex_free(handle->thread_mutex);
743                 handle->thread_mutex = NULL;
744         }
745
746         if (handle->args) {
747                 __mf_ug_search_args_free(handle->args);
748                 handle->args = NULL;
749         }
750         if (handle->result) {
751                 __mf_ug_search_result_free(handle->result);
752                 handle->result = NULL;
753         }
754
755         handle->state = MF_SEARCH_STATE_INIT;
756         handle->is_stop = FALSE;
757
758         __mf_ug_search_cmd_unlock(handle);
759
760         return MF_SEARCH_ERROR_NONE;
761 }
762
763 void _mf_ug_search_finalize(ms_handle_t **handle)
764 {
765         ms_handle_t *ms_handle = *handle;
766
767         ms_debug("");
768
769         if (!ms_handle) {
770                 ms_warn("invaild handle");
771                 return;
772         }
773
774         if (ms_handle->state == MF_SEARCH_STATE_SEARCH) {
775                 mf_ug_search_stop(ms_handle);
776         }
777 /*      __mf_ug_search_cmd_lock(ms_handle); */
778 /*      __mf_ug_search_cmd_unlock(ms_handle); */
779
780         if (ms_handle->cmd_lock) {
781                 g_mutex_free(ms_handle->cmd_lock);
782                 ms_handle->cmd_lock = NULL;
783         }
784         g_free(ms_handle);
785         *handle = NULL;
786
787         return;
788 }
789
790 /*+++++++++++++++++++++++++ UTIL APIs ++++++++++++++++++++++++++++++ */
791 static void __mf_ug_search_tx_wait()
792 {
793         pthread_mutex_lock(&gLockSearchMsg);
794         while (flagSearchMsg == 0) {
795                 pthread_cond_wait(&gCondSearchMsg, &gLockSearchMsg);
796         }
797         flagSearchMsg = 0;
798         pthread_mutex_unlock(&gLockSearchMsg);
799 }
800
801 static void __mf_ug_search_result_publish_msg(mf_search_pipe_msg_type type, void *result, void *user_data)
802 {
803         ugData *ugd = (ugData *)user_data;
804         /*generate message block*/
805         mf_search_pipe_msg msg;
806         memset(&msg, 0, sizeof(mf_search_pipe_msg));
807
808         msg.mf_sp_msg_type = type;
809         if (msg.mf_sp_msg_type == MF_SEARCH_PIPE_MSG_RESULT_REPORT) {
810                 msg.report_result = g_strdup((gchar *) result);
811                 msg.current_path = NULL;
812         } else if (msg.mf_sp_msg_type == MF_SEARCH_PIPE_MSG_ROOT_CHANGE) {
813                 msg.report_result = NULL;
814                 msg.current_path = g_strdup((gchar *) result);
815                 ms_debug("current path is %s", msg.current_path);
816         } else if (msg.mf_sp_msg_type == MF_SEARCH_PIPE_MSG_FINISHED) {
817                 msg.report_result = result;
818                 msg.current_path = NULL;
819         } else {
820                 msg.report_result = NULL;
821                 msg.current_path = NULL;
822         }
823
824         /*write message to pipe*/
825         ecore_pipe_write(ugd->ug_UiGadget.ug_pSyncPipe, &msg, sizeof(msg));
826 }
827
828 gchar *_mf_ug_search_result_dir_get(mf_search_result_t * result)
829 {
830         gchar *name = NULL;
831         if (result) {
832                 GList *list = NULL;
833                 list = result->dir_list;
834                 if (list && list->data) {
835                         gchar *item = (gchar *) list->data;
836                         result->dir_list = g_list_remove(list, item);
837                         name = item;
838                 }
839         }
840         return name;
841 }
842
843 gchar *_mf_ug_search_result_file_get(mf_search_result_t * result)
844 {
845         gchar *name = NULL;
846         if (result) {
847                 GList *list = NULL;
848                 list = result->file_list;
849                 if (list && list->data) {
850                         gchar *item = (gchar *) list->data;
851                         result->file_list = g_list_remove(list, item);
852                         name = item;
853                 }
854         }
855         return name;
856 }
857
858 gboolean _mf_ug_search_result_is_end(mf_search_result_t *result)
859 {
860         gboolean end = FALSE;
861         if (result) {
862                 end = result->is_end;
863         }
864         return end;
865 }
866
867 guint _mf_ug_search_result_total_count_get(mf_search_result_t *result)
868 {
869         guint count = 0;
870         if (result) {
871                 count = result->total_count;
872         }
873         return count;
874 }
875
876 gchar *_mf_ug_search_result_current_dir_get(mf_search_result_t * result)
877 {
878         gchar *c_dir = NULL;
879         if (result) {
880                 if (result->current_dir) {
881                         c_dir = result->current_dir;
882                         result->current_dir = NULL;
883                 }
884         }
885         return c_dir;
886 }