forked from enlightenment/efl
parent
10ff95e654
commit
ab4a53f091
|
@ -44,7 +44,6 @@ _eio_dir_recursiv_ls(Ecore_Thread *thread, Eio_Dir_Copy *copy, const char *targe
|
||||||
|
|
||||||
EINA_ITERATOR_FOREACH(it, info)
|
EINA_ITERATOR_FOREACH(it, info)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "entry: %s\n", info->path);
|
|
||||||
switch (info->dirent->d_type)
|
switch (info->dirent->d_type)
|
||||||
{
|
{
|
||||||
case DT_UNKNOWN:
|
case DT_UNKNOWN:
|
||||||
|
@ -93,6 +92,152 @@ _eio_dir_recursiv_ls(Ecore_Thread *thread, Eio_Dir_Copy *copy, const char *targe
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_eio_dir_init(Ecore_Thread *thread,
|
||||||
|
off_t *step, off_t *count,
|
||||||
|
int *length_source, int *length_dest,
|
||||||
|
Eio_Dir_Copy *order,
|
||||||
|
Eio_File_Progress *progress)
|
||||||
|
{
|
||||||
|
struct stat buffer;
|
||||||
|
|
||||||
|
/* notify main thread of the amount of work todo */
|
||||||
|
*step = 0;
|
||||||
|
*count = eina_list_count(order->files) + eina_list_count(order->dirs) * 2;
|
||||||
|
eio_progress_send(thread, &order->progress, *step, *count);
|
||||||
|
|
||||||
|
/* sort the content, so we create the directory in the right order */
|
||||||
|
order->dirs = eina_list_sort(order->dirs, -1, eio_strcmp);
|
||||||
|
order->files = eina_list_sort(order->files, -1, eio_strcmp);
|
||||||
|
|
||||||
|
/* prepare stuff */
|
||||||
|
*length_source = eina_stringshare_strlen(order->progress.source);
|
||||||
|
*length_dest = eina_stringshare_strlen(order->progress.dest);
|
||||||
|
|
||||||
|
memcpy(progress, &order->progress, sizeof (Eio_File_Progress));
|
||||||
|
progress->source = NULL;
|
||||||
|
progress->dest = NULL;
|
||||||
|
|
||||||
|
/* create destination dir if not available */
|
||||||
|
if (stat(order->progress.dest, &buffer) != 0)
|
||||||
|
{
|
||||||
|
if (stat(order->progress.source, &buffer) != 0)
|
||||||
|
{
|
||||||
|
eio_file_thread_error(&order->progress.common, thread);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mkdir(order->progress.dest, buffer.st_mode) != 0)
|
||||||
|
{
|
||||||
|
eio_file_thread_error(&order->progress.common, thread);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_eio_dir_target(Eio_Dir_Copy *order, char *target, const char *dir, int length_source, int length_dest)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
|
||||||
|
length = eina_stringshare_strlen(dir);
|
||||||
|
|
||||||
|
memcpy(target, order->progress.dest, length_dest);
|
||||||
|
target[length_dest] = '/';
|
||||||
|
memcpy(target + length_dest + 1, dir + length_source, length - length_source + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_eio_dir_mkdir(Ecore_Thread *thread, Eio_Dir_Copy *order,
|
||||||
|
off_t *step, off_t count,
|
||||||
|
int length_source, int length_dest)
|
||||||
|
{
|
||||||
|
const char *dir;
|
||||||
|
Eina_List *l;
|
||||||
|
char target[PATH_MAX];
|
||||||
|
|
||||||
|
/* create all directory */
|
||||||
|
EINA_LIST_FOREACH(order->dirs, l, dir)
|
||||||
|
{
|
||||||
|
/* build target dir path */
|
||||||
|
_eio_dir_target(order, target, dir, length_source, length_dest);
|
||||||
|
|
||||||
|
/* create the directory (we will apply the mode later) */
|
||||||
|
if (mkdir(target, 0777) != 0)
|
||||||
|
{
|
||||||
|
eio_file_thread_error(&order->progress.common, thread);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inform main thread */
|
||||||
|
(*step)++;
|
||||||
|
eio_progress_send(thread, &order->progress, *step, count);
|
||||||
|
|
||||||
|
/* check for cancel request */
|
||||||
|
if (ecore_thread_check(thread))
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_eio_dir_chmod(Ecore_Thread *thread, Eio_Dir_Copy *order,
|
||||||
|
off_t *step, off_t count,
|
||||||
|
int length_source, int length_dest,
|
||||||
|
Eina_Bool rmdir_source)
|
||||||
|
{
|
||||||
|
const char *dir;
|
||||||
|
char target[PATH_MAX];
|
||||||
|
struct stat buffer;
|
||||||
|
|
||||||
|
while(order->dirs)
|
||||||
|
{
|
||||||
|
/* destroy in reverse order so that we don't prevent change of lower dir */
|
||||||
|
dir = eina_list_data_get(eina_list_last(order->dirs));
|
||||||
|
order->dirs = eina_list_remove_list(order->dirs, eina_list_last(order->dirs));
|
||||||
|
|
||||||
|
/* build target dir path */
|
||||||
|
_eio_dir_target(order, target, dir, length_source, length_dest);
|
||||||
|
|
||||||
|
/* FIXME: in some case we already did a stat call, so would be nice to reuse previous result here */
|
||||||
|
/* stat the original dir for mode info */
|
||||||
|
if (stat(dir, &buffer) != 0)
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
/* set the orginal mode to the newly created dir */
|
||||||
|
if (chmod(target, buffer.st_mode) != 0)
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
/* if required destroy original directory */
|
||||||
|
if (rmdir_source)
|
||||||
|
{
|
||||||
|
if (rmdir(dir) != 0)
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inform main thread */
|
||||||
|
(*step)++;
|
||||||
|
eio_progress_send(thread, &order->progress, *step, count);
|
||||||
|
|
||||||
|
/* check for cancel request */
|
||||||
|
if (ecore_thread_check(thread))
|
||||||
|
goto on_cancel;
|
||||||
|
|
||||||
|
eina_stringshare_del(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
eio_file_thread_error(&order->progress.common, thread);
|
||||||
|
on_cancel:
|
||||||
|
if (dir) eina_stringshare_del(dir);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_eio_dir_copy_heavy(Ecore_Thread *thread, void *data)
|
_eio_dir_copy_heavy(Ecore_Thread *thread, void *data)
|
||||||
{
|
{
|
||||||
|
@ -102,10 +247,9 @@ _eio_dir_copy_heavy(Ecore_Thread *thread, void *data)
|
||||||
|
|
||||||
Eio_File_Progress file_copy;
|
Eio_File_Progress file_copy;
|
||||||
char target[PATH_MAX];
|
char target[PATH_MAX];
|
||||||
struct stat buffer;
|
|
||||||
|
|
||||||
int length_source;
|
int length_source = 0;
|
||||||
int length_dest;
|
int length_dest = 0;
|
||||||
off_t count;
|
off_t count;
|
||||||
off_t step;
|
off_t step;
|
||||||
|
|
||||||
|
@ -113,91 +257,34 @@ _eio_dir_copy_heavy(Ecore_Thread *thread, void *data)
|
||||||
if (!_eio_dir_recursiv_ls(thread, copy, copy->progress.source))
|
if (!_eio_dir_recursiv_ls(thread, copy, copy->progress.source))
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
/* notify main thread of the amount of work todo */
|
/* init all structure needed to copy the file */
|
||||||
step = 0;
|
if (!_eio_dir_init(thread, &step, &count, &length_source, &length_dest, copy, &file_copy))
|
||||||
count = eina_list_count(copy->files) + eina_list_count(copy->dirs);
|
goto on_error;
|
||||||
eio_progress_send(thread, ©->progress, step, count);
|
|
||||||
|
|
||||||
/* sort the content, so we create the directory in the right order */
|
/* suboperation is a file copy */
|
||||||
copy->dirs = eina_list_sort(copy->dirs, -1, eio_strcmp);
|
|
||||||
copy->files = eina_list_sort(copy->files, -1, eio_strcmp);
|
|
||||||
|
|
||||||
/* prepare stuff */
|
|
||||||
length_source = eina_stringshare_strlen(copy->progress.source);
|
|
||||||
length_dest = eina_stringshare_strlen(copy->progress.dest);
|
|
||||||
|
|
||||||
memcpy(&file_copy, ©->progress, sizeof (Eio_File_Progress));
|
|
||||||
file_copy.op = EIO_FILE_COPY;
|
file_copy.op = EIO_FILE_COPY;
|
||||||
file_copy.source = NULL;
|
|
||||||
file_copy.dest = NULL;
|
|
||||||
|
|
||||||
/* create destination dir if not available */
|
|
||||||
if (stat(copy->progress.dest, &buffer) != 0)
|
|
||||||
{
|
|
||||||
if (stat(copy->progress.source, &buffer) != 0)
|
|
||||||
{
|
|
||||||
eio_file_thread_error(©->progress.common, thread);
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mkdir(copy->progress.dest, buffer.st_mode) != 0)
|
|
||||||
{
|
|
||||||
eio_file_thread_error(©->progress.common, thread);
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create all directory */
|
/* create all directory */
|
||||||
EINA_LIST_FREE(copy->dirs, dir)
|
if (!_eio_dir_mkdir(thread, copy, &step, count, length_source, length_dest))
|
||||||
{
|
goto on_error;
|
||||||
/* build target dir path */
|
|
||||||
strcpy(target, copy->progress.dest);
|
|
||||||
target[length_dest] = '/';
|
|
||||||
strcpy(target + length_dest + 1, dir + length_source);
|
|
||||||
|
|
||||||
/* stat the original file for mode info */
|
/* copy all files */
|
||||||
/* FIXME: in some case we already did a stat call, so would be nice to reuse previous result here */
|
|
||||||
/* FIXME: apply mode later so that readonly could be copied and property will be set correctly */
|
|
||||||
if (stat(dir, &buffer) != 0)
|
|
||||||
{
|
|
||||||
eio_file_thread_error(©->progress.common, thread);
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create the directory */
|
|
||||||
if (mkdir(target, buffer.st_mode) != 0)
|
|
||||||
{
|
|
||||||
eio_file_thread_error(©->progress.common, thread);
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
step++;
|
|
||||||
eio_progress_send(thread, ©->progress, step, count);
|
|
||||||
|
|
||||||
if (ecore_thread_check(thread))
|
|
||||||
goto on_error;
|
|
||||||
|
|
||||||
eina_stringshare_del(dir);
|
|
||||||
}
|
|
||||||
dir = NULL;
|
|
||||||
|
|
||||||
/* Copy all files */
|
|
||||||
EINA_LIST_FREE(copy->files, file)
|
EINA_LIST_FREE(copy->files, file)
|
||||||
{
|
{
|
||||||
/* build target dir path */
|
/* build target file path */
|
||||||
strcpy(target, copy->progress.dest);
|
_eio_dir_target(copy, target, file, length_source, length_dest);
|
||||||
target[length_dest] = '/';
|
|
||||||
strcpy(target + length_dest + 1, file + length_source);
|
|
||||||
|
|
||||||
file_copy.source = file;
|
file_copy.source = file;
|
||||||
file_copy.dest = eina_stringshare_add(target);
|
file_copy.dest = eina_stringshare_add(target);
|
||||||
|
|
||||||
|
/* copy the file */
|
||||||
if (!eio_file_copy_do(thread, &file_copy))
|
if (!eio_file_copy_do(thread, &file_copy))
|
||||||
{
|
{
|
||||||
copy->progress.common.error = file_copy.common.error;
|
copy->progress.common.error = file_copy.common.error;
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* notify main thread */
|
||||||
step++;
|
step++;
|
||||||
eio_progress_send(thread, ©->progress, step, count);
|
eio_progress_send(thread, ©->progress, step, count);
|
||||||
|
|
||||||
|
@ -210,10 +297,13 @@ _eio_dir_copy_heavy(Ecore_Thread *thread, void *data)
|
||||||
file_copy.dest = NULL;
|
file_copy.dest = NULL;
|
||||||
file = NULL;
|
file = NULL;
|
||||||
|
|
||||||
|
/* set directory right back */
|
||||||
|
if (!_eio_dir_chmod(thread, copy, &step, count, length_source, length_dest, EINA_FALSE))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
/* cleanup the mess */
|
/* cleanup the mess */
|
||||||
if (file_copy.dest) eina_stringshare_del(file_copy.dest);
|
if (file_copy.dest) eina_stringshare_del(file_copy.dest);
|
||||||
if (dir) eina_stringshare_del(dir);
|
|
||||||
if (file) eina_stringshare_del(file);
|
if (file) eina_stringshare_del(file);
|
||||||
|
|
||||||
EINA_LIST_FREE(copy->files, file)
|
EINA_LIST_FREE(copy->files, file)
|
||||||
|
@ -264,6 +354,111 @@ _eio_dir_copy_error(void *data)
|
||||||
_eio_dir_copy_free(copy);
|
_eio_dir_copy_free(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_eio_dir_move_heavy(Ecore_Thread *thread, void *data)
|
||||||
|
{
|
||||||
|
Eio_Dir_Copy *move = data;
|
||||||
|
const char *file = NULL;
|
||||||
|
const char *dir = NULL;
|
||||||
|
|
||||||
|
Eio_File_Progress file_move;
|
||||||
|
char target[PATH_MAX];
|
||||||
|
|
||||||
|
int length_source;
|
||||||
|
int length_dest;
|
||||||
|
off_t count;
|
||||||
|
off_t step;
|
||||||
|
|
||||||
|
/* just try a rename, maybe we are lucky... */
|
||||||
|
if (rename(move->progress.source, move->progress.dest) == 0)
|
||||||
|
{
|
||||||
|
/* we are really lucky */
|
||||||
|
eio_progress_send(thread, &move->progress, 1, 1);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* list all the content that should be moved */
|
||||||
|
if (!_eio_dir_recursiv_ls(thread, move, move->progress.source))
|
||||||
|
return ;
|
||||||
|
|
||||||
|
/* init all structure needed to move the file */
|
||||||
|
if (!_eio_dir_init(thread, &step, &count, &length_source, &length_dest, move, &file_move))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
/* sub operation is a file move */
|
||||||
|
file_move.op = EIO_FILE_MOVE;
|
||||||
|
|
||||||
|
/* create all directory */
|
||||||
|
if (!_eio_dir_mkdir(thread, move, &step, count, length_source, length_dest))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
/* move file around */
|
||||||
|
EINA_LIST_FREE(move->files, file)
|
||||||
|
{
|
||||||
|
/* build target file path */
|
||||||
|
_eio_dir_target(move, target, file, length_source, length_dest);
|
||||||
|
|
||||||
|
file_move.source = file;
|
||||||
|
file_move.dest = eina_stringshare_add(target);
|
||||||
|
|
||||||
|
/* first try to rename */
|
||||||
|
if (rename(file_move.source, file_move.dest) < 0)
|
||||||
|
{
|
||||||
|
if (errno != EXDEV)
|
||||||
|
{
|
||||||
|
eio_file_thread_error(&move->progress.common, thread);
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* then try real copy */
|
||||||
|
if (!eio_file_copy_do(thread, &file_move))
|
||||||
|
{
|
||||||
|
move->progress.common.error = file_move.common.error;
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* and unlink the original */
|
||||||
|
if (unlink(file) != 0)
|
||||||
|
{
|
||||||
|
eio_file_thread_error(&move->progress.common, thread);
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
step++;
|
||||||
|
eio_progress_send(thread, &move->progress, step, count);
|
||||||
|
|
||||||
|
if (ecore_thread_check(thread))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
eina_stringshare_del(file_move.dest);
|
||||||
|
eina_stringshare_del(file);
|
||||||
|
}
|
||||||
|
file_move.dest = NULL;
|
||||||
|
file = NULL;
|
||||||
|
|
||||||
|
/* set directory right back */
|
||||||
|
if (!_eio_dir_chmod(thread, move, &step, count, length_source, length_dest, EINA_TRUE))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
if (rmdir(move->progress.source) != 0)
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
/* cleanup the mess */
|
||||||
|
if (file_move.dest) eina_stringshare_del(file_move.dest);
|
||||||
|
if (file) eina_stringshare_del(file);
|
||||||
|
|
||||||
|
EINA_LIST_FREE(move->files, file)
|
||||||
|
eina_stringshare_del(file);
|
||||||
|
EINA_LIST_FREE(move->dirs, dir)
|
||||||
|
eina_stringshare_del(dir);
|
||||||
|
|
||||||
|
if (!ecore_thread_check(thread))
|
||||||
|
eio_progress_send(thread, &move->progress, count, count);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup Eio_Group Asynchronous Inout/Output library
|
* @addtogroup Eio_Group Asynchronous Inout/Output library
|
||||||
|
@ -282,7 +477,7 @@ _eio_dir_copy_error(void *data)
|
||||||
*
|
*
|
||||||
* This function will copy a directory and all it's content from source to dest.
|
* This function will copy a directory and all it's content from source to dest.
|
||||||
* It will try to use splice if possible, if not it will fallback to mmap/write.
|
* It will try to use splice if possible, if not it will fallback to mmap/write.
|
||||||
* It will try to preserve access right, but not user/group identification.
|
* It will try to preserve access right, but not user/group identity.
|
||||||
*/
|
*/
|
||||||
EAPI Eio_File *
|
EAPI Eio_File *
|
||||||
eio_dir_copy(const char *source,
|
eio_dir_copy(const char *source,
|
||||||
|
@ -321,6 +516,57 @@ eio_dir_copy(const char *source,
|
||||||
return ©->progress.common;
|
return ©->progress.common;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move a directory and it's content asynchronously
|
||||||
|
* @param source Should be the name of the directory to copy the data from.
|
||||||
|
* @param dest Should be the name of the directory to copy the data to.
|
||||||
|
* @param progress_cb Callback called to know the progress of the copy.
|
||||||
|
* @param done_cb Callback called when the copy is done.
|
||||||
|
* @param error_cb Callback called when something goes wrong.
|
||||||
|
* @param data Private data given to callback.
|
||||||
|
*
|
||||||
|
* This function will move a directory and all it's content from source to dest.
|
||||||
|
* It will try first to rename the directory, if not it will try to use splice
|
||||||
|
* if possible, if not it will fallback to mmap/write.
|
||||||
|
* It will try to preserve access right, but not user/group identity.
|
||||||
|
*/
|
||||||
|
EAPI Eio_File *
|
||||||
|
eio_dir_move(const char *source,
|
||||||
|
const char *dest,
|
||||||
|
Eio_Progress_Cb progress_cb,
|
||||||
|
Eio_Done_Cb done_cb,
|
||||||
|
Eio_Error_Cb error_cb,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
Eio_Dir_Copy *move;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
|
||||||
|
|
||||||
|
move = malloc(sizeof(Eio_Dir_Copy));
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(move, NULL);
|
||||||
|
|
||||||
|
move->progress.op = EIO_DIR_MOVE;
|
||||||
|
move->progress.progress_cb = progress_cb;
|
||||||
|
move->progress.source = eina_stringshare_add(source);
|
||||||
|
move->progress.dest = eina_stringshare_add(dest);
|
||||||
|
move->files = NULL;
|
||||||
|
|
||||||
|
if (!eio_long_file_set(&move->progress.common,
|
||||||
|
done_cb,
|
||||||
|
error_cb,
|
||||||
|
data,
|
||||||
|
_eio_dir_move_heavy,
|
||||||
|
_eio_dir_copy_notify,
|
||||||
|
_eio_dir_copy_end,
|
||||||
|
_eio_dir_copy_error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &move->progress.common;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue