ec0a1f72ba509225b33790b90097a759ff7e45f0
[profile/ivi/ecore.git] / src / lib / ecore_file / ecore_file.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6 #include <string.h>
7
8 #ifndef _MSC_VER
9 # include <unistd.h>
10 # include <libgen.h>
11 #endif
12
13 #ifndef _FILE_OFFSET_BITS
14 # define _FILE_OFFSET_BITS  64
15 #endif
16
17 #ifdef HAVE_FEATURES_H
18 # include <features.h>
19 #endif
20 #include <ctype.h>
21 #include <errno.h>
22
23 #include "ecore_file_private.h"
24
25 int _ecore_file_log_dom = -1;
26 static int _ecore_file_init_count = 0;
27
28 /* externally accessible functions */
29 /**
30  * Initialize Ecore_File and the services it will use. Call this function
31  * once before you use any of the ecore file functions.
32  * @return Return the number howoften ecore_file_init() was call succesfully;
33  *         0 if it failed.
34  */
35 EAPI int
36 ecore_file_init()
37 {
38    if (++_ecore_file_init_count != 1)
39      return _ecore_file_init_count;
40    _ecore_file_log_dom = eina_log_domain_register("EcoreFile", ECORE_FILE_DEFAULT_LOG_COLOR);
41    if(_ecore_file_log_dom < 0) 
42      {
43        EINA_LOG_ERR("Impossible to create a log domain for the ecore file module.");
44        return --_ecore_file_init_count;
45      }
46    ecore_file_path_init();
47    ecore_file_monitor_init();
48    ecore_file_download_init();
49
50    /* FIXME: were the tests disabled for a good reason ? */
51
52    /*
53    if (!ecore_file_monitor_init())
54      goto shutdown_ecore_file_path;
55
56    if (!ecore_file_download_init())
57      goto shutdown_ecore_file_monitor;
58    */
59
60    return _ecore_file_init_count;
61
62    /*
63  shutdown_ecore_file_monitor:
64    ecore_file_monitor_shutdown();
65  shutdown_ecore_file_path:
66    ecore_file_path_shutdown();
67
68    return --_ecore_file_init_count;
69    */
70 }
71
72 /**
73  * Shutdown the Ecore_File
74  * @return returns the number of libraries that still uses Ecore_File
75  */
76 EAPI int
77 ecore_file_shutdown()
78 {
79    if (--_ecore_file_init_count != 0)
80      return _ecore_file_init_count;
81
82    ecore_file_download_shutdown();
83    ecore_file_monitor_shutdown();
84    ecore_file_path_shutdown();
85    eina_log_domain_unregister(_ecore_file_log_dom);
86    _ecore_file_log_dom = -1;
87    return _ecore_file_init_count;
88 }
89
90 /**
91  * Get the time of the last modification to the give file
92  * @param file The name of the file
93  * @return Return the time of the last data modification, if an error should
94  *         occur it will return 0
95  */
96 EAPI long long
97 ecore_file_mod_time(const char *file)
98 {
99    struct stat st;
100
101    if (stat(file, &st) < 0) return 0;
102    return st.st_mtime;
103 }
104
105 /**
106  * Get the size of the given file
107  * @param  file The name of the file
108  * @return The size of the file in byte
109  */
110 EAPI long long
111 ecore_file_size(const char *file)
112 {
113    struct stat st;
114
115    if (stat(file, &st) < 0) return 0;
116    return st.st_size;
117 }
118
119 /**
120  * Check if file exists
121  * @param  file The name of the file
122  * @return EINA_TRUE if file exists on local filesystem, EINA_FALSE otherwise
123  */
124 EAPI Eina_Bool
125 ecore_file_exists(const char *file)
126 {
127    struct stat st;
128
129    /*Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor*/
130    if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE;
131    return EINA_TRUE;
132 }
133
134 /**
135  * Check if file is a directory
136  * @param  file The name of the file
137  * @return EINA_TRUE if file exist and is a directory, EINA_FALSE otherwise
138  */
139 EAPI Eina_Bool
140 ecore_file_is_dir(const char *file)
141 {
142    struct stat st;
143
144    if (stat(file, &st) < 0) return EINA_FALSE;
145    if (S_ISDIR(st.st_mode)) return EINA_TRUE;
146    return EINA_FALSE;
147 }
148
149 static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
150
151 /**
152  * Create a new directory
153  * @param  dir The name of the directory to create
154  * @return EINA_TRUE on successfull creation, EINA_FALSE on failure
155  *
156  * The directory is created with the mode: S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
157  */
158 EAPI Eina_Bool
159 ecore_file_mkdir(const char *dir)
160 {
161    if (mkdir(dir, default_mode) < 0) return EINA_FALSE;
162    return EINA_TRUE;
163 }
164
165 /**
166  * Create complete directory in a batch.
167  *
168  * @param dirs list of directories, null terminated.
169  * @return number of successfull directories created, -1 if dirs is NULL.
170  *
171  * @see ecore_file_mkdir() and ecore_file_mkpaths()
172  */
173 EAPI int
174 ecore_file_mkdirs(const char **dirs)
175 {
176    int i = 0;
177
178    if (!dirs) return -1;
179
180    for (; *dirs; dirs++)
181      if (ecore_file_mkdir(*dirs))
182        i++;
183    return i;
184 }
185
186 /**
187  * Create complete list of sub-directories in a batch (optimized).
188  *
189  * @param base the base directory to act on, will be created if does
190  *     not exists.
191  * @param subdirs list of directories, null terminated. These are
192  *     created similarly to ecore_file_mkdir(), so same mode and whole
193  *     path to that point must exists. So if creating base/a/b/c,
194  *     provide subdirs with "a", "a/b" and "a/b/c" in that order!
195  *
196  * @return number of successfull directories created, -1 if subdirs or
197  *     base is NULL or invalid.
198  *
199  * @see ecore_file_mkdir() and ecore_file_mkpaths()
200  */
201 EAPI int
202 ecore_file_mksubdirs(const char *base, const char **subdirs)
203 {
204 #ifndef HAVE_ATFILE_SOURCE
205    char buf[PATH_MAX];
206    int baselen;
207 #else
208    int fd;
209    DIR *dir;
210 #endif
211    int i;
212
213    if (!subdirs) return -1;
214    if ((!base) || (base[0] == '\0')) return -1;
215
216    if ((!ecore_file_is_dir(base)) && (!ecore_file_mkpath(base)))
217      return 0;
218
219 #ifndef HAVE_ATFILE_SOURCE
220    baselen = eina_strlcpy(buf, base, sizeof(buf));
221    if ((baselen < 1) || (baselen + 1 >= (int)sizeof(buf)))
222      return 0;
223
224    if (buf[baselen - 1] != '/')
225      {
226         buf[baselen] = '/';
227         baselen++;
228      }
229 #else
230    dir = opendir(base);
231    if (!dir)
232      return 0;
233    fd = dirfd(dir);
234 #endif
235
236    i = 0;
237    for (; *subdirs; subdirs++)
238      {
239         struct stat st;
240
241 #ifndef HAVE_ATFILE_SOURCE
242         eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen);
243         if (stat(buf, &st) == 0)
244 #else
245         if (fstatat(fd, *subdirs, &st, 0) == 0)
246 #endif
247           {
248              if (S_ISDIR(st.st_mode))
249                {
250                   i++;
251                   continue;
252                }
253           }
254         else
255           {
256              if (errno == ENOENT)
257                {
258 #ifndef HAVE_ATFILE_SOURCE
259                   if (mkdir(buf, default_mode) == 0)
260 #else
261                   if (mkdirat(fd, *subdirs, default_mode) == 0)
262 #endif
263                     {
264                        i++;
265                        continue;
266                     }
267                  }
268             }
269      }
270
271 #ifdef HAVE_ATFILE_SOURCE
272    closedir(dir);
273 #endif
274
275    return i;
276 }
277
278 /**
279  * Delete the given dir
280  * @param  dir The name of the directory to delete
281  * @return EINA_TRUE on success, EINA_FALSE on failure
282  */
283 EAPI Eina_Bool
284 ecore_file_rmdir(const char *dir)
285 {
286    if (rmdir(dir) < 0) return EINA_FALSE;
287    return EINA_TRUE;
288 }
289
290 /**
291  * Delete the given file
292  * @param  file The name of the file to delete
293  * @return EINA_TRUE on success, EINA_FALSE on failure
294  */
295 EAPI Eina_Bool
296 ecore_file_unlink(const char *file)
297 {
298    if (unlink(file) < 0) return EINA_FALSE;
299    return EINA_TRUE;
300 }
301
302 /**
303  * Remove the given file or directory
304  * @param  file The name of the file or directory to delete
305  * @return EINA_TRUE on success, EINA_FALSE on failure
306  */
307 EAPI Eina_Bool
308 ecore_file_remove(const char *file)
309 {
310    if (remove(file) < 0) return EINA_FALSE;
311    return EINA_TRUE;
312 }
313
314 /**
315  * Delete a directory and all its contents
316  * @param  dir The name of the directory to delete
317  * @return EINA_TRUE on success, EINA_FALSE on failure
318  *
319  * If dir is a link only the link is removed
320  */
321 EAPI Eina_Bool
322 ecore_file_recursive_rm(const char *dir)
323 {
324    DIR *dirp;
325    struct dirent *dp;
326    char path[PATH_MAX], buf[PATH_MAX];
327    struct stat st;
328    int ret;
329
330    if (readlink(dir, buf, sizeof(buf)) > 0)
331      return ecore_file_unlink(dir);
332
333    ret = stat(dir, &st);
334    if ((ret == 0) && (S_ISDIR(st.st_mode)))
335      {
336         ret = 1;
337         if (stat(dir, &st) == -1) return EINA_FALSE;
338         dirp = opendir(dir);
339         if (dirp)
340           {
341              while ((dp = readdir(dirp)))
342                {
343                   if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
344                     {
345                        snprintf(path, PATH_MAX, "%s/%s", dir, dp->d_name);
346                        if (!ecore_file_recursive_rm(path))
347                          ret = 0;
348                     }
349                }
350              closedir(dirp);
351           }
352         if (!ecore_file_rmdir(dir)) ret = 0;
353         if (ret)
354             return EINA_TRUE;
355         else
356             return EINA_FALSE;
357      }
358    else
359      {
360         if (ret == -1) return EINA_FALSE;
361         return ecore_file_unlink(dir);
362      }
363 }
364
365 static inline Eina_Bool
366 _ecore_file_mkpath_if_not_exists(const char *path)
367 {
368    struct stat st;
369
370    if (stat(path, &st) < 0)
371      return ecore_file_mkdir(path);
372    else if (!S_ISDIR(st.st_mode))
373      return EINA_FALSE;
374    else
375      return EINA_TRUE;
376 }
377
378 /**
379  * Create a complete path
380  * @param  path The path to create
381  * @return EINA_TRUE on success, EINA_FALSE on failure
382  *
383  * @see ecore_file_mkpaths() and ecore_file_mkdir()
384  */
385 EAPI Eina_Bool
386 ecore_file_mkpath(const char *path)
387 {
388    char ss[PATH_MAX];
389    unsigned int i;
390
391    if (ecore_file_is_dir(path))
392      return EINA_TRUE;
393
394    for (i = 0; path[i] != '\0'; ss[i] = path[i], i++)
395      {
396         if (i == sizeof(ss) - 1) return EINA_FALSE;
397         if ((path[i] == '/') && (i > 0))
398           {
399              ss[i] = '\0';
400              if (!_ecore_file_mkpath_if_not_exists(ss))
401                return EINA_FALSE;
402           }
403      }
404    ss[i] = '\0';
405    return _ecore_file_mkpath_if_not_exists(ss);
406 }
407
408 /**
409  * Create complete paths in a batch.
410  *
411  * @param paths list of paths, null terminated.
412  * @return number of successfull paths created, -1 if paths is NULL.
413  *
414  * @see ecore_file_mkpath() and ecore_file_mkdirs()
415  */
416 EAPI int
417 ecore_file_mkpaths(const char **paths)
418 {
419    int i = 0;
420
421    if (!paths) return -1;
422
423    for (; *paths; paths++)
424      if (ecore_file_mkpath(*paths))
425        i++;
426    return i;
427 }
428
429 /**
430  * Copy a file
431  * @param  src The name of the source file
432  * @param  dst The name of the destination file
433  * @return EINA_TRUE on success, EINA_FALSE on failure
434  */
435 EAPI Eina_Bool
436 ecore_file_cp(const char *src, const char *dst)
437 {
438    FILE *f1, *f2;
439    char buf[16384];
440    char realpath1[PATH_MAX], realpath2[PATH_MAX];
441    size_t num;
442    Eina_Bool ret = EINA_TRUE;
443
444    if (!realpath(src, realpath1)) return EINA_FALSE;
445    if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return EINA_FALSE;
446
447    f1 = fopen(src, "rb");
448    if (!f1) return EINA_FALSE;
449    f2 = fopen(dst, "wb");
450    if (!f2)
451      {
452         fclose(f1);
453         return EINA_FALSE;
454      }
455    while ((num = fread(buf, 1, sizeof(buf), f1)) > 0)
456      {
457         if (fwrite(buf, 1, num, f2) != num) ret = EINA_FALSE;
458      }
459    fclose(f1);
460    fclose(f2);
461    return ret;
462 }
463
464 /**
465  * Move a file
466  * @param  src The name of the source file
467  * @param  dst The name of the destination file
468  * @return EINA_TRUE on success, EINA_FALSE on failure
469  */
470 EAPI Eina_Bool
471 ecore_file_mv(const char *src, const char *dst)
472 {
473    char buf[PATH_MAX];
474    int fd;
475
476    if (rename(src, dst))
477      {
478         // File cannot be moved directly because
479         // it resides on a different mount point.
480         if (errno == EXDEV)
481           {
482              struct stat st;
483
484              // Make sure this is a regular file before
485              // we do anything fancy.
486              stat(src, &st);
487              if (S_ISREG(st.st_mode))
488                {
489                   char *dir;
490
491                   dir = ecore_file_dir_get(dst);
492                   // Since we can't directly rename, try to 
493                   // copy to temp file in the dst directory
494                   // and then rename.
495                   snprintf(buf, sizeof(buf), "%s/.%s.tmp.XXXXXX", 
496                            dir, ecore_file_file_get(dst));
497                   free(dir);
498                   fd = mkstemp(buf);
499                   if (fd < 0)
500                     {
501                        perror("mkstemp");
502                        goto FAIL;
503                     }
504                   close(fd);
505
506                   // Copy to temp file
507                   if (!ecore_file_cp(src, buf))
508                     goto FAIL;
509
510                   // Set file permissions of temp file to match src
511                   chmod(buf, st.st_mode);
512
513                   // Try to atomically move temp file to dst
514                   if (rename(buf, dst))
515                     {
516                        // If we still cannot atomically move
517                        // do a normal copy and hope for the best.
518                        if (!ecore_file_cp(buf, dst))
519                          goto FAIL;
520                     }
521
522                   // Delete temporary file and src
523                   ecore_file_unlink(buf);
524                   ecore_file_unlink(src);
525                   goto PASS;
526                }
527           }
528         goto FAIL;
529      }
530
531 PASS:
532    return EINA_TRUE;
533
534 FAIL:
535    return EINA_FALSE;
536 }
537
538 /**
539  * Create a symbolic link
540  * @param  src The name of the file to link
541  * @param  dest The name of link
542  * @return EINA_TRUE on success, EINA_FALSE on failure
543  */
544 EAPI Eina_Bool
545 ecore_file_symlink(const char *src, const char *dest)
546 {
547    if (!symlink(src, dest)) return EINA_TRUE;
548
549    return EINA_FALSE;
550 }
551
552 /**
553  * Get the canonicalized absolute pathname
554  * @param  file The file path
555  * @return The canonicalized absolute pathname; on failure it will return
556  *         an empty string
557  */
558 EAPI char *
559 ecore_file_realpath(const char *file)
560 {
561    char buf[PATH_MAX];
562
563    /*
564     * Some implementations of realpath do not conform to the SUS.
565     * And as a result we must prevent a null arg from being passed.
566     */
567    if (!file) return strdup("");
568    if (!realpath(file, buf)) return strdup("");
569
570    return strdup(buf);
571 }
572
573 /**
574  * Get the filename from a give path
575  * @param  path The complete path
576  * @return Only the file name
577  */
578 EAPI const char *
579 ecore_file_file_get(const char *path)
580 {
581    char *result = NULL;
582
583    if (!path) return NULL;
584    if ((result = strrchr(path, '/'))) result++;
585    else result = (char *)path;
586    return result;
587 }
588
589 /**
590  * Get the directory where file reside
591  * @param  file The name of the file
592  * @return The directory name
593  */
594 EAPI char *
595 ecore_file_dir_get(const char *file)
596 {
597    char *p;
598    char buf[PATH_MAX];
599
600    if (!file) return NULL;
601    strncpy(buf, file, PATH_MAX);
602    buf[PATH_MAX - 1] = 0;
603    p = dirname(buf);
604    return strdup(p);
605 }
606
607 /**
608  * Check if file can be read
609  * @param  file The name of the file
610  * @return EINA_TRUE if the file is readable, EINA_FALSE otherwise
611  */
612 EAPI Eina_Bool
613 ecore_file_can_read(const char *file)
614 {
615    if (!file) return EINA_FALSE;
616    if (!access(file, R_OK)) return EINA_TRUE;
617    return EINA_FALSE;
618 }
619
620 /**
621  * Check if file can be written
622  * @param  file The name of the file
623  * @return EINA_TRUE if the file is writable, EINA_FALSE otherwise
624  */
625 EAPI Eina_Bool
626 ecore_file_can_write(const char *file)
627 {
628    if (!file) return EINA_FALSE;
629    if (!access(file, W_OK)) return EINA_TRUE;
630    return EINA_FALSE;
631 }
632
633 /**
634  * Check if file can be executed
635  * @param  file The name of the file
636  * @return EINA_TRUE if the file can be executed, EINA_FALSE otherwise
637  */
638 EAPI Eina_Bool
639 ecore_file_can_exec(const char *file)
640 {
641    if (!file) return EINA_FALSE;
642    if (!access(file, X_OK)) return EINA_TRUE;
643    return EINA_FALSE;
644 }
645
646 /**
647  * Get the path pointed by link
648  * @param  link The name of the link
649  * @return The path pointed by link or NULL
650  */
651 EAPI char *
652 ecore_file_readlink(const char *link)
653 {
654    char buf[PATH_MAX];
655    int count;
656
657    if ((count = readlink(link, buf, sizeof(buf) - 1)) < 0) return NULL;
658    buf[count] = 0;
659    return strdup(buf);
660 }
661
662 /**
663  * Get the list of the files and directories in a given directory. The list
664  * will be sorted with strcoll as compare function. That means that you may
665  * want to set the current locale for the category LC_COLLATE with setlocale().
666  * For more information see the manual pages of strcoll and setlocale.
667  * The list will not contain the directory entries for '.' and '..'.
668  * @param  dir The name of the directory to list
669  * @return Return an Eina_List containing all the files in the directory;
670  *         on failure it returns NULL.
671  */
672 EAPI Eina_List *
673 ecore_file_ls(const char *dir)
674 {
675    char *f;
676    DIR *dirp;
677    struct dirent *dp;
678    Eina_List *list = NULL;
679
680    dirp = opendir(dir);
681    if (!dirp) return NULL;
682
683    while ((dp = readdir(dirp)))
684      {
685         if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
686           {
687                f = strdup(dp->d_name);
688                list = eina_list_append(list, f);
689           }
690      }
691    closedir(dirp);
692
693    list = eina_list_sort(list, eina_list_count(list), EINA_COMPARE_CB(strcoll));
694
695    return list;
696 }
697
698 /**
699  * FIXME: To be documented.
700  */
701 EAPI char *
702 ecore_file_app_exe_get(const char *app)
703 {
704    char *p, *pp, *exe1 = NULL, *exe2 = NULL;
705    char *exe = NULL;
706    int in_quot_dbl = 0, in_quot_sing = 0, restart = 0;
707
708    if (!app) return NULL;
709
710    p = (char *)app;
711 restart:
712    while ((*p) && (isspace(*p))) p++;
713    exe1 = p;
714    while (*p)
715      {
716         if (in_quot_sing)
717           {
718              if (*p == '\'')
719                in_quot_sing = 0;
720           }
721         else if (in_quot_dbl)
722           {
723              if (*p == '\"')
724                in_quot_dbl = 0;
725           }
726         else
727           {
728              if (*p == '\'')
729                in_quot_sing = 1;
730              else if (*p == '\"')
731                in_quot_dbl = 1;
732              if ((isspace(*p)) && (!((p > app) && (p[-1] != '\\'))))
733                break;
734           }
735         p++;
736      }
737    exe2 = p;
738    if (exe2 == exe1) return NULL;
739    if (*exe1 == '~')
740      {
741         char *homedir;
742         int len;
743
744         /* Skip ~ */
745         exe1++;
746
747         homedir = getenv("HOME");
748         if (!homedir) return NULL;
749         len = strlen(homedir);
750         if (exe) free(exe);
751         exe = malloc(len + exe2 - exe1 + 2);
752         if (!exe) return NULL;
753         pp = exe;
754         if (len)
755           {
756              strcpy(exe, homedir);
757              pp += len;
758              if (*(pp - 1) != '/')
759                {
760                   *pp = '/';
761                   pp++;
762                }
763           }
764      }
765    else
766      {
767         if (exe) free(exe);
768         exe = malloc(exe2 - exe1 + 1);
769         if (!exe) return NULL;
770         pp = exe;
771      }
772    p = exe1;
773    restart = 0;
774    in_quot_dbl = 0;
775    in_quot_sing = 0;
776    while (*p)
777      {
778         if (in_quot_sing)
779           {
780              if (*p == '\'')
781                in_quot_sing = 0;
782              else
783                {
784                   *pp = *p;
785                   pp++;
786                }
787           }
788         else if (in_quot_dbl)
789           {
790              if (*p == '\"')
791                in_quot_dbl = 0;
792              else
793                {
794                   /* techcincally this is wrong. double quotes also accept
795                    * special chars:
796                    *
797                    * $, `, \
798                    */
799                   *pp = *p;
800                   pp++;
801                }
802           }
803         else
804           {
805              /* technically we should handle special chars:
806               *
807               * $, `, \, etc.
808               */
809              if ((p > exe1) && (p[-1] == '\\'))
810                {
811                   if (*p != '\n')
812                     {
813                        *pp = *p;
814                        pp++;
815                     }
816                }
817              else if ((p > exe1) && (*p == '='))
818                {
819                   restart = 1;
820                   *pp = *p;
821                   pp++;
822                }
823              else if (*p == '\'')
824                in_quot_sing = 1;
825              else if (*p == '\"')
826                in_quot_dbl = 1;
827              else if (isspace(*p))
828                {
829                   if (restart)
830                     goto restart;
831                   else
832                     break;
833                }
834              else
835                {
836                   *pp = *p;
837                   pp++;
838                }
839           }
840         p++;
841      }
842    *pp = 0;
843    return exe;
844 }
845
846 /**
847  * Add the escape sequence ('\\') to the given filename
848  * @param  filename The file name
849  * @return The file name with special characters escaped; if the length of the
850  *         resulting string is longer than PATH_MAX it will return NULL
851  */
852 EAPI char *
853 ecore_file_escape_name(const char *filename)
854 {
855    const char *p;
856    char *q;
857    char buf[PATH_MAX];
858
859    p = filename;
860    q = buf;
861    while (*p)
862      {
863         if ((q - buf) > (PATH_MAX - 6)) return NULL;
864         if (
865             (*p == ' ') || (*p == '\t') || (*p == '\n') ||
866             (*p == '\\') || (*p == '\'') || (*p == '\"') ||
867             (*p == ';') || (*p == '!') || (*p == '#') ||
868             (*p == '$') || (*p == '%') || (*p == '&') ||
869             (*p == '*') || (*p == '(') || (*p == ')') ||
870             (*p == '[') || (*p == ']') || (*p == '{') ||
871             (*p == '}') || (*p == '|') || (*p == '<') ||
872             (*p == '>') || (*p == '?')
873             )
874           {
875              *q = '\\';
876              q++;
877           }
878         *q = *p;
879         q++;
880         p++;
881      }
882    *q = 0;
883    return strdup(buf);
884 }
885
886 /**
887  * Remove the extension from a given path
888  * @param  path The name of the file
889  * @return A newly allocated string with the extension stripped out or NULL on errors
890  */
891 EAPI char *
892 ecore_file_strip_ext(const char *path)
893 {
894    char *p, *file = NULL;
895
896    p = strrchr(path, '.');
897    if (!p)
898      file = strdup(path);
899    else if (p != path)
900      {
901         file = malloc(((p - path) + 1) * sizeof(char));
902         if (file)
903           {
904              memcpy(file, path, (p - path));
905              file[p - path] = 0;
906           }
907      }
908
909    return file;
910 }
911
912 /**
913  * Check if the given directory is empty. The '.' and '..' files will be ignored.
914  * @param  dir The name of the directory to check
915  * @return 1 if directory is empty, 0 if it has at least one file or -1 in case of errors
916  */
917 EAPI int
918 ecore_file_dir_is_empty(const char *dir)
919 {
920    DIR *dirp;
921    struct dirent *dp;
922
923    dirp = opendir(dir);
924    if (!dirp) return -1;
925
926    while ((dp = readdir(dirp)))
927      {
928         if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
929           {
930              closedir(dirp);
931              return 0;
932           }
933      }
934    
935    closedir(dirp);
936    return 1;
937 }