Fix batch insert error
[platform/core/multimedia/media-server.git] / lib / media-util-register.c
1 /*
2  * Media Utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <unistd.h>
21 #include <sys/syscall.h>
22 #include <glib.h>
23
24 #include "media-util-dbg.h"
25 #include "media-util-register.h"
26 #include "media-util-err.h"
27 #include "media-util-user.h"
28 #include "media-util-ipc.h"
29
30 static GMutex scan_req_mutex;
31
32 typedef struct media_scan_data {
33         GIOChannel *channel;
34         scan_complete_cb user_callback;
35         int pid;
36         guint source_id;
37         char *req_path;
38         void *user_data;
39 } media_scan_data;
40
41 static GSList *req_list;
42
43 static int __check_dir_path(const char *dir_path, uid_t uid)
44 {
45         MSAPI_RETVM_IF(!ms_user_is_valid_path(uid, dir_path), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
46
47         /* dir_path can be a deleted path. */
48         if (g_file_test(dir_path, G_FILE_TEST_EXISTS)) {
49                 /* Check only exist */
50                 MSAPI_RETVM_IF(!g_file_test(dir_path, G_FILE_TEST_IS_DIR), MS_MEDIA_ERR_INVALID_PARAMETER, "Not a directory");
51         }
52
53         return MS_MEDIA_ERR_NONE;
54 }
55
56 static gint __find_req_item(gconstpointer data, gconstpointer compare)
57 {
58         return g_strcmp0(((media_scan_data *)data)->req_path, (const char *)compare);
59 }
60
61 /* receive message from media-server[function : ms_receive_message_from_scanner] */
62 static gboolean __read_socket(GIOChannel *channel, GIOCondition condition, gpointer data)
63 {
64         ms_comm_msg_s recv_msg = {0, };
65         media_request_result_s req_result = {0, };
66         int sockfd = -1;
67         media_scan_data *req_data = NULL;
68         GSList *found = NULL;
69
70         sockfd = g_io_channel_unix_get_fd(channel);
71         if (sockfd < 0) {
72                 MSAPI_DBG("sock fd is invalid!");
73                 return G_SOURCE_REMOVE;
74         }
75
76         if (read(sockfd, &recv_msg, sizeof(ms_comm_msg_s)) < 0) {
77                 MSAPI_DBG_STRERROR("recv failed");
78                 return G_SOURCE_REMOVE;
79         }
80
81         MSAPI_RETVM_IF(strlen(recv_msg.msg) == 0 || strlen(recv_msg.msg) >= MAX_MSG_SIZE, G_SOURCE_REMOVE, "Invalid msg");
82
83         switch (recv_msg.msg_type) {
84         case MS_MSG_SCANNER_RESULT:
85                 req_result.request_type = MEDIA_DIRECTORY_SCAN;
86                 break;
87         case MS_MSG_SCANNER_BULK_RESULT:
88                 req_result.request_type = MEDIA_FILES_REGISTER;
89                 break;
90         case MS_MSG_SCANNER_COMPLETE:
91                 req_result.request_type = MEDIA_REQUEST_SCAN_COMPLETE;
92                 break;
93         case MS_MSG_SCANNER_PARTIAL:
94                 req_result.request_type = MEDIA_REQUEST_SCAN_PARTIAL;
95                 break;
96         case MS_MSG_RECURSIVE_START:
97                 req_result.request_type = MEDIA_RECURSIVE_START;
98                 break;
99         case MS_MSG_EXTRACTOR_COMPLETE:
100                 req_result.request_type = MEDIA_REQUEST_EXTRACT_COMPLETE;
101                 break;
102         default:
103                 MSAPI_DBG("Invalid msg_type[%d]", recv_msg.msg_type);
104                 return G_SOURCE_REMOVE;
105         }
106
107
108         MSAPI_DBG_SLOG("complete_path :%s", recv_msg.msg);
109         MSAPI_DBG("pid[%d] result[%d] request_type[%d]", recv_msg.pid, recv_msg.result, req_result.request_type);
110
111         /*NEED MUTEX*/
112         g_mutex_lock(&scan_req_mutex);
113
114         found = g_slist_find_custom(req_list, recv_msg.msg, __find_req_item);
115         if (!found) {
116                 g_mutex_unlock(&scan_req_mutex);
117                 MSAPI_DBG("Not in scan queue :%s", recv_msg.msg);
118                 return G_SOURCE_REMOVE;
119         }
120
121         req_data = (media_scan_data *)found->data;
122
123         req_result.complete_path = recv_msg.msg;
124         req_result.pid = recv_msg.pid;
125         req_result.result = recv_msg.result;
126
127         if (recv_msg.msg_type != MS_MSG_SCANNER_COMPLETE &&
128                 recv_msg.msg_type != MS_MSG_SCANNER_PARTIAL &&
129                 recv_msg.msg_type != MS_MSG_RECURSIVE_START) {
130
131                 (req_data->user_callback)(&req_result, req_data->user_data);
132                 g_free(req_data->req_path);
133                 g_free(req_data);
134                 req_list = g_slist_delete_link(req_list, found);
135
136                 g_mutex_unlock(&scan_req_mutex);
137
138                 MSAPI_DBG("REMOVE OK");
139
140                 return G_SOURCE_REMOVE;
141         }
142
143         /*call user define function. Scanner V2 case only*/
144         (req_data->user_callback)(&req_result, req_data->user_data);
145         g_mutex_unlock(&scan_req_mutex);
146
147         return G_SOURCE_CONTINUE;
148 }
149
150 static void __add_request(media_scan_data *scan_data)
151 {
152         /* NEED MUTEX */
153         g_mutex_lock(&scan_req_mutex);
154
155         req_list = g_slist_append(req_list, scan_data);
156
157         g_mutex_unlock(&scan_req_mutex);
158 }
159
160 static int __remove_request(const char *req_path)
161 {
162         media_scan_data *req_data = NULL;
163         media_request_result_s req_result;
164         GSList *found = NULL;
165
166          /*NEED MUTEX*/
167         g_mutex_lock(&scan_req_mutex);
168
169         found = g_slist_find_custom(req_list, req_path, __find_req_item);
170         if (!found) {
171                 MSAPI_DBG("Not in scan queue :%s", req_path);
172                 g_mutex_unlock(&scan_req_mutex);
173                 return MS_MEDIA_ERR_INVALID_PARAMETER;
174         }
175
176         req_data = (media_scan_data *)found->data;
177
178         req_result.pid = -1;
179         req_result.result = MS_MEDIA_ERR_NONE;
180         req_result.complete_path = (char *)req_path;
181         req_result.request_type = MEDIA_FILES_REGISTER;
182
183         /*call user define function*/
184         MSAPI_DBG("Call Cancel Callback");
185         (req_data->user_callback)(&req_result, req_data->user_data);
186
187         g_source_remove(req_data->source_id);
188
189         g_free(req_data->req_path);
190         g_free(req_data);
191         req_list = g_slist_delete_link(req_list, found);
192
193         MSAPI_DBG("CANCEL OK");
194
195         g_mutex_unlock(&scan_req_mutex);
196
197         return MS_MEDIA_ERR_NONE;
198 }
199
200 static void __attach_callback(const char *req_path, int *sockfd, scan_complete_cb user_callback, void *user_data)
201 {
202         GIOChannel *channel = NULL;
203         media_scan_data *data = NULL;
204         guint source_id = 0;
205
206         data = g_new0(media_scan_data, 1);
207         /* Create new channel to watch socket */
208         channel = g_io_channel_unix_new(*sockfd);
209         g_io_channel_set_close_on_unref(channel, TRUE);
210         source_id = g_io_add_watch(channel, G_IO_IN, __read_socket, NULL);
211         g_io_channel_unref(channel);
212
213         data->user_callback = user_callback;
214         data->user_data = user_data;
215         data->req_path = g_strdup(req_path);
216         data->channel = channel;
217         data->source_id = source_id;
218
219         __add_request(data);
220 }
221
222 static int __media_db_request_update_async(ms_msg_type_e msg_type,
223                                                                                         const char *storage_id,
224                                                                                         const char *path,
225                                                                                         scan_complete_cb user_callback,
226                                                                                         void *user_data,
227                                                                                         uid_t uid)
228 {
229         int ret = MS_MEDIA_ERR_NONE;
230         int sockfd = -1;
231         ms_comm_msg_s send_msg = { 0, };
232         g_autofree gchar *request_path = NULL;
233
234         MSAPI_RETVM_IF(!path || strlen(path) == 0, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
235
236         request_path = g_canonicalize_filename(path, NULL);
237         MSAPI_DBG_SLOG("trimmed path[%s]", request_path);
238
239         send_msg.msg_type = msg_type;
240         send_msg.pid = syscall(__NR_getpid);
241         send_msg.uid = uid;
242         if (g_strlcpy(send_msg.msg, request_path, sizeof(send_msg.msg)) >= MAX_MSG_SIZE) {
243                 MSAPI_DBG_ERR("path exceeds MAX_MSG_SIZE");
244                 return MS_MEDIA_ERR_INVALID_PARAMETER;
245         }
246         if (g_strlcpy(send_msg.storage_id, storage_id, sizeof(send_msg.storage_id)) >= MS_UUID_SIZE) {
247                 MSAPI_DBG_ERR("storage_id exceeds MS_UUID_SIZE");
248                 return MS_MEDIA_ERR_INVALID_PARAMETER;
249         }
250
251         /*Create Socket*/
252         ret = ms_ipc_create_client_socket(0, &sockfd);
253         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_ipc_create_client_socket failed[%d]", ret);
254
255         ret = ms_ipc_send_msg_to_server_tcp(sockfd, MS_SCANNER_PORT, &send_msg, NULL);
256         if (ret != MS_MEDIA_ERR_NONE) {
257                 MSAPI_DBG_ERR("ms_ipc_send_msg_to_server failed : %d", ret);
258                 close(sockfd);
259                 return ret;
260         }
261
262         __attach_callback(request_path, &sockfd, user_callback, user_data);
263
264         return ret;
265 }
266
267 static int __media_db_request_update_cancel(ms_msg_type_e msg_type, const char *path)
268 {
269         int ret = MS_MEDIA_ERR_NONE;
270         int sockfd = -1;
271         ms_comm_msg_s send_msg = { 0, };
272         g_autofree gchar *request_path = NULL;
273
274         MSAPI_RETVM_IF(!path || strlen(path) == 0, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
275
276         request_path = g_canonicalize_filename(path, NULL);
277         MSAPI_DBG("REQUEST CANCEL DIRECTORY SCANNING[%s]", request_path);
278
279         send_msg.msg_type = msg_type;
280         send_msg.pid = syscall(__NR_getpid);
281         if (g_strlcpy(send_msg.msg, request_path, sizeof(send_msg.msg)) >= MAX_MSG_SIZE) {
282                 MSAPI_DBG_ERR("path exceeds MAX_MSG_SIZE");
283                 return MS_MEDIA_ERR_INVALID_PARAMETER;
284         }
285
286         /*Create Socket*/
287         ret = ms_ipc_create_client_socket(0, &sockfd);
288         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_ipc_create_client_socket failed[%d]", ret);
289
290         ret = ms_ipc_send_msg_to_server_tcp(sockfd, MS_SCANNER_PORT, &send_msg, NULL);
291         close(sockfd);
292         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_ipc_send_msg_to_server_tcp failed[%d]", ret);
293
294         return __remove_request(request_path);
295 }
296
297 int media_directory_scanning_async(const char *directory_path,
298                                                                         const char *storage_id,
299                                                                         bool recursive_on,
300                                                                         scan_complete_cb user_callback,
301                                                                         void *user_data,
302                                                                         uid_t uid)
303 {
304         int ret = MS_MEDIA_ERR_NONE;
305
306         ret = __check_dir_path(directory_path, uid);
307         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "Invalid path");
308
309         if (recursive_on)
310                 ret = __media_db_request_update_async(MS_MSG_DIRECTORY_SCANNING, storage_id, directory_path, user_callback, user_data, uid);
311         else
312                 ret = __media_db_request_update_async(MS_MSG_DIRECTORY_SCANNING_NON_RECURSIVE, storage_id, directory_path, user_callback, user_data, uid);
313
314         return ret;
315 }
316
317 int media_directory_scanning_cancel(const char *directory_path, uid_t uid)
318 {
319         return __media_db_request_update_cancel(MS_MSG_DIRECTORY_SCANNING_CANCEL, directory_path);
320 }
321
322 int media_files_register(const char *list_path, insert_complete_cb user_callback, void *user_data, uid_t uid)
323 {
324         return __media_db_request_update_async(MS_MSG_BULK_INSERT, NULL, list_path, user_callback, user_data, uid);
325 }