* eina: fix usage of eina_file_*ls in thread.
[profile/ivi/eina.git] / src / lib / eina_file.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #ifdef HAVE_ALLOCA_H
24 # include <alloca.h>
25 #elif defined __GNUC__
26 # define alloca __builtin_alloca
27 #elif defined _AIX
28 # define alloca __alloca
29 #elif defined _MSC_VER
30 # include <malloc.h>
31 # define alloca _alloca
32 #else
33 # include <stddef.h>
34 # ifdef  __cplusplus
35 extern "C"
36 # endif
37 void *alloca (size_t);
38 #endif
39
40 #include <string.h>
41 #include <stddef.h>
42 #include <dirent.h>
43
44 #ifndef _WIN32
45 # include <sys/types.h>
46 # include <sys/stat.h>
47 # include <unistd.h>
48 #else
49 # include <Evil.h>
50 #endif /* _WIN2 */
51
52 #ifndef _WIN32
53 # define PATH_DELIM '/'
54 #else
55 # define PATH_DELIM '\\'
56 # define NAME_MAX MAX_PATH
57 #endif
58
59 #ifdef __sun
60 # ifndef NAME_MAX
61 #  define NAME_MAX 255
62 # endif
63 #endif
64
65 #include "eina_config.h"
66 #include "eina_private.h"
67
68 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
69 #include "eina_safety_checks.h"
70 #include "eina_file.h"
71 #include "eina_stringshare.h"
72
73 typedef struct _Eina_File_Iterator Eina_File_Iterator;
74 struct _Eina_File_Iterator
75 {
76    Eina_Iterator iterator;
77
78    DIR *dirp;
79    int length;
80
81    char dir[1];
82 };
83
84 static Eina_Bool
85 _eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
86 {
87    struct dirent *dp;
88    char *name;
89    size_t length;
90
91    dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
92
93    do
94      {
95         if (readdir_r(it->dirp, dp, &dp))
96           return EINA_FALSE;
97         if (dp == NULL)
98           return EINA_FALSE;
99      }
100    while ((dp->d_name[0] == '.') &&
101           ((dp->d_name[1] == '\0') ||
102            ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
103
104    length = strlen(dp->d_name);
105    name = alloca(length + 2 + it->length);
106
107    memcpy(name,                  it->dir,    it->length);
108    memcpy(name + it->length,     "/",        1);
109    memcpy(name + it->length + 1, dp->d_name, length + 1);
110
111    *data = (char *)eina_stringshare_add(name);
112    return EINA_TRUE;
113 }
114
115 static DIR *
116 _eina_file_ls_iterator_container(Eina_File_Iterator *it)
117 {
118    return it->dirp;
119 }
120
121 static void
122 _eina_file_ls_iterator_free(Eina_File_Iterator *it)
123 {
124    closedir(it->dirp);
125
126    EINA_MAGIC_SET(&it->iterator, 0);
127    free(it);
128 }
129
130 typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
131 struct _Eina_File_Direct_Iterator
132 {
133    Eina_Iterator iterator;
134
135    DIR *dirp;
136    int length;
137
138    Eina_File_Direct_Info info;
139
140    char dir[1];
141 };
142
143 static Eina_Bool
144 _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
145 {
146    struct dirent *dp;
147    size_t length;
148
149    dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
150
151    do
152      {
153         if (readdir_r(it->dirp, dp, &dp))
154            return EINA_FALSE;
155         if (!dp)
156            return EINA_FALSE;
157
158         length = strlen(dp->d_name);
159         if (it->info.name_start + length + 1 >= PATH_MAX)
160            continue;
161      }
162    while ((dp->d_name[0] == '.') &&
163           ((dp->d_name[1] == '\0') ||
164            ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
165
166    memcpy(it->info.path + it->info.name_start, dp->d_name, length);
167    it->info.name_length = length;
168    it->info.path_length = it->info.name_start + length;
169    it->info.path[it->info.path_length] = '\0';
170    it->info.dirent = dp;
171
172    *data = &it->info;
173    return EINA_TRUE;
174 }
175
176 static DIR *
177 _eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
178 {
179    return it->dirp;
180 }
181
182 static void
183 _eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
184 {
185    closedir(it->dirp);
186
187    EINA_MAGIC_SET(&it->iterator, 0);
188    free(it);
189 }
190
191 /*============================================================================*
192 *                                 Global                                     *
193 *============================================================================*/
194
195 /*============================================================================*
196 *                                   API                                      *
197 *============================================================================*/
198
199 /**
200  * @addtogroup Eina_File_Group File
201  *
202  * @brief Functions to traverse directories and split paths.
203  *
204  * @li eina_file_dir_list() list the content of a directory,
205  * recusrsively or not, and can call a callback function for eachfound
206  * file.
207  * @li eina_file_split() split a path into all the subdirectories that
208  * compose it, according to the separator of the file system.
209  *
210  * @{
211  */
212
213 /**
214  * @brief List all files on the directory calling the function for every file found.
215  *
216  * @param dir The directory name.
217  * @param recursive Iterate recursively in the directory.
218  * @param cb The callback to be called.
219  * @param data The data to pass to the callback.
220  * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
221  *
222  * This function lists all the files in @p dir. To list also all the
223  * sub directoris recursively, @p recursive must be set to #EINA_TRUE,
224  * otherwise it must be set to #EINA_FALSE. For each found file, @p cb
225  * is called and @p data is passed to it.
226  *
227  * If @p cb or @p dir are @c NULL, or if @p dir is a string of size 0,
228  * or if @p dir can not be opened, this function returns #EINA_FALSE
229  * immediately. otherwise, it returns #EINA_TRUE.
230  */
231 EAPI Eina_Bool
232 eina_file_dir_list(const char *dir,
233                    Eina_Bool recursive,
234                    Eina_File_Dir_List_Cb cb,
235                    void *data)
236 {
237 #ifndef _WIN32
238    struct dirent *de;
239    DIR *d;
240
241    EINA_SAFETY_ON_NULL_RETURN_VAL(cb,  EINA_FALSE);
242    EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
243    EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
244
245    d = opendir(dir);
246    if (!d)
247       return EINA_FALSE;
248
249    de = alloca(offsetof(struct dirent, d_name) + pathconf(dir, _PC_NAME_MAX) + 1);
250
251    while ((!readdir_r(d, de, &de) && de))
252      {
253         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
254            continue;
255
256         cb(de->d_name, dir, data);
257         /* d_type is only available on linux and bsd (_BSD_SOURCE) */
258
259         if (recursive == EINA_TRUE)
260           {
261              char *path;
262
263              path = alloca(strlen(dir) + strlen(de->d_name) + 2);
264              strcpy(path, dir);
265              strcat(path, "/");
266              strcat(path, de->d_name);
267 #ifndef sun
268              if (de->d_type == DT_UNKNOWN)
269                {
270 #endif
271              struct stat st;
272
273              if (stat(path, &st))
274                 continue;
275
276              if (!S_ISDIR(st.st_mode))
277                 continue;
278
279 #ifndef sun
280           }
281         else if (de->d_type != DT_DIR)
282            continue;
283
284 #endif
285
286              eina_file_dir_list(path, recursive, cb, data);
287           }
288      }
289
290    closedir(d);
291 #else
292    WIN32_FIND_DATA file;
293    HANDLE hSearch;
294    char *new_dir;
295    TCHAR *tdir;
296    size_t length_dir;
297
298    EINA_SAFETY_ON_NULL_RETURN_VAL(cb,  EINA_FALSE);
299    EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
300    EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
301
302    length_dir = strlen(dir);
303    new_dir = (char *)alloca(length_dir + 5);
304    if (!new_dir)
305       return EINA_FALSE;
306
307    memcpy(new_dir,              dir,    length_dir);
308    memcpy(new_dir + length_dir, "/*.*", 5);
309
310 #ifdef UNICODE
311    tdir = evil_char_to_wchar(new_dir);
312 #else
313    tdir = new_dir;
314 #endif /* ! UNICODE */
315    hSearch = FindFirstFile(tdir, &file);
316 #ifdef UNICODE
317    free(tdir);
318 #endif /* UNICODE */
319
320    if (hSearch == INVALID_HANDLE_VALUE)
321       return EINA_FALSE;
322
323    do
324      {
325         char *filename;
326
327 #ifdef UNICODE
328         filename = evil_wchar_to_char(file.cFileName);
329 #else
330         filename = file.cFileName;
331 #endif /* ! UNICODE */
332         if (!strcmp(filename, ".") || !strcmp(filename, ".."))
333            continue;
334
335         cb(filename, dir, data);
336
337         if (recursive == EINA_TRUE)
338           {
339              char *path;
340
341              path = alloca(strlen(dir) + strlen(filename) + 2);
342              strcpy(path, dir);
343              strcat(path, "/");
344              strcat(path, filename);
345
346              if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
347                 continue;
348
349              eina_file_dir_list(path, recursive, cb, data);
350           }
351
352 #ifdef UNICODE
353         free(filename);
354 #endif /* UNICODE */
355
356      } while (FindNextFile(hSearch, &file));
357    FindClose(hSearch);
358 #endif /* _WIN32 */
359
360    return EINA_TRUE;
361 }
362
363 /**
364  * @brief Split a path according to the delimiter of the filesystem.
365  *
366  * @param path The path to split.
367  * @return An array of the parts of the path to split.
368  *
369  * This function splits @p path according to the delimiter of the used
370  * filesystem. If  @p path is @c NULL or if the array can not be
371  * created, @c NULL is returned, otherwise, an array with the
372  * different parts of @p path is returned.
373  */
374 EAPI Eina_Array *
375 eina_file_split(char *path)
376 {
377    Eina_Array *ea;
378    char *current;
379    size_t length;
380
381    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
382
383    ea = eina_array_new(16);
384
385    if (!ea)
386       return NULL;
387
388    for (current = strchr(path, PATH_DELIM);
389         current;
390         path = current + 1, current = strchr(path, PATH_DELIM))
391      {
392         length = current - path;
393
394         if (length <= 0)
395            continue;
396
397         eina_array_push(ea, path);
398         *current = '\0';
399      }
400
401    if (*path != '\0')
402         eina_array_push(ea, path);
403
404    return ea;
405 }
406
407 /**
408  * Get an iterator to list the content of a directory.
409  *
410  * Iterators are cheap to be created and allow interruption at any
411  * iteration. At each iteration, only the next directory entry is read
412  * from the filesystem with readdir_r().
413  *
414  * The iterator will handle the user a stringshared value with the
415  * full path. One must call eina_stringshare_del() on it after usage
416  * to not leak!
417  *
418  * The eina_file_direct_ls() function will provide a possibly faster
419  * alternative if you need to filter the results somehow, like
420  * checking extension.
421  *
422  * The iterator will walk over '.' and '..' without returning them.
423  *
424  * The iterator container is the DIR* corresponding to the current walk.
425  *
426  * @param  dir The name of the directory to list
427  * @return Return an Eina_Iterator that will walk over the files and
428  *         directory in the pointed directory. On failure it will
429  *         return NULL. The iterator emits stringshared value with the
430  *         full path and must be freed with eina_stringshare_del().
431  *
432  * @see eina_file_direct_ls()
433  */
434 EAPI Eina_Iterator *
435 eina_file_ls(const char *dir)
436 {
437    Eina_File_Iterator *it;
438    size_t length;
439
440    if (!dir)
441       return NULL;
442
443    length = strlen(dir);
444    if (length < 1)
445       return NULL;
446
447    it = calloc(1, sizeof (Eina_File_Iterator) + length);
448    if (!it)
449       return NULL;
450
451    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
452
453    it->dirp = opendir(dir);
454    if (!it->dirp)
455      {
456         free(it);
457         return NULL;
458      }
459
460    memcpy(it->dir, dir, length + 1);
461    if (dir[length - 1] != '/')
462       it->length = length;
463    else
464       it->length = length - 1;
465
466    it->iterator.version = EINA_ITERATOR_VERSION;
467    it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
468    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
469          _eina_file_ls_iterator_container);
470    it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
471
472    return &it->iterator;
473 }
474
475 /**
476  * Get an iterator to list the content of a directory, with direct information.
477  *
478  * Iterators are cheap to be created and allow interruption at any
479  * iteration. At each iteration, only the next directory entry is read
480  * from the filesystem with readdir_r().
481  *
482  * The iterator returns the direct pointer to couple of useful information in
483  * #Eina_File_Direct_Info and that pointer should not be modified anyhow!
484  *
485  * The iterator will walk over '.' and '..' without returning them.
486  *
487  * The iterator container is the DIR* corresponding to the current walk.
488  *
489  * @param  dir The name of the directory to list
490
491  * @return Return an Eina_Iterator that will walk over the files and
492  *         directory in the pointed directory. On failure it will
493  *         return NULL. The iterator emits #Eina_File_Direct_Info
494  *         pointers that could be used but not modified. The lifetime
495  *         of the returned pointer is until the next iteration and
496  *         while the iterator is live, deleting the iterator
497  *         invalidates the pointer.
498  *
499  * @see eina_file_ls()
500  */
501 EAPI Eina_Iterator *
502 eina_file_direct_ls(const char *dir)
503 {
504    Eina_File_Direct_Iterator *it;
505    size_t length;
506
507    if (!dir)
508       return NULL;
509
510    length = strlen(dir);
511    if (length < 1)
512       return NULL;
513
514    if (length + NAME_MAX + 2 >= PATH_MAX)
515       return NULL;
516
517    it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
518    if (!it)
519       return NULL;
520
521    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
522
523    it->dirp = opendir(dir);
524    if (!it->dirp)
525      {
526         free(it);
527         return NULL;
528      }
529
530    memcpy(it->dir,       dir, length + 1);
531    it->length = length;
532
533    memcpy(it->info.path, dir, length);
534    if (dir[length - 1] == '/')
535       it->info.name_start = length;
536    else
537      {
538         it->info.path[length] = '/';
539         it->info.name_start = length + 1;
540      }
541
542    it->iterator.version = EINA_ITERATOR_VERSION;
543    it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
544    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
545          _eina_file_direct_ls_iterator_container);
546    it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
547
548    return &it->iterator;
549 }
550
551 /**
552  * @}
553  */