Fix TV build error
[platform/core/api/media-content.git] / src / media_content.c
1 /*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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 <media_info_private.h>
18 #include <media_util_private.h>
19 #include <mntent.h>
20 #include <tzplatform_config.h>
21
22 static sqlite3 *db_handle = NULL;
23 static int ref_count = 0;
24 static GMutex db_mutex;
25 static uid_t content_g_uid = 0;
26
27 sqlite3 * _content_get_db_handle(void)
28 {
29         return db_handle;
30 }
31
32 uid_t _content_get_uid(void)
33 {
34         return (content_g_uid == 0) ? tzplatform_getuid(TZ_USER_NAME) : content_g_uid;
35 }
36
37 int _content_query_prepare(const char *select_query, const char *condition_query, const char *option_query, sqlite3_stmt **stmt)
38 {
39         int ret = MEDIA_CONTENT_ERROR_NONE;
40         char *query = NULL;
41
42         content_retip_if_fail(select_query);
43
44         /* If 'option_query' is NULL, 'condition_query' is also NULL. */
45         if (option_query) {
46                 if (STRING_VALID(condition_query))
47                         query = sqlite3_mprintf("%s AND %s %s", select_query, condition_query, option_query);
48                 else
49                         query = sqlite3_mprintf("%s %s", select_query, option_query);
50
51         } else {
52                 query = sqlite3_mprintf("%s", select_query);
53         }
54
55         ret = _content_get_result(query, stmt);
56         SQLITE3_SAFE_FREE(query);
57
58         return ret;
59 }
60
61 int _content_get_result(const char *query, sqlite3_stmt **stmt)
62 {
63         int err = SQLITE_OK;
64
65         content_retip_if_fail(_content_get_db_handle());
66         content_retip_if_fail(query);
67
68         content_debug("Query[%s]", query);
69
70         err = sqlite3_prepare_v2(_content_get_db_handle(), query, strlen(query), stmt, NULL);
71         if (err != SQLITE_OK) {
72                 content_error("Failed to sqlite3_prepare_v2[%s]", sqlite3_errmsg(_content_get_db_handle()));
73                 if (err == SQLITE_BUSY)
74                         return MEDIA_CONTENT_ERROR_DB_BUSY;
75                 else if (err == SQLITE_PERM)
76                         return MEDIA_CONTENT_ERROR_PERMISSION_DENIED;
77                 else
78                         return MEDIA_CONTENT_ERROR_DB_FAILED;
79         }
80
81         return MEDIA_CONTENT_ERROR_NONE;
82 }
83
84 int _content_error_capi(int internal_error)
85 {
86         if (internal_error == MS_MEDIA_ERR_NONE)
87                 return MEDIA_CONTENT_ERROR_NONE;
88
89         content_error("MS Error[%d]", internal_error);
90
91         switch (internal_error) {
92         case MS_MEDIA_ERR_INVALID_PARAMETER:
93                 return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
94         case MS_MEDIA_ERR_OUT_OF_MEMORY:
95                 return MEDIA_CONTENT_ERROR_OUT_OF_MEMORY;
96         case MS_MEDIA_ERR_DB_BUSY_FAIL:
97                 return MEDIA_CONTENT_ERROR_DB_BUSY;
98         case MS_MEDIA_ERR_DB_CONSTRAINT_FAIL:
99         case MS_MEDIA_ERR_DB_NO_RECORD:
100         case MS_MEDIA_ERR_DB_CORRUPT:
101         case MS_MEDIA_ERR_DB_FULL_FAIL:
102         case MS_MEDIA_ERR_DB_RESET:
103         case MS_MEDIA_ERR_DB_INTERNAL:
104                 return MEDIA_CONTENT_ERROR_DB_FAILED;
105         case MS_MEDIA_ERR_IPC:
106                 return MEDIA_CONTENT_ERROR_NETWORK;
107         case MS_MEDIA_ERR_PERMISSION_DENIED:
108                 return MEDIA_CONTENT_ERROR_PERMISSION_DENIED;
109         case MS_MEDIA_ERR_THUMB_UNSUPPORTED:
110                 return MEDIA_CONTENT_ERROR_UNSUPPORTED_CONTENT;
111         default:
112                 return MEDIA_CONTENT_ERROR_INVALID_OPERATION;
113         }
114 }
115
116 int _content_query_sql(char *query_str)
117 {
118         return _content_error_capi(media_db_request_update_db(query_str, _content_get_uid()));
119 }
120
121 int media_content_connect(void)
122 {
123         int ret = MEDIA_CONTENT_ERROR_NONE;
124
125         g_mutex_lock(&db_mutex);
126         content_info("ref count : %d", ref_count);
127
128         if (ref_count == 0) {
129                 if (db_handle == NULL) {
130                         ret = media_db_connect(&db_handle, _content_get_uid(), false);
131                         ret = _content_error_capi(ret);
132                         if (ret == MEDIA_CONTENT_ERROR_NONE)
133                                 ref_count++;
134                 } else {
135                         content_error("Wrong DB Connection status");
136                         ret = MEDIA_CONTENT_ERROR_DB_FAILED;
137                 }
138         } else {
139                 if (db_handle != NULL) {
140                         ref_count++;
141                 } else {
142                         content_error("Wrong DB Handle status");
143                         ret = MEDIA_CONTENT_ERROR_DB_FAILED;
144                 }
145         }
146
147         content_info("ref count changed to: %d", ref_count);
148         g_mutex_unlock(&db_mutex);
149
150         return ret;
151 }
152
153 int media_content_connect_with_uid(uid_t uid)
154 {
155         content_sec_debug("media_content_connect_with_uid [%d]", uid);
156         content_g_uid = uid;
157
158         return media_content_connect();
159 }
160
161 int media_content_disconnect(void)
162 {
163         g_mutex_lock(&db_mutex);
164         content_debug("ref count : %d", ref_count);
165
166         if (db_handle && ref_count > 0) {
167                 if (--ref_count == 0) {
168                         media_db_disconnect(db_handle);
169                         db_handle = NULL;
170                 }
171         } else {
172                 content_error("Database is not connected");
173                 g_mutex_unlock(&db_mutex);
174                 return MEDIA_CONTENT_ERROR_DB_FAILED;
175         }
176
177         g_mutex_unlock(&db_mutex);
178
179         content_info("ref count changed to: %d", ref_count);
180
181         return MEDIA_CONTENT_ERROR_NONE;
182 }
183
184 int media_content_scan_file(const char *path)
185 {
186         int ret = MEDIA_CONTENT_ERROR_NONE;
187         g_autofree gchar *folder_path = NULL;
188         char storage_id[MEDIA_CONTENT_UUID_SIZE+1] = {0,};
189
190         content_retip_if_fail(STRING_VALID(path));
191
192         content_sec_debug("Path : %s", path);
193
194         content_retvm_if(_media_util_is_ignorable_file(path), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid path");
195
196         ret = media_svc_get_storage_id(_content_get_db_handle(), path, storage_id, _content_get_uid());
197         if (ret != MS_MEDIA_ERR_NONE) {
198                 content_error("media_svc_get_storage_id failed : %d", ret);
199                 return _content_error_capi(ret);
200         }
201
202         ret = _media_util_check_file_exist(path);
203         content_retvm_if(ret == MEDIA_CONTENT_ERROR_PERMISSION_DENIED, ret, "Permission denied");
204         if (ret != MEDIA_CONTENT_ERROR_NONE) {
205                 content_debug("No file. Try to delete from DB");
206                 ret = media_svc_delete_item_by_path(_content_get_db_handle(), storage_id, path, _content_get_uid());
207                 content_retvm_if(ret == MS_MEDIA_ERR_DB_NO_RECORD, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid path");
208                 return _content_error_capi(ret);
209         }
210
211         folder_path = g_path_get_dirname(path);
212         content_retv_if(_media_util_is_ignorable_dir(folder_path), MEDIA_CONTENT_ERROR_INVALID_PARAMETER);
213         content_retvm_if(!_media_util_check_support_media_type(path), MEDIA_CONTENT_ERROR_NOT_SUPPORTED, "Unsupported type");
214
215         ret = media_svc_check_item_exist_by_path(_content_get_db_handle(), storage_id, path);
216         if (ret == MS_MEDIA_ERR_NONE) {
217                 /* Refresh */
218                 ret = media_svc_refresh_item(_content_get_db_handle(), false, storage_id, path, _content_get_uid());
219                 content_retvm_if(ret != MS_MEDIA_ERR_NONE, _content_error_capi(ret), "Refresh failed");
220                 return MEDIA_CONTENT_ERROR_NONE;
221         }
222
223         if (ret == MS_MEDIA_ERR_DB_NO_RECORD) {
224                 /* Insert */
225                 ret = media_svc_insert_item_immediately(_content_get_db_handle(), storage_id, path, _content_get_uid());
226                 content_retvm_if(ret == MS_MEDIA_ERR_DB_CONSTRAINT_FAIL, MEDIA_CONTENT_ERROR_NONE, "[No error] Already inserted");
227                 content_retvm_if(ret != MS_MEDIA_ERR_NONE, _content_error_capi(ret), "Insertion failed");
228                 return MEDIA_CONTENT_ERROR_NONE;
229         }
230
231         content_error("media_svc_check_item_exist_by_path failed : %d", ret);
232
233         return _content_error_capi(ret);
234 }
235
236 static void __media_content_scan_cb(media_request_result_s *result, void *user_data)
237 {
238         int err = _content_error_capi(result->result);
239         media_content_scan_cb_data *cb_data = user_data;
240
241 #ifdef _USE_TVPD_MODE
242         if (result->request_type != MEDIA_REQUEST_SCAN_COMPLETE &&
243                 result->request_type != MEDIA_REQUEST_SCAN_PARTIAL &&
244                 result->request_type != MEDIA_RECURSIVE_START) {
245                 if (cb_data && cb_data->callback) {
246                         content_debug("begin:User callback is being called now, result=%d", err);
247                         cb_data->callback(err, cb_data->user_data);
248                         content_debug("end:User callback is being called now, result=%d", err);
249                 }
250
251                 g_free(cb_data);
252         }
253 #else
254         if (cb_data && cb_data->callback) {
255                 content_debug("User callback is being called now");
256                 cb_data->callback(err, cb_data->user_data);
257         }
258
259         g_free(cb_data);
260 #endif
261 }
262
263 #ifdef _USE_TVPD_MODE
264 static void __media_content_scan_cb_v2(media_request_result_s* result, void *user_data)
265 {
266         int err = _content_error_capi(result->result);
267         media_content_scan_cb_data_v2 *cb_data = user_data;
268         media_content_complete_phase_e complete_phase = -1;
269         if (!cb_data)
270                 content_debug("cb_data is NULL");
271
272         content_debug("result is %d", err);
273
274         if (result->request_type == MEDIA_REQUEST_SCAN_PARTIAL)
275                 complete_phase = MEDIA_CONTENT_SCAN_PARTIAL_COMPLETE;
276         else if (result->request_type == MEDIA_REQUEST_SCAN_COMPLETE)
277                 complete_phase = MEDIA_CONTENT_SCAN_COMPLETE;
278         else if (result->request_type == MEDIA_REQUEST_EXTRACT_COMPLETE)
279                 complete_phase = MEDIA_CONTENT_EXTRACT_COMPLETE;
280         else if (result->request_type == MEDIA_RECURSIVE_START)
281                 complete_phase = MEDIA_CONTENT_RECURSIVE_START;
282
283         if (cb_data && cb_data->callback)
284                 cb_data->callback(err, complete_phase, cb_data->user_data);
285         else
286                 content_debug("run error");
287
288         if ((result->request_type != MEDIA_REQUEST_SCAN_COMPLETE) &&
289         (result->request_type != MEDIA_REQUEST_SCAN_PARTIAL) &&
290         (result->request_type != MEDIA_RECURSIVE_START))
291                 g_free(cb_data);
292 }
293 #endif
294
295 int media_content_scan_folder(const char *path, bool is_recursive, media_scan_completed_cb callback, void *user_data)
296 {
297         int ret = MEDIA_CONTENT_ERROR_NONE;
298         char storage_id[MEDIA_CONTENT_UUID_SIZE+1] = {0, };
299
300         content_retip_if_fail(STRING_VALID(path));
301         content_retip_if_fail(callback);
302
303         ret = _media_content_check_dir(path);
304         content_retvm_if(ret == MEDIA_CONTENT_ERROR_PERMISSION_DENIED, ret, "Permission denied");
305
306         content_sec_debug("Path : %s", path);
307
308         if (ret == MEDIA_CONTENT_ERROR_NONE) {
309                 /* If directory exist check that's ignore directory or not*/
310                 content_retvm_if(_media_util_is_ignorable_dir(path), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid path");
311         } else {
312                 /* This means this folder has to be deleted */
313                 /* Or, it is real invalid path.. check storage type */
314                 content_retvm_if(!ms_user_is_valid_path(_content_get_uid(), path), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid path");
315
316                 content_debug("No directory. Try to remove from DB");
317         }
318
319         ret = media_svc_get_storage_id(_content_get_db_handle(), path, storage_id, _content_get_uid());
320         content_retvm_if(ret != MS_MEDIA_ERR_NONE, _content_error_capi(ret), "Failed to get storage id");
321
322         media_content_scan_cb_data *cb_data = g_new0(media_content_scan_cb_data, 1);
323
324         cb_data->callback = callback;
325         cb_data->user_data = user_data;
326
327         ret = media_directory_scanning_async(path, storage_id, is_recursive, __media_content_scan_cb, cb_data, _content_get_uid());
328         if (ret != MS_MEDIA_ERR_NONE) {
329                 content_error("media_directory_scanning_async failed : %d", ret);
330                 g_free(cb_data);
331         }
332
333         return _content_error_capi(ret);
334 }
335
336 #ifdef _USE_TVPD_MODE
337 bool _is_mounted(const char *dir_path)
338 {
339         bool ret = false;
340         char mount_path[MAX_PATH_LEN] = {0,};
341         char root_path[MAX_PATH_LEN] = {0,};
342         struct mntent *mnt;
343         const char *table = "/etc/mtab";
344         FILE *fp;
345
346         snprintf(root_path, MAX_PATH_LEN, "%s%s", tzplatform_getenv(TZ_SYS_STORAGE), "/USBDrive");
347         if (!g_str_has_prefix(dir_path, root_path))
348                 return true;
349
350         char *p = strstr(dir_path + strlen(root_path), "/");
351         if(p && p - dir_path < MAX_PATH_LEN)
352                 strncpy(mount_path, dir_path, p - dir_path);
353         else
354                 snprintf(mount_path, MAX_PATH_LEN, "%s", dir_path);
355
356         fp = setmntent(table, "r");
357         if (!fp) {
358                 content_error("open /etc/mtab failed");
359                 return false;
360         }
361         while ((mnt = getmntent(fp))) {
362                 if (!strncmp(mnt->mnt_dir, mount_path, strlen(mount_path))) {
363                         ret = true;
364                         break;
365                 }
366         }
367         endmntent(fp);
368
369         content_error("[NO ERROR] dir_path[%s] mount_path[%s] ret[%d]", dir_path, mount_path, ret);
370         return ret;
371 }
372
373 int media_content_scan_folder_v2(const char *path, bool is_recursive, media_scan_completed_cb_v2 callback, void *user_data)
374 {
375         int ret = MEDIA_CONTENT_ERROR_NONE;
376         char storage_id[MEDIA_CONTENT_UUID_SIZE+1] = {0, };
377
378         content_retip_if_fail(STRING_VALID(path));
379         content_retip_if_fail(callback);
380
381         content_sec_debug("Path : %s", path);
382
383         content_retvm_if(!_is_mounted(path), MEDIA_CONTENT_ERROR_PERMISSION_DENIED, "path is not mounted");
384         content_retvm_if(_media_util_is_ignorable_dir(path), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid folder path");
385
386         ret = _media_content_check_dir(path);
387         content_retvm_if(ret == MEDIA_CONTENT_ERROR_PERMISSION_DENIED, ret, "Permission Denied");
388         content_retvm_if(ret == MEDIA_CONTENT_ERROR_INVALID_PARAMETER, ret, "invalid path[%s]", path);
389
390         media_content_scan_cb_data_v2* cb_data = NULL;
391         cb_data = g_new0(media_content_scan_cb_data_v2, 1);
392
393         cb_data->callback = callback;
394         cb_data->user_data = user_data;
395
396         ret = media_svc_get_storage_id(_content_get_db_handle(), path, storage_id, _content_get_uid());
397         /*FIX ME. need to check ret value?*/
398
399         ret = media_directory_scanning_async(path, storage_id, is_recursive, __media_content_scan_cb_v2, cb_data, _content_get_uid());
400         if (ret != MS_MEDIA_ERR_NONE) {
401                 content_error("media_directory_scanning_async failed : %d", ret);
402                 g_free(cb_data);
403         }
404
405         return _content_error_capi(ret);
406 }
407 #endif
408
409 int media_content_cancel_scan_folder(const char *path)
410 {
411         int ret = MEDIA_CONTENT_ERROR_NONE;
412
413         content_retip_if_fail(STRING_VALID(path));
414
415         ret = media_directory_scanning_cancel(path, _content_get_uid());
416         if (ret != MS_MEDIA_ERR_NONE)
417                 content_error("media_directory_scanning_cancel failed : %d", ret);
418
419         return _content_error_capi(ret);
420 }
421
422 void _media_content_db_update_noti_cb(int pid,
423                                                                         media_item_type_e item,
424                                                                         media_item_update_type_e update_type,
425                                                                         char* path,
426                                                                         char* uuid,
427                                                                         int content_type,
428                                                                         char *mime_type,
429                                                                         void *user_data)
430 {
431         media_noti_cb_s *_noti_info = (media_noti_cb_s *)user_data;
432
433         if (_noti_info && _noti_info->update_noti_cb)
434                 _noti_info->update_noti_cb(
435                                         MEDIA_CONTENT_ERROR_NONE,
436                                         pid,
437                                         item,
438                                         update_type,
439                                         content_type,
440                                         uuid,
441                                         path,
442                                         mime_type,
443                                         _noti_info->user_data);
444 }
445
446 int media_content_add_db_updated_cb(media_content_db_update_cb callback, void *user_data, media_content_noti_h *noti_handle)
447 {
448         int ret = MEDIA_CONTENT_ERROR_NONE;
449         media_noti_cb_s *noti_info = NULL;
450
451         content_retip_if_fail(callback);
452         content_retip_if_fail(noti_handle);
453
454         noti_info = g_new0(media_noti_cb_s, 1);
455
456         noti_info->update_noti_cb = callback;
457         noti_info->user_data = user_data;
458
459         ret = media_db_update_subscribe((MediaNotiHandle*)noti_handle, _media_content_db_update_noti_cb, (void *)noti_info);
460         if (ret != MS_MEDIA_ERR_NONE)
461                 g_free(noti_info);
462
463         return _content_error_capi(ret);
464 }
465
466 int media_content_remove_db_updated_cb(media_content_noti_h noti_handle)
467 {
468         int ret = MEDIA_CONTENT_ERROR_NONE;
469
470         ret = media_db_update_unsubscribe((MediaNotiHandle)noti_handle);
471
472         return _content_error_capi(ret);
473 }
474
475 #ifdef _USE_TVPD_MODE
476 GMutex* _content_get_db_mutex(void)
477 {
478         return &db_mutex;
479 }
480 #endif