Tizen 2.0 Release
[apps/core/preloaded/myfiles.git] / src / common / file-operation / mf-copy-internal.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 <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <sys/syscall.h>
29 #include <unistd.h>
30 #include <ftw.h>
31
32 #include "mf-copy-internal.h"
33 #include "mf-cancel.h"
34 #include "mf-fo-common.h"
35 #include "mf-fo-internal.h"
36 #include "mf-media-content.h"
37 #include "mf-fo-debug.h"
38
39 struct _mf_copy_handle_intenal {
40         GList *src_items;
41         char *dst_dir;
42         mf_cancel *cancel;
43         void *u_data;
44         Ecore_Pipe *pipe;
45         gboolean sync;
46
47         GMutex *lock;
48         GCond *cond;
49
50         mf_fo_msg msg;
51         mf_fo_request *req;
52 };
53
54 GSList *copy_list = NULL;
55
56 #ifndef SAFE_FREE
57 #define SAFE_FREE(x) do {\
58                                 if ((x) != NULL) {\
59                                         free(x); x = NULL;\
60                                 } \
61                         } while (0)
62 #endif
63
64 #define MSG_REPORT_PERIOD (1)
65 #define DEF_ALLLOC_SIZE 16384   /*((4)*(1024))*/
66 #define DIR_MODE_BIT (01777)
67 #define FILE_MODE_BIT (S_IRWXU | S_IRWXG | S_IRWXO)
68 #define PER_HANDLE_MAX_SIZE (10*1024*1204)
69 #define PER_HANDLE_MIN_SIZE (1024*1024)
70
71
72 static gchar *__mf_copy_change_root_name(const char *name, const char *old_root, const char *new_root)
73 {
74         gchar *new_name = NULL;
75
76         if (name && old_root && new_root) {
77                 int old_len = strlen(old_root);
78                 int new_len = strlen(new_root);
79                 int name_len = strlen(name);
80                 const char *base = NULL;
81                 GString *n = NULL;
82
83                 if ((strstr(name, old_root) == NULL)
84                     || (name_len <= old_len)
85                     || ((name[old_len] == '/' && name[old_len + 1] == '\0'))
86                     || FALSE) {
87                         mf_fo_loge("invaild args - name : [%s], old_root : [%s]", name, old_root);
88                         return NULL;
89                 }
90
91                 base = name + old_len;
92                 if (name[old_len] == '/') {
93                         base += 1;
94                 }
95
96                 n = g_string_new(new_root);
97                 if (n) {
98                         if (n->str[new_len - 1] == '/') {
99                                 g_string_append_printf(n, "%s", base);
100                         } else {
101                                 g_string_append_printf(n, "/%s", base);
102                         }
103                         new_name = g_string_free(n, FALSE);
104                 }
105         }
106         return new_name;
107 }
108
109
110 int _mf_copy_copy_regfile(const char *src, struct stat *src_statp, const char *dst, unsigned long buf_size, mf_cancel *cancel, _mf_fo_msg_cb msg_cb,
111                           void *msg_data)
112 {
113         FO_TRACE_BEGIN;
114         FILE *src_f = NULL;
115         FILE *dst_f = NULL;
116         void *buf = NULL;
117         unsigned long alloc_size = DEF_ALLLOC_SIZE;
118         ssize_t r_size = 0;
119         mode_t src_mode = 0;
120         int err = 0;
121         char err_buf[MF_ERR_BUF] = { 0, };
122
123         if (!src) {
124                 mf_fo_loge("check argument src");
125                 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_ARGUMENT);
126                 if (msg_cb) {
127                         msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
128                 }
129                 return err;
130         }
131         if (!dst) {
132                 mf_fo_loge("check argument dst");
133                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
134                 if (msg_cb) {
135                         msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
136                 }
137                 return err;
138         }
139
140         if (src_statp) {
141                 src_mode = src_statp->st_mode;
142         } else {
143                 struct stat src_info;
144                 if (stat(src, &src_info)) {
145                         mf_fo_loge("Fail to stat src file : %s", src);
146                         err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
147                         if (msg_cb) {
148                                 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
149                         }
150                         return err;
151                 }
152                 src_mode = src_info.st_mode;
153         }
154
155
156         if (!S_ISREG(src_mode)) {
157                 mf_fo_loge("src[%s] is not regular file", src);
158                 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_TYPE);
159                 if (msg_cb) {
160                         msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
161                 }
162                 return err;
163         }
164         src_f = fopen(src, "rb");
165         if (!src_f) {
166                 mf_fo_loge("Fail to fopen %s file", src);
167                 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
168                 if (msg_cb) {
169                         msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
170                 }
171                 return err;
172         }
173
174         dst_f = fopen(dst, "wb");
175         if (!dst_f) {
176                 mf_fo_loge("Fail to fopen %s file", dst);
177                 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
178                 if (msg_cb) {
179                         msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
180                 }
181                 goto ERROR_CLOSE_FD;
182         }
183         if (buf_size == 0) {
184                 struct stat dst_info;
185                 if (stat(dst, &dst_info)) {
186                         MF_FILE_ERROR_LOG(err_buf, "Fail to stat dst file", dst);
187                         err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
188                         if (msg_cb) {
189                                 msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
190                         }
191                         goto ERROR_CLOSE_FD;
192                 }
193                 if (dst_info.st_blksize > 0) {
194                         alloc_size = dst_info.st_blksize;
195                 }
196         } else {
197                 alloc_size = buf_size;
198         }
199         alloc_size = DEF_ALLLOC_SIZE;
200
201         buf = malloc(alloc_size);
202         if (!buf) {
203                 mf_fo_loge("fail to alloc buf, alloc_size : %lu", alloc_size);
204                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_MEM);
205                 if (msg_cb) {
206                         msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
207                 }
208                 goto ERROR_CLOSE_FD;
209         }
210
211         int count = 0;
212         ssize_t msg_size = 0;
213
214         struct _mf_copy_handle_intenal *cp_handle = NULL;
215         cp_handle = (struct _mf_copy_handle_intenal *)msg_data;
216         mf_debug("cp_handle->msg.total_size=%lld", cp_handle->msg.total_size);
217         int dynamic_size = 0;
218         if (cp_handle->msg.total_size > PER_HANDLE_MAX_SIZE) {
219                 dynamic_size = 64;
220         } else if (cp_handle->msg.total_size <= PER_HANDLE_MAX_SIZE &&
221                    cp_handle->msg.total_size > PER_HANDLE_MIN_SIZE) {
222                 dynamic_size = 8;
223         } else {
224                 dynamic_size = 1;
225         }
226
227         while ((r_size = fread(buf, 1, alloc_size, src_f)) > 0)
228         {
229                 ssize_t total = r_size;
230                 void *buf_p = buf;
231
232                 count++;
233                 while (total > 0) {
234                         ssize_t w_size = 0;
235                         w_size = fwrite(buf_p, 1, total, dst_f);
236                         if (ferror(dst_f) != 0 || (r_size != w_size)) {
237                                 MF_FILE_ERROR_LOG(err_buf, "fail to write", dst_f);
238                                 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
239                                 if (msg_cb) {
240                                         msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
241                                 }
242                                 goto ERROR_CLOSE_FD;
243                         }
244
245                         buf_p += w_size;
246                         total -= w_size;
247                 }
248                 if (cancel && mf_cancel_check_cancel(cancel)) {
249                         goto CANCEL_CLOSE_FD;
250                 }
251
252                 if (count == dynamic_size && msg_cb) {
253                         msg_size += r_size;
254                         msg_cb(MF_MSG_DOING, src, msg_size, 0, msg_data);
255                         msg_size = 0;
256                 } else {
257                         msg_size += r_size;
258                 }
259
260                 count = count % dynamic_size;
261                 //g_usleep(10000);
262         }
263
264         if (msg_size > 0 && msg_cb) {
265                 msg_size += r_size;
266                 msg_cb(MF_MSG_DOING, src, msg_size, 0, msg_data);
267                 msg_size = 0;
268         }
269
270         free(buf);
271
272         fclose(src_f);
273         fclose(dst_f);
274         mf_fo_logd("success to copy file %s to %s", src, dst);
275
276         return 0;
277
278 ERROR_CLOSE_FD:
279
280
281         if (src_f) {
282                 fclose(src_f);
283                 src_f = NULL;
284         }
285         if (dst_f) {
286                 fclose(dst_f);
287                 dst_f = NULL;
288                 remove(dst);
289         }
290         if (buf) {
291                 free(buf);
292         }
293         return err;
294
295
296 CANCEL_CLOSE_FD:
297         if (buf) {
298                 free(buf);
299         }
300         if (src_f) {
301                 fclose(src_f);
302                 src_f = NULL;
303         }
304         if (dst_f) {
305                 fclose(dst_f);
306                 dst_f = NULL;
307                 remove(dst);
308         }
309         return 1;
310 }
311
312 static int __get_copy_directory_hierarchies( const char *pathname, const struct stat *statptr, int type)
313 {
314         mf_fo_dir_list_info *info = NULL;
315         mf_debug("pathname is [%s]\t type is [%d]\t",
316                 pathname, type);
317
318         switch (type) {
319
320         case FTW_F:
321                 info = calloc(sizeof(mf_fo_dir_list_info), 1);
322                 info->ftw_path = g_strdup(pathname);
323                 info->type = type;
324                 copy_list = g_slist_append(copy_list, info);
325                 mf_debug("File pathname is [%s]", pathname);
326                 break;
327         case FTW_D:
328                 info = calloc(sizeof(mf_fo_dir_list_info), 1);
329                 info->ftw_path = g_strdup(pathname);
330                 info->type = type;
331                 copy_list = g_slist_append(copy_list, info);
332                 mf_debug("Directory pathname is [%s]", pathname);
333                 //process file
334                 break;
335         default:
336                 mf_debug("Default pathname is [%s]", pathname);
337         }
338
339         return 0;
340 }
341
342 int _mf_copy_copy_directory(const char *src, struct stat *src_statp, const char *dst, mf_cancel *cancel, _mf_fo_msg_cb msg_cb, void *msg_data)
343 {
344         int ret = -1;
345         mode_t src_mode = 0;
346         int err = 0;
347         char err_buf[MF_ERR_BUF] = { 0, };
348         if (!src) {
349                 mf_fo_loge("check argument src");
350                 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_ARGUMENT);
351                 if (msg_cb) {
352                         msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
353                 }
354                 return err;
355         }
356         if (!dst) {
357                 mf_fo_loge("check argument dst");
358                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
359                 if (msg_cb) {
360                         msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
361                 }
362                 return err;
363         }
364
365         if (src_statp) {
366                 src_mode = src_statp->st_mode;
367         } else {
368                 struct stat src_info;
369                 if (stat(src, &src_info)) {
370                         mf_fo_loge("Fail to stat src file : %s", src);
371                         err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
372                         if (msg_cb) {
373                                 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
374                         }
375                         return err;
376                 }
377                 src_mode = src_info.st_mode;
378         }
379
380         if (access(dst, F_OK)) {
381                 if (mkdir(dst, (src_mode & DIR_MODE_BIT))) {
382                         MF_FILE_ERROR_LOG(err_buf, "Fail to make directory", dst);
383                         err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
384                         if (msg_cb) {
385                                 msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
386                         }
387                         return err;
388                 } else {
389                         if (msg_cb) {
390                                 msg_cb(MF_MSG_DOING, dst, MF_VISUAL_FOLDER_SIZE, 0, msg_data);
391                         }
392                 }
393         } else {
394                 mf_fo_logd("directory[%s] is already existed", dst);
395         }
396
397         ret = ftw(src, __get_copy_directory_hierarchies, 16);
398         if (ret == 0) {
399                 mf_debug();
400                 mf_fo_dir_list_info *ent = NULL;
401                 GSList *list = NULL;
402                 list = copy_list;
403                 while (list) {
404                         if (cancel && mf_cancel_check_cancel(cancel)) {
405                                 goto DO_CANCEL;
406                         }
407                         ent = (mf_fo_dir_list_info *)list->data;
408                         mf_debug("name is [%s] type is [%d]", ent->ftw_path, ent->type);
409                         if (ent->type == FTW_D) {
410                                 if (ent->ftw_path == NULL || strlen(ent->ftw_path) == 0) {
411                                         list = g_slist_next(list);
412                                         continue;
413                                 }
414                                 if (g_strcmp0(ent->ftw_path, src) == 0) {
415                                         list = g_slist_next(list);
416                                         continue;
417                                 }
418                                 char *new_dir = __mf_copy_change_root_name(ent->ftw_path, src, dst);
419                                 mf_fo_logi("copy dir %s to %s", ent->ftw_path, new_dir);
420                                 if (new_dir) {
421                                         if (!_mf_fo_check_exist(new_dir)) {
422                                                 struct stat info;
423                                                 if (stat(ent->ftw_path, &info) == 0) {
424                                                         if (mkdir(new_dir, (info.st_mode & DIR_MODE_BIT))) {
425                                                                 /* fts_set(fts, ent, FTS_SKIP); */
426                                                                 mf_fo_loge("Fail to make directory [%s]", new_dir);
427                                                                 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
428                                                                 if (msg_cb) {
429                                                                         msg_cb(MF_MSG_ERROR, new_dir, 0, err, msg_data);
430                                                                 }
431                                                                 free(new_dir);
432                                                                 goto ERROR_CLOSE_FD;
433                                                         } else {
434                                                                 if (msg_cb) {
435                                                                         msg_cb(MF_MSG_DOING, ent->ftw_path, 0, 0, msg_data);
436                                                                 }
437                                                         }
438                                                 } else {
439                                                         MF_FILE_ERROR_LOG(err_buf, "Fail to stat ", ent->ftw_path);
440                                                         /* fts_set(fts, ent, FTS_SKIP); */
441                                                         err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
442                                                         if (msg_cb) {
443                                                                 msg_cb(MF_MSG_ERROR, ent->ftw_path, 0, err, msg_data);
444                                                         }
445                                                         free(new_dir);
446                                                         goto ERROR_CLOSE_FD;
447                                                 }
448                                         } else {
449                                                 struct stat new_dst_info;
450                                                 if (stat(new_dir, &new_dst_info) == 0) {
451                                                         if (S_ISDIR(new_dst_info.st_mode)) {
452                                                                 if (msg_cb) {
453                                                                         msg_cb(MF_MSG_DOING, ent->ftw_path, 0, 0, msg_data);
454                                                                 }
455                                                         } else {
456                                                                 mf_fo_loge("[%s] is already existed, and this one is not directory", new_dir);
457                                                                 /*set FTS_SKIP to skip children of current*/
458                                                                 /*fts_set(fts, ent, FTS_SKIP);*/
459                                                                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
460                                                                 if (msg_cb) {
461                                                                         msg_cb(MF_MSG_ERROR, new_dir, 0, err, msg_data);
462                                                                 }
463                                                                 free(new_dir);
464                                                                 goto ERROR_CLOSE_FD;
465                                                         }
466                                                 } else {
467                                                         MF_FILE_ERROR_LOG(err_buf, "Fail to stat ", new_dir);
468                                                         /*fts_set(fts, ent, FTS_SKIP);*/
469                                                         err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
470                                                         if (msg_cb) {
471                                                                 msg_cb(MF_MSG_ERROR, new_dir, 0, err, msg_data);
472                                                         }
473                                                         free(new_dir);
474                                                         goto ERROR_CLOSE_FD;
475                                                 }
476                                         }
477                                         free(new_dir);
478                                 } else {
479                                         err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
480                                         if (msg_cb) {
481                                                 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
482                                         }
483                                         goto ERROR_CLOSE_FD;
484                                 }
485                         } else if (ent->type == FTW_F) {
486                                 if (ent->ftw_path == NULL || strlen(ent->ftw_path) == 0) {
487                                         list = g_slist_next(list);
488                                         continue;
489                                 }
490                                 char *new_file = __mf_copy_change_root_name(ent->ftw_path, src, dst);
491                                 if (new_file) {
492                                         err = _mf_copy_copy_regfile(ent->ftw_path, NULL, new_file, 0, cancel, msg_cb, msg_data);
493                                         if (err == 0) {
494                                                 mf_media_content_scan_file(new_file);
495                                         }
496                                         free(new_file);
497                                         if (err > 0) {
498                                                 goto DO_CANCEL;
499                                         } else if (err < 0) {
500                                                 goto ERROR_CLOSE_FD;
501                                         }
502                                 } else {
503                                         err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
504                                         if (msg_cb) {
505                                                 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
506                                         }
507                                         goto ERROR_CLOSE_FD;
508                                 }
509                         }
510                         mf_debug("ent->path is [%s]", ent->ftw_path);
511                         list = g_slist_next(list);
512                 }
513
514         } else {
515                 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
516                 if (msg_cb) {
517                         msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
518                 }
519                 _mf_fo_free_directory_hierarchies(&copy_list);
520                 return err;
521
522         }
523         _mf_fo_free_directory_hierarchies(&copy_list);
524         return 0;
525
526 ERROR_CLOSE_FD:
527         _mf_fo_free_directory_hierarchies(&copy_list);
528         return err;
529
530 DO_CANCEL:
531         _mf_fo_free_directory_hierarchies(&copy_list);
532         return 1;
533 }
534
535 int _mf_copy_copy_internal(const char *src, const char *dst_dir, mf_cancel *cancel, _mf_fo_msg_cb msg_func, mf_req_callback req_func, void *msg_data)
536 {
537         int err = 0;
538         char *src_basename = NULL;
539         char *new_dst = NULL;
540         char *next_name = NULL;
541         int base_size = 0;
542         int root_size = 0;
543         int with_slash = 1;
544         int alloc_size = 1;     /*for null*/
545         struct stat src_info;
546         char err_buf[MF_ERR_BUF] = { 0, };
547
548         if (!src || strlen(src) <= 1) {
549                 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_ARGUMENT);
550                 if (msg_func) {
551                         msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
552                 }
553                 return err;
554         }
555
556         if (!dst_dir) {
557                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
558                 if (msg_func) {
559                         msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
560                 }
561                 return err;
562         }
563
564         if (access(dst_dir, R_OK | W_OK)) {
565                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_PERMISSION);
566                 if (msg_func) {
567                         msg_func(MF_MSG_ERROR, dst_dir, 0, err, msg_data);
568                 }
569                 return err;
570         }
571
572         if (stat(src, &src_info)) {
573                 MF_FILE_ERROR_LOG(err_buf, "Fail to stat src ", src);
574                 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
575                 if (msg_func) {
576                         msg_func(MF_MSG_ERROR, src, 0, err, msg_data);
577                 }
578                 return err;
579         }
580
581         if (S_ISDIR(src_info.st_mode)) {
582                 if (g_strcmp0(dst_dir, src) == 0) {
583                         mf_fo_loge("dst is child of src - src : %s, dst : %s", src, dst_dir);
584                         err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_ARGUMENT);
585                         if (msg_func) {
586                                 msg_func(MF_MSG_ERROR, dst_dir, 0, err, msg_data);
587                         }
588                         return err;
589                 }
590         }
591         src_basename = g_path_get_basename(src);
592         if (!src_basename) {
593                 mf_fo_loge("fail to get basename from src[%s]", src);
594                 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
595                 if (msg_func) {
596                         msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
597                 }
598                 return err;
599         }
600
601         base_size = strlen(src_basename);
602         root_size = strlen(dst_dir);
603
604         if (dst_dir[root_size - 1] != '/') {
605                 alloc_size += 1;
606                 with_slash = 0;
607         }
608
609         alloc_size += (base_size + root_size);
610
611         new_dst = malloc(sizeof(char) * (alloc_size));
612         if (!new_dst) {
613                 mf_fo_loge("fail to alloc new dst");
614                 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
615                 if (msg_func) {
616                         msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
617                 }
618                 goto ERROR_FREE_MEM;
619         }
620
621         if (with_slash) {
622                 snprintf(new_dst, alloc_size, "%s%s", dst_dir, src_basename);
623         } else {
624                 snprintf(new_dst, alloc_size, "%s/%s", dst_dir, src_basename);
625         }
626         SAFE_FREE(src_basename);
627
628         if (cancel && mf_cancel_check_cancel(cancel)) {
629                 goto CANCEL_FREE_MEM;
630         }
631
632         if (access(new_dst, F_OK)) {
633                 if (S_ISDIR(src_info.st_mode)) {
634                         err = _mf_copy_copy_directory(src, &src_info, new_dst, cancel, msg_func, msg_data);
635                         if (err == 0) {
636                                 mf_media_content_scan_folder(new_dst);
637                         }
638                 } else if (S_ISREG(src_info.st_mode)) {
639                         /*just copy*/
640                         err = _mf_copy_copy_regfile(src, &src_info, new_dst, 0, cancel, msg_func, msg_data);
641                         if (err == 0) {
642                                 mf_media_content_scan_file(new_dst);
643                         }
644                 } else {
645                         mf_fo_loge("item[%s] is not file or directory", src);
646                         err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_TYPE | MF_FO_ERR_REPORT_CLASS);
647                         if (msg_func) {
648                                 msg_func(MF_MSG_ERROR, src, 0, err, msg_data);
649                         }
650                         goto ERROR_FREE_MEM;
651                 }
652         } else {
653                 mf_request_type result = MF_REQ_NONE;
654                 if (req_func) {
655                         mf_fo_request *req = mf_request_new();
656                         if (req) {
657                                 mf_request_set_path(req, new_dst);
658                                 mf_fo_logd("~~~~~~ waiting for request");
659                                 req_func(req, msg_data);
660                                 result = mf_request_get_result(req);
661                                 mf_fo_logd("~~~~~~ get request : %d", result);
662                                 if (result == MF_REQ_RENAME) {
663                                         next_name = mf_request_get_new_name(req);
664                                 }
665                                 mf_request_free(req);
666                         } else {
667                                 mf_fo_loge("Fail to alloc request");
668                                 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
669                                 if (msg_func) {
670                                         msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
671                                 }
672                                 goto ERROR_FREE_MEM;
673                         }
674                 }
675
676                 switch (result) {
677                 case MF_REQ_NONE:
678                 case MF_REQ_MERGE:
679                         {
680                                 struct stat dst_info;
681                                 if (stat(new_dst, &dst_info)) {
682                                         MF_FILE_ERROR_LOG(err_buf, "Fail to stat new_dst ", new_dst);
683                                         if (msg_func) {
684                                                 msg_func(MF_MSG_ERROR, NULL, 0, errno, msg_data);
685                                         }
686                                         goto ERROR_FREE_MEM;
687                                 }
688
689                                 if (S_ISDIR(src_info.st_mode)) {
690                                         if (!S_ISDIR(dst_info.st_mode)) {
691                                                 mf_fo_loge("src[%s] is directory, but dst[%s] is already existed and not a directory", src, new_dst);
692
693                                                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_TYPE);
694                                                 if (msg_func) {
695                                                         msg_func(MF_MSG_ERROR, new_dst, 0, err, msg_data);
696                                                 }
697                                                 goto ERROR_FREE_MEM;
698                                         }
699                                         /*just copy*/
700                                         err = _mf_copy_copy_directory(src, &src_info, new_dst, cancel, msg_func, msg_data);
701                                         if (err == 0) {
702                                                 mf_media_content_scan_folder(new_dst);
703                                         }
704                                 } else if (S_ISREG(src_info.st_mode)) {
705                                         if (!S_ISREG(dst_info.st_mode)) {
706                                                 mf_fo_loge("src[%s] is file, but dst[%s] is already existed and not a file", src, new_dst);
707                                                 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_TYPE);
708                                                 if (msg_func) {
709                                                         msg_func(MF_MSG_ERROR, new_dst, 0, err, msg_data);
710                                                 }
711                                                 goto ERROR_FREE_MEM;
712                                         }
713                                         /*just copy*/
714                                         err = _mf_copy_copy_regfile(src, &src_info, new_dst, dst_info.st_blksize, cancel, msg_func, msg_data);
715                                         if (err == 0) {
716                                                 mf_media_content_scan_file(new_dst);
717                                         }
718                                 }
719
720                         }
721                         break;
722                 case MF_REQ_RENAME:
723                         {
724                                 if (next_name) {
725                                         if (S_ISDIR(src_info.st_mode)) {
726                                                 err = _mf_copy_copy_directory(src, &src_info, next_name, cancel, msg_func, msg_data);
727                                                 if (err == 0) {
728                                                         mf_media_content_scan_folder(next_name);
729                                                 }
730                                         } else if (S_ISREG(src_info.st_mode)) {
731                                                 err = _mf_copy_copy_regfile(src, &src_info, next_name, 0, cancel, msg_func, msg_data);
732                                                 if (err == 0) {
733                                                         mf_media_content_scan_file(next_name);
734                                                 }
735                                         }
736                                         SAFE_FREE(next_name);
737                                 } else {
738                                         if (S_ISDIR(src_info.st_mode)) {
739                                                 int errcode = 0;
740                                                 next_name = _mf_fo_get_next_unique_dirname(new_dst, &errcode);
741                                                 if (!next_name) {
742                                                         mf_fo_loge("Fail to get next directory name [%s]", new_dst);
743                                                         err = (_mf_fo_errno_to_mferr(errcode) | MF_FO_ERR_DST_CLASS);
744                                                         if (msg_func) {
745                                                                 msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
746                                                         }
747                                                         goto ERROR_FREE_MEM;
748                                                 }
749                                                 err = _mf_copy_copy_directory(src, &src_info, next_name, cancel, msg_func, msg_data);
750                                                 if (err == 0) {
751                                                         mf_media_content_scan_folder(next_name);
752                                                 }
753                                         } else if (S_ISREG(src_info.st_mode)) {
754                                                 int errcode = 0;
755                                                 next_name = _mf_fo_get_next_unique_filename(new_dst, &errcode);
756                                                 if (!next_name) {
757                                                         mf_fo_loge("Fail to get next file name [%s]", new_dst);
758                                                         err = (_mf_fo_errno_to_mferr(errcode) | MF_FO_ERR_DST_CLASS);
759                                                         if (msg_func) {
760                                                                 msg_func(MF_MSG_ERROR, NULL, 0, err, msg_data);
761                                                         }
762                                                         goto ERROR_FREE_MEM;
763                                                 }
764                                                 err = _mf_copy_copy_regfile(src, &src_info, next_name, 0, cancel, msg_func, msg_data);
765                                                 if (err == 0) {
766                                                         mf_media_content_scan_file(next_name);
767                                                 }
768                                         }
769                                         SAFE_FREE(next_name);
770                                 }
771                         }
772                         break;
773                 case MF_REQ_SKIP:
774                         {
775                                 if (msg_func) {
776                                         unsigned long long size = 0;
777                                         /*1 TODO : Do i need to report error, if i fail to get size ?*/
778                                         _mf_fo_get_total_item_size(src, &size);
779                                         msg_func(MF_MSG_SKIP, NULL, size, 0, msg_data);
780                                 }
781                         }
782                         break;
783                 case MF_REQ_CANCEL:
784                         {
785                                 if (cancel) {
786                                         mf_cancel_do_cancel(cancel);
787                                 }
788                                 goto CANCEL_FREE_MEM;
789                         }
790                         break;
791                 default:
792                         abort();
793                         break;
794
795                 }
796         }
797         SAFE_FREE(new_dst);
798
799         if (err > 0) {
800                 goto CANCEL_FREE_MEM;
801         } else if (err < 0) {
802                 goto ERROR_FREE_MEM;
803         }
804
805         return 0;
806
807 ERROR_FREE_MEM:
808         mf_fo_logi("Copy error");
809         SAFE_FREE(src_basename);
810         SAFE_FREE(new_dst);
811
812         return err;
813
814 CANCEL_FREE_MEM:
815
816         mf_fo_logi("Copy cancelled");
817         SAFE_FREE(new_dst);
818         SAFE_FREE(next_name);
819
820         return 1;
821 }