Tizen 2.1 base
[apps/home/myfiles.git] / src / common / file-operation / mf-move.c
1 /*
2  * Copyright 2013         Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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://floralicense.org/license/
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
18
19
20 #include <stdio.h>
21 #include <glib.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/time.h>
27 #include <sys/syscall.h>
28
29 #include "mf-move.h"
30 #include "mf-move-internal.h"
31 #include "mf-cancel.h"
32 #include "mf-fo-common.h"
33 #include "mf-fo-internal.h"
34 #include "mf-fo-debug.h"
35 #include "mf-callback.h"
36
37 extern int flagMsg;
38 extern pthread_mutex_t gLockMsg;
39 extern pthread_cond_t gCondMsg;
40
41 struct _mf_move_handle {
42         GList *src_items;
43         char *dst_dir;
44         mf_cancel *cancel;
45         void *u_data;
46         gboolean sync;
47
48         GMutex *lock;
49         GCond *cond;
50
51         mf_fo_msg msg;
52         mf_fo_request *req;
53         Ecore_Pipe *pipe;
54 };
55
56 static double __mf_move_get_time(void)
57 {
58         struct timeval timev;
59
60         gettimeofday(&timev, NULL);
61         return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
62 }
63
64 static void __mf_move_free_handle(struct _mf_move_handle *handle)
65 {
66         if (handle) {
67                 if (handle->lock) {
68                         g_mutex_free(handle->lock);
69                 }
70                 if (handle->cond) {
71                         g_cond_free(handle->cond);
72                 }
73                 if (handle->dst_dir) {
74                         free(handle->dst_dir);
75                 }
76                 if (handle->src_items) {
77                         g_list_foreach(handle->src_items, (GFunc) free, NULL);
78                         g_list_free(handle->src_items);
79                 }
80                 if (handle->msg.current_real) {
81                         g_free(handle->msg.current_real);
82                         handle->msg.current_real = NULL;
83                 }
84                 free(handle);
85         }
86
87         return;
88 }
89
90 static gboolean __mf_move_msg_publish(gpointer data)
91 {
92         struct _mf_move_handle *handle = NULL;
93         handle = (struct _mf_move_handle *)data;
94         mf_fo_msg msg;
95
96         if (!handle) {
97                 goto EXIT;
98         }
99         MYFILE_MAGIC_SET(&msg, MYFILE_MAGIC_PIPE_DATA);
100
101         g_mutex_lock(handle->lock);
102         msg.msg_type = handle->msg.msg_type;
103         msg.error_code = handle->msg.error_code;
104         msg.current = handle->msg.current;
105         msg.current_index = handle->msg.current_index;
106         msg.total_index = handle->msg.total_index;
107         msg.current_size = handle->msg.current_size;
108         msg.total_size = handle->msg.total_size;
109         msg.current_real = handle->msg.current_real;
110         msg.request = NULL;
111         msg.pipe = handle->pipe;
112         g_mutex_unlock(handle->lock);
113
114         ecore_pipe_write(handle->pipe, &msg, sizeof(msg));
115
116 EXIT:
117         return FALSE;
118 }
119
120 static void __mf_move_msg_cb(mf_msg_type msg_type, const char *real, unsigned long long size, int error_code, void *data)
121 {
122         struct _mf_move_handle *handle = NULL;
123         handle = (struct _mf_move_handle *)data;
124
125         pthread_mutex_lock(&gLockMsg);
126         while (flagMsg == 0) {
127                 mf_fo_loge("!!!!!!!!!!!! wait");
128                 pthread_cond_wait(&gCondMsg, &gLockMsg);
129         }
130         flagMsg = 0;
131         pthread_mutex_unlock(&gLockMsg);
132
133         if (handle) {
134                 g_mutex_lock(handle->lock);
135                 handle->msg.msg_type = msg_type;
136                 if (msg_type == MF_MSG_ERROR) {
137                         handle->msg.error_code = error_code;
138                         if (real) {
139                                 if (handle->msg.current_real) {
140                                         free(handle->msg.current_real);
141                                 }
142                                 handle->msg.current_real = strdup(real);
143                         }
144                 } else {
145                         handle->msg.error_code = 0;
146                         if (msg_type == MF_MSG_DOING) {
147                                 if (real) {
148                                         if (handle->msg.current_real) {
149                                                 free(handle->msg.current_real);
150                                         }
151                                         handle->msg.current_real = strdup(real);
152                                 }
153                                 handle->msg.current_size += size;
154                                 handle->msg.error_code = 0;
155                         } else if (msg_type == MF_MSG_SKIP) {
156                                 handle->msg.total_size -= size;
157                                 handle->msg.error_code = 0;
158                         }
159                 }
160                 g_mutex_unlock(handle->lock);
161                 __mf_move_msg_publish(handle);
162         }
163         return;
164 }
165
166 static gboolean __mf_move_req_msg_callback(gpointer data)
167 {
168         FO_TRACE_BEGIN;
169
170         struct _mf_move_handle *mv_handle = NULL;
171         mv_handle = (struct _mf_move_handle *)data;
172         mf_fo_msg msg;
173         memset(&msg, 0, sizeof(mf_fo_msg));
174
175         MYFILE_MAGIC_SET(&msg, MYFILE_MAGIC_PIPE_DATA);
176         if (!mv_handle) {
177                 goto EXIT;
178         }
179
180         g_mutex_lock(mv_handle->lock);
181         msg.msg_type = MF_MSG_REQUEST;
182         msg.error_code = mv_handle->msg.error_code;
183         msg.current = mv_handle->msg.current;
184         msg.current_index = mv_handle->msg.current_index;
185         msg.total_index = mv_handle->msg.total_index;
186         msg.current_size = mv_handle->msg.current_size;
187         msg.total_size = mv_handle->msg.total_size;
188         msg.current_real = mv_handle->msg.current_real;
189         msg.request = mv_handle->req;
190         g_mutex_unlock(mv_handle->lock);
191         ecore_pipe_write(mv_handle->pipe, &msg, sizeof(msg));
192
193 EXIT:
194
195         FO_TRACE_END;
196         return FALSE;
197 }
198
199 static void __mf_move_req_cb(mf_fo_request *req, void *data)
200 {
201         struct _mf_move_handle *handle = NULL;
202         handle = (struct _mf_move_handle *)data;
203
204         if (handle) {
205
206                 handle->req = req;
207                 mf_request_set_cond(req, handle->cond);
208                 __mf_move_req_msg_callback(handle);
209                 g_mutex_lock(handle->lock);
210                 while (mf_request_flag_get(req)) {
211                         g_cond_wait(handle->cond, handle->lock);
212                 }
213                 mf_request_flag_set(req, 1);
214                 g_mutex_unlock(handle->lock);
215         }
216         return;
217 }
218
219 static void *__mf_move_thread_func(void *data)
220 {
221         struct _mf_move_handle *handle = NULL;
222         handle = (struct _mf_move_handle *)data;
223
224         gboolean cancelled = FALSE;
225         double s_start = 0.0;
226         double s_stop = 0.0;
227         double c_start = 0.0;
228         double c_stop = 0.0;
229         char err_buf[MF_ERR_BUF] = {0,};
230
231         if (handle) {
232                 GList *tmp_src_list = NULL;
233                 unsigned long long t_size = 0;
234                 unsigned long long r_size = 0;
235                 unsigned long long n_size = 0;
236                 int errcode = 0;
237                 struct stat dst_info;
238
239                 errcode = _mf_fo_get_remain_space(handle->dst_dir, &r_size);
240                 if (errcode < 0) {
241
242                         __mf_move_msg_cb(MF_MSG_ERROR, handle->dst_dir, 0, (MF_FO_ERR_DST_CLASS | _mf_fo_errno_to_mferr(-errcode)), handle);
243
244                         goto ERROR_END_THREAD;
245                 }
246
247                 if (r_size == 0) {
248
249                         int err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_SPACE);
250                         __mf_move_msg_cb(MF_MSG_ERROR, handle->dst_dir, 0, err, handle);
251
252                         goto ERROR_END_THREAD;
253                 }
254
255                 n_size = r_size;
256
257                 if (stat(handle->dst_dir, &dst_info)) {
258
259                         __mf_move_msg_cb(MF_MSG_ERROR, handle->dst_dir, 0, (MF_FO_ERR_DST_CLASS | _mf_fo_errno_to_mferr(errno)), handle);
260
261                         goto ERROR_END_THREAD;
262                 }
263
264                 s_start = __mf_move_get_time();
265                 tmp_src_list = handle->src_items;
266                 while (tmp_src_list) {
267                         if (tmp_src_list->data) {
268                                 const char *s_path = NULL;
269                                 unsigned long long size = 0;
270
271                                 s_path = tmp_src_list->data;
272                                 if (access(s_path, R_OK) == 0) {
273                                         errcode = _mf_fo_get_total_item_size(s_path, &size);
274                                         if (errcode < 0) {
275                                                 mf_fo_loge("Fail to get size of %s", s_path);
276
277                                                 __mf_move_msg_cb(MF_MSG_ERROR, s_path, 0,
278                                                                  (MF_FO_ERR_SRC_CLASS | _mf_fo_errno_to_mferr(-errcode)), handle);
279
280
281                                                 goto ERROR_END_THREAD;
282                                         } else {
283                                                 struct stat src_info;
284                                                 mf_fo_logi("size of %s - %lld", s_path, size);
285                                                 t_size += size;
286
287                                                 if (stat(s_path, &src_info)) {
288
289                                                         __mf_move_msg_cb(MF_MSG_ERROR, handle->dst_dir, 0,
290                                                                          (MF_FO_ERR_DST_CLASS | _mf_fo_errno_to_mferr(errno)), handle);
291
292                                                         goto ERROR_END_THREAD;
293                                                 }
294
295                                                 if (dst_info.st_dev != src_info.st_dev) {
296                                                         if (n_size > size) {
297                                                                 n_size -= size;
298                                                         } else {
299                                                                 mf_fo_loge("remain size [%lld], needed size [%lld], current item size [%lld] -[%s]",
300                                                                            r_size, n_size, size, s_path);
301
302
303                                                                 int err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_SPACE);
304                                                                 __mf_move_msg_cb(MF_MSG_ERROR, handle->dst_dir, 0, err, handle);
305
306                                                                 goto ERROR_END_THREAD;
307                                                         }
308                                                 }
309                                         }
310                                 } else {
311                                         MF_FILE_ERROR_LOG(err_buf, "Unable to access", s_path);
312
313                                         __mf_move_msg_cb(MF_MSG_ERROR, s_path, 0, (MF_FO_ERR_SRC_CLASS | _mf_fo_errno_to_mferr(errno)), handle);
314
315                                         goto ERROR_END_THREAD;
316                                 }
317                         }
318                         tmp_src_list = g_list_next(tmp_src_list);
319                 }
320                 s_stop = __mf_move_get_time();
321                 g_mutex_lock(handle->lock);
322                 handle->msg.total_size = t_size;
323                 g_mutex_unlock(handle->lock);
324
325                 mf_fo_logi("total size [%lld], remain size [%lld] -[%s]", t_size, r_size, handle->dst_dir);
326
327                 c_start = __mf_move_get_time();
328                 tmp_src_list = handle->src_items;
329                 while (tmp_src_list) {
330                         if (tmp_src_list->data) {
331                                 const char *s_path = NULL;
332                                 s_path = tmp_src_list->data;
333                                 int ret = 0;
334                                 g_mutex_lock(handle->lock);
335                                 handle->msg.current_index++;
336                                 handle->msg.current = s_path;
337                                 g_mutex_unlock(handle->lock);
338                                 ret = _mf_move_move_internal(s_path, handle->dst_dir, handle->cancel, __mf_move_req_cb, __mf_move_msg_cb, handle);
339
340                                 if (ret > 0) {
341                                         if (handle->cancel) {
342                                                 mf_cancel_set_cancelled(handle->cancel);
343                                         }
344                                         cancelled = TRUE;
345                                         break;
346                                 }
347                                 if (ret < 0) {
348                                         mf_fo_loge("Fail to move [%s] to [%s]", s_path, handle->dst_dir);
349                                         break;
350                                 }
351                         }
352                         tmp_src_list = g_list_next(tmp_src_list);
353
354                 }
355                 c_stop = __mf_move_get_time();
356                 mf_fo_logi("## Total src size - %lld byte, size time : %lf sec, move time : %lf sec",
357                            handle->msg.total_size, s_stop - s_start, c_stop - c_start);
358
359                 if (cancelled) {
360                         __mf_move_msg_cb(MF_MSG_CANCELLED, NULL, 0, 0, handle);
361                 }
362
363 ERROR_END_THREAD:
364
365                 if (handle->sync) {
366                         double start = 0.0;
367                         double stop = 0.0;
368                         __mf_move_msg_cb(MF_MSG_SYNC, NULL, 0, 0, handle);
369                         start = __mf_move_get_time();
370                         sync();
371                         stop = __mf_move_get_time();
372                         mf_fo_logi("sync time : %lf sec", stop - start);
373                 }
374
375                 __mf_move_msg_cb(MF_MSG_END, NULL, 0, 0, handle);
376
377                 __mf_move_free_handle(handle);
378                 handle = NULL;
379         } else {
380                 mf_fo_loge("handle is NULL");
381                 abort();
382         }
383
384         mf_fo_logd("The end of __mf_move_thread_func");
385         return NULL;
386 }
387
388
389 int mf_move_move_items(GList *item_list, const char *dst_dir, mf_cancel *cancel, gboolean sync, void *u_data)
390 {
391         struct _mf_move_handle *handle = NULL;
392         GList *tmp_list = NULL;
393         int err = 0;
394
395         if (!item_list) {
396                 mf_fo_loge("item_list is NULL");
397                 return -(MF_FO_ERR_ARGUMENT);
398         }
399         if (!dst_dir) {
400                 mf_fo_loge("dst_dir is NULL");
401                 return -(MF_FO_ERR_ARGUMENT);
402         }
403
404         if (!_mf_fo_check_exist(dst_dir)) {
405                 mf_fo_loge("dst_dir[%s] is not existed", dst_dir);
406                 return -(MF_FO_ERR_ARGUMENT);
407         }
408
409         if (!g_thread_supported()) {
410                 g_thread_init(NULL);
411         }
412
413         handle = malloc(sizeof(struct _mf_move_handle));
414         if (!handle) {
415                 mf_fo_loge("Fail to allocate handle");
416                 return -(MF_FO_ERR_MEM);
417         }
418         memset(handle, 0x00, sizeof(struct _mf_move_handle));
419
420         handle->lock = g_mutex_new();
421         if (!handle->lock) {
422                 mf_fo_loge("Fail to allocate mutex");
423                 err = MF_FO_ERR_MEM;
424                 goto ERROR_FREE_MEM;
425         }
426         handle->cond = g_cond_new();
427         if (!handle->cond) {
428                 mf_fo_loge("Fail to allocate cond");
429                 err = MF_FO_ERR_MEM;
430                 goto ERROR_FREE_MEM;
431         }
432
433         handle->dst_dir = strdup(dst_dir);
434         if (!handle->dst_dir) {
435                 mf_fo_loge("Fail to allocate memory");
436                 err = MF_FO_ERR_MEM;
437                 goto ERROR_FREE_MEM;
438         }
439         handle->cancel = cancel;
440         handle->u_data = u_data;
441         handle->sync = sync;
442
443         pthread_mutex_lock(&gLockMsg);
444         flagMsg = 1;
445         pthread_mutex_unlock(&gLockMsg);
446
447         tmp_list = item_list;
448         while (tmp_list) {
449                 if (tmp_list->data) {
450                         char *src_item = NULL;
451                         src_item = strdup((char *)tmp_list->data);
452                         if (src_item) {
453                                 if (_mf_fo_check_exist(src_item)) {
454                                         handle->src_items = g_list_append(handle->src_items, src_item);
455                                 } else {
456                                         mf_fo_loge("src_item[%s] is not existed", src_item);
457                                         err = MF_FO_ERR_ARGUMENT;
458                                         free(src_item);
459                                         src_item = NULL;
460                                 }
461                         } else {
462                                 mf_fo_loge("Fail to allocate memory");
463                                 err = MF_FO_ERR_MEM;
464                                 goto ERROR_FREE_MEM;
465                         }
466                 }
467                 tmp_list = g_list_next(tmp_list);
468         }
469
470         if (!handle->src_items) {
471                 mf_fo_loge("Fail to create src list");
472                 err = MF_FO_ERR_ARGUMENT;
473                 goto ERROR_FREE_MEM;
474         }
475
476         handle->pipe = ecore_pipe_add(mf_callback_thread_pipe_cb, u_data);
477         if (!g_thread_create((GThreadFunc) __mf_move_thread_func, handle, FALSE, NULL)) {
478                 mf_fo_loge("Fail to create move thread");
479                 err = MF_FO_ERR_MEM;
480                 goto ERROR_FREE_MEM;
481         }
482
483         return 0;
484
485 ERROR_FREE_MEM:
486         __mf_move_free_handle(handle);
487         return -(err);
488 }