94bd75625dd098c2fdc8bfc878ce94212a96fb48
[platform/core/multimedia/media-server.git] / lib / media-util-db.c
1 /*
2  * Media Utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Yong Yeon Kim <yy9875.kim@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <sys/smack.h>
26
27 #include <dlfcn.h>
28
29 #include <unicode/utypes.h>
30 #include <unicode/ucol.h>
31 #include <unicode/uiter.h>
32 #include <unicode/ustring.h>
33 #include <vconf.h>
34
35 #include "media-server-ipc.h"
36 #include "media-util-dbg.h"
37 #include "media-util-internal.h"
38 #include "media-util.h"
39
40 #define BATCH_START "BEGIN"
41 #define BATCH_END "COMMIT"
42
43 static int __media_db_request_recovery(uid_t uid);
44
45 static int __media_db_busy_handler(void *pData, int count)
46 {
47         usleep(50000);
48
49         MSAPI_DBG("media_db_busy_handler called : %d", count);
50
51         return 200 - count;
52 }
53
54 /* The collating function must return an integer that is negative, zero or positive */
55 static int __media_db_collate_icu_8(void *ucol, int str1_len, const void *str1, int str2_len, const void *str2)
56 {
57         UCharIterator uiter1, uiter2;
58         UErrorCode error = U_ZERO_ERROR;
59
60         uiter_setUTF8(&uiter1, (const char *) str1, str1_len);
61         uiter_setUTF8(&uiter2, (const char *) str2, str2_len);
62
63         UCollationResult result = ucol_strcollIter((UCollator *) ucol, &uiter1, &uiter2, &error);
64         if (U_FAILURE(error)) {
65                 MSAPI_DBG_ERR("ucol_strcollIter error: %d", error);
66                 return -1;
67         }
68
69         return result;
70 }
71
72 static void __media_db_collation_cb(void* pArg, sqlite3* handle, int charset, const char* name)
73 {
74         int ret = MS_MEDIA_ERR_NONE;
75         UErrorCode status = U_ZERO_ERROR;
76         const char* locale = NULL;
77         char *lang = NULL;
78         UCollator* ucol = NULL;
79
80         if (handle == NULL || !MS_STRING_VALID(name)) {
81                 MSAPI_DBG_ERR("Input parameter is NULL");
82                 return;
83         }
84
85         if (charset == SQLITE_UTF8 && !sqlite3_stricmp(name, "localized")) {
86                 lang = vconf_get_str(VCONFKEY_LANGSET);
87                 /* get current locale */
88                 if (lang) {
89                         uloc_setDefault(lang, &status);
90                         MS_SAFE_FREE(lang);
91                 } else {
92                         MSAPI_DBG_ERR("Fail to get current language vconf");
93                         return;
94                 }
95                 locale = uloc_getDefault();
96                 if (locale == NULL) {
97                         MSAPI_DBG_ERR("Fail to get current locale");
98                         return;
99                 }
100                 MSAPI_DBG_INFO("locale : %s", locale);
101
102                 ucol = ucol_open(locale, &status);
103                 if (status == U_USING_DEFAULT_WARNING) {
104                         MSAPI_DBG("ucol_open success with default collate option");
105                 } else if (U_FAILURE(status)) {
106                         MSAPI_DBG_ERR("ucol_open fail : %d", status);
107                         return;
108                 }
109
110                 ucol_setStrength(ucol, UCOL_SECONDARY); /* NOTICE : MCD sets UCOL_PRIMARY */
111                 if (U_FAILURE(status)) {
112                         MSAPI_DBG_ERR("ucol_setStrength fail : %d", status);
113                         return;
114                 }
115
116                 ret = sqlite3_create_collation_v2(handle, name, SQLITE_UTF8, ucol, __media_db_collate_icu_8, (void *)ucol_close);
117                 if (ret != SQLITE_OK) {
118                         MSAPI_DBG_ERR("sqlite3_create_collation_v2 fail : %d", ret);
119                         ucol_close(ucol);
120                 } else {
121                         MSAPI_DBG("sqlite3_create_collation_v2 success");
122                 }
123         } else {
124                 MSAPI_DBG_ERR("No matching collator for %s", name);
125         }
126 }
127
128 static int __media_db_connect_db_with_handle(sqlite3 **db_handle, uid_t uid, bool need_write)
129 {
130         int ret = SQLITE_OK;
131         char *db_path = NULL;
132         char *sql = NULL;
133
134         ret = ms_user_get_media_db_path(uid, &db_path);
135         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, MS_MEDIA_ERR_DB_INTERNAL, "ms_user_get_media_db_path failed");
136
137         /*Connect DB*/
138         if (need_write)
139                 ret = sqlite3_open_v2(db_path, db_handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
140         else
141                 ret = sqlite3_open_v2(db_path, db_handle, SQLITE_OPEN_READONLY, NULL);
142
143         if (SQLITE_OK != ret) {
144                 MSAPI_DBG_ERR("error when db open path[%s],ret[%d]", db_path, ret);
145                 g_free(db_path);
146                 *db_handle = NULL;
147                 return MS_MEDIA_ERR_DB_INTERNAL;
148         }
149         g_free(db_path);
150
151         if (*db_handle == NULL) {
152                 MSAPI_DBG_ERR("*db_handle is NULL");
153                 return MS_MEDIA_ERR_DB_INTERNAL;
154         }
155
156         /*Register busy handler*/
157         ret = sqlite3_busy_handler(*db_handle, __media_db_busy_handler, NULL);
158         if (SQLITE_OK != ret) {
159                 if (*db_handle)
160                         MSAPI_DBG_ERR("[error when register busy handler] %s", sqlite3_errmsg(*db_handle));
161
162                 sqlite3_close_v2(*db_handle);
163                 *db_handle = NULL;
164
165                 return MS_MEDIA_ERR_DB_INTERNAL;
166         }
167
168         /*For TV internal space issue, change TRUNCATE to OFF */
169         sql = sqlite3_mprintf("%s", "PRAGMA journal_mode = OFF");
170         ret = sqlite3_exec(*db_handle, sql, NULL, NULL, NULL);
171         MS_SQL_SAFE_FREE(sql);
172         if (SQLITE_OK != ret) {
173                 if (*db_handle)
174                         MSAPI_DBG_ERR("[error when change the journal mode] %s", sqlite3_errmsg(*db_handle));
175
176                 sqlite3_close_v2(*db_handle);
177                 *db_handle = NULL;
178
179                 if (ret == SQLITE_CORRUPT) {
180                         MSAPI_DBG_ERR("MEDIA DB IS CORRUPTED");
181                         return MS_MEDIA_ERR_DB_CORRUPT;
182                 }
183
184                 return MS_MEDIA_ERR_DB_INTERNAL;
185         }
186
187         /* Set for localized collate */
188         sqlite3_collation_needed(*db_handle, NULL, __media_db_collation_cb);
189
190         return MS_MEDIA_ERR_NONE;
191 }
192
193 extern char MEDIA_IPC_PATH[][70];
194 #define MAX_RETRY_COUNT 3
195
196 static int __media_db_request_update_tcp(ms_msg_type_e msg_type, const char *request_msg, uid_t uid)
197 {
198         int ret = MS_MEDIA_ERR_NONE;
199         int sockfd = -1;
200         struct sockaddr_un serv_addr;
201         int retry_count = 0;
202
203         MSAPI_RETVM_IF(!ms_ipc_is_valid_msg(request_msg), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid request_msg");
204
205         ms_comm_msg_s send_msg;
206         memset((void *)&send_msg, 0, sizeof(ms_comm_msg_s));
207
208         send_msg.msg_type = msg_type;
209         SAFE_STRLCPY(send_msg.msg, request_msg, sizeof(send_msg.msg));
210         send_msg.uid = uid;
211
212         /*Create Socket*/
213         ret = ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sockfd);
214         MSAPI_RETV_IF(ret != MS_MEDIA_ERR_NONE, ret);
215
216         /*Set server Address*/
217         memset(&serv_addr, 0, sizeof(serv_addr));
218         serv_addr.sun_family = AF_UNIX;
219         SAFE_STRLCPY(serv_addr.sun_path, tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[MS_DB_UPDATE_PORT]), sizeof(serv_addr.sun_path));
220
221         /* Connecting to the media db server */
222         if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
223                 MSAPI_DBG_STRERROR("connect error");
224                 close(sockfd);
225                 if (errno == EACCES)
226                         return MS_MEDIA_ERR_PERMISSION_DENIED;
227                 else
228                         return MS_MEDIA_ERR_IPC;
229         }
230
231         /* Send request */
232         if (send(sockfd, &send_msg, sizeof(send_msg), 0) != sizeof(send_msg)) {
233                 MSAPI_DBG_STRERROR("send failed");
234                 close(sockfd);
235                 return MS_MEDIA_ERR_IPC;
236         }
237
238         /*Receive Response*/
239         int recv_msg_size = -1;
240         int recv_msg = -1;
241 RETRY:
242         if ((recv_msg_size = recv(sockfd, &recv_msg, sizeof(recv_msg), 0)) < 0) {
243                 MSAPI_DBG_STRERROR("recv failed");
244
245                 if (errno == EINTR || errno == EWOULDBLOCK) {
246                         if (retry_count < MAX_RETRY_COUNT) {
247                                 MSAPI_DBG_ERR("TIME OUT[%d]", retry_count);
248                                 retry_count++;
249                                 goto RETRY;
250                         }
251                 }
252                 close(sockfd);
253                 return MS_MEDIA_ERR_IPC;
254         }
255
256         MSAPI_DBG("RECEIVE OK [%d]", recv_msg);
257         ret = recv_msg;
258
259         close(sockfd);
260
261         return ret;
262 }
263
264 #define RETRY_CNT 9
265 #define SLEEP_TIME 1000 * 1000
266 static int __media_db_update_directly(sqlite3 *db_handle, const char *sql_str)
267 {
268         int ret = MS_MEDIA_ERR_NONE;
269         char *zErrMsg = NULL;
270         int retry_count = 0;
271
272 EXEC_RETRY:
273         ret = sqlite3_exec(db_handle, sql_str, NULL, NULL, &zErrMsg);
274
275         if (SQLITE_OK != ret) {
276                 MSAPI_ERR_SLOG("Error[%s],Query[%s]", zErrMsg, sql_str);
277                 MS_SQL_SAFE_FREE(zErrMsg);
278                 if (ret == SQLITE_BUSY) {
279                         ret = MS_MEDIA_ERR_DB_BUSY_FAIL;
280                 } else if (ret == SQLITE_CONSTRAINT) {
281                         ret = MS_MEDIA_ERR_DB_CONSTRAINT_FAIL;
282                 } else if (ret == SQLITE_FULL) {
283                         ret = MS_MEDIA_ERR_DB_FULL_FAIL;
284                 } else if (ret == SQLITE_LOCKED) {
285                         if (retry_count < RETRY_CNT) {
286                                 MSAPI_DBG_ERR("Locked retry[%d]", retry_count);
287                                 retry_count++;
288                                 usleep(SLEEP_TIME);
289                                 goto EXEC_RETRY;
290                         }
291                         ret = MS_MEDIA_ERR_DB_INTERNAL;
292                 } else {
293                         ret = MS_MEDIA_ERR_DB_INTERNAL;
294                 }
295         }
296
297         return ret;
298 }
299
300 int media_db_check_integrity(sqlite3 *handle)
301 {
302         MSAPI_RETVM_IF(handle == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "Handle is NULL");
303
304         int ret = 0;
305         sqlite3_stmt *stmt = NULL;
306         const char integrity_check_query[] = "PRAGMA integrity_check";
307
308         ret = sqlite3_prepare_v2(handle, integrity_check_query, strlen(integrity_check_query), &stmt, NULL);
309         if (ret != SQLITE_OK) {
310                 MSAPI_DBG_ERR("prepare error, ret = %d, error = %s", ret, sqlite3_errmsg(handle));
311                 return MS_MEDIA_ERR_DB_CORRUPT;
312         }
313
314         ret = sqlite3_step(stmt);
315         if (ret != SQLITE_ROW) {
316                 MSAPI_DBG_ERR("integrity_check failed in step");
317                 sqlite3_finalize(stmt);
318                 return MS_MEDIA_ERR_DB_CORRUPT;
319         }
320
321         char* check_result = (char*) sqlite3_column_text(stmt, 0);
322         if (check_result == NULL || strncmp(check_result, "ok", strlen(check_result))) {
323                 MSAPI_DBG_ERR("integrity_check failed - result(%s)\n", check_result);
324                 sqlite3_finalize(stmt);
325                 return MS_MEDIA_ERR_DB_CORRUPT;
326         }
327         sqlite3_finalize(stmt);
328
329         return MS_MEDIA_ERR_NONE;
330 }
331
332 int media_db_connect(sqlite3 **handle, uid_t uid, bool need_write)
333 {
334         int ret = MS_MEDIA_ERR_NONE;
335         sqlite3 * db_handle = NULL;
336         int retry_cnt = 0;
337
338         MSAPI_DBG_FUNC();
339
340 RETRY_CONN:
341         ret = __media_db_connect_db_with_handle(&db_handle, uid, need_write);
342         if (ret != MS_MEDIA_ERR_NONE) {
343                 if (ret == MS_MEDIA_ERR_DB_CORRUPT && retry_cnt == 0) {
344                         retry_cnt++;
345
346                         ret = __media_db_request_recovery(uid);
347                         if (ret == MS_MEDIA_ERR_NONE)
348                                 goto RETRY_CONN;
349                         else
350                                 return MS_MEDIA_ERR_DB_CORRUPT;
351                 } else {
352                         return ret;
353                 }
354         }
355
356         *handle = db_handle;
357         return MS_MEDIA_ERR_NONE;
358 }
359
360 void media_db_disconnect(sqlite3 *handle)
361 {
362         MSAPI_DBG_FUNC();
363
364         if (handle)
365                 sqlite3_close_v2(handle);
366 }
367
368 int media_db_request_update_db(const char *query_str, uid_t uid)
369 {
370         int ret = MS_MEDIA_ERR_NONE;
371
372         MSAPI_DBG_FUNC();
373
374         MSAPI_RETVM_IF(!MS_STRING_VALID(query_str), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
375
376         ret = __media_db_request_update_tcp(MS_MSG_DB_UPDATE, query_str, uid);
377         if (ret != MS_MEDIA_ERR_NONE)
378                 MSAPI_DBG_ERR("__media_db_request_update_tcp failed : %d", ret);
379
380         return ret;
381 }
382
383 int media_db_update_db_direct(const char *query_str, uid_t uid)
384 {
385         int ret = MS_MEDIA_ERR_NONE;
386         sqlite3 *handle = NULL;
387
388         MSAPI_DBG_FUNC();
389
390         MSAPI_RETVM_IF(!MS_STRING_VALID(query_str), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
391
392         ret = media_db_connect(&handle, uid, true);
393         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "Connect failed");
394
395         ret = __media_db_update_directly(handle, query_str);
396         if (ret != MS_MEDIA_ERR_NONE)
397                 MSAPI_DBG_ERR("Query failed");
398
399         media_db_disconnect(handle);
400
401         return ret;
402 }
403
404 int media_db_update_db(sqlite3 *handle, const char *query_str)
405 {
406         MSAPI_RETVM_IF(handle == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "Handle is NULL");
407         MSAPI_RETVM_IF(!MS_STRING_VALID(query_str), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
408
409         return __media_db_update_directly(handle, query_str);
410 }
411
412 static int __media_db_request_recovery(uid_t uid)
413 {
414         int ret = MS_MEDIA_ERR_NONE;
415         int sockfd = -1;
416         struct sockaddr_un serv_addr;
417         int retry_count = 0;
418         char *db_path = NULL;
419
420         ret = ms_user_get_media_db_path(uid, &db_path);
421         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, MS_MEDIA_ERR_INVALID_PARAMETER, "ms_user_get_media_db_path failed");
422
423         if (!ms_ipc_is_valid_msg(db_path)) {
424                 g_free(db_path);
425                 return MS_MEDIA_ERR_INVALID_PARAMETER;
426         }
427
428         ms_comm_msg_s send_msg;
429         memset((void *)&send_msg, 0, sizeof(ms_comm_msg_s));
430
431         send_msg.msg_type = MS_MSG_MEDIA_DB_MALFORMED;
432         SAFE_STRLCPY(send_msg.msg, db_path, sizeof(send_msg.msg));
433         g_free(db_path);
434         send_msg.uid = uid;
435
436         /*Create Socket*/
437         ret = ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sockfd);
438         MSAPI_RETV_IF(ret != MS_MEDIA_ERR_NONE, ret);
439
440         /*Set server Address*/
441         memset(&serv_addr, 0, sizeof(serv_addr));
442         serv_addr.sun_family = AF_UNIX;
443         /*      MSAPI_DBG_SLOG("%s", MEDIA_IPC_PATH[port]); */
444         SAFE_STRLCPY(serv_addr.sun_path, MEDIA_IPC_PATH[MS_SCANNER_PORT], sizeof(serv_addr.sun_path));
445
446         /* Connecting to the media db server */
447         if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
448                 MSAPI_DBG_STRERROR("connect error");
449                 close(sockfd);
450                 return MS_MEDIA_ERR_IPC;
451         }
452
453         /* Send request */
454         if (send(sockfd, &send_msg, sizeof(send_msg), 0) != sizeof(send_msg)) {
455                 MSAPI_DBG_STRERROR("send failed");
456                 close(sockfd);
457                 return MS_MEDIA_ERR_IPC;
458         }
459
460         /*Receive Response*/
461         int recv_msg_size = -1;
462         ms_comm_msg_s recv_msg;
463 RETRY:
464         if ((recv_msg_size = recv(sockfd, &recv_msg, sizeof(recv_msg), 0)) < 0) {
465                 MSAPI_DBG_STRERROR("recv failed");
466
467                 if (errno == EINTR || errno == EWOULDBLOCK) {
468                         if (retry_count < MAX_RETRY_COUNT) {
469                                 MSAPI_DBG_ERR("TIME OUT[%d]", retry_count);
470                                 retry_count++;
471                                 goto RETRY;
472                         }
473                 }
474                 close(sockfd);
475                 return MS_MEDIA_ERR_IPC;
476         }
477
478         MSAPI_DBG("RECEIVE OK [%d]", recv_msg.result);
479         ret = recv_msg.result;
480
481         close(sockfd);
482
483         return ret;
484 }
485
486 int media_db_get_result(sqlite3 *handle, char *sql_str, sqlite3_stmt **stmt)
487 {
488         int err = -1;
489
490         MSAPI_RETVM_IF(sql_str == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "invalid query");
491         if (handle == NULL) {
492                 MSAPI_DBG_ERR("handle is NULL");
493                 MS_SQL_SAFE_FREE(sql_str);
494                 return MS_MEDIA_ERR_INVALID_PARAMETER;
495         }
496
497         MSAPI_DBG_SLOG("[SQL query] : %s", sql_str);
498
499         err = sqlite3_prepare_v2(handle, sql_str, -1, stmt, NULL);
500         MS_SQL_SAFE_FREE(sql_str);
501
502         if (err != SQLITE_OK) {
503                 MSAPI_DBG_ERR("prepare error %d[%s]", err, sqlite3_errmsg(handle));
504                 if (err == SQLITE_CORRUPT)
505                         return MS_MEDIA_ERR_DB_CORRUPT;
506
507                 return MS_MEDIA_ERR_DB_INTERNAL;
508         }
509
510         return MS_MEDIA_ERR_NONE;
511 }