1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <libgen.h>
10
11 #ifdef _WIN32
12 # include <direct.h>
13 # include <evil_private.h> /* mkdir realpath */
14 #endif
15
16 #ifdef HAVE_FEATURES_H
17 # include <features.h>
18 #endif
19 #include <ctype.h>
20 #include <errno.h>
21
22 #ifdef HAVE_ATFILE_SOURCE
23 # include <dirent.h>
24 #endif
25
26 #include "ecore_file_private.h"
27
28 /*
29 * FIXME: the following functions will certainly not work on Windows:
30 * ecore_file_app_exe_get()
31 * ecore_file_escape_name()
32 */
33
34 int _ecore_file_log_dom = -1;
35 static int _ecore_file_init_count = 0;
36
37 static Eina_Bool
_ecore_file_stat(const char * file,long long * mtime,long long * size,mode_t * mode,Eina_Bool * is_dir,Eina_Bool * is_reg)38 _ecore_file_stat(const char *file,
39 long long *mtime,
40 long long *size,
41 mode_t *mode,
42 Eina_Bool *is_dir,
43 Eina_Bool *is_reg)
44 {
45 struct stat st;
46 #ifdef _WIN32
47 /*
48 * On Windows, stat() returns -1 is file is a path finishing with
49 * a slash or blackslash
50 * see https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
51 * ("Return Value" section)
52 *
53 * so we ensure that file never finishes with \ or /
54 */
55 char f[MAX_PATH];
56 size_t len;
57
58 len = strlen(file);
59 if ((len + 1) > MAX_PATH)
60 return EINA_FALSE;
61
62 memcpy(f, file, len + 1);
63 if ((f[len - 1] == '/') || (f[len - 1] == '\\'))
64 f[len - 1] = '\0';
65
66 if (stat(f, &st) < 0)
67 return EINA_FALSE;
68 #else
69 if (stat(file, &st) < 0)
70 return EINA_FALSE;
71 #endif
72
73 if (mtime) *mtime = st.st_mtime;
74 if (size) *size = st.st_size;
75 if (mode) *mode = st.st_mode;
76 if (is_dir) *is_dir = S_ISDIR(st.st_mode);
77 if (is_reg) *is_reg = S_ISREG(st.st_mode);
78
79 return EINA_TRUE;
80 }
81
82 EAPI int
ecore_file_init()83 ecore_file_init()
84 {
85 if (++_ecore_file_init_count != 1)
86 return _ecore_file_init_count;
87
88 if (!ecore_init())
89 return --_ecore_file_init_count;
90
91 _ecore_file_log_dom = eina_log_domain_register
92 ("ecore_file", ECORE_FILE_DEFAULT_LOG_COLOR);
93 if(_ecore_file_log_dom < 0)
94 {
95 EINA_LOG_ERR("Impossible to create a log domain for the ecore file module.");
96 return --_ecore_file_init_count;
97 }
98 ecore_file_path_init();
99 ecore_file_monitor_init();
100 ecore_file_download_init();
101
102 /* FIXME: were the tests disabled for a good reason ? */
103
104 /*
105 if (!ecore_file_monitor_init())
106 goto shutdown_ecore_file_path;
107
108 if (!ecore_file_download_init())
109 goto shutdown_ecore_file_monitor;
110 */
111
112 return _ecore_file_init_count;
113
114 /*
115 shutdown_ecore_file_monitor:
116 ecore_file_monitor_shutdown();
117 shutdown_ecore_file_path:
118 ecore_file_path_shutdown();
119
120 return --_ecore_file_init_count;
121 */
122 }
123
124 EAPI int
ecore_file_shutdown()125 ecore_file_shutdown()
126 {
127 if (--_ecore_file_init_count != 0)
128 return _ecore_file_init_count;
129
130 ecore_file_download_shutdown();
131 ecore_file_monitor_shutdown();
132 ecore_file_path_shutdown();
133
134 eina_log_domain_unregister(_ecore_file_log_dom);
135 _ecore_file_log_dom = -1;
136
137 ecore_shutdown();
138
139 return _ecore_file_init_count;
140 }
141
142 EAPI long long
ecore_file_mod_time(const char * file)143 ecore_file_mod_time(const char *file)
144 {
145 long long time;
146
147 if (!_ecore_file_stat(file, &time, NULL, NULL, NULL, NULL))
148 return 0;
149
150 return time;
151 }
152
153 EAPI long long
ecore_file_size(const char * file)154 ecore_file_size(const char *file)
155 {
156 long long size;
157
158 if (!_ecore_file_stat(file, NULL, &size, NULL, NULL, NULL))
159 return 0;
160
161 return size;
162 }
163
164 EAPI Eina_Bool
ecore_file_exists(const char * file)165 ecore_file_exists(const char *file)
166 {
167 #ifdef _WIN32
168 /* I prefer not touching the specific UNIX code... */
169 return _ecore_file_stat(file, NULL, NULL, NULL, NULL, NULL);
170 #else
171 struct stat st;
172 if (!file) return EINA_FALSE;
173
174 /*Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor*/
175 if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE;
176 return EINA_TRUE;
177 #endif
178 }
179
180 EAPI Eina_Bool
ecore_file_is_dir(const char * file)181 ecore_file_is_dir(const char *file)
182 {
183 Eina_Bool is_dir;
184
185 if (!_ecore_file_stat(file, NULL, NULL, NULL, &is_dir, NULL))
186 return EINA_FALSE;
187
188 return is_dir;
189 }
190
191 static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
192
193 EAPI Eina_Bool
ecore_file_mkdir(const char * dir)194 ecore_file_mkdir(const char *dir)
195 {
196 return (mkdir(dir, default_mode) == 0);
197 }
198
199 EAPI int
ecore_file_mkdirs(const char ** dirs)200 ecore_file_mkdirs(const char **dirs)
201 {
202 int i = 0;
203
204 if (!dirs) return -1;
205
206 for (; *dirs; dirs++)
207 if (ecore_file_mkdir(*dirs))
208 i++;
209 return i;
210 }
211
212 EAPI int
ecore_file_mksubdirs(const char * base,const char ** subdirs)213 ecore_file_mksubdirs(const char *base, const char **subdirs)
214 {
215 #ifndef HAVE_ATFILE_SOURCE
216 char buf[PATH_MAX];
217 int baselen;
218 #else
219 int fd;
220 DIR *dir;
221 #endif
222 int i;
223
224 if (!subdirs) return -1;
225 if ((!base) || (base[0] == '\0')) return -1;
226
227 if ((!ecore_file_is_dir(base)) && (!ecore_file_mkpath(base)))
228 return 0;
229
230 #ifndef HAVE_ATFILE_SOURCE
231 baselen = eina_strlcpy(buf, base, sizeof(buf));
232 if ((baselen < 1) || (baselen + 1 >= (int)sizeof(buf)))
233 return 0;
234
235 if (buf[baselen - 1] != '/')
236 {
237 buf[baselen] = '/';
238 baselen++;
239 }
240 #else
241 dir = opendir(base);
242 if (!dir)
243 return 0;
244 fd = dirfd(dir);
245 #endif
246
247 i = 0;
248 for (; *subdirs; subdirs++)
249 {
250 #ifdef HAVE_ATFILE_SOURCE
251 struct stat st;
252 #endif
253 Eina_Bool is_dir;
254
255 #ifndef HAVE_ATFILE_SOURCE
256 eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen);
257 if (_ecore_file_stat(buf, NULL, NULL, NULL, &is_dir, NULL))
258 {
259 #else
260 if (fstatat(fd, *subdirs, &st, 0) == 0)
261 {
262 is_dir = S_ISDIR(st.st_mode);
263 #endif
264 if (is_dir)
265 {
266 i++;
267 continue;
268 }
269 }
270 else
271 {
272 if (errno == ENOENT)
273 {
274 #ifndef HAVE_ATFILE_SOURCE
275 if (ecore_file_mkdir(buf))
276 #else
277 if (mkdirat(fd, *subdirs, default_mode) == 0)
278 #endif
279 {
280 i++;
281 continue;
282 }
283 }
284 }
285 }
286
287 #ifdef HAVE_ATFILE_SOURCE
288 closedir(dir);
289 #endif
290
291 return i;
292 }
293
294 EAPI Eina_Bool
295 ecore_file_rmdir(const char *dir)
296 {
297 if (rmdir(dir) < 0) return EINA_FALSE;
298 return EINA_TRUE;
299 }
300
301 EAPI Eina_Bool
302 ecore_file_unlink(const char *file)
303 {
304 if (unlink(file) < 0) return EINA_FALSE;
305 return EINA_TRUE;
306 }
307
308 EAPI Eina_Bool
309 ecore_file_remove(const char *file)
310 {
311 if (remove(file) < 0) return EINA_FALSE;
312 return EINA_TRUE;
313 }
314
315 EAPI Eina_Bool
316 ecore_file_recursive_rm(const char *dir)
317 {
318 #ifndef _WIN32
319 struct stat st;
320 #endif
321 Eina_Bool is_dir;
322
323 #ifdef _WIN32
324 if (!_ecore_file_stat(dir, NULL, NULL, NULL, &is_dir, NULL))
325 return EINA_FALSE;
326 #else
327 if (lstat(dir, &st) == -1)
328 return EINA_FALSE;
329 is_dir = S_ISDIR(st.st_mode);
330 #endif
331
332 if (is_dir)
333 {
334 Eina_File_Direct_Info *info;
335 Eina_Iterator *it;
336 int ret;
337
338 ret = 1;
339 it = eina_file_direct_ls(dir);
340 EINA_ITERATOR_FOREACH(it, info)
341 {
342 if (!ecore_file_recursive_rm(info->path))
343 ret = 0;
344 }
345 eina_iterator_free(it);
346
347 if (!ecore_file_rmdir(dir)) ret = 0;
348 if (ret)
349 return EINA_TRUE;
350 else
351 return EINA_FALSE;
352 }
353 else
354 {
355 return ecore_file_unlink(dir);
356 }
357 }
358
359 static inline Eina_Bool
360 _ecore_file_mkpath_if_not_exists(const char *path)
361 {
362 Eina_Bool is_dir;
363
364 /* Windows: path like C: or D: etc are valid, but stat() returns an error */
365 #ifdef _WIN32
366 if ((strlen(path) == 2) &&
367 ((path[0] >= 'a' && path[0] <= 'z') ||
368 (path[0] >= 'A' && path[0] <= 'Z')) &&
369 (path[1] == ':'))
370 return EINA_TRUE;
371 #endif
372
373 if (!_ecore_file_stat(path, NULL, NULL, NULL, &is_dir, NULL))
374 return ecore_file_mkdir(path);
375 else if (!is_dir)
376 return EINA_FALSE;
377 else
378 return EINA_TRUE;
379 }
380
381 EAPI Eina_Bool
382 ecore_file_mkpath(const char *path)
383 {
384 char ss[PATH_MAX];
385 unsigned int i;
386
387 EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
388
389 if (ecore_file_is_dir(path))
390 return EINA_TRUE;
391
392 for (i = 0; path[i] != '\0'; ss[i] = path[i], i++)
393 {
394 if (i == sizeof(ss) - 1) return EINA_FALSE;
395 if (((path[i] == '/') || (path[i] == '\\')) && (i > 0))
396 {
397 ss[i] = '\0';
398 if (!_ecore_file_mkpath_if_not_exists(ss))
399 return EINA_FALSE;
400 }
401 }
402 ss[i] = '\0';
403 return _ecore_file_mkpath_if_not_exists(ss);
404 }
405
406 EAPI int
407 ecore_file_mkpaths(const char **paths)
408 {
409 int i = 0;
410
411 if (!paths) return -1;
412
413 for (; *paths; paths++)
414 if (ecore_file_mkpath(*paths))
415 i++;
416 return i;
417 }
418
419 EAPI Eina_Bool
420 ecore_file_cp(const char *src, const char *dst)
421 {
422 FILE *f1, *f2;
423 char buf[16384];
424 char realpath1[PATH_MAX], realpath2[PATH_MAX];
425 size_t num;
426 Eina_Bool ret = EINA_TRUE;
427
428 if (!realpath(src, realpath1)) return EINA_FALSE;
429 if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return EINA_FALSE;
430
431 f1 = fopen(src, "rb");
432 if (!f1) return EINA_FALSE;
433 f2 = fopen(dst, "wb");
434 if (!f2)
435 {
436 fclose(f1);
437 return EINA_FALSE;
438 }
439 while ((num = fread(buf, 1, sizeof(buf), f1)) > 0)
440 {
441 if (fwrite(buf, 1, num, f2) != num) ret = EINA_FALSE;
442 }
443 fclose(f1);
444 fclose(f2);
445 return ret;
446 }
447
448 EAPI Eina_Bool
449 ecore_file_mv(const char *src, const char *dst)
450 {
451 char buf[PATH_MAX];
452 int fd;
453
454 if (rename(src, dst))
455 {
456 // File cannot be moved directly because
457 // it resides on a different mount point.
458 if (errno == EXDEV)
459 {
460 mode_t mode;
461 Eina_Bool is_reg;
462
463 // Make sure this is a regular file before
464 // we do anything fancy.
465 if (!_ecore_file_stat(src, NULL, NULL, &mode, NULL, &is_reg))
466 goto FAIL;
467 if (is_reg)
468 {
469 char *dir;
470 Eina_Tmpstr *tmpstr = NULL;
471
472 dir = ecore_file_dir_get(dst);
473 // Since we can't directly rename, try to
474 // copy to temp file in the dst directory
475 // and then rename.
476 snprintf(buf, sizeof(buf), "%s/.%s.tmp.XXXXXX",
477 dir, ecore_file_file_get(dst));
478 free(dir);
479 fd = eina_file_mkstemp(buf, &tmpstr);
480 if (fd < 0) goto FAIL;
481 close(fd);
482
483 // Copy to temp file
484 if (!ecore_file_cp(src, tmpstr))
485 {
486 eina_tmpstr_del(tmpstr);
487 goto FAIL;
488 }
489
490 // Set file permissions of temp file to match src
491 if (chmod(tmpstr, mode) == -1)
492 {
493 eina_tmpstr_del(tmpstr);
494 goto FAIL;
495 }
496
497 // Try to atomically move temp file to dst
498 if (rename(tmpstr, dst))
499 {
500 // If we still cannot atomically move
501 // do a normal copy and hope for the best.
502 if (!ecore_file_cp(tmpstr, dst))
503 {
504 eina_tmpstr_del(tmpstr);
505 goto FAIL;
506 }
507 }
508
509 // Delete temporary file and src
510 ecore_file_unlink(tmpstr);
511 ecore_file_unlink(src);
512 eina_tmpstr_del(tmpstr);
513 goto PASS;
514 }
515 }
516 #ifdef _WIN32
517 if (errno == ENOENT)
518 {
519 struct _stat s;
520 _stat(dst, &s);
521 if (_S_IFREG & s.st_mode)
522 {
523 ecore_file_unlink(dst);
524 if (rename(src, dst))
525 {
526 return EINA_TRUE;
527 }
528 }
529 }
530 #endif
531 goto FAIL;
532 }
533
534 PASS:
535 return EINA_TRUE;
536
537 FAIL:
538 return EINA_FALSE;
539 }
540
541 EAPI Eina_Bool
542 ecore_file_symlink(const char *src, const char *dest)
543 {
544 #ifndef _WIN32
545 return !symlink(src, dest);
546 #else
547 return EINA_FALSE;
548 (void)src;
549 (void)dest;
550 #endif
551 }
552
553 EAPI char *
554 ecore_file_realpath(const char *file)
555 {
556 char buf[PATH_MAX];
557
558 /*
559 * Some implementations of realpath do not conform to the SUS.
560 * And as a result we must prevent a null arg from being passed.
561 */
562 if (!file) return strdup("");
563 if (!realpath(file, buf)) return strdup("");
564
565 return strdup(buf);
566 }
567
568 EAPI const char *
569 ecore_file_file_get(const char *path)
570 {
571 char *result = NULL;
572
573 if (!path) return NULL;
574
575 if ((result = strrchr(path, '/'))) result++;
576 else result = (char *)path;
577
578 #ifdef _WIN32
579 /*
580 * Here, we know that there is no more / in the string beginning at
581 * 'result'. So just check that there is no more \ from it.
582 */
583 {
584 char *result_backslash;
585 if ((result_backslash = strrchr(result, '\\')))
586 result = ++result_backslash;
587 }
588 #endif
589
590 return result;
591 }
592
593 EAPI char *
594 ecore_file_dir_get(const char *file)
595 {
596 char *p;
597 char buf[PATH_MAX];
598
599 if (!file) return NULL;
600 strncpy(buf, file, PATH_MAX);
601 buf[PATH_MAX - 1] = 0;
602 p = dirname(buf);
603 return strdup(p);
604 }
605
606 EAPI Eina_Bool
607 ecore_file_can_read(const char *file)
608 {
609 if (!file) return EINA_FALSE;
610 if (!access(file, R_OK)) return EINA_TRUE;
611 return EINA_FALSE;
612 }
613
614 EAPI Eina_Bool
615 ecore_file_can_write(const char *file)
616 {
617 if (!file) return EINA_FALSE;
618 if (!access(file, W_OK)) return EINA_TRUE;
619 return EINA_FALSE;
620 }
621
622 EAPI Eina_Bool
623 ecore_file_can_exec(const char *file)
624 {
625 #ifdef _WIN32
626 HANDLE h;
627 HANDLE fm;
628 char *base;
629 char *base_nt;
630 LARGE_INTEGER sz;
631 WORD characteristics;
632 #endif
633
634 if (!file || !*file) return EINA_FALSE;
635
636 #ifdef _WIN32
637 /*
638 * we parse the file to check if it is a PE file (EXE or DLL)
639 * and we finally check whether it's a DLL or not.
640 * Reference :
641 * https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
642 */
643 h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL,
644 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
645 if (h == INVALID_HANDLE_VALUE)
646 goto test_bat;
647
648 if (!GetFileSizeEx(h, &sz))
649 goto close_h;
650
651 /* a PE file must have at least the DOS and NT headers */
652 if (sz.QuadPart < (LONGLONG)(sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS)))
653 goto close_h;
654
655 fm = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL);
656 if (fm == NULL)
657 goto close_h;
658
659 base = (char *)MapViewOfFile(fm, FILE_MAP_READ, 0, 0, 0);
660 CloseHandle(fm);
661 if (base == NULL)
662 goto close_h;
663
664 /*
665 * the PE file begins with the DOS header.
666 * First magic number : the DOS header must begin with a DOS magic number,
667 * that is "MZ", that is 0x5a4d, stored in a WORD.
668 */
669 if (*((WORD *)base) != 0x5a4d)
670 goto unmap_view;
671
672 /*
673 * The position of the NT header is located at the offset 0x3c.
674 */
675 base_nt = base + *((DWORD *)(base + 0x3c));
676 /*
677 * The NT header begins with the magic number "PE\0\0", that is
678 * 0x00004550, stored in a DWORD.
679 */
680 if (*((DWORD *)base_nt) != 0x00004550)
681 goto unmap_view;
682
683 /*
684 * to get informations about executable (EXE or DLL), we look at
685 * the 'Characteristics' member of the NT header, located at the offset
686 * 22 (4 for the magic number, 18 for the offset) from base_nt.
687 * https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#characteristics
688 */
689 characteristics = *((WORD *)(base_nt + 4 + 18));
690
691 UnmapViewOfFile(base);
692 CloseHandle(h);
693
694 /*
695 * 0x0002 : if set, EXE or DLL
696 * 0x2000 : if set, DLL
697 */
698 if ((characteristics & 0x0002) && !(characteristics & 0x2000))
699 return EINA_TRUE;
700 unmap_view:
701 UnmapViewOfFile(base);
702 close_h:
703 CloseHandle(h);
704 test_bat:
705 /*
706 * a .bat file, considered as an executable, is only a text file,
707 * so we rely on the extension. Not the best but we cannot do more.
708 */
709 return eina_str_has_extension(file, ".bat");
710 #else
711 if (!access(file, X_OK)) return EINA_TRUE;
712 #endif
713 return EINA_FALSE;
714 }
715
716 EAPI char *
717 ecore_file_readlink(const char *link)
718 {
719 #ifndef _WIN32
720 char buf[PATH_MAX];
721 int count;
722
723 if ((count = readlink(link, buf, sizeof(buf) - 1)) < 0) return NULL;
724 buf[count] = 0;
725 return strdup(buf);
726 #else
727 return NULL;
728 (void)link;
729 #endif
730 }
731
732 EAPI Eina_List *
733 ecore_file_ls(const char *dir)
734 {
735 Eina_File_Direct_Info *info;
736 Eina_Iterator *ls;
737 Eina_List *list = NULL;
738
739 ls = eina_file_direct_ls(dir);
740 if (!ls) return NULL;
741
742 EINA_ITERATOR_FOREACH(ls, info)
743 {
744 char *f;
745
746 f = strdup(info->path + info->name_start);
747 list = eina_list_append(list, f);
748 }
749 eina_iterator_free(ls);
750
751 list = eina_list_sort(list, eina_list_count(list), EINA_COMPARE_CB(strcoll));
752
753 return list;
754 }
755
756 EAPI char *
757 ecore_file_app_exe_get(const char *app)
758 {
759 Eina_Strbuf *buf;
760 char *exe;
761 const char *p;
762 Eina_Bool in_qout_double = EINA_FALSE;
763 Eina_Bool in_qout_single = EINA_FALSE;
764
765 if (!app) return NULL;
766 buf = eina_strbuf_new();
767 if (!buf) return NULL;
768 p = app;
769 if ((p[0] == '~') && (p[1] == '/'))
770 {
771 const char *home = eina_environment_home_get();
772 if (home) eina_strbuf_append(buf, home);
773 p++;
774 }
775 for (; *p; p++)
776 {
777 if (in_qout_double)
778 {
779 if (*p == '\\')
780 {
781 if (p[1]) p++;
782 eina_strbuf_append_char(buf, *p);
783 }
784 else if (*p == '"') in_qout_double = EINA_FALSE;
785 else eina_strbuf_append_char(buf, *p);
786 }
787 else if (in_qout_single)
788 {
789 if (*p == '\\')
790 {
791 if (p[1]) p++;
792 eina_strbuf_append_char(buf, *p);
793 }
794 else if (*p == '\'') in_qout_single = EINA_FALSE;
795 else eina_strbuf_append_char(buf, *p);
796 }
797 else
798 {
799 if (*p == '\\')
800 {
801 if (p[1]) p++;
802 eina_strbuf_append_char(buf, *p);
803 }
804 else if (*p == '"') in_qout_double = EINA_TRUE;
805 else if (*p == '\'') in_qout_single = EINA_TRUE;
806 else
807 {
808 if (isspace((unsigned char)(*p))) break;
809 eina_strbuf_append_char(buf, *p);
810 }
811 }
812 }
813 exe = eina_strbuf_string_steal(buf);
814 eina_strbuf_free(buf);
815 return exe;
816 }
817
818 EAPI char *
819 ecore_file_escape_name(const char *filename)
820 {
821 const char *p;
822 char *q;
823 char buf[PATH_MAX];
824
825 EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
826
827 p = filename;
828 q = buf;
829 while (*p)
830 {
831 if ((q - buf) > (PATH_MAX - 6)) return NULL;
832 if (
833 (*p == ' ') || (*p == '\\') || (*p == '\'') ||
834 (*p == '\"') || (*p == ';') || (*p == '!') ||
835 (*p == '#') || (*p == '$') || (*p == '%') ||
836 (*p == '&') || (*p == '*') || (*p == '(') ||
837 (*p == ')') || (*p == '[') || (*p == ']') ||
838 (*p == '{') || (*p == '}') || (*p == '|') ||
839 (*p == '<') || (*p == '>') || (*p == '?')
840 )
841 {
842 *q = '\\';
843 q++;
844 }
845 else if (*p == '\t')
846 {
847 *q = '\\';
848 q++;
849 *q = '\\';
850 q++;
851 *q = 't';
852 q++;
853 p++;
854 continue;
855 }
856 else if (*p == '\n')
857 {
858 *q = '\\';
859 q++;
860 *q = '\\';
861 q++;
862 *q = 'n';
863 q++;
864 p++;
865 continue;
866 }
867
868 *q = *p;
869 q++;
870 p++;
871 }
872 *q = 0;
873 return strdup(buf);
874 }
875
876 EAPI char *
877 ecore_file_strip_ext(const char *path)
878 {
879 char *p, *file = NULL;
880
881 if (!path)
882 return NULL;
883
884 p = strrchr(path, '.');
885 if (!p)
886 file = strdup(path);
887 else if (p != path)
888 {
889 file = malloc(((p - path) + 1) * sizeof(char));
890 if (file)
891 {
892 memcpy(file, path, (p - path));
893 file[p - path] = 0;
894 }
895 }
896
897 return file;
898 }
899
900 EAPI int
901 ecore_file_dir_is_empty(const char *dir)
902 {
903 Eina_File_Direct_Info *info;
904 Eina_Iterator *it;
905
906 it = eina_file_direct_ls(dir);
907 if (!it) return -1;
908
909 EINA_ITERATOR_FOREACH(it, info)
910 {
911 eina_iterator_free(it);
912 return 0;
913 }
914
915 eina_iterator_free(it);
916 return 1;
917 }
918