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