1 /* EIO - EFL data type library
2  * Copyright (C) 2010 Enlightenment Developers:
3  *           Cedric Bail <cedric.bail@free.fr>
4  *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
5  *           Stephen "okra" Houston <UnixTitan@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library;
19  * if not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "eio_private.h"
23 #include "Eio.h"
24 
25 /*============================================================================*
26  *                                  Local                                     *
27  *============================================================================*/
28 
29 /**
30  * @cond LOCAL
31  */
32 
33 static void
_eio_file_heavy(void * data,Ecore_Thread * thread)34 _eio_file_heavy(void *data, Ecore_Thread *thread)
35 {
36    Eio_File_Char_Ls *async = data;
37    Eina_Iterator *ls;
38    const char *file;
39    Eina_List *pack = NULL;
40    double start;
41 
42    ls = eina_file_ls(async->ls.directory);
43    if (!ls)
44      {
45         eio_file_thread_error(&async->ls.common, thread);
46         return;
47      }
48 
49    eio_file_container_set(&async->ls.common, eina_iterator_container_get(ls));
50 
51    start = ecore_time_get();
52 
53    EINA_ITERATOR_FOREACH(ls, file)
54      {
55         Eina_Bool filter = EINA_TRUE;
56 
57         if (async->filter_cb)
58 	         {
59              filter = async->filter_cb((void*) async->ls.common.data, &async->ls.common, file);
60 	         }
61 
62         if (filter)
63           {
64              Eio_File_Char *send_fc;
65 
66              send_fc = eio_char_malloc();
67              if (!send_fc) goto on_error;
68 
69              send_fc->filename = file;
70 	            send_fc->associated = async->ls.common.worker.associated;
71              async->ls.common.worker.associated = NULL;
72 
73 	            pack = eina_list_append(pack, send_fc);
74           }
75         else
76           {
77 on_error:
78              eina_stringshare_del(file);
79 
80              if (async->ls.common.worker.associated)
81                {
82                   eina_hash_free(async->ls.common.worker.associated);
83                   async->ls.common.worker.associated = NULL;
84                }
85           }
86 
87         pack = eio_pack_send(thread, pack, &start);
88 
89         if (ecore_thread_check(thread))
90           break;
91      }
92 
93    if (pack) ecore_thread_feedback(thread, pack);
94 
95    async->ls.ls = ls;
96 }
97 
98 void
_eio_string_notify(void * data,Ecore_Thread * thread EINA_UNUSED,void * msg_data)99 _eio_string_notify(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data)
100 {
101    Eio_File_Char_Ls *async = data;
102    Eina_List *pack = msg_data;
103    Eio_File_Char *info;
104 
105    async->ls.common.length += eina_list_count(pack);
106 
107    // Check if it is an internal use
108    if (async->ls.gather)
109      {
110         Eina_Array *gather;
111 
112         gather = eina_array_new(eina_list_count(pack));
113         EINA_LIST_FREE(pack, info)
114           {
115              if (!gather)
116                eina_stringshare_del(info->filename);
117              else
118                eina_array_push(gather, info->filename);
119              eio_char_free(info);
120           }
121 
122         // transfer ownership to caller
123         async->main_internal_cb((void*) async->ls.common.data,
124                                 &async->ls.common,
125                                 gather);
126 
127         return ;
128      }
129 
130    EINA_LIST_FREE(pack, info)
131      {
132         async->ls.common.main.associated = info->associated;
133 
134         async->main_cb((void*) async->ls.common.data,
135                        &async->ls.common,
136                        info->filename);
137 
138         if (async->ls.common.main.associated)
139           {
140              eina_hash_free(async->ls.common.main.associated);
141              async->ls.common.main.associated = NULL;
142           }
143 
144         eina_stringshare_del(info->filename);
145         eio_char_free(info);
146      }
147 }
148 
149 static void
_eio_file_eina_ls_heavy(Ecore_Thread * thread,Eio_File_Direct_Ls * async,Eina_Iterator * ls)150 _eio_file_eina_ls_heavy(Ecore_Thread *thread, Eio_File_Direct_Ls *async, Eina_Iterator *ls)
151 {
152    const Eina_File_Direct_Info *info;
153    Eina_List *pack = NULL;
154    double start;
155 
156    if (!ls)
157      {
158         eio_file_thread_error(&async->ls.common, thread);
159         return;
160      }
161 
162    eio_file_container_set(&async->ls.common, eina_iterator_container_get(ls));
163 
164    start = ecore_time_get();
165 
166    EINA_ITERATOR_FOREACH(ls, info)
167      {
168         Eina_Bool filter = EINA_TRUE;
169 
170         if (async->filter_cb)
171           {
172              filter = async->filter_cb((void*) async->ls.common.data, &async->ls.common, info);
173           }
174 
175         if (filter)
176           {
177 	            Eio_File_Direct_Info *send_di;
178 
179              send_di = eio_direct_info_malloc();
180 	            if (!send_di) continue;
181 
182              memcpy(&send_di->info, info, sizeof (Eina_File_Direct_Info));
183              send_di->associated = async->ls.common.worker.associated;
184 	            async->ls.common.worker.associated = NULL;
185 
186              pack = eina_list_append(pack, send_di);
187 	         }
188         else if (async->ls.common.worker.associated)
189           {
190              eina_hash_free(async->ls.common.worker.associated);
191              async->ls.common.worker.associated = NULL;
192           }
193 
194         pack = eio_pack_send(thread, pack, &start);
195 
196         if (ecore_thread_check(thread))
197           break;
198      }
199 
200    if (pack) ecore_thread_feedback(thread, pack);
201 
202    async->ls.ls = ls;
203 }
204 
205 static void
_eio_file_direct_heavy(void * data,Ecore_Thread * thread)206 _eio_file_direct_heavy(void *data, Ecore_Thread *thread)
207 {
208    Eio_File_Direct_Ls *async = data;
209    Eina_Iterator *ls;
210 
211    ls = eina_file_direct_ls(async->ls.directory);
212 
213    _eio_file_eina_ls_heavy(thread, async, ls);
214 }
215 
216 static void
_eio_file_stat_heavy(void * data,Ecore_Thread * thread)217 _eio_file_stat_heavy(void *data, Ecore_Thread *thread)
218 {
219    Eio_File_Direct_Ls *async = data;
220    Eina_Iterator *ls;
221 
222    ls = eina_file_stat_ls(async->ls.directory);
223 
224    _eio_file_eina_ls_heavy(thread, async, ls);
225 }
226 
227 void
_eio_direct_notify(void * data,Ecore_Thread * thread EINA_UNUSED,void * msg_data)228 _eio_direct_notify(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data)
229 {
230    Eio_File_Direct_Ls *async = data;
231    Eina_List *pack = msg_data;
232    Eio_File_Direct_Info *info;
233 
234    async->ls.common.length += eina_list_count(pack);
235 
236    // Check if it is an internal use
237    if (async->ls.gather)
238      {
239         Eina_Array *gather;
240 
241         gather = eina_array_new(eina_list_count(pack));
242         EINA_LIST_FREE(pack, info)
243           eina_array_push(gather, &info->info);
244 
245         // transfer ownership to caller
246         async->main_internal_cb((void*) async->ls.common.data,
247                                 &async->ls.common,
248                                 gather);
249 
250         return ;
251      }
252 
253    EINA_LIST_FREE(pack, info)
254      {
255         async->ls.common.main.associated = info->associated;
256 
257         async->main_cb((void*) async->ls.common.data,
258                        &async->ls.common,
259                        &info->info);
260 
261         if (async->ls.common.main.associated)
262           {
263              eina_hash_free(async->ls.common.main.associated);
264              async->ls.common.main.associated = NULL;
265           }
266 
267         eio_direct_info_free(info);
268      }
269 }
270 
271 #ifndef MAP_HUGETLB
272 # define MAP_HUGETLB 0
273 #endif
274 
275 static void
_eio_file_copy_heavy(void * data,Ecore_Thread * thread)276 _eio_file_copy_heavy(void *data, Ecore_Thread *thread)
277 {
278    Eio_File_Progress *copy = data;
279 
280    eio_file_copy_do(thread, copy);
281 }
282 
283 static void
_eio_file_copy_notify(void * data,Ecore_Thread * thread EINA_UNUSED,void * msg_data)284 _eio_file_copy_notify(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data)
285 {
286    Eio_File_Progress *copy = data;
287 
288    eio_progress_cb(msg_data, copy);
289 }
290 
291 static void
_eio_file_copy_free(Eio_File_Progress * copy)292 _eio_file_copy_free(Eio_File_Progress *copy)
293 {
294    eina_stringshare_del(copy->source);
295    eina_stringshare_del(copy->dest);
296    eio_file_free(&copy->common);
297 }
298 
299 static void
_eio_file_copy_end(void * data,Ecore_Thread * thread EINA_UNUSED)300 _eio_file_copy_end(void *data, Ecore_Thread *thread EINA_UNUSED)
301 {
302    Eio_File_Progress *copy = data;
303 
304    copy->common.done_cb((void*) copy->common.data, &copy->common);
305 
306    _eio_file_copy_free(copy);
307 }
308 
309 static void
_eio_file_copy_error(void * data,Ecore_Thread * thread EINA_UNUSED)310 _eio_file_copy_error(void *data, Ecore_Thread *thread EINA_UNUSED)
311 {
312    Eio_File_Progress *copy = data;
313 
314    eio_file_error(&copy->common);
315 
316    _eio_file_copy_free(copy);
317 }
318 
319 static void
_eio_file_move_free(Eio_File_Move * move)320 _eio_file_move_free(Eio_File_Move *move)
321 {
322    eina_stringshare_del(move->progress.source);
323    eina_stringshare_del(move->progress.dest);
324    eio_file_free(&move->progress.common);
325 }
326 
327 static void
_eio_file_move_copy_progress(void * data,Eio_File * handler EINA_UNUSED,const Eio_Progress * info)328 _eio_file_move_copy_progress(void *data, Eio_File *handler EINA_UNUSED, const Eio_Progress *info)
329 {
330    Eio_File_Move *move = data;
331 
332    move->progress.progress_cb((void*) move->progress.common.data, &move->progress.common, info);
333 }
334 
335 static void
_eio_file_move_unlink_done(void * data,Eio_File * handler EINA_UNUSED)336 _eio_file_move_unlink_done(void *data, Eio_File *handler EINA_UNUSED)
337 {
338    Eio_File_Move *move = data;
339 
340    move->progress.common.done_cb((void*) move->progress.common.data, &move->progress.common);
341 
342    _eio_file_move_free(move);
343 }
344 
345 static void
_eio_file_move_unlink_error(void * data,Eio_File * handler EINA_UNUSED,int error)346 _eio_file_move_unlink_error(void *data, Eio_File *handler EINA_UNUSED, int error)
347 {
348    Eio_File_Move *move = data;
349 
350    move->copy = NULL;
351 
352    move->progress.common.error = error;
353    eio_file_error(&move->progress.common);
354 
355    _eio_file_move_free(move);
356 }
357 
358 static void
_eio_file_move_copy_done(void * data,Eio_File * handler EINA_UNUSED)359 _eio_file_move_copy_done(void *data, Eio_File *handler EINA_UNUSED)
360 {
361    Eio_File_Move *move = data;
362    Eio_File *rm;
363 
364    rm = eio_file_unlink(move->progress.source,
365 			_eio_file_move_unlink_done,
366 			_eio_file_move_unlink_error,
367 			move);
368    if (rm) move->copy = rm;
369 }
370 
371 static void
_eio_file_move_copy_error(void * data,Eio_File * handler EINA_UNUSED,int error)372 _eio_file_move_copy_error(void *data, Eio_File *handler EINA_UNUSED, int error)
373 {
374    Eio_File_Move *move = data;
375 
376    move->progress.common.error = error;
377    eio_file_error(&move->progress.common);
378 
379    _eio_file_move_free(move);
380 }
381 
382 static void
_eio_file_move_heavy(void * data,Ecore_Thread * thread)383 _eio_file_move_heavy(void *data, Ecore_Thread *thread)
384 {
385    Eio_File_Move *move = data;
386 
387    if (rename(move->progress.source, move->progress.dest) < 0)
388      eio_file_thread_error(&move->progress.common, thread);
389    else
390      eio_progress_send(thread, &move->progress, 1, 1);
391 }
392 
393 static void
_eio_file_move_notify(void * data,Ecore_Thread * thread EINA_UNUSED,void * msg_data)394 _eio_file_move_notify(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data)
395 {
396    Eio_File_Move *move = data;
397 
398    eio_progress_cb(msg_data, &move->progress);
399 }
400 
401 static void
_eio_file_move_end(void * data,Ecore_Thread * thread EINA_UNUSED)402 _eio_file_move_end(void *data, Ecore_Thread *thread EINA_UNUSED)
403 {
404    Eio_File_Move *move = data;
405 
406    move->progress.common.done_cb((void*) move->progress.common.data, &move->progress.common);
407 
408    _eio_file_move_free(move);
409 }
410 
411 static void
_eio_file_move_error(void * data,Ecore_Thread * thread EINA_UNUSED)412 _eio_file_move_error(void *data, Ecore_Thread *thread EINA_UNUSED)
413 {
414    Eio_File_Move *move = data;
415 
416    if (move->copy)
417      {
418         eio_file_cancel(move->copy);
419         return;
420      }
421 
422    if (move->progress.common.error == EXDEV)
423      {
424         Eio_File *eio_cp;
425 
426         eio_cp = eio_file_copy(move->progress.source, move->progress.dest,
427                                move->progress.progress_cb ? _eio_file_move_copy_progress : NULL,
428                                _eio_file_move_copy_done,
429                                _eio_file_move_copy_error,
430                                move);
431 
432         if (eio_cp)
433           {
434              move->copy = eio_cp;
435              move->progress.common.thread = ((Eio_File_Progress*)move->copy)->common.thread;
436              return;
437           }
438      }
439 
440    eio_file_error(&move->progress.common);
441 
442    _eio_file_move_free(move);
443 }
444 
445 /**
446  * @endcond
447  */
448 
449 
450 /*============================================================================*
451  *                                 Global                                     *
452  *============================================================================*/
453 
454 /**
455  * @cond LOCAL
456  */
457 
458 void
eio_progress_cb(Eio_Progress * progress,Eio_File_Progress * op)459 eio_progress_cb(Eio_Progress *progress, Eio_File_Progress *op)
460 {
461    op->progress_cb((void *) op->common.data, &op->common, progress);
462 
463    eio_progress_free(progress);
464 }
465 
466 static Eina_Bool
_eio_file_copy_progress(void * data,unsigned long long done,unsigned long long total)467 _eio_file_copy_progress(void *data, unsigned long long done, unsigned long long total)
468 {
469    void **ctx = data;
470    Ecore_Thread *thread = ctx[0];
471    Eio_File_Progress *copy = ctx[1];
472 
473    eio_progress_send(thread, copy, done, total);
474 
475    return !ecore_thread_check(thread);
476 }
477 
478 Eina_Bool
eio_file_copy_do(Ecore_Thread * thread,Eio_File_Progress * copy)479 eio_file_copy_do(Ecore_Thread *thread, Eio_File_Progress *copy)
480 {
481    void *ctx[2] = {thread, copy};
482    Eina_Bool ret = eina_file_copy(copy->source, copy->dest,
483                                   (EINA_FILE_COPY_PERMISSION |
484                                    EINA_FILE_COPY_XATTR),
485                                   _eio_file_copy_progress,
486                                   ctx);
487 
488    if (!ret)
489      {
490         eio_file_thread_error(&copy->common, thread);
491         return EINA_FALSE;
492      }
493 
494    return EINA_TRUE;
495 }
496 
497 void
eio_async_free(Eio_File_Ls * async)498 eio_async_free(Eio_File_Ls *async)
499 {
500    eina_stringshare_del(async->directory);
501    eio_file_free(&async->common);
502 }
503 
504 void
eio_async_end(void * data,Ecore_Thread * thread EINA_UNUSED)505 eio_async_end(void *data, Ecore_Thread *thread EINA_UNUSED)
506 {
507    Eio_File_Ls *async = data;
508 
509    async->common.done_cb((void*) async->common.data, &async->common);
510    eio_file_container_set(&async->common, NULL);
511    eina_iterator_free(async->ls);
512    eio_async_free(async);
513 }
514 
515 void
eio_async_error(void * data,Ecore_Thread * thread EINA_UNUSED)516 eio_async_error(void *data, Ecore_Thread *thread EINA_UNUSED)
517 {
518    Eio_File_Ls *async = data;
519 
520    eio_file_error(&async->common);
521 
522    eio_async_free(async);
523 }
524 
525 /**
526  * @endcond
527  */
528 
529 
530 /*============================================================================*
531  *                                   API                                      *
532  *============================================================================*/
533 static Eio_File *
_eio_file_internal_ls(const char * dir,Eio_Filter_Cb filter_cb,Eio_Main_Cb main_cb,Eio_Array_Cb main_internal_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)534 _eio_file_internal_ls(const char *dir,
535                       Eio_Filter_Cb filter_cb,
536                       Eio_Main_Cb main_cb,
537                       Eio_Array_Cb main_internal_cb,
538                       Eio_Done_Cb done_cb,
539                       Eio_Error_Cb error_cb,
540                       const void *data)
541 {
542    Eio_File_Char_Ls *async;
543 
544    EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
545    EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
546    EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
547 
548    async = eio_common_alloc(sizeof(Eio_File_Char_Ls));
549    EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL);
550 
551    async->ls.directory = eina_stringshare_add(dir);
552    async->filter_cb = filter_cb;
553    if (main_internal_cb)
554      {
555         async->main_internal_cb = main_internal_cb;
556         async->ls.gather = EINA_TRUE;
557      }
558    else
559      {
560         async->main_cb = main_cb;
561      }
562 
563    if (!eio_long_file_set(&async->ls.common,
564 			  done_cb,
565 			  error_cb,
566 			  data,
567 			  _eio_file_heavy,
568 			  _eio_string_notify,
569 			  eio_async_end,
570 			  eio_async_error))
571      return NULL;
572 
573    return &async->ls.common;
574 }
575 
576 EAPI Eio_File *
eio_file_ls(const char * dir,Eio_Filter_Cb filter_cb,Eio_Main_Cb main_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)577 eio_file_ls(const char *dir,
578 	    Eio_Filter_Cb filter_cb,
579 	    Eio_Main_Cb main_cb,
580 	    Eio_Done_Cb done_cb,
581 	    Eio_Error_Cb error_cb,
582 	    const void *data)
583 {
584    EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL);
585 
586    return _eio_file_internal_ls(dir, filter_cb, main_cb, NULL, done_cb, error_cb, data);
587 }
588 
589 Eio_File *
_eio_file_ls(const char * dir,Eio_Array_Cb main_internal_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)590 _eio_file_ls(const char *dir,
591              Eio_Array_Cb main_internal_cb,
592              Eio_Done_Cb done_cb,
593              Eio_Error_Cb error_cb,
594              const void *data)
595 {
596    EINA_SAFETY_ON_NULL_RETURN_VAL(main_internal_cb, NULL);
597 
598    return _eio_file_internal_ls(dir, NULL, NULL, main_internal_cb, done_cb, error_cb, data);
599 }
600 
601 static Eio_File *
_eio_file_direct_internal_ls(const char * dir,Eio_Filter_Direct_Cb filter_cb,Eio_Main_Direct_Cb main_cb,Eio_Array_Cb main_internal_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)602 _eio_file_direct_internal_ls(const char *dir,
603                              Eio_Filter_Direct_Cb filter_cb,
604                              Eio_Main_Direct_Cb main_cb,
605                              Eio_Array_Cb main_internal_cb,
606                              Eio_Done_Cb done_cb,
607                              Eio_Error_Cb error_cb,
608                              const void *data)
609 {
610    Eio_File_Direct_Ls *async;
611 
612    EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
613    EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
614    EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
615 
616    async = eio_common_alloc(sizeof(Eio_File_Direct_Ls));
617    EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL);
618 
619    async->ls.directory = eina_stringshare_add(dir);
620    async->filter_cb = filter_cb;
621    if (main_internal_cb)
622      {
623         async->main_internal_cb = main_internal_cb;
624         async->ls.gather = EINA_TRUE;
625      }
626    else
627      {
628         async->main_cb = main_cb;
629      }
630 
631    if (!eio_long_file_set(&async->ls.common,
632 			  done_cb,
633 			  error_cb,
634 			  data,
635 			  _eio_file_direct_heavy,
636 			  _eio_direct_notify,
637 			  eio_async_end,
638 			  eio_async_error))
639      return NULL;
640 
641    return &async->ls.common;
642 }
643 
644 EAPI Eio_File *
eio_file_direct_ls(const char * dir,Eio_Filter_Direct_Cb filter_cb,Eio_Main_Direct_Cb main_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)645 eio_file_direct_ls(const char *dir,
646 		   Eio_Filter_Direct_Cb filter_cb,
647 		   Eio_Main_Direct_Cb main_cb,
648 		   Eio_Done_Cb done_cb,
649 		   Eio_Error_Cb error_cb,
650 		   const void *data)
651 {
652    EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL);
653 
654    return _eio_file_direct_internal_ls(dir, filter_cb, main_cb, NULL, done_cb, error_cb, data);
655 }
656 
657 Eio_File *
_eio_file_direct_ls(const char * dir,Eio_Array_Cb main_internal_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)658 _eio_file_direct_ls(const char *dir,
659                     Eio_Array_Cb main_internal_cb,
660                     Eio_Done_Cb done_cb,
661                     Eio_Error_Cb error_cb,
662                     const void *data)
663 {
664    EINA_SAFETY_ON_NULL_RETURN_VAL(main_internal_cb, NULL);
665 
666    return _eio_file_direct_internal_ls(dir, NULL, NULL, main_internal_cb, done_cb, error_cb, data);
667 }
668 
669 static Eio_File *
_eio_file_stat_internal_ls(const char * dir,Eio_Filter_Direct_Cb filter_cb,Eio_Main_Direct_Cb main_cb,Eio_Array_Cb main_internal_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)670 _eio_file_stat_internal_ls(const char *dir,
671                            Eio_Filter_Direct_Cb filter_cb,
672                            Eio_Main_Direct_Cb main_cb,
673                            Eio_Array_Cb main_internal_cb,
674                            Eio_Done_Cb done_cb,
675                            Eio_Error_Cb error_cb,
676                            const void *data)
677 {
678    Eio_File_Direct_Ls *async;
679 
680    EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
681    EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
682    EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
683 
684    async = eio_common_alloc(sizeof(Eio_File_Direct_Ls));
685    EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL);
686 
687    async->ls.directory = eina_stringshare_add(dir);
688    async->filter_cb = filter_cb;
689    if (main_internal_cb)
690      {
691         async->main_internal_cb = main_internal_cb;
692         async->ls.gather = EINA_TRUE;
693      }
694    else
695      {
696         async->main_cb = main_cb;
697      }
698 
699    if (!eio_long_file_set(&async->ls.common,
700 			  done_cb,
701 			  error_cb,
702 			  data,
703 			  _eio_file_stat_heavy,
704 			  _eio_direct_notify,
705 			  eio_async_end,
706 			  eio_async_error))
707      return NULL;
708 
709    return &async->ls.common;
710 }
711 
712 EAPI Eio_File *
eio_file_stat_ls(const char * dir,Eio_Filter_Direct_Cb filter_cb,Eio_Main_Direct_Cb main_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)713 eio_file_stat_ls(const char *dir,
714                  Eio_Filter_Direct_Cb filter_cb,
715                  Eio_Main_Direct_Cb main_cb,
716                  Eio_Done_Cb done_cb,
717                  Eio_Error_Cb error_cb,
718                  const void *data)
719 {
720    EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL);
721 
722    return _eio_file_stat_internal_ls(dir, filter_cb, main_cb, NULL, done_cb, error_cb, data);
723 }
724 
725 Eio_File *
_eio_file_stat_ls(const char * dir,Eio_Array_Cb main_internal_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)726 _eio_file_stat_ls(const char *dir,
727                  Eio_Array_Cb main_internal_cb,
728                  Eio_Done_Cb done_cb,
729                  Eio_Error_Cb error_cb,
730                  const void *data)
731 {
732    EINA_SAFETY_ON_NULL_RETURN_VAL(main_internal_cb, NULL);
733 
734    return _eio_file_stat_internal_ls(dir, NULL, NULL, main_internal_cb, done_cb, error_cb, data);
735 }
736 
737 EAPI Eina_Bool
eio_file_cancel(Eio_File * ls)738 eio_file_cancel(Eio_File *ls)
739 {
740    if (!ls) return EINA_FALSE;
741    EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_FALSE);
742    // ensure callbacks are not called aftera  cancel otherwise bad things
743    // happen higher up the stack - you cant stop these being caleld even if
744    // the dataptr they are passed has been freed or invalidated. being unable
745    // to stop future cb's and cancel them is BAD.
746    ls->error_cb = NULL;;
747    ls->done_cb = NULL;
748    return ecore_thread_cancel(ls->thread);
749 }
750 
751 EAPI Eina_Bool
eio_file_check(Eio_File * ls)752 eio_file_check(Eio_File *ls)
753 {
754    EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_TRUE);
755    return ecore_thread_check(ls->thread);
756 }
757 
758 EAPI void *
eio_file_container_get(Eio_File * ls)759 eio_file_container_get(Eio_File *ls)
760 {
761    EINA_SAFETY_ON_NULL_RETURN_VAL(ls, NULL);
762    return ls->container;
763 }
764 
765 EAPI Eina_Bool
eio_file_associate_add(Eio_File * ls,const char * key,const void * data,Eina_Free_Cb free_cb)766 eio_file_associate_add(Eio_File *ls,
767                        const char *key,
768                        const void *data, Eina_Free_Cb free_cb)
769 {
770    EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_FALSE);
771    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
772    /* FIXME: Check if we are in the right worker thread */
773    if (!ls->worker.associated)
774      ls->worker.associated = eina_hash_string_small_new(eio_associate_free);
775 
776    return eina_hash_add(ls->worker.associated,
777                         key,
778                         eio_associate_malloc(data, free_cb));
779 }
780 
781 EAPI Eina_Bool
eio_file_associate_direct_add(Eio_File * ls,const char * key,const void * data,Eina_Free_Cb free_cb)782 eio_file_associate_direct_add(Eio_File *ls,
783                               const char *key,
784                               const void *data, Eina_Free_Cb free_cb)
785 {
786    EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_FALSE);
787    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
788    /* FIXME: Check if we are in the right worker thread */
789    if (!ls->worker.associated)
790      ls->worker.associated = eina_hash_string_small_new(eio_associate_free);
791 
792    return eina_hash_direct_add(ls->worker.associated,
793                                key,
794                                eio_associate_malloc(data, free_cb));
795 }
796 
797 EAPI void *
eio_file_associate_find(Eio_File * ls,const char * key)798 eio_file_associate_find(Eio_File *ls, const char *key)
799 {
800    Eio_File_Associate *search;
801 
802    EINA_SAFETY_ON_NULL_RETURN_VAL(ls, NULL);
803    EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
804    if (!ls->main.associated)
805      return NULL;
806 
807    search = eina_hash_find(ls->main.associated, key);
808    if (!search) return NULL;
809    return search->data;
810 }
811 
812 EAPI Eio_File *
eio_file_copy(const char * source,const char * dest,Eio_Progress_Cb progress_cb,Eio_Done_Cb done_cb,Eio_Error_Cb error_cb,const void * data)813 eio_file_copy(const char *source,
814 	      const char *dest,
815 	      Eio_Progress_Cb progress_cb,
816 	      Eio_Done_Cb done_cb,
817 	      Eio_Error_Cb error_cb,
818 	      const void *data)
819 {
820    Eio_File_Progress *copy;
821 
822    EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL);
823    EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL);
824    EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
825    EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
826 
827    copy = eio_common_alloc(sizeof(Eio_File_Progress));
828    EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL);
829 
830    copy->op = EIO_FILE_COPY;
831    copy->progress_cb = progress_cb;
832    copy->source = eina_stringshare_add(source);
833    copy->dest = eina_stringshare_add(dest);
834 
835    if (!eio_long_file_set(&copy->common,
836 			  done_cb,
837 			  error_cb,
838 			  data,
839 			  _eio_file_copy_heavy,
840 			  _eio_file_copy_notify,
841 			  _eio_file_copy_end,
842 			  _eio_file_copy_error))
843      return NULL;
844 
845    return &copy->common;
846 }
847 
848 EAPI Eio_File *
eio_file_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)849 eio_file_move(const char *source,
850 	      const char *dest,
851 	      Eio_Progress_Cb progress_cb,
852 	      Eio_Done_Cb done_cb,
853 	      Eio_Error_Cb error_cb,
854 	      const void *data)
855 {
856    Eio_File_Move *move;
857 
858    EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL);
859    EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL);
860    EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
861    EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
862 
863    move = eio_common_alloc(sizeof(Eio_File_Move));
864    EINA_SAFETY_ON_NULL_RETURN_VAL(move, NULL);
865 
866    move->progress.op = EIO_FILE_MOVE;
867    move->progress.progress_cb = progress_cb;
868    move->progress.source = eina_stringshare_add(source);
869    move->progress.dest = eina_stringshare_add(dest);
870    move->copy = NULL;
871 
872    if (!eio_long_file_set(&move->progress.common,
873 			  done_cb,
874 			  error_cb,
875 			  data,
876 			  _eio_file_move_heavy,
877 			  _eio_file_move_notify,
878 			  _eio_file_move_end,
879 			  _eio_file_move_error))
880      return NULL;
881 
882    return &move->progress.common;
883 }
884