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.
24 #include "media-util.h"
25 #include "media-server-ipc.h"
26 #include "media-common-utils.h"
27 #include "media-common-external-storage.h"
28 #include "media-common-db-svc.h"
29 #include "media-scanner-dbg.h"
30 #include "media-scanner-socket.h"
31 #include "media-scanner-scan.h"
33 static bool power_off;
34 static GAsyncQueue * storage_queue;
35 static GAsyncQueue *scan_queue;
36 static GAsyncQueue *reg_queue;
37 static GMutex scan_req_mutex;
39 static bool __msc_is_power_off(void)
42 MS_DBG_ERR("Power off");
49 static int __msc_dir_scan(sqlite3 *handle, const char *storage_id, char *start_path, bool check_exists, bool is_recursive, uid_t uid)
51 int ret = MS_MEDIA_ERR_NONE;
55 GPtrArray *dir_array = NULL;
56 char *current_path = NULL;
58 int (*scan_function)(sqlite3 *, const char*, const char*, uid_t) = NULL;
60 dir_array = g_ptr_array_new();
61 g_ptr_array_add(dir_array, start_path);
63 scan_function = (check_exists == false) ? ms_insert_item_batch : ms_validate_item;
65 while (dir_array->len != 0) {
66 current_path = g_ptr_array_index(dir_array, 0);
67 g_ptr_array_remove_index(dir_array, 0);
69 if (__msc_is_power_off()) {
70 ret = MS_MEDIA_ERR_SCANNER_FORCE_STOP;
71 MS_SAFE_FREE(current_path);
75 if (ms_check_scan_ignore(current_path, uid) != MS_MEDIA_ERR_NONE) {
76 MS_DBG_SERR("%s is ignore", current_path);
77 MS_SAFE_FREE(current_path);
81 dir = g_dir_open(current_path, 0, &error);
83 MS_DBG_ERR("g_dir_open fails [%s]", current_path);
84 MS_SAFE_FREE(current_path);
90 if (ms_insert_folder(handle, storage_id, current_path, uid) != MS_MEDIA_ERR_NONE)
91 MS_DBG_ERR("insert folder failed");
93 while ((name = g_dir_read_name(dir))) {
94 if (__msc_is_power_off()) {
95 ret = MS_MEDIA_ERR_SCANNER_FORCE_STOP;
102 path = g_build_path(G_DIR_SEPARATOR_S, current_path, name, NULL);
104 if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
105 /* Check symbolic link file */
106 if (g_file_test(path, G_FILE_TEST_IS_SYMLINK)) {
107 MS_DBG_WARN("Symbolic link.. Skip this file");
112 /* Check content.scanning.others feature */
113 if (!ms_check_support_media_type(path)) {
114 MS_DBG("Unsupported media type");
119 if (scan_function(handle, storage_id, path, uid) != MS_MEDIA_ERR_NONE)
120 MS_DBG_ERR("failed to update db");
125 g_ptr_array_add(dir_array, path);
127 ret = ms_insert_folder(handle, storage_id, path, uid);
128 if (ret != MS_MEDIA_ERR_NONE)
129 MS_DBG_ERR("ms_insert_folder failed");
135 MS_SAFE_FREE(current_path);
141 g_ptr_array_free(dir_array, TRUE);
146 static int __msc_db_update(sqlite3 *handle, const char *storage_id, const ms_comm_msg_s * scan_data)
149 int err = MS_MEDIA_ERR_NONE;
150 char *start_path = NULL;
152 scan_type = scan_data->msg_type;
153 start_path = g_strdup(scan_data->msg);
155 if (scan_type != MS_MSG_STORAGE_INVALID) {
156 MS_DBG_INFO("INSERT");
157 if (scan_type == MS_MSG_STORAGE_ALL)
158 err = __msc_dir_scan(handle, storage_id, start_path, false, true, scan_data->uid);
160 err = __msc_dir_scan(handle, storage_id, start_path, true, true, scan_data->uid);
162 if (err != MS_MEDIA_ERR_NONE)
163 MS_DBG_ERR("error : %d", err);
166 MS_DBG_INFO("INVALID");
167 err = ms_validity_change_all_items(handle, storage_id, false, scan_data->uid);
168 if (err != MS_MEDIA_ERR_NONE)
169 MS_DBG_ERR("error : %d", err);
171 ms_set_folder_validity(handle, storage_id, start_path, 0, true, scan_data->uid);
181 static int __msc_directory_scan_insert_only(sqlite3 *handle, ms_comm_msg_s *scan_data, bool is_recursive)
183 int ret = MS_MEDIA_ERR_NONE;
184 char *start_path = NULL;
185 char *folder_uuid = NULL;
187 MS_DBG_RETVM_IF(!handle, MS_MEDIA_ERR_INVALID_PARAMETER, "handle is NULL");
188 MS_DBG_RETVM_IF(!scan_data, MS_MEDIA_ERR_INVALID_PARAMETER, "scan_data is NULL");
190 start_path = g_strdup(scan_data->msg);
192 ms_batch_commit_enable(false, 0);
193 ret = __msc_dir_scan(handle, scan_data->storage_id, start_path, false, is_recursive, scan_data->uid);
194 ms_batch_commit_disable(scan_data->uid);
196 if (ret != MS_MEDIA_ERR_SCANNER_FORCE_STOP) {
197 MS_DBG_INFO("working normally");
198 ret = ms_get_folder_id(handle, scan_data->storage_id, scan_data->msg, &folder_uuid);
199 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_get_folder_id failed");
200 ret = ms_send_dir_update_noti(scan_data->msg, folder_uuid, MS_ITEM_INSERT, scan_data->pid);
202 MS_SAFE_FREE(folder_uuid);
208 static int __msc_directory_scan_update_and_delete(sqlite3 *handle, ms_comm_msg_s *scan_data, bool is_recursive, int noti_type)
210 int ret = MS_MEDIA_ERR_NONE;
211 char *start_path = NULL;
212 char *folder_uuid = NULL;
214 MS_DBG_RETVM_IF(!handle, MS_MEDIA_ERR_INVALID_PARAMETER, "handle is NULL");
215 MS_DBG_RETVM_IF(!scan_data, MS_MEDIA_ERR_INVALID_PARAMETER, "scan_data is NULL");
217 ret = ms_set_folder_validity(handle, scan_data->storage_id, scan_data->msg, MS_SCANNING, is_recursive, scan_data->uid);
218 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "set_folder_validity failed");
220 ret = ms_set_folder_item_validity(handle, scan_data->storage_id, scan_data->msg, MS_SCANNING, is_recursive, scan_data->uid);
221 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_set_folder_item_validity failed");
223 start_path = g_strdup(scan_data->msg);
225 ret = ms_get_folder_id(handle, scan_data->storage_id, scan_data->msg, &folder_uuid);
226 if (ret != MS_MEDIA_ERR_NONE) {
227 MS_DBG_ERR("ms_get_folder_id failed");
232 ms_batch_commit_enable(false, 0);
233 ret = __msc_dir_scan(handle, scan_data->storage_id, start_path, true, is_recursive, scan_data->uid);
234 ms_batch_commit_disable(scan_data->uid);
236 if (ms_delete_invalid_items(handle, scan_data->storage_id, scan_data->uid) != MS_MEDIA_ERR_NONE)
237 MS_DBG_ERR("deleting invalid items in storage failed");
239 if (ms_delete_invalid_folder(scan_data->storage_id, scan_data->uid) != MS_MEDIA_ERR_NONE)
240 MS_DBG_ERR("deleting invalid folders in storage failed");
242 if (ret != MS_MEDIA_ERR_SCANNER_FORCE_STOP) {
243 MS_DBG_INFO("working normally");
244 ret = ms_send_dir_update_noti(scan_data->msg, folder_uuid, noti_type, scan_data->pid);
252 gpointer msc_directory_scan_thread(gpointer data)
254 int ret = MS_MEDIA_ERR_NONE;
255 sqlite3 *handle = NULL;
256 ms_comm_msg_s *scan_data = NULL;
257 bool is_recursive = true;
260 scan_data = g_async_queue_pop(scan_queue);
261 if (scan_data->pid == POWEROFF) {
262 MS_DBG_ERR("power off");
266 MS_DBG_WARN("DIRECTORY SCAN START [%.*s][%s][%d]", MAX_MSG_SIZE, scan_data->msg, scan_data->storage_id, scan_data->msg_type);
268 if (strlen(scan_data->storage_id) == 0) {
269 MS_DBG_ERR("storage_id length is 0");
270 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
274 if (scan_data->msg_type != MS_MSG_DIRECTORY_SCANNING && scan_data->msg_type != MS_MSG_DIRECTORY_SCANNING_NON_RECURSIVE) {
275 MS_DBG_ERR("Invalid request");
276 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
280 ret = ms_connect_db(&handle, scan_data->uid);
281 if (ret != MS_MEDIA_ERR_NONE) {
282 MS_DBG_ERR("ms_connect_db failed");
286 ms_trim_dir_path(scan_data->msg);
287 is_recursive = (scan_data->msg_type == MS_MSG_DIRECTORY_SCANNING_NON_RECURSIVE) ? false : true;
289 if (g_file_test(scan_data->msg, G_FILE_TEST_IS_DIR)) {
290 if (ms_check_folder_exist(handle, scan_data->storage_id, scan_data->msg) == MS_MEDIA_ERR_NONE) {
291 MS_DBG_WARN("[%.*s] already exist", MAX_MSG_SIZE, scan_data->msg);
292 ret = __msc_directory_scan_update_and_delete(handle, scan_data, is_recursive, MS_ITEM_UPDATE);
294 MS_DBG_WARN("[%.*s] new insert path", MAX_MSG_SIZE, scan_data->msg);
295 ret = __msc_directory_scan_insert_only(handle, scan_data, is_recursive);
298 MS_DBG_WARN("[%.*s] delete path", MAX_MSG_SIZE, scan_data->msg);
299 ret = __msc_directory_scan_update_and_delete(handle, scan_data, true, MS_ITEM_DELETE);
302 ms_disconnect_db(handle);
304 if (__msc_is_power_off())
310 msc_send_result(ret, scan_data);
312 MS_DBG_INFO("DIRECTORY SCAN END [%d]", ret);
321 static int __msc_storage_scan_partial(ms_comm_msg_s *scan_data, ms_user_storage_type_e storage_type)
323 int ret = MS_MEDIA_ERR_NONE;
324 sqlite3 *handle = NULL;
326 ret = ms_connect_db(&handle, scan_data->uid);
327 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_connect_db failed");
329 ms_set_db_status(MS_DB_UPDATING, storage_type);
331 ret = ms_validity_change_all_items(handle, scan_data->storage_id, false, scan_data->uid);
332 if (ret != MS_MEDIA_ERR_NONE) {
333 MS_DBG_ERR("ms_validity_change_all_items failed");
334 ms_disconnect_db(handle);
339 ms_batch_commit_enable(false, 0);
340 ret = __msc_db_update(handle, scan_data->storage_id, scan_data);
341 ms_batch_commit_disable(scan_data->uid);
343 if (ms_delete_invalid_items(handle, scan_data->storage_id, scan_data->uid) != MS_MEDIA_ERR_NONE)
344 MS_DBG_ERR("deleting invalid items in storage failed");
346 if (ms_delete_invalid_folder(scan_data->storage_id, scan_data->uid) != MS_MEDIA_ERR_NONE)
347 MS_DBG_ERR("deleting invalid folders in storage failed");
349 ms_disconnect_db(handle);
354 static int __msc_storage_scan_all(ms_comm_msg_s *scan_data, ms_user_storage_type_e storage_type)
356 int ret = MS_MEDIA_ERR_NONE;
357 sqlite3 *handle = NULL;
359 ret = ms_connect_db(&handle, scan_data->uid);
360 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_connect_db failed");
362 ms_set_db_status(MS_DB_UPDATING, storage_type);
364 ms_batch_commit_enable(false, 0);
365 ret = __msc_db_update(handle, scan_data->storage_id, scan_data);
366 ms_batch_commit_disable(scan_data->uid);
368 ms_disconnect_db(handle);
373 gpointer msc_storage_scan_thread(gpointer data)
375 int ret = MS_MEDIA_ERR_NONE;
376 ms_comm_msg_s *scan_data = NULL;
377 ms_user_storage_type_e storage_type = MS_USER_STORAGE_INTERNAL;
380 scan_data = g_async_queue_pop(storage_queue);
381 if (scan_data->pid == POWEROFF) {
382 MS_DBG_WARN("power off");
386 MS_DBG_WARN("STORAGE SCAN START [%.*s][%s]", MAX_MSG_SIZE, scan_data->msg, scan_data->storage_id);
388 if (strlen(scan_data->storage_id) == 0) {
389 MS_DBG_ERR("storage_id length is 0");
390 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
394 ret = ms_user_get_storage_type(scan_data->uid, scan_data->msg, &storage_type);
395 if (ret != MS_MEDIA_ERR_NONE) {
396 MS_DBG_ERR("ms_user_get_storage_type failed");
400 if (scan_data->msg_type == MS_MSG_STORAGE_PARTIAL) {
401 ret = __msc_storage_scan_partial(scan_data, storage_type);
402 } else if (scan_data->msg_type == MS_MSG_STORAGE_ALL || scan_data->msg_type == MS_MSG_STORAGE_INVALID) {
403 ret = __msc_storage_scan_all(scan_data, storage_type);
405 MS_DBG_ERR("Invalid request[%d]", scan_data->msg_type);
406 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
410 /* send notification */
411 ms_send_dir_update_noti(scan_data->msg, NULL, MS_ITEM_UPDATE, scan_data->pid);
413 if (ret == MS_MEDIA_ERR_SCANNER_FORCE_STOP)
414 ms_set_db_status(MS_DB_STOPPED, storage_type);
416 ms_set_db_status(MS_DB_UPDATED, storage_type);
418 if (__msc_is_power_off())
424 msc_send_result(ret, scan_data);
427 MS_DBG_WARN("STORAGE SCAN END[%d]", ret);
435 static int __msc_make_file_list(char *file_path, GPtrArray **path_array, uid_t uid)
438 char buf[MS_FILE_PATH_LEN_MAX] = {0, };
441 GPtrArray *_path_array = NULL;
442 int ret = MS_MEDIA_ERR_NONE;
444 fp = fopen(file_path, "rt");
445 MS_DBG_RETVM_IF(!fp, MS_MEDIA_ERR_INTERNAL, "fopen failed");
447 _path_array = g_ptr_array_new_with_free_func(g_free);
449 while (fgets(buf, MS_FILE_PATH_LEN_MAX, fp) != NULL) {
451 length = strlen(buf);
452 path = g_strndup(buf, length - 1);
454 /* check valid path */
455 ret = ms_check_ignore_dir(path, uid);
456 if (ret != MS_MEDIA_ERR_NONE) {
457 MS_DBG_SERR("invalide path : %s", path);
462 g_ptr_array_add(_path_array, path);
467 *path_array = _path_array;
469 return MS_MEDIA_ERR_NONE;
472 static int __msc_batch_insert(int pid, GPtrArray *path_array, uid_t uid)
474 int ret = MS_MEDIA_ERR_NONE;
475 sqlite3 *handle = NULL;
476 char *insert_path = NULL;
477 char storage_id[MS_UUID_SIZE] = {0,};
482 ret = ms_connect_db(&handle, uid);
483 MS_DBG_RETV_IF(ret != MS_MEDIA_ERR_NONE, MS_MEDIA_ERR_DB_INTERNAL);
485 ms_batch_commit_enable(true, pid);
487 for (i = 0; i < path_array->len; i++) {
488 insert_path = g_ptr_array_index(path_array, i);
490 memset(storage_id, 0x0, MS_UUID_SIZE);
491 if (ms_get_storage_id(handle, insert_path, storage_id, uid) != MS_MEDIA_ERR_NONE) {
492 MS_DBG_ERR("There is no storage id in media db");
496 ret = ms_insert_item_batch(handle, storage_id, insert_path, uid);
498 if (__msc_is_power_off()) {
499 ret = MS_MEDIA_ERR_SCANNER_FORCE_STOP;
504 /*call for bundle commit*/
505 ms_batch_commit_disable(uid);
506 ms_disconnect_db(handle);
513 gpointer msc_register_thread(gpointer data)
515 int ret = MS_MEDIA_ERR_NONE;
516 ms_comm_msg_s *register_data = NULL;
517 GPtrArray *path_array = NULL;
520 register_data = g_async_queue_pop(reg_queue);
522 if (register_data->pid == POWEROFF) {
523 MS_DBG_ERR("power off");
524 g_free(register_data);
528 if (register_data->msg_type == MS_MSG_BULK_INSERT) {
529 ret = __msc_make_file_list(register_data->msg, &path_array, register_data->uid);
530 if (ret == MS_MEDIA_ERR_NONE) {
531 MS_DBG_SLOG("BULK REGISTER START [%.*s]", MAX_MSG_SIZE, register_data->msg);
532 ret = __msc_batch_insert(register_data->pid, path_array, register_data->uid);
533 g_ptr_array_free(path_array, TRUE);
535 MS_DBG_WARN("BULK REGISTER END [%d]", ret);
537 MS_DBG_ERR("__msc_make_file_list failed [%d]", ret);
541 MS_DBG_ERR("invalid message type [%d]", register_data->msg_type);
542 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
548 msc_send_result(ret, register_data);
549 g_free(register_data);
555 static gpointer __msc_metadata_update_thread(gpointer data)
557 ms_comm_msg_s *scan_data = data;
558 int ret = MS_MEDIA_ERR_NONE;
559 sqlite3 *handle = NULL;
561 ret = ms_connect_db(&handle, scan_data->uid);
562 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, NULL, "ms_connect_db failed");
564 MS_DBG_INFO("META UPDATE START");
566 ret = ms_update_meta_batch(handle, scan_data->uid);
567 ms_disconnect_db(handle);
569 msc_send_result(ret, scan_data);
572 MS_DBG_INFO("META UPDATE END [%d]", ret);
577 void msc_metadata_update_thread(ms_comm_msg_s *recv_msg)
579 GThread *update_thread = g_thread_new("metadata_update_thread", __msc_metadata_update_thread, recv_msg);
580 g_thread_join(update_thread);
583 void msc_init_scanner(void)
585 if (!scan_queue) scan_queue = g_async_queue_new();
586 if (!reg_queue) reg_queue = g_async_queue_new();
587 if (!storage_queue) storage_queue = g_async_queue_new();
589 /*Init mutex variable*/
590 g_mutex_init(&scan_req_mutex);
594 void msc_deinit_scanner(void)
596 if (scan_queue) g_async_queue_unref(scan_queue);
597 if (reg_queue) g_async_queue_unref(reg_queue);
598 if (storage_queue) g_async_queue_unref(storage_queue);
600 /*Clear db mutex variable*/
601 g_mutex_clear(&scan_req_mutex);
605 int msc_push_scan_request(ms_scan_type_e scan_type, ms_comm_msg_s *recv_msg)
607 int ret = MS_MEDIA_ERR_NONE;
610 case MS_SCAN_STORAGE:
611 g_async_queue_push(storage_queue, recv_msg);
613 case MS_SCAN_DIRECTORY:
614 g_async_queue_push(scan_queue, recv_msg);
616 case MS_SCAN_REGISTER:
617 g_async_queue_push(reg_queue, recv_msg);
620 MS_DBG_ERR("invalid parameter");
621 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
628 void msc_send_power_off_request(void)
630 ms_comm_msg_s *data = NULL;
635 /*notify to scannig thread*/
636 data = g_new0(ms_comm_msg_s, 1);
638 data->pid = POWEROFF;
639 msc_push_scan_request(MS_SCAN_DIRECTORY, data);
643 /*notify to register thread*/
644 data = g_new0(ms_comm_msg_s, 1);
646 data->pid = POWEROFF;
647 msc_push_scan_request(MS_SCAN_REGISTER, data);
651 /*notify to register thread*/
652 data = g_new0(ms_comm_msg_s, 1);
654 data->pid = POWEROFF;
655 msc_push_scan_request(MS_SCAN_STORAGE, data);
659 void msc_remove_dir_scan_request(ms_comm_msg_s *recv_msg)
662 ms_comm_msg_s *msg = NULL;
663 GAsyncQueue *temp_scan_queue = NULL;
664 int queue_len = g_async_queue_length(scan_queue);
666 if (queue_len == 0) {
667 MS_DBG_ERR("Request is not stacked");
671 MS_DBG_WARN("scan_req_mutex is LOCKED");
672 g_mutex_lock(&scan_req_mutex);
674 temp_scan_queue = g_async_queue_new();
676 for (i = 0; i < queue_len; i++) {
677 /*create new queue to compare request*/
678 msg = g_async_queue_pop(scan_queue);
679 if ((g_strcmp0(msg->msg, recv_msg->msg) == 0) && (recv_msg->pid == msg->pid)) {
680 MS_DBG("Find request. Remove it");
683 g_async_queue_push(temp_scan_queue, msg);
686 g_async_queue_unref(scan_queue);
687 scan_queue = temp_scan_queue;
689 g_mutex_unlock(&scan_req_mutex);
690 MS_DBG_WARN("scan_req_mutex is UNLOCKED");