summaryrefslogtreecommitdiff
path: root/src/lib/eio/eio_dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eio/eio_dir.c')
-rw-r--r--src/lib/eio/eio_dir.c1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/src/lib/eio/eio_dir.c b/src/lib/eio/eio_dir.c
new file mode 100644
index 0000000..71cc3a0
--- /dev/null
+++ b/src/lib/eio/eio_dir.c
@@ -0,0 +1,1001 @@
1/* EIO - EFL data type library
2 * Copyright (C) 2010 Enlightenment Developers:
3 * Cedric Bail <cedric.bail@free.fr>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "eio_private.h"
21#include "Eio.h"
22
23/*============================================================================*
24 * Local *
25 *============================================================================*/
26
27/**
28 * @cond LOCAL
29 */
30
31static int
32eio_strcmp(const void *a, const void *b)
33{
34 return strcmp(a, b);
35}
36static Eina_Bool
37_eio_dir_recursive_progress(Eio_Dir_Copy *copy, Eio_File *handler, const Eina_File_Direct_Info *info)
38{
39 if (copy->filter_cb && !copy->filter_cb(&copy->progress.common.data, handler, info))
40 return EINA_FALSE;
41
42 switch (info->type)
43 {
44 case EINA_FILE_UNKNOWN:
45 eio_file_thread_error(&copy->progress.common, handler->thread);
46 return EINA_FALSE;
47 case EINA_FILE_LNK:
48 copy->links = eina_list_append(copy->links, eina_stringshare_add(info->path));
49 break;
50 case EINA_FILE_DIR:
51 copy->dirs = eina_list_append(copy->dirs, eina_stringshare_add(info->path));
52 break;
53 default:
54 copy->files = eina_list_append(copy->files, eina_stringshare_add(info->path));
55 break;
56 }
57
58 return EINA_TRUE;
59}
60
61static Eina_Bool
62_eio_file_recursiv_ls(Ecore_Thread *thread,
63 Eio_File *common,
64 Eio_Filter_Direct_Cb filter_cb,
65 Eina_Iterator *(*Eina_File_Ls)(const char *target),
66 void *data,
67 const char *target)
68{
69 Eina_File_Direct_Info *info;
70 Eina_Iterator *it = NULL;
71 Eina_List *dirs = NULL;
72 const char *dir;
73
74 it = Eina_File_Ls(target);
75 if (!it)
76 {
77 eio_file_thread_error(common, thread);
78 return EINA_FALSE;
79 }
80
81 eio_file_container_set(common, eina_iterator_container_get(it));
82
83 EINA_ITERATOR_FOREACH(it, info)
84 {
85 Eina_Bool filter = EINA_TRUE;
86 _eio_stat_t buffer;
87
88 switch (info->type)
89 {
90 case EINA_FILE_DIR:
91 if (_eio_lstat(info->path, &buffer) != 0)
92 continue;
93
94 if (S_ISLNK(buffer.st_mode))
95 info->type = EINA_FILE_LNK;
96 default:
97 break;
98 }
99
100 filter = filter_cb(data, common, info);
101 if (filter && info->type == EINA_FILE_DIR)
102 dirs = eina_list_append(dirs, eina_stringshare_add(info->path));
103
104 if (ecore_thread_check(thread))
105 goto on_error;
106 }
107
108 eio_file_container_set(common, NULL);
109
110 eina_iterator_free(it);
111 it = NULL;
112
113 EINA_LIST_FREE(dirs, dir)
114 {
115 Eina_Bool err;
116
117 err = !_eio_file_recursiv_ls(thread, common, filter_cb, Eina_File_Ls, data, dir);
118
119 eina_stringshare_del(dir);
120 if (err) goto on_error;
121 }
122
123 return EINA_TRUE;
124
125 on_error:
126 if (it) eina_iterator_free(it);
127
128 EINA_LIST_FREE(dirs, dir)
129 eina_stringshare_del(dir);
130
131 return EINA_FALSE;
132}
133
134
135static Eina_Bool
136_eio_dir_recursiv_ls(Ecore_Thread *thread, Eio_Dir_Copy *copy, const char *target)
137{
138 if (!_eio_file_recursiv_ls(thread, &copy->progress.common,
139 (Eio_Filter_Direct_Cb) _eio_dir_recursive_progress,
140 eina_file_stat_ls,
141 copy, target))
142 return EINA_FALSE;
143
144 return EINA_TRUE;
145}
146
147static Eina_Bool
148_eio_dir_init(Ecore_Thread *thread,
149 long long *step, long long *count,
150 int *length_source, int *length_dest,
151 Eio_Dir_Copy *order,
152 Eio_File_Progress *progress)
153{
154 struct stat buffer;
155
156 /* notify main thread of the amount of work todo */
157 *step = 0;
158 *count = eina_list_count(order->files)
159 + eina_list_count(order->dirs) * 2
160 + eina_list_count(order->links);
161 eio_progress_send(thread, &order->progress, *step, *count);
162
163 /* sort the content, so we create the directory in the right order */
164 order->dirs = eina_list_sort(order->dirs, -1, eio_strcmp);
165 order->files = eina_list_sort(order->files, -1, eio_strcmp);
166 order->links = eina_list_sort(order->links, -1, eio_strcmp);
167
168 /* prepare stuff */
169 *length_source = eina_stringshare_strlen(order->progress.source);
170 *length_dest = eina_stringshare_strlen(order->progress.dest);
171
172 memcpy(progress, &order->progress, sizeof (Eio_File_Progress));
173 progress->source = NULL;
174 progress->dest = NULL;
175
176 /* create destination dir if not available */
177 if (stat(order->progress.dest, &buffer) != 0)
178 {
179 if (stat(order->progress.source, &buffer) != 0)
180 {
181 eio_file_thread_error(&order->progress.common, thread);
182 return EINA_FALSE;
183 }
184
185 if (mkdir(order->progress.dest, buffer.st_mode) != 0)
186 {
187 eio_file_thread_error(&order->progress.common, thread);
188 return EINA_FALSE;
189 }
190 }
191
192 return EINA_TRUE;
193}
194
195static void
196_eio_dir_target(Eio_Dir_Copy *order, char *target, const char *dir, int length_source, int length_dest)
197{
198 int length;
199
200 length = eina_stringshare_strlen(dir);
201
202 memcpy(target, order->progress.dest, length_dest);
203 target[length_dest] = '/';
204 memcpy(target + length_dest + 1, dir + length_source, length - length_source + 1);
205}
206
207static Eina_Bool
208_eio_dir_mkdir(Ecore_Thread *thread, Eio_Dir_Copy *order,
209 long long *step, long long count,
210 int length_source, int length_dest)
211{
212 const char *dir;
213 Eina_List *l;
214 char target[PATH_MAX];
215
216 /* create all directory */
217 EINA_LIST_FOREACH(order->dirs, l, dir)
218 {
219 /* build target dir path */
220 _eio_dir_target(order, target, dir, length_source, length_dest);
221
222 /* create the directory (we will apply the mode later) */
223 if (mkdir(target, 0777) != 0)
224 {
225 eio_file_thread_error(&order->progress.common, thread);
226 return EINA_FALSE;
227 }
228
229 /* inform main thread */
230 (*step)++;
231 eio_progress_send(thread, &order->progress, *step, count);
232
233 /* check for cancel request */
234 if (ecore_thread_check(thread))
235 return EINA_FALSE;
236 }
237
238 return EINA_TRUE;
239}
240
241static Eina_Bool
242_eio_dir_link(Ecore_Thread *thread, Eio_Dir_Copy *order,
243 long long *step, long long count,
244 int length_source, int length_dest)
245{
246 const char *ln;
247 Eina_List *l;
248 char oldpath[PATH_MAX];
249 char target[PATH_MAX];
250 char buffer[PATH_MAX];
251 char *newpath;
252
253 /* Build once the base of the link target */
254 memcpy(buffer, order->progress.dest, length_dest);
255 buffer[length_dest] = '/';
256
257 /* recreate all links */
258 EINA_LIST_FOREACH(order->links, l, ln)
259 {
260 ssize_t length;
261
262 /* build oldpath link */
263 _eio_dir_target(order, oldpath, ln, length_source, length_dest);
264
265 /* read link target */
266 length = readlink(ln, target, PATH_MAX);
267 if (length < 0)
268 goto on_error;
269
270 if (strncmp(target, order->progress.source, length_source) == 0)
271 {
272 /* The link is inside the zone to copy, so rename it */
273 memcpy(buffer + length_dest + 1, target + length_source, length - length_source + 1);
274 newpath = target;
275 }
276 else
277 {
278 /* The link is outside the zone to copy */
279 newpath = target;
280 }
281
282 /* create the link */
283 if (symlink(newpath, oldpath) != 0)
284 goto on_error;
285
286 /* inform main thread */
287 (*step)++;
288 eio_progress_send(thread, &order->progress, *step, count);
289
290 /* check for cancel request */
291 if (ecore_thread_check(thread))
292 return EINA_FALSE;
293 }
294
295 return EINA_TRUE;
296
297 on_error:
298 eio_file_thread_error(&order->progress.common, thread);
299 return EINA_FALSE;
300}
301
302static Eina_Bool
303_eio_dir_chmod(Ecore_Thread *thread, Eio_Dir_Copy *order,
304 long long *step, long long count,
305 int length_source, int length_dest,
306 Eina_Bool rmdir_source)
307{
308 const char *dir;
309 char target[PATH_MAX];
310 struct stat buffer;
311
312 while(order->dirs)
313 {
314 /* destroy in reverse order so that we don't prevent change of lower dir */
315 dir = eina_list_data_get(eina_list_last(order->dirs));
316 order->dirs = eina_list_remove_list(order->dirs, eina_list_last(order->dirs));
317
318 /* build target dir path */
319 _eio_dir_target(order, target, dir, length_source, length_dest);
320
321 /* FIXME: in some case we already did a stat call, so would be nice to reuse previous result here */
322 /* stat the original dir for mode info */
323 if (stat(dir, &buffer) != 0)
324 goto on_error;
325
326 /* set the orginal mode to the newly created dir */
327 if (chmod(target, buffer.st_mode) != 0)
328 goto on_error;
329
330 /* if required destroy original directory */
331 if (rmdir_source)
332 {
333 if (rmdir(dir) != 0)
334 goto on_error;
335 }
336
337 /* inform main thread */
338 (*step)++;
339 eio_progress_send(thread, &order->progress, *step, count);
340
341 /* check for cancel request */
342 if (ecore_thread_check(thread))
343 goto on_cancel;
344
345 eina_stringshare_del(dir);
346 }
347
348 return EINA_TRUE;
349
350 on_error:
351 eio_file_thread_error(&order->progress.common, thread);
352 on_cancel:
353 if (dir) eina_stringshare_del(dir);
354 return EINA_FALSE;
355}
356
357static void
358_eio_dir_copy_heavy(void *data, Ecore_Thread *thread)
359{
360 Eio_Dir_Copy *copy = data;
361 const char *file = NULL;
362 const char *dir;
363 const char *ln;
364
365 Eio_File_Progress file_copy;
366 char target[PATH_MAX];
367
368 int length_source = 0;
369 int length_dest = 0;
370 long long count;
371 long long step;
372
373 /* list all the content that should be copied */
374 if (!_eio_dir_recursiv_ls(thread, copy, copy->progress.source))
375 return ;
376
377 /* init all structure needed to copy the file */
378 if (!_eio_dir_init(thread, &step, &count, &length_source, &length_dest, copy, &file_copy))
379 goto on_error;
380
381 /* suboperation is a file copy */
382 file_copy.op = EIO_FILE_COPY;
383
384 /* create all directory */
385 if (!_eio_dir_mkdir(thread, copy, &step, count, length_source, length_dest))
386 goto on_error;
387
388 /* copy all files */
389 EINA_LIST_FREE(copy->files, file)
390 {
391 /* build target file path */
392 _eio_dir_target(copy, target, file, length_source, length_dest);
393
394 file_copy.source = file;
395 file_copy.dest = eina_stringshare_add(target);
396
397 /* copy the file */
398 if (!eio_file_copy_do(thread, &file_copy))
399 {
400 copy->progress.common.error = file_copy.common.error;
401 goto on_error;
402 }
403
404 /* notify main thread */
405 step++;
406 eio_progress_send(thread, &copy->progress, step, count);
407
408 if (ecore_thread_check(thread))
409 goto on_error;
410
411 eina_stringshare_del(file_copy.dest);
412 eina_stringshare_del(file);
413 }
414 file_copy.dest = NULL;
415 file = NULL;
416
417 /* recreate link */
418 if (!_eio_dir_link(thread, copy, &step, count, length_source, length_dest))
419 goto on_error;
420
421 /* set directory right back */
422 if (!_eio_dir_chmod(thread, copy, &step, count, length_source, length_dest, EINA_FALSE))
423 goto on_error;
424
425 on_error:
426 /* cleanup the mess */
427 if (file_copy.dest) eina_stringshare_del(file_copy.dest);
428 if (file) eina_stringshare_del(file);
429
430 EINA_LIST_FREE(copy->files, file)
431 eina_stringshare_del(file);
432 EINA_LIST_FREE(copy->dirs, dir)
433 eina_stringshare_del(dir);
434 EINA_LIST_FREE(copy->links, ln)
435 eina_stringshare_del(ln);
436
437 if (!ecore_thread_check(thread))
438 eio_progress_send(thread, &copy->progress, count, count);
439
440 return ;
441}
442
443static void
444_eio_dir_copy_notify(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data)
445{
446 Eio_Dir_Copy *copy = data;
447 Eio_Progress *progress = msg_data;
448
449 eio_progress_cb(progress, &copy->progress);
450}
451
452static void
453_eio_dir_copy_free(Eio_Dir_Copy *copy)
454{
455 eina_stringshare_del(copy->progress.source);
456 eina_stringshare_del(copy->progress.dest);
457 eio_file_free(&copy->progress.common);
458}
459
460static void
461_eio_dir_copy_end(void *data, Ecore_Thread *thread EINA_UNUSED)
462{
463 Eio_Dir_Copy *copy = data;
464
465 copy->progress.common.done_cb((void*) copy->progress.common.data, &copy->progress.common);
466
467 _eio_dir_copy_free(copy);
468}
469
470static void
471_eio_dir_copy_error(void *data, Ecore_Thread *thread EINA_UNUSED)
472{
473 Eio_Dir_Copy *copy = data;
474
475 eio_file_error(&copy->progress.common);
476
477 _eio_dir_copy_free(copy);
478}
479
480static void
481_eio_dir_move_heavy(void *data, Ecore_Thread *thread)
482{
483 Eio_Dir_Copy *move = data;
484 const char *file = NULL;
485 const char *dir = NULL;
486
487 Eio_File_Progress file_move;
488 char target[PATH_MAX];
489
490 int length_source;
491 int length_dest;
492 long long count;
493 long long step;
494
495 /* just try a rename, maybe we are lucky... */
496 if (rename(move->progress.source, move->progress.dest) == 0)
497 {
498 /* we are really lucky */
499 eio_progress_send(thread, &move->progress, 1, 1);
500 return ;
501 }
502
503 /* list all the content that should be moved */
504 if (!_eio_dir_recursiv_ls(thread, move, move->progress.source))
505 return ;
506
507 /* init all structure needed to move the file */
508 if (!_eio_dir_init(thread, &step, &count, &length_source, &length_dest, move, &file_move))
509 goto on_error;
510
511 /* sub operation is a file move */
512 file_move.op = EIO_FILE_MOVE;
513
514 /* create all directory */
515 if (!_eio_dir_mkdir(thread, move, &step, count, length_source, length_dest))
516 goto on_error;
517
518 /* move file around */
519 EINA_LIST_FREE(move->files, file)
520 {
521 /* build target file path */
522 _eio_dir_target(move, target, file, length_source, length_dest);
523
524 file_move.source = file;
525 file_move.dest = eina_stringshare_add(target);
526
527 /* first try to rename */
528 if (rename(file_move.source, file_move.dest) < 0)
529 {
530 if (errno != EXDEV)
531 {
532 eio_file_thread_error(&move->progress.common, thread);
533 goto on_error;
534 }
535
536 /* then try real copy */
537 if (!eio_file_copy_do(thread, &file_move))
538 {
539 move->progress.common.error = file_move.common.error;
540 goto on_error;
541 }
542
543 /* and unlink the original */
544 if (unlink(file) != 0)
545 {
546 eio_file_thread_error(&move->progress.common, thread);
547 goto on_error;
548 }
549 }
550
551 step++;
552 eio_progress_send(thread, &move->progress, step, count);
553
554 if (ecore_thread_check(thread))
555 goto on_error;
556
557 eina_stringshare_del(file_move.dest);
558 eina_stringshare_del(file);
559 }
560 file_move.dest = NULL;
561 file = NULL;
562
563 /* recreate link */
564 if (!_eio_dir_link(thread, move, &step, count, length_source, length_dest))
565 goto on_error;
566
567 /* set directory right back */
568 if (!_eio_dir_chmod(thread, move, &step, count, length_source, length_dest, EINA_TRUE))
569 goto on_error;
570
571 if (rmdir(move->progress.source) != 0)
572 goto on_error;
573
574 on_error:
575 /* cleanup the mess */
576 if (file_move.dest) eina_stringshare_del(file_move.dest);
577 if (file) eina_stringshare_del(file);
578
579 EINA_LIST_FREE(move->files, file)
580 eina_stringshare_del(file);
581 EINA_LIST_FREE(move->dirs, dir)
582 eina_stringshare_del(dir);
583
584 if (!ecore_thread_check(thread))
585 eio_progress_send(thread, &move->progress, count, count);
586
587 return;
588}
589
590static void
591_eio_dir_rmrf_heavy(void *data, Ecore_Thread *thread)
592{
593 Eio_Dir_Copy *rmrf = data;
594 const char *file = NULL;
595 const char *dir = NULL;
596
597 long long count;
598 long long step;
599
600 /* list all the content that should be moved */
601 if (!_eio_dir_recursiv_ls(thread, rmrf, rmrf->progress.source))
602 return ;
603
604 /* init counter */
605 step = 0;
606 count = eina_list_count(rmrf->files) + eina_list_count(rmrf->dirs) + 1;
607
608 EINA_LIST_FREE(rmrf->files, file)
609 {
610 if (unlink(file) != 0)
611 {
612 eio_file_thread_error(&rmrf->progress.common, thread);
613 goto on_error;
614 }
615
616 eina_stringshare_replace(&rmrf->progress.dest, file);
617
618 step++;
619 eio_progress_send(thread, &rmrf->progress, step, count);
620
621 if (ecore_thread_check(thread))
622 goto on_error;
623
624 eina_stringshare_del(file);
625 }
626 file = NULL;
627
628 /* reverse directory listing, so the leaf would be destroyed before
629 the root */
630 rmrf->dirs = eina_list_reverse(rmrf->dirs);
631
632 EINA_LIST_FREE(rmrf->dirs, dir)
633 {
634 if (rmdir(dir) != 0)
635 {
636 eio_file_thread_error(&rmrf->progress.common, thread);
637 goto on_error;
638 }
639
640 eina_stringshare_replace(&rmrf->progress.dest, dir);
641
642 step++;
643 eio_progress_send(thread, &rmrf->progress, step, count);
644
645 if (ecore_thread_check(thread))
646 goto on_error;
647
648 eina_stringshare_del(dir);
649 }
650 dir = NULL;
651
652 if (rmdir(rmrf->progress.source) != 0)
653 goto on_error;
654 step++;
655
656 on_error:
657 if (dir) eina_stringshare_del(dir);
658 if (file) eina_stringshare_del(file);
659
660 EINA_LIST_FREE(rmrf->dirs, dir)
661 eina_stringshare_del(dir);
662 EINA_LIST_FREE(rmrf->files, file)
663 eina_stringshare_del(file);
664
665 if (!ecore_thread_check(thread))
666 eio_progress_send(thread, &rmrf->progress, count, count);
667
668 return;
669}
670
671static Eina_Bool
672_eio_dir_stat_find_forward(Eio_File_Dir_Ls *async,
673 Eio_File *handler,
674 Eina_File_Direct_Info *info)
675{
676 Eina_Bool filter = EINA_TRUE;
677 double current;
678
679 if (async->filter_cb)
680 {
681 filter = async->filter_cb((void*) async->ls.common.data, &async->ls.common, info);
682 }
683
684 if (filter)
685 {
686 Eio_File_Direct_Info *send_di;
687
688 send_di = eio_direct_info_malloc();
689 if (!send_di) return EINA_FALSE;
690
691 memcpy(&send_di->info, info, sizeof (Eina_File_Direct_Info));
692 send_di->associated = async->ls.common.worker.associated;
693 async->ls.common.worker.associated = NULL;
694
695 async->pack = eina_list_append(async->pack, send_di);
696 }
697 else if (async->ls.common.worker.associated)
698 {
699 eina_hash_free(async->ls.common.worker.associated);
700 async->ls.common.worker.associated = NULL;
701 }
702
703 current = ecore_time_get();
704 if (current - async->start > EIO_PACKED_TIME)
705 {
706 async->start = current;
707 ecore_thread_feedback(handler->thread, async->pack);
708 async->pack = NULL;
709 }
710
711 return filter;
712}
713
714static void
715_eio_dir_stat_find_heavy(void *data, Ecore_Thread *thread)
716{
717 Eio_File_Dir_Ls *async = data;
718
719 async->ls.common.thread = thread;
720 async->pack = NULL;
721 async->start = ecore_time_get();
722
723 _eio_file_recursiv_ls(thread, &async->ls.common,
724 (Eio_Filter_Direct_Cb) _eio_dir_stat_find_forward,
725 eina_file_stat_ls,
726 async, async->ls.directory);
727
728 if (async->pack) ecore_thread_feedback(thread, async->pack);
729 async->pack = NULL;
730}
731
732static void
733_eio_dir_direct_find_heavy(void *data, Ecore_Thread *thread)
734{
735 Eio_File_Dir_Ls *async = data;
736
737 async->ls.common.thread = thread;
738 async->pack = NULL;
739 async->start = ecore_time_get();
740
741 _eio_file_recursiv_ls(thread, &async->ls.common,
742 (Eio_Filter_Direct_Cb) _eio_dir_stat_find_forward,
743 eina_file_direct_ls,
744 async, async->ls.directory);
745
746 if (async->pack) ecore_thread_feedback(thread, async->pack);
747 async->pack = NULL;
748}
749
750static void
751_eio_dir_stat_find_notify(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data)
752{
753 Eio_File_Dir_Ls *async = data;
754 Eina_List *pack = msg_data;
755 Eio_File_Direct_Info *info;
756
757 EINA_LIST_FREE(pack, info)
758 {
759 async->ls.common.main.associated = info->associated;
760
761 async->main_cb((void*) async->ls.common.data, &async->ls.common, &info->info);
762
763 if (async->ls.common.main.associated)
764 {
765 eina_hash_free(async->ls.common.main.associated);
766 async->ls.common.main.associated = NULL;
767 }
768
769 eio_direct_info_free(info);
770 }
771}
772
773static void
774_eio_dir_stat_done(void *data, Ecore_Thread *thread EINA_UNUSED)
775{
776 Eio_File_Ls *async = data;
777
778 async->common.done_cb((void*) async->common.data, &async->common);
779
780 eio_async_free(async);
781}
782
783static void
784_eio_dir_stat_error(void *data, Ecore_Thread *thread EINA_UNUSED)
785{
786 Eio_File_Ls *async = data;
787
788 eio_file_error(&async->common);
789
790 eio_async_free(async);
791}
792
793/**
794 * @endcond
795 */
796
797/*============================================================================*
798 * Global *
799 *============================================================================*/
800
801
802/*============================================================================*
803 * API *
804 *============================================================================*/
805
806
807EAPI Eio_File *
808eio_dir_copy(const char *source,
809 const char *dest,
810 Eio_Filter_Direct_Cb filter_cb,
811 Eio_Progress_Cb progress_cb,
812 Eio_Done_Cb done_cb,
813 Eio_Error_Cb error_cb,
814 const void *data)
815{
816 Eio_Dir_Copy *copy;
817
818 EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL);
819 EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL);
820 EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
821 EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
822
823 copy = malloc(sizeof(Eio_Dir_Copy));
824 EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL);
825
826 copy->progress.op = EIO_DIR_COPY;
827 copy->progress.progress_cb = progress_cb;
828 copy->progress.source = eina_stringshare_add(source);
829 copy->progress.dest = eina_stringshare_add(dest);
830 copy->filter_cb = filter_cb;
831 copy->files = NULL;
832 copy->dirs = NULL;
833 copy->links = NULL;
834
835 if (!eio_long_file_set(&copy->progress.common,
836 done_cb,
837 error_cb,
838 data,
839 _eio_dir_copy_heavy,
840 _eio_dir_copy_notify,
841 _eio_dir_copy_end,
842 _eio_dir_copy_error))
843 return NULL;
844
845 return &copy->progress.common;
846}
847
848EAPI Eio_File *
849eio_dir_move(const char *source,
850 const char *dest,
851 Eio_Filter_Direct_Cb filter_cb,
852 Eio_Progress_Cb progress_cb,
853 Eio_Done_Cb done_cb,
854 Eio_Error_Cb error_cb,
855 const void *data)
856{
857 Eio_Dir_Copy *move;
858
859 EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL);
860 EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL);
861 EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
862 EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
863
864 move = malloc(sizeof(Eio_Dir_Copy));
865 EINA_SAFETY_ON_NULL_RETURN_VAL(move, NULL);
866
867 move->progress.op = EIO_DIR_MOVE;
868 move->progress.progress_cb = progress_cb;
869 move->progress.source = eina_stringshare_add(source);
870 move->progress.dest = eina_stringshare_add(dest);
871 move->filter_cb = filter_cb;
872 move->files = NULL;
873 move->dirs = NULL;
874 move->links = NULL;
875
876 if (!eio_long_file_set(&move->progress.common,
877 done_cb,
878 error_cb,
879 data,
880 _eio_dir_move_heavy,
881 _eio_dir_copy_notify,
882 _eio_dir_copy_end,
883 _eio_dir_copy_error))
884 return NULL;
885
886 return &move->progress.common;
887}
888
889EAPI Eio_File *
890eio_dir_unlink(const char *path,
891 Eio_Filter_Direct_Cb filter_cb,
892 Eio_Progress_Cb progress_cb,
893 Eio_Done_Cb done_cb,
894 Eio_Error_Cb error_cb,
895 const void *data)
896{
897 Eio_Dir_Copy *rmrf;
898
899 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
900 EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
901 EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
902
903 rmrf = malloc(sizeof(Eio_Dir_Copy));
904 EINA_SAFETY_ON_NULL_RETURN_VAL(rmrf, NULL);
905
906 rmrf->progress.op = EIO_UNLINK;
907 rmrf->progress.progress_cb = progress_cb;
908 rmrf->progress.source = eina_stringshare_add(path);
909 rmrf->progress.dest = NULL;
910 rmrf->filter_cb = filter_cb;
911 rmrf->files = NULL;
912 rmrf->dirs = NULL;
913 rmrf->links = NULL;
914
915 if (!eio_long_file_set(&rmrf->progress.common,
916 done_cb,
917 error_cb,
918 data,
919 _eio_dir_rmrf_heavy,
920 _eio_dir_copy_notify,
921 _eio_dir_copy_end,
922 _eio_dir_copy_error))
923 return NULL;
924
925 return &rmrf->progress.common;
926}
927
928EAPI Eio_File *
929eio_dir_stat_ls(const char *dir,
930 Eio_Filter_Direct_Cb filter_cb,
931 Eio_Main_Direct_Cb main_cb,
932 Eio_Done_Cb done_cb,
933 Eio_Error_Cb error_cb,
934 const void *data)
935{
936 Eio_File_Dir_Ls *async;
937
938 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
939 EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL);
940 EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
941 EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
942
943 async = malloc(sizeof(Eio_File_Dir_Ls));
944 EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL);
945
946 /* Eio_Filter_Direct_Cb must be casted to Eio_Filter_Dir_Cb here
947 * because we keep the Eio_File_Dir_Ls pointing to that variant
948 * where info can be modified, but in our case it's already doing
949 * stat() then it shouldn't be needed!
950 */
951 async->filter_cb = (Eio_Filter_Dir_Cb)filter_cb;
952 async->main_cb = main_cb;
953 async->ls.directory = eina_stringshare_add(dir);
954
955 if (!eio_long_file_set(&async->ls.common,
956 done_cb,
957 error_cb,
958 data,
959 _eio_dir_stat_find_heavy,
960 _eio_dir_stat_find_notify,
961 _eio_dir_stat_done,
962 _eio_dir_stat_error))
963 return NULL;
964
965 return &async->ls.common;
966}
967
968EAPI Eio_File *
969eio_dir_direct_ls(const char *dir,
970 Eio_Filter_Dir_Cb filter_cb,
971 Eio_Main_Direct_Cb main_cb,
972 Eio_Done_Cb done_cb,
973 Eio_Error_Cb error_cb,
974 const void *data)
975{
976 Eio_File_Dir_Ls *async;
977
978 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
979 EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL);
980 EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL);
981 EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL);
982
983 async = malloc(sizeof(Eio_File_Dir_Ls));
984 EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL);
985
986 async->filter_cb = filter_cb;
987 async->main_cb = main_cb;
988 async->ls.directory = eina_stringshare_add(dir);
989
990 if (!eio_long_file_set(&async->ls.common,
991 done_cb,
992 error_cb,
993 data,
994 _eio_dir_direct_find_heavy,
995 _eio_dir_stat_find_notify,
996 _eio_dir_stat_done,
997 _eio_dir_stat_error))
998 return NULL;
999
1000 return &async->ls.common;
1001}