Sync code with Tizen 3.0 branch
[platform/core/connectivity/mtp-responder.git] / src / mtp_inoti_handler.c
1 /*
2  * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/syscall.h>
20 #include <sys/stat.h>
21 #include <glib.h>
22 #include <glib/gprintf.h>
23 #include "mtp_thread.h"
24 #include "mtp_inoti_handler.h"
25 #include "mtp_event_handler.h"
26 #include "mtp_support.h"
27 #include "mtp_device.h"
28 #include "mtp_util.h"
29
30 /*
31  * GLOBAL AND STATIC VARIABLES
32  */
33 pthread_mutex_t g_cmd_inoti_mutex;
34
35 #ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT
36 mtp_char g_last_created_dir[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
37 mtp_char g_last_deleted[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
38 mtp_char g_last_moved[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
39 mtp_char g_last_copied[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
40 static pthread_t g_inoti_thrd;
41 static mtp_int32 g_cnt_watch_folder = 0;
42 static mtp_int32 g_inoti_fd;
43 static open_files_info_t *g_open_files_list;
44 static inoti_watches_t g_inoti_watches[INOTI_FOLDER_COUNT_MAX];
45 #endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/
46
47 /*
48  * STATIC FUNCTIONS
49  */
50 #ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT
51 static mtp_bool __process_inoti_event(struct inotify_event *event);
52 static void __remove_inoti_watch(mtp_char *path);
53 static mtp_bool __add_file_to_inoti_open_files_list(mtp_int32 wd,
54                 mtp_char *event_name);
55 static open_files_info_t *__find_file_in_inoti_open_files_list(mtp_int32 wd,
56                 mtp_char *event_name);
57 static void __remove_file_from_inoti_open_files_list(open_files_info_t *node);
58 static mtp_int32 __get_inoti_watch_id(mtp_int32 iwd);
59 static mtp_bool __get_inoti_event_full_path(mtp_int32 wd, mtp_char *event_name,
60                 mtp_char *path, mtp_int32 path_len, mtp_char *parent_path);
61 static void __remove_recursive_inoti_watch(mtp_char *path);
62 static void __clean_up_inoti(void *data);
63 static void __delete_children_from_store_inoti(mtp_store_t *store,
64                 mtp_obj_t *obj);
65 static void __process_object_added_event(mtp_char *fullpath,
66                 mtp_char *file_name, mtp_char *parent_path);
67 static void __process_object_deleted_event(mtp_char *fullpath,
68                 mtp_char *file_name, mtp_bool isdir);
69 static void __destroy_inoti_open_files_list();
70 #endif /* MTP_SUPPORT_OBJECTADDDELETE_EVENT */
71
72 /*
73  * FUNCTIONS
74  */
75 #ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT
76 void *_thread_inoti(void *arg)
77 {
78         mtp_int32 i = 0;
79         mtp_int32 length = 0;
80         mtp_int64 temp_idx;
81         mtp_char buffer[INOTI_BUF_LEN] = { 0 };
82         struct inotify_event *event = NULL;
83
84         pthread_cleanup_push(__clean_up_inoti, NULL);
85
86         DBG("START INOTIFY SYSTEM");
87
88         while (1) {
89                 pthread_testcancel();
90                 errno = 0;
91                 i = 0;
92                 length = read(g_inoti_fd, buffer, sizeof(buffer));
93                 if (length < 0) {
94                         ERR("read() Fail");
95                         _util_print_error();
96                         break;
97                 }
98
99                 while (i < length) {
100                         event = (struct inotify_event *)(&buffer[i]);
101                         __process_inoti_event(event);
102                         temp_idx = i + event->len + INOTI_EVENT_SIZE;
103                         if (temp_idx > length)
104                                 break;
105                         else
106                                 i = temp_idx;
107                 }
108         }
109
110         DBG("Inoti thread exited");
111         pthread_cleanup_pop(1);
112
113         return NULL;
114 }
115
116 void _inoti_add_watch_for_fs_events(mtp_char *path)
117 {
118         mtp_int32 i = 0;
119
120         ret_if(path == NULL);
121
122         if (g_cnt_watch_folder == INOTI_FOLDER_COUNT_MAX) {
123                 /* find empty cell */
124                 for (i = 0; i < INOTI_FOLDER_COUNT_MAX; i++) {
125                         /* If not empty */
126                         if (g_inoti_watches[i].wd != 0)
127                                 continue;
128                         else
129                                 break;
130                 }
131
132                 if (i == INOTI_FOLDER_COUNT_MAX) {
133                         ERR("no empty space for a new inotify watch.");
134                         return;
135                 }
136                 DBG("g_watch_folders[%d] add watch : %s\n", i, path);
137                 g_inoti_watches[i].forlder_name = g_strdup(path);
138                 g_inoti_watches[i].wd = inotify_add_watch(g_inoti_fd,
139                                 g_inoti_watches[i].forlder_name,
140                                 IN_CLOSE_WRITE | IN_CREATE |
141                                 IN_DELETE | IN_MOVED_FROM |
142                                 IN_MOVED_TO);
143                 return;
144         }
145
146         DBG("g_watch_folders[%d] add watch : %s\n", g_cnt_watch_folder, path);
147         g_inoti_watches[g_cnt_watch_folder].forlder_name = g_strdup(path);
148         g_inoti_watches[g_cnt_watch_folder].wd = inotify_add_watch(g_inoti_fd,
149                         g_inoti_watches[g_cnt_watch_folder].forlder_name,
150                         IN_CLOSE_WRITE |
151                         IN_CREATE | IN_DELETE |
152                         IN_MOVED_FROM |
153                         IN_MOVED_TO);
154         g_cnt_watch_folder++;
155
156         return;
157 }
158
159 mtp_bool _inoti_init_filesystem_evnts()
160 {
161         mtp_bool ret = FALSE;
162
163         g_inoti_fd = inotify_init();
164         if (g_inoti_fd < 0) {
165                 ERR("inotify_init() Fail : g_inoti_fd = %d", g_inoti_fd);
166                 return FALSE;
167         }
168
169         ret = _util_thread_create(&g_inoti_thrd, "File system inotify thread\n",
170                         PTHREAD_CREATE_JOINABLE, _thread_inoti, NULL);
171         if (FALSE == ret) {
172                 ERR("_util_thread_create() Fail");
173                 _util_print_error();
174                 close(g_inoti_fd);
175                 return FALSE;
176         }
177
178         return TRUE;
179 }
180
181 static mtp_bool __process_inoti_event(struct inotify_event *event)
182 {
183         static mtp_int32 last_moved_cookie = -1;
184
185         mtp_bool res = FALSE;
186         mtp_char full_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
187         mtp_char parentpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
188
189         if (event->len == 0 || event->len > MTP_MAX_FILENAME_SIZE) {
190                 ERR_SECURE("Event len is invalid[%d], event->name[%s]\n", event->len,
191                                 event->name);
192                 return FALSE;
193         } else if (event->wd < 1) {
194                 ERR("invalid wd : %d\n", event->wd);
195                 return FALSE;
196         }
197
198         /* start of one event */
199         res = __get_inoti_event_full_path(event->wd, event->name, full_path,
200                         sizeof(full_path), parentpath);
201         if (res == FALSE) {
202                 ERR("__get_inoti_event_full_path() Fail");
203                 return FALSE;
204         }
205
206         if (_util_is_path_len_valid(full_path) == FALSE) {
207                 ERR("path len is invalid");
208                 return FALSE;
209         }
210         DBG_SECURE("Event full path = %s\n", full_path);
211         if (event->mask & IN_MOVED_FROM) {
212                 if (!g_strcmp0(g_last_moved, full_path)) {
213                         /* Ignore this case as this is generated due to MTP*/
214                         DBG("[%s] is moved_from by MTP\n", full_path);
215                         memset(g_last_moved, 0,
216                                         MTP_MAX_PATHNAME_SIZE + 1);
217                         last_moved_cookie = event->cookie;
218                 } else if (event->mask & IN_ISDIR) {
219                         DBG("IN_MOVED_FROM --> IN_ISDIR");
220                         UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
221                         __process_object_deleted_event(full_path,
222                                         event->name, TRUE);
223                         UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
224                 } else {
225                         DBG("IN_MOVED_FROM --> NOT IN_ISDIR");
226                         UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
227                         __process_object_deleted_event(full_path,
228                                         event->name, FALSE);
229                         UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
230                 }
231         } else if (event->mask & IN_MOVED_TO) {
232                 DBG("Moved To event, path = [%s]\n", full_path);
233                 if (last_moved_cookie == event->cookie) {
234                         /* Ignore this case as this is generated due to MTP*/
235                         DBG("%s  is moved_to by MTP\n", full_path);
236                         last_moved_cookie = -1;
237                 } else {
238                         UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
239                         __process_object_added_event(full_path,
240                                         event->name, parentpath);
241                         UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
242                 }
243         } else if (event->mask & IN_CREATE) {
244                 if (event->mask & IN_ISDIR) {
245                         DBG("IN_CREATE --> IN_ISDIR");
246                         if (!g_strcmp0(g_last_created_dir, full_path)) {
247                                 /* Ignore this case as this is generated due to MTP*/
248                                 DBG("%s folder is generated by MTP\n",
249                                                 full_path);
250                                 memset(g_last_created_dir, 0,
251                                                 MTP_MAX_PATHNAME_SIZE + 1);
252                         } else {
253                                 UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
254                                 __process_object_added_event(full_path,
255                                                 event->name, parentpath);
256                                 UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
257                         }
258                 } else {
259                         if (FALSE == __add_file_to_inoti_open_files_list(event->wd,
260                                                 event->name)) {
261                                 DBG_SECURE("__add_file_to_inoti_open_files_list fail\
262                                                 %s\n", event->name);
263                         }
264                         DBG("IN_CREATE --> NOT IN_ISDIR");
265                 }
266         } else if (event->mask &  IN_DELETE) {
267                 if (!g_strcmp0(g_last_deleted, full_path)) {
268                         /* Ignore this case as this is generated due to MTP*/
269                         DBG("%s  is deleted by MTP\n", full_path);
270                         memset(g_last_deleted, 0,
271                                         MTP_MAX_PATHNAME_SIZE + 1);
272                 } else if (event->mask & IN_ISDIR) {
273                         DBG("IN_DELETE --> IN_ISDIR");
274                         UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
275                         __process_object_deleted_event(full_path,
276                                         event->name, TRUE);
277                         UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
278                 } else {
279                         DBG("IN_DELETE --> NOT IN_ISDIR");
280                         UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
281                         __process_object_deleted_event(full_path,
282                                         event->name, FALSE);
283                         UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
284                 }
285         } else if (event->mask & IN_CLOSE_WRITE) {
286                 DBG_SECURE("IN_CLOSE_WRITE %d, %s\n", event->wd, event->name);
287                 if (!g_strcmp0(g_last_copied, full_path)) {
288                         /* Ignore this case as this is generated due to MTP*/
289                         DBG("[%s] is copied by MTP\n", full_path);
290                         memset(g_last_copied, 0,
291                                         MTP_MAX_PATHNAME_SIZE + 1);
292                 } else {
293                         open_files_info_t *node = NULL;
294                         node = __find_file_in_inoti_open_files_list(event->wd,
295                                         event->name);
296
297                         if (node != NULL) {
298                                 UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex);
299                                 __process_object_added_event(full_path,
300                                                 event->name, parentpath);
301                                 UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex);
302                                 __remove_file_from_inoti_open_files_list(node);
303                         }
304                 }
305         } else {
306                 DBG("This case is ignored");
307                 return FALSE;
308         }
309
310         return TRUE;
311 }
312
313 void _inoti_deinit_filesystem_events()
314 {
315         if (TRUE != _util_thread_cancel(g_inoti_thrd)) {
316                 ERR("thread cancel fail.");
317                 return;
318         }
319
320         if (_util_thread_join(g_inoti_thrd, 0) == FALSE)
321                 ERR("_util_thread_join() Fail");
322
323         return;
324 }
325
326 static void __remove_inoti_watch(mtp_char *path)
327 {
328         mtp_int32 i = 0;
329
330         for (i = 0; i < g_cnt_watch_folder; i++) {
331                 if (g_inoti_watches[i].forlder_name == NULL)
332                         continue;
333
334                 if (g_strcmp0(g_inoti_watches[i].forlder_name, path) != 0)
335                         continue;
336
337                 g_free(g_inoti_watches[i].forlder_name);
338                 g_inoti_watches[i].forlder_name = NULL;
339                 inotify_rm_watch(g_inoti_fd, g_inoti_watches[i].wd);
340                 g_inoti_watches[i].wd = 0;
341
342                 break;
343         }
344
345         if (i == g_cnt_watch_folder)
346                 ERR("Path not found in g_noti_watches");
347         return;
348 }
349
350 static mtp_bool __add_file_to_inoti_open_files_list(mtp_int32 wd,
351                 mtp_char *event_name)
352 {
353         open_files_info_t *new_node = NULL;
354
355         new_node = (open_files_info_t *)g_malloc(sizeof(open_files_info_t));
356         if (NULL == new_node) {
357                 ERR("new_node is null malloc fail");
358                 return FALSE;
359         }
360
361         new_node->name = g_strdup(event_name);
362         new_node->wd = wd;
363
364         /* First created file */
365         if (NULL == g_open_files_list) {
366                 new_node->previous = NULL;
367         } else {
368                 g_open_files_list->next = new_node;
369                 new_node->previous = g_open_files_list;
370         }
371         new_node->next = NULL;
372         g_open_files_list = new_node;
373
374         return TRUE;
375 }
376
377 static open_files_info_t *__find_file_in_inoti_open_files_list(mtp_int32 wd,
378                 mtp_char *event_name)
379 {
380         open_files_info_t *current_node = g_open_files_list;
381
382         while (NULL != current_node) {
383                 if ((current_node->wd == wd) &&
384                                 (g_strcmp0(current_node->name, event_name) == 0)) {
385                         return current_node;
386                 }
387
388                 current_node = current_node->previous;
389         }
390
391         ERR("Cannot find file in open file's list");
392         return NULL;
393 }
394
395 static void __remove_file_from_inoti_open_files_list(open_files_info_t *node)
396 {
397         if (NULL != node->previous)
398                 node->previous->next = node->next;
399
400         if (NULL != node->next)
401                 node->next->previous = node->previous;
402
403         if (node == g_open_files_list)
404                 g_open_files_list = node->previous;
405
406         g_free(node->name);
407         g_free(node);
408
409         return;
410 }
411
412 static mtp_int32 __get_inoti_watch_id(mtp_int32 iwd)
413 {
414         mtp_int32 i = 0;
415
416         for (i = 0; i < INOTI_FOLDER_COUNT_MAX; i++) {
417                 if (iwd == g_inoti_watches[i].wd)
418                         break;
419         }
420
421         if (i >= INOTI_FOLDER_COUNT_MAX) {
422                 ERR("inoti_folder is not found");
423                 return -1;
424         }
425
426         return i;
427 }
428
429 static mtp_bool __get_inoti_event_full_path(mtp_int32 wd, mtp_char *event_name,
430                 mtp_char *path, mtp_int32 path_len, mtp_char *parent_path)
431 {
432         mtp_int32 inoti_id = 0;
433
434         retv_if(wd == 0, FALSE);
435         retv_if(path == NULL, FALSE);
436         retv_if(event_name == NULL, FALSE);
437
438         inoti_id = __get_inoti_watch_id(wd);
439         if (inoti_id < 0) {
440                 ERR("FAIL to find last_inoti_id : %d\n", inoti_id);
441                 return FALSE;
442         }
443
444         /* 2 is for / and null character */
445         if (path_len < (strlen(g_inoti_watches[inoti_id].forlder_name) +
446                                 strlen(event_name) + 2))
447                 return FALSE;
448
449         g_snprintf(path, path_len, "%s/%s",
450                         g_inoti_watches[inoti_id].forlder_name, event_name);
451         g_snprintf(parent_path, path_len, "%s",
452                         g_inoti_watches[inoti_id].forlder_name);
453
454         return TRUE;
455 }
456
457 static void __remove_recursive_inoti_watch(mtp_char *path)
458 {
459         mtp_int32 i = 0;
460         mtp_char *res = NULL;
461
462         for (i = 0; i < g_cnt_watch_folder; i++) {
463                 if (g_inoti_watches[i].forlder_name == NULL)
464                         continue;
465
466                 res = strstr(g_inoti_watches[i].forlder_name, path);
467                 if (res == NULL)
468                         continue;
469
470                 g_free(g_inoti_watches[i].forlder_name);
471                 g_inoti_watches[i].forlder_name = NULL;
472                 inotify_rm_watch(g_inoti_fd, g_inoti_watches[i].wd);
473                 g_inoti_watches[i].wd = 0;
474         }
475
476         return;
477 }
478
479 static void __clean_up_inoti(void *data)
480 {
481         char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
482         char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
483         _util_get_external_path(ext_path);
484         _util_get_internal_path(inter_path);
485
486         __remove_recursive_inoti_watch((mtp_char *)inter_path);
487         __remove_recursive_inoti_watch((mtp_char *)ext_path);
488         __destroy_inoti_open_files_list();
489
490         close(g_inoti_fd);
491         g_inoti_fd = 0;
492         return;
493 }
494
495 static void __delete_children_from_store_inoti(mtp_store_t *store,
496                 mtp_obj_t *obj)
497 {
498         mtp_uint32 i = 0;
499         ptp_array_t child_arr = { 0 };
500         mtp_obj_t *child_obj = NULL;
501         slist_node_t *node = NULL;
502
503         __remove_inoti_watch(obj->file_path);
504
505         _prop_init_ptparray(&child_arr, UINT32_TYPE);
506         _entity_get_child_handles(store, obj->obj_handle, &child_arr);
507
508         for (i = 0; i < child_arr.num_ele; i++) {
509
510                 mtp_uint32 *ptr32 = child_arr.array_entry;
511                 child_obj = _entity_get_object_from_store(store, ptr32[i]);
512
513                 if (child_obj != NULL && child_obj->obj_info != NULL &&
514                                 child_obj->obj_info->obj_fmt ==
515                                 PTP_FMT_ASSOCIATION) {
516                         __delete_children_from_store_inoti(store, child_obj);
517                 }
518
519                 node = _util_delete_node(&(store->obj_list), child_obj);
520                 g_free(node);
521                 _entity_dealloc_mtp_obj(child_obj);
522         }
523
524         _prop_deinit_ptparray(&child_arr);
525         return;
526 }
527
528 static void __process_object_added_event(mtp_char *fullpath,
529                 mtp_char *file_name, mtp_char *parent_path)
530 {
531         mtp_uint32 store_id = 0;
532         mtp_store_t *store = NULL;
533         mtp_obj_t *parent_obj = NULL;
534         mtp_uint32 h_parent = 0;
535         mtp_obj_t *obj = NULL;
536         struct stat stat_buf = { 0 };
537         mtp_int32 ret = 0;
538         dir_entry_t dir_info = { { 0 }, 0 };
539
540         if (NULL != g_strrstr(file_name, MTP_TEMP_FILE)) {
541                 ERR("File is a temp file");
542                 return;
543         }
544
545         if (file_name[0] == '.') {
546                 DBG_SECURE("Hidden file filename=[%s]\n", file_name);
547                 return;
548         }
549
550         store_id = _entity_get_store_id_by_path(fullpath);
551         store = _device_get_store(store_id);
552         if (NULL == store) {
553                 ERR("store is NULL so return");
554                 return;
555         }
556         parent_obj = _entity_get_object_from_store_by_path(store, parent_path);
557         if (NULL == parent_obj) {
558                 char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
559                 char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
560                 _util_get_external_path(ext_path);
561                 _util_get_internal_path(inter_path);
562
563                 if (!g_strcmp0(parent_path, inter_path) ||
564                                 !g_strcmp0(parent_path, ext_path)) {
565                         DBG("parent is the root folder");
566                         h_parent = 0;
567                 } else {
568                         DBG("Cannot find the parent, return");
569                         return;
570                 }
571         } else {
572                 h_parent = parent_obj->obj_handle;
573         }
574
575         ret = stat(fullpath, &stat_buf);
576         if (ret < 0) {
577                 ERR("stat() Fail");
578                 _util_print_error();
579                 return;
580         }
581
582         g_strlcpy(dir_info.filename, fullpath, MTP_MAX_PATHNAME_SIZE + 1);
583         dir_info.attrs.mtime = stat_buf.st_mtime;
584         dir_info.attrs.fsize = (mtp_uint64)stat_buf.st_size;
585
586         /* Reset the attributes */
587         dir_info.attrs.attribute = MTP_FILE_ATTR_MODE_NONE;
588         if (S_ISBLK(stat_buf.st_mode) || S_ISCHR(stat_buf.st_mode) ||
589                         S_ISLNK(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode)) {
590                 dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_SYSTEM;
591         }
592
593         if (S_ISREG(stat_buf.st_mode)) {
594                 dir_info.type = MTP_FILE_TYPE;
595                 dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_NONE;
596
597                 if (!((S_IWUSR & stat_buf.st_mode) ||
598                                         (S_IWGRP & stat_buf.st_mode) ||
599                                         (S_IWOTH & stat_buf.st_mode))) {
600                         dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_READ_ONLY;
601                 }
602
603                 obj = _entity_add_file_to_store(store, h_parent, fullpath,
604                                 file_name, &dir_info);
605                 if (NULL == obj) {
606                         ERR("_entity_add_file_to_store fail.");
607                         return;
608                 }
609         } else if (S_ISDIR(stat_buf.st_mode)) {
610                 dir_info.type = MTP_DIR_TYPE;
611                 dir_info.attrs.attribute  |= MTP_FILE_ATTR_MODE_DIR;
612                 obj = _entity_add_folder_to_store(store, h_parent, fullpath,
613                                 file_name, &dir_info);
614                 if (NULL == obj) {
615                         ERR("_entity_add_folder_to_store fail.");
616                         return;
617                 }
618         } else {
619                 ERR("%s type is neither DIR nor FILE.\n", fullpath);
620                 return;
621         }
622
623         _eh_send_event_req_to_eh_thread(EVENT_OBJECT_ADDED,
624                         obj->obj_handle, 0, NULL);
625
626         return;
627 }
628
629 static void __process_object_deleted_event(mtp_char *fullpath,
630                 mtp_char *file_name, mtp_bool isdir)
631 {
632         mtp_obj_t *obj = NULL;
633         mtp_obj_t *parent_obj = NULL;
634         mtp_store_t *store = NULL;
635         mtp_uint32 storageid = 0;
636         mtp_uint32 h_parent = 0;
637         mtp_uint32 obj_handle = 0;
638         slist_node_t *node = NULL;
639
640         if (NULL != strstr(fullpath, MTP_TEMP_FILE)) {
641                 ERR("File is a temp file, need to ignore");
642                 return;
643         }
644
645         if (file_name[0] == '.') {
646                 DBG_SECURE("Hidden file filename=[%s], Ignore\n", file_name);
647                 return;
648         }
649
650         storageid = _entity_get_store_id_by_path(fullpath);
651         store = _device_get_store(storageid);
652         if (NULL == store) {
653                 ERR("store is NULL so return");
654                 return;
655         }
656
657         obj = _entity_get_object_from_store_by_path(store, fullpath);
658         if (NULL == obj) {
659                 ERR("object is NULL so return");
660                 return;
661         }
662
663         obj_handle = obj->obj_handle;
664         h_parent = obj->obj_info->h_parent;
665         if (h_parent != PTP_OBJECTHANDLE_ROOT) {
666                 parent_obj = _entity_get_object_from_store(store, h_parent);
667                 if (NULL != parent_obj) {
668                         _entity_remove_reference_child_array(parent_obj,
669                                         obj->obj_handle);
670                 }
671         }
672
673         if (TRUE == isdir)
674                 __delete_children_from_store_inoti(store, obj);
675
676         node = _util_delete_node(&(store->obj_list), obj);
677         g_free(node);
678         _entity_dealloc_mtp_obj(obj);
679
680         _eh_send_event_req_to_eh_thread(EVENT_OBJECT_REMOVED, obj_handle,
681                         0, NULL);
682
683         return;
684 }
685
686 static void __destroy_inoti_open_files_list()
687 {
688         open_files_info_t *current = NULL;
689
690         ret_if(g_open_files_list == NULL);
691
692         while (g_open_files_list) {
693                 current = g_open_files_list;
694                 g_open_files_list = g_open_files_list->previous;
695
696                 if (g_open_files_list)
697                         g_open_files_list->next = NULL;
698
699                 g_free(current->name);
700                 current->wd = 0;
701                 current->previous = NULL;
702                 current->next = NULL;
703                 g_free(current);
704         }
705
706         g_open_files_list = NULL;
707         return;
708 }
709 #endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/