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 &&
275 scan_data->msg_type != MS_MSG_DIRECTORY_SCANNING_NON_RECURSIVE) {
276 MS_DBG_ERR("Invalid request");
277 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
281 ret = ms_connect_db(&handle, scan_data->uid);
282 if (ret != MS_MEDIA_ERR_NONE) {
283 MS_DBG_ERR("ms_connect_db failed");
287 ms_trim_dir_path(scan_data->msg);
288 is_recursive = (scan_data->msg_type == MS_MSG_DIRECTORY_SCANNING_NON_RECURSIVE) ? false : true;
290 if (g_file_test(scan_data->msg, G_FILE_TEST_IS_DIR)) {
291 if (ms_check_folder_exist(handle, scan_data->storage_id, scan_data->msg) == MS_MEDIA_ERR_NONE) {
292 MS_DBG_WARN("[%.*s] already exist", MAX_MSG_SIZE, scan_data->msg);
293 ret = __msc_directory_scan_update_and_delete(handle, scan_data, is_recursive, MS_ITEM_UPDATE);
295 MS_DBG_WARN("[%.*s] new insert path", MAX_MSG_SIZE, scan_data->msg);
296 ret = __msc_directory_scan_insert_only(handle, scan_data, is_recursive);
299 MS_DBG_WARN("[%.*s] delete path", MAX_MSG_SIZE, scan_data->msg);
300 ret = __msc_directory_scan_update_and_delete(handle, scan_data, true, MS_ITEM_DELETE);
303 ms_disconnect_db(handle);
305 if (__msc_is_power_off())
311 msc_send_result(ret, scan_data);
313 MS_DBG_INFO("DIRECTORY SCAN END [%d]", ret);
322 static int __msc_storage_scan_partial(ms_comm_msg_s *scan_data, ms_user_storage_type_e storage_type)
324 int ret = MS_MEDIA_ERR_NONE;
325 sqlite3 *handle = NULL;
327 ret = ms_connect_db(&handle, scan_data->uid);
328 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_connect_db failed");
330 ms_set_db_status(MS_DB_UPDATING, storage_type);
332 ret = ms_validity_change_all_items(handle, scan_data->storage_id, false, scan_data->uid);
333 if (ret != MS_MEDIA_ERR_NONE) {
334 MS_DBG_ERR("ms_validity_change_all_items failed");
335 ms_disconnect_db(handle);
340 ms_batch_commit_enable(false, 0);
341 ret = __msc_db_update(handle, scan_data->storage_id, scan_data);
342 ms_batch_commit_disable(scan_data->uid);
344 if (ms_delete_invalid_items(handle, scan_data->storage_id, scan_data->uid) != MS_MEDIA_ERR_NONE)
345 MS_DBG_ERR("deleting invalid items in storage failed");
347 if (ms_delete_invalid_folder(scan_data->storage_id, scan_data->uid) != MS_MEDIA_ERR_NONE)
348 MS_DBG_ERR("deleting invalid folders in storage failed");
350 ms_disconnect_db(handle);
355 static int __msc_storage_scan_all(ms_comm_msg_s *scan_data, ms_user_storage_type_e storage_type)
357 int ret = MS_MEDIA_ERR_NONE;
358 sqlite3 *handle = NULL;
360 ret = ms_connect_db(&handle, scan_data->uid);
361 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_connect_db failed");
363 ms_set_db_status(MS_DB_UPDATING, storage_type);
365 ms_batch_commit_enable(false, 0);
366 ret = __msc_db_update(handle, scan_data->storage_id, scan_data);
367 ms_batch_commit_disable(scan_data->uid);
369 ms_disconnect_db(handle);
374 gpointer msc_storage_scan_thread(gpointer data)
376 int ret = MS_MEDIA_ERR_NONE;
377 ms_comm_msg_s *scan_data = NULL;
378 ms_user_storage_type_e storage_type = MS_USER_STORAGE_INTERNAL;
381 scan_data = g_async_queue_pop(storage_queue);
382 if (scan_data->pid == POWEROFF) {
383 MS_DBG_WARN("power off");
387 MS_DBG_WARN("STORAGE SCAN START [%.*s][%s]", MAX_MSG_SIZE, scan_data->msg, scan_data->storage_id);
389 if (strlen(scan_data->storage_id) == 0) {
390 MS_DBG_ERR("storage_id length is 0");
391 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
395 ret = ms_user_get_storage_type(scan_data->uid, scan_data->msg, &storage_type);
396 if (ret != MS_MEDIA_ERR_NONE) {
397 MS_DBG_ERR("ms_user_get_storage_type failed");
401 if (scan_data->msg_type == MS_MSG_STORAGE_PARTIAL) {
402 ret = __msc_storage_scan_partial(scan_data, storage_type);
403 } else if (scan_data->msg_type == MS_MSG_STORAGE_ALL || scan_data->msg_type == MS_MSG_STORAGE_INVALID) {
404 ret = __msc_storage_scan_all(scan_data, storage_type);
406 MS_DBG_ERR("Invalid request[%d]", scan_data->msg_type);
407 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
411 /* send notification */
412 ms_send_dir_update_noti(scan_data->msg, NULL, MS_ITEM_UPDATE, scan_data->pid);
414 if (ret == MS_MEDIA_ERR_SCANNER_FORCE_STOP)
415 ms_set_db_status(MS_DB_STOPPED, storage_type);
417 ms_set_db_status(MS_DB_UPDATED, storage_type);
419 if (__msc_is_power_off())
425 msc_send_result(ret, scan_data);
428 MS_DBG_WARN("STORAGE SCAN END[%d]", ret);
436 static int __msc_make_file_list(char *file_path, GPtrArray **path_array, uid_t uid)
439 char buf[MS_FILE_PATH_LEN_MAX] = {0, };
442 GPtrArray *_path_array = NULL;
443 int ret = MS_MEDIA_ERR_NONE;
445 fp = fopen(file_path, "rt");
446 MS_DBG_RETVM_IF(!fp, MS_MEDIA_ERR_INTERNAL, "fopen failed");
448 _path_array = g_ptr_array_new_with_free_func(g_free);
450 while (fgets(buf, MS_FILE_PATH_LEN_MAX, fp) != NULL) {
452 length = strlen(buf);
453 path = g_strndup(buf, length - 1);
455 /* check valid path */
456 ret = ms_check_ignore_dir(path, uid);
457 if (ret != MS_MEDIA_ERR_NONE) {
458 MS_DBG_SERR("invalide path : %s", path);
463 g_ptr_array_add(_path_array, path);
468 *path_array = _path_array;
470 return MS_MEDIA_ERR_NONE;
473 static int __msc_batch_insert(int pid, GPtrArray *path_array, uid_t uid)
475 int ret = MS_MEDIA_ERR_NONE;
476 sqlite3 *handle = NULL;
477 char *insert_path = NULL;
478 char storage_id[MS_UUID_SIZE] = {0,};
483 ret = ms_connect_db(&handle, uid);
484 MS_DBG_RETV_IF(ret != MS_MEDIA_ERR_NONE, MS_MEDIA_ERR_DB_INTERNAL);
486 ms_batch_commit_enable(true, pid);
488 for (i = 0; i < path_array->len; i++) {
489 insert_path = g_ptr_array_index(path_array, i);
491 memset(storage_id, 0x0, MS_UUID_SIZE);
492 if (ms_get_storage_id(handle, insert_path, storage_id, uid) != MS_MEDIA_ERR_NONE) {
493 MS_DBG_ERR("There is no storage id in media db");
497 ret = ms_insert_item_batch(handle, storage_id, insert_path, uid);
499 if (__msc_is_power_off()) {
500 ret = MS_MEDIA_ERR_SCANNER_FORCE_STOP;
505 /*call for bundle commit*/
506 ms_batch_commit_disable(uid);
507 ms_disconnect_db(handle);
514 gpointer msc_register_thread(gpointer data)
516 int ret = MS_MEDIA_ERR_NONE;
517 ms_comm_msg_s *register_data = NULL;
518 GPtrArray *path_array = NULL;
521 register_data = g_async_queue_pop(reg_queue);
523 if (register_data->pid == POWEROFF) {
524 MS_DBG_ERR("power off");
525 g_free(register_data);
529 if (register_data->msg_type == MS_MSG_BULK_INSERT) {
530 ret = __msc_make_file_list(register_data->msg, &path_array, register_data->uid);
531 if (ret == MS_MEDIA_ERR_NONE) {
532 MS_DBG_SLOG("BULK REGISTER START [%.*s]", MAX_MSG_SIZE, register_data->msg);
533 ret = __msc_batch_insert(register_data->pid, path_array, register_data->uid);
534 g_ptr_array_free(path_array, TRUE);
536 MS_DBG_WARN("BULK REGISTER END [%d]", ret);
538 MS_DBG_ERR("__msc_make_file_list failed [%d]", ret);
542 MS_DBG_ERR("invalid message type [%d]", register_data->msg_type);
543 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
549 msc_send_result(ret, register_data);
550 g_free(register_data);
556 static gpointer __msc_metadata_update_thread(gpointer data)
558 ms_comm_msg_s *scan_data = data;
559 int ret = MS_MEDIA_ERR_NONE;
560 sqlite3 *handle = NULL;
562 ret = ms_connect_db(&handle, scan_data->uid);
563 MS_DBG_RETVM_IF(ret != MS_MEDIA_ERR_NONE, NULL, "ms_connect_db failed");
565 MS_DBG_INFO("META UPDATE START");
567 ret = ms_update_meta_batch(handle, scan_data->uid);
568 ms_disconnect_db(handle);
570 msc_send_result(ret, scan_data);
573 MS_DBG_INFO("META UPDATE END [%d]", ret);
578 void msc_metadata_update_thread(ms_comm_msg_s *recv_msg)
580 GThread *update_thread = g_thread_new("metadata_update_thread", __msc_metadata_update_thread, recv_msg);
581 g_thread_join(update_thread);
584 void msc_init_scanner(void)
586 if (!scan_queue) scan_queue = g_async_queue_new();
587 if (!reg_queue) reg_queue = g_async_queue_new();
588 if (!storage_queue) storage_queue = g_async_queue_new();
590 /*Init mutex variable*/
591 g_mutex_init(&scan_req_mutex);
595 void msc_deinit_scanner(void)
597 if (scan_queue) g_async_queue_unref(scan_queue);
598 if (reg_queue) g_async_queue_unref(reg_queue);
599 if (storage_queue) g_async_queue_unref(storage_queue);
601 /*Clear db mutex variable*/
602 g_mutex_clear(&scan_req_mutex);
606 int msc_push_scan_request(ms_scan_type_e scan_type, ms_comm_msg_s *recv_msg)
608 int ret = MS_MEDIA_ERR_NONE;
611 case MS_SCAN_STORAGE:
612 g_async_queue_push(storage_queue, recv_msg);
614 case MS_SCAN_DIRECTORY:
615 g_async_queue_push(scan_queue, recv_msg);
617 case MS_SCAN_REGISTER:
618 g_async_queue_push(reg_queue, recv_msg);
621 MS_DBG_ERR("invalid parameter");
622 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
629 void msc_send_power_off_request(void)
631 ms_comm_msg_s *data = NULL;
636 /*notify to scannig thread*/
637 data = g_new0(ms_comm_msg_s, 1);
639 data->pid = POWEROFF;
640 msc_push_scan_request(MS_SCAN_DIRECTORY, data);
644 /*notify to register thread*/
645 data = g_new0(ms_comm_msg_s, 1);
647 data->pid = POWEROFF;
648 msc_push_scan_request(MS_SCAN_REGISTER, data);
652 /*notify to register thread*/
653 data = g_new0(ms_comm_msg_s, 1);
655 data->pid = POWEROFF;
656 msc_push_scan_request(MS_SCAN_STORAGE, data);
660 void msc_remove_dir_scan_request(ms_comm_msg_s *recv_msg)
663 ms_comm_msg_s *msg = NULL;
664 GAsyncQueue *temp_scan_queue = NULL;
665 int queue_len = g_async_queue_length(scan_queue);
667 if (queue_len == 0) {
668 MS_DBG_ERR("Request is not stacked");
672 MS_DBG_WARN("scan_req_mutex is LOCKED");
673 g_mutex_lock(&scan_req_mutex);
675 temp_scan_queue = g_async_queue_new();
677 for (i = 0; i < queue_len; i++) {
678 /*create new queue to compare request*/
679 msg = g_async_queue_pop(scan_queue);
680 if ((g_strcmp0(msg->msg, recv_msg->msg) == 0) && (recv_msg->pid == msg->pid)) {
681 MS_DBG("Find request. Remove it");
684 g_async_queue_push(temp_scan_queue, msg);
687 g_async_queue_unref(scan_queue);
688 scan_queue = temp_scan_queue;
690 g_mutex_unlock(&scan_req_mutex);
691 MS_DBG_WARN("scan_req_mutex is UNLOCKED");