2 * Copyright 2013 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
23 #include <sys/types.h>
29 #include <sys/syscall.h>
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"
42 GSList *move_list = NULL;
45 #define SAFE_FREE(x) do {\
53 #define DIR_MODE_BIT (01777)
55 static gchar *__mf_move_change_root_name(const char *name, const char *old_root, const char *new_root)
57 gchar *new_name = NULL;
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;
66 if ((strstr(name, old_root) == NULL)
67 || (name_len <= old_len)
68 || ((name[old_len] == '/' && name[old_len + 1] == '\0'))
70 mf_fo_loge("invaild args - name : [%s], old_root : [%s]", name, old_root);
74 base = name + old_len;
75 if (name[old_len] == '/') {
79 n = g_string_new(new_root);
81 if (n->str[new_len - 1] == '/') {
82 g_string_append_printf(n, "%s", base);
84 g_string_append_printf(n, "/%s", base);
86 new_name = g_string_free(n, FALSE);
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)
99 struct stat dst_dir_i;
100 char *dst_dir = NULL;
102 char err_buf[MF_ERR_BUF] = {0,};
105 mf_fo_loge("check argument src");
106 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_ARGUMENT);
108 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
113 mf_fo_loge("check argument dst");
114 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
116 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
122 src_size = src_statp->st_size;
123 src_dev = src_statp->st_dev;
124 src_mode = src_statp->st_mode;
126 struct stat src_info;
127 if (stat(src, &src_info)) {
128 mf_fo_loge("Fail to stat src file : %s", src);
130 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
132 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
136 src_size = src_info.st_size;
137 src_dev = src_info.st_dev;
138 src_mode = src_info.st_mode;
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);
145 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
151 dst_dir = g_path_get_dirname(dst);
153 if (stat(dst_dir, &dst_dir_i)) {
154 mf_fo_loge("Fail to stat dst dir file : %s", dst_dir);
156 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
158 msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
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);
168 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
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);
177 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
179 msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
183 mf_fo_logd("success to move file from [%s] to [%s]", src, dst);
185 msg_cb(MF_MSG_DOING, src, src_size, 0, msg_data);
189 err = _mf_copy_copy_regfile(src, src_statp, dst, 0, cancel, msg_cb, msg_data);
191 mf_media_content_scan_file(dst);
195 } else if (err < 0) {
199 err = _mf_delete_delete_regfile(src, src_statp, cancel, NULL, NULL);
201 mf_media_content_scan_file(src);
205 } else if (err < 0) {
207 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
211 mf_fo_logd("[copy/del]success to move file from [%s] to [%s]", src, dst);
224 static int __get_move_directory_hierarchies( const char *pathname, const struct stat *statptr, int type)
227 mf_fo_dir_list_info *info = NULL;
228 mf_debug("pathname is [%s]\t type is [%d]\t",
233 info = calloc(sizeof(mf_fo_dir_list_info), 1);
234 info->ftw_path = g_strdup(pathname);
236 move_list = g_slist_append(move_list, info);
237 mf_debug("File pathname is [%s]", pathname);
240 info = calloc(sizeof(mf_fo_dir_list_info), 1);
241 info->ftw_path = g_strdup(pathname);
243 move_list = g_slist_append(move_list, info);
244 mf_debug("File pathname is [%s]", pathname);
248 mf_debug("Default pathname is [%s]", pathname);
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)
261 gboolean is_same_dev = FALSE;
262 char err_buf[MF_ERR_BUF] = {0,};
265 mf_fo_loge("check argument src");
266 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_ARGUMENT);
268 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
273 mf_fo_loge("check argument dst");
274 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
276 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
282 src_dev = src_statp->st_dev;
283 src_mode = src_statp->st_mode;
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);
290 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
294 src_dev = src_info.st_dev;
295 src_mode = src_info.st_mode;
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);
303 msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
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);
314 msg_cb(MF_MSG_ERROR, dst, 0, err, msg_data);
319 if (src_dev == dst_info.st_dev) {
320 mf_fo_logd("src and dst is same dev");
324 ret = ftw(src, __get_move_directory_hierarchies, 16);
326 mf_fo_dir_list_info *ent = NULL;
327 GSList *list = move_list;
330 if (cancel && mf_cancel_check_cancel(cancel)) {
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);
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);
343 if (!_mf_fo_check_exist(new_dir)) {
344 unsigned long long size = 0;
346 err_code = _mf_fo_get_total_item_size(ent->ftw_path, &size);
348 err = (_mf_fo_errno_to_mferr(err_code) | MF_FO_ERR_SRC_CLASS);
350 msg_cb(MF_MSG_ERROR, ent->ftw_path, 0, err, msg_data);
356 msg_cb(MF_MSG_DOING, ent->ftw_path, 0, 0, msg_data);
360 mf_fo_logi("directory[%s] is already existed", new_dir);
363 if (!_mf_fo_check_exist(new_dir)) {
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);
372 msg_cb(MF_MSG_ERROR, new_dir, 0, err, msg_data);
378 msg_cb(MF_MSG_DOING, ent->ftw_path, 0, 0, msg_data);
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);
386 msg_cb(MF_MSG_ERROR, ent->ftw_path, 0, err, msg_data);
393 struct stat new_dst_info;
394 if (stat(new_dir, &new_dst_info) == 0) {
395 if (S_ISDIR(new_dst_info.st_mode)) {
397 msg_cb(MF_MSG_DOING, ent->ftw_path, 0, 0, msg_data);
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);
403 msg_cb(MF_MSG_ERROR, new_dir, 0, err, msg_data);
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);
412 msg_cb(MF_MSG_ERROR, new_dir, 0, err, msg_data);
422 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
424 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
428 } else if (ent->type == FTW_F) {
429 char *new_file = __mf_move_change_root_name(ent->ftw_path, src, dst);
431 err = _mf_move_move_regfile(ent->ftw_path, NULL, new_file, 0, cancel, msg_cb, msg_data);
433 mf_media_content_scan_file(new_file);
438 } else if (err < 0) {
442 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
444 msg_cb(MF_MSG_ERROR, NULL, 0, err, msg_data);
449 mf_debug("ent->path is [%s]", ent->ftw_path);
450 list = g_slist_next(list);
454 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
456 msg_cb(MF_MSG_ERROR, src, 0, err, msg_data);
458 _mf_fo_free_directory_hierarchies(&move_list);
461 _mf_fo_free_directory_hierarchies(&move_list);
465 _mf_fo_free_directory_hierarchies(&move_list);
469 _mf_fo_free_directory_hierarchies(&move_list);
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)
476 char *src_basename = NULL;
477 char *new_dst = NULL;
478 char *next_name = NULL;
482 int alloc_size = 1; /*for null*/
484 struct stat src_info;
485 struct stat dst_dir_i;
486 char err_buf[MF_ERR_BUF] = {0,};
488 if (!src || strlen(src) <= 1) {
489 err = MF_FO_ERR_SET(MF_FO_ERR_SRC_CLASS | MF_FO_ERR_ARGUMENT);
491 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
497 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_ARGUMENT);
499 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
504 if (access(dst_dir, R_OK | W_OK)) {
506 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_PERMISSION);
508 msg_callback(MF_MSG_ERROR, dst_dir, 0, err, msg_data);
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);
517 msg_callback(MF_MSG_ERROR, src, 0, err, msg_data);
522 if (stat(dst_dir, &dst_dir_i)) {
523 MF_FILE_ERROR_LOG(err_buf, "Fail to stat dst_dir", src);
525 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_SRC_CLASS);
527 msg_callback(MF_MSG_ERROR, dst_dir, 0, err, msg_data);
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);
536 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_REPORT_CLASS | MF_FO_ERR_ARGUMENT);
538 msg_callback(MF_MSG_ERROR, dst_dir, 0, err, msg_data);
543 src_basename = g_path_get_basename(src);
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);
548 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
553 base_size = strlen(src_basename);
554 root_size = strlen(dst_dir);
556 if (dst_dir[root_size - 1] != '/') {
561 alloc_size += (base_size + root_size);
563 new_dst = malloc(sizeof(char) * (alloc_size));
565 mf_fo_loge("fail to alloc new dst");
566 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
568 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
574 snprintf(new_dst, alloc_size, "%s%s", dst_dir, src_basename);
576 snprintf(new_dst, alloc_size, "%s/%s", dst_dir, src_basename);
578 SAFE_FREE(src_basename);
580 if (cancel && mf_cancel_check_cancel(cancel)) {
581 goto CANCEL_FREE_MEM;
584 if (access(new_dst, F_OK)) {
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);
590 MF_FILE_ERROR_LOG(err_buf, "Fail to get item size", new_dst);
592 err = (_mf_fo_errno_to_mferr(-ret) | MF_FO_ERR_SRC_CLASS);
594 msg_callback(MF_MSG_ERROR, src, 0, err, msg_data);
598 if (rename(src, new_dst)) {
599 MF_FILE_ERROR_LOG(err_buf, "Fail to rename item", new_dst);
601 err = (_mf_fo_errno_to_mferr(errno) | MF_FO_ERR_DST_CLASS);
603 msg_callback(MF_MSG_ERROR, new_dst, 0, err, msg_data);
608 mf_media_content_scan_file(new_dst);
611 msg_callback(MF_MSG_DOING, src, size, 0, msg_data);
616 if (S_ISDIR(src_info.st_mode)) {
617 err = _mf_move_move_directory(src, &src_info, new_dst, cancel, msg_callback, msg_data);
619 mf_media_content_scan_folder(new_dst);
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);
624 mf_media_content_scan_file(new_dst);
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);
630 msg_callback(MF_MSG_ERROR, src, 0, err, msg_data);
636 mf_request_type result = MF_REQ_NONE;
637 if (request_callback) {
638 mf_fo_request *req = mf_request_new();
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);
646 if (result == MF_REQ_RENAME) {
647 next_name = mf_request_get_new_name(req);
649 mf_request_free(req);
651 mf_fo_loge("Fail to alloc request");
652 err = MF_FO_ERR_SET(MF_FO_ERR_COMMON_CLASS | MF_FO_ERR_MEM);
654 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
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);
668 msg_callback(MF_MSG_ERROR, NULL, 0, errno, msg_data);
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);
677 err = MF_FO_ERR_SET(MF_FO_ERR_DST_CLASS | MF_FO_ERR_TYPE);
679 msg_callback(MF_MSG_ERROR, new_dst, 0, err, msg_data);
683 err = _mf_move_move_directory(src, &src_info, new_dst, cancel, msg_callback, msg_data);
685 mf_media_content_scan_folder(new_dst);
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);
692 msg_callback(MF_MSG_ERROR, new_dst, 0, err, msg_data);
696 err = _mf_move_move_regfile(src, &src_info, new_dst, dst_info.st_blksize, cancel, msg_callback, msg_data);
698 mf_media_content_scan_file(new_dst);
707 if (S_ISDIR(src_info.st_mode)) {
708 err = _mf_move_move_directory(src, &src_info, next_name, cancel, msg_callback, msg_data);
710 mf_media_content_scan_folder(next_name);
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);
715 mf_media_content_scan_file(next_name);
718 SAFE_FREE(next_name);
720 if (S_ISDIR(src_info.st_mode)) {
722 next_name = _mf_fo_get_next_unique_dirname(new_dst, &errcode);
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);
727 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
731 err = _mf_move_move_directory(src, &src_info, next_name, cancel, msg_callback, msg_data);
733 mf_media_content_scan_folder(next_name);
735 } else if (S_ISREG(src_info.st_mode)) {
737 next_name = _mf_fo_get_next_unique_filename(new_dst, &errcode);
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);
742 msg_callback(MF_MSG_ERROR, NULL, 0, err, msg_data);
746 err = _mf_move_move_regfile(src, &src_info, next_name, 0, cancel, msg_callback, msg_data);
748 mf_media_content_scan_file(next_name);
751 SAFE_FREE(next_name);
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);
767 mf_cancel_do_cancel(cancel);
769 goto CANCEL_FREE_MEM;
781 goto CANCEL_FREE_MEM;
782 } else if (err < 0) {
789 SAFE_FREE(src_basename);
796 mf_fo_logi("move cancelled");