|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#ifndef _FILE_OFFSET_BITS
|
|
|
|
# define _FILE_OFFSET_BITS 64
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
# include <alloca.h>
|
|
|
|
#elif defined __GNUC__
|
|
|
|
# define alloca __builtin_alloca
|
|
|
|
#elif defined _AIX
|
|
|
|
# define alloca __alloca
|
|
|
|
#elif defined _MSC_VER
|
|
|
|
# include <malloc.h>
|
|
|
|
# define alloca _alloca
|
|
|
|
#else
|
|
|
|
# include <stddef.h>
|
|
|
|
# ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
# endif
|
|
|
|
void *alloca(size_t);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <utime.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <Ecore.h>
|
|
|
|
#include <Ecore_File.h>
|
|
|
|
|
|
|
|
#include <eina_stringshare.h>
|
|
|
|
|
|
|
|
#define E_TYPEDEFS
|
|
|
|
#include "e_fm_op.h"
|
|
|
|
#undef E_TYPEDEFS
|
|
|
|
#include "e_fm_op.h"
|
|
|
|
|
|
|
|
#define READBUFSIZE 65536
|
|
|
|
#define COPYBUFSIZE 16384
|
|
|
|
#define REMOVECHUNKSIZE 4096
|
|
|
|
#define NB_PASS 3
|
|
|
|
|
|
|
|
#define E_FREE(p) do { free(p); p = NULL; } while (0)
|
|
|
|
|
|
|
|
#define _E_FM_OP_ERROR_SEND_SCAN(_task, _e_fm_op_error_type, _fmt, ...) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
int _errno = errno; \
|
|
|
|
_e_fm_op_scan_error = 1; \
|
|
|
|
_e_fm_op_send_error(_task, _e_fm_op_error_type, _fmt, __VA_ARGS__, strerror(_errno)); \
|
|
|
|
return 1; \
|
|
|
|
} \
|
|
|
|
while (0)
|
|
|
|
|
|
|
|
#define _E_FM_OP_ERROR_SEND_WORK(_task, _e_fm_op_error_type, _fmt, ...) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
int _errno = errno; \
|
|
|
|
_e_fm_op_work_error = 1; \
|
|
|
|
_e_fm_op_send_error(_task, _e_fm_op_error_type, _fmt, __VA_ARGS__, strerror(_errno)); \
|
|
|
|
return 1; \
|
|
|
|
} \
|
|
|
|
while (0)
|
|
|
|
|
|
|
|
typedef struct _E_Fm_Op_Task E_Fm_Op_Task;
|
|
|
|
typedef struct _E_Fm_Op_Copy_Data E_Fm_Op_Copy_Data;
|
|
|
|
|
|
|
|
static E_Fm_Op_Task *_e_fm_op_task_new(void);
|
|
|
|
static void _e_fm_op_task_free(void *t);
|
|
|
|
|
|
|
|
static void _e_fm_op_remove_link_task(E_Fm_Op_Task *task);
|
|
|
|
static Eina_Bool _e_fm_op_stdin_data(void *data, Ecore_Fd_Handler *fd_handler);
|
|
|
|
static void _e_fm_op_set_up_idlers(void);
|
|
|
|
static void _e_fm_op_delete_idler(int *mark);
|
|
|
|
static int _e_fm_op_idler_handle_error(int *mark, Eina_List **queue, Eina_List **node, E_Fm_Op_Task *task);
|
|
|
|
|
|
|
|
static Eina_Bool _e_fm_op_work_idler(void *data);
|
|
|
|
static Eina_Bool _e_fm_op_scan_idler(void *data);
|
|
|
|
|
|
|
|
static void _e_fm_op_send_error(E_Fm_Op_Task *task, E_Fm_Op_Type type, const char *fmt, ...) EINA_PRINTF(3, 4);
|
|
|
|
static void _e_fm_op_rollback(E_Fm_Op_Task *task);
|
|
|
|
static void _e_fm_op_update_progress_report_simple(int percent, const char *src, const char *dst);
|
|
|
|
static void _e_fm_op_update_progress(E_Fm_Op_Task *task, off_t _plus_e_fm_op_done, off_t _plus_e_fm_op_total);
|
|
|
|
static void _e_fm_op_copy_stat_info(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_handle_overwrite(E_Fm_Op_Task *task);
|
|
|
|
|
|
|
|
static int _e_fm_op_copy_dir(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_copy_link(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_copy_fifo(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_open_files(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_copy_chunk(E_Fm_Op_Task *task);
|
|
|
|
|
|
|
|
static int _e_fm_op_copy_atom(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_scan_atom(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_copy_stat_info_atom(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_symlink_atom(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_remove_atom(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_rename_atom(E_Fm_Op_Task *task);
|
|
|
|
static int _e_fm_op_destroy_atom(E_Fm_Op_Task *task);
|
|
|
|
static void _e_fm_op_random_buf(char *buf, ssize_t len);
|
|
|
|
static void _e_fm_op_random_char(char *buf, size_t len);
|
|
|
|
|
|
|
|
static int _e_fm_op_make_copy_name(const char *abs, char *buf, size_t buf_size);
|
|
|
|
|
|
|
|
Eina_List *_e_fm_op_work_queue = NULL, *_e_fm_op_scan_queue = NULL;
|
|
|
|
Ecore_Idler *_e_fm_op_work_idler_p = NULL, *_e_fm_op_scan_idler_p = NULL;
|
|
|
|
|
|
|
|
int _e_fm_op_abort = 0; /* Abort mark. */
|
|
|
|
int _e_fm_op_scan_error = 0;
|
|
|
|
int _e_fm_op_work_error = 0;
|
|
|
|
int _e_fm_op_overwrite = 0;
|
|
|
|
|
|
|
|
int _e_fm_op_error_response = E_FM_OP_NONE;
|
|
|
|
int _e_fm_op_overwrite_response = E_FM_OP_NONE;
|
|
|
|
|
|
|
|
Eina_List *_e_fm_op_separator = NULL;
|
|
|
|
|
|
|
|
char *_e_fm_op_stdin_buffer = NULL;
|
|
|
|
|
|
|
|
struct _E_Fm_Op_Task
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
struct stat st;
|
|
|
|
} src;
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
size_t done;
|
|
|
|
} dst;
|
|
|
|
|
|
|
|
int started, finished;
|
|
|
|
unsigned int passes;
|
|
|
|
off_t pos;
|
|
|
|
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
E_Fm_Op_Task *parent;
|
|
|
|
E_Fm_Op_Type type;
|
|
|
|
E_Fm_Op_Type overwrite;
|
|
|
|
|
|
|
|
Eina_List *link;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _E_Fm_Op_Copy_Data
|
|
|
|
{
|
|
|
|
FILE *from;
|
|
|
|
FILE *to;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int i, last;
|
|
|
|
E_Fm_Op_Type type;
|
|
|
|
|
|
|
|
ecore_app_no_system_modules();
|
|
|
|
ecore_init();
|
|
|
|
|
|
|
|
_e_fm_op_stdin_buffer = malloc(READBUFSIZE);
|
|
|
|
if (!_e_fm_op_stdin_buffer) return 0;
|
|
|
|
|
|
|
|
ecore_main_fd_handler_add(STDIN_FILENO, ECORE_FD_READ, _e_fm_op_stdin_data,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (argc < 3) return 0;
|
|
|
|
|
|
|
|
last = argc - 1;
|
|
|
|
i = 2;
|
|
|
|
|
|
|
|
if (!strcmp(argv[1], "cp")) type = E_FM_OP_COPY;
|
|
|
|
else if (!strcmp(argv[1], "mv"))
|
|
|
|
type = E_FM_OP_MOVE;
|
|
|
|
else if (!strcmp(argv[1], "rm"))
|
|
|
|
type = E_FM_OP_REMOVE;
|
|
|
|
else if (!strcmp(argv[1], "srm"))
|
|
|
|
type = E_FM_OP_SECURE_REMOVE;
|
|
|
|
else if (!strcmp(argv[1], "lns"))
|
|
|
|
type = E_FM_OP_SYMLINK;
|
|
|
|
else if (!strcmp(argv[1], "mvf"))
|
|
|
|
type = E_FM_OP_RENAME;
|
|
|
|
else return 0;
|
|
|
|
|
|
|
|
if (type == E_FM_OP_SECURE_REMOVE)
|
|
|
|
{
|
|
|
|
_e_fm_op_work_queue = eina_list_append(_e_fm_op_work_queue, NULL);
|
|
|
|
_e_fm_op_separator = _e_fm_op_work_queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((type == E_FM_OP_COPY) ||
|
|
|
|
(type == E_FM_OP_SYMLINK) ||
|
|
|
|
(type == E_FM_OP_MOVE) ||
|
|
|
|
(type == E_FM_OP_RENAME))
|
|
|
|
{
|
|
|
|
if (argc < 4) goto quit;
|
|
|
|
|
|
|
|
if (ecore_file_is_dir(argv[last]))
|
|
|
|
{
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
char *p2, *p3;
|
|
|
|
int p2_len, last_len, done, total;
|
|
|
|
|
|
|
|
p2 = ecore_file_realpath(argv[last]);
|
|
|
|
if (!p2) goto quit;
|
|
|
|
p2_len = strlen(p2);
|
|
|
|
|
|
|
|
last_len = strlen(argv[last]);
|
|
|
|
if ((last_len < 1) || (last_len + 2 >= PATH_MAX))
|
|
|
|
{
|
|
|
|
E_FREE(p2);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
memcpy(buf, argv[last], last_len);
|
|
|
|
if (buf[last_len - 1] != '/')
|
|
|
|
{
|
|
|
|
buf[last_len] = '/';
|
|
|
|
last_len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
p3 = buf + last_len;
|
|
|
|
|
|
|
|
done = 0;
|
|
|
|
total = last - 2;
|
|
|
|
|
|
|
|
for (; i < last; i++)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
size_t name_len;
|
|
|
|
char *dir;
|
|
|
|
int r;
|
|
|
|
Eina_Bool make_copy;
|
|
|
|
|
|
|
|
/* Don't move a dir into itself */
|
|
|
|
if (ecore_file_is_dir(argv[i]) &&
|
|
|
|
(strcmp(argv[i], p2) == 0))
|
|
|
|
goto skip_arg;
|
|
|
|
|
|
|
|
make_copy = EINA_FALSE;
|
|
|
|
/* Don't move/rename/symlink into same directory
|
|
|
|
* in case of copy, make copy name automatically */
|
|
|
|
dir = ecore_file_dir_get(argv[i]);
|
|
|
|
if (dir)
|
|
|
|
{
|
|
|
|
r = (strcmp(dir, p2) == 0);
|
|
|
|
E_FREE(dir);
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
if (type == E_FM_OP_COPY) make_copy = EINA_TRUE;
|
|
|
|
else goto skip_arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
name = ecore_file_file_get(argv[i]);
|
|
|
|
if (!name) goto skip_arg;
|
|
|
|
name_len = strlen(name);
|
|
|
|
if (p2_len + name_len >= PATH_MAX) goto skip_arg;
|
|
|
|
memcpy(p3, name, name_len + 1);
|
|
|
|
if (make_copy)
|
|
|
|
{
|
|
|
|
if (_e_fm_op_make_copy_name(buf, p3, PATH_MAX - p2_len - 1))
|
|
|
|
goto skip_arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((type == E_FM_OP_SYMLINK) &&
|
|
|
|
(symlink(argv[i], buf) == 0))
|
|
|
|
{
|
|
|
|
done++;
|
|
|
|
_e_fm_op_update_progress_report_simple
|
|
|
|
(done * 100 / total, argv[i], buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (type == E_FM_OP_MOVE)
|
|
|
|
{
|
|
|
|
if (!strcmp(argv[i], buf))
|
|
|
|
goto skip_arg;
|
|
|
|
|
|
|
|
if (buf[0] != '/')
|
|
|
|
{
|
|
|
|
free(p2);
|
|
|
|
_E_FM_OP_ERROR_SEND_SCAN(0, E_FM_OP_ERROR,
|
|
|
|
"Unknown destination '%s': %s.", buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == E_FM_OP_RENAME)
|
|
|
|
{
|
|
|
|
if (!strcmp(argv[i], buf))
|
|
|
|
goto skip_arg;
|
|
|
|
|
|
|
|
if (buf[0] != '/')
|
|
|
|
{
|
|
|
|
free(p2);
|
|
|
|
_E_FM_OP_ERROR_SEND_SCAN(0, E_FM_OP_ERROR,
|
|
|
|
"Unknown destination '%s': %s.", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (access(buf, F_OK) == -1)
|
|
|
|
{
|
|
|
|
/* race condition, i know, but it's
|
|
|
|
* unvoidable. */
|
|
|
|
if (rename(argv[i], buf) == -1)
|
|
|
|
{
|
|
|
|
/* if it's another device */
|
|
|
|
if (errno == EXDEV)
|
|
|
|
type = E_FM_OP_MOVE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free(p2);
|
|
|
|
_E_FM_OP_ERROR_SEND_SCAN(0, E_FM_OP_ERROR,
|
|
|
|
"Cannot move '%s' to '%s': %s.",
|
|
|
|
argv[i], buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
done++;
|
|
|
|
_e_fm_op_update_progress_report_simple
|
|
|
|
(done * 100 / total, argv[i], buf);
|
|
|
|
goto skip_arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* if the destination file already exists,
|
|
|
|
* store a task which handles overwrite */
|
|
|
|
struct stat st1;
|
|
|
|
struct stat st2;
|
|
|
|
if ((stat(argv[i], &st1) == 0) &&
|
|
|
|
(stat(buf, &st2) == 0))
|
|
|
|
{
|
|
|
|
/* if files are not on the same device */
|
|
|
|
if (st1.st_dev != st2.st_dev)
|
|
|
|
type = E_FM_OP_MOVE;
|
|
|
|
}
|
|
|
|
else type = E_FM_OP_MOVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == E_FM_OP_MOVE)
|
|
|
|
{
|
|
|
|
_e_fm_op_work_queue = eina_list_append(_e_fm_op_work_queue, NULL);
|
|
|
|
_e_fm_op_separator = _e_fm_op_work_queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
E_Fm_Op_Task *task;
|
|
|
|
|
|
|
|
task = _e_fm_op_task_new();
|
|
|
|
task->type = type;
|
|
|
|
task->src.name = eina_stringshare_add(argv[i]);
|
|
|
|
task->dst.name = eina_stringshare_add(buf);
|
|
|
|
|
|
|
|
_e_fm_op_scan_queue =
|
|
|
|
eina_list_append(_e_fm_op_scan_queue, task);
|
|
|
|
}
|
|
|
|
|
|
|
|
skip_arg:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
E_FREE(p2);
|
|
|
|
}
|
|
|
|
else if (argc == 4)
|
|
|
|
{
|
|
|
|
char *p, *p2;
|
|
|
|
|
|
|
|
p = ecore_file_realpath(argv[2]);
|
|
|
|
p2 = ecore_file_realpath(argv[3]);
|
|
|
|
|
|
|
|
/* Don't move a file on top of itself. */
|
|
|
|
i = (strcmp(p, p2) == 0);
|
|
|
|
E_FREE(p);
|
|
|
|
E_FREE(p2);
|
|
|
|
if (i) goto quit;
|
|
|
|
|
|
|
|
if ((type == E_FM_OP_SYMLINK) &&
|
|
|
|
(symlink(argv[2], argv[3]) == 0))
|
|
|
|
{
|
|
|
|
_e_fm_op_update_progress_report_simple(100, argv[2], argv[3]);
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (type == E_FM_OP_MOVE)
|
|
|
|
type = E_FM_OP_RENAME;
|
|
|
|
|
|
|
|
E_Fm_Op_Task *task;
|
|
|
|
|
|
|
|
task = _e_fm_op_task_new();
|
|
|
|
task->type = type;
|
|
|
|
task->src.name = eina_stringshare_add(argv[2]);
|
|
|
|
task->dst.name = eina_stringshare_add(argv[3]);
|
|
|
|
_e_fm_op_scan_queue = eina_list_append(_e_fm_op_scan_queue, task);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
else if ((type == E_FM_OP_REMOVE) || (type == E_FM_OP_SECURE_REMOVE))
|
|
|
|
{
|
|
|
|
E_Fm_Op_Task *task;
|
|
|
|
|
|
|
|
while (i <= last)
|
|
|
|
{
|
|
|
|
task = _e_fm_op_task_new();
|
|
|
|
task->type = type;
|
|
|
|
task->src.name = eina_stringshare_add(argv[i]);
|
|
|
|
_e_fm_op_scan_queue = eina_list_append(_e_fm_op_scan_queue, task);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_e_fm_op_set_up_idlers();
|
|
|
|
|
|
|
|
ecore_main_loop_begin();
|
|
|
|
|
|
|
|
quit:
|
|
|
|
ecore_shutdown();
|
|
|
|
|
|
|
|
E_FREE(_e_fm_op_stdin_buffer);
|
|
|
|
|
|
|
|
E_FM_OP_DEBUG("Slave quit.\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create new task. */
|
|
|
|
static E_Fm_Op_Task *
|
|
|
|
_e_fm_op_task_new()
|
|
|
|
{
|
|
|
|
E_Fm_Op_Task *t;
|
|
|
|
|
|
|
|
t = malloc(sizeof(E_Fm_Op_Task));
|
|
|
|
t->src.name = NULL;
|
|
|
|
memset(&(t->src.st), 0, sizeof(struct stat));
|
|
|
|
|
|
|
|
t->dst.name = NULL;
|
|
|
|
t->dst.done = 0;
|
|
|
|
t->started = 0;
|
|
|
|
t->finished = 0;
|
|
|
|
t->data = NULL;
|
|
|
|
t->type = E_FM_OP_NONE;
|
|
|
|
t->overwrite = E_FM_OP_NONE;
|
|
|
|
t->link = NULL;
|
|
|
|
t->pos = t->passes = 0;
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free task. */
|
|
|
|
static void
|
|
|
|
_e_fm_op_task_free(void *t)
|
|
|
|
{
|
|
|
|
E_Fm_Op_Task *task = t;
|
|
|
|
E_Fm_Op_Copy_Data *data;
|
|
|
|
|
|
|
|
if (!task) return;
|
|
|
|
|
|
|
|
if (task->src.name) eina_stringshare_del(task->src.name);
|
|
|
|
if (task->dst.name) eina_stringshare_del(task->dst.name);
|
|
|
|
|
|
|
|
if (task->data)
|
|
|
|
{
|
|
|
|
data = task->data;
|
|
|
|
if (task->type == E_FM_OP_COPY)
|
|
|
|
{
|
|
|
|
if (data->from) fclose(data->from);
|
|
|
|
if (data->to) fclose(data->to);
|
|
|
|
}
|
|
|
|
E_FREE(task->data);
|
|
|
|
}
|
|
|
|
E_FREE(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Removes link task from work queue.
|
|
|
|
* Link task is not NULL in case of MOVE. Then two tasks are created: copy and remove.
|
|
|
|
* Remove task is a link task for the copy task. If copy task is aborted (e.g. error
|
|
|
|
* occurred and user chooses to ignore this), then the remove task is removed from
|
|
|
|
* queue with this functions.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_e_fm_op_remove_link_task(E_Fm_Op_Task *task)
|
|
|
|
{
|
List of changes:
1. Gadcon sities:
-- 'E_Gadcon_Site' enum to list all available sities,
-- added 'is_site' callback for distinguish gadcon sities,
-- 'e_gadcon_site_is_*' helpers written to use in gadget modules,
-- gadcon config dialogs modified to show only gadgets that appropriate
to selected gadcon site,
-- all gadget modules updated for using new callback.
When callback is not provided in module, then gadget can be used in
any gadcon site.
2. Filemanager:
-- added error icon to unexisting path dialog,
-- added callback 'func.abort' to 'E_Fm2_Op_Registry_Entry' to specify
abort operation sequence (if not provided, then operation is not
cancelable),
-- added parameter to 'e_fm2_op_registry_entry_add' to specify abort
method on construct 'E_Fm2_Op_Registry_Entry' or make non-cancelable
operation if this function is not provided,
-- added 'e_fm2_operation_abort' call to cancel efm2 operation,
-- added method '_e_fm2_operation_abort_internal' that represent efm2
default handler of operation cancelling,
-- 'done' and 'total' fields of 'E_Fm2_Op_Registry_Entry' changed to
off_t type, also all message handlers modified to work with it
(to show progress for large files correctly),
-- improved file operation progress processing,
-- added cancel button to operation progress gadget in filemanager window,
-- added delete file glyph to operation progress gadget,
-- improved status message for efm2 operation progress.
3. Filemanager slave:
-- fixed critical bug in message handling via stdin/stdout,
-- fixed critical bug in removing task from list,
-- improved 'E_FM_OP_ABORT' handling,
-- fix rollback counting on moving files.
4. Fileman_opinfo module:
-- a new theme writed: status string and gadget for view operation status
in summary and detail modes,
-- summary mode: operation glyph, state message, progressbar, abort button,
-- detail mode: all for summary + from filename, to filename,
-- summary/detailed button works as trigger,
-- added source of module theme and used images.
4. Pathbar module:
-- non-critical fix, just for safety.
Also patch contains several minor updates to serve main task.
SVN revision: 41224
14 years ago
|
|
|
E_Fm_Op_Task *ltask;
|
|
|
|
|
|
|
|
if (!task) return;
|
|
|
|
if (task->link)
|
|
|
|
{
|
List of changes:
1. Gadcon sities:
-- 'E_Gadcon_Site' enum to list all available sities,
-- added 'is_site' callback for distinguish gadcon sities,
-- 'e_gadcon_site_is_*' helpers written to use in gadget modules,
-- gadcon config dialogs modified to show only gadgets that appropriate
to selected gadcon site,
-- all gadget modules updated for using new callback.
When callback is not provided in module, then gadget can be used in
any gadcon site.
2. Filemanager:
-- added error icon to unexisting path dialog,
-- added callback 'func.abort' to 'E_Fm2_Op_Registry_Entry' to specify
abort operation sequence (if not provided, then operation is not
cancelable),
-- added parameter to 'e_fm2_op_registry_entry_add' to specify abort
method on construct 'E_Fm2_Op_Registry_Entry' or make non-cancelable
operation if this function is not provided,
-- added 'e_fm2_operation_abort' call to cancel efm2 operation,
-- added method '_e_fm2_operation_abort_internal' that represent efm2
default handler of operation cancelling,
-- 'done' and 'total' fields of 'E_Fm2_Op_Registry_Entry' changed to
off_t type, also all message handlers modified to work with it
(to show progress for large files correctly),
-- improved file operation progress processing,
-- added cancel button to operation progress gadget in filemanager window,
-- added delete file glyph to operation progress gadget,
-- improved status message for efm2 operation progress.
3. Filemanager slave:
-- fixed critical bug in message handling via stdin/stdout,
-- fixed critical bug in removing task from list,
-- improved 'E_FM_OP_ABORT' handling,
-- fix rollback counting on moving files.
4. Fileman_opinfo module:
-- a new theme writed: status string and gadget for view operation status
in summary and detail modes,
-- summary mode: operation glyph, state message, progressbar, abort button,
-- detail mode: all for summary + from filename, to filename,
-- summary/detailed button works as trigger,
-- added source of module theme and used images.
4. Pathbar module:
-- non-critical fix, just for safety.
Also patch contains several minor updates to serve main task.
SVN revision: 41224
14 years ago
|
|
|
ltask = eina_list_data_get(task->link);
|
|
|
|
_e_fm_op_work_queue =
|
|
|
|
eina_list_remove_list(_e_fm_op_work_queue, task->link);
|
List of changes:
1. Gadcon sities:
-- 'E_Gadcon_Site' enum to list all available sities,
-- added 'is_site' callback for distinguish gadcon sities,
-- 'e_gadcon_site_is_*' helpers written to use in gadget modules,
-- gadcon config dialogs modified to show only gadgets that appropriate
to selected gadcon site,
-- all gadget modules updated for using new callback.
When callback is not provided in module, then gadget can be used in
any gadcon site.
2. Filemanager:
-- added error icon to unexisting path dialog,
-- added callback 'func.abort' to 'E_Fm2_Op_Registry_Entry' to specify
abort operation sequence (if not provided, then operation is not
cancelable),
-- added parameter to 'e_fm2_op_registry_entry_add' to specify abort
method on construct 'E_Fm2_Op_Registry_Entry' or make non-cancelable
operation if this function is not provided,
-- added 'e_fm2_operation_abort' call to cancel efm2 operation,
-- added method '_e_fm2_operation_abort_internal' that represent efm2
default handler of operation cancelling,
-- 'done' and 'total' fields of 'E_Fm2_Op_Registry_Entry' changed to
off_t type, also all message handlers modified to work with it
(to show progress for large files correctly),
-- improved file operation progress processing,
-- added cancel button to operation progress gadget in filemanager window,
-- added delete file glyph to operation progress gadget,
-- improved status message for efm2 operation progress.
3. Filemanager slave:
-- fixed critical bug in message handling via stdin/stdout,
-- fixed critical bug in removing task from list,
-- improved 'E_FM_OP_ABORT' handling,
-- fix rollback counting on moving files.
4. Fileman_opinfo module:
-- a new theme writed: status string and gadget for view operation status
in summary and detail modes,
-- summary mode: operation glyph, state message, progressbar, abort button,
-- detail mode: all for summary + from filename, to filename,
-- summary/detailed button works as trigger,
-- added source of module theme and used images.
4. Pathbar module:
-- non-critical fix, just for safety.
Also patch contains several minor updates to serve main task.
SVN revision: 41224
14 years ago
|
|
|
_e_fm_op_task_free(ltask);
|
|
|
|
task->link = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handles data from STDIN.
|
|
|
|
* Received data must be in this format:
|
|
|
|
* 1) (int) magic number,
|
|
|
|
* 2) (int) id,
|
|
|
|
* 3) (int) message length.
|
|
|
|
* Right now message length is always 0. Id is what matters.
|
|
|
|
*
|
|
|
|
* This function uses a couple of static variables and a global
|
|
|
|
* variable _e_fm_op_stdin_buffer to deal with a situation, when read()
|
|
|
|
* did not actually read enough data.
|
|
|
|
*/
|
|
|
|
static Eina_Bool
|
|
|
|
_e_fm_op_stdin_data(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
static char *buf = NULL;
|
|
|
|
static int length = 0;
|
|
|
|
char *begin = NULL;
|
|
|
|
ssize_t num = 0;
|
|
|
|
int msize, identity;
|
|
|
|
|
|
|
|
fd = ecore_main_fd_handler_fd_get(fd_handler);
|
|
|
|
if (!buf)
|
|
|
|
{
|
|
|
|
buf = _e_fm_op_stdin_buffer;
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
num = read(fd, buf, READBUFSIZE - length);
|
|
|
|
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
E_FM_OP_DEBUG("STDIN was closed. Abort. \n");
|
|
|
|
_e_fm_op_abort = 1;
|
|
|
|
}
|
|
|
|
else if (num < 0)
|
|
|
|
{
|
|
|
|
E_FM_OP_DEBUG("Error while reading from STDIN: read returned -1. (%s) Abort. \n", strerror(errno));
|
|
|
|
_e_fm_op_abort = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
length += num;
|
|
|
|
|
|
|
|
buf = _e_fm_op_stdin_buffer;
|
|
|
|
begin = _e_fm_op_stdin_buffer;
|
|
|
|
|
|
|
|
while (length >= ((int)(3 * sizeof(int))))
|
|
|
|
{
|
|
|
|
begin = buf;
|
|
|
|
|
|
|
|
/* Check magic. */
|
|
|
|
if (*((int *)(void *)buf) != E_FM_OP_MAGIC)
|
|
|
|
{
|
|
|
|
E_FM_OP_DEBUG("Error while reading from STDIN: magic is not correct!\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
buf += sizeof(int);
|
|
|
|
|
|
|
|
/* Read indentifying data. */
|
|
|
|
memcpy(&identity, buf, sizeof(int));
|
|
|
|
buf += sizeof(int);
|
|
|
|
|
|
|
|
/* Read message length. */
|
|
|
|
memcpy(&msize, buf, sizeof(int));
|
|
|
|
buf += sizeof(int);
|
|
|
|
|
|
|
|
if ((length - 3 * (int)sizeof(int)) < msize)
|
|
|
|
{
|
|
|
|
/* There is not enough data to read the whole message. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
length -= (3 * sizeof(int));
|
|
|
|
|
|
|
|
/* You may want to read msize bytes of data too,
|
|
|
|
* but currently commands here do not have any data.
|
|
|
|
* msize is always 0.
|
|
|
|
*/
|
|
|
|
switch (identity)
|
|
|
|
{
|
|
|
|
case E_FM_OP_ABORT:
|
|
|
|
_e_fm_op_abort = 1;
|
|
|
|
E_FM_OP_DEBUG("Aborted.\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_FM_OP_ERROR_RESPONSE_ABORT:
|
|
|
|
case E_FM_OP_ERROR_RESPONSE_IGNORE_THIS:
|
|
|
|
case E_FM_OP_ERROR_RESPONSE_IGNORE_ALL:
|
|
|
|
case E_FM_OP_ERROR_RESPONSE_RETRY:
|
|
|
|
_e_fm_op_error_response = identity;
|
|
|
|
_e_fm_op_set_up_idlers();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_FM_OP_OVERWRITE_RESPONSE_NO:
|
|
|
|
case E_FM_OP_OVERWRITE_RESPONSE_NO_ALL:
|
|
|
|
case E_FM_OP_OVERWRITE_RESPONSE_YES:
|
|
|
|
case E_FM_OP_OVERWRITE_RESPONSE_YES_ALL:
|
|
|
|
_e_fm_op_overwrite_response = identity;
|
|
|
|
_e_fm_op_set_up_idlers();
|
|
|
|
E_FM_OP_DEBUG("Overwrite response set.\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (length > 0) memmove(_e_fm_op_stdin_buffer, begin, length);
|
|
|
|
buf = _e_fm_op_stdin_buffer + length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_e_fm_op_set_up_idlers()
|
|
|
|
{
|
|
|
|
if (!_e_fm_op_scan_idler_p)
|
|
|
|
_e_fm_op_scan_idler_p = ecore_idler_add(_e_fm_op_scan_idler, NULL);
|
|
|
|
if (!_e_fm_op_work_idler_p)
|
|
|
|
_e_fm_op_work_idler_p = ecore_idler_add(_e_fm_op_work_idler, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_e_fm_op_delete_idler(int *mark)
|
|
|
|
{
|
|
|
|
if (mark == &_e_fm_op_work_error)
|
|
|
|
{
|
|
|
|
ecore_idler_del(_e_fm_op_work_idler_p);
|
|
|
|
_e_fm_op_work_idler_p = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ecore_idler_del(_e_fm_op_scan_idler_p);
|
|
|
|
_e_fm_op_scan_idler_p = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Code to deal with overwrites and errors in idlers.
|
|
|
|
* Basically, it checks if we got a response.
|
|
|
|
* Returns 1 if we did; otherwise checks it and does what needs to be done.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
_e_fm_op_idler_handle_error(int *mark, Eina_List **queue, Eina_List **node, E_Fm_Op_Task *task)
|
|
|
|
{
|
|
|