3 #ifndef _FILE_OFFSET_BITS
4 #define _FILE_OFFSET_BITS 64
15 #include <sys/types.h>
18 #include <sys/param.h>
31 #include <Ecore_Ipc.h>
32 #include <Ecore_File.h>
37 #include <eina_stringshare.h>
41 //#include "e_fm_shared_c.h"
45 #define DEF_SYNC_NUM 8
46 #define DEF_ROUND_TRIP 0.05
47 #define DEF_ROUND_TRIP_TOLERANCE 0.01
48 #define DEF_MOD_BACKOFF 0.2
50 typedef struct _E_Dir E_Dir;
51 typedef struct _E_Fop E_Fop;
52 typedef struct _E_Mod E_Mod;
53 typedef struct _e_fm_ipc_slave E_Fm_Slave;
54 typedef struct _E_Fm_Task E_Fm_Task;
60 Ecore_File_Monitor *mon;
69 Eina_List *recent_mods;
70 Ecore_Timer *recent_clean;
71 unsigned char cleaning : 1;
82 unsigned char del_after : 1;
83 unsigned char gone_bad : 1;
92 unsigned char add : 1;
93 unsigned char del : 1;
94 unsigned char mod : 1;
95 unsigned char done : 1;
98 struct _e_fm_ipc_slave
117 /* local subsystem globals */
118 Ecore_Ipc_Server *_e_fm_ipc_server = NULL;
120 static Eina_List *_e_dirs = NULL;
121 static Eina_List *_e_fops = NULL;
122 static int _e_sync_num = 0;
125 static Eina_List *_e_fm_ipc_slaves = NULL;
126 static Eina_List *_e_fm_tasks = NULL;
128 /* local subsystem functions */
129 static Eina_Bool _e_fm_ipc_cb_server_add(void *data, int type, void *event);
130 static Eina_Bool _e_fm_ipc_cb_server_del(void *data, int type, void *event);
131 static Eina_Bool _e_fm_ipc_cb_server_data(void *data, int type, void *event);
133 static void _e_fm_ipc_monitor_start(int id, const char *path);
134 static void _e_fm_ipc_monitor_start_try(E_Fm_Task *task);
135 static void _e_fm_ipc_monitor_end(int id, const char *path);
136 static E_Fm_Task *_e_fm_ipc_task_get(int id);
137 static Eina_List *_e_fm_ipc_task_node_get(int id);
138 static void _e_fm_ipc_task_remove(E_Fm_Task *task);
139 static void _e_fm_ipc_mkdir_try(E_Fm_Task *task);
140 static void _e_fm_ipc_mkdir(int id, const char *src, const char *rel, int rel_to, int x, int y);
141 static void _e_fm_ipc_handle_error_response(int id, E_Fm_Op_Type type);
143 static int _e_fm_ipc_client_send(int id, E_Fm_Op_Type type, void *data, int size);
145 static int _e_fm_ipc_slave_run(E_Fm_Op_Type type, const char *args, int id);
146 static E_Fm_Slave *_e_fm_ipc_slave_get(int id);
147 static int _e_fm_ipc_slave_send(E_Fm_Slave *slave, E_Fm_Op_Type type, void *data, int size);
149 static void _e_fm_ipc_cb_file_monitor(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path);
150 static Eina_Bool _e_fm_ipc_cb_recent_clean(void *data);
152 static void _e_fm_ipc_file_add_mod(E_Dir *ed, const char *path, E_Fm_Op_Type op, int listing);
153 static void _e_fm_ipc_file_add(E_Dir *ed, const char *path, int listing);
154 static void _e_fm_ipc_file_del(E_Dir *ed, const char *path);
155 static void _e_fm_ipc_file_mod(E_Dir *ed, const char *path);
156 static void _e_fm_ipc_file_mon_dir_del(E_Dir *ed, const char *path);
157 static void _e_fm_ipc_file_mon_list_sync(E_Dir *ed);
159 static Eina_Bool _e_fm_ipc_cb_file_mon_list_idler(void *data);
160 static Eina_Bool _e_fm_ipc_cb_fop_trash_idler(void *data);
161 static char *_e_str_list_remove(Eina_List **list, char *str);
162 static void _e_fm_ipc_reorder(const char *file, const char *dst, const char *relative, int after);
163 static void _e_fm_ipc_dir_del(E_Dir *ed);
165 static const char *_e_fm_ipc_prepare_command(E_Fm_Op_Type type, const char *args);
168 /* local subsystem functions */
174 sdir = getenv("E_IPC_SOCKET");
177 printf("The E_IPC_SOCKET environment variable is not set. This is\n"
178 "exported by Enlightenment to all processes it launches.\n"
179 "This environment variable must be set and must point to\n"
180 "Enlightenment's IPC socket file (minus port number).\n");
183 _e_fm_ipc_server = ecore_ipc_server_connect(ECORE_IPC_LOCAL_SYSTEM, sdir, 0, NULL);
184 if (!_e_fm_ipc_server)
186 printf("Cannot connect to enlightenment - abort\n");
190 ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _e_fm_ipc_cb_server_add, NULL);
191 ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _e_fm_ipc_cb_server_del, NULL);
192 ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _e_fm_ipc_cb_server_data, NULL);
198 _e_fm_ipc_cb_server_add(void *data __UNUSED__, int type __UNUSED__, void *event)
200 Ecore_Ipc_Event_Server_Add *e;
203 ecore_ipc_server_send(e->server,
204 6/*E_IPC_DOMAIN_FM*/,
206 0, 0, 0, NULL, 0); /* send hello */
207 return ECORE_CALLBACK_PASS_ON;
211 _e_fm_ipc_cb_server_del(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
214 ecore_main_loop_quit();
215 return ECORE_CALLBACK_PASS_ON;
219 _e_fm_ipc_monitor_start(int id, const char *path)
221 E_Fm_Task *task = malloc(sizeof(E_Fm_Task));
226 task->type = E_FM_OP_MONITOR_START;
228 task->src = eina_stringshare_add(path);
235 _e_fm_tasks = eina_list_append(_e_fm_tasks, task);
237 _e_fm_ipc_monitor_start_try(task);
241 _e_fm_ipc_monitor_start_try(E_Fm_Task *task)
243 E_Dir *ed, *ped = NULL;
248 /* look for any previous dir entries monitoring this dir */
249 EINA_LIST_FOREACH(_e_dirs, l, ed)
251 if ((ed->mon) && (!strcmp(ed->dir, task->src)))
253 /* found a previous dir - save it in ped */
259 /* open the dir to list */
260 dir = opendir(task->src);
263 char buf[PATH_MAX + 4096];
265 snprintf(buf, sizeof(buf), "Cannot open directory '%s': %s.", task->src, strerror(errno));
266 _e_fm_ipc_client_send(task->id, E_FM_OP_ERROR_RETRY_ABORT, buf, strlen(buf) + 1);
270 Eina_List *files = NULL;
276 /* create a new dir entry */
277 ed = calloc(1, sizeof(E_Dir));
279 ed->dir = eina_stringshare_add(task->src);
282 /* if no previous monitoring dir exists - this one
283 * becomes the master monitor enty */
284 ed->mon = ecore_file_monitor_add(ed->dir, _e_fm_ipc_cb_file_monitor, ed);
289 /* an existing monitor exists - ref it up */
293 _e_dirs = eina_list_append(_e_dirs, ed);
295 /* read everything except a .order, . and .. */
296 while ((dp = readdir(dir)))
298 if ((!strcmp(dp->d_name, ".")) || (!strcmp(dp->d_name, "..")))
300 if (!strcmp(dp->d_name, ".order"))
305 files = eina_list_append(files, strdup(dp->d_name));
308 /* if there was a .order - we need to parse it */
311 snprintf(buf, sizeof(buf), "%s/.order", task->src);
315 Eina_List *f2 = NULL;
319 /* inset files in order if the existed in file
321 while (fgets(buf, sizeof(buf), f))
324 if (len > 0) buf[len - 1] = 0;
325 s = _e_str_list_remove(&files, buf);
326 if (s) f2 = eina_list_append(f2, s);
329 /* append whats left */
330 files = eina_list_merge(f2, files);
334 /* FIXME: if .order file- load it, sort all items int it
335 * that are in files then just append whatever is left in
338 /* FIXME: maybe one day we can sort files here and handle
339 * .order file stuff here - but not today
341 /* note that we had a .order at all */
342 ed->dot_order = dot_order;
345 /* if we did - tell the E about this FIRST - it will
346 * decide what to do if it first sees a .order or not */
347 if (!strcmp(task->src, "/"))
348 snprintf(buf, sizeof(buf), "/.order");
350 snprintf(buf, sizeof(buf), "%s/.order", task->src);
351 if (eina_list_count(files) == 1)
352 _e_fm_ipc_file_add(ed, buf, 2);
354 _e_fm_ipc_file_add(ed, buf, 1);
356 /* send empty file - indicate empty dir */
357 if (!files) _e_fm_ipc_file_add(ed, "", 2);
358 /* and in an idler - list files, statting them etc. */
359 ed->idler = ecore_idler_add(_e_fm_ipc_cb_file_mon_list_idler, ed);
360 ed->sync_num = DEF_SYNC_NUM;
365 _e_fm_ipc_monitor_end(int id, const char *path)
371 EINA_LIST_FOREACH(_e_dirs, l, ed)
372 /* look for the dire entry to stop monitoring */
373 if ((id == ed->id) && (!strcmp(ed->dir, path)))
375 /* if this is not the real monitoring node - unref the
379 /* unref original monitor node */
380 ed->mon_real->mon_ref--;
381 if (ed->mon_real->mon_ref == 0)
383 /* original is at 0 ref - free it */
384 _e_fm_ipc_dir_del(ed->mon_real);
388 _e_fm_ipc_dir_del(ed);
390 /* this is a core monitoring node - remove ref */
394 /* we are the last ref - free */
395 if (ed->mon_ref == 0) _e_fm_ipc_dir_del(ed);
397 /* remove from dirs list anyway */
398 _e_dirs = eina_list_remove_list(_e_dirs, l);
402 task = _e_fm_ipc_task_get(id);
403 if (task) _e_fm_ipc_task_remove(task);
407 _e_fm_ipc_task_get(int id)
409 Eina_List *l = _e_fm_ipc_task_node_get(id);
411 return (E_Fm_Task *)eina_list_data_get(l);
415 _e_fm_ipc_task_node_get(int id)
420 EINA_LIST_FOREACH(_e_fm_tasks, l, task)
428 _e_fm_ipc_task_remove(E_Fm_Task *task)
430 Eina_List *l = _e_fm_ipc_task_node_get(task->id);
434 case E_FM_OP_MONITOR_START:
438 /* we can't open the dir - tell E the dir is deleted as
439 * * we can't look in it */
440 memset(&ted, 0, sizeof(E_Dir));
442 _e_fm_ipc_file_mon_dir_del(&ted, task->src);
449 _e_fm_tasks = eina_list_remove_list(_e_fm_tasks, l);
451 if (task->src) eina_stringshare_del(task->src);
452 if (task->dst) eina_stringshare_del(task->dst);
453 if (task->rel) eina_stringshare_del(task->rel);
459 _e_fm_ipc_mkdir_try(E_Fm_Task *task)
461 char buf[PATH_MAX + 4096];
463 if (mkdir(task->src, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0)
465 snprintf(buf, sizeof(buf), "Cannot make directory '%s': %s.", task->src, strerror(errno));
466 _e_fm_ipc_client_send(task->id, E_FM_OP_ERROR_RETRY_ABORT, buf, strlen(buf) + 1);
470 _e_fm_ipc_reorder(ecore_file_file_get(task->src), ecore_file_dir_get(task->src), task->rel, task->rel_to);
471 _e_fm_ipc_task_remove(task);
476 _e_fm_ipc_mkdir(int id, const char *src, const char *rel, int rel_to __UNUSED__, int x, int y)
480 task = malloc(sizeof(E_Fm_Task));
483 task->type = E_FM_OP_MKDIR;
485 task->src = eina_stringshare_add(src);
487 task->rel = eina_stringshare_add(rel);
491 _e_fm_tasks = eina_list_append(_e_fm_tasks, task);
493 _e_fm_ipc_mkdir_try(task);
497 _e_fm_ipc_handle_error_response(int id, E_Fm_Op_Type type)
499 E_Fm_Task *task = _e_fm_ipc_task_get(id);
500 E_Fm_Slave *slave = NULL;
504 slave = _e_fm_ipc_slave_get(id);
505 if (slave) _e_fm_ipc_slave_send(slave, type, NULL, 0);
509 if (type == E_FM_OP_ERROR_RESPONSE_ABORT)
511 _e_fm_ipc_task_remove(task);
513 else if (type == E_FM_OP_ERROR_RESPONSE_RETRY)
518 _e_fm_ipc_mkdir_try(task);
521 case E_FM_OP_MONITOR_START:
522 _e_fm_ipc_monitor_start_try(task);
531 _e_fm_ipc_cb_server_data(void *data __UNUSED__, int type __UNUSED__, void *event)
533 Ecore_Ipc_Event_Server_Data *e;
536 if (e->major != 6/*E_IPC_DOMAIN_FM*/) return ECORE_CALLBACK_PASS_ON;
539 case E_FM_OP_MONITOR_START: /* monitor dir (and implicitly list) */
541 _e_fm_ipc_monitor_start(e->ref, e->data);
544 case E_FM_OP_MONITOR_END: /* monitor dir end */
546 // printf("End listing directory: %s\n", e->data);
547 _e_fm_ipc_monitor_end(e->ref, e->data);
550 case E_FM_OP_REMOVE: /* fop delete file/dir */
552 _e_fm_ipc_slave_run(E_FM_OP_REMOVE, (const char *)e->data, e->ref);
555 case E_FM_OP_TRASH: /* fop trash file/dir */
559 fop = calloc(1, sizeof(E_Fop));
563 fop->src = eina_stringshare_add(e->data);
564 _e_fops = eina_list_append(_e_fops, fop);
565 fop->idler = ecore_idler_add(_e_fm_ipc_cb_fop_trash_idler, fop);
569 case E_FM_OP_MOVE: /* fop mv file/dir */
571 _e_fm_ipc_slave_run(E_FM_OP_MOVE, (const char *)e->data, e->ref);
574 case E_FM_OP_COPY: /* fop cp file/dir */
576 _e_fm_ipc_slave_run(E_FM_OP_COPY, (const char *)e->data, e->ref);
579 case E_FM_OP_SYMLINK: /* fop ln -s */
581 _e_fm_ipc_slave_run(E_FM_OP_SYMLINK, (const char *)e->data, e->ref);
584 case E_FM_OP_MKDIR: /* fop mkdir */
586 const char *src, *rel;
590 rel = src + strlen(src) + 1;
591 memcpy(&rel_to, rel + strlen(rel) + 1, sizeof(int));
592 memcpy(&x, rel + strlen(rel) + 1 + sizeof(int), sizeof(int));
593 memcpy(&y, rel + strlen(rel) + 1 + sizeof(int), sizeof(int));
595 _e_fm_ipc_mkdir(e->ref, src, rel, rel_to, x, y);
598 case E_FM_OP_MOUNT: /* mount udi mountpoint */
601 const char *udi, *mountpoint;
604 mountpoint = udi + strlen(udi) + 1;
605 v = e_volume_find(udi);
606 // printf("REQ M %p (find from %s -> %s)\n", v, udi, mountpoint); fflush(stdout);
611 if (v->mount_point) eina_stringshare_del(v->mount_point);
612 v->mount_point = eina_stringshare_add(mountpoint);
618 case E_FM_OP_UNMOUNT:/* unmount udi */
624 v = e_volume_find(udi);
627 // printf("REQ UM\n"); fflush(stdout);
632 case E_FM_OP_EJECT:/* eject udi */
638 v = e_volume_find(udi);
643 case E_FM_OP_QUIT: /* quit */
644 ecore_main_loop_quit();
646 case E_FM_OP_MONITOR_SYNC: /* mon list sync */
652 EINA_LIST_FOREACH(_e_dirs, l, ed)
656 if (ed->sync == e->response)
658 stime = ecore_time_get() - ed->sync_time;
659 /* try keep round trips to round trip tolerance */
661 (stime < (DEF_ROUND_TRIP - DEF_ROUND_TRIP_TOLERANCE))
664 (stime > (DEF_ROUND_TRIP + DEF_ROUND_TRIP_TOLERANCE))
666 /* always sync at least 1 file */
667 if (ed->sync_num < 1) ed->sync_num = 1;
668 ed->idler = ecore_idler_add(_e_fm_ipc_cb_file_mon_list_idler, ed);
675 case E_FM_OP_ABORT: // abort copy/move/delete operation by user
677 E_Fm_Slave *slave = _e_fm_ipc_slave_get(e->ref);
679 _e_fm_ipc_slave_send(slave, e->minor, NULL, 0);
682 case E_FM_OP_ERROR_RESPONSE_IGNORE_THIS:
683 case E_FM_OP_ERROR_RESPONSE_IGNORE_ALL:
684 case E_FM_OP_ERROR_RESPONSE_ABORT:
685 case E_FM_OP_ERROR_RESPONSE_RETRY:
687 _e_fm_ipc_handle_error_response(e->ref, e->minor);
690 case E_FM_OP_OVERWRITE_RESPONSE_NO:
691 case E_FM_OP_OVERWRITE_RESPONSE_NO_ALL:
692 case E_FM_OP_OVERWRITE_RESPONSE_YES:
693 case E_FM_OP_OVERWRITE_RESPONSE_YES_ALL:
695 _e_fm_ipc_slave_send(_e_fm_ipc_slave_get(e->ref), e->minor, NULL, 0);
698 case E_FM_OP_REORDER:
700 const char *file, *dst, *relative;
705 p += strlen(file) + 1;
708 p += strlen(dst) + 1;
711 p += strlen(relative) + 1;
715 _e_fm_ipc_reorder(file, dst, relative, after);
721 /* always send back an "OK" for each request so e can basically keep a
722 * count of outstanding requests - maybe for balancing between fm
723 * slaves later. ref_to is set to the the ref id in the request to
724 * allow for async handling later */
725 ecore_ipc_server_send(_e_fm_ipc_server,
726 6/*E_IPC_DOMAIN_FM*/,
728 0, e->ref, 0, NULL, 0);
729 return ECORE_CALLBACK_PASS_ON;
732 static int _e_fm_ipc_client_send(int id, E_Fm_Op_Type type, void *data, int size)
734 return ecore_ipc_server_send(_e_fm_ipc_server,
735 6/*E_IPC_DOMAIN_FM*/,
737 id, 0, 0, data, size);
740 static int _e_fm_ipc_slave_run(E_Fm_Op_Type type, const char *args, int id)
745 slave = malloc(sizeof(E_Fm_Slave));
747 if (!slave) return 0;
749 command = eina_stringshare_add(_e_fm_ipc_prepare_command(type, args));
752 slave->exe = ecore_exe_pipe_run(command, ECORE_EXE_PIPE_WRITE | ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR, slave );
753 // printf("EFM command: %s\n", command);
755 eina_stringshare_del(command);
757 _e_fm_ipc_slaves = eina_list_append(_e_fm_ipc_slaves, slave);
759 return (!!slave->exe);
762 static E_Fm_Slave *_e_fm_ipc_slave_get(int id)
767 EINA_LIST_FOREACH(_e_fm_ipc_slaves, l, slave)
776 static int _e_fm_ipc_slave_send(E_Fm_Slave *slave, E_Fm_Op_Type type, void *data, int size)
780 int magic = E_FM_OP_MAGIC;
783 ssize = 3 * sizeof(int) + size;
784 sdata = malloc(ssize);
786 if (!sdata) return 0;
788 memcpy(sdata, &magic, sizeof(int));
789 memcpy(sdata + sizeof(int), &type, sizeof(E_Fm_Op_Type));
790 memcpy(sdata + sizeof(int) + sizeof(E_Fm_Op_Type), &size, sizeof(int));
792 memcpy(sdata + 2 * sizeof(int) + sizeof(E_Fm_Op_Type), data, size);
794 result = ecore_exe_send(slave->exe, sdata, ssize);
802 _e_fm_ipc_slave_data_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
804 Ecore_Exe_Event_Data *e = event;
810 if (!e) return ECORE_CALLBACK_PASS_ON;
812 slave = ecore_exe_data_get(e->exe);
813 if (!slave) return ECORE_CALLBACK_RENEW;
818 while ((unsigned int)ssize >= 3 * sizeof(int))
820 memcpy(&magic, sdata, sizeof(int));
821 memcpy(&id, sdata + sizeof(int), sizeof(int));
822 memcpy(&size, sdata + sizeof(int) + sizeof(int), sizeof(int));
824 if (magic != E_FM_OP_MAGIC)
826 printf("%s:%s(%d) Wrong magic number from slave #%d. ", __FILE__, __FUNCTION__, __LINE__, slave->id);
830 sdata += 3 * sizeof(int);
831 ssize -= 3 * sizeof(int);
833 if (id == E_FM_OP_OVERWRITE)
835 _e_fm_ipc_client_send(slave->id, E_FM_OP_OVERWRITE, sdata, size);
836 printf("%s:%s(%d) Overwrite sent to client from slave #%d.\n", __FILE__, __FUNCTION__, __LINE__, slave->id);
838 else if (id == E_FM_OP_ERROR)
840 _e_fm_ipc_client_send(slave->id, E_FM_OP_ERROR, sdata, size);
842 else if (id == E_FM_OP_PROGRESS)
844 _e_fm_ipc_client_send(slave->id, E_FM_OP_PROGRESS, sdata, size);
851 return ECORE_CALLBACK_PASS_ON;
855 _e_fm_ipc_slave_error_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
857 Ecore_Exe_Event_Data *e = event;
862 slave = ecore_exe_data_get(e->exe);
863 if (!slave) return ECORE_CALLBACK_RENEW;
865 printf("EFM: Data from STDERR of slave #%d: %.*s", slave->id, e->size, (char *)e->data);
871 _e_fm_ipc_slave_del_cb(void *data __UNUSED__, int type __UNUSED__, void *event)
873 Ecore_Exe_Event_Del *e = event;
878 slave = ecore_exe_data_get(e->exe);
879 if (!slave) return 1;
880 _e_fm_ipc_client_send(slave->id, E_FM_OP_QUIT, NULL, 0);
882 _e_fm_ipc_slaves = eina_list_remove(_e_fm_ipc_slaves, (void *)slave);
889 _e_fm_ipc_cb_file_monitor(void *data __UNUSED__, Ecore_File_Monitor *em __UNUSED__, Ecore_File_Event event, const char *path)
892 char *dir, *rp, *drp;
895 dir = ecore_file_dir_get(path);
896 /* FIXME: get no create events if dir is empty */
897 if ((event == ECORE_FILE_EVENT_CREATED_FILE) ||
898 (event == ECORE_FILE_EVENT_CREATED_DIRECTORY))
900 rp = ecore_file_realpath(dir);
901 EINA_LIST_FOREACH(_e_dirs, l, ed)
903 drp = ecore_file_realpath(ed->dir);
906 if (!strcmp(rp, drp))
907 _e_fm_ipc_file_add(ed, path, 0);
913 else if ((event == ECORE_FILE_EVENT_DELETED_FILE) ||
914 (event == ECORE_FILE_EVENT_DELETED_DIRECTORY))
916 rp = ecore_file_realpath(dir);
917 EINA_LIST_FOREACH(_e_dirs, l, ed)
919 drp = ecore_file_realpath(ed->dir);
922 if (!strcmp(rp, drp))
923 _e_fm_ipc_file_del(ed, path);
929 else if (event == ECORE_FILE_EVENT_MODIFIED)
931 rp = ecore_file_realpath(dir);
932 EINA_LIST_FOREACH(_e_dirs, l, ed)
934 drp = ecore_file_realpath(ed->dir);
937 if (!strcmp(rp, drp))
938 _e_fm_ipc_file_mod(ed, path);
944 else if (event == ECORE_FILE_EVENT_DELETED_SELF)
946 rp = ecore_file_realpath(path);
947 EINA_LIST_FOREACH(_e_dirs, l, ed)
949 drp = ecore_file_realpath(ed->dir);
952 if (!strcmp(rp, drp))
953 _e_fm_ipc_file_mon_dir_del(ed, path);
963 _e_fm_ipc_cb_recent_clean(void *data)
972 t_now = ecore_time_unix_get();
973 EINA_LIST_FOREACH_SAFE(ed->recent_mods, pl, l, m)
974 if ((m->mod) && ((t_now - m->timestamp) >= DEF_MOD_BACKOFF))
976 ed->recent_mods = eina_list_remove_list(ed->recent_mods, pl);
977 if (!m->done) _e_fm_ipc_file_add_mod(ed, m->path, 5, 0);
978 eina_stringshare_del(m->path);
982 if (ed->recent_mods) return ECORE_CALLBACK_RENEW;
983 ed->recent_clean = NULL;
984 return ECORE_CALLBACK_CANCEL;
989 _e_fm_ipc_file_add_mod(E_Dir *ed, const char *path, E_Fm_Op_Type op, int listing)
992 char *lnk = NULL, *rlnk = NULL;
995 unsigned char *p, buf
996 /* file add/change format is as follows:
998 * stat_info[stat size] + broken_link[1] + path[n]\0 + lnk[n]\0 + rlnk[n]\0 */
999 [sizeof(struct stat) + 1 + 4096 + 4096 + 4096];
1001 /* FIXME: handle BACKOFF */
1002 if ((!listing) && (op == E_FM_OP_FILE_CHANGE) && (!ed->cleaning)) /* 5 == mod */
1009 t_now = ecore_time_unix_get();
1010 EINA_LIST_FOREACH(ed->recent_mods, l, m)
1012 if ((m->mod) && (!strcmp(m->path, path)))
1014 if ((t_now - m->timestamp) < DEF_MOD_BACKOFF)
1023 m = calloc(1, sizeof(E_Mod));
1024 m->path = eina_stringshare_add(path);
1027 m->timestamp = t_now;
1028 ed->recent_mods = eina_list_append(ed->recent_mods, m);
1030 if ((!ed->recent_clean) && (ed->recent_mods))
1031 ed->recent_clean = ecore_timer_add(DEF_MOD_BACKOFF, _e_fm_ipc_cb_recent_clean, ed);
1034 // printf("SKIP MOD %s %3.3f\n", path, t_now);
1038 // printf("MOD %s %3.3f\n", path, ecore_time_unix_get());
1039 lnk = ecore_file_readlink(path);
1040 memset(&st, 0, sizeof(struct stat));
1041 if (stat(path, &st) == -1)
1043 if ((path[0] == 0) || (lnk)) broken_lnk = 1;
1046 if ((lnk) && (lnk[0] != '/')) rlnk = ecore_file_realpath(path);
1047 else if (lnk) rlnk = strdup(lnk);
1048 if (!lnk) lnk = strdup("");
1049 if (!rlnk) rlnk = strdup("");
1052 /* NOTE: i am NOT converting this data to portable arch/os independent
1053 * format. i am ASSUMING e_fm_main and e are local and built together
1054 * and thus this will work. if this ever changes this here needs to
1056 memcpy(buf, &st, sizeof(struct stat));
1057 p += sizeof(struct stat);
1062 strcpy((char *)p, path);
1063 p += strlen(path) + 1;
1065 strcpy((char *)p, lnk);
1066 p += strlen(lnk) + 1;
1068 strcpy((char *)p, rlnk);
1069 p += strlen(rlnk) + 1;
1072 ecore_ipc_server_send(_e_fm_ipc_server, 6/*E_IPC_DOMAIN_FM*/, op, 0, ed->id,
1075 if (rlnk) free(rlnk);
1079 _e_fm_ipc_file_add(E_Dir *ed, const char *path, int listing)
1083 /* FIXME: handle BACKOFF */
1085 _e_fm_ipc_file_add_mod(ed, path, E_FM_OP_FILE_ADD, listing);/*file add*/
1089 _e_fm_ipc_file_del(E_Dir *ed, const char *path)
1092 /* FIXME: handle BACKOFF */
1094 ecore_ipc_server_send(_e_fm_ipc_server,
1095 6/*E_IPC_DOMAIN_FM*/,
1097 0, ed->id, 0, (void *)path, strlen(path) + 1);
1101 _e_fm_ipc_file_mod(E_Dir *ed, const char *path)
1104 /* FIXME: handle BACKOFF */
1106 _e_fm_ipc_file_add_mod(ed, path, E_FM_OP_FILE_CHANGE, 0);/*file change*/
1110 _e_fm_ipc_file_mon_dir_del(E_Dir *ed, const char *path)
1112 ecore_ipc_server_send(_e_fm_ipc_server,
1113 6/*E_IPC_DOMAIN_FM*/,
1114 E_FM_OP_MONITOR_END,
1115 0, ed->id, 0, (void *)path, strlen(path) + 1);
1119 _e_fm_ipc_file_mon_list_sync(E_Dir *ed)
1122 if (_e_sync_num == 0) _e_sync_num = 1;
1123 ed->sync = _e_sync_num;
1124 ed->sync_time = ecore_time_get();
1125 ecore_ipc_server_send(_e_fm_ipc_server,
1126 6/*E_IPC_DOMAIN_FM*/,
1127 E_FM_OP_MONITOR_SYNC,
1128 0, ed->id, ed->sync, NULL, 0);
1132 _e_fm_ipc_cb_file_mon_list_idler(void *data)
1136 char *file, buf[4096];
1139 /* FIXME: spool off files in idlers and handle sync req's */
1142 file = eina_list_data_get(ed->fq);
1143 if (!((ed->dot_order) && (!strcmp(file, ".order"))))
1145 if (!strcmp(ed->dir, "/"))
1146 snprintf(buf, sizeof(buf), "/%s", file);
1148 snprintf(buf, sizeof(buf), "%s/%s", ed->dir, file);
1149 _e_fm_ipc_file_add(ed, buf, 1);
1152 ed->fq = eina_list_remove_list(ed->fq, ed->fq);
1154 if (n == ed->sync_num)
1156 _e_fm_ipc_file_mon_list_sync(ed);
1158 if (!ed->fq) _e_fm_ipc_file_add(ed, "", 2);
1162 ed->sync_num = DEF_SYNC_NUM;
1164 ed->sync_time = 0.0;
1166 if (!ed->fq) _e_fm_ipc_file_add(ed, "", 2);
1167 return ECORE_CALLBACK_CANCEL;
1171 _e_fm_ipc_cb_fop_trash_idler(void *data)
1175 const char *trash_dir = NULL;
1176 const char *filename = NULL;
1177 const char *escname = NULL;
1178 const char *dest = NULL;
1184 /* FIXME: For now, this will only implement 'home trash'
1185 * Later, implement mount/remote/removable device trash, if wanted. */
1187 fop = (E_Fop *)data;
1190 /* Check that 'home trash' and subsequesnt dirs exists, create if not */
1191 snprintf(buf, sizeof(buf), "%s/Trash", efreet_data_home_get());
1192 trash_dir = eina_stringshare_add(buf);
1193 snprintf(buf, sizeof(buf), "%s/files", trash_dir);
1194 if (!ecore_file_mkpath(buf)) return 0;
1195 snprintf(buf, sizeof(buf), "%s/info", trash_dir);
1196 if (!ecore_file_mkpath(buf)) return 0;
1198 filename = eina_stringshare_add(strrchr(fop->src, '/'));
1199 escname = ecore_file_escape_name(filename);
1200 eina_stringshare_del(filename);
1202 /* Find path for info file. Pointer address is part of the filename to
1203 * alleviate some of the looping in case of multiple filenames with the
1204 * same name. Also use the name of the file to help */
1207 snprintf(buf, sizeof(buf), "%s/file%s.%p.%u", trash_dir, escname,
1210 while (ecore_file_exists(buf));
1211 dest = eina_stringshare_add(buf);
1213 /* Try to move the file */
1214 if (rename(fop->src, dest))
1218 /* Move failed. Spec says delete files that can't be trashed */
1219 ecore_file_unlink(fop->src);
1220 return ECORE_CALLBACK_CANCEL;
1224 /* Move worked. Create info file */
1225 snprintf(buf, sizeof(buf), "%s/info%s.%p.%u.trashinfo", trash_dir,
1227 info = fopen(buf, "w");
1233 /* Insert info for trashed file */
1235 "[Trash Info]\nPath=%s\nDeletionDate=%04u%02u%02uT%02u:%02u:%02u",
1236 fop->src, lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday,
1237 lt->tm_hour, lt->tm_min, lt->tm_sec);
1241 /* Could not create info file. Spec says to put orig file back */
1242 rename(dest, fop->src);
1244 if (dest) eina_stringshare_del(dest);
1245 if (trash_dir) eina_stringshare_del(trash_dir);
1246 eina_stringshare_del(fop->src);
1247 eina_stringshare_del(fop->dst);
1249 _e_fops = eina_list_remove(_e_fops, fop);
1250 return ECORE_CALLBACK_CANCEL;
1254 _e_str_list_remove(Eina_List **list, char *str)
1259 EINA_LIST_FOREACH(*list, l, s)
1260 if (!strcmp(s, str))
1262 *list = eina_list_remove_list(*list, l);
1270 _e_fm_ipc_reorder(const char *file, const char *dst, const char *relative, int after)
1272 char buffer[PATH_MAX];
1273 char order[PATH_MAX];
1275 if (!file || !dst || !relative) return;
1276 if (after != 0 && after != 1 && after != 2) return;
1277 // printf("%s:%s(%d) Reorder:\n\tfile = %s\n\tdst = %s\n\trelative = %s\n\tafter = %d\n", __FILE__, __FUNCTION__, __LINE__, file, dst, relative, after);
1279 snprintf(order, sizeof(order), "%s/.order", dst);
1280 if (ecore_file_exists(order))
1283 Eina_List *files = NULL, *l;
1286 forder = fopen(order, "r");
1291 /* inset files in order if the existed in file
1293 while (fgets(buffer, sizeof(buffer), forder))
1295 len = strlen(buffer);
1296 if (len > 0) buffer[len - 1] = 0;
1297 files = eina_list_append(files, strdup(buffer));
1301 /* remove dest file from .order - if there */
1302 EINA_LIST_FOREACH(files, l, str)
1303 if (!strcmp(str, file))
1306 files = eina_list_remove_list(files, l);
1309 /* now insert dest into list or replace entry */
1310 EINA_LIST_FOREACH(files, l, str)
1312 if (!strcmp(str, relative))
1314 if (after == 2) /* replace */
1317 l->data = strdup(file);
1319 else if (after == 0) /* before */
1321 files = eina_list_prepend_relative_list(files, strdup(file), l);
1323 else if (after == 1) /* after */
1325 files = eina_list_append_relative_list(files, strdup(file), l);
1331 forder = fopen(order, "w");
1334 EINA_LIST_FREE(files, str)
1336 fprintf(forder, "%s\n", str);
1345 _e_fm_ipc_dir_del(E_Dir *ed)
1350 eina_stringshare_del(ed->dir);
1351 if (ed->idler) ecore_idler_del(ed->idler);
1352 if (ed->recent_clean)
1353 ecore_timer_del(ed->recent_clean);
1354 EINA_LIST_FREE(ed->recent_mods, m)
1356 eina_stringshare_del(m->path);
1359 EINA_LIST_FREE(ed->fq, data)
1365 _e_fm_ipc_prepare_command(E_Fm_Op_Type type, const char *args)
1368 unsigned int length = 0;
1371 if (type == E_FM_OP_MOVE)
1372 strcpy(command, "mv");
1373 else if (type == E_FM_OP_REMOVE)
1374 strcpy(command, "rm");
1375 else if (type == E_FM_OP_COPY)
1376 strcpy(command, "cp");
1377 else if (type == E_FM_OP_SYMLINK)
1378 strcpy(command, "lns");
1380 strcpy(command, "???");
1382 length = 256 + strlen(getenv("E_LIB_DIR")) + strlen(args);
1383 buffer = malloc(length);
1384 snprintf(buffer, length,
1385 "%s/enlightenment/utils/enlightenment_fm_op %s %s",
1386 getenv("E_LIB_DIR"), command, args);