4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Yong Yeon Kim <yy9875.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 * This file defines api utilities of contents manager engines.
25 * @file media-server-inotify.c
26 * @author Yong Yeon Kim(yy9875.kim@samsung.com)
35 #include "media-util.h"
36 #include "media-server-dbg.h"
37 #include "media-server-utils.h"
38 #include "media-server-db-svc.h"
39 #include "media-server-inotify-internal.h"
40 #include "media-server-inotify.h"
47 ms_inoti_dir_data *first_inoti_node;
48 ms_ignore_file_info *latest_ignore_file;
50 int _ms_inoti_directory_scan_and_register_file(void **handle, char *dir_path)
53 struct dirent *res = NULL;
55 char path[MS_FILE_PATH_LEN_MAX] = { 0 };
59 return MS_MEDIA_ERR_INVALID_PATH;
61 dp = opendir(dir_path);
63 MS_DBG_ERR("Fail to open dir %s", dir_path);
64 return MS_MEDIA_ERR_DIR_OPEN_FAIL;
67 ms_inoti_add_watch(dir_path);
69 while (!readdir_r(dp, &ent, &res)) {
73 if (ent.d_name[0] == '.')
76 err = ms_strappend(path, sizeof(path), "%s/%s", dir_path, ent.d_name);
77 if (err != MS_MEDIA_ERR_NONE) {
78 MS_DBG_ERR("ms_strappend error : %d", err);
82 /*in case of directory */
83 if (ent.d_type == DT_DIR) {
84 _ms_inoti_directory_scan_and_register_file(handle, path);
86 err = ms_register_file(handle, path, NULL);
87 if (err != MS_MEDIA_ERR_NONE) {
88 MS_DBG_ERR("ms_register_file error : %d", err);
99 int _ms_inoti_scan_renamed_folder(void **handle, char *org_path, char *chg_path)
103 struct dirent *res = NULL;
106 char path_from[MS_FILE_PATH_LEN_MAX] = { 0 };
107 char path_to[MS_FILE_PATH_LEN_MAX] = { 0 };
108 ms_storage_type_t src_storage = 0;
109 ms_storage_type_t des_storage = 0;
111 if (org_path == NULL || chg_path == NULL) {
112 MS_DBG_ERR("Parameter is wrong");
113 return MS_MEDIA_ERR_INVALID_PARAMETER;
116 dp = opendir(chg_path);
118 MS_DBG_ERR("Fail to open dir %s", chg_path);
119 return MS_MEDIA_ERR_DIR_OPEN_FAIL;
121 MS_DBG("Modify added watch");
122 ms_inoti_modify_watch(org_path, chg_path);
125 while (!readdir_r(dp, &ent, &res)) {
129 if (ent.d_name[0] == '.')
132 err = ms_strappend(path_from, sizeof(path_from), "%s/%s", org_path, ent.d_name);
133 if (err != MS_MEDIA_ERR_NONE) {
134 MS_DBG_ERR("ms_strappend error : %d", err);
138 err = ms_strappend(path_to, sizeof(path_to), "%s/%s", chg_path, ent.d_name);
139 if (err != MS_MEDIA_ERR_NONE) {
140 MS_DBG_ERR("ms_strappend error : %d", err);
144 /*in case of directory */
145 if (ent.d_type == DT_DIR) {
146 _ms_inoti_scan_renamed_folder(handle, path_from, path_to);
150 if (ent.d_type == DT_REG) {
151 src_storage = ms_get_storage_type_by_full(path_from);
152 des_storage = ms_get_storage_type_by_full(path_to);
154 if ((src_storage != MS_MEDIA_ERR_INVALID_PATH)
155 && (des_storage != MS_MEDIA_ERR_INVALID_PATH))
156 ms_move_item(handle, src_storage, des_storage, path_from, path_to);
158 MS_DBG_ERR("src_storage : %s", src_storage);
159 MS_DBG_ERR("des_storage : %s", des_storage);
169 int ms_inoti_add_ignore_file(const char *path)
171 ms_ignore_file_info *new_node;
173 new_node = ms_inoti_find_ignore_file(path);
174 if (new_node != NULL)
175 return MS_MEDIA_ERR_NONE;
177 new_node = malloc(sizeof(ms_ignore_file_info));
178 new_node->path = strdup(path);
180 /*first created file */
181 if (latest_ignore_file == NULL) {
182 latest_ignore_file = malloc(sizeof(ms_ignore_file_info));
183 new_node->previous = NULL;
185 latest_ignore_file->next = new_node;
186 new_node->previous = latest_ignore_file;
188 new_node->next = NULL;
190 latest_ignore_file = new_node;
192 return MS_MEDIA_ERR_NONE;
195 int ms_inoti_delete_ignore_file(ms_ignore_file_info * delete_node)
197 if (delete_node->previous != NULL)
198 delete_node->previous->next = delete_node->next;
199 if (delete_node->next != NULL)
200 delete_node->next->previous = delete_node->previous;
202 if (delete_node == latest_ignore_file) {
203 latest_ignore_file = delete_node->previous;
206 MS_SAFE_FREE(delete_node->path);
207 MS_SAFE_FREE(delete_node);
210 return MS_MEDIA_ERR_NONE;
213 ms_ignore_file_info *ms_inoti_find_ignore_file(const char *path)
215 ms_ignore_file_info *node = NULL;
217 node = latest_ignore_file;
218 while (node != NULL) {
219 if (strcmp(node->path, path) == 0) {
223 node = node->previous;
229 void ms_inoti_delete_mmc_ignore_file(void)
231 ms_ignore_file_info *prv_node = NULL;
232 ms_ignore_file_info *cur_node = NULL;
233 ms_ignore_file_info *del_node = NULL;
235 if (latest_ignore_file != NULL) {
236 cur_node = latest_ignore_file;
237 while (cur_node != NULL) {
238 if (strstr(cur_node->path, MEDIA_ROOT_PATH_SDCARD) != NULL) {
239 if (prv_node != NULL) {
240 prv_node->previous = cur_node->previous;
243 if (cur_node == latest_ignore_file)
244 latest_ignore_file = latest_ignore_file->previous;
251 cur_node = cur_node->previous;
253 if (del_node != NULL) {
254 MS_SAFE_FREE(del_node->path);
255 MS_SAFE_FREE(del_node);
264 int ms_inoti_init(void)
266 inoti_fd = inotify_init();
268 perror("inotify_init");
269 MS_DBG_ERR("inotify_init failed");
273 return MS_MEDIA_ERR_NONE;
276 void ms_inoti_add_watch(char *path)
278 ms_inoti_dir_data *current_dir = NULL;
279 ms_inoti_dir_data *prv_node = NULL;
280 ms_inoti_dir_data *last_node = NULL;
282 /*find same folder */
283 if (first_inoti_node != NULL) {
284 last_node = first_inoti_node;
285 while (last_node != NULL) {
286 if (strcmp(path, last_node->name) == 0) {
287 MS_DBG("watch is already added: %s", path);
290 prv_node = last_node;
291 last_node = last_node->next;
295 /*there is no same path. */
296 current_dir = malloc(sizeof(ms_inoti_dir_data));
297 current_dir->wd = inotify_add_watch(inoti_fd, path,
298 IN_CLOSE_WRITE | IN_CREATE | IN_DELETE |
299 IN_MOVED_FROM | IN_MOVED_TO);
301 if (current_dir->wd > 0) {
302 current_dir->name = strdup(path);
303 current_dir->next = NULL;
305 if (first_inoti_node == NULL) {
306 first_inoti_node = current_dir;
308 /*if next node of current node is NULL, it is the lastest node. */
309 prv_node->next = current_dir;
311 MS_DBG("add watch : %s", path);
313 MS_DBG_ERR("inotify_add_watch failed");
314 MS_SAFE_FREE(current_dir);
318 int ms_inoti_add_watch_with_node(ms_dir_scan_info * const node, int depth)
321 char full_path[MS_FILE_PATH_LEN_MAX] = { 0 };
322 ms_inoti_dir_data *current_dir = NULL;
323 ms_inoti_dir_data *prv_node = NULL;
324 ms_inoti_dir_data *last_node = NULL;
326 err = ms_get_full_path_from_node(node, full_path, depth);
327 if (err != MS_MEDIA_ERR_NONE)
328 return MS_MEDIA_ERR_INVALID_PATH;
330 /*find same folder */
331 if (first_inoti_node != NULL) {
332 last_node = first_inoti_node;
333 while (last_node != NULL) {
334 if (strcmp(full_path, last_node->name) == 0) {
335 return MS_MEDIA_ERR_NONE;
337 prv_node = last_node;
338 last_node = last_node->next;
342 /*there is no same path. */
343 current_dir = malloc(sizeof(ms_inoti_dir_data));
344 current_dir->wd = inotify_add_watch(inoti_fd, full_path,
345 IN_CLOSE_WRITE | IN_CREATE | IN_DELETE |
346 IN_MOVED_FROM | IN_MOVED_TO);
347 if( current_dir->wd > 0) {
348 current_dir->name = strdup(full_path);
349 current_dir->next = NULL;
351 if (first_inoti_node == NULL) {
352 first_inoti_node = current_dir;
354 /*if next node of current node is NULL, it is the lastest node. */
355 prv_node->next = current_dir;
357 MS_DBG("add watch : %s", full_path);
359 MS_DBG_ERR("inotify_add_watch failed : %d", current_dir->wd);
360 MS_SAFE_FREE(current_dir);
363 return MS_MEDIA_ERR_NONE;
366 void ms_inoti_remove_watch_recursive(char *path)
368 ms_inoti_dir_data *prv_node = NULL;
369 ms_inoti_dir_data *cur_node = NULL;
370 ms_inoti_dir_data *del_node = NULL;
372 if (first_inoti_node != NULL) {
373 cur_node = first_inoti_node;
374 while (cur_node != NULL) {
375 if (strstr(cur_node->name, path) != NULL) {
376 if (prv_node != NULL) {
381 if (cur_node == first_inoti_node)
383 first_inoti_node->next;
390 cur_node = cur_node->next;
392 if (del_node != NULL) {
393 MS_SAFE_FREE(del_node->name);
394 MS_SAFE_FREE(del_node);
403 void ms_inoti_remove_watch(char *path)
405 ms_inoti_dir_data *del_node = NULL;
406 ms_inoti_dir_data *prv_node = NULL;
408 if (strcmp(first_inoti_node->name, path) == 0) {
409 del_node = first_inoti_node;
410 first_inoti_node = first_inoti_node->next;
412 /*find same folder */
413 if (first_inoti_node != NULL) {
414 del_node = first_inoti_node;
415 while (del_node != NULL) {
416 MS_DBG("current node %s", del_node->name);
417 if (strcmp(path, del_node->name) == 0) {
418 MS_DBG("find delete node: %s", del_node->name);
419 if (prv_node != NULL) {
420 MS_DBG("previous_node : %s", prv_node->name);
421 prv_node->next = del_node->next;
423 /*free deleted node */
424 MS_SAFE_FREE(del_node->name);
425 MS_SAFE_FREE(del_node);
429 del_node = del_node->next;
438 void ms_inoti_modify_watch(char *path_from, char *path_to)
441 ms_inoti_dir_data *mod_node;
443 if (strcmp(first_inoti_node->name, path_from) == 0) {
444 mod_node = first_inoti_node;
446 /*find same folder */
447 if (first_inoti_node != NULL) {
448 mod_node = first_inoti_node;
449 while (mod_node != NULL) {
450 /*find previous directory*/
451 if (strcmp(path_from, mod_node->name) == 0) {
452 /*change path of directory*/
453 /*free previous name of node */
454 MS_SAFE_FREE(mod_node->name);
457 mod_node->name = strdup(path_to);
465 mod_node = mod_node->next;
470 /*this is new directory*/
472 ms_inoti_add_watch(path_to);
476 #define STOP_INOTI "stop_inoti"
478 gboolean ms_inoti_thread(void *data)
486 char name[MS_FILE_NAME_LEN_MAX + 1] = { 0 };
487 char prev_name[MS_FILE_NAME_LEN_MAX + 1] = { 0 };
488 char buffer[INOTI_BUF_LEN] = { 0 };
489 char path[MS_FILE_PATH_LEN_MAX] = { 0 };
490 struct inotify_event *event;
491 void **handle = NULL;
493 MS_DBG("START INOTIFY");
495 err = ms_connect_db(&handle);
496 if (err != MS_MEDIA_ERR_NONE) {
497 MS_DBG_ERR(" INOTIFY : sqlite3_open: ret = %d", err);
503 length = read(inoti_fd, buffer, sizeof(buffer) - 1);
505 if (length < 0 || length > sizeof(buffer)) { /*this is error */
509 while (i < length && i < INOTI_BUF_LEN) {
510 /*check poweroff status*/
516 /*it's possible that ums lets reset phone data... */
517 event = (struct inotify_event *)&buffer[i];
519 if (strcmp(event->name, POWEROFF_DIR_NAME) == 0) {
522 } else if (strcmp(event->name, STOP_INOTI) == 0) {
523 MS_DBG("stop inotify thread");
525 } else if (event->name[0] == '.') {
526 /*event of hidden folder is ignored */
527 goto NEXT_INOTI_EVENT;
528 } else if (event->wd < 1) {
530 MS_DBG_ERR("invalid wd : %d", event->wd);
531 goto NEXT_INOTI_EVENT;
534 /*start of one event */
535 if (event->len && (event->len <= MS_FILE_NAME_LEN_MAX + 1)) {
536 /*Add for fixing prevent defect 2011-02-15 */
537 err = ms_strcopy(name, sizeof(name), "%s", event->name);
538 if (err != MS_MEDIA_ERR_NONE) {
539 MS_DBG_ERR("ms_strcopy error : %d", err);
540 goto NEXT_INOTI_EVENT;
543 /*get full path of file or directory */
544 res = _ms_inoti_get_full_path(event->wd, name, path, sizeof(path));
546 MS_DBG_ERR("_ms_inoti_get_full_path error");
547 goto NEXT_INOTI_EVENT;
550 MS_DBG("INOTIFY[%d : %s]", event->wd, name);
551 if (event->mask & IN_ISDIR) {
552 MS_DBG("DIRECTORY INOTIFY");
554 if (event->mask & IN_MOVED_FROM) {
555 MS_DBG("MOVED_FROM");
557 prev_mask = event->mask;
560 err = ms_strcopy(prev_name, sizeof(prev_name), "%s", event->name);
561 if (err != MS_MEDIA_ERR_NONE) {
562 MS_DBG_ERR("ms_strcopy fail");
563 goto NEXT_INOTI_EVENT;
566 else if (event->mask & IN_MOVED_TO) {
569 char full_path_from[MS_FILE_PATH_LEN_MAX] = { 0 };
571 res = _ms_inoti_get_full_path(prev_wd, prev_name, full_path_from, sizeof(full_path_from));
573 MS_DBG_ERR("_ms_inoti_get_full_path error");
574 goto NEXT_INOTI_EVENT;
576 /*enable bundle commit*/
577 ms_move_start(handle);
579 /*need update file information under renamed directory */
580 _ms_inoti_scan_renamed_folder(handle, full_path_from, path);
582 /*disable bundle commit*/
585 prev_mask = prev_wd = 0; /*reset */
587 else if (event->mask & IN_CREATE) {
590 _ms_inoti_directory_scan_and_register_file(handle, path);
591 prev_mask = event->mask;
593 else if (event->mask & IN_DELETE) {
596 ms_inoti_remove_watch(path);
600 MS_DBG("FILE INOTIFY");
602 if (event->mask & IN_MOVED_FROM) {
603 MS_DBG("MOVED_FROM");
605 err = ms_delete_item(handle, path);
606 if (err != MS_MEDIA_ERR_NONE) {
607 MS_DBG_ERR("ms_media_db_delete fail error : %d", err);
610 else if (event->mask & IN_MOVED_TO) {
613 err = ms_register_file(handle, path, NULL);
614 if (err != MS_MEDIA_ERR_NONE) {
615 MS_DBG_ERR("ms_register_file error : %d", err);
618 else if (event->mask & IN_CREATE) {
621 _ms_inoti_add_create_file_list(event->wd, name);
623 else if (event->mask & IN_DELETE) {
626 err = ms_delete_item(handle, path);
627 if (err != MS_MEDIA_ERR_NONE) {
628 MS_DBG_ERR("ms_media_db_delete error : %d", err);
631 else if (event->mask & IN_CLOSE_WRITE) {
632 MS_DBG("CLOSE_WRITE");
633 ms_create_file_info *node;
635 node = _ms_inoti_find_create_file_list (event->wd, name);
636 if (node != NULL || ((prev_mask & IN_ISDIR) & IN_CREATE)) {
637 err = ms_register_file(handle, path, NULL);
638 if (err != MS_MEDIA_ERR_NONE) {
639 MS_DBG_ERR("ms_register_file error : %d", err);
642 _ms_inoti_delete_create_file_list(node);
645 ms_ignore_file_info *ignore_file;
647 ignore_file = ms_inoti_find_ignore_file(path);
648 if (ignore_file == NULL) {
649 /*in case of replace */
650 MS_DBG("This case is replacement or changing meta data.");
651 err = ms_refresh_item(handle, path);
652 if (err != MS_MEDIA_ERR_NONE) {
653 MS_DBG_ERR("ms_refresh_item error : %d", err);
654 goto NEXT_INOTI_EVENT;
657 /*This is ignore case*/
660 prev_mask = prev_wd = 0; /*reset */
663 } /*end of one event */
665 /*This is ignore case*/
666 if (event->mask & IN_IGNORED) {
667 MS_DBG("This case is ignored");
671 i += INOTI_EVENT_SIZE + event->len;
678 ms_inoti_remove_watch_recursive(MEDIA_ROOT_PATH_INTERNAL);
679 ms_inoti_remove_watch_recursive(MEDIA_ROOT_PATH_SDCARD);
683 if (handle) ms_disconnect_db(&handle);
688 int _ms_get_path_from_current_node(int find_folder,
689 ms_dir_scan_info **current_root,
690 ms_dir_scan_info **real_root, char **path, int *depth)
692 int err = MS_MEDIA_ERR_NONE;
693 char get_path[FAT_FILEPATH_LEN_MAX] = { 0 };
695 if (find_folder == 0) {
696 if ((*current_root)->Rbrother != NULL) {
697 *current_root = (*current_root)->Rbrother;
700 if ((*current_root)->parent == *real_root
701 || (*current_root)->parent == NULL) {
702 *current_root = NULL;
704 return MS_MEDIA_ERR_NONE;
705 } else if ((*current_root)->parent->Rbrother == NULL) {
706 *current_root = (*current_root)->parent;
709 *current_root = (*current_root)->parent->Rbrother;
718 err = ms_get_full_path_from_node(*current_root, get_path, *depth);
719 if (err != MS_MEDIA_ERR_NONE)
720 return MS_MEDIA_ERR_INVALID_PATH;
722 *path = strdup(get_path);
727 void ms_inoti_add_watch_all_directory(ms_storage_type_t storage_type)
732 char get_path[MS_FILE_PATH_LEN_MAX] = { 0 };
736 struct dirent *result;
738 ms_dir_scan_info *root;
739 ms_dir_scan_info *tmp_root = NULL;
740 ms_dir_scan_info *cur_node = NULL; /*current node*/
741 ms_dir_scan_info *prv_node = NULL; /*previous node*/
742 ms_dir_scan_info *next_node = NULL;
744 root = malloc(sizeof(ms_dir_scan_info));
746 MS_DBG_ERR("malloc fail");
750 if (storage_type == MS_STORAGE_INTERNAL)
751 root->name = strdup(MEDIA_ROOT_PATH_INTERNAL);
753 root->name = strdup(MEDIA_ROOT_PATH_SDCARD);
754 if (root->name == NULL) {
755 MS_DBG_ERR("strdup fail");
761 root->Rbrother = NULL;
766 path = malloc(sizeof(char) * MS_FILE_PATH_LEN_MAX);
768 err = ms_get_full_path_from_node(tmp_root, path, depth);
769 if (err != MS_MEDIA_ERR_NONE) {
775 ms_inoti_add_watch_with_node(root, depth);
778 /*check poweroff status*/
784 /*check SD card in out*/
785 if ((mmc_state != VCONFKEY_SYSMAN_MMC_MOUNTED) && (storage_type == MS_STORAGE_EXTERNAL))
791 MS_DBG_ERR("%s folder opendir fails", path);
795 while (!readdir_r(dp, &entry, &result)) {
796 /*check poweroff status*/
805 if (entry.d_name[0] == '.')
808 /*check SD card in out*/
809 if ((mmc_state != VCONFKEY_SYSMAN_MMC_MOUNTED) && (storage_type == MS_STORAGE_EXTERNAL)) {
813 if (entry.d_type & DT_DIR) {
815 err = ms_strappend(get_path, sizeof(get_path), "%s/%s",path, entry.d_name);
816 if (err != MS_MEDIA_ERR_NONE) {
817 MS_DBG_ERR("ms_strappend error");
821 tmp_dp = opendir(get_path);
822 if (tmp_dp == NULL) {
823 MS_DBG_ERR("%s folder opendir fails", get_path);
824 MS_DBG("error : %d, %s", errno ,strerror(errno));
830 cur_node = malloc(sizeof(ms_dir_scan_info));
831 if (cur_node == NULL) {
832 MS_DBG_ERR("malloc fail");
837 cur_node->name = strdup(entry.d_name);
838 cur_node->Rbrother = NULL;
839 cur_node->next = NULL;
842 if (find_folder == 0) {
843 cur_node->parent = tmp_root;
846 cur_node->parent = tmp_root->parent;
847 prv_node->Rbrother = cur_node;
849 prv_node->next = cur_node;
852 ms_inoti_add_watch_with_node(cur_node, depth);
860 if (dp) closedir(dp);
865 err = _ms_get_path_from_current_node(find_folder, &tmp_root, &root, &path, &depth);
866 if (err != MS_MEDIA_ERR_NONE)
869 if (tmp_root == NULL)
876 /*free allocated memory */
877 if (dp) closedir(dp);
881 while (cur_node != NULL) {
882 next_node = cur_node->next;
883 MS_SAFE_FREE(cur_node->name);
884 MS_SAFE_FREE(cur_node);
885 cur_node = next_node;