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