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