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