Apache SINGA
A distributed deep learning platform .
 All Classes Namespaces Files Functions Variables Typedefs Macros
tinydir.h
1 /*
2 Copyright (c) 2013-2014, Cong Xu, Baudouin Feildel
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 
8 1. Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation
12  and/or other materials provided with the distribution.
13 
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 #ifndef TINYDIR_H
26 #define TINYDIR_H
27 
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #ifdef _WIN32
32 #define WIN32_LEAN_AND_MEAN
33 #include <windows.h>
34 #ifdef _MSC_VER
35 #pragma warning (disable : 4996)
36 #endif
37 #else
38 #include <dirent.h>
39 #include <libgen.h>
40 #include <sys/stat.h>
41 #endif
42 
43 
44 /* types */
45 
46 #define _TINYDIR_PATH_MAX 4096
47 #ifdef _WIN32
48 /* extra chars for the "\\*" mask */
49 #define _TINYDIR_PATH_EXTRA 2
50 #else
51 #define _TINYDIR_PATH_EXTRA 0
52 #endif
53 #define _TINYDIR_FILENAME_MAX 256
54 
55 #ifdef _MSC_VER
56 #define _TINYDIR_FUNC static __inline
57 #else
58 #define _TINYDIR_FUNC static __inline__
59 #endif
60 
61 /* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
62 #if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
63 #elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
64 #else
65 #error "Either define both alloc and free or none of them!"
66 #endif
67 
68 #if !defined(_TINYDIR_MALLOC)
69  #define _TINYDIR_MALLOC(_size) malloc(_size)
70  #define _TINYDIR_FREE(_ptr) free(_ptr)
71 #endif
72 
73 typedef struct
74 {
75  char path[_TINYDIR_PATH_MAX];
76  char name[_TINYDIR_FILENAME_MAX];
77  char *extension;
78  int is_dir;
79  int is_reg;
80 
81 #ifdef _WIN32
82 #else
83  struct stat _s;
84 #endif
85 } tinydir_file;
86 
87 typedef struct
88 {
89  char path[_TINYDIR_PATH_MAX];
90  int has_next;
91  size_t n_files;
92 
93  tinydir_file *_files;
94 #ifdef _WIN32
95  HANDLE _h;
96  WIN32_FIND_DATAA _f;
97 #else
98  DIR *_d;
99  struct dirent *_e;
100 #endif
101 } tinydir_dir;
102 
103 
104 /* declarations */
105 
106 _TINYDIR_FUNC
107 int tinydir_open(tinydir_dir *dir, const char *path);
108 _TINYDIR_FUNC
109 int tinydir_open_sorted(tinydir_dir *dir, const char *path);
110 _TINYDIR_FUNC
111 void tinydir_close(tinydir_dir *dir);
112 
113 _TINYDIR_FUNC
114 int tinydir_next(tinydir_dir *dir);
115 _TINYDIR_FUNC
116 int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
117 _TINYDIR_FUNC
118 int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
119 _TINYDIR_FUNC
120 int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
121 
122 _TINYDIR_FUNC
123 void _tinydir_get_ext(tinydir_file *file);
124 _TINYDIR_FUNC
125 int _tinydir_file_cmp(const void *a, const void *b);
126 
127 
128 /* definitions*/
129 
130 _TINYDIR_FUNC
131 int tinydir_open(tinydir_dir *dir, const char *path)
132 {
133  if (dir == NULL || path == NULL || strlen(path) == 0)
134  {
135  errno = EINVAL;
136  return -1;
137  }
138  if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
139  {
140  errno = ENAMETOOLONG;
141  return -1;
142  }
143 
144  /* initialise dir */
145  dir->_files = NULL;
146 #ifdef _WIN32
147  dir->_h = INVALID_HANDLE_VALUE;
148 #else
149  dir->_d = NULL;
150 #endif
151  tinydir_close(dir);
152 
153  strcpy(dir->path, path);
154 #ifdef _WIN32
155  strcat(dir->path, "\\*");
156  dir->_h = FindFirstFileA(dir->path, &dir->_f);
157  dir->path[strlen(dir->path) - 2] = '\0';
158  if (dir->_h == INVALID_HANDLE_VALUE)
159 #else
160  dir->_d = opendir(path);
161  if (dir->_d == NULL)
162 #endif
163  {
164  errno = ENOENT;
165  goto bail;
166  }
167 
168  /* read first file */
169  dir->has_next = 1;
170 #ifndef _WIN32
171  dir->_e = readdir(dir->_d);
172  if (dir->_e == NULL)
173  {
174  dir->has_next = 0;
175  }
176 #endif
177 
178  return 0;
179 
180 bail:
181  tinydir_close(dir);
182  return -1;
183 }
184 
185 _TINYDIR_FUNC
186 int tinydir_open_sorted(tinydir_dir *dir, const char *path)
187 {
188  /* Count the number of files first, to pre-allocate the files array */
189  size_t n_files = 0;
190  if (tinydir_open(dir, path) == -1)
191  {
192  return -1;
193  }
194  while (dir->has_next)
195  {
196  n_files++;
197  if (tinydir_next(dir) == -1)
198  {
199  goto bail;
200  }
201  }
202  tinydir_close(dir);
203 
204  if (tinydir_open(dir, path) == -1)
205  {
206  return -1;
207  }
208 
209  dir->n_files = 0;
210  dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
211  if (dir->_files == NULL)
212  {
213  errno = ENOMEM;
214  goto bail;
215  }
216  while (dir->has_next)
217  {
218  tinydir_file *p_file;
219  dir->n_files++;
220 
221  p_file = &dir->_files[dir->n_files - 1];
222  if (tinydir_readfile(dir, p_file) == -1)
223  {
224  goto bail;
225  }
226 
227  if (tinydir_next(dir) == -1)
228  {
229  goto bail;
230  }
231 
232  /* Just in case the number of files has changed between the first and
233  second reads, terminate without writing into unallocated memory */
234  if (dir->n_files == n_files)
235  {
236  break;
237  }
238  }
239 
240  qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
241 
242  return 0;
243 
244 bail:
245  tinydir_close(dir);
246  return -1;
247 }
248 
249 _TINYDIR_FUNC
250 void tinydir_close(tinydir_dir *dir)
251 {
252  if (dir == NULL)
253  {
254  return;
255  }
256 
257  memset(dir->path, 0, sizeof(dir->path));
258  dir->has_next = 0;
259  dir->n_files = 0;
260  if (dir->_files != NULL)
261  {
262  _TINYDIR_FREE(dir->_files);
263  }
264  dir->_files = NULL;
265 #ifdef _WIN32
266  if (dir->_h != INVALID_HANDLE_VALUE)
267  {
268  FindClose(dir->_h);
269  }
270  dir->_h = INVALID_HANDLE_VALUE;
271 #else
272  if (dir->_d)
273  {
274  closedir(dir->_d);
275  }
276  dir->_d = NULL;
277  dir->_e = NULL;
278 #endif
279 }
280 
281 _TINYDIR_FUNC
282 int tinydir_next(tinydir_dir *dir)
283 {
284  if (dir == NULL)
285  {
286  errno = EINVAL;
287  return -1;
288  }
289  if (!dir->has_next)
290  {
291  errno = ENOENT;
292  return -1;
293  }
294 
295 #ifdef _WIN32
296  if (FindNextFileA(dir->_h, &dir->_f) == 0)
297 #else
298  dir->_e = readdir(dir->_d);
299  if (dir->_e == NULL)
300 #endif
301  {
302  dir->has_next = 0;
303 #ifdef _WIN32
304  if (GetLastError() != ERROR_SUCCESS &&
305  GetLastError() != ERROR_NO_MORE_FILES)
306  {
307  tinydir_close(dir);
308  errno = EIO;
309  return -1;
310  }
311 #endif
312  }
313 
314  return 0;
315 }
316 
317 _TINYDIR_FUNC
318 int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
319 {
320  if (dir == NULL || file == NULL)
321  {
322  errno = EINVAL;
323  return -1;
324  }
325 #ifdef _WIN32
326  if (dir->_h == INVALID_HANDLE_VALUE)
327 #else
328  if (dir->_e == NULL)
329 #endif
330  {
331  errno = ENOENT;
332  return -1;
333  }
334  if (strlen(dir->path) +
335  strlen(
336 #ifdef _WIN32
337  dir->_f.cFileName
338 #else
339  dir->_e->d_name
340 #endif
341  ) + 1 + _TINYDIR_PATH_EXTRA >=
342  _TINYDIR_PATH_MAX)
343  {
344  /* the path for the file will be too long */
345  errno = ENAMETOOLONG;
346  return -1;
347  }
348  if (strlen(
349 #ifdef _WIN32
350  dir->_f.cFileName
351 #else
352  dir->_e->d_name
353 #endif
354  ) >= _TINYDIR_FILENAME_MAX)
355  {
356  errno = ENAMETOOLONG;
357  return -1;
358  }
359 
360  strcpy(file->path, dir->path);
361  strcat(file->path, "/");
362  strcpy(file->name,
363 #ifdef _WIN32
364  dir->_f.cFileName
365 #else
366  dir->_e->d_name
367 #endif
368  );
369  strcat(file->path, file->name);
370 #ifndef _WIN32
371  if (stat(file->path, &file->_s) == -1)
372  {
373  return -1;
374  }
375 #endif
376  _tinydir_get_ext(file);
377 
378  file->is_dir =
379 #ifdef _WIN32
380  !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
381 #else
382  S_ISDIR(file->_s.st_mode);
383 #endif
384  file->is_reg =
385 #ifdef _WIN32
386  !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
387  (
388  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
389  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
390  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
391 #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
392  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
393 #endif
394 #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
395  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
396 #endif
397  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
398  !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
399 #else
400  S_ISREG(file->_s.st_mode);
401 #endif
402 
403  return 0;
404 }
405 
406 _TINYDIR_FUNC
407 int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
408 {
409  if (dir == NULL || file == NULL)
410  {
411  errno = EINVAL;
412  return -1;
413  }
414  if (i >= dir->n_files)
415  {
416  errno = ENOENT;
417  return -1;
418  }
419 
420  memcpy(file, &dir->_files[i], sizeof(tinydir_file));
421  _tinydir_get_ext(file);
422 
423  return 0;
424 }
425 
426 _TINYDIR_FUNC
427 int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
428 {
429  char path[_TINYDIR_PATH_MAX];
430  if (dir == NULL)
431  {
432  errno = EINVAL;
433  return -1;
434  }
435  if (i >= dir->n_files || !dir->_files[i].is_dir)
436  {
437  errno = ENOENT;
438  return -1;
439  }
440 
441  strcpy(path, dir->_files[i].path);
442  tinydir_close(dir);
443  if (tinydir_open_sorted(dir, path) == -1)
444  {
445  return -1;
446  }
447 
448  return 0;
449 }
450 
451 /* Open a single file given its path */
452 _TINYDIR_FUNC
453 int tinydir_file_open(tinydir_file *file, const char *path)
454 {
455  tinydir_dir dir;
456  int result = 0;
457  int found = 0;
458  char dir_name_buf[_TINYDIR_PATH_MAX];
459  char file_name_buf[_TINYDIR_FILENAME_MAX];
460  char *dir_name;
461  char *base_name;
462 #ifdef _WIN32
463  char drive_buf[_TINYDIR_PATH_MAX];
464  char ext_buf[_TINYDIR_FILENAME_MAX];
465 #endif
466 
467  if (file == NULL || path == NULL || strlen(path) == 0)
468  {
469  errno = EINVAL;
470  return -1;
471  }
472  if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
473  {
474  errno = ENAMETOOLONG;
475  return -1;
476  }
477 
478  /* Get the parent path */
479 #ifdef _WIN32
480  if (_splitpath_s(
481  path,
482  drive_buf, sizeof drive_buf,
483  dir_name_buf, sizeof dir_name_buf,
484  file_name_buf, sizeof file_name_buf,
485  ext_buf, sizeof ext_buf))
486  {
487  errno = EINVAL;
488  return -1;
489  }
490  /* Concatenate the drive letter and dir name to form full dir name */
491  strcat(drive_buf, dir_name_buf);
492  dir_name = drive_buf;
493  /* Concatenate the file name and extension to form base name */
494  strcat(file_name_buf, ext_buf);
495  base_name = file_name_buf;
496 #else
497  strcpy(dir_name_buf, path);
498  dir_name = dirname(dir_name_buf);
499  strcpy(file_name_buf, path);
500  base_name = basename(file_name_buf);
501 #endif
502 
503  /* Open the parent directory */
504  if (tinydir_open(&dir, dir_name) == -1)
505  {
506  return -1;
507  }
508 
509  /* Read through the parent directory and look for the file */
510  while (dir.has_next)
511  {
512  if (tinydir_readfile(&dir, file) == -1)
513  {
514  result = -1;
515  goto bail;
516  }
517  if (strcmp(file->name, base_name) == 0)
518  {
519  /* File found */
520  found = 1;
521  goto bail;
522  }
523  tinydir_next(&dir);
524  }
525  if (!found)
526  {
527  result = -1;
528  errno = ENOENT;
529  }
530 
531 bail:
532  tinydir_close(&dir);
533  return result;
534 }
535 
536 _TINYDIR_FUNC
537 void _tinydir_get_ext(tinydir_file *file)
538 {
539  char *period = strrchr(file->name, '.');
540  if (period == NULL)
541  {
542  file->extension = &(file->name[strlen(file->name)]);
543  }
544  else
545  {
546  file->extension = period + 1;
547  }
548 }
549 
550 _TINYDIR_FUNC
551 int _tinydir_file_cmp(const void *a, const void *b)
552 {
553  const tinydir_file *fa = (const tinydir_file *)a;
554  const tinydir_file *fb = (const tinydir_file *)b;
555  if (fa->is_dir != fb->is_dir)
556  {
557  return -(fa->is_dir - fb->is_dir);
558  }
559  return strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
560 }
561 
562 #endif
defined(_TINYDIR_MALLOC)
Definition: tinydir.h:73
Definition: tinydir.h:87