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